diff options
author | Walter Jang <wjang@google.com> | 2015-02-05 13:41:43 -0800 |
---|---|---|
committer | Walter Jang <wjang@google.com> | 2015-02-05 15:23:13 -0800 |
commit | 3e9a62449b8ca3a38b1d51019c6ea13972263bc2 (patch) | |
tree | b5d4ea5eee637909dd9f0f5b0bfe341c1935aa2e /src | |
parent | 1eb21f12372b31794ef5a567013c1d2d98081120 (diff) | |
download | packages_apps_Contacts-3e9a62449b8ca3a38b1d51019c6ea13972263bc2.tar.gz packages_apps_Contacts-3e9a62449b8ca3a38b1d51019c6ea13972263bc2.tar.bz2 packages_apps_Contacts-3e9a62449b8ca3a38b1d51019c6ea13972263bc2.zip |
Move suggest joins popup & activiy to BaseEditContactFragment
Bug 19124091
Change-Id: Ic5a6b8b6359dc9691cfcac2348ba895c542d05d9
Diffstat (limited to 'src')
5 files changed, 519 insertions, 476 deletions
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java index fbde8c9d3..4291f9116 100644 --- a/src/com/android/contacts/editor/CompactContactEditorFragment.java +++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java @@ -75,25 +75,4 @@ public class CompactContactEditorFragment extends ContactEditorBaseFragment onSaveCompleted(/* hadChanges =*/ false, SaveMode.RELOAD, /* saveSucceeded =*/ uri != null, uri); } - - @Override - public void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded, - Uri contactLookupUri) { - switch (saveMode) { - case SaveMode.CLOSE: - case SaveMode.HOME: - if (mListener != null) { - final Intent resultIntent; - if (saveSucceeded && contactLookupUri != null) { - final Uri lookupUri = maybeConvertToLegacyLookupUri( - mContext, contactLookupUri, mLookupUri); - resultIntent = composeQuickContactsIntent(mContext, lookupUri); - } else { - resultIntent = null; - } - mListener.onSaveFinished(resultIntent); - } - break; - } - } } diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java index e1a841a39..d4f5a5a41 100644 --- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java +++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java @@ -23,6 +23,7 @@ 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.ContactEditorActivity; import com.android.contacts.activities.ContactEditorBaseActivity; import com.android.contacts.activities.ContactEditorBaseActivity.ContactEditor; import com.android.contacts.common.model.AccountTypeManager; @@ -35,9 +36,12 @@ import com.android.contacts.common.model.RawContactModifier; import com.android.contacts.common.model.ValuesDelta; import com.android.contacts.common.model.account.AccountType; import com.android.contacts.common.model.account.AccountWithDataSet; +import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion; +import com.android.contacts.list.UiIntentActions; import com.android.contacts.quickcontact.QuickContactActivity; import com.android.contacts.util.HelpUtils; import com.android.contacts.util.PhoneCapabilityTester; +import com.android.contacts.util.UiClosables; import android.accounts.Account; import android.app.Activity; @@ -66,11 +70,16 @@ import android.provider.ContactsContract.Intents; import android.provider.ContactsContract.QuickContact; import android.provider.ContactsContract.RawContacts; 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; +import android.widget.BaseAdapter; import android.widget.LinearLayout; +import android.widget.ListPopupWindow; import android.widget.Toast; import java.util.ArrayList; @@ -80,7 +89,8 @@ import java.util.List; * Base Fragment for contact editors. */ abstract public class ContactEditorBaseFragment extends Fragment implements - ContactEditor, SplitContactConfirmationDialogFragment.Listener { + ContactEditor, SplitContactConfirmationDialogFragment.Listener, + AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener { protected static final String TAG = "ContactEditor"; @@ -115,6 +125,14 @@ abstract public class ContactEditorBaseFragment extends Fragment implements private static final String KEY_ENABLED = "enabled"; + // Aggregation PopupWindow + private static final String KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID = + "aggregationSuggestionsRawContactId"; + + // Join Activity + private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin"; + private static final String KEY_CONTACT_WRITABLE_FOR_JOIN = "contactwritableforjoin"; + 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; @@ -189,6 +207,52 @@ abstract public class ContactEditorBaseFragment extends Fragment implements void onDeleteRequested(Uri contactUri); } + /** + * Adapter for aggregation suggestions displayed in a PopupWindow when + * editor fields change. + */ + protected static final class AggregationSuggestionAdapter extends BaseAdapter { + private final LayoutInflater mLayoutInflater; + private final boolean mSetNewContact; + private final AggregationSuggestionView.Listener mListener; + private final List<AggregationSuggestionEngine.Suggestion> mSuggestions; + + public AggregationSuggestionAdapter(Activity activity, boolean setNewContact, + AggregationSuggestionView.Listener listener, List<Suggestion> suggestions) { + mLayoutInflater = activity.getLayoutInflater(); + mSetNewContact = setNewContact; + mListener = listener; + mSuggestions = suggestions; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final Suggestion suggestion = (Suggestion) getItem(position); + final AggregationSuggestionView suggestionView = + (AggregationSuggestionView) mLayoutInflater.inflate( + R.layout.aggregation_suggestions_item, null); + suggestionView.setNewContact(mSetNewContact); + suggestionView.setListener(mListener); + suggestionView.bindSuggestion(suggestion); + return suggestionView; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public Object getItem(int position) { + return mSuggestions.get(position); + } + + @Override + public int getCount() { + return mSuggestions.size(); + } + } + protected Context mContext; protected Listener mListener; @@ -197,6 +261,7 @@ abstract public class ContactEditorBaseFragment extends Fragment implements // protected LinearLayout mContent; protected View mAggregationSuggestionView; + protected ListPopupWindow mAggregationSuggestionPopup; // // Parameters passed in on {@link #load} @@ -214,6 +279,7 @@ abstract public class ContactEditorBaseFragment extends Fragment implements protected ContactEditorUtils mEditorUtils; protected RawContactDeltaComparator mComparator; protected ViewIdGenerator mViewIdGenerator; + private AggregationSuggestionEngine mAggregationSuggestionEngine; // // Loaded data @@ -248,6 +314,13 @@ abstract public class ContactEditorBaseFragment extends Fragment implements // Whether editor views and options menu items should be enabled private boolean mEnabled = true; + // Aggregation PopupWindow + private long mAggregationSuggestionsRawContactId; + + // Join Activity + private long mContactIdForJoin; + private boolean mContactWritableForJoin; + // // Editor state for {@link ContactEditorView}. // (Not saved/restored on rotates) @@ -372,6 +445,14 @@ abstract public class ContactEditorBaseFragment extends Fragment implements mCustomRingtone = savedState.getString(KEY_CUSTOM_RINGTONE); mEnabled = savedState.getBoolean(KEY_ENABLED); + + // Aggregation PopupWindow + mAggregationSuggestionsRawContactId = savedState.getLong( + KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID); + + // Join Activity + mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN); + mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN); } // mState can still be null because it may not have have finished loading before @@ -481,12 +562,49 @@ abstract public class ContactEditorBaseFragment extends Fragment implements outState.putBoolean(KEY_ENABLED, mEnabled); + // Aggregation PopupWindow + outState.putLong(KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID, + mAggregationSuggestionsRawContactId); + + // Join Activity + outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin); + outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin); + super.onSaveInstanceState(outState); } @Override + public void onStop() { + super.onStop(); + + UiClosables.closeQuietly(mAggregationSuggestionPopup); + + // If anything was left unsaved, save it now but keep the editor open. + if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) { + save(SaveMode.RELOAD); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (mAggregationSuggestionEngine != null) { + mAggregationSuggestionEngine.quit(); + } + } + + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { + case REQUEST_CODE_JOIN: { + // Ignore failed requests + if (resultCode != Activity.RESULT_OK) return; + if (data != null) { + final long contactId = ContentUris.parseId(data.getData()); + joinAggregate(contactId); + } + break; + } case REQUEST_CODE_ACCOUNTS_CHANGED: { // Bail if the account selector was not successful. if (resultCode != Activity.RESULT_OK) { @@ -643,9 +761,17 @@ abstract public class ContactEditorBaseFragment extends Fragment implements @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(); + if (mState.isEmpty()) { + // This may happen when this Fragment is recreated by the system during users + // confirming the split action (and thus this method is called just before onCreate()), + // for example. + Log.e(TAG, "mState became null during the user's confirming split action. " + + "Cannot perform the save action."); + return; + } + + mState.markRawContactsForSplitting(); + save(SaveMode.SPLIT);; } private boolean doSplitContactAction() { @@ -947,7 +1073,7 @@ abstract public class ContactEditorBaseFragment extends Fragment implements } /** - * Bind editors using {@link #mState} and other members intialized from the loaded (or new) + * Bind editors using {@link #mState} and other members initialized from the loaded (or new) * Contact. */ abstract void bindEditors(); @@ -1008,6 +1134,268 @@ abstract public class ContactEditorBaseFragment extends Fragment implements } } + @Override + public void onJoinCompleted(Uri uri) { + onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri); + } + + @Override + public void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded, + Uri contactLookupUri) { + if (hadChanges) { + if (saveSucceeded) { + if (saveMode != SaveMode.JOIN) { + Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show(); + } + } + switch (saveMode) { + case SaveMode.CLOSE: + case SaveMode.HOME: + final Intent resultIntent; + if (saveSucceeded && contactLookupUri != null) { + final Uri lookupUri = maybeConvertToLegacyLookupUri( + mContext, contactLookupUri, mLookupUri); + resultIntent = composeQuickContactsIntent(mContext, lookupUri); + } else { + resultIntent = null; + } + // It is already saved, so prevent that it is saved again + mStatus = Status.CLOSING; + if (mListener != null) mListener.onSaveFinished(resultIntent); + break; + + case SaveMode.RELOAD: + case SaveMode.JOIN: + if (saveSucceeded && contactLookupUri != null) { + // If it was a JOIN, we are now ready to bring up the join activity. + if (saveMode == SaveMode.JOIN && hasValidState()) { + showJoinAggregateActivity(contactLookupUri); + } + + // If this was in INSERT, we are changing into an EDIT now. + // If it already was an EDIT, we are changing to the new Uri now + mState = new RawContactDeltaList(); + load(Intent.ACTION_EDIT, contactLookupUri, null); + mStatus = Status.LOADING; + getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener); + } + break; + + case SaveMode.SPLIT: + mStatus = Status.CLOSING; + if (mListener != null) { + mListener.onContactSplit(contactLookupUri); + } else { + Log.d(TAG, "No listener registered, can not call onSplitFinished"); + } + break; + } + } + + /** + * Shows a list of aggregates that can be joined into the currently viewed aggregate. + * + * @param contactLookupUri the fresh URI for the currently edited contact (after saving it) + */ + private void showJoinAggregateActivity(Uri contactLookupUri) { + if (contactLookupUri == null || !isAdded()) { + return; + } + + mContactIdForJoin = ContentUris.parseId(contactLookupUri); + mContactWritableForJoin = isContactWritable(); + final Intent intent = new Intent(UiIntentActions.PICK_JOIN_CONTACT_ACTION); + intent.putExtra(UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY, mContactIdForJoin); + startActivityForResult(intent, REQUEST_CODE_JOIN); + } + + /** + * Returns true if there is at least one writable raw contact in the current contact. + */ + private boolean isContactWritable() { + final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); + int size = mState.size(); + for (int i = 0; i < size; i++) { + RawContactDelta entity = mState.get(i); + final AccountType type = entity.getAccountType(accountTypes); + if (type.areContactsWritable()) { + return true; + } + } + return false; + } + + // + // Aggregation PopupWindow + // + + /** + * Triggers an asynchronous search for aggregation suggestions. + */ + protected void acquireAggregationSuggestions(Context context, + RawContactEditorView rawContactEditor) { + long rawContactId = rawContactEditor.getRawContactId(); + if (mAggregationSuggestionsRawContactId != rawContactId + && mAggregationSuggestionView != null) { + mAggregationSuggestionView.setVisibility(View.GONE); + mAggregationSuggestionView = null; + mAggregationSuggestionEngine.reset(); + } + + mAggregationSuggestionsRawContactId = rawContactId; + + if (mAggregationSuggestionEngine == null) { + mAggregationSuggestionEngine = new AggregationSuggestionEngine(context); + mAggregationSuggestionEngine.setListener(this); + mAggregationSuggestionEngine.start(); + } + + mAggregationSuggestionEngine.setContactId(getContactId()); + + LabeledEditorView nameEditor = rawContactEditor.getNameEditor(); + mAggregationSuggestionEngine.onNameChange(nameEditor.getValues()); + } + + /** + * Returns the contact ID for the currently edited contact or 0 if the contact is new. + */ + private long getContactId() { + for (RawContactDelta rawContact : mState) { + Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID); + if (contactId != null) { + return contactId; + } + } + return 0; + } + + @Override + public void onAggregationSuggestionChange() { + final Activity activity = getActivity(); + if ((activity != null && activity.isFinishing()) + || !isVisible() || mState.isEmpty() || mStatus != Status.EDITING) { + return; + } + + UiClosables.closeQuietly(mAggregationSuggestionPopup); + + if (mAggregationSuggestionEngine.getSuggestedContactCount() == 0) { + return; + } + + final RawContactEditorView rawContactView = (RawContactEditorView) + getRawContactEditorView(mAggregationSuggestionsRawContactId); + if (rawContactView == null) { + return; // Raw contact deleted? + } + final View anchorView = rawContactView.findViewById(R.id.anchor_view); + mAggregationSuggestionPopup = new ListPopupWindow(mContext, null); + mAggregationSuggestionPopup.setAnchorView(anchorView); + mAggregationSuggestionPopup.setWidth(anchorView.getWidth()); + mAggregationSuggestionPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); + mAggregationSuggestionPopup.setAdapter( + new AggregationSuggestionAdapter( + getActivity(), + mState.size() == 1 && mState.get(0).isContactInsert(), + /* listener =*/ this, + mAggregationSuggestionEngine.getSuggestions())); + mAggregationSuggestionPopup.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + final AggregationSuggestionView suggestionView = (AggregationSuggestionView) view; + suggestionView.handleItemClickEvent(); + UiClosables.closeQuietly(mAggregationSuggestionPopup); + mAggregationSuggestionPopup = null; + } + }); + mAggregationSuggestionPopup.show(); + } + + /** + * Finds raw contact editor view for the given rawContactId. + */ + private BaseRawContactEditorView getRawContactEditorView(long rawContactId) { + for (int i = 0; i < mContent.getChildCount(); i++) { + final View childView = mContent.getChildAt(i); + if (childView instanceof BaseRawContactEditorView) { + final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView; + if (editor.getRawContactId() == rawContactId) { + return editor; + } + } + } + return null; + } + + /** + * Whether the given raw contact ID matches the one used to last load aggregation + * suggestions. + */ + protected boolean isAggregationSuggestionRawContactId(long rawContactId) { + return mAggregationSuggestionsRawContactId == rawContactId; + } + + @Override + public void onJoinAction(long contactId, List<Long> rawContactIdList) { + final long rawContactIds[] = new long[rawContactIdList.size()]; + for (int i = 0; i < rawContactIds.length; i++) { + rawContactIds[i] = rawContactIdList.get(i); + } + try { + JoinSuggestedContactDialogFragment.show(this, rawContactIds); + } catch (Exception ignored) { + // No problem - the activity is no longer available to display the dialog + } + } + + /** + * Joins the suggested contact (specified by the id's of constituent raw + * contacts), save all changes, and stay in the editor. + */ + protected void doJoinSuggestedContact(long[] rawContactIds) { + if (!hasValidState() || mStatus != Status.EDITING) { + return; + } + + mState.setJoinWithRawContacts(rawContactIds); + save(SaveMode.RELOAD); + } + + @Override + public void onEditAction(Uri contactLookupUri) { + SuggestionEditConfirmationDialogFragment.show(this, contactLookupUri); + } + + /** + * Abandons the currently edited contact and switches to editing the suggested + * one, transferring all the data there + */ + protected void doEditSuggestedContact(Uri contactUri) { + if (mListener != null) { + // make sure we don't save this contact when closing down + mStatus = Status.CLOSING; + mListener.onEditOtherContactRequested( + contactUri, mState.get(0).getContentValues()); + } + } + + // + // Join Activity + // + + /** + * Performs aggregation with the contact selected by the user from suggestions or A-Z list. + */ + private void joinAggregate(final long contactId) { + Intent intent = ContactSaveService.createJoinContactsIntent(mContext, mContactIdForJoin, + contactId, mContactWritableForJoin, + ContactEditorActivity.class, ContactEditorActivity.ACTION_JOIN_COMPLETED); + mContext.startService(intent); + } + // // Utility methods // diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java index dfa58ac2b..c71c891de 100644 --- a/src/com/android/contacts/editor/ContactEditorFragment.java +++ b/src/com/android/contacts/editor/ContactEditorFragment.java @@ -17,29 +17,20 @@ package com.android.contacts.editor; import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.ContentUris; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.provider.ContactsContract.CommonDataKinds.Photo; -import android.provider.ContactsContract.RawContacts; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.BaseAdapter; import android.widget.LinearLayout; import android.widget.ListPopupWindow; -import android.widget.Toast; import com.android.contacts.ContactSaveService; import com.android.contacts.R; @@ -55,9 +46,7 @@ import com.android.contacts.common.model.account.AccountWithDataSet; import com.android.contacts.common.util.AccountsListAdapter; import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter; import com.android.contacts.detail.PhotoSelectionHandler; -import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion; import com.android.contacts.editor.Editor.EditorListener; -import com.android.contacts.list.UiIntentActions; import com.android.contacts.util.ContactPhotoUtils; import com.android.contacts.util.UiClosables; @@ -74,42 +63,19 @@ import java.util.List; */ public class ContactEditorFragment extends ContactEditorBaseFragment implements ContactEditor, SplitContactConfirmationDialogFragment.Listener, - AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener, RawContactReadOnlyEditorView.Listener { - // 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"; - // Photos private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester"; private static final String KEY_CURRENT_PHOTO_URI = "currentphotouri"; private static final String KEY_UPDATED_PHOTOS = "updatedPhotos"; - // Aggregations - private static final String KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID = - "aggregationSuggestionsRawContactId"; - public static final String SAVE_MODE_EXTRA_KEY = "saveMode"; - // - // Helpers - // - private AggregationSuggestionEngine mAggregationSuggestionEngine; - - // - // Contact editor state - // - // Joins - private long mContactIdForJoin; - private boolean mContactWritableForJoin; - // Used to store which raw contact editors have been expanded. Keyed on raw contact ids. private HashMap<Long, Boolean> mExpandedEditors = new HashMap<Long, Boolean>(); - // Photos /** * The raw contact for which we started "take photo" or "choose photo from gallery" most * recently. Used to restore {@link #mCurrentPhotoHandler} after orientation change. @@ -128,88 +94,10 @@ public class ContactEditorFragment extends ContactEditorBaseFragment implements private Uri mCurrentPhotoUri; private Bundle mUpdatedPhotos = new Bundle(); - // Aggregations - private long mAggregationSuggestionsRawContactId; - private ListPopupWindow mAggregationSuggestionPopup; - - private static final class AggregationSuggestionAdapter extends BaseAdapter { - private final Activity mActivity; - private final boolean mSetNewContact; - private final AggregationSuggestionView.Listener mListener; - private final List<Suggestion> mSuggestions; - - public AggregationSuggestionAdapter(Activity activity, boolean setNewContact, - AggregationSuggestionView.Listener listener, List<Suggestion> suggestions) { - mActivity = activity; - mSetNewContact = setNewContact; - mListener = listener; - mSuggestions = suggestions; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Suggestion suggestion = (Suggestion) getItem(position); - LayoutInflater inflater = mActivity.getLayoutInflater(); - AggregationSuggestionView suggestionView = - (AggregationSuggestionView) inflater.inflate( - R.layout.aggregation_suggestions_item, null); - suggestionView.setNewContact(mSetNewContact); - suggestionView.setListener(mListener); - suggestionView.bindSuggestion(suggestion); - return suggestionView; - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public Object getItem(int position) { - return mSuggestions.get(position); - } - - @Override - public int getCount() { - return mSuggestions.size(); - } - } - - private OnItemClickListener mAggregationSuggestionItemClickListener = - new OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - final AggregationSuggestionView suggestionView = (AggregationSuggestionView) view; - suggestionView.handleItemClickEvent(); - UiClosables.closeQuietly(mAggregationSuggestionPopup); - mAggregationSuggestionPopup = null; - } - }; - public ContactEditorFragment() { } @Override - public void onStop() { - super.onStop(); - - UiClosables.closeQuietly(mAggregationSuggestionPopup); - - // If anything was left unsaved, save it now but keep the editor open. - if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) { - save(SaveMode.RELOAD); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (mAggregationSuggestionEngine != null) { - mAggregationSuggestionEngine.quit(); - } - } - - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false); @@ -221,32 +109,16 @@ public class ContactEditorFragment extends ContactEditorBaseFragment implements } @Override - public void onStart() { - getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener); - super.onStart(); - } - - @Override public void onCreate(Bundle savedState) { super.onCreate(savedState); if (savedState != null) { - // Joins - mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN); - mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN); - mExpandedEditors = (HashMap<Long, Boolean>) savedState.getSerializable(KEY_EXPANDED_EDITORS); - - // Photos mRawContactIdRequestingPhoto = savedState.getLong( KEY_RAW_CONTACT_ID_REQUESTING_PHOTO); mCurrentPhotoUri = savedState.getParcelable(KEY_CURRENT_PHOTO_URI); mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS); - - // Aggregations - mAggregationSuggestionsRawContactId = savedState.getLong( - KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID); } } @@ -420,7 +292,7 @@ public class ContactEditorFragment extends ContactEditorBaseFragment implements rawContactEditor.getNickNameEditor(); nickNameEditor.setEditorListener(listener); - if (rawContactId == mAggregationSuggestionsRawContactId) { + if (isAggregationSuggestionRawContactId(rawContactId)) { acquireAggregationSuggestions(activity, rawContactEditor); } @@ -595,302 +467,11 @@ public class ContactEditorFragment extends ContactEditorBaseFragment implements } @Override - public void onJoinCompleted(Uri uri) { - onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri); - } - - @Override - public void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded, - Uri contactLookupUri) { - if (hadChanges) { - if (saveSucceeded) { - if (saveMode != SaveMode.JOIN) { - Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show(); - } - } else { - Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show(); - } - } - switch (saveMode) { - case SaveMode.CLOSE: - case SaveMode.HOME: - final Intent resultIntent; - if (saveSucceeded && contactLookupUri != null) { - final Uri lookupUri = maybeConvertToLegacyLookupUri( - mContext, contactLookupUri, mLookupUri); - resultIntent = composeQuickContactsIntent(mContext, lookupUri); - } else { - resultIntent = null; - } - // It is already saved, so prevent that it is saved again - mStatus = Status.CLOSING; - if (mListener != null) mListener.onSaveFinished(resultIntent); - break; - - case SaveMode.RELOAD: - case SaveMode.JOIN: - if (saveSucceeded && contactLookupUri != null) { - // If it was a JOIN, we are now ready to bring up the join activity. - if (saveMode == SaveMode.JOIN && hasValidState()) { - showJoinAggregateActivity(contactLookupUri); - } - - // If this was in INSERT, we are changing into an EDIT now. - // If it already was an EDIT, we are changing to the new Uri now - mState = new RawContactDeltaList(); - load(Intent.ACTION_EDIT, contactLookupUri, null); - mStatus = Status.LOADING; - getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener); - } - break; - - case SaveMode.SPLIT: - mStatus = Status.CLOSING; - if (mListener != null) { - mListener.onContactSplit(contactLookupUri); - } else { - Log.d(TAG, "No listener registered, can not call onSplitFinished"); - } - break; - } - } - - /** - * Shows a list of aggregates that can be joined into the currently viewed aggregate. - * - * @param contactLookupUri the fresh URI for the currently edited contact (after saving it) - */ - private void showJoinAggregateActivity(Uri contactLookupUri) { - if (contactLookupUri == null || !isAdded()) { - return; - } - - mContactIdForJoin = ContentUris.parseId(contactLookupUri); - mContactWritableForJoin = isContactWritable(); - final Intent intent = new Intent(UiIntentActions.PICK_JOIN_CONTACT_ACTION); - intent.putExtra(UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY, mContactIdForJoin); - startActivityForResult(intent, REQUEST_CODE_JOIN); - } - - /** - * Performs aggregation with the contact selected by the user from suggestions or A-Z list. - */ - private void joinAggregate(final long contactId) { - Intent intent = ContactSaveService.createJoinContactsIntent(mContext, mContactIdForJoin, - contactId, mContactWritableForJoin, - ContactEditorActivity.class, ContactEditorActivity.ACTION_JOIN_COMPLETED); - mContext.startService(intent); - } - - /** - * Returns true if there is at least one writable raw contact in the current contact. - */ - private boolean isContactWritable() { - final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); - int size = mState.size(); - for (int i = 0; i < size; i++) { - RawContactDelta entity = mState.get(i); - final AccountType type = entity.getAccountType(accountTypes); - if (type.areContactsWritable()) { - return true; - } - } - return false; - } - - /** - * Returns the contact ID for the currently edited contact or 0 if the contact is new. - */ - protected long getContactId() { - for (RawContactDelta rawContact : mState) { - Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID); - if (contactId != null) { - return contactId; - } - } - return 0; - } - - /** - * Triggers an asynchronous search for aggregation suggestions. - */ - private void acquireAggregationSuggestions(Context context, - RawContactEditorView rawContactEditor) { - long rawContactId = rawContactEditor.getRawContactId(); - if (mAggregationSuggestionsRawContactId != rawContactId - && mAggregationSuggestionView != null) { - mAggregationSuggestionView.setVisibility(View.GONE); - mAggregationSuggestionView = null; - mAggregationSuggestionEngine.reset(); - } - - mAggregationSuggestionsRawContactId = rawContactId; - - if (mAggregationSuggestionEngine == null) { - mAggregationSuggestionEngine = new AggregationSuggestionEngine(context); - mAggregationSuggestionEngine.setListener(this); - mAggregationSuggestionEngine.start(); - } - - mAggregationSuggestionEngine.setContactId(getContactId()); - - LabeledEditorView nameEditor = rawContactEditor.getNameEditor(); - mAggregationSuggestionEngine.onNameChange(nameEditor.getValues()); - } - - @Override - public void onAggregationSuggestionChange() { - Activity activity = getActivity(); - if ((activity != null && activity.isFinishing()) - || !isVisible() || mState.isEmpty() || mStatus != Status.EDITING) { - return; - } - - UiClosables.closeQuietly(mAggregationSuggestionPopup); - - if (mAggregationSuggestionEngine.getSuggestedContactCount() == 0) { - return; - } - - final RawContactEditorView rawContactView = - (RawContactEditorView)getRawContactEditorView(mAggregationSuggestionsRawContactId); - if (rawContactView == null) { - return; // Raw contact deleted? - } - final View anchorView = rawContactView.findViewById(R.id.anchor_view); - mAggregationSuggestionPopup = new ListPopupWindow(mContext, null); - mAggregationSuggestionPopup.setAnchorView(anchorView); - mAggregationSuggestionPopup.setWidth(anchorView.getWidth()); - mAggregationSuggestionPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); - mAggregationSuggestionPopup.setAdapter( - new AggregationSuggestionAdapter(getActivity(), - mState.size() == 1 && mState.get(0).isContactInsert(), - this, mAggregationSuggestionEngine.getSuggestions())); - mAggregationSuggestionPopup.setOnItemClickListener(mAggregationSuggestionItemClickListener); - mAggregationSuggestionPopup.show(); - } - - @Override - public void onJoinAction(long contactId, List<Long> rawContactIdList) { - long rawContactIds[] = new long[rawContactIdList.size()]; - for (int i = 0; i < rawContactIds.length; i++) { - rawContactIds[i] = rawContactIdList.get(i); - } - JoinSuggestedContactDialogFragment dialog = - new JoinSuggestedContactDialogFragment(); - Bundle args = new Bundle(); - args.putLongArray("rawContactIds", rawContactIds); - dialog.setArguments(args); - dialog.setTargetFragment(this, 0); - try { - dialog.show(getFragmentManager(), "join"); - } catch (Exception ex) { - // No problem - the activity is no longer available to display the dialog - } - } - - public static class JoinSuggestedContactDialogFragment extends DialogFragment { - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()) - .setIconAttribute(android.R.attr.alertDialogIcon) - .setMessage(R.string.aggregation_suggestion_join_dialog_message) - .setPositiveButton(android.R.string.yes, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - ContactEditorFragment targetFragment = - (ContactEditorFragment) getTargetFragment(); - long rawContactIds[] = - getArguments().getLongArray("rawContactIds"); - targetFragment.doJoinSuggestedContact(rawContactIds); - } - } - ) - .setNegativeButton(android.R.string.no, null) - .create(); - } - } - - /** - * Joins the suggested contact (specified by the id's of constituent raw - * contacts), save all changes, and stay in the editor. - */ - protected void doJoinSuggestedContact(long[] rawContactIds) { - if (!hasValidState() || mStatus != Status.EDITING) { - return; - } - - mState.setJoinWithRawContacts(rawContactIds); - save(SaveMode.RELOAD); - } - - @Override - public void onEditAction(Uri contactLookupUri) { - SuggestionEditConfirmationDialogFragment dialog = - new SuggestionEditConfirmationDialogFragment(); - Bundle args = new Bundle(); - args.putParcelable("contactUri", contactLookupUri); - dialog.setArguments(args); - dialog.setTargetFragment(this, 0); - dialog.show(getFragmentManager(), "edit"); - } - - public static class SuggestionEditConfirmationDialogFragment extends DialogFragment { - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()) - .setIconAttribute(android.R.attr.alertDialogIcon) - .setMessage(R.string.aggregation_suggestion_edit_dialog_message) - .setPositiveButton(android.R.string.yes, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - ContactEditorFragment targetFragment = - (ContactEditorFragment) getTargetFragment(); - Uri contactUri = - getArguments().getParcelable("contactUri"); - targetFragment.doEditSuggestedContact(contactUri); - } - } - ) - .setNegativeButton(android.R.string.no, null) - .create(); - } - } - - /** - * Abandons the currently edited contact and switches to editing the suggested - * one, transferring all the data there - */ - protected void doEditSuggestedContact(Uri contactUri) { - if (mListener != null) { - // make sure we don't save this contact when closing down - mStatus = Status.CLOSING; - mListener.onEditOtherContactRequested( - contactUri, mState.get(0).getContentValues()); - } - } - - @Override public void onSaveInstanceState(Bundle outState) { - // Joins - outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin); - outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin); - outState.putSerializable(KEY_EXPANDED_EDITORS, mExpandedEditors); - - // Photos outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto); outState.putParcelable(KEY_CURRENT_PHOTO_URI, mCurrentPhotoUri); outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos); - - // Aggregations - outState.putLong(KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID, - mAggregationSuggestionsRawContactId); - super.onSaveInstanceState(outState); } @@ -906,21 +487,7 @@ public class ContactEditorFragment extends ContactEditorBaseFragment implements return; } - switch (requestCode) { - case REQUEST_CODE_JOIN: { - // Ignore failed requests - if (resultCode != Activity.RESULT_OK) return; - if (data != null) { - final long contactId = ContentUris.parseId(data.getData()); - joinAggregate(contactId); - } - break; - } - default: { - super.onActivityResult(requestCode, resultCode, data); - break; - } - } + super.onActivityResult(requestCode, resultCode, data); } /** @@ -1002,21 +569,6 @@ public class ContactEditorFragment extends ContactEditorBaseFragment implements return false; } - @Override - public void onSplitContactConfirmed() { - if (mState.isEmpty()) { - // This may happen when this Fragment is recreated by the system during users - // confirming the split action (and thus this method is called just before onCreate()), - // for example. - Log.e(TAG, "mState became null during the user's confirming split action. " + - "Cannot perform the save action."); - return; - } - - mState.markRawContactsForSplitting(); - save(SaveMode.SPLIT); - } - /** * Custom photo handler for the editor. The inner listener that this creates also has a * reference to the editor and acts as an {@link EditorListener}, and uses that editor to hold diff --git a/src/com/android/contacts/editor/JoinSuggestedContactDialogFragment.java b/src/com/android/contacts/editor/JoinSuggestedContactDialogFragment.java new file mode 100644 index 000000000..dca6e18f6 --- /dev/null +++ b/src/com/android/contacts/editor/JoinSuggestedContactDialogFragment.java @@ -0,0 +1,61 @@ +/* + * 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; + +public class JoinSuggestedContactDialogFragment extends DialogFragment { + + private static final String ARG_RAW_CONTACT_IDS = "rawContactIds"; + + public static void show(ContactEditorBaseFragment fragment, long[] rawContactIds) { + final Bundle args = new Bundle(); + args.putLongArray(ARG_RAW_CONTACT_IDS, rawContactIds); + + final JoinSuggestedContactDialogFragment dialog = new JoinSuggestedContactDialogFragment(); + dialog.setArguments(args); + dialog.setTargetFragment(fragment, 0); + dialog.show(fragment.getFragmentManager(), "join"); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setIconAttribute(android.R.attr.alertDialogIcon) + .setMessage(R.string.aggregation_suggestion_join_dialog_message) + .setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + ContactEditorFragment targetFragment = + (ContactEditorFragment) getTargetFragment(); + long rawContactIds[] = + getArguments().getLongArray(ARG_RAW_CONTACT_IDS); + targetFragment.doJoinSuggestedContact(rawContactIds); + } + } + ) + .setNegativeButton(android.R.string.no, null) + .create(); + } +}
\ No newline at end of file diff --git a/src/com/android/contacts/editor/SuggestionEditConfirmationDialogFragment.java b/src/com/android/contacts/editor/SuggestionEditConfirmationDialogFragment.java new file mode 100644 index 000000000..0af2d2d74 --- /dev/null +++ b/src/com/android/contacts/editor/SuggestionEditConfirmationDialogFragment.java @@ -0,0 +1,63 @@ +/* + * 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.net.Uri; +import android.os.Bundle; + +public class SuggestionEditConfirmationDialogFragment extends DialogFragment { + + private static final String ARG_CONTACT_URI = "contactUri"; + + public static void show(ContactEditorBaseFragment fragment, Uri contactUri) { + final Bundle args = new Bundle(); + args.putParcelable(ARG_CONTACT_URI, contactUri); + + final SuggestionEditConfirmationDialogFragment dialog = new + SuggestionEditConfirmationDialogFragment(); + dialog.setArguments(args); + dialog.setTargetFragment(fragment, 0); + dialog.show(fragment.getFragmentManager(), "edit"); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setIconAttribute(android.R.attr.alertDialogIcon) + .setMessage(R.string.aggregation_suggestion_edit_dialog_message) + .setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + final ContactEditorFragment targetFragment = + (ContactEditorFragment) getTargetFragment(); + final Uri contactUri = + getArguments().getParcelable(ARG_CONTACT_URI); + targetFragment.doEditSuggestedContact(contactUri); + } + } + ) + .setNegativeButton(android.R.string.no, null) + .create(); + } +} |