IccProvider.java revision 9f36f51844a6d8936f27af925ce8c22729a63f27
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.telephony; 18 19import android.content.ContentProvider; 20import android.content.UriMatcher; 21import android.content.ContentValues; 22import com.android.internal.database.ArrayListCursor; 23import android.database.Cursor; 24import android.net.Uri; 25import android.os.SystemProperties; 26import android.os.RemoteException; 27import android.os.ServiceManager; 28import android.text.TextUtils; 29import android.util.Log; 30 31import java.util.ArrayList; 32import java.util.List; 33 34import com.android.internal.telephony.IccConstants; 35import com.android.internal.telephony.AdnRecord; 36import com.android.internal.telephony.IIccPhoneBook; 37 38 39/** 40 * {@hide} 41 */ 42public class IccProvider extends ContentProvider { 43 private static final String TAG = "IccProvider"; 44 private static final boolean DBG = false; 45 46 47 private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] { 48 "name", 49 "number", 50 "emails" 51 }; 52 53 private static final int ADN = 1; 54 private static final int FDN = 2; 55 private static final int SDN = 3; 56 57 private static final String STR_TAG = "tag"; 58 private static final String STR_NUMBER = "number"; 59 private static final String STR_EMAILS = "emails"; 60 private static final String STR_PIN2 = "pin2"; 61 62 private static final UriMatcher URL_MATCHER = 63 new UriMatcher(UriMatcher.NO_MATCH); 64 65 static { 66 URL_MATCHER.addURI("icc", "adn", ADN); 67 URL_MATCHER.addURI("icc", "fdn", FDN); 68 URL_MATCHER.addURI("icc", "sdn", SDN); 69 } 70 71 72 private boolean mSimulator; 73 74 @Override 75 public boolean onCreate() { 76 String device = SystemProperties.get("ro.product.device"); 77 if (!TextUtils.isEmpty(device)) { 78 mSimulator = false; 79 } else { 80 // simulator 81 mSimulator = true; 82 } 83 84 return true; 85 } 86 87 @Override 88 public Cursor query(Uri url, String[] projection, String selection, 89 String[] selectionArgs, String sort) { 90 ArrayList<ArrayList> results; 91 92 if (!mSimulator) { 93 switch (URL_MATCHER.match(url)) { 94 case ADN: 95 results = loadFromEf(IccConstants.EF_ADN); 96 break; 97 98 case FDN: 99 results = loadFromEf(IccConstants.EF_FDN); 100 break; 101 102 case SDN: 103 results = loadFromEf(IccConstants.EF_SDN); 104 break; 105 106 default: 107 throw new IllegalArgumentException("Unknown URL " + url); 108 } 109 } else { 110 // Fake up some data for the simulator 111 results = new ArrayList<ArrayList>(4); 112 ArrayList<String> contact; 113 114 contact = new ArrayList<String>(); 115 contact.add("Ron Stevens/H"); 116 contact.add("512-555-5038"); 117 results.add(contact); 118 119 contact = new ArrayList<String>(); 120 contact.add("Ron Stevens/M"); 121 contact.add("512-555-8305"); 122 results.add(contact); 123 124 contact = new ArrayList<String>(); 125 contact.add("Melissa Owens"); 126 contact.add("512-555-8305"); 127 results.add(contact); 128 129 contact = new ArrayList<String>(); 130 contact.add("Directory Assistence"); 131 contact.add("411"); 132 results.add(contact); 133 } 134 135 return new ArrayListCursor(ADDRESS_BOOK_COLUMN_NAMES, results); 136 } 137 138 @Override 139 public String getType(Uri url) { 140 switch (URL_MATCHER.match(url)) { 141 case ADN: 142 case FDN: 143 case SDN: 144 return "vnd.android.cursor.dir/sim-contact"; 145 146 default: 147 throw new IllegalArgumentException("Unknown URL " + url); 148 } 149 } 150 151 @Override 152 public Uri insert(Uri url, ContentValues initialValues) { 153 Uri resultUri; 154 int efType; 155 String pin2 = null; 156 157 if (DBG) log("insert"); 158 159 int match = URL_MATCHER.match(url); 160 switch (match) { 161 case ADN: 162 efType = IccConstants.EF_ADN; 163 break; 164 165 case FDN: 166 efType = IccConstants.EF_FDN; 167 pin2 = initialValues.getAsString("pin2"); 168 break; 169 170 default: 171 throw new UnsupportedOperationException( 172 "Cannot insert into URL: " + url); 173 } 174 175 String tag = initialValues.getAsString("tag"); 176 String number = initialValues.getAsString("number"); 177 // TODO(): Read email instead of sending null. 178 boolean success = addIccRecordToEf(efType, tag, number, null, pin2); 179 180 if (!success) { 181 return null; 182 } 183 184 StringBuilder buf = new StringBuilder("content://icc/"); 185 switch (match) { 186 case ADN: 187 buf.append("adn/"); 188 break; 189 190 case FDN: 191 buf.append("fdn/"); 192 break; 193 } 194 195 // TODO: we need to find out the rowId for the newly added record 196 buf.append(0); 197 198 resultUri = Uri.parse(buf.toString()); 199 200 /* 201 // notify interested parties that an insertion happened 202 getContext().getContentResolver().notifyInsert( 203 resultUri, rowID, null); 204 */ 205 206 return resultUri; 207 } 208 209 private String normalizeValue(String inVal) { 210 int len = inVal.length(); 211 String retVal = inVal; 212 213 if (inVal.charAt(0) == '\'' && inVal.charAt(len-1) == '\'') { 214 retVal = inVal.substring(1, len-1); 215 } 216 217 return retVal; 218 } 219 220 @Override 221 public int delete(Uri url, String where, String[] whereArgs) { 222 int efType; 223 224 if (DBG) log("delete"); 225 226 int match = URL_MATCHER.match(url); 227 switch (match) { 228 case ADN: 229 efType = IccConstants.EF_ADN; 230 break; 231 232 case FDN: 233 efType = IccConstants.EF_FDN; 234 break; 235 236 default: 237 throw new UnsupportedOperationException( 238 "Cannot insert into URL: " + url); 239 } 240 241 // parse where clause 242 String tag = null; 243 String number = null; 244 String[] emails = null; 245 String pin2 = null; 246 247 String[] tokens = where.split("AND"); 248 int n = tokens.length; 249 250 while (--n >= 0) { 251 String param = tokens[n]; 252 if (DBG) log("parsing '" + param + "'"); 253 254 String[] pair = param.split("="); 255 256 if (pair.length != 2) { 257 Log.e(TAG, "resolve: bad whereClause parameter: " + param); 258 continue; 259 } 260 261 String key = pair[0].trim(); 262 String val = pair[1].trim(); 263 264 if (STR_TAG.equals(key)) { 265 tag = normalizeValue(val); 266 } else if (STR_NUMBER.equals(key)) { 267 number = normalizeValue(val); 268 } else if (STR_EMAILS.equals(key)) { 269 //TODO(): Email is null. 270 emails = null; 271 } else if (STR_PIN2.equals(key)) { 272 pin2 = normalizeValue(val); 273 } 274 } 275 276 if (TextUtils.isEmpty(number)) { 277 return 0; 278 } 279 280 if (efType == IccConstants.EF_FDN && TextUtils.isEmpty(pin2)) { 281 return 0; 282 } 283 284 boolean success = deleteIccRecordFromEf(efType, tag, number, emails, pin2); 285 if (!success) { 286 return 0; 287 } 288 289 return 1; 290 } 291 292 @Override 293 public int update(Uri url, ContentValues values, String where, String[] whereArgs) { 294 int efType; 295 String pin2 = null; 296 297 if (DBG) log("update"); 298 299 int match = URL_MATCHER.match(url); 300 switch (match) { 301 case ADN: 302 efType = IccConstants.EF_ADN; 303 break; 304 305 case FDN: 306 efType = IccConstants.EF_FDN; 307 pin2 = values.getAsString("pin2"); 308 break; 309 310 default: 311 throw new UnsupportedOperationException( 312 "Cannot insert into URL: " + url); 313 } 314 315 String tag = values.getAsString("tag"); 316 String number = values.getAsString("number"); 317 String[] emails = null; 318 String newTag = values.getAsString("newTag"); 319 String newNumber = values.getAsString("newNumber"); 320 String[] newEmails = null; 321 // TODO(): Update for email. 322 boolean success = updateIccRecordInEf(efType, tag, number, 323 newTag, newNumber, pin2); 324 325 if (!success) { 326 return 0; 327 } 328 329 return 1; 330 } 331 332 private ArrayList<ArrayList> loadFromEf(int efType) { 333 ArrayList<ArrayList> results = new ArrayList<ArrayList>(); 334 List<AdnRecord> adnRecords = null; 335 336 if (DBG) log("loadFromEf: efType=" + efType); 337 338 try { 339 IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( 340 ServiceManager.getService("simphonebook")); 341 if (iccIpb != null) { 342 adnRecords = iccIpb.getAdnRecordsInEf(efType); 343 } 344 } catch (RemoteException ex) { 345 // ignore it 346 } catch (SecurityException ex) { 347 if (DBG) log(ex.toString()); 348 } 349 if (adnRecords != null) { 350 // Load the results 351 352 int N = adnRecords.size(); 353 if (DBG) log("adnRecords.size=" + N); 354 for (int i = 0; i < N ; i++) { 355 loadRecord(adnRecords.get(i), results); 356 } 357 } else { 358 // No results to load 359 Log.w(TAG, "Cannot load ADN records"); 360 results.clear(); 361 } 362 if (DBG) log("loadFromEf: return results"); 363 return results; 364 } 365 366 private boolean 367 addIccRecordToEf(int efType, String name, String number, String[] emails, String pin2) { 368 if (DBG) log("addIccRecordToEf: efType=" + efType + ", name=" + name + 369 ", number=" + number + ", emails=" + emails); 370 371 boolean success = false; 372 373 // TODO: do we need to call getAdnRecordsInEf() before calling 374 // updateAdnRecordsInEfBySearch()? In any case, we will leave 375 // the UI level logic to fill that prereq if necessary. But 376 // hopefully, we can remove this requirement. 377 378 try { 379 IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( 380 ServiceManager.getService("simphonebook")); 381 if (iccIpb != null) { 382 success = iccIpb.updateAdnRecordsInEfBySearch(efType, "", "", 383 name, number, pin2); 384 } 385 } catch (RemoteException ex) { 386 // ignore it 387 } catch (SecurityException ex) { 388 if (DBG) log(ex.toString()); 389 } 390 if (DBG) log("addIccRecordToEf: " + success); 391 return success; 392 } 393 394 private boolean 395 updateIccRecordInEf(int efType, String oldName, String oldNumber, 396 String newName, String newNumber, String pin2) { 397 if (DBG) log("updateIccRecordInEf: efType=" + efType + 398 ", oldname=" + oldName + ", oldnumber=" + oldNumber + 399 ", newname=" + newName + ", newnumber=" + newNumber); 400 boolean success = false; 401 402 try { 403 IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( 404 ServiceManager.getService("simphonebook")); 405 if (iccIpb != null) { 406 success = iccIpb.updateAdnRecordsInEfBySearch(efType, 407 oldName, oldNumber, newName, newNumber, pin2); 408 } 409 } catch (RemoteException ex) { 410 // ignore it 411 } catch (SecurityException ex) { 412 if (DBG) log(ex.toString()); 413 } 414 if (DBG) log("updateIccRecordInEf: " + success); 415 return success; 416 } 417 418 419 private boolean deleteIccRecordFromEf(int efType, String name, String number, String[] emails, 420 String pin2) { 421 if (DBG) log("deleteIccRecordFromEf: efType=" + efType + 422 ", name=" + name + ", number=" + number + ", emails=" + emails + ", pin2=" + pin2); 423 424 boolean success = false; 425 426 try { 427 IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( 428 ServiceManager.getService("simphonebook")); 429 if (iccIpb != null) { 430 success = iccIpb.updateAdnRecordsInEfBySearch(efType, 431 name, number, "", "", pin2); 432 } 433 } catch (RemoteException ex) { 434 // ignore it 435 } catch (SecurityException ex) { 436 if (DBG) log(ex.toString()); 437 } 438 if (DBG) log("deleteIccRecordFromEf: " + success); 439 return success; 440 } 441 442 /** 443 * Loads an AdnRecord into an ArrayList. Must be called with mLock held. 444 * 445 * @param record the ADN record to load from 446 * @param results the array list to put the results in 447 */ 448 private void loadRecord(AdnRecord record, 449 ArrayList<ArrayList> results) { 450 if (!record.isEmpty()) { 451 ArrayList<String> contact = new ArrayList<String>(); 452 String alphaTag = record.getAlphaTag(); 453 String number = record.getNumber(); 454 String[] emails = record.getEmails(); 455 456 if (DBG) log("loadRecord: " + alphaTag + ", " + number + ","); 457 contact.add(alphaTag); 458 contact.add(number); 459 StringBuilder emailString = new StringBuilder(); 460 461 if (emails != null) { 462 for (String email: emails) { 463 if (DBG) log("Adding email:" + email); 464 emailString.append(email); 465 emailString.append(","); 466 } 467 contact.add(emailString.toString()); 468 } else { 469 contact.add(null); 470 } 471 results.add(contact); 472 } 473 } 474 475 private void log(String msg) { 476 Log.d(TAG, "[IccProvider] " + msg); 477 } 478 479} 480