Merge "Hide cursor when no digit."
diff --git a/res/layout/contact_detail_loader_fragment.xml b/res/layout/contact_detail_loader_fragment.xml
index 3c4bbef..62edb3d 100644
--- a/res/layout/contact_detail_loader_fragment.xml
+++ b/res/layout/contact_detail_loader_fragment.xml
@@ -14,7 +14,13 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"/>
\ No newline at end of file
+<!--
+ Invisible view.
+ Note we show/hide the fragment at runtime with FragmentTransaction.show()/hide() in order to
+ change the visibility of the options menu. This means the visibility of the view will be
+ changed at runtime, so we use width/height to make it invisible, rather than using
+ visibility.
+-->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dip"
+ android:layout_height="0dip"/>
\ No newline at end of file
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index 194d0ba..775009e 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -371,19 +371,29 @@
}
/**
- * Creates an intent that can be sent to this service to create a new group.
+ * Creates an intent that can be sent to this service to create a new group as
+ * well as add new members at the same time.
+ *
+ * @param context of the application
+ * @param account in which the group should be created
+ * @param label is the name of the group (cannot be null)
+ * @param rawContactsToAdd is an array of raw contact IDs for contacts that
+ * should be added to the group
+ * @param callbackActivity is the activity to send the callback intent to
+ * @param callbackAction is the intent action for the callback intent
*/
- public static Intent createNewGroupIntent(Context context, Account account, String label,
- Class<?> callbackActivity, String callbackAction) {
+ public static Intent createNewGroupIntent(Context context, Account account,
+ String label, long[] rawContactsToAdd, Class<?> callbackActivity,
+ String callbackAction) {
Intent serviceIntent = new Intent(context, ContactSaveService.class);
serviceIntent.setAction(ContactSaveService.ACTION_CREATE_GROUP);
serviceIntent.putExtra(ContactSaveService.EXTRA_ACCOUNT_TYPE, account.type);
serviceIntent.putExtra(ContactSaveService.EXTRA_ACCOUNT_NAME, account.name);
serviceIntent.putExtra(ContactSaveService.EXTRA_GROUP_LABEL, label);
+ serviceIntent.putExtra(ContactSaveService.EXTRA_RAW_CONTACTS_TO_ADD, rawContactsToAdd);
// Callback intent will be invoked by the service once the new group is
- // created. The service will put a group membership row in the extras
- // of the callback intent.
+ // created.
Intent callbackIntent = new Intent(context, callbackActivity);
callbackIntent.setAction(callbackAction);
serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent);
@@ -392,28 +402,41 @@
}
private void createGroup(Intent intent) {
- String accountType = intent.getStringExtra(EXTRA_ACCOUNT_TYPE);
- String accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME);
- String label = intent.getStringExtra(EXTRA_GROUP_LABEL);
+ final String accountType = intent.getStringExtra(EXTRA_ACCOUNT_TYPE);
+ final String accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME);
+ final String label = intent.getStringExtra(EXTRA_GROUP_LABEL);
+ final long[] rawContactsToAdd = intent.getLongArrayExtra(EXTRA_RAW_CONTACTS_TO_ADD);
ContentValues values = new ContentValues();
values.put(Groups.ACCOUNT_TYPE, accountType);
values.put(Groups.ACCOUNT_NAME, accountName);
values.put(Groups.TITLE, label);
- Uri groupUri = getContentResolver().insert(Groups.CONTENT_URI, values);
+ final ContentResolver resolver = getContentResolver();
+
+ // Create the new group
+ final Uri groupUri = resolver.insert(Groups.CONTENT_URI, values);
+
+ // If there's no URI, then the insertion failed. Abort early because group members can't be
+ // added if the group doesn't exist
if (groupUri == null) {
+ Log.e(TAG, "Couldn't create group with label " + label);
return;
}
+ // Add new group members
+ addMembersToGroup(resolver, rawContactsToAdd, ContentUris.parseId(groupUri));
+
+ // TODO: Move this into the contact editor where it belongs. This needs to be integrated
+ // with the way other intent extras that are passed to the {@link ContactEditorActivity}.
values.clear();
values.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
values.put(GroupMembership.GROUP_ROW_ID, ContentUris.parseId(groupUri));
Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT);
callbackIntent.setData(groupUri);
+ // TODO: This can be taken out when the above TODO is addressed
callbackIntent.putExtra(ContactsContract.Intents.Insert.DATA, Lists.newArrayList(values));
-
deliverCallback(callbackIntent);
}
@@ -527,10 +550,23 @@
if (label != null) {
ContentValues values = new ContentValues();
values.put(Groups.TITLE, label);
- getContentResolver().update(groupUri, values, null, null);
+ resolver.update(groupUri, values, null, null);
}
- // Add new group members
+ // Add and remove members if necessary
+ addMembersToGroup(resolver, rawContactsToAdd, groupId);
+ removeMembersFromGroup(resolver, rawContactsToRemove, groupId);
+
+ Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT);
+ callbackIntent.setData(groupUri);
+ deliverCallback(callbackIntent);
+ }
+
+ private void addMembersToGroup(ContentResolver resolver, long[] rawContactsToAdd,
+ long groupId) {
+ if (rawContactsToAdd == null) {
+ return;
+ }
for (long rawContactId : rawContactsToAdd) {
try {
final ArrayList<ContentProviderOperation> rawContactOperations =
@@ -577,8 +613,13 @@
String.valueOf(groupId), e);
}
}
+ }
- // Remove group members
+ private void removeMembersFromGroup(ContentResolver resolver, long[] rawContactsToRemove,
+ long groupId) {
+ if (rawContactsToRemove == null) {
+ return;
+ }
for (long rawContactId : rawContactsToRemove) {
// Apply the delete operation on the data row for the given raw contact's
// membership in the given group. If no contact matches the provided selection, then
@@ -588,10 +629,6 @@
new String[] { String.valueOf(rawContactId),
GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(groupId)});
}
-
- Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT);
- callbackIntent.setData(groupUri);
- deliverCallback(callbackIntent);
}
/**
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 03e96c4..a12154d 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -234,8 +234,7 @@
private void updateDisplayOptions() {
// All the flags we may change in this method.
final int MASK = ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME
- | ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_DISABLE_HOME
- | ActionBar.DISPLAY_SHOW_CUSTOM;
+ | ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_CUSTOM;
// The current flags set to the action bar. (only the ones that we may change here)
final int current = mActionBar.getDisplayOptions() & MASK;
@@ -250,12 +249,10 @@
newFlags |= ActionBar.DISPLAY_SHOW_HOME;
newFlags |= ActionBar.DISPLAY_HOME_AS_UP;
newFlags |= ActionBar.DISPLAY_SHOW_CUSTOM;
- } else {
- newFlags |= ActionBar.DISPLAY_DISABLE_HOME;
- if (mAlwaysShowSearchView) {
- newFlags |= ActionBar.DISPLAY_SHOW_CUSTOM;
- }
+ } else if (mAlwaysShowSearchView) {
+ newFlags |= ActionBar.DISPLAY_SHOW_CUSTOM;
}
+ mActionBar.setHomeButtonEnabled(mSearchMode);
if (current != newFlags) {
// Pass the mask here to preserve other flags that we're not interested here.
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index 7456967..0637fd5 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -174,11 +174,7 @@
@Override
public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
boolean globalSearch) {
- if (globalSearch) {
- super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
- } else {
- ContactsSearchManager.startSearch(this, initialQuery);
- }
+ // Ignore search key press
}
@Override
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index cc0be9d..1ee7f1d 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -122,11 +122,7 @@
@Override
public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
boolean globalSearch) {
- if (globalSearch) {
- super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
- } else {
- ContactsSearchManager.startSearch(this, initialQuery);
- }
+ // Ignore search key press
}
@Override
diff --git a/src/com/android/contacts/activities/GroupDetailActivity.java b/src/com/android/contacts/activities/GroupDetailActivity.java
index 7a74bfd..635c130 100644
--- a/src/com/android/contacts/activities/GroupDetailActivity.java
+++ b/src/com/android/contacts/activities/GroupDetailActivity.java
@@ -90,4 +90,10 @@
}
return super.onOptionsItemSelected(item);
}
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ // Ignore search key press
+ }
}
diff --git a/src/com/android/contacts/activities/GroupEditorActivity.java b/src/com/android/contacts/activities/GroupEditorActivity.java
index fa41051..ecadcec 100644
--- a/src/com/android/contacts/activities/GroupEditorActivity.java
+++ b/src/com/android/contacts/activities/GroupEditorActivity.java
@@ -85,11 +85,7 @@
@Override
public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
boolean globalSearch) {
- if (globalSearch) {
- super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
- } else {
- ContactsSearchManager.startSearch(this, initialQuery);
- }
+ // Ignore search key press
}
@Override
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index b0844e9..f25a069 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -390,7 +390,11 @@
@Override
protected void onDestroy() {
- mActionBarAdapter.setListener(null);
+ // mActionBarAdapter will be null here when redirecting to another activity in
+ // configureContentView().
+ if (mActionBarAdapter != null) {
+ mActionBarAdapter.setListener(null);
+ }
super.onDestroy();
}
@@ -543,11 +547,14 @@
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
+ // Note mContactDetailLoaderFragment is an invisible fragment, but we still have to show/
+ // hide it so its options menu will be shown/hidden.
switch (tab) {
case FAVORITES:
showFragment(ft, mFavoritesFragment);
showFragment(ft, mFrequentFragment);
hideFragment(ft, mAllFragment);
+ hideFragment(ft, mContactDetailLoaderFragment);
hideFragment(ft, mContactDetailFragment);
hideFragment(ft, mGroupsFragment);
hideFragment(ft, mGroupDetailFragment);
@@ -556,6 +563,7 @@
hideFragment(ft, mFavoritesFragment);
hideFragment(ft, mFrequentFragment);
showFragment(ft, mAllFragment);
+ showFragment(ft, mContactDetailLoaderFragment);
showFragment(ft, mContactDetailFragment);
hideFragment(ft, mGroupsFragment);
hideFragment(ft, mGroupDetailFragment);
@@ -564,6 +572,7 @@
hideFragment(ft, mFavoritesFragment);
hideFragment(ft, mFrequentFragment);
hideFragment(ft, mAllFragment);
+ hideFragment(ft, mContactDetailLoaderFragment);
hideFragment(ft, mContactDetailFragment);
showFragment(ft, mGroupsFragment);
showFragment(ft, mGroupDetailFragment);
@@ -572,8 +581,10 @@
if (!ft.isEmpty()) {
ft.commit();
fragmentManager.executePendingTransactions();
+ // When switching tabs, we need to invalidate options menu, but executing a
+ // fragment transaction does it implicitly. We don't have to call invalidateOptionsMenu
+ // manually.
}
- invalidateOptionsMenu();
}
private class TabPagerListener implements ViewPager.OnPageChangeListener {
diff --git a/src/com/android/contacts/detail/ContactLoaderFragment.java b/src/com/android/contacts/detail/ContactLoaderFragment.java
index b7cb2b7..0dc83ef 100644
--- a/src/com/android/contacts/detail/ContactLoaderFragment.java
+++ b/src/com/android/contacts/detail/ContactLoaderFragment.java
@@ -28,15 +28,12 @@
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ActivityNotFoundException;
-import android.content.ContentValues;
import android.content.Context;
-import android.content.Entity;
import android.content.Intent;
import android.content.Loader;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.RawContacts;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -124,7 +121,9 @@
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
setHasOptionsMenu(true);
- // This is an empty view that is set to visibility gone.
+ // This is an invisible view. This fragment is declared in a layout, so it can't be
+ // "viewless". (i.e. can't return null here.)
+ // See also the comment in the layout file.
return inflater.inflate(R.layout.contact_detail_loader_fragment, container, false);
}
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index 092e657..717db46 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -815,7 +815,18 @@
startActivity(newFlashIntent());
} else {
if (!TextUtils.isEmpty(mLastNumberDialed)) {
+ // Recall the last number dialed.
mDigits.setText(mLastNumberDialed);
+
+ // ...and move the cursor to the end of the digits string,
+ // so you'll be able to delete digits using the Delete
+ // button (just as if you had typed the number manually.)
+ //
+ // Note we use mDigits.getText().length() here, not
+ // mLastNumberDialed.length(), since the EditText widget now
+ // contains a *formatted* version of mLastNumberDialed (due to
+ // mTextWatcher) and its length may have changed.
+ mDigits.setSelection(mDigits.getText().length());
} else {
// There's no "last number dialed" or the
// background query is still running. There's
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index 76f48a3..da57c82 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -238,20 +238,11 @@
// Account specified in Intent
mAccountName = account.name;
mAccountType = account.type;
- setupAccountHeader();
+ setupEditorForAccount();
} else {
// No Account specified. Let the user choose from a disambiguation dialog.
selectAccountAndCreateGroup();
}
-
- mStatus = Status.EDITING;
-
- // The user wants to create a new group, temporarily hide the "add members" text view
- // TODO: Need to allow users to add members if it's a new group. Under the current
- // approach, we can't add members because it needs a group ID in order to save,
- // and we don't have a group ID for a new group until the whole group is saved.
- // Take this out when batch add/remove members is working.
- mAutoCompleteTextView.setVisibility(View.GONE);
} else {
throw new IllegalArgumentException("Unknown Action String " + mAction +
". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT);
@@ -278,7 +269,7 @@
if (accounts.size() == 1) {
mAccountName = accounts.get(0).name;
mAccountType = accounts.get(0).type;
- setupAccountHeader();
+ setupEditorForAccount();
return; // Don't show a dialog.
}
@@ -292,7 +283,7 @@
public void onAccountChosen(int requestCode, Account account) {
mAccountName = account.name;
mAccountType = account.type;
- setupAccountHeader();
+ setupEditorForAccount();
}
@Override
@@ -304,9 +295,10 @@
}
/**
- * Sets up the account header.
+ * Sets up the editor based on the group's account name and type.
*/
- private void setupAccountHeader() {
+ private void setupEditorForAccount() {
+ // Setup the account header
final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(mContext);
final AccountType accountType = accountTypeManager.getAccountType(mAccountType);
CharSequence accountTypeDisplayLabel = accountType.getDisplayLabel(mContext);
@@ -316,6 +308,31 @@
}
mAccountTypeTextView.setText(accountTypeDisplayLabel);
mAccountIcon.setImageDrawable(accountType.getDisplayIcon(mContext));
+
+ // Setup the autocomplete adapter (for contacts to suggest to add to the group) based on the
+ // account name and type
+ mAutoCompleteAdapter = new SuggestedMemberListAdapter(mContext,
+ android.R.layout.simple_dropdown_item_1line);
+ mAutoCompleteAdapter.setContentResolver(mContentResolver);
+ mAutoCompleteAdapter.setAccountType(mAccountType);
+ mAutoCompleteAdapter.setAccountName(mAccountName);
+ mAutoCompleteTextView.setAdapter(mAutoCompleteAdapter);
+ mAutoCompleteTextView.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ SuggestedMember member = mAutoCompleteAdapter.getItem(position);
+ loadMemberToAddToGroup(member.getRawContactId(),
+ String.valueOf(member.getContactId()));
+
+ // Update the autocomplete adapter so the contact doesn't get suggested again
+ mAutoCompleteAdapter.addNewMember(member.getContactId());
+
+ // Clear out the text field
+ mAutoCompleteTextView.setText("");
+ }
+ });
+
+ mStatus = Status.EDITING;
}
public void load(String action, Uri groupUri, Bundle intentExtras) {
@@ -349,7 +366,7 @@
// focus on the field).
mGroupNameView.setText(mOriginalGroupName);
mGroupNameView.setFocusable(!mGroupNameIsReadOnly);
- setupAccountHeader();
+ setupEditorForAccount();
}
public void loadMemberToAddToGroup(long rawContactId, String contactId) {
@@ -380,8 +397,7 @@
}
private boolean revert() {
- if (mGroupNameView.getText() != null &&
- mGroupNameView.getText().toString().equals(mOriginalGroupName)) {
+ if (!hasNameChange() && !hasMembershipChange()) {
doRevertAction();
} else {
CancelEditDialogFragment.show(this);
@@ -453,24 +469,20 @@
}
Intent saveIntent = null;
if (mAction == Intent.ACTION_INSERT) {
- // TODO: Perform similar work to add members at the same time as creating a new group
+ // Create array of raw contact IDs for contacts to add to the group
+ long[] membersToAddArray = convertToArray(mListMembersToAdd);
+
+ // Create the save intent to create the group and add members at the same time
saveIntent = ContactSaveService.createNewGroupIntent(activity,
new Account(mAccountName, mAccountType), mGroupNameView.getText().toString(),
- activity.getClass(), GroupEditorActivity.ACTION_SAVE_COMPLETED);
+ membersToAddArray, activity.getClass(),
+ GroupEditorActivity.ACTION_SAVE_COMPLETED);
} else if (mAction == Intent.ACTION_EDIT) {
// Create array of raw contact IDs for contacts to add to the group
- int membersToAddCount = mListMembersToAdd.size();
- long[] membersToAddArray = new long[membersToAddCount];
- for (int i = 0; i < membersToAddCount; i++) {
- membersToAddArray[i] = mListMembersToAdd.get(i).getRawContactId();
- }
+ long[] membersToAddArray = convertToArray(mListMembersToAdd);
// Create array of raw contact IDs for contacts to add to the group
- int membersToRemoveCount = mListMembersToRemove.size();
- long[] membersToRemoveArray = new long[membersToRemoveCount];
- for (int i = 0; i < membersToRemoveCount; i++) {
- membersToRemoveArray[i] = mListMembersToRemove.get(i).getRawContactId();
- }
+ long[] membersToRemoveArray = convertToArray(mListMembersToRemove);
// Create the update intent (which includes the updated group name if necessary)
saveIntent = ContactSaveService.createGroupUpdateIntent(activity, mGroupId,
@@ -555,6 +567,15 @@
return groupNameFromTextView;
}
+ private static long[] convertToArray(List<Member> listMembers) {
+ int size = listMembers.size();
+ long[] membersArray = new long[size];
+ for (int i = 0; i < size; i++) {
+ membersArray[i] = listMembers.get(i).getRawContactId();
+ }
+ return membersArray;
+ }
+
private void addExistingMembers(List<Member> members, List<Long> listContactIds) {
mListToDisplay.addAll(members);
mMemberListAdapter.notifyDataSetChanged();
@@ -605,7 +626,6 @@
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- mStatus = Status.EDITING;
bindGroupMetaData(data);
// Load existing members
@@ -651,27 +671,6 @@
data.close();
}
- mAutoCompleteAdapter = new SuggestedMemberListAdapter(getActivity(),
- android.R.layout.simple_dropdown_item_1line);
- mAutoCompleteAdapter.setContentResolver(mContentResolver);
- mAutoCompleteAdapter.setAccountType(mAccountType);
- mAutoCompleteAdapter.setAccountName(mAccountName);
- mAutoCompleteTextView.setAdapter(mAutoCompleteAdapter);
- mAutoCompleteTextView.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- SuggestedMember member = mAutoCompleteAdapter.getItem(position);
- loadMemberToAddToGroup(member.getRawContactId(),
- String.valueOf(member.getContactId()));
-
- // Update the autocomplete adapter so the contact doesn't get suggested again
- mAutoCompleteAdapter.addNewMember(member.getContactId());
-
- // Clear out the text field
- mAutoCompleteTextView.setText("");
- }
- });
-
// Update the display list
addExistingMembers(listExistingMembers, listContactIds);
diff --git a/src/com/android/contacts/interactions/GroupCreationDialogFragment.java b/src/com/android/contacts/interactions/GroupCreationDialogFragment.java
index 8991928..87d83b4 100644
--- a/src/com/android/contacts/interactions/GroupCreationDialogFragment.java
+++ b/src/com/android/contacts/interactions/GroupCreationDialogFragment.java
@@ -60,6 +60,7 @@
Activity activity = getActivity();
activity.startService(ContactSaveService.createNewGroupIntent(activity,
new Account(accountName, accountType), groupLabel,
+ null /* no new members to add */,
activity.getClass(), Intent.ACTION_EDIT));
}
}