Merge "Add edit contact menu options to compact editor"
diff --git a/src/com/android/contacts/editor/CancelEditDialogFragment.java b/src/com/android/contacts/editor/CancelEditDialogFragment.java
new file mode 100644
index 0000000..300759e
--- /dev/null
+++ b/src/com/android/contacts/editor/CancelEditDialogFragment.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.contacts.editor;
+
+import com.android.contacts.R;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+/**
+ * Asks the user whether to cancel editing the contact.
+ */
+public class CancelEditDialogFragment extends DialogFragment {
+
+ private static final String TAG = "cancelEditor";
+
+ /**
+ * Shows a {@link CancelEditDialogFragment} after setting the given Fragment as the
+ * target of the dialog.
+ */
+ public static void show(ContactEditorBaseFragment fragment) {
+ final CancelEditDialogFragment dialog = new CancelEditDialogFragment();
+ dialog.setTargetFragment(fragment, 0);
+ dialog.show(fragment.getFragmentManager(), TAG);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return new AlertDialog.Builder(getActivity())
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setMessage(R.string.cancel_confirmation_dialog_message)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int which) {
+ final Listener targetListener = (Listener) getTargetFragment();
+ targetListener.onCancelEditConfirmed();
+ }
+ }
+ )
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ }
+
+ /**
+ * Callbacks for {@link CancelEditDialogFragment} hosts.
+ */
+ public interface Listener {
+
+ /**
+ * Invoked when the user confirms that they want to cancel editing the contact.
+ */
+ void onCancelEditConfirmed();
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index 46f50d2..aee1f73 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -20,7 +20,6 @@
import com.android.contacts.R;
import com.android.contacts.activities.ContactEditorBaseActivity.ContactEditor;
-import com.android.contacts.common.model.Contact;
import com.android.contacts.common.model.RawContact;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
@@ -28,7 +27,6 @@
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -41,18 +39,23 @@
implements ContactEditor {
@Override
- public void setListener(Listener listener) {
- mListener = listener;
- }
-
- @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ setHasOptionsMenu(true);
+
final View view = inflater.inflate(
R.layout.compact_contact_editor_fragment, container, false);
mContent = (LinearLayout) view.findViewById(R.id.editors);
return view;
}
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (mStatus == Status.SUB_ACTIVITY) {
+ mStatus = Status.EDITING;
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
//
// ContactEditorBaseFragment
//
@@ -75,22 +78,11 @@
protected void bindGroupMetaData() {
}
- @Override
- protected void bindMenuItemsForPhone(Contact contact) {
- }
-
//
// ContactEditor
//
@Override
- public void load(String action, Uri lookupUri, Bundle intentExtras) {
- mAction = action;
- mLookupUri = lookupUri;
- mIntentExtras = intentExtras;
- }
-
- @Override
public void setIntentExtras(Bundle extras) {
}
diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
index 70d5be2..4dcacca 100644
--- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
@@ -19,7 +19,9 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
+import com.android.contacts.ContactSaveService;
import com.android.contacts.GroupMetaDataLoader;
+import com.android.contacts.R;
import com.android.contacts.activities.ContactEditorAccountsChangedActivity;
import com.android.contacts.activities.ContactEditorBaseActivity;
import com.android.contacts.activities.ContactEditorBaseActivity.ContactEditor;
@@ -28,14 +30,18 @@
import com.android.contacts.common.model.ContactLoader;
import com.android.contacts.common.model.RawContact;
import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.quickcontact.QuickContactActivity;
+import com.android.contacts.util.HelpUtils;
+import com.android.contacts.util.PhoneCapabilityTester;
import android.accounts.Account;
import android.app.Activity;
import android.app.Fragment;
import android.app.LoaderManager;
+import android.content.ActivityNotFoundException;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
@@ -44,6 +50,7 @@
import android.content.Loader;
import android.database.Cursor;
import android.graphics.Rect;
+import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
@@ -53,7 +60,11 @@
import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsContract.RawContacts;
import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.widget.LinearLayout;
+import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
@@ -62,7 +73,7 @@
* Base Fragment for contact editors.
*/
abstract public class ContactEditorBaseFragment extends Fragment implements
- ContactEditor {
+ ContactEditor, SplitContactConfirmationDialogFragment.Listener {
protected static final String TAG = "ContactEditor";
@@ -88,11 +99,31 @@
private static final String KEY_IS_EDIT = "isEdit";
private static final String KEY_EXISTING_CONTACT_READY = "existingContactDataReady";
+ // Phone option menus
+ private static final String KEY_SEND_TO_VOICE_MAIL_STATE = "sendToVoicemailState";
+ private static final String KEY_ARE_PHONE_OPTIONS_CHANGEABLE = "arePhoneOptionsChangable";
+ private static final String KEY_CUSTOM_RINGTONE = "customRingtone";
+
+ private static final String KEY_IS_USER_PROFILE = "isUserProfile";
+
+ private static final String KEY_ENABLED = "enabled";
+
protected static final int REQUEST_CODE_JOIN = 0;
protected static final int REQUEST_CODE_ACCOUNTS_CHANGED = 1;
protected static final int REQUEST_CODE_PICK_RINGTONE = 2;
/**
+ * An intent extra that forces the editor to add the edited contact
+ * to the default group (e.g. "My Contacts").
+ */
+ public static final String INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY = "addToDefaultDirectory";
+
+ public static final String INTENT_EXTRA_NEW_LOCAL_PROFILE = "newLocalProfile";
+
+ public static final String INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION =
+ "disableDeleteMenuOption";
+
+ /**
* Callbacks for Activities that host contact editors Fragments.
*/
public interface Listener {
@@ -194,6 +225,16 @@
protected boolean mIsEdit;
protected boolean mExistingContactDataReady;
+ // Phone specific option menus
+ private boolean mSendToVoicemailState;
+ private boolean mArePhoneOptionsChangable;
+ private String mCustomRingtone;
+
+ protected boolean mIsUserProfile;
+
+ // Whether editors and options menu items are enabled
+ protected boolean mEnabled = true;
+
/**
* The contact data loader listener.
*/
@@ -297,6 +338,15 @@
mIsEdit = savedState.getBoolean(KEY_IS_EDIT);
mExistingContactDataReady = savedState.getBoolean(KEY_EXISTING_CONTACT_READY);
+
+ // Phone specific options menus
+ mSendToVoicemailState = savedState.getBoolean(KEY_SEND_TO_VOICE_MAIL_STATE);
+ mArePhoneOptionsChangable = savedState.getBoolean(KEY_ARE_PHONE_OPTIONS_CHANGEABLE);
+ mCustomRingtone = savedState.getString(KEY_CUSTOM_RINGTONE);
+
+ mIsUserProfile = savedState.getBoolean(KEY_IS_USER_PROFILE);
+
+ mEnabled = savedState.getBoolean(KEY_ENABLED);
}
// mState can still be null because it may not have have finished loading before
@@ -374,8 +424,7 @@
}
@Override
- public void
- onSaveInstanceState(Bundle outState) {
+ public void onSaveInstanceState(Bundle outState) {
outState.putString(KEY_ACTION, mAction);
outState.putParcelable(KEY_URI, mLookupUri);
outState.putBoolean(KEY_AUTO_ADD_TO_DEFAULT_GROUP, mAutoAddToDefaultGroup);
@@ -398,9 +447,220 @@
outState.putBoolean(KEY_IS_EDIT, mIsEdit);
outState.putBoolean(KEY_EXISTING_CONTACT_READY, mExistingContactDataReady);
+ // Phone specific options
+ outState.putBoolean(KEY_SEND_TO_VOICE_MAIL_STATE, mSendToVoicemailState);
+ outState.putBoolean(KEY_ARE_PHONE_OPTIONS_CHANGEABLE, mArePhoneOptionsChangable);
+ outState.putString(KEY_CUSTOM_RINGTONE, mCustomRingtone);
+
+ outState.putBoolean(KEY_IS_USER_PROFILE, mIsUserProfile);
+ outState.putBoolean(KEY_ENABLED, mEnabled);
+
super.onSaveInstanceState(outState);
}
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case REQUEST_CODE_ACCOUNTS_CHANGED: {
+ // Bail if the account selector was not successful.
+ if (resultCode != Activity.RESULT_OK) {
+ mListener.onReverted();
+ return;
+ }
+ // If there's an account specified, use it.
+ if (data != null) {
+ AccountWithDataSet account = data.getParcelableExtra(
+ Intents.Insert.EXTRA_ACCOUNT);
+ if (account != null) {
+ createContact(account);
+ return;
+ }
+ }
+ // If there isn't an account specified, then this is likely a phone-local
+ // contact, so we should continue setting up the editor by automatically selecting
+ // the most appropriate account.
+ createContact();
+ break;
+ }
+ case REQUEST_CODE_PICK_RINGTONE: {
+ if (data != null) {
+ final Uri pickedUri = data.getParcelableExtra(
+ RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
+ handleRingtonePicked(pickedUri);
+ }
+ break;
+ }
+ }
+ }
+
+ private void handleRingtonePicked(Uri pickedUri) {
+ if (pickedUri == null || RingtoneManager.isDefault(pickedUri)) {
+ mCustomRingtone = null;
+ } else {
+ mCustomRingtone = pickedUri.toString();
+ }
+ Intent intent = ContactSaveService.createSetRingtone(
+ mContext, mLookupUri, mCustomRingtone);
+ mContext.startService(intent);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
+ inflater.inflate(R.menu.edit_contact, menu);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ // This supports the keyboard shortcut to save changes to a contact but shouldn't be visible
+ // because the custom action bar contains the "save" button now (not the overflow menu).
+ // TODO: Find a better way to handle shortcuts, i.e. onKeyDown()?
+ final MenuItem doneMenu = menu.findItem(R.id.menu_done);
+ final MenuItem splitMenu = menu.findItem(R.id.menu_split);
+ final MenuItem joinMenu = menu.findItem(R.id.menu_join);
+ final MenuItem helpMenu = menu.findItem(R.id.menu_help);
+ final MenuItem discardMenu = menu.findItem(R.id.menu_discard);
+ final MenuItem sendToVoiceMailMenu = menu.findItem(R.id.menu_send_to_voicemail);
+ final MenuItem ringToneMenu = menu.findItem(R.id.menu_set_ringtone);
+ final MenuItem deleteMenu = menu.findItem(R.id.menu_delete);
+ deleteMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ deleteMenu.setIcon(R.drawable.ic_delete_white_24dp);
+
+ // Set visibility of menus
+ doneMenu.setVisible(false);
+
+ // Discard menu is only available if at least one raw contact is editable
+ discardMenu.setVisible(mState != null &&
+ mState.getFirstWritableRawContact(mContext) != null);
+
+ // help menu depending on whether this is inserting or editing
+ if (Intent.ACTION_INSERT.equals(mAction)) {
+ HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_add);
+ splitMenu.setVisible(false);
+ joinMenu.setVisible(false);
+ deleteMenu.setVisible(false);
+ } else if (Intent.ACTION_EDIT.equals(mAction)) {
+ HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_edit);
+ // Split only if more than one raw profile and not a user profile
+ splitMenu.setVisible(mState.size() > 1 && !isEditingUserProfile());
+ // Cannot join a user profile
+ joinMenu.setVisible(!isEditingUserProfile());
+ deleteMenu.setVisible(!mDisableDeleteMenuOption);
+ } else {
+ // something else, so don't show the help menu
+ helpMenu.setVisible(false);
+ }
+
+ // Hide telephony-related settings (ringtone, send to voicemail)
+ // if we don't have a telephone or are editing a new contact.
+ sendToVoiceMailMenu.setChecked(mSendToVoicemailState);
+ sendToVoiceMailMenu.setVisible(mArePhoneOptionsChangable);
+ ringToneMenu.setVisible(mArePhoneOptionsChangable);
+
+ int size = menu.size();
+ for (int i = 0; i < size; i++) {
+ menu.getItem(i).setEnabled(mEnabled);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ case R.id.menu_done:
+ return save(SaveMode.CLOSE);
+ case R.id.menu_discard:
+ return revert();
+ case R.id.menu_delete:
+ if (mListener != null) mListener.onDeleteRequested(mLookupUri);
+ return true;
+ case R.id.menu_split:
+ return doSplitContactAction();
+ case R.id.menu_join:
+ return doJoinContactAction();
+ case R.id.menu_set_ringtone:
+ doPickRingtone();
+ return true;
+ case R.id.menu_send_to_voicemail:
+ // Update state and save
+ mSendToVoicemailState = !mSendToVoicemailState;
+ item.setChecked(mSendToVoicemailState);
+ final Intent intent = ContactSaveService.createSetSendToVoicemail(
+ mContext, mLookupUri, mSendToVoicemailState);
+ mContext.startService(intent);
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean revert() {
+ if (mState.isEmpty() || !hasPendingChanges()) {
+ onSplitContactConfirmed();
+ } else {
+ CancelEditDialogFragment.show(this);
+ }
+ return true;
+ }
+
+ @Override
+ public void onSplitContactConfirmed() {
+ // When this Fragment is closed we don't want it to auto-save
+ mStatus = Status.CLOSING;
+ if (mListener != null) mListener.onReverted();
+ }
+
+ private boolean doSplitContactAction() {
+ if (!hasValidState()) return false;
+
+ SplitContactConfirmationDialogFragment.show(this);
+ return true;
+ }
+
+ private boolean doJoinContactAction() {
+ if (!hasValidState()) {
+ return false;
+ }
+
+ // If we just started creating a new contact and haven't added any data, it's too
+ // early to do a join
+ if (mState.size() == 1 && mState.get(0).isContactInsert() && !hasPendingChanges()) {
+ Toast.makeText(mContext, R.string.toast_join_with_empty_contact,
+ Toast.LENGTH_LONG).show();
+ return true;
+ }
+
+ return save(SaveMode.JOIN);
+ }
+
+ private void doPickRingtone() {
+ final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
+ // Allow user to pick 'Default'
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
+ // Show only ringtones
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE);
+ // Allow the user to pick a silent ringtone
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
+
+ final Uri ringtoneUri;
+ if (mCustomRingtone != null) {
+ ringtoneUri = Uri.parse(mCustomRingtone);
+ } else {
+ // Otherwise pick default ringtone Uri so that something is selected.
+ ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
+ }
+
+ // Put checkmark next to the current ringtone for this contact
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, ringtoneUri);
+
+ // Launch!
+ try {
+ startActivityForResult(intent, REQUEST_CODE_PICK_RINGTONE);
+ } catch (ActivityNotFoundException ex) {
+ Toast.makeText(mContext, R.string.missing_app, Toast.LENGTH_SHORT).show();
+ }
+ }
+
/**
* Check if our internal {@link #mState} is valid, usually checked before
* performing user actions.
@@ -409,52 +669,17 @@
return mState.size() > 0;
}
- private void setData(Contact contact) {
+ protected boolean isEditingUserProfile() {
+ return mNewLocalProfile || mIsUserProfile;
+ }
- // If we have already loaded data, we do not want to change it here to not confuse the user
- if (!mState.isEmpty()) {
- Log.v(TAG, "Ignoring background change. This will have to be rebased later");
- return;
- }
-
- // See if this edit operation needs to be redirected to a custom editor
- mRawContacts = contact.getRawContacts();
- if (mRawContacts.size() == 1) {
- RawContact rawContact = mRawContacts.get(0);
- String type = rawContact.getAccountTypeString();
- String dataSet = rawContact.getDataSet();
- AccountType accountType = rawContact.getAccountType(mContext);
- if (accountType.getEditContactActivityClassName() != null &&
- !accountType.areContactsWritable()) {
- if (mListener != null) {
- String name = rawContact.getAccountName();
- long rawContactId = rawContact.getId();
- mListener.onCustomEditContactActivityRequested(
- new AccountWithDataSet(name, type, dataSet),
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
- mIntentExtras, true);
- }
- return;
- }
- }
-
- String displayName = null;
- // Check for writable raw contacts. If there are none, then we need to create one so user
- // can edit. For the user profile case, there is already an editable contact.
- if (!contact.isUserProfile() && !contact.isWritableContact(mContext)) {
- mHasNewContact = true;
-
- // This is potentially an asynchronous call and will add deltas to list.
- selectAccountAndCreateContact();
- displayName = contact.getDisplayName();
- }
-
- // This also adds deltas to list
- // If displayName is null at this point it is simply ignored later on by the editor.
- bindEditorsForExistingContact(displayName, contact.isUserProfile(),
- mRawContacts);
-
- bindMenuItemsForPhone(contact);
+ /**
+ * Return true if there are any edits to the current contact which need to
+ * be saved.
+ */
+ protected boolean hasPendingChanges() {
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
+ return RawContactModifier.hasChanges(mState, accountTypes);
}
//
@@ -519,6 +744,67 @@
}
}
+ //
+ // Data binding
+ //
+
+ private void setData(Contact contact) {
+
+ // If we have already loaded data, we do not want to change it here to not confuse the user
+ if (!mState.isEmpty()) {
+ Log.v(TAG, "Ignoring background change. This will have to be rebased later");
+ return;
+ }
+
+ // See if this edit operation needs to be redirected to a custom editor
+ mRawContacts = contact.getRawContacts();
+ if (mRawContacts.size() == 1) {
+ RawContact rawContact = mRawContacts.get(0);
+ String type = rawContact.getAccountTypeString();
+ String dataSet = rawContact.getDataSet();
+ AccountType accountType = rawContact.getAccountType(mContext);
+ if (accountType.getEditContactActivityClassName() != null &&
+ !accountType.areContactsWritable()) {
+ if (mListener != null) {
+ String name = rawContact.getAccountName();
+ long rawContactId = rawContact.getId();
+ mListener.onCustomEditContactActivityRequested(
+ new AccountWithDataSet(name, type, dataSet),
+ ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
+ mIntentExtras, true);
+ }
+ return;
+ }
+ }
+
+ String displayName = null;
+ // Check for writable raw contacts. If there are none, then we need to create one so user
+ // can edit. For the user profile case, there is already an editable contact.
+ if (!contact.isUserProfile() && !contact.isWritableContact(mContext)) {
+ mHasNewContact = true;
+
+ // This is potentially an asynchronous call and will add deltas to list.
+ selectAccountAndCreateContact();
+ displayName = contact.getDisplayName();
+ }
+
+ // This also adds deltas to list
+ // If displayName is null at this point it is simply ignored later on by the editor.
+ bindEditorsForExistingContact(displayName, contact.isUserProfile(),
+ mRawContacts);
+
+ bindMenuItemsForPhone(contact);
+ }
+
+ private void bindMenuItemsForPhone(Contact contact) {
+ if (contact != null) {
+ mSendToVoicemailState = contact.isSendToVoicemail();
+ mCustomRingtone = contact.getCustomRingtone();
+ mArePhoneOptionsChangable = !contact.isDirectoryEntry()
+ && PhoneCapabilityTester.isPhone(mContext);
+ }
+ }
+
// TODO: add javadocs after these are finalized
abstract protected void bindEditorsForExistingContact(String displayName, boolean isUserProfile,
ImmutableList<RawContact> rawContacts);
@@ -526,8 +812,31 @@
final AccountType accountType);
abstract protected void bindEditors();
abstract protected void bindGroupMetaData();
- // TODO: should be removed after options menu is moved to base
- abstract protected void bindMenuItemsForPhone(Contact contact);
+
+ //
+ // ContactEditor
+ //
+
+ @Override
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void load(String action, Uri lookupUri, Bundle intentExtras) {
+ mAction = action;
+ mLookupUri = lookupUri;
+ mIntentExtras = intentExtras;
+
+ if (mIntentExtras != null) {
+ mAutoAddToDefaultGroup =
+ mIntentExtras.containsKey(INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY);
+ mNewLocalProfile =
+ mIntentExtras.getBoolean(INTENT_EXTRA_NEW_LOCAL_PROFILE);
+ mDisableDeleteMenuOption =
+ mIntentExtras.getBoolean(INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION);
+ }
+ }
/**
* Returns a legacy version of the given contactLookupUri if a legacy Uri was originally
@@ -537,7 +846,6 @@
* @param requestLookupUri The lookup Uri originally passed to the contact editor
* (via Intent data), may be null.
*/
- // TODO: move to ContactEditorUtils?
protected static Uri maybeConvertToLegacyLookupUri(Context context, Uri contactLookupUri,
Uri requestLookupUri) {
final String legacyAuthority = "contacts";
@@ -558,7 +866,6 @@
* Creates the result Intent for the given contactLookupUri that should started after a
* successful saving a contact.
*/
- // TODO: move to ContactEditorUtils?
protected static Intent composeQuickContactsIntent(Context context, Uri contactLookupUri) {
final Intent intent = QuickContact.composeQuickContactsIntent(
context, (Rect) null, contactLookupUri, QuickContactActivity.MODE_FULLY_EXPANDED,
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 6639e1b..7fb4378 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -20,7 +20,6 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
-import android.content.ActivityNotFoundException;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
@@ -40,9 +39,6 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
@@ -57,7 +53,6 @@
import com.android.contacts.activities.ContactEditorActivity;
import com.android.contacts.activities.ContactEditorBaseActivity.ContactEditor;
import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.Contact;
import com.android.contacts.common.model.RawContact;
import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.RawContactDeltaList;
@@ -72,8 +67,6 @@
import com.android.contacts.editor.Editor.EditorListener;
import com.android.contacts.list.UiIntentActions;
import com.android.contacts.util.ContactPhotoUtils;
-import com.android.contacts.util.HelpUtils;
-import com.android.contacts.util.PhoneCapabilityTester;
import com.android.contacts.util.UiClosables;
import com.google.common.collect.ImmutableList;
@@ -92,21 +85,12 @@
AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener,
RawContactReadOnlyEditorView.Listener {
- // Phone option menus
- private static final String KEY_SEND_TO_VOICE_MAIL_STATE = "sendToVoicemailState";
- private static final String KEY_ARE_PHONE_OPTIONS_CHANGEABLE = "arePhoneOptionsChangable";
- private static final String KEY_CUSTOM_RINGTONE = "customRingtone";
-
// Joins
private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
private static final String KEY_CONTACT_WRITABLE_FOR_JOIN = "contactwritableforjoin";
private static final String KEY_EXPANDED_EDITORS = "expandedEditors";
- private static final String KEY_IS_USER_PROFILE = "isUserProfile";
-
- private static final String KEY_ENABLED = "enabled";
-
// Photos
private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
private static final String KEY_CURRENT_PHOTO_URI = "currentphotouri";
@@ -118,17 +102,6 @@
public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
- /**
- * An intent extra that forces the editor to add the edited contact
- * to the default group (e.g. "My Contacts").
- */
- public static final String INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY = "addToDefaultDirectory";
-
- public static final String INTENT_EXTRA_NEW_LOCAL_PROFILE = "newLocalProfile";
-
- public static final String INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION =
- "disableDeleteMenuOption";
-
//
// Helpers
//
@@ -137,11 +110,6 @@
//
// Contact editor state
//
- // Phone specific option menus
- private boolean mSendToVoicemailState;
- private boolean mArePhoneOptionsChangable;
- private String mCustomRingtone;
-
// Joins
private long mContactIdForJoin;
private boolean mContactWritableForJoin;
@@ -149,11 +117,6 @@
// Used to store which raw contact editors have been expanded. Keyed on raw contact ids.
private HashMap<Long, Boolean> mExpandedEditors = new HashMap<Long, Boolean>();
- private boolean mIsUserProfile = false;
-
- // Whether editors and options menu items are enabled
- private boolean mEnabled = true;
-
// Whether the name editor should receive focus after being bound
private boolean mRequestFocus;
@@ -295,33 +258,10 @@
}
@Override
- public void load(String action, Uri lookupUri, Bundle intentExtras) {
- mAction = action;
- mLookupUri = lookupUri;
- mIntentExtras = intentExtras;
- mAutoAddToDefaultGroup = mIntentExtras != null
- && mIntentExtras.containsKey(INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY);
- mNewLocalProfile = mIntentExtras != null
- && mIntentExtras.getBoolean(INTENT_EXTRA_NEW_LOCAL_PROFILE);
- mDisableDeleteMenuOption = mIntentExtras != null
- && mIntentExtras.getBoolean(INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION);
- }
-
- @Override
- public void setListener(Listener value) {
- mListener = value;
- }
-
- @Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
if (savedState != null) {
- // Phone specific options menus
- mSendToVoicemailState = savedState.getBoolean(KEY_SEND_TO_VOICE_MAIL_STATE);
- mArePhoneOptionsChangable = savedState.getBoolean(KEY_ARE_PHONE_OPTIONS_CHANGEABLE);
- mCustomRingtone = savedState.getString(KEY_CUSTOM_RINGTONE);
-
// Joins
mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN);
@@ -329,10 +269,6 @@
mExpandedEditors = (HashMap<Long, Boolean>)
savedState.getSerializable(KEY_EXPANDED_EDITORS);
- mIsUserProfile = savedState.getBoolean(KEY_IS_USER_PROFILE);
-
- mEnabled = savedState.getBoolean(KEY_ENABLED);
-
// NOTE: mRequestFocus and mDefaultDisplayName are not saved/restored
// Photos
@@ -397,20 +333,6 @@
}
@Override
- protected void bindMenuItemsForPhone(Contact contact) {
- mSendToVoicemailState = contact.isSendToVoicemail();
- mCustomRingtone = contact.getCustomRingtone();
- mArePhoneOptionsChangable = arePhoneOptionsChangable(contact);
- }
-
- private boolean arePhoneOptionsChangable(Contact contact) {
- return contact != null && !contact.isDirectoryEntry()
- && PhoneCapabilityTester.isPhone(mContext);
- }
-
- /**
- * Merges extras from the intent.
- */
public void setIntentExtras(Bundle extras) {
if (extras == null || extras.size() == 0) {
return;
@@ -786,130 +708,6 @@
}
@Override
- public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
- inflater.inflate(R.menu.edit_contact, menu);
- }
-
- @Override
- public void onPrepareOptionsMenu(Menu menu) {
- // This supports the keyboard shortcut to save changes to a contact but shouldn't be visible
- // because the custom action bar contains the "save" button now (not the overflow menu).
- // TODO: Find a better way to handle shortcuts, i.e. onKeyDown()?
- final MenuItem doneMenu = menu.findItem(R.id.menu_done);
- final MenuItem splitMenu = menu.findItem(R.id.menu_split);
- final MenuItem joinMenu = menu.findItem(R.id.menu_join);
- final MenuItem helpMenu = menu.findItem(R.id.menu_help);
- final MenuItem discardMenu = menu.findItem(R.id.menu_discard);
- final MenuItem sendToVoiceMailMenu = menu.findItem(R.id.menu_send_to_voicemail);
- final MenuItem ringToneMenu = menu.findItem(R.id.menu_set_ringtone);
- final MenuItem deleteMenu = menu.findItem(R.id.menu_delete);
- deleteMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
- deleteMenu.setIcon(R.drawable.ic_delete_white_24dp);
-
- // Set visibility of menus
- doneMenu.setVisible(false);
-
- // Discard menu is only available if at least one raw contact is editable
- discardMenu.setVisible(mState != null &&
- mState.getFirstWritableRawContact(mContext) != null);
-
- // help menu depending on whether this is inserting or editing
- if (Intent.ACTION_INSERT.equals(mAction)) {
- HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_add);
- splitMenu.setVisible(false);
- joinMenu.setVisible(false);
- deleteMenu.setVisible(false);
- } else if (Intent.ACTION_EDIT.equals(mAction)) {
- HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_edit);
- // Split only if more than one raw profile and not a user profile
- splitMenu.setVisible(mState.size() > 1 && !isEditingUserProfile());
- // Cannot join a user profile
- joinMenu.setVisible(!isEditingUserProfile());
- deleteMenu.setVisible(!mDisableDeleteMenuOption);
- } else {
- // something else, so don't show the help menu
- helpMenu.setVisible(false);
- }
-
- // Hide telephony-related settings (ringtone, send to voicemail)
- // if we don't have a telephone or are editing a new contact.
- sendToVoiceMailMenu.setChecked(mSendToVoicemailState);
- sendToVoiceMailMenu.setVisible(mArePhoneOptionsChangable);
- ringToneMenu.setVisible(mArePhoneOptionsChangable);
-
- int size = menu.size();
- for (int i = 0; i < size; i++) {
- menu.getItem(i).setEnabled(mEnabled);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- case R.id.menu_done:
- return save(SaveMode.CLOSE);
- case R.id.menu_discard:
- return revert();
- case R.id.menu_delete:
- if (mListener != null) mListener.onDeleteRequested(mLookupUri);
- return true;
- case R.id.menu_split:
- return doSplitContactAction();
- case R.id.menu_join:
- return doJoinContactAction();
- case R.id.menu_set_ringtone:
- doPickRingtone();
- return true;
- case R.id.menu_send_to_voicemail:
- // Update state and save
- mSendToVoicemailState = !mSendToVoicemailState;
- item.setChecked(mSendToVoicemailState);
- final Intent intent = ContactSaveService.createSetSendToVoicemail(
- mContext, mLookupUri, mSendToVoicemailState);
- mContext.startService(intent);
- return true;
- }
-
- return false;
- }
-
- private boolean doSplitContactAction() {
- if (!hasValidState()) return false;
-
- final SplitContactConfirmationDialogFragment dialog =
- new SplitContactConfirmationDialogFragment();
- dialog.setTargetFragment(this, 0);
- dialog.show(getFragmentManager(), SplitContactConfirmationDialogFragment.TAG);
- return true;
- }
-
- private boolean doJoinContactAction() {
- if (!hasValidState()) {
- return false;
- }
-
- // If we just started creating a new contact and haven't added any data, it's too
- // early to do a join
- if (mState.size() == 1 && mState.get(0).isContactInsert() && !hasPendingChanges()) {
- Toast.makeText(mContext, R.string.toast_join_with_empty_contact,
- Toast.LENGTH_LONG).show();
- return true;
- }
-
- return save(SaveMode.JOIN);
- }
-
- /**
- * Return true if there are any edits to the current contact which need to
- * be saved.
- */
- private boolean hasPendingChanges() {
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
- return RawContactModifier.hasChanges(mState, accountTypes);
- }
-
- @Override
public boolean save(int saveMode) {
if (!hasValidState() || mStatus != Status.EDITING) {
return false;
@@ -951,88 +749,6 @@
return true;
}
- private void doPickRingtone() {
-
- final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
- // Allow user to pick 'Default'
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
- // Show only ringtones
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE);
- // Allow the user to pick a silent ringtone
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
-
- final Uri ringtoneUri;
- if (mCustomRingtone != null) {
- ringtoneUri = Uri.parse(mCustomRingtone);
- } else {
- // Otherwise pick default ringtone Uri so that something is selected.
- ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
- }
-
- // Put checkmark next to the current ringtone for this contact
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, ringtoneUri);
-
- // Launch!
- try {
- startActivityForResult(intent, REQUEST_CODE_PICK_RINGTONE);
- } catch (ActivityNotFoundException ex) {
- Toast.makeText(mContext, R.string.missing_app, Toast.LENGTH_SHORT).show();
- }
- }
-
- private void handleRingtonePicked(Uri pickedUri) {
- if (pickedUri == null || RingtoneManager.isDefault(pickedUri)) {
- mCustomRingtone = null;
- } else {
- mCustomRingtone = pickedUri.toString();
- }
- Intent intent = ContactSaveService.createSetRingtone(
- mContext, mLookupUri, mCustomRingtone);
- mContext.startService(intent);
- }
-
- public static class CancelEditDialogFragment extends DialogFragment {
-
- public static void show(ContactEditorFragment fragment) {
- CancelEditDialogFragment dialog = new CancelEditDialogFragment();
- dialog.setTargetFragment(fragment, 0);
- dialog.show(fragment.getFragmentManager(), "cancelEditor");
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- AlertDialog dialog = new AlertDialog.Builder(getActivity())
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setMessage(R.string.cancel_confirmation_dialog_message)
- .setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int whichButton) {
- ((ContactEditorFragment)getTargetFragment()).doRevertAction();
- }
- }
- )
- .setNegativeButton(android.R.string.cancel, null)
- .create();
- return dialog;
- }
- }
-
- private boolean revert() {
- if (mState.isEmpty() || !hasPendingChanges()) {
- doRevertAction();
- } else {
- CancelEditDialogFragment.show(this);
- }
- return true;
- }
-
- private void doRevertAction() {
- // When this Fragment is closed we don't want it to auto-save
- mStatus = Status.CLOSING;
- if (mListener != null) mListener.onReverted();
- }
-
@Override
public void onJoinCompleted(Uri uri) {
onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri);
@@ -1137,10 +853,6 @@
return false;
}
- private boolean isEditingUserProfile() {
- return mNewLocalProfile || mIsUserProfile;
- }
-
/**
* Returns the contact ID for the currently edited contact or 0 if the contact is new.
*/
@@ -1332,18 +1044,11 @@
@Override
public void onSaveInstanceState(Bundle outState) {
- // Phone specific options
- outState.putBoolean(KEY_SEND_TO_VOICE_MAIL_STATE, mSendToVoicemailState);
- outState.putBoolean(KEY_ARE_PHONE_OPTIONS_CHANGEABLE, mArePhoneOptionsChangable);
- outState.putString(KEY_CUSTOM_RINGTONE, mCustomRingtone);
-
// Joins
outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin);
outState.putSerializable(KEY_EXPANDED_EDITORS, mExpandedEditors);
- outState.putBoolean(KEY_IS_USER_PROFILE, mIsUserProfile);
- outState.putBoolean(KEY_ENABLED, mEnabled);
// Photos
outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
@@ -1379,33 +1084,8 @@
}
break;
}
- case REQUEST_CODE_ACCOUNTS_CHANGED: {
- // Bail if the account selector was not successful.
- if (resultCode != Activity.RESULT_OK) {
- mListener.onReverted();
- return;
- }
- // If there's an account specified, use it.
- if (data != null) {
- AccountWithDataSet account = data.getParcelableExtra(
- Intents.Insert.EXTRA_ACCOUNT);
- if (account != null) {
- createContact(account);
- return;
- }
- }
- // If there isn't an account specified, then this is likely a phone-local
- // contact, so we should continue setting up the editor by automatically selecting
- // the most appropriate account.
- createContact();
- break;
- }
- case REQUEST_CODE_PICK_RINGTONE: {
- if (data != null) {
- final Uri pickedUri = data.getParcelableExtra(
- RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
- handleRingtonePicked(pickedUri);
- }
+ default: {
+ super.onActivityResult(requestCode, resultCode, data);
break;
}
}
diff --git a/src/com/android/contacts/editor/SplitContactConfirmationDialogFragment.java b/src/com/android/contacts/editor/SplitContactConfirmationDialogFragment.java
index c790e0b..b4181b8 100644
--- a/src/com/android/contacts/editor/SplitContactConfirmationDialogFragment.java
+++ b/src/com/android/contacts/editor/SplitContactConfirmationDialogFragment.java
@@ -34,7 +34,11 @@
public class SplitContactConfirmationDialogFragment extends DialogFragment {
public static final String TAG = "SplitContactConfirmationDialog";
- public SplitContactConfirmationDialogFragment() {
+ public static void show(ContactEditorBaseFragment fragment) {
+ SplitContactConfirmationDialogFragment dialog = new
+ SplitContactConfirmationDialogFragment();
+ dialog.setTargetFragment(fragment, 0);
+ dialog.show(fragment.getFragmentManager(), "splitContact");
}
@Override