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 
17 package com.android.dialer.preferredsim;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.os.Build.VERSION;
22 import android.os.Build.VERSION_CODES;
23 import android.support.annotation.NonNull;
24 import android.support.annotation.Nullable;
25 import android.telecom.PhoneAccount;
26 import android.telecom.PhoneAccountHandle;
27 import android.telecom.TelecomManager;
28 import android.telephony.SubscriptionInfo;
29 import android.telephony.SubscriptionManager;
30 import android.telephony.TelephonyManager;
31 import android.text.TextUtils;
32 import com.android.dialer.common.LogUtil;
33 import com.android.dialer.configprovider.ConfigProviderComponent;
34 import com.google.common.base.Optional;
35 import com.google.common.collect.ImmutableSet;
36 
37 /**
38  * Utilities for looking up and validating preferred {@link PhoneAccountHandle}. Contacts should
39  * follow the same logic.
40  */
41 public class PreferredAccountUtil {
42 
43   /**
44    * Validates {@code componentNameString} and {@code idString} maps to SIM that is present on the
45    * device.
46    */
47   @NonNull
getValidPhoneAccount( @onNull Context context, @Nullable String componentNameString, @Nullable String idString)48   public static Optional<PhoneAccountHandle> getValidPhoneAccount(
49       @NonNull Context context, @Nullable String componentNameString, @Nullable String idString) {
50     if (TextUtils.isEmpty(componentNameString) || TextUtils.isEmpty(idString)) {
51       LogUtil.i("PreferredAccountUtil.getValidPhoneAccount", "empty componentName or id");
52       return Optional.absent();
53     }
54     ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
55     if (componentName == null) {
56       LogUtil.e("PreferredAccountUtil.getValidPhoneAccount", "cannot parse component name");
57       return Optional.absent();
58     }
59     PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(componentName, idString);
60 
61     if (isPhoneAccountValid(context, phoneAccountHandle)) {
62       return Optional.of(phoneAccountHandle);
63     }
64     return Optional.absent();
65   }
66 
isPhoneAccountValid( Context context, PhoneAccountHandle phoneAccountHandle)67   public static boolean isPhoneAccountValid(
68       Context context, PhoneAccountHandle phoneAccountHandle) {
69     if (VERSION.SDK_INT >= VERSION_CODES.O) {
70       return context
71               .getSystemService(TelephonyManager.class)
72               .createForPhoneAccountHandle(phoneAccountHandle)
73           != null;
74     }
75 
76     PhoneAccount phoneAccount =
77         context.getSystemService(TelecomManager.class).getPhoneAccount(phoneAccountHandle);
78     if (phoneAccount == null) {
79       LogUtil.e("PreferredAccountUtil.isPhoneAccountValid", "invalid phone account");
80       return false;
81     }
82 
83     if (!phoneAccount.isEnabled()) {
84       LogUtil.e("PreferredAccountUtil.isPhoneAccountValid", "disabled phone account");
85       return false;
86     }
87     for (SubscriptionInfo info :
88         SubscriptionManager.from(context).getActiveSubscriptionInfoList()) {
89       if (phoneAccountHandle.getId().startsWith(info.getIccId())) {
90         LogUtil.i("PreferredAccountUtil.isPhoneAccountValid", "sim found");
91         return true;
92       }
93     }
94     return false;
95   }
96 
97   /**
98    * Return a set of {@link android.accounts.Account#type} that is known to have writable contacts.
99    * This is a light weight implementation of {@link
100    * com.android.contacts.common.model.AccountTypeManager#getAccountTypes(boolean)}. External
101    * accounts are not supported.
102    */
getValidAccountTypes(Context context)103   public static ImmutableSet<String> getValidAccountTypes(Context context) {
104     return ImmutableSet.copyOf(
105         ConfigProviderComponent.get(context)
106             .getConfigProvider()
107             .getString(
108                 "preferred_sim_valid_account_types",
109                 "com.google;"
110                     + "com.osp.app.signin;"
111                     + "com.android.exchange;"
112                     + "com.google.android.exchange;"
113                     + "com.google.android.gm.exchange")
114             .split(";"));
115   }
116 }
117