1 /*
2  * Copyright (C) 2017 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 package android.service.euicc;
17 
18 import android.annotation.IntDef;
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.os.Build;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.service.carrier.CarrierIdentifier;
27 import android.telephony.SubscriptionInfo;
28 import android.telephony.UiccAccessRule;
29 import android.text.TextUtils;
30 
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 import java.util.Arrays;
34 import java.util.Collections;
35 import java.util.List;
36 import java.util.Objects;
37 
38 /**
39  * Information about an embedded profile (subscription) on an eUICC.
40  *
41  * @hide
42  */
43 @SystemApi
44 public final class EuiccProfileInfo implements Parcelable {
45 
46     /** Profile policy rules (bit mask) */
47     @Retention(RetentionPolicy.SOURCE)
48     @IntDef(flag = true, prefix = { "POLICY_RULE_" }, value = {
49             POLICY_RULE_DO_NOT_DISABLE,
50             POLICY_RULE_DO_NOT_DELETE,
51             POLICY_RULE_DELETE_AFTER_DISABLING
52     })
53     public @interface PolicyRule {}
54     /** Once this profile is enabled, it cannot be disabled. */
55     public static final int POLICY_RULE_DO_NOT_DISABLE = 1;
56     /** This profile cannot be deleted. */
57     public static final int POLICY_RULE_DO_NOT_DELETE = 1 << 1;
58     /** This profile should be deleted after being disabled. */
59     public static final int POLICY_RULE_DELETE_AFTER_DISABLING = 1 << 2;
60 
61     /** Class of the profile */
62     @Retention(RetentionPolicy.SOURCE)
63     @IntDef(prefix = { "PROFILE_CLASS_" }, value = {
64             PROFILE_CLASS_TESTING,
65             PROFILE_CLASS_PROVISIONING,
66             PROFILE_CLASS_OPERATIONAL,
67             PROFILE_CLASS_UNSET
68     })
69     public @interface ProfileClass {}
70     /** Testing profiles */
71     public static final int PROFILE_CLASS_TESTING = 0;
72     /** Provisioning profiles which are pre-loaded on eUICC */
73     public static final int PROFILE_CLASS_PROVISIONING = 1;
74     /** Operational profiles which can be pre-loaded or downloaded */
75     public static final int PROFILE_CLASS_OPERATIONAL = 2;
76     /**
77      * Profile class not set.
78      * @hide
79      */
80     public static final int PROFILE_CLASS_UNSET = -1;
81 
82     /** State of the profile */
83     @Retention(RetentionPolicy.SOURCE)
84     @IntDef(prefix = { "PROFILE_STATE_" }, value = {
85             PROFILE_STATE_DISABLED,
86             PROFILE_STATE_ENABLED,
87             PROFILE_STATE_UNSET
88     })
89     public @interface ProfileState {}
90     /** Disabled profiles */
91     public static final int PROFILE_STATE_DISABLED = 0;
92     /** Enabled profile */
93     public static final int PROFILE_STATE_ENABLED = 1;
94     /**
95      * Profile state not set.
96      * @hide
97      */
98     public static final int PROFILE_STATE_UNSET = -1;
99 
100     /** The iccid of the subscription. */
101     private final String mIccid;
102 
103     /** An optional nickname for the subscription. */
104     private final @Nullable String mNickname;
105 
106     /** The service provider name for the subscription. */
107     private final String mServiceProviderName;
108 
109     /** The profile name for the subscription. */
110     private final String mProfileName;
111 
112     /** Profile class for the subscription. */
113     @ProfileClass private final int mProfileClass;
114 
115     /** The profile state of the subscription. */
116     @ProfileState private final int mState;
117 
118     /** The operator Id of the subscription. */
119     private final CarrierIdentifier mCarrierIdentifier;
120 
121     /** The policy rules of the subscription. */
122     @PolicyRule private final int mPolicyRules;
123 
124     /**
125      * Optional access rules defining which apps can manage this subscription. If unset, only the
126      * platform can manage it.
127      */
128     private final @Nullable UiccAccessRule[] mAccessRules;
129 
130     public static final @android.annotation.NonNull Creator<EuiccProfileInfo> CREATOR = new Creator<EuiccProfileInfo>() {
131         @Override
132         public EuiccProfileInfo createFromParcel(Parcel in) {
133             return new EuiccProfileInfo(in);
134         }
135 
136         @Override
137         public EuiccProfileInfo[] newArray(int size) {
138             return new EuiccProfileInfo[size];
139         }
140     };
141 
142     // TODO(b/70292228): Remove this method when LPA can be updated.
143     /**
144      * @hide
145      * @deprecated - Do not use.
146      */
147     @Deprecated
148     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
EuiccProfileInfo(String iccid, @Nullable UiccAccessRule[] accessRules, @Nullable String nickname)149     public EuiccProfileInfo(String iccid, @Nullable UiccAccessRule[] accessRules,
150             @Nullable String nickname) {
151         if (!TextUtils.isDigitsOnly(iccid)) {
152             throw new IllegalArgumentException("iccid contains invalid characters: " + iccid);
153         }
154         this.mIccid = iccid;
155         this.mAccessRules = accessRules;
156         this.mNickname = nickname;
157 
158         this.mServiceProviderName = null;
159         this.mProfileName = null;
160         this.mProfileClass = PROFILE_CLASS_UNSET;
161         this.mState = PROFILE_STATE_UNSET;
162         this.mCarrierIdentifier = null;
163         this.mPolicyRules = 0;
164     }
165 
EuiccProfileInfo(Parcel in)166     private EuiccProfileInfo(Parcel in) {
167         mIccid = in.readString();
168         mNickname = in.readString();
169         mServiceProviderName = in.readString();
170         mProfileName = in.readString();
171         mProfileClass = in.readInt();
172         mState = in.readInt();
173         byte exist = in.readByte();
174         if (exist == (byte) 1) {
175             mCarrierIdentifier = CarrierIdentifier.CREATOR.createFromParcel(in);
176         } else {
177             mCarrierIdentifier = null;
178         }
179         mPolicyRules = in.readInt();
180         mAccessRules = in.createTypedArray(UiccAccessRule.CREATOR);
181     }
182 
183     @Override
writeToParcel(Parcel dest, int flags)184     public void writeToParcel(Parcel dest, int flags) {
185         dest.writeString(mIccid);
186         dest.writeString(mNickname);
187         dest.writeString(mServiceProviderName);
188         dest.writeString(mProfileName);
189         dest.writeInt(mProfileClass);
190         dest.writeInt(mState);
191         if (mCarrierIdentifier != null) {
192             dest.writeByte((byte) 1);
193             mCarrierIdentifier.writeToParcel(dest, flags);
194         } else {
195             dest.writeByte((byte) 0);
196         }
197         dest.writeInt(mPolicyRules);
198         dest.writeTypedArray(mAccessRules, flags);
199     }
200 
201     @Override
describeContents()202     public int describeContents() {
203         return 0;
204     }
205 
206     /** The builder to build a new {@link EuiccProfileInfo} instance. */
207     public static final class Builder {
208         private String mIccid;
209         private List<UiccAccessRule> mAccessRules;
210         private String mNickname;
211         private String mServiceProviderName;
212         private String mProfileName;
213         @ProfileClass private int mProfileClass;
214         @ProfileState private int mState;
215         private CarrierIdentifier mCarrierIdentifier;
216         @PolicyRule private int mPolicyRules;
217 
Builder(String value)218         public Builder(String value) {
219             if (!TextUtils.isDigitsOnly(value)) {
220                 throw new IllegalArgumentException("iccid contains invalid characters: " + value);
221             }
222             mIccid = value;
223         }
224 
Builder(EuiccProfileInfo baseProfile)225         public Builder(EuiccProfileInfo baseProfile) {
226             mIccid = baseProfile.mIccid;
227             mNickname = baseProfile.mNickname;
228             mServiceProviderName = baseProfile.mServiceProviderName;
229             mProfileName = baseProfile.mProfileName;
230             mProfileClass = baseProfile.mProfileClass;
231             mState = baseProfile.mState;
232             mCarrierIdentifier = baseProfile.mCarrierIdentifier;
233             mPolicyRules = baseProfile.mPolicyRules;
234             mAccessRules = baseProfile.mAccessRules == null
235                             ? Collections.emptyList()
236                             : Arrays.asList(baseProfile.mAccessRules);
237         }
238 
239         /** Builds the profile instance. */
build()240         public EuiccProfileInfo build() {
241             if (mIccid == null) {
242                 throw new IllegalStateException("ICCID must be set for a profile.");
243             }
244             return new EuiccProfileInfo(
245                     mIccid,
246                     mNickname,
247                     mServiceProviderName,
248                     mProfileName,
249                     mProfileClass,
250                     mState,
251                     mCarrierIdentifier,
252                     mPolicyRules,
253                     mAccessRules);
254         }
255 
256         /** Sets the iccId of the subscription. */
setIccid(String value)257         public Builder setIccid(String value) {
258             if (!TextUtils.isDigitsOnly(value)) {
259                 throw new IllegalArgumentException("iccid contains invalid characters: " + value);
260             }
261             mIccid = value;
262             return this;
263         }
264 
265         /** Sets the nickname of the subscription. */
setNickname(String value)266         public Builder setNickname(String value) {
267             mNickname = value;
268             return this;
269         }
270 
271         /** Sets the service provider name of the subscription. */
setServiceProviderName(String value)272         public Builder setServiceProviderName(String value) {
273             mServiceProviderName = value;
274             return this;
275         }
276 
277         /** Sets the profile name of the subscription. */
setProfileName(String value)278         public Builder setProfileName(String value) {
279             mProfileName = value;
280             return this;
281         }
282 
283         /** Sets the profile class of the subscription. */
setProfileClass(@rofileClass int value)284         public Builder setProfileClass(@ProfileClass int value) {
285             mProfileClass = value;
286             return this;
287         }
288 
289         /** Sets the state of the subscription. */
setState(@rofileState int value)290         public Builder setState(@ProfileState int value) {
291             mState = value;
292             return this;
293         }
294 
295         /** Sets the carrier identifier of the subscription. */
setCarrierIdentifier(CarrierIdentifier value)296         public Builder setCarrierIdentifier(CarrierIdentifier value) {
297             mCarrierIdentifier = value;
298             return this;
299         }
300 
301         /** Sets the policy rules of the subscription. */
setPolicyRules(@olicyRule int value)302         public Builder setPolicyRules(@PolicyRule int value) {
303             mPolicyRules = value;
304             return this;
305         }
306 
307         /** Sets the access rules of the subscription. */
setUiccAccessRule(@ullable List<UiccAccessRule> value)308         public Builder setUiccAccessRule(@Nullable List<UiccAccessRule> value) {
309             mAccessRules = value;
310             return this;
311         }
312     }
313 
EuiccProfileInfo( String iccid, @Nullable String nickname, String serviceProviderName, String profileName, @ProfileClass int profileClass, @ProfileState int state, CarrierIdentifier carrierIdentifier, @PolicyRule int policyRules, @Nullable List<UiccAccessRule> accessRules)314     private EuiccProfileInfo(
315             String iccid,
316             @Nullable String nickname,
317             String serviceProviderName,
318             String profileName,
319             @ProfileClass int profileClass,
320             @ProfileState int state,
321             CarrierIdentifier carrierIdentifier,
322             @PolicyRule int policyRules,
323             @Nullable List<UiccAccessRule> accessRules) {
324         this.mIccid = iccid;
325         this.mNickname = nickname;
326         this.mServiceProviderName = serviceProviderName;
327         this.mProfileName = profileName;
328         this.mProfileClass = profileClass;
329         this.mState = state;
330         this.mCarrierIdentifier = carrierIdentifier;
331         this.mPolicyRules = policyRules;
332         if (accessRules != null && accessRules.size() > 0) {
333             this.mAccessRules = accessRules.toArray(new UiccAccessRule[accessRules.size()]);
334         } else {
335             this.mAccessRules = null;
336         }
337     }
338 
339     /** Gets the ICCID string. */
getIccid()340     public String getIccid() {
341         return mIccid;
342     }
343 
344     /** Gets the access rules. */
345     @Nullable
getUiccAccessRules()346     public List<UiccAccessRule> getUiccAccessRules() {
347         if (mAccessRules == null) return null;
348         return Arrays.asList(mAccessRules);
349     }
350 
351     /** Gets the nickname. */
352     @Nullable
getNickname()353     public String getNickname() {
354         return mNickname;
355     }
356 
357     /** Gets the service provider name. */
getServiceProviderName()358     public String getServiceProviderName() {
359         return mServiceProviderName;
360     }
361 
362     /** Gets the profile name. */
getProfileName()363     public String getProfileName() {
364         return mProfileName;
365     }
366 
367     /** Gets the profile class. */
368     @ProfileClass
getProfileClass()369     public int getProfileClass() {
370         return mProfileClass;
371     }
372 
373     /** Gets the state of the subscription. */
374     @ProfileState
getState()375     public int getState() {
376         return mState;
377     }
378 
379     /** Gets the carrier identifier. */
getCarrierIdentifier()380     public CarrierIdentifier getCarrierIdentifier() {
381         return mCarrierIdentifier;
382     }
383 
384     /** Gets the policy rules. */
385     @PolicyRule
getPolicyRules()386     public int getPolicyRules() {
387         return mPolicyRules;
388     }
389 
390     /** Returns whether any policy rule exists. */
hasPolicyRules()391     public boolean hasPolicyRules() {
392         return mPolicyRules != 0;
393     }
394 
395     /** Checks whether a certain policy rule exists. */
hasPolicyRule(@olicyRule int policy)396     public boolean hasPolicyRule(@PolicyRule int policy) {
397         return (mPolicyRules & policy) != 0;
398     }
399 
400     @Override
equals(@ullable Object obj)401     public boolean equals(@Nullable Object obj) {
402         if (this == obj) {
403             return true;
404         }
405         if (obj == null || getClass() != obj.getClass()) {
406             return false;
407         }
408 
409         EuiccProfileInfo that = (EuiccProfileInfo) obj;
410         return Objects.equals(mIccid, that.mIccid)
411                 && Objects.equals(mNickname, that.mNickname)
412                 && Objects.equals(mServiceProviderName, that.mServiceProviderName)
413                 && Objects.equals(mProfileName, that.mProfileName)
414                 && mProfileClass == that.mProfileClass
415                 && mState == that.mState
416                 && Objects.equals(mCarrierIdentifier, that.mCarrierIdentifier)
417                 && mPolicyRules == that.mPolicyRules
418                 && Arrays.equals(mAccessRules, that.mAccessRules);
419     }
420 
421     @Override
hashCode()422     public int hashCode() {
423         int result = 1;
424         result = 31 * result + Objects.hashCode(mIccid);
425         result = 31 * result + Objects.hashCode(mNickname);
426         result = 31 * result + Objects.hashCode(mServiceProviderName);
427         result = 31 * result + Objects.hashCode(mProfileName);
428         result = 31 * result + mProfileClass;
429         result = 31 * result + mState;
430         result = 31 * result + Objects.hashCode(mCarrierIdentifier);
431         result = 31 * result + mPolicyRules;
432         result = 31 * result + Arrays.hashCode(mAccessRules);
433         return result;
434     }
435 
436     @NonNull
437     @Override
toString()438     public String toString() {
439         return "EuiccProfileInfo (nickname="
440                 + mNickname
441                 + ", serviceProviderName="
442                 + mServiceProviderName
443                 + ", profileName="
444                 + mProfileName
445                 + ", profileClass="
446                 + mProfileClass
447                 + ", state="
448                 + mState
449                 + ", CarrierIdentifier="
450                 + mCarrierIdentifier
451                 + ", policyRules="
452                 + mPolicyRules
453                 + ", accessRules="
454                 + Arrays.toString(mAccessRules)
455                 + ", iccid="
456                 + SubscriptionInfo.getPrintableId(mIccid)
457                 + ")";
458     }
459 }
460