Android 4.x SIM卡聯系人插入過程


一 對SIM卡聯系人插入過程,其實分為兩部分來完成,第一部分是插入SIM卡里存儲的聯系人,第二部分是插入到本地數據庫里。只有當這兩個步驟都完成時,才能完成SIM卡聯系人的插入。

  1 我們就從Android4.x的源碼來分析下,源碼一定能淋漓盡致的來說明此問題。

     插入過程從下列開始ContactEditorFragment來展開說明:

     當用戶來插入聯系人時,點擊完成時會調用ContactEditorFragment類里面的

 public boolean save(int saveMode) {
        if (!hasValidState() || mStatus != Status.EDITING) {
            return false;
        }

        // If we are about to close the editor - there is no need to refresh the data
        if (saveMode == SaveMode.CLOSE || saveMode == SaveMode.SPLIT) {
            getLoaderManager().destroyLoader(LOADER_DATA);
        }

        mStatus = Status.SAVING;

        if (!hasPendingChanges()) {
            if (mLookupUri == null && saveMode == SaveMode.RELOAD) {
                // We don't have anything to save and there isn't even an existing contact yet.
                // Nothing to do, simply go back to editing mode
                mStatus = Status.EDITING;
                return true;
            }
            onSaveCompleted(false, saveMode, mLookupUri != null, mLookupUri,
                getActivity().getIntent().getIntExtra(ContactSaveService.SAVE_CONTACT_RESULT, 0));
            return true;
        }

        setEnabled(false);

        // Store account as default account, only if this is a new contact
        saveDefaultAccountIfNecessary();

        // Save contact
        Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState,
                SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
                ((Activity)mContext).getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED,
                mUpdatedPhotos);
        mContext.startService(intent);

        // Don't try to save the same photos twice.
        mUpdatedPhotos = new Bundle();

        return true;
    }
點擊確定后就執行了該方法,該方法里真正執行插入聯系人的方法是 

 Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState,
                SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
                ((Activity)mContext).getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED,
                mUpdatedPhotos);
        mContext.startService(intent);

創建了一個Intent來啟動一個服務來完成聯系人的插入全部過程。

接下來我們來研究下該服務是如何來保存聯系人的,首先該服務是繼承IntentService ,具體IntentService 個service有什么不同自己百度可以了解,在此就不多說了

直接上代碼了

protected void onHandleIntent(Intent intent) {
  // Call an appropriate method. If we're sure it affects how incoming
  // phone calls are
  // handled, then notify the fact to in-call screen.
  String action = intent.getAction();
  if (ACTION_NEW_RAW_CONTACT.equals(action)) {
   createRawContact(intent);
   CallerInfoCacheUtils.sendUpdateCallerInfoCacheIntent(this);
  } else if (ACTION_SAVE_CONTACT.equals(action)) {
   saveContact(intent);
   CallerInfoCacheUtils.sendUpdateCallerInfoCacheIntent(this);
  } else if (ACTION_CREATE_GROUP.equals(action)) {

當接收到ACTION_SAVE_CONTACT這個action后開始保存聯系人

private void saveContact(Intent intent) {
  RawContactDeltaList state = intent
    .getParcelableExtra(EXTRA_CONTACT_STATE);
  boolean isProfile = intent
    .getBooleanExtra(EXTRA_SAVE_IS_PROFILE, false);
  Bundle updatedPhotos = intent.getParcelableExtra(EXTRA_UPDATED_PHOTOS);

  // Trim any empty fields, and RawContacts, before persisting
  final AccountTypeManager accountTypes = AccountTypeManager
    .getInstance(this);
  RawContactModifier.trimEmpty(state, accountTypes);

  Uri lookupUri = null;

  final ContentResolver resolver = getContentResolver();
  boolean succeeded = false;

  // Keep track of the id of a newly raw-contact (if any... there can be
  // at most one).
  long insertedRawContactId = -1;

  // Attempt to persist changes
  Integer result = RESULT_FAILURE;

  boolean isCardOperation = false;
  for (int i = 0; i < state.size(); i++) {
   final RawContactDelta entity = state.get(i);
   final String accountType = entity.getValues().getAsString(
     RawContacts.ACCOUNT_TYPE);
   final String accountName = entity.getValues().getAsString(
     RawContacts.ACCOUNT_NAME);
   final int subscription = ContactEditorActivity.getSubscription(
     accountType, accountName);
   isCardOperation = (subscription != -1) ? true : false;
   if (isCardOperation) {
    // modified by neng.wen for bug KAI-729 at 2013.5.14 start:
    if (!isSimFinish(subscription)) {
     Log.e(TAG, "sim card is not ready, accountName: "
       + accountName);
     result = RESULT_SIM_FAILURE;
    } else {
     result = doSaveToSimCard(entity, resolver, subscription);
    }
    // modified by neng.wen for bug KAI-729 end.
    Log.d(TAG, "doSaveToSimCard result is  " + result);
    switch (result) {
    case RESULT_SUCCESS:
     result = RESULT_FAILURE;
     break;
    default:
     break;
    }
   }
  }
  int tries = 0;
  while (tries++ < PERSIST_TRIES) {
   if (result == RESULT_FAILURE) {
    try {
     // Build operations and try applying
     final ArrayList<ContentProviderOperation> diff = state
       .buildDiff();
     if (DEBUG) {
      Log.v(TAG, "Content Provider Operations:");
      for (ContentProviderOperation operation : diff) {
       Log.v(TAG, operation.toString());
      }
     }

     ContentProviderResult[] results = null;
     if (!diff.isEmpty()) {
      results = resolver.applyBatch(
        ContactsContract.AUTHORITY, diff);
     }

     final long rawContactId = getRawContactId(state, diff,
       results);
     if (rawContactId == -1) {
      throw new IllegalStateException(
        "Could not determine RawContact ID after save");
     }
     // We don't have to check to see if the value is still -1.
     // If we reach here,
     // the previous loop iteration didn't succeed, so any ID
     // that we obtained is bogus.
     insertedRawContactId = getInsertedRawContactId(diff,
       results);
     if (isProfile) {
      // Since the profile supports local raw contacts, which
      // may have been completely
      // removed if all information was removed, we need to do
      // a special query to
      // get the lookup URI for the profile contact (if it
      // still exists).
      Cursor c = resolver
        .query(Profile.CONTENT_URI, new String[] {
          Contacts._ID, Contacts.LOOKUP_KEY },
          null, null, null);
      try {
       if (c.moveToFirst()) {
        final long contactId = c.getLong(0);
        final String lookupKey = c.getString(1);
        lookupUri = Contacts.getLookupUri(contactId,
          lookupKey);
       }
      } finally {
       c.close();
      }
     } else {
      final Uri rawContactUri = ContentUris.withAppendedId(
        RawContacts.CONTENT_URI, rawContactId);
      lookupUri = RawContacts.getContactLookupUri(resolver,
        rawContactUri);
     }
     Log.v(TAG, "Saved contact. New URI: " + lookupUri);
     if (lookupUri == null) {
      resolver.delete(RawContacts.CONTENT_URI,
        RawContacts._ID + "=?",
        new String[] { String.valueOf(rawContactId) });
     }
     // We can change this back to false later, if we fail to
     // save the contact photo.
     succeeded = true;
     break;

    } catch (RemoteException e) {
     // Something went wrong, bail without success
     Log.e(TAG, "Problem persisting user edits", e);
     break;

    } catch (OperationApplicationException e) {
     // Version consistency failed, re-parent change and try
     // again
     Log.w(TAG,
       "Version consistency failed, re-parenting: "
         + e.toString());
     final StringBuilder sb = new StringBuilder(RawContacts._ID
       + " IN(");
     boolean first = true;
     final int count = state.size();
     for (int i = 0; i < count; i++) {
      Long rawContactId = state.getRawContactId(i);
      if (rawContactId != null && rawContactId != -1) {
       if (!first) {
        sb.append(',');
       }
       sb.append(rawContactId);
       first = false;
      }
     }
     sb.append(")");

     if (first) {
      throw new IllegalStateException(
        "Version consistency failed for a new contact");
     }

     final RawContactDeltaList newState = RawContactDeltaList
       .fromQuery(
         isProfile ? RawContactsEntity.PROFILE_CONTENT_URI
           : RawContactsEntity.CONTENT_URI,
         resolver, sb.toString(), null, null);
     state = RawContactDeltaList.mergeAfter(newState, state);

     // Update the new state to use profile URIs if appropriate.
     if (isProfile) {
      for (RawContactDelta delta : state) {
       delta.setProfileQueryUri();
      }
     }
    }
   }
  }

  // Now save any updated photos. We do this at the end to ensure that
  // the ContactProvider already knows about newly-created contacts.
  if (updatedPhotos != null) {
   for (String key : updatedPhotos.keySet()) {
    String photoFilePath = updatedPhotos.getString(key);
    long rawContactId = Long.parseLong(key);

    // If the raw-contact ID is negative, we are saving a new
    // raw-contact;
    // replace the bogus ID with the new one that we actually saved
    // the contact at.
    if (rawContactId < 0) {
     rawContactId = insertedRawContactId;
     if (rawContactId == -1) {
      throw new IllegalStateException(
        "Could not determine RawContact ID for image insertion");
     }
    }

    File photoFile = new File(photoFilePath);
    if (!saveUpdatedPhoto(rawContactId, photoFile))
     succeeded = false;
   }
  }

  Intent callbackIntent = intent
    .getParcelableExtra(EXTRA_CALLBACK_INTENT);
  if (callbackIntent != null) {
   if (succeeded) {
    // Mark the intent to indicate that the save was successful
    // (even if the lookup URI
    // is now null). For local contacts or the local profile, it's
    // possible that the
    // save triggered removal of the contact, so no lookup URI would
    // exist..
    callbackIntent.putExtra(EXTRA_SAVE_SUCCEEDED, true);
   }
   callbackIntent.setData(lookupUri);
   callbackIntent.putExtra(SAVE_CONTACT_RESULT, result);

   deliverCallback(callbackIntent);
  }
 }

大家看這個方法開始保存聯系人了 首先重點

final int subscription = ContactEditorActivity.getSubscription(
     accountType, accountName);
   isCardOperation = (subscription != -1) ? true : false;
   if (isCardOperation) {
    // modified by neng.wen for bug KAI-729 at 2013.5.14 start:
    if (!isSimFinish(subscription)) {
     Log.e(TAG, "sim card is not ready, accountName: "
       + accountName);
     result = RESULT_SIM_FAILURE;
    } else {
     result = doSaveToSimCard(entity, resolver, subscription);
    }

首先來判斷是否是要插入到SIM卡里,如果是插入到SIM卡里那么就執行該方法doSaveToSimCard(entity,resolver,subscription);來插入到SIM卡里,

如果插入成功result會返回1  如果插入不成功會返回-1

如果返回為1 時,那么switch (result) {
    case RESULT_SUCCESS:
     result = RESULT_FAILURE;
     break;
    default:
     break;
    }
   }
把result值重新讓RESULT_FAILURE 也就是2  意味着失敗,是為了下面插入本地數據庫做准備。

int tries = 0;
  while (tries++ < PERSIST_TRIES) {
   if (result == RESULT_FAILURE) {
    try {
     // Build operations and try applying
     final ArrayList<ContentProviderOperation> diff = state
       .buildDiff();
     if (DEBUG) {
      Log.v(TAG, "Content Provider Operations:");
      for (ContentProviderOperation operation : diff) {
       Log.v(TAG, operation.toString());
      }
     }

     ContentProviderResult[] results = null;
     if (!diff.isEmpty()) {
      results = resolver.applyBatch(
        ContactsContract.AUTHORITY, diff);
     }

     final long rawContactId = getRawContactId(state, diff,
       results);
     if (rawContactId == -1) {
      throw new IllegalStateException(
        "Could not determine RawContact ID after save");
     }
     // We don't have to check to see if the value is still -1.
     // If we reach here,
     // the previous loop iteration didn't succeed, so any ID
     // that we obtained is bogus.
     insertedRawContactId = getInsertedRawContactId(diff,
       results);
     if (isProfile) {
      // Since the profile supports local raw contacts, which
      // may have been completely
      // removed if all information was removed, we need to do
      // a special query to
      // get the lookup URI for the profile contact (if it
      // still exists).
      Cursor c = resolver
        .query(Profile.CONTENT_URI, new String[] {
          Contacts._ID, Contacts.LOOKUP_KEY },
          null, null, null);
      try {
       if (c.moveToFirst()) {
        final long contactId = c.getLong(0);
        final String lookupKey = c.getString(1);
        lookupUri = Contacts.getLookupUri(contactId,
          lookupKey);
       }
      } finally {
       c.close();
      }
     } else {
      final Uri rawContactUri = ContentUris.withAppendedId(
        RawContacts.CONTENT_URI, rawContactId);
      lookupUri = RawContacts.getContactLookupUri(resolver,
        rawContactUri);
     }
     Log.v(TAG, "Saved contact. New URI: " + lookupUri);
     if (lookupUri == null) {
      resolver.delete(RawContacts.CONTENT_URI,
        RawContacts._ID + "=?",
        new String[] { String.valueOf(rawContactId) });
     }
     // We can change this back to false later, if we fail to
     // save the contact photo.
     succeeded = true;
     break;

    } catch (RemoteException e) {
     // Something went wrong, bail without success
     Log.e(TAG, "Problem persisting user edits", e);
     break;

    } catch (OperationApplicationException e) {
     // Version consistency failed, re-parent change and try
     // again
     Log.w(TAG,
       "Version consistency failed, re-parenting: "
         + e.toString());
     final StringBuilder sb = new StringBuilder(RawContacts._ID
       + " IN(");
     boolean first = true;
     final int count = state.size();
     for (int i = 0; i < count; i++) {
      Long rawContactId = state.getRawContactId(i);
      if (rawContactId != null && rawContactId != -1) {
       if (!first) {
        sb.append(',');
       }
       sb.append(rawContactId);
       first = false;
      }
     }
     sb.append(")");

     if (first) {
      throw new IllegalStateException(
        "Version consistency failed for a new contact");
     }

     final RawContactDeltaList newState = RawContactDeltaList
       .fromQuery(
         isProfile ? RawContactsEntity.PROFILE_CONTENT_URI
           : RawContactsEntity.CONTENT_URI,
         resolver, sb.toString(), null, null);
     state = RawContactDeltaList.mergeAfter(newState, state);

     // Update the new state to use profile URIs if appropriate.
     if (isProfile) {
      for (RawContactDelta delta : state) {
       delta.setProfileQueryUri();
      }
     }
    }
   }
  }

這一段代碼就是插入本地數據庫,if (!diff.isEmpty()) {
      results = resolver.applyBatch(
        ContactsContract.AUTHORITY, diff);
這個就是插入到本地數據庫,具體就到ContactsProvider里的inster了,再次不做詳細介紹,

看看是如何插入到SIM卡里的,我們一起來看看 doSaveToSimCard(entity, resolver, subscription);
這個方法

private Integer doSaveToSimCard(RawContactDelta entity,
   ContentResolver resolver, int subscription) {
  // Return Error code to indicate caller that device is in
  // the "AirPlane" mode and application can't access SIM card.
  if (isCurrentInAirPlaneMode()) {
   return RESULT_AIR_PLANE_MODE;
  }

  boolean isInsert = entity.isContactInsert();
  Integer result = RESULT_SIM_FAILURE;
  mSimContactsOperation = new SimContactsOperation(this);

  ContentValues values = entity.buildSimDiff();
  String tag = null;
  String number = null;
  String anr = null;
  String email = null;

  if (entity.isContactInsert()) {
   tag = values.getAsString(SimContactsConstants.STR_TAG);
   number = values.getAsString(SimContactsConstants.STR_NUMBER);
   anr = values.getAsString(SimContactsConstants.STR_ANRS);
   email = values.getAsString(SimContactsConstants.STR_EMAILS);
  } else {
   tag = values.getAsString(SimContactsConstants.STR_NEW_TAG);
   number = values.getAsString(SimContactsConstants.STR_NEW_NUMBER);
   anr = values.getAsString(SimContactsConstants.STR_NEW_ANRS);
   email = values.getAsString(SimContactsConstants.STR_NEW_EMAILS);
  }

  if (TextUtils.isEmpty(number) && TextUtils.isEmpty(anr)) {
   return RESULT_NO_NUMBER;
  }

  if ((!TextUtils.isEmpty(number) && number.length() > MAX_NUM_LENGTH)
    || (!TextUtils.isEmpty(anr) && anr.length() > MAX_NUM_LENGTH)) {
   return RESULT_NUMBER_ANR_FAILURE;
  }

  if (!TextUtils.isEmpty(number)
    && TextUtils.isEmpty(PhoneNumberUtils.stripSeparators(number))) {
   return RESULT_NUMBER_INVALID;
  }

  if (!TextUtils.isEmpty(email) && email.length() >= MAX_EMAIL_LENGTH) {
   return RESULT_EMAIL_FAILURE;
  }

  if (!TextUtils.isEmpty(tag)) {
   if (!hasChinese(tag)) {
    if (tag.length() > MAX_EN_LENGTH) {
     return RESULT_TAG_FAILURE;
    }
   } else {
    if (tag.length() > MAX_CH_LENGTH) {
     return RESULT_TAG_FAILURE;
    }
   }
  }

  if (entity.isContactInsert()) {
   int count = 0;
   Cursor c = null;
   Uri iccUri;
   if (!MSimTelephonyManager.getDefault().isMultiSimEnabled()) {
    iccUri = Uri.parse("content://icc/adn");
   } else {
    iccUri = Uri.parse(subscription == 0 ? "content://iccmsim/adn"
      : "content://iccmsim/adn_sub2");
   }
   try {
    c = resolver.query(iccUri, null, null, null, null);
    if (c != null) {
     count = c.getCount();
    }
   } finally {
    if (c != null) {
     c.close();
    }
   }

   //modified by neng.wen for bug CW-1269 at 2013.12.13
   if (!MSimTelephonyManager.getDefault().isMultiSimEnabled()) {
    if(getSimCardMaxCount() == 0){
     Log.e(TAG, "getSimCardMaxCount == 0");
     return RESULT_FAILURE;
    }
    
    if (count == getSimCardMaxCount())
     return RESULT_SIM_FULL_FAILURE;
   } else {
    if(getMSimCardMaxCount(subscription) == 0){
     Log.e(TAG, "getMSimCardMaxCount == 0");
     return RESULT_FAILURE;
    }
    
    if (count == getMSimCardMaxCount(subscription))
     return RESULT_SIM_FULL_FAILURE;
   }
  }

  if (isInsert) {
   Uri resultUri = mSimContactsOperation.insert(values, subscription);
   if (resultUri != null)
    result = RESULT_SUCCESS;
  } else {
   int resultInt = mSimContactsOperation.update(values, subscription);
   if (resultInt == 1)
    result = RESULT_SUCCESS;
  }
  return result;
 }
這個方法就是對姓名 電話號碼等不同的字段做判斷,來判斷看是否能夠插入到SIM卡里面,假如可以那么我們就看看是怎么插入的

各種判斷之后具體方法插入Uri resultUri = mSimContactsOperation.insert(values, subscription);
來插入到SIM卡里面,我們來研究下怎么插入到SIM卡里

   public Uri insert(ContentValues values, int subscription) {
        Uri uri = getContentUri(subscription);
        String number = values.getAsString(SimContactsConstants.STR_NUMBER);
        String anrs = values.getAsString(SimContactsConstants.STR_ANRS);
        String emails = values.getAsString(SimContactsConstants.STR_EMAILS);
        values.put(SimContactsConstants.STR_NUMBER,PhoneNumberUtils.stripSeparators(number));
        values.put(SimContactsConstants.STR_ANRS,PhoneNumberUtils.stripSeparators(anrs));
        values.put(SimContactsConstants.STR_EMAILS,emails);
        Uri resultUri;
        resultUri = mResolver.insert(uri,values);
        return resultUri;
    }
就是這個如此簡單的方法來完成SIM卡聯系人的插入,
resultUri = mResolver.insert(uri,values);
這個方法就可以插入聯系人到SIM卡里 ,具體是如何插入,就要設計framework/opt  下面的iccProvider具體關於很多SIM卡的操作,
framework/opt下面有初始化SIM卡相關所有東東,以及一個聯系人通過RILJ到RILC層是如何實現,這個后面會給大家完成詳細的分析的。

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com