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. Apps registering {@link PhoneAccountHandle}s should ensure that the 38 * {@link #getId()} provided does not expose personally identifying information. A 39 * {@link ConnectionService} should use an opaque token as the {@link PhoneAccountHandle} 40 * identifier.</li> 41 * </ul> 42 * 43 * Note: This Class requires a non-null {@link ComponentName} and {@link UserHandle} to operate 44 * properly. Passing in invalid parameters will generate a log warning. 45 * 46 * See {@link PhoneAccount}, {@link TelecomManager}. 47 */ 48 public final class PhoneAccountHandle implements Parcelable { 49 /** 50 * Expected component name of Telephony phone accounts; ONLY used to determine if we should log 51 * the phone account handle ID. 52 */ 53 private static final ComponentName TELEPHONY_COMPONENT_NAME = 54 new ComponentName("com.android.phone", 55 "com.android.services.telephony.TelephonyConnectionService"); 56 57 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196) 58 private final ComponentName mComponentName; 59 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 60 private final String mId; 61 private final UserHandle mUserHandle; 62 63 /** 64 * Creates a new {@link PhoneAccountHandle}. 65 * 66 * @param componentName The {@link ComponentName} of the {@link ConnectionService} which 67 * services this {@link PhoneAccountHandle}. 68 * @param id A string identifier that is unique across {@code PhoneAccountHandle}s with the same 69 * component name. Apps registering {@link PhoneAccountHandle}s should ensure that the 70 * ID provided does not expose personally identifying information. A 71 * {@link ConnectionService} should use an opaque token as the 72 * {@link PhoneAccountHandle} identifier. 73 * <p> 74 * Note: Each String field is limited to 256 characters. This check is enforced when 75 * registering the PhoneAccount via 76 * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an 77 * {@link IllegalArgumentException} to be thrown if the character field limit is 78 * over 256. 79 */ PhoneAccountHandle( @onNull ComponentName componentName, @NonNull String id)80 public PhoneAccountHandle( 81 @NonNull ComponentName componentName, 82 @NonNull String id) { 83 this(componentName, id, Process.myUserHandle()); 84 } 85 86 /** 87 * Creates a new {@link PhoneAccountHandle}. 88 * 89 * @param componentName The {@link ComponentName} of the {@link ConnectionService} which 90 * services this {@link PhoneAccountHandle}. 91 * @param id A string identifier that is unique across {@code PhoneAccountHandle}s with the same 92 * component name. Apps registering {@link PhoneAccountHandle}s should ensure that the 93 * ID provided does not expose personally identifying information. A 94 * {@link ConnectionService} should use an opaque token as the 95 * {@link PhoneAccountHandle} identifier. 96 * @param userHandle The {@link UserHandle} associated with this {@link PhoneAccountHandle}. 97 * 98 * <p> 99 * Note: Each String field is limited to 256 characters. This check is enforced when 100 * registering the PhoneAccount via 101 * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an 102 * {@link IllegalArgumentException} to be thrown if the character field limit is 103 * over 256. 104 */ PhoneAccountHandle( @onNull ComponentName componentName, @NonNull String id, @NonNull UserHandle userHandle)105 public PhoneAccountHandle( 106 @NonNull ComponentName componentName, 107 @NonNull String id, 108 @NonNull UserHandle userHandle) { 109 checkParameters(componentName, userHandle); 110 mComponentName = componentName; 111 mId = id; 112 mUserHandle = userHandle; 113 } 114 115 /** 116 * The {@code ComponentName} of the connection service which is responsible for making phone 117 * calls using this {@code PhoneAccountHandle}. 118 * 119 * @return A suitable {@code ComponentName}. 120 */ getComponentName()121 public ComponentName getComponentName() { 122 return mComponentName; 123 } 124 125 /** 126 * A string that uniquely distinguishes this particular {@code PhoneAccountHandle} from all the 127 * others supported by the connection service that created it. 128 * <p> 129 * A connection service must select identifiers that are stable for the lifetime of 130 * their users' relationship with their service, across many Android devices. The identifier 131 * should be a stable opaque token which uniquely identifies the user within the service. 132 * Depending on how a service chooses to operate, a bad set of identifiers might be an 133 * increasing series of integers ({@code 0}, {@code 1}, {@code 2}, ...) that are generated 134 * locally on each phone and could collide with values generated on other phones or after a data 135 * wipe of a given phone. 136 * <p> 137 * Important: A non-unique identifier could cause non-deterministic call-log backup/restore 138 * behavior. 139 * 140 * @return A service-specific unique opaque identifier for this {@code PhoneAccountHandle}. 141 */ getId()142 public String getId() { 143 return mId; 144 } 145 146 /** 147 * @return the {@link UserHandle} to use when connecting to this PhoneAccount. 148 */ getUserHandle()149 public UserHandle getUserHandle() { 150 return mUserHandle; 151 } 152 153 @Override hashCode()154 public int hashCode() { 155 return Objects.hash(mComponentName, mId, mUserHandle); 156 } 157 158 @Override toString()159 public String toString() { 160 StringBuilder sb = new StringBuilder() 161 .append(mComponentName) 162 .append(", "); 163 164 if (TELEPHONY_COMPONENT_NAME.equals(mComponentName)) { 165 // Telephony phone account handles are now keyed by subscription id which is not 166 // sensitive. 167 sb.append(mId); 168 } else { 169 // Note: Log.pii called for mId as it can contain personally identifying phone account 170 // information such as SIP account IDs. 171 sb.append(Log.pii(mId)); 172 } 173 sb.append(", "); 174 sb.append(mUserHandle); 175 176 return sb.toString(); 177 } 178 179 @Override equals(Object other)180 public boolean equals(Object other) { 181 return other != null && 182 other instanceof PhoneAccountHandle && 183 Objects.equals(((PhoneAccountHandle) other).getComponentName(), 184 getComponentName()) && 185 Objects.equals(((PhoneAccountHandle) other).getId(), getId()) && 186 Objects.equals(((PhoneAccountHandle) other).getUserHandle(), getUserHandle()); 187 } 188 189 // 190 // Parcelable implementation. 191 // 192 193 @Override describeContents()194 public int describeContents() { 195 return 0; 196 } 197 198 @Override writeToParcel(Parcel out, int flags)199 public void writeToParcel(Parcel out, int flags) { 200 mComponentName.writeToParcel(out, flags); 201 out.writeString(mId); 202 mUserHandle.writeToParcel(out, flags); 203 } 204 checkParameters(ComponentName componentName, UserHandle userHandle)205 private void checkParameters(ComponentName componentName, UserHandle userHandle) { 206 if(componentName == null) { 207 android.util.Log.w("PhoneAccountHandle", new Exception("PhoneAccountHandle has " + 208 "been created with null ComponentName!")); 209 } 210 if(userHandle == null) { 211 android.util.Log.w("PhoneAccountHandle", new Exception("PhoneAccountHandle has " + 212 "been created with null UserHandle!")); 213 } 214 } 215 216 public static final @android.annotation.NonNull Creator<PhoneAccountHandle> CREATOR = 217 new Creator<PhoneAccountHandle>() { 218 @Override 219 public PhoneAccountHandle createFromParcel(Parcel in) { 220 return new PhoneAccountHandle(in); 221 } 222 223 @Override 224 public PhoneAccountHandle[] newArray(int size) { 225 return new PhoneAccountHandle[size]; 226 } 227 }; 228 229 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) PhoneAccountHandle(Parcel in)230 private PhoneAccountHandle(Parcel in) { 231 this(ComponentName.CREATOR.createFromParcel(in), 232 in.readString(), 233 UserHandle.CREATOR.createFromParcel(in)); 234 } 235 236 /** 237 * Determines if two {@link PhoneAccountHandle}s are from the same package. 238 * 239 * @param a Phone account handle to check for same {@link ConnectionService} package. 240 * @param b Other phone account handle to check for same {@link ConnectionService} package. 241 * @return {@code true} if the two {@link PhoneAccountHandle}s passed in belong to the same 242 * {@link ConnectionService} / package, {@code false} otherwise. Note: {@code null} phone 243 * account handles are considered equivalent to other {@code null} phone account handles. 244 * @hide 245 */ areFromSamePackage(@ullable PhoneAccountHandle a, @Nullable PhoneAccountHandle b)246 public static boolean areFromSamePackage(@Nullable PhoneAccountHandle a, 247 @Nullable PhoneAccountHandle b) { 248 String aPackageName = a != null ? a.getComponentName().getPackageName() : null; 249 String bPackageName = b != null ? b.getComponentName().getPackageName() : null; 250 return Objects.equals(aPackageName, bPackageName); 251 } 252 } 253