blob: 6241942442c65071585efbeae22cfe1632503056 [file] [log] [blame]
yingrenw91f15e02018-01-17 17:03:15 +08001/*
2 * Copyright (C) 2017, The Linux Foundation. All Rights Reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 */
30
31package com.android.contacts;
32
33import android.accounts.Account;
34import android.content.Context;
35import android.content.ContentProviderOperation;
36import android.content.ContentProviderResult;
37import android.content.ContentValues;
38import android.database.Cursor;
39import android.provider.ContactsContract;
40import android.provider.ContactsContract.CommonDataKinds.Email;
41import android.provider.ContactsContract.CommonDataKinds.Phone;
42import android.provider.ContactsContract.CommonDataKinds.StructuredName;
43import android.provider.ContactsContract.Data;
44import android.provider.ContactsContract.RawContacts;
45import android.telephony.SubscriptionInfo;
46import android.telephony.SubscriptionManager;
47import android.telephony.TelephonyManager;
48import android.telephony.PhoneNumberUtils;
49import android.text.TextUtils;
50import android.util.Log;
51import android.net.Uri;
52
53import com.android.contacts.model.account.SimAccountType;
54import com.android.contacts.SimContactsConstants;
55
Weijie Wang1a1df862018-03-21 16:53:40 +080056import android.os.IBinder;
Weijie Wang1a1df862018-03-21 16:53:40 +080057
Weijie Wangf5e786d2018-04-09 21:13:45 +080058import android.os.ServiceManager;
59import com.android.internal.telephony.IIccPhoneBook;
yingrenw91f15e02018-01-17 17:03:15 +080060
61import java.util.ArrayList;
62/**
63 * Shared static SIM contact methods.
64 */
65public class ContactUtils {
66
67 private static final String TAG = "ContactUtils";
68 private static final int NAME_POS = 0;
69 private static final int NUMBER_POS = 1;
70 private static final int EMAIL_POS = 2;
71 private static final int ANR_POS = 3;
72 private static final int ADN_COUNT_POS = 0;
73 private static final int ADN_USED_POS = 1;
74 private static final int EMAIL_COUNT_POS = 2;
75 private static final int EMAIL_USED_POS = 3;
76 private static final int ANR_COUNT_POS = 4;
77 private static final int ANR_USED_POS = 5;
78 public static final int NAME_LENGTH_POS = 6;
79 public static final int NUMBER_LENGTH_POS = 7;
80 public static final int EMAIL_LENGTH_POS = 8;
81 public static final int ANR_LENGTH_POS = 9;
82
83 public final static int[] IC_SIM_PICTURE = {
84 R.drawable.ic_contact_picture_sim_1,
85 R.drawable.ic_contact_picture_sim_2,
86 };
87
88 public static int getSubscription(String accountType, String accountName) {
89 int subscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
90 if (accountType == null || accountName == null)
91 return subscription;
92 if (accountType.equals(SimAccountType.ACCOUNT_TYPE)) {
93 if (accountName.equals(SimContactsConstants.SIM_NAME)
94 || accountName.equals(SimContactsConstants.SIM_NAME_1)) {
95 subscription = SimContactsConstants.SLOT1;
96 } else if (accountName.equals(SimContactsConstants.SIM_NAME_2)) {
97 subscription = SimContactsConstants.SLOT2;
98 }
99 }
100 return subscription;
101 }
102
103 public static Account getAcount(Context c , int slot) {
104 Account account = null;
105 TelephonyManager tm = (TelephonyManager) c
106 .getSystemService(Context.TELEPHONY_SERVICE);
107 if (tm.getPhoneCount() > 1) {
108 if (slot == SimContactsConstants.SLOT1) {
109 account = new Account(SimContactsConstants.SIM_NAME_1,
110 SimAccountType.ACCOUNT_TYPE);
111 } else if (slot == SimContactsConstants.SLOT2) {
112 account = new Account(SimContactsConstants.SIM_NAME_2,
113 SimAccountType.ACCOUNT_TYPE);
114 }
115 } else {
116 if (slot == SimContactsConstants.SLOT1)
117 account = new Account(SimContactsConstants.SIM_NAME,
118 SimAccountType.ACCOUNT_TYPE);
119 }
120 return account;
121 }
122
123 public static int[] getAdnRecordsCapacity(Context c, int slot) {
124 int subId = getActiveSubId(c, slot);
Weijie Wang1a1df862018-03-21 16:53:40 +0800125 return getAdnRecordsCapacityForSubscriber(subId);
yingrenw91f15e02018-01-17 17:03:15 +0800126 }
127
128 /**
129 * Returns the subscription's card can save anr or not.
130 */
131 public static boolean canSaveAnr(Context c, int slot) {
132 int adnCapacity[] = getAdnRecordsCapacity(c, slot);
133 return adnCapacity[ANR_COUNT_POS] > 0;
134 }
135
136 /**
137 * Returns the subscription's card can save email or not.
138 */
139 public static boolean canSaveEmail(Context c, int slot) {
140 int adnCapacity[] = getAdnRecordsCapacity(c, slot);
141 return adnCapacity[EMAIL_COUNT_POS] > 0;
142 }
143
144 public static int getOneSimAnrCount(Context c, int slot) {
145 int count = 0;
146 int adnCapacity[] = getAdnRecordsCapacity(c, slot);
147 int anrCount = adnCapacity[ANR_COUNT_POS];
148 int adnCount = adnCapacity[ADN_COUNT_POS];
149 if (adnCount > 0) {
150 count = anrCount % adnCount != 0 ? (anrCount / adnCount + 1)
151 : (anrCount / adnCount);
152 }
153 return count;
154 }
155
156 public static int getOneSimEmailCount(Context c, int slot) {
157 int count = 0;
158 int adnCapacity[] = getAdnRecordsCapacity(c, slot);
159 int emailCount = adnCapacity[EMAIL_COUNT_POS];
160 int adnCount = adnCapacity[ADN_COUNT_POS];
161 if (adnCount > 0) {
162 count = emailCount % adnCount != 0 ? (emailCount / adnCount + 1)
163 : (emailCount / adnCount);
164 }
165 return count;
166 }
167
168 public static int getSimFreeCount(Context context, int slot) {
169 int adnCapacity[] = getAdnRecordsCapacity(context, slot);
170 int count = adnCapacity[ADN_COUNT_POS]-adnCapacity[ADN_USED_POS];
171 Log.d(TAG, "spare adn:" + count);
172 return count;
173 }
174
175 public static int getSpareAnrCount(Context c, int slot) {
176 int adnCapacity[] = getAdnRecordsCapacity(c, slot);
177 int spareCount = adnCapacity[ANR_COUNT_POS]-adnCapacity[ANR_USED_POS];
178 Log.d(TAG, "spare anr:" + spareCount);
179 return spareCount;
180 }
181
182 public static int getSpareEmailCount(Context c, int slot) {
183 int adnCapacity[] = getAdnRecordsCapacity(c, slot);
184 int spareCount = adnCapacity[EMAIL_COUNT_POS]-adnCapacity[EMAIL_USED_POS];
185 Log.d(TAG, "spare email:" + spareCount);
186 return spareCount;
187 }
188
189 public static int getActiveSubId(Context c , int slot) {
190 SubscriptionInfo subInfoRecord = null;
191 try {
192 SubscriptionManager sm = SubscriptionManager.from(c);
193 subInfoRecord = sm.getActiveSubscriptionInfoForSimSlotIndex(slot);
194 } catch (Exception e) {
195 }
196 if (subInfoRecord != null)
197 return subInfoRecord.getSubscriptionId();
198 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
199 }
200
201 public static int getActiveSlotId(Context c , int subId) {
202 SubscriptionInfo subInfoRecord = null;
203 try {
204 SubscriptionManager sm = SubscriptionManager.from(c);
205 subInfoRecord = sm.getActiveSubscriptionInfo(subId);
206 } catch (Exception e) {
207 }
208 if (subInfoRecord != null)
209 return subInfoRecord.getSimSlotIndex();
210 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
211 }
212
213 public static boolean insertToPhone(String[] values, Context c, int slot) {
214 Account account = getAcount(c, slot);
215 final String name = values[NAME_POS];
216 final String phoneNumber = values[NUMBER_POS];
217 final String emailAddresses = values[EMAIL_POS];
218 final String anrs = values[ANR_POS];
219 final String[] emailAddressArray;
220 final String[] anrArray;
221 boolean success = true;
222 if (!TextUtils.isEmpty(emailAddresses)) {
223 emailAddressArray = emailAddresses.split(",");
224 } else {
225 emailAddressArray = null;
226 }
227 if (!TextUtils.isEmpty(anrs)) {
228 anrArray = anrs.split(SimContactsConstants.ANR_SEP);
229 } else {
230 anrArray = null;
231 }
232 Log.d(TAG, "insertToPhone: name= " + name + ", phoneNumber= "
233 + phoneNumber + ", emails= " + emailAddresses + ", anrs= "
234 + anrs + ", account= " + account);
235 final ArrayList<ContentProviderOperation> operationList =
236 new ArrayList<ContentProviderOperation>();
237 ContentProviderOperation.Builder builder = ContentProviderOperation
238 .newInsert(RawContacts.CONTENT_URI);
239 builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
240
241 if (account != null) {
242 builder.withValue(RawContacts.ACCOUNT_NAME, account.name);
243 builder.withValue(RawContacts.ACCOUNT_TYPE, account.type);
244 }
245 operationList.add(builder.build());
246
247 // do not allow empty value insert into database.
248 if (!TextUtils.isEmpty(name)) {
249 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
250 builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
251 builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
252 builder.withValue(StructuredName.GIVEN_NAME, name);
253 operationList.add(builder.build());
254 }
255 if (!TextUtils.isEmpty(phoneNumber)) {
256 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
257 builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
258 builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
259 builder.withValue(Phone.TYPE, Phone.TYPE_MOBILE);
260 builder.withValue(Phone.NUMBER, phoneNumber);
261 builder.withValue(Data.IS_PRIMARY, 1);
262 operationList.add(builder.build());
263 }
264 if (anrArray != null) {
265 for (String anr : anrArray) {
266 if (!TextUtils.isEmpty(anr)) {
267 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
268 builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
269 builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
270 builder.withValue(Phone.TYPE, Phone.TYPE_HOME);
271 builder.withValue(Phone.NUMBER, anr);
272 operationList.add(builder.build());
273 }
274 }
275 }
276 if (emailAddressArray != null) {
277 for (String emailAddress : emailAddressArray) {
278 if (!TextUtils.isEmpty(emailAddress)) {
279 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
280 builder.withValueBackReference(Email.RAW_CONTACT_ID, 0);
281 builder.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
282 builder.withValue(Email.ADDRESS, emailAddress);
283 operationList.add(builder.build());
284 }
285 }
286 }
287
288 try {
289 ContentProviderResult[] results =
290 c.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
291 for (ContentProviderResult result: results) {
292 if (result.uri == null) {
293 success = false;
294 break;
295 }
296 }
297 return success;
298 } catch (Exception e) {
299 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
300 return false;
301 }
302 }
303
304 public static Uri insertToCard(Context context, String name, String number, String emails,
305 String anrNumber, int slot) {
306 return insertToCard(context, name, number, emails, anrNumber,slot, true);
307 }
308
309 public static Uri insertToCard(Context context, String name, String number, String emails,
310 String anrNumber, int slot, boolean insertToPhone) {
311 Uri result;
312 ContentValues mValues = new ContentValues();
313 mValues.clear();
314 mValues.put(SimContactsConstants.STR_TAG, name);
315 if (!TextUtils.isEmpty(number)) {
316 number = PhoneNumberUtils.stripSeparators(number);
317 mValues.put(SimContactsConstants.STR_NUMBER, number);
318 }
319 if (!TextUtils.isEmpty(emails)) {
320 mValues.put(SimContactsConstants.STR_EMAILS, emails);
321 }
322 if (!TextUtils.isEmpty(anrNumber)) {
323 anrNumber = anrNumber.replaceAll("[^0123456789PWN\\,\\;\\*\\#\\+\\:]", "");
324 mValues.put(SimContactsConstants.STR_ANRS, anrNumber);
325 }
326
327 SimContactsOperation mSimContactsOperation = new SimContactsOperation(context);
328 result = mSimContactsOperation.insert(mValues, slot);
329 if (result != null) {
330 if (insertToPhone) {
331 // we should import the contact to the sim account at the same
332 // time.
333 String[] value = new String[] { name, number, emails, anrNumber };
334 insertToPhone(value, context, slot);
335 }
336 } else {
337 Log.e(TAG, "export contact: [" + name + ", " + number + ", " + emails + "] to slot "
338 + slot + " failed");
339 }
340 return result;
341 }
342
343 //judge the max length of number,anr,email,name for sim contact
344 public static boolean isInValidData(String data, int maxLength) {
345 if (!TextUtils.isEmpty(data)) {
346 if (data.getBytes().length > data.length()) {
347 if (data.length() > ((maxLength - 1) / 2))
348 return true;
349 } else if (data.length() > maxLength)
350 return true;
351 }
352 return false;
353 }
Weijie Wang1a1df862018-03-21 16:53:40 +0800354
355 /* capacity[0] is the max count of ADN
356 capacity[1] is the used count of ADN
357 capacity[2] is the max count of EMAIL
358 capacity[3] is the used count of EMAIL
359 capacity[4] is the max count of ANR
360 capacity[5] is the used count of ANR
361 capacity[6] is the max length of name
362 capacity[7] is the max length of number
363 capacity[8] is the max length of email
364 capacity[9] is the max length of anr
365 */
366 private static int[] getAdnRecordsCapacityForSubscriber(int subId) {
367 int defaultCapacity[] = { 0, 0, 0, 0, 0, 0, 14, 40, 40, 40 };
368 try {
Weijie Wangf5e786d2018-04-09 21:13:45 +0800369 IIccPhoneBook iccIpb = IIccPhoneBook.Stub
370 .asInterface(ServiceManager.getService("simphonebook"));
371 if (iccIpb != null) {
372 int[] capacity = iccIpb.getAdnRecordsCapacityForSubscriber(subId);
373 if (capacity != null)
374 return capacity;
Weijie Wang1a1df862018-03-21 16:53:40 +0800375 }
376 }catch (Exception e){
377 Log.e(TAG," getAdnRecordsCapacityForSubscriber error = "+e.toString());
378 }
379 return defaultCapacity;
380 }
yingrenw91f15e02018-01-17 17:03:15 +0800381}