1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.util;
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentResolver;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Intent;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.pm.ApplicationInfo;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.pm.PackageManager;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.pm.PackageManager.NameNotFoundException;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.Cursor;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.net.ConnectivityManager;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.Settings;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.Telephony;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.util.ArrayMap;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.telephony.PhoneNumberUtils;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.telephony.SmsManager;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.telephony.SubscriptionInfo;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.telephony.SubscriptionManager;
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.telephony.TelephonyManager;
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.R;
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.ParticipantData;
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.sms.MmsSmsUtils;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.i18n.phonenumbers.NumberParseException;
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.i18n.phonenumbers.PhoneNumberUtil;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.lang.reflect.Method;
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.ArrayList;
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.HashSet;
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.List;
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Locale;
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * This class abstracts away platform dependency of calling telephony related
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * platform APIs, mostly involving TelephonyManager, SubscriptionManager and
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * a bit of SmsManager.
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * The class instance can only be obtained via the get(int subId) method parameterized
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * by a SIM subscription ID. On pre-L_MR1, the subId is not used and it has to be
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * the default subId (-1).
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * A convenient getDefault() method is provided for default subId (-1) on any platform
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic abstract class PhoneUtils {
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String TAG = LogUtil.BUGLE_TAG;
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int MINIMUM_PHONE_NUMBER_LENGTH_TO_FORMAT = 6;
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final List<SubscriptionInfo> EMPTY_SUBSCRIPTION_LIST = new ArrayList<>();
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // The canonical phone number cache
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Each country gets its own cache. The following maps from ISO country code to
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // the country's cache. Each cache maps from original phone number to canonicalized phone
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final ArrayMap<String, ArrayMap<String, String>> sCanonicalPhoneNumberCache =
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            new ArrayMap<>();
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final Context mContext;
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final TelephonyManager mTelephonyManager;
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final int mSubId;
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public PhoneUtils(int subId) {
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mSubId = subId;
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mContext = Factory.get().getApplicationContext();
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mTelephonyManager =
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get the SIM's country code
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the country code on the SIM
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract String getSimCountry();
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get number of SIM slots
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the SIM slot count
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract int getSimSlotCount();
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get SIM's carrier name
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the carrier name of the SIM
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract String getCarrierName();
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Check if there is SIM inserted on the device
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if there is SIM inserted, false otherwise
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract boolean hasSim();
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Check if the SIM is roaming
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if the SIM is in romaing state, false otherwise
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract boolean isRoaming();
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get the MCC and MNC in integer of the SIM's provider
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return an array of two ints, [0] is the MCC code and [1] is the MNC code
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract int[] getMccMnc();
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get the mcc/mnc string
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the text of mccmnc string
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract String getSimOperatorNumeric();
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get the SIM's self raw number, i.e. not canonicalized
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param allowOverride Whether to use the app's setting to override the self number
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the original self number
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @throws IllegalStateException if no active subscription on L-MR1+
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract String getSelfRawNumber(final boolean allowOverride);
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns the "effective" subId, or the subId used in the context of actual messages,
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * conversations and subscription-specific settings, for the given "nominal" sub id.
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * For pre-L-MR1 platform, this should always be
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * {@value com.android.messaging.datamodel.data.ParticipantData#DEFAULT_SELF_SUB_ID};
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * On the other hand, for L-MR1 and above, DEFAULT_SELF_SUB_ID will be mapped to the system
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * default subscription id for SMS.
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param subId The input subId
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the real subId if we can convert
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract int getEffectiveSubId(int subId);
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns the number of active subscriptions in the device.
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract int getActiveSubscriptionCount();
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get {@link SmsManager} instance
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the relevant SmsManager instance based on OS version and subId
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract SmsManager getSmsManager();
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get the default SMS subscription id
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the default sub ID
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract int getDefaultSmsSubscriptionId();
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns if there's currently a system default SIM selected for sending SMS.
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract boolean getHasPreferredSmsSim();
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * For L_MR1, system may return a negative subId. Convert this into our own
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * subId, so that we consistently use -1 for invalid or default.
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * see b/18629526 and b/18670346
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param intent The push intent from system
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param extraName The name of the sub id extra
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the subId that is valid and meaningful for the app
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract int getEffectiveIncomingSubIdFromSystem(Intent intent, String extraName);
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get the subscription_id column value from a telephony provider cursor
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param cursor The database query cursor
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param subIdIndex The index of the subId column in the cursor
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the subscription_id column value from the cursor
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract int getSubIdFromTelephony(Cursor cursor, int subIdIndex);
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Check if data roaming is enabled
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if data roaming is enabled, false otherwise
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract boolean isDataRoamingEnabled();
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Check if mobile data is enabled
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if mobile data is enabled, false otherwise
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract boolean isMobileDataEnabled();
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get the set of self phone numbers, all normalized
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the set of normalized self phone numbers
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract HashSet<String> getNormalizedSelfNumbers();
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * This interface packages methods should only compile on L_MR1.
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * This is needed to make unit tests happy when mockito tries to
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * mock these methods. Calling on these methods on L_MR1 requires
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * an extra invocation of toMr1().
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public interface LMr1 {
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        /**
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         * Get this SIM's information. Only applies to L_MR1 above
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         *
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         * @return the subscription info of the SIM
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         */
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public abstract SubscriptionInfo getActiveSubscriptionInfo();
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        /**
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         * Get the list of active SIMs in system. Only applies to L_MR1 above
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         *
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         * @return the list of subscription info for all inserted SIMs
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         */
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public abstract List<SubscriptionInfo> getActiveSubscriptionInfoList();
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        /**
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         * Register subscription change listener. Only applies to L_MR1 above
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         *
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         * @param listener The listener to register
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         */
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public abstract void registerOnSubscriptionsChangedListener(
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                SubscriptionManager.OnSubscriptionsChangedListener listener);
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * The PhoneUtils class for pre L_MR1
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static class PhoneUtilsPreLMR1 extends PhoneUtils {
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        private final ConnectivityManager mConnectivityManager;
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public PhoneUtilsPreLMR1() {
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            super(ParticipantData.DEFAULT_SELF_SUB_ID);
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mConnectivityManager =
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public String getSimCountry() {
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String country = mTelephonyManager.getSimCountryIso();
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (TextUtils.isEmpty(country)) {
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return null;
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return country.toUpperCase();
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getSimSlotCount() {
279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Don't support MSIM pre-L_MR1
280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return 1;
281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public String getCarrierName() {
285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mTelephonyManager.getNetworkOperatorName();
286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean hasSim() {
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_ABSENT;
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean isRoaming() {
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mTelephonyManager.isNetworkRoaming();
296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int[] getMccMnc() {
300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String mccmnc = mTelephonyManager.getSimOperator();
301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            int mcc = 0;
302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            int mnc = 0;
303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            try {
304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mcc = Integer.parseInt(mccmnc.substring(0, 3));
305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mnc = Integer.parseInt(mccmnc.substring(3));
306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } catch (Exception e) {
307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.w(TAG, "PhoneUtils.getMccMnc: invalid string " + mccmnc, e);
308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return new int[]{mcc, mnc};
310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public String getSimOperatorNumeric() {
314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mTelephonyManager.getSimOperator();
315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public String getSelfRawNumber(final boolean allowOverride) {
319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (allowOverride) {
320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final String userDefinedNumber = getNumberFromPrefs(mContext,
321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        ParticipantData.DEFAULT_SELF_SUB_ID);
322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!TextUtils.isEmpty(userDefinedNumber)) {
323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    return userDefinedNumber;
324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mTelephonyManager.getLine1Number();
327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getEffectiveSubId(int subId) {
331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Assert.equals(ParticipantData.DEFAULT_SELF_SUB_ID, subId);
332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return ParticipantData.DEFAULT_SELF_SUB_ID;
333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public SmsManager getSmsManager() {
337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return SmsManager.getDefault();
338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getDefaultSmsSubscriptionId() {
342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Assert.fail("PhoneUtils.getDefaultSmsSubscriptionId(): not supported before L MR1");
343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return ParticipantData.DEFAULT_SELF_SUB_ID;
344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean getHasPreferredSmsSim() {
348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // SIM selection is not supported pre-L_MR1.
349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return true;
350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getActiveSubscriptionCount() {
354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return hasSim() ? 1 : 0;
355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getEffectiveIncomingSubIdFromSystem(Intent intent, String extraName) {
359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Pre-L_MR1 always returns the default id
360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return ParticipantData.DEFAULT_SELF_SUB_ID;
361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getSubIdFromTelephony(Cursor cursor, int subIdIndex) {
365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // No subscription_id column before L_MR1
366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return ParticipantData.DEFAULT_SELF_SUB_ID;
367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @SuppressWarnings("deprecation")
371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean isDataRoamingEnabled() {
372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            boolean dataRoamingEnabled = false;
373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ContentResolver cr = mContext.getContentResolver();
374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (OsUtil.isAtLeastJB_MR1()) {
375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                dataRoamingEnabled =
376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        (Settings.Global.getInt(cr, Settings.Global.DATA_ROAMING, 0) != 0);
377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
378d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                dataRoamingEnabled =
379d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        (Settings.System.getInt(cr, Settings.System.DATA_ROAMING, 0) != 0);
380d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
381d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return dataRoamingEnabled;
382d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
383d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean isMobileDataEnabled() {
386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            boolean mobileDataEnabled = false;
387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            try {
388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final Class cmClass = mConnectivityManager.getClass();
389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                method.setAccessible(true); // Make the method callable
391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // get the setting for "mobile data"
392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mobileDataEnabled = (Boolean) method.invoke(mConnectivityManager);
393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } catch (final Exception e) {
394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.e(TAG, "PhoneUtil.isMobileDataEnabled: system api not found", e);
395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mobileDataEnabled;
397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public HashSet<String> getNormalizedSelfNumbers() {
401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final HashSet<String> numbers = new HashSet<>();
402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            numbers.add(getCanonicalForSelf(true/*allowOverride*/));
403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return numbers;
404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * The PhoneUtils class for L_MR1
409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static class PhoneUtilsLMR1 extends PhoneUtils implements LMr1 {
411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        private final SubscriptionManager mSubscriptionManager;
412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public PhoneUtilsLMR1(final int subId) {
414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            super(subId);
415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSubscriptionManager = SubscriptionManager.from(Factory.get().getApplicationContext());
416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public String getSimCountry() {
420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final SubscriptionInfo subInfo = getActiveSubscriptionInfo();
421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (subInfo != null) {
422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final String country = subInfo.getCountryIso();
423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (TextUtils.isEmpty(country)) {
424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    return null;
425d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
426d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return country.toUpperCase();
427d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
428d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
429d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
430d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
431d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
432d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getSimSlotCount() {
433d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mSubscriptionManager.getActiveSubscriptionInfoCountMax();
434d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
435d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
436d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
437d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public String getCarrierName() {
438d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final SubscriptionInfo subInfo = getActiveSubscriptionInfo();
439d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (subInfo != null) {
440d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final CharSequence displayName = subInfo.getDisplayName();
441d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!TextUtils.isEmpty(displayName)) {
442d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    return displayName.toString();
443d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
444d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final CharSequence carrierName = subInfo.getCarrierName();
445d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (carrierName != null) {
446d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    return carrierName.toString();
447d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
448d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
449d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
450d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
451d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
452d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
453d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean hasSim() {
454d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mSubscriptionManager.getActiveSubscriptionInfoCount() > 0;
455d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
456d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
457d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
458d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean isRoaming() {
459d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mSubscriptionManager.isNetworkRoaming(mSubId);
460d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
461d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
462d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
463d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int[] getMccMnc() {
464d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            int mcc = 0;
465d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            int mnc = 0;
466d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final SubscriptionInfo subInfo = getActiveSubscriptionInfo();
467d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (subInfo != null) {
468d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mcc = subInfo.getMcc();
469d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mnc = subInfo.getMnc();
470d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
471d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return new int[]{mcc, mnc};
472d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
473d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
474d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
475d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public String getSimOperatorNumeric() {
476d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // For L_MR1 we return the canonicalized (xxxxxx) string
477d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return getMccMncString(getMccMnc());
478d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
479d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
480d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
481d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public String getSelfRawNumber(final boolean allowOverride) {
482d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (allowOverride) {
483d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final String userDefinedNumber = getNumberFromPrefs(mContext, mSubId);
484d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!TextUtils.isEmpty(userDefinedNumber)) {
485d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    return userDefinedNumber;
486d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
487d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
488d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
489d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final SubscriptionInfo subInfo = getActiveSubscriptionInfo();
490d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (subInfo != null) {
491d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                String phoneNumber = subInfo.getNumber();
492d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (TextUtils.isEmpty(phoneNumber) && LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
493d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.d(TAG, "SubscriptionInfo phone number for self is empty!");
494d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
495d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return phoneNumber;
496d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
497d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.w(TAG, "PhoneUtils.getSelfRawNumber: subInfo is null for " + mSubId);
498d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new IllegalStateException("No active subscription");
499d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
500d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
501d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
502d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public SubscriptionInfo getActiveSubscriptionInfo() {
503d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            try {
504d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final SubscriptionInfo subInfo =
505d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        mSubscriptionManager.getActiveSubscriptionInfo(mSubId);
506d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (subInfo == null) {
507d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
508d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // This is possible if the sub id is no longer available.
509d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.d(TAG, "PhoneUtils.getActiveSubscriptionInfo(): empty sub info for "
510d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                + mSubId);
511d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
512d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
513d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return subInfo;
514d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } catch (Exception e) {
515d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.e(TAG, "PhoneUtils.getActiveSubscriptionInfo: system exception for "
516d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        + mSubId, e);
517d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
518d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
519d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
520d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
521d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
522d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
523d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final List<SubscriptionInfo> subscriptionInfos =
524d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mSubscriptionManager.getActiveSubscriptionInfoList();
525d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (subscriptionInfos != null) {
526d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return subscriptionInfos;
527d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
528d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return EMPTY_SUBSCRIPTION_LIST;
529d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
530d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
531d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
532d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getEffectiveSubId(int subId) {
533d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (subId == ParticipantData.DEFAULT_SELF_SUB_ID) {
534d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return getDefaultSmsSubscriptionId();
535d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
536d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return subId;
537d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
538d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
539d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
540d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void registerOnSubscriptionsChangedListener(
541d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                SubscriptionManager.OnSubscriptionsChangedListener listener) {
542d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSubscriptionManager.addOnSubscriptionsChangedListener(listener);
543d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
544d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
545d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
546d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public SmsManager getSmsManager() {
547d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return SmsManager.getSmsManagerForSubscriptionId(mSubId);
548d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
549d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
550d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
551d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getDefaultSmsSubscriptionId() {
552d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int systemDefaultSubId = SmsManager.getDefaultSmsSubscriptionId();
553d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (systemDefaultSubId < 0) {
554d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Always use -1 for any negative subId from system
555d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return ParticipantData.DEFAULT_SELF_SUB_ID;
556d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
557d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return systemDefaultSubId;
558d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
559d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
560d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
561d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean getHasPreferredSmsSim() {
562d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return getDefaultSmsSubscriptionId() != ParticipantData.DEFAULT_SELF_SUB_ID;
563d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
564d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
565d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
566d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getActiveSubscriptionCount() {
567d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mSubscriptionManager.getActiveSubscriptionInfoCount();
568d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
569d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
570d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
571d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getEffectiveIncomingSubIdFromSystem(Intent intent, String extraName) {
572d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return getEffectiveIncomingSubIdFromSystem(intent.getIntExtra(extraName,
573d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ParticipantData.DEFAULT_SELF_SUB_ID));
574d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
575d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
576d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        private int getEffectiveIncomingSubIdFromSystem(int subId) {
577d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (subId < 0) {
578d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (mSubscriptionManager.getActiveSubscriptionInfoCount() > 1) {
579d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // For multi-SIM device, we can not decide which SIM to use if system
580d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // does not know either. So just make it the invalid sub id.
581d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    return ParticipantData.DEFAULT_SELF_SUB_ID;
582d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
583d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // For single-SIM device, it must come from the only SIM we have
584d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return getDefaultSmsSubscriptionId();
585d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
586d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return subId;
587d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
588d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
589d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
590d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getSubIdFromTelephony(Cursor cursor, int subIdIndex) {
591d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return getEffectiveIncomingSubIdFromSystem(cursor.getInt(subIdIndex));
592d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
593d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
594d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
595d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean isDataRoamingEnabled() {
596d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final SubscriptionInfo subInfo = getActiveSubscriptionInfo();
597d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (subInfo == null) {
598d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // There is nothing we can do if system give us empty sub info
599d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.e(TAG, "PhoneUtils.isDataRoamingEnabled: system return empty sub info for "
600d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        + mSubId);
601d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return false;
602d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
603d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return subInfo.getDataRoaming() != SubscriptionManager.DATA_ROAMING_DISABLE;
604d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
605d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
606d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
607d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean isMobileDataEnabled() {
608d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            boolean mobileDataEnabled = false;
609d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            try {
610d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final Class cmClass = mTelephonyManager.getClass();
611d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final Method method = cmClass.getDeclaredMethod("getDataEnabled", Integer.TYPE);
612d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                method.setAccessible(true); // Make the method callable
613d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // get the setting for "mobile data"
614d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mobileDataEnabled = (Boolean) method.invoke(
615d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        mTelephonyManager, Integer.valueOf(mSubId));
616d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } catch (final Exception e) {
617d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.e(TAG, "PhoneUtil.isMobileDataEnabled: system api not found", e);
618d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
619d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mobileDataEnabled;
620d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
621d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
622d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
623d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
624d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public HashSet<String> getNormalizedSelfNumbers() {
625d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final HashSet<String> numbers = new HashSet<>();
626d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (SubscriptionInfo info : getActiveSubscriptionInfoList()) {
627d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                numbers.add(PhoneUtils.get(info.getSubscriptionId()).getCanonicalForSelf(
628d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        true/*allowOverride*/));
629d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
630d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return numbers;
631d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
632d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
633d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
634d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
635d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * A convenient get() method that uses the default SIM. Use this when SIM is
636d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * not relevant, e.g. isDefaultSmsApp
637d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
638d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return an instance of PhoneUtils for default SIM
639d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
640d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static PhoneUtils getDefault() {
641d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return Factory.get().getPhoneUtils(ParticipantData.DEFAULT_SELF_SUB_ID);
642d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
643d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
644d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
645d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get an instance of PhoneUtils associated with a specific SIM, which is also platform
646d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * specific.
647d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
648d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param subId The SIM's subscription ID
649d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the instance
650d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
651d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static PhoneUtils get(int subId) {
652d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return Factory.get().getPhoneUtils(subId);
653d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
654d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
655d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public LMr1 toLMr1() {
656d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastL_MR1()) {
657d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return (LMr1) this;
658d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
659d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Assert.fail("PhoneUtils.toLMr1(): invalid OS version");
660d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
661d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
662d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
663d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
664d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
665d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Check if this device supports SMS
666d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
667d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if SMS is supported, false otherwise
668d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
669d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean isSmsCapable() {
670d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return mTelephonyManager.isSmsCapable();
671d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
672d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
673d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
674d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Check if this device supports voice calling
675d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
676d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if voice calling is supported, false otherwise
677d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
678d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean isVoiceCapable() {
679d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return mTelephonyManager.isVoiceCapable();
680d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
681d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
682d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
683d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get the ISO country code from system locale setting
684d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
685d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the ISO country code from system locale
686d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
687d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static String getLocaleCountry() {
688d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String country = Locale.getDefault().getCountry();
689d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (TextUtils.isEmpty(country)) {
690d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
691d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
692d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return country.toUpperCase();
693d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
694d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
695d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
696d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get ISO country code from the SIM, if not available, fall back to locale
697d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
698d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return SIM or locale ISO country code
699d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
700d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public String getSimOrDefaultLocaleCountry() {
701d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String country = getSimCountry();
702d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (country == null) {
703d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            country = getLocaleCountry();
704d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
705d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return country;
706d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
707d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
708d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Get or set the cache of canonicalized phone numbers for a specific country
709d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static ArrayMap<String, String> getOrAddCountryMapInCacheLocked(String country) {
710d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (country == null) {
711d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            country = "";
712d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
713d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ArrayMap<String, String> countryMap = sCanonicalPhoneNumberCache.get(country);
714d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (countryMap == null) {
715d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            countryMap = new ArrayMap<>();
716d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            sCanonicalPhoneNumberCache.put(country, countryMap);
717d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
718d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return countryMap;
719d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
720d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
721d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Get canonicalized phone number from cache
722d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static String getCanonicalFromCache(final String phoneText, String country) {
723d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        synchronized (sCanonicalPhoneNumberCache) {
724d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ArrayMap<String, String> countryMap = getOrAddCountryMapInCacheLocked(country);
725d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return countryMap.get(phoneText);
726d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
727d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
728d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
729d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Put canonicalized phone number into cache
730d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void putCanonicalToCache(final String phoneText, String country,
731d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String canonical) {
732d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        synchronized (sCanonicalPhoneNumberCache) {
733d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ArrayMap<String, String> countryMap = getOrAddCountryMapInCacheLocked(country);
734d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            countryMap.put(phoneText, canonical);
735d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
736d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
737d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
738d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
739d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Utility method to parse user input number into standard E164 number.
740d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
741d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param phoneText Phone number text as input by user.
742d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param country ISO country code based on which to parse the number.
743d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return E164 phone number. Returns null in case parsing failed.
744d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
745d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static String getValidE164Number(final String phoneText, final String country) {
746d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
747d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
748d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PhoneNumber phoneNumber = phoneNumberUtil.parse(phoneText, country);
749d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (phoneNumber != null && phoneNumberUtil.isValidNumber(phoneNumber)) {
750d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return phoneNumberUtil.format(phoneNumber, PhoneNumberFormat.E164);
751d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
752d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final NumberParseException e) {
753d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(TAG, "PhoneUtils.getValidE164Number(): Not able to parse phone number "
754d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        + LogUtil.sanitizePII(phoneText) + " for country " + country);
755d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
756d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
757d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
758d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
759d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
760d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Canonicalize phone number using system locale country
761d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
762d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param phoneText The phone number to canonicalize
763d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the canonicalized number
764d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
765d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public String getCanonicalBySystemLocale(final String phoneText) {
766d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return getCanonicalByCountry(phoneText, getLocaleCountry());
767d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
768d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
769d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
770d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Canonicalize phone number using SIM's country, may fall back to system locale country
771d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * if SIM country can not be obtained
772d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
773d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param phoneText The phone number to canonicalize
774d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the canonicalized number
775d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
776d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public String getCanonicalBySimLocale(final String phoneText) {
777d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return getCanonicalByCountry(phoneText, getSimOrDefaultLocaleCountry());
778d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
779d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
780d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
781d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Canonicalize phone number using a country code.
782d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * This uses an internal cache per country to speed up.
783d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
784d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param phoneText The phone number to canonicalize
785d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param country The ISO country code to use
786d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the canonicalized number, or the original number if can't be parsed
787d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
788d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private String getCanonicalByCountry(final String phoneText, final String country) {
789d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Assert.notNull(phoneText);
790d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
791d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String canonicalNumber = getCanonicalFromCache(phoneText, country);
792d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (canonicalNumber != null) {
793d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return canonicalNumber;
794d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
795d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        canonicalNumber = getValidE164Number(phoneText, country);
796d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (canonicalNumber == null) {
797d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // If we can't normalize this number, we just use the display string number.
798d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // This is possible for short codes and other non-localizable numbers.
799d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            canonicalNumber = phoneText;
800d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
801d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        putCanonicalToCache(phoneText, country, canonicalNumber);
802d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return canonicalNumber;
803d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
804d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
805d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
806d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Canonicalize the self (per SIM) phone number
807d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
808d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param allowOverride whether to use the override number in app settings
809d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the canonicalized self phone number
810d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
811d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public String getCanonicalForSelf(final boolean allowOverride) {
812d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String selfNumber = null;
813d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
814d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            selfNumber = getSelfRawNumber(allowOverride);
815d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (IllegalStateException e) {
816d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // continue;
817d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
818d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (selfNumber == null) {
819d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return "";
820d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
821d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return getCanonicalBySimLocale(selfNumber);
822d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
823d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
824d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
825d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get the SIM's phone number in NATIONAL format with only digits, used in sending
826d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * as LINE1NOCOUNTRYCODE macro in mms_config
827d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
828d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return all digits national format number of the SIM
829d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
830d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public String getSimNumberNoCountryCode() {
831d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String selfNumber = null;
832d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
833d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            selfNumber = getSelfRawNumber(false/*allowOverride*/);
834d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (IllegalStateException e) {
835d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // continue
836d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
837d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (selfNumber == null) {
838d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            selfNumber = "";
839d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
840d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String country = getSimCountry();
841d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
842d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
843d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PhoneNumber phoneNumber = phoneNumberUtil.parse(selfNumber, country);
844d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (phoneNumber != null && phoneNumberUtil.isValidNumber(phoneNumber)) {
845d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return phoneNumberUtil
846d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        .format(phoneNumber, PhoneNumberFormat.NATIONAL)
847d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        .replaceAll("\\D", "");
848d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
849d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final NumberParseException e) {
850d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(TAG, "PhoneUtils.getSimNumberNoCountryCode(): Not able to parse phone number "
851d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + LogUtil.sanitizePII(selfNumber) + " for country " + country);
852d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
853d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return selfNumber;
854d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
855d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
856d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
857d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
858d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Format a phone number for displaying, using system locale country.
859d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * If the country code matches between the system locale and the input phone number,
860d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * it will be formatted into NATIONAL format, otherwise, the INTERNATIONAL format
861d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
862d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param phoneText The original phone text
863d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return formatted number
864d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
865d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public String formatForDisplay(final String phoneText) {
866d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Only format a valid number which length >=6
867d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (TextUtils.isEmpty(phoneText) ||
868d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                phoneText.replaceAll("\\D", "").length() < MINIMUM_PHONE_NUMBER_LENGTH_TO_FORMAT) {
869d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return phoneText;
870d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
871d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
872d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String systemCountry = getLocaleCountry();
873d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int systemCountryCode = phoneNumberUtil.getCountryCodeForRegion(systemCountry);
874d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
875d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PhoneNumber parsedNumber = phoneNumberUtil.parse(phoneText, systemCountry);
876d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PhoneNumberFormat phoneNumberFormat =
877d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    (systemCountryCode > 0 && parsedNumber.getCountryCode() == systemCountryCode) ?
878d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            PhoneNumberFormat.NATIONAL : PhoneNumberFormat.INTERNATIONAL;
879d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return phoneNumberUtil.format(parsedNumber, phoneNumberFormat);
880d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (NumberParseException e) {
881d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(TAG, "PhoneUtils.formatForDisplay: invalid phone number "
882d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + LogUtil.sanitizePII(phoneText) + " with country " + systemCountry);
883d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return phoneText;
884d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
885d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
886d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
887d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
888d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Is Messaging the default SMS app?
889d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * - On KLP+ this checks the system setting.
890d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * - On JB (and below) this always returns true, since the setting was added in KLP.
891d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
892d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean isDefaultSmsApp() {
893d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastKLP()) {
894d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String configuredApplication = Telephony.Sms.getDefaultSmsPackage(mContext);
895d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return  mContext.getPackageName().equals(configuredApplication);
896d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
897d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return true;
898d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
899d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
900d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
901d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get default SMS app package name
902d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
903d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return the package name of default SMS app
904d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
905d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public String getDefaultSmsApp() {
906d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastKLP()) {
907d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return Telephony.Sms.getDefaultSmsPackage(mContext);
908d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
909d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
910d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
911d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
912d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
913d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Determines if SMS is currently enabled on this device.
914d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * - Device must support SMS
915d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * - On KLP+ we must be set as the default SMS app
916d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
917d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean isSmsEnabled() {
918d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return isSmsCapable() && isDefaultSmsApp();
919d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
920d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
921d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
922d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns the name of the default SMS app, or the empty string if there is
923d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * an error or there is no default app (e.g. JB and below).
924d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
925d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public String getDefaultSmsAppLabel() {
926d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastKLP()) {
927d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String packageName = Telephony.Sms.getDefaultSmsPackage(mContext);
928d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PackageManager pm = mContext.getPackageManager();
929d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            try {
930d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0);
931d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return pm.getApplicationLabel(appInfo).toString();
932d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } catch (NameNotFoundException e) {
933d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Fall through and return empty string
934d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
935d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
936d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return "";
937d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
938d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
939d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
940d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Gets the state of Airplane Mode.
941d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
942d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if enabled.
943d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
944d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @SuppressWarnings("deprecation")
945d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean isAirplaneModeOn() {
946d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastJB_MR1()) {
947d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return Settings.Global.getInt(mContext.getContentResolver(),
948d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
949d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
950d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return Settings.System.getInt(mContext.getContentResolver(),
951d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Settings.System.AIRPLANE_MODE_ON, 0) != 0;
952d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
953d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
954d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
955d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static String getMccMncString(int[] mccmnc) {
956d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mccmnc == null || mccmnc.length != 2) {
957d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return "000000";
958d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
959d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return String.format("%03d%03d", mccmnc[0], mccmnc[1]);
960d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
961d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
962d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static String canonicalizeMccMnc(final String mcc, final String mnc) {
963d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
964d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return String.format("%03d%03d", Integer.parseInt(mcc), Integer.parseInt(mnc));
965d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final NumberFormatException e) {
966d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Return invalid as is
967d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.w(TAG, "canonicalizeMccMnc: invalid mccmnc:" + mcc + " ," + mnc);
968d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
969d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return mcc + mnc;
970d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
971d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
972d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
973d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns whether the given destination is valid for sending SMS/MMS message.
974d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
975d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isValidSmsMmsDestination(final String destination) {
976d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return PhoneNumberUtils.isWellFormedSmsAddress(destination) ||
977d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                MmsSmsUtils.isEmailAddress(destination);
978d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
979d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
980d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public interface SubscriptionRunnable {
981d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        void runForSubscription(int subId);
982d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
983d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
984d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
985d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * A convenience method for iterating through all active subscriptions
986d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
987d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param runnable a {@link SubscriptionRunnable} for performing work on each subscription.
988d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
989d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void forEachActiveSubscription(final SubscriptionRunnable runnable) {
990d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastL_MR1()) {
991d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final List<SubscriptionInfo> subscriptionList =
992d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    getDefault().toLMr1().getActiveSubscriptionInfoList();
993d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (final SubscriptionInfo subscriptionInfo : subscriptionList) {
994d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                runnable.runForSubscription(subscriptionInfo.getSubscriptionId());
995d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
996d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
997d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            runnable.runForSubscription(ParticipantData.DEFAULT_SELF_SUB_ID);
998d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
999d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1000d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1001d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static String getNumberFromPrefs(final Context context, final int subId) {
1002d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final BuglePrefs prefs = BuglePrefs.getSubscriptionPrefs(subId);
1003d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String mmsPhoneNumberPrefKey =
1004d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                context.getString(R.string.mms_phone_number_pref_key);
1005d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String userDefinedNumber = prefs.getString(mmsPhoneNumberPrefKey, null);
1006d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!TextUtils.isEmpty(userDefinedNumber)) {
1007d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return userDefinedNumber;
1008d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1009d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
1010d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1011d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
1012