| package com.android.contacts.activities; |
| |
| import android.app.Activity; |
| import android.app.FragmentManager; |
| import android.app.FragmentTransaction; |
| import android.app.LoaderManager; |
| import android.content.ContentUris; |
| import android.content.Intent; |
| import android.content.Loader; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.provider.ContactsContract; |
| import android.provider.ContactsContract.RawContacts; |
| import android.widget.Toast; |
| |
| import com.android.contacts.AppCompatContactsActivity; |
| import com.android.contacts.ContactSaveService; |
| import com.android.contacts.R; |
| import com.android.contacts.editor.ContactEditorFragment; |
| import com.android.contacts.editor.EditorIntents; |
| import com.android.contacts.editor.PickRawContactDialogFragment; |
| import com.android.contacts.editor.PickRawContactLoader; |
| import com.android.contacts.editor.PickRawContactLoader.RawContactsMetadata; |
| import com.android.contacts.editor.SplitContactConfirmationDialogFragment; |
| import com.android.contacts.logging.EditorEvent; |
| import com.android.contacts.logging.Logger; |
| import com.android.contacts.model.AccountTypeManager; |
| import com.android.contacts.quickcontact.QuickContactActivity; |
| import com.android.contacts.util.ImplicitIntentsUtil; |
| import com.android.contacts.util.MaterialColorMapUtils.MaterialPalette; |
| import com.android.contactsbind.FeedbackHelper; |
| |
| /** |
| * Transparent springboard activity that hosts a dialog to select a raw contact to edit. |
| * All intents coming out from this activity have {@code FLAG_ACTIVITY_FORWARD_RESULT} set. |
| */ |
| public class ContactEditorSpringBoardActivity extends AppCompatContactsActivity implements |
| PickRawContactDialogFragment.PickRawContactListener, |
| SplitContactConfirmationDialogFragment.Listener { |
| |
| private static final String TAG = "EditorSpringBoard"; |
| private static final String TAG_RAW_CONTACTS_DIALOG = "rawContactsDialog"; |
| private static final String KEY_RAW_CONTACTS_METADATA = "rawContactsMetadata"; |
| private static final int LOADER_RAW_CONTACTS = 1; |
| |
| public static final String EXTRA_SHOW_READ_ONLY = "showReadOnly"; |
| |
| private Uri mUri; |
| private RawContactsMetadata mResult; |
| private MaterialPalette mMaterialPalette; |
| private boolean mHasWritableAccount; |
| private boolean mShowReadOnly; |
| private int mWritableAccountPosition; |
| |
| /** |
| * The contact data loader listener. |
| */ |
| protected final LoaderManager.LoaderCallbacks<RawContactsMetadata> mRawContactLoaderListener = |
| new LoaderManager.LoaderCallbacks<RawContactsMetadata>() { |
| |
| @Override |
| public Loader<RawContactsMetadata> onCreateLoader(int id, Bundle args) { |
| return new PickRawContactLoader(ContactEditorSpringBoardActivity.this, mUri); |
| } |
| |
| @Override |
| public void onLoadFinished(Loader<RawContactsMetadata> loader, |
| RawContactsMetadata result) { |
| if (result == null) { |
| toastErrorAndFinish(); |
| return; |
| } |
| mResult = result; |
| onLoad(); |
| } |
| |
| @Override |
| public void onLoaderReset(Loader<RawContactsMetadata> loader) { |
| } |
| }; |
| |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| if (RequestPermissionsActivity.startPermissionActivityIfNeeded(this)) { |
| return; |
| } |
| |
| final Intent intent = getIntent(); |
| final String action = intent.getAction(); |
| |
| if (!Intent.ACTION_EDIT.equals(action)) { |
| finish(); |
| return; |
| } |
| // Just for shorter variable names. |
| final String primary = ContactEditorFragment.INTENT_EXTRA_MATERIAL_PALETTE_PRIMARY_COLOR; |
| final String secondary = |
| ContactEditorFragment.INTENT_EXTRA_MATERIAL_PALETTE_SECONDARY_COLOR; |
| if (intent.hasExtra(primary) && intent.hasExtra(secondary)) { |
| mMaterialPalette = new MaterialPalette(intent.getIntExtra(primary, -1), |
| intent.getIntExtra(secondary, -1)); |
| } |
| mShowReadOnly = intent.getBooleanExtra(EXTRA_SHOW_READ_ONLY, false); |
| |
| mUri = intent.getData(); |
| final String authority = mUri.getAuthority(); |
| final String type = getContentResolver().getType(mUri); |
| // Go straight to editor if we're passed a raw contact Uri. |
| if (ContactsContract.AUTHORITY.equals(authority) && |
| RawContacts.CONTENT_ITEM_TYPE.equals(type)) { |
| Logger.logEditorEvent( |
| EditorEvent.EventType.SHOW_RAW_CONTACT_PICKER, /* numberRawContacts */ 0); |
| final long rawContactId = ContentUris.parseId(mUri); |
| startEditorAndForwardExtras(getIntentForRawContact(rawContactId)); |
| } else if (android.provider.Contacts.AUTHORITY.equals(authority)) { |
| // Fail if given a legacy URI. |
| FeedbackHelper.sendFeedback(this, TAG, |
| "Legacy Uri was passed to editor.", new IllegalArgumentException()); |
| toastErrorAndFinish(); |
| } else { |
| getLoaderManager().initLoader(LOADER_RAW_CONTACTS, null, mRawContactLoaderListener); |
| } |
| } |
| |
| @Override |
| public void onPickRawContact(long rawContactId) { |
| startEditorAndForwardExtras(getIntentForRawContact(rawContactId)); |
| } |
| |
| /** |
| * Once the load is finished, decide whether to show the dialog or load the editor directly. |
| */ |
| private void onLoad() { |
| maybeTrimReadOnly(); |
| setHasWritableAccount(); |
| if (mShowReadOnly || (mResult.rawContacts.size() > 1 && mHasWritableAccount)) { |
| showDialog(); |
| } else { |
| loadEditor(); |
| } |
| } |
| |
| /** |
| * If not configured to show read only raw contact, trim them from the result. |
| */ |
| private void maybeTrimReadOnly() { |
| mResult.showReadOnly = mShowReadOnly; |
| if (mShowReadOnly) { |
| return; |
| } |
| |
| mResult.trimReadOnly(AccountTypeManager.getInstance(this)); |
| } |
| |
| /** |
| * Start the dialog to pick the raw contact to edit. |
| */ |
| private void showDialog() { |
| final FragmentManager fm = getFragmentManager(); |
| final SplitContactConfirmationDialogFragment split = |
| (SplitContactConfirmationDialogFragment) fm |
| .findFragmentByTag(SplitContactConfirmationDialogFragment.TAG); |
| // If we were showing the split confirmation before show it again. |
| if (split != null && split.isAdded()) { |
| fm.beginTransaction().show(split).commitAllowingStateLoss(); |
| return; |
| } |
| PickRawContactDialogFragment pick = (PickRawContactDialogFragment) fm |
| .findFragmentByTag(TAG_RAW_CONTACTS_DIALOG); |
| if (pick == null) { |
| pick = PickRawContactDialogFragment.getInstance(mResult); |
| final FragmentTransaction ft = fm.beginTransaction(); |
| ft.add(pick, TAG_RAW_CONTACTS_DIALOG); |
| // commitAllowingStateLoss is safe in this activity because the fragment entirely |
| // depends on the result of the loader. Even if we lose the fragment because the |
| // activity was in the background, when it comes back onLoadFinished will be called |
| // again which will have all the state the picker needs. This situation should be |
| // very rare, since the load should be quick. |
| ft.commitAllowingStateLoss(); |
| } |
| } |
| |
| /** |
| * Starts the editor for the only writable raw contact in the cursor if one exists. Otherwise, |
| * the editor is started normally and handles creation of a new writable raw contact. |
| */ |
| private void loadEditor() { |
| Logger.logEditorEvent( |
| EditorEvent.EventType.SHOW_RAW_CONTACT_PICKER, /* numberRawContacts */ 0); |
| final Intent intent; |
| if (mHasWritableAccount) { |
| intent = getIntentForRawContact(mResult.rawContacts.get(mWritableAccountPosition).id); |
| } else { |
| // If the contact has only read-only raw contacts, we'll want to let the editor create |
| // the writable raw contact for it. |
| intent = EditorIntents.createEditContactIntent(this, mUri, mMaterialPalette, -1); |
| intent.setClass(this, ContactEditorActivity.class); |
| } |
| startEditorAndForwardExtras(intent); |
| } |
| |
| /** |
| * Determines if this contact has a writable account. |
| */ |
| private void setHasWritableAccount() { |
| mWritableAccountPosition = mResult.getIndexOfFirstWritableAccount( |
| AccountTypeManager.getInstance(this)); |
| mHasWritableAccount = mWritableAccountPosition != -1; |
| } |
| |
| /** |
| * Returns an intent to load the editor for the given raw contact. Sets |
| * {@code FLAG_ACTIVITY_FORWARD_RESULT} in case the activity that started us expects a result. |
| * @param rawContactId Raw contact to edit |
| */ |
| private Intent getIntentForRawContact(long rawContactId) { |
| final Intent intent = EditorIntents.createEditContactIntentForRawContact( |
| this, mUri, rawContactId, mMaterialPalette); |
| intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); |
| return intent; |
| } |
| |
| /** |
| * Starts the given intent within the app, attaching any extras to it that were passed to us. |
| */ |
| private void startEditorAndForwardExtras(Intent intent) { |
| final Bundle extras = getIntent().getExtras(); |
| if (extras != null) { |
| intent.putExtras(extras); |
| } |
| ImplicitIntentsUtil.startActivityInApp(this, intent); |
| finish(); |
| } |
| |
| private void toastErrorAndFinish() { |
| Toast.makeText(ContactEditorSpringBoardActivity.this, |
| R.string.editor_failed_to_load, Toast.LENGTH_SHORT).show(); |
| setResult(RESULT_CANCELED, null); |
| finish(); |
| } |
| |
| @Override |
| protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
| // Ignore failed requests |
| if (resultCode != Activity.RESULT_OK) { |
| finish(); |
| } |
| if (data != null) { |
| final Intent intent = ContactSaveService.createJoinContactsIntent( |
| this, mResult.contactId, ContentUris.parseId(data.getData()), |
| QuickContactActivity.class, Intent.ACTION_VIEW); |
| startService(intent); |
| finish(); |
| } |
| } |
| |
| @Override |
| public void onSplitContactConfirmed(boolean hasPendingChanges) { |
| final long[][] rawContactIds = getRawContactIds(); |
| final Intent intent = ContactSaveService.createHardSplitContactIntent(this, rawContactIds); |
| startService(intent); |
| finish(); |
| } |
| |
| @Override |
| public void onSplitContactCanceled() { |
| finish(); |
| } |
| |
| @Override |
| protected void onSaveInstanceState(Bundle outState) { |
| super.onSaveInstanceState(outState); |
| outState.putParcelable(KEY_RAW_CONTACTS_METADATA, mResult); |
| } |
| |
| @Override |
| protected void onRestoreInstanceState(Bundle savedInstanceState) { |
| super.onRestoreInstanceState(savedInstanceState); |
| mResult = savedInstanceState.getParcelable(KEY_RAW_CONTACTS_METADATA); |
| } |
| |
| private long[][] getRawContactIds() { |
| final long[][] result = new long[mResult.rawContacts.size()][1]; |
| for (int i = 0; i < mResult.rawContacts.size(); i++) { |
| result[i][0] = mResult.rawContacts.get(i).id; |
| } |
| return result; |
| } |
| } |