一 對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卡里
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。