1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.telecom; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.content.ComponentName; 23 import android.os.Build; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.os.Process; 27 import android.os.UserHandle; 28 29 import java.util.Objects; 30 31 /** 32 * The unique identifier for a {@link PhoneAccount}. A {@code PhoneAccountHandle} is made of two 33 * parts: 34 * <ul> 35 * <li>The component name of the associated connection service.</li> 36 * <li>A string identifier that is unique across {@code PhoneAccountHandle}s with the same 37 * component name.</li> 38 * </ul> 39 * 40 * Note: This Class requires a non-null {@link ComponentName} and {@link UserHandle} to operate 41 * properly. Passing in invalid parameters will generate a log warning. 42 * 43 * See {@link PhoneAccount}, {@link TelecomManager}. 44 */ 45 public final class PhoneAccountHandle implements Parcelable { 46 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196) 47 private final ComponentName mComponentName; 48 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 49 private final String mId; 50 private final UserHandle mUserHandle; 51 PhoneAccountHandle( @onNull ComponentName componentName, @NonNull String id)52 public PhoneAccountHandle( 53 @NonNull ComponentName componentName, 54 @NonNull String id) { 55 this(componentName, id, Process.myUserHandle()); 56 } 57 PhoneAccountHandle( @onNull ComponentName componentName, @NonNull String id, @NonNull UserHandle userHandle)58 public PhoneAccountHandle( 59 @NonNull ComponentName componentName, 60 @NonNull String id, 61 @NonNull UserHandle userHandle) { 62 checkParameters(componentName, userHandle); 63 mComponentName = componentName; 64 mId = id; 65 mUserHandle = userHandle; 66 } 67 68 /** 69 * The {@code ComponentName} of the connection service which is responsible for making phone 70 * calls using this {@code PhoneAccountHandle}. 71 * 72 * @return A suitable {@code ComponentName}. 73 */ getComponentName()74 public ComponentName getComponentName() { 75 return mComponentName; 76 } 77 78 /** 79 * A string that uniquely distinguishes this particular {@code PhoneAccountHandle} from all the 80 * others supported by the connection service that created it. 81 * <p> 82 * A connection service must select identifiers that are stable for the lifetime of 83 * their users' relationship with their service, across many Android devices. For example, a 84 * good set of identifiers might be the email addresses with which with users registered for 85 * their accounts with a particular service. Depending on how a service chooses to operate, 86 * a bad set of identifiers might be an increasing series of integers 87 * ({@code 0}, {@code 1}, {@code 2}, ...) that are generated locally on each phone and could 88 * collide with values generated on other phones or after a data wipe of a given phone. 89 * 90 * Important: A non-unique identifier could cause non-deterministic call-log backup/restore 91 * behavior. 92 * 93 * @return A service-specific unique identifier for this {@code PhoneAccountHandle}. 94 */ getId()95 public String getId() { 96 return mId; 97 } 98 99 /** 100 * @return the {@link UserHandle} to use when connecting to this PhoneAccount. 101 */ getUserHandle()102 public UserHandle getUserHandle() { 103 return mUserHandle; 104 } 105 106 @Override hashCode()107 public int hashCode() { 108 return Objects.hash(mComponentName, mId, mUserHandle); 109 } 110 111 @Override toString()112 public String toString() { 113 // Note: Log.pii called for mId as it can contain personally identifying phone account 114 // information such as SIP account IDs. 115 return new StringBuilder().append(mComponentName) 116 .append(", ") 117 .append(Log.pii(mId)) 118 .append(", ") 119 .append(mUserHandle) 120 .toString(); 121 } 122 123 @Override equals(Object other)124 public boolean equals(Object other) { 125 return other != null && 126 other instanceof PhoneAccountHandle && 127 Objects.equals(((PhoneAccountHandle) other).getComponentName(), 128 getComponentName()) && 129 Objects.equals(((PhoneAccountHandle) other).getId(), getId()) && 130 Objects.equals(((PhoneAccountHandle) other).getUserHandle(), getUserHandle()); 131 } 132 133 // 134 // Parcelable implementation. 135 // 136 137 @Override describeContents()138 public int describeContents() { 139 return 0; 140 } 141 142 @Override writeToParcel(Parcel out, int flags)143 public void writeToParcel(Parcel out, int flags) { 144 mComponentName.writeToParcel(out, flags); 145 out.writeString(mId); 146 mUserHandle.writeToParcel(out, flags); 147 } 148 checkParameters(ComponentName componentName, UserHandle userHandle)149 private void checkParameters(ComponentName componentName, UserHandle userHandle) { 150 if(componentName == null) { 151 android.util.Log.w("PhoneAccountHandle", new Exception("PhoneAccountHandle has " + 152 "been created with null ComponentName!")); 153 } 154 if(userHandle == null) { 155 android.util.Log.w("PhoneAccountHandle", new Exception("PhoneAccountHandle has " + 156 "been created with null UserHandle!")); 157 } 158 } 159 160 public static final @android.annotation.NonNull Creator<PhoneAccountHandle> CREATOR = new Creator<PhoneAccountHandle>() { 161 @Override 162 public PhoneAccountHandle createFromParcel(Parcel in) { 163 return new PhoneAccountHandle(in); 164 } 165 166 @Override 167 public PhoneAccountHandle[] newArray(int size) { 168 return new PhoneAccountHandle[size]; 169 } 170 }; 171 172 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) PhoneAccountHandle(Parcel in)173 private PhoneAccountHandle(Parcel in) { 174 this(ComponentName.CREATOR.createFromParcel(in), 175 in.readString(), 176 UserHandle.CREATOR.createFromParcel(in)); 177 } 178 179 /** 180 * Determines if two {@link PhoneAccountHandle}s are from the same package. 181 * 182 * @param a Phone account handle to check for same {@link ConnectionService} package. 183 * @param b Other phone account handle to check for same {@link ConnectionService} package. 184 * @return {@code true} if the two {@link PhoneAccountHandle}s passed in belong to the same 185 * {@link ConnectionService} / package, {@code false} otherwise. Note: {@code null} phone 186 * account handles are considered equivalent to other {@code null} phone account handles. 187 * @hide 188 */ areFromSamePackage(@ullable PhoneAccountHandle a, @Nullable PhoneAccountHandle b)189 public static boolean areFromSamePackage(@Nullable PhoneAccountHandle a, 190 @Nullable PhoneAccountHandle b) { 191 String aPackageName = a != null ? a.getComponentName().getPackageName() : null; 192 String bPackageName = b != null ? b.getComponentName().getPackageName() : null; 193 return Objects.equals(aPackageName, bPackageName); 194 } 195 } 196