blob: cf2ce9cffeda0fe318806bb3d8d5b8ec01ea6421 [file] [log] [blame]
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;
}
}