Merge change 26772 into eclair
* changes:
Fixes the issue about fasttrack window not being dismissed on tapping just outside it.
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 624885c..2c66748 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -345,7 +345,10 @@
<string name="starredInAndroid">Starred in Android</string>
<!-- Displayed in a spinner dialog after the user creates a contact and it's being saved to the database -->
- <string name="savingContact">Saving contact...</string>
+ <string name="savingContact">Saving contact\u2026</string>
+
+ <!-- Displayed in a spinner dialog as user changes to display groups are saved -->
+ <string name="savingDisplayGroups">Saving display groups\u2026</string>
<!-- Toast displayed when a contact is created -->
<string name="contactCreatedToast">Contact created.</string>
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 79af879..bae9b5c 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -926,8 +926,8 @@
sources.getInflatedSource(account.type,
ContactsSource.LEVEL_SUMMARY);
- text1.setText(source.getDisplayLabel(ContactsListActivity.this));
- text2.setText(account.name);
+ text1.setText(account.name);
+ text2.setText(source.getDisplayLabel(ContactsListActivity.this));
return convertView;
}
@@ -1719,7 +1719,7 @@
case MODE_JOIN_CONTACT:
mQueryHandler.setLoadingJoinSuggestions(true);
mQueryHandler.startQuery(QUERY_TOKEN, null, getJoinSuggestionsUri(null), projection,
- null, null, null);
+ Contacts._ID + " != " + mQueryAggregateId, null, null);
break;
}
}
@@ -1795,7 +1795,8 @@
null, null);
mAdapter.setSuggestionsCursor(cursor);
return resolver.query(getContactFilterUri(filter), projection,
- getContactSelection(), null, getSortOrder(projection));
+ Contacts._ID + " != " + mQueryAggregateId, null,
+ getSortOrder(projection));
}
}
throw new UnsupportedOperationException("filtering not allowed in mode " + mMode);
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index 70c1867..9b22b4b 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -862,6 +862,11 @@
final String accountType = entValues.getAsString(RawContacts.ACCOUNT_TYPE);
final long rawContactId = entValues.getAsLong(RawContacts._ID);
+ if (!mRawContactIds.contains(rawContactId)) {
+ mRawContactIds.add(rawContactId);
+ }
+
+
// // This performs the tab filtering
// if (mSelectedRawContactId != null
// && mSelectedRawContactId != rawContactId
@@ -903,10 +908,6 @@
continue;
}
- if (!mRawContactIds.contains(entry.contactId)) {
- mRawContactIds.add(entry.contactId);
- }
-
if (CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mimetype)
|| CommonDataKinds.Email.CONTENT_ITEM_TYPE.equals(mimetype)
|| CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE.equals(mimetype)
diff --git a/src/com/android/contacts/model/EntityModifier.java b/src/com/android/contacts/model/EntityModifier.java
index 0d8ede9..1d78cfc 100644
--- a/src/com/android/contacts/model/EntityModifier.java
+++ b/src/com/android/contacts/model/EntityModifier.java
@@ -33,9 +33,11 @@
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.Intents.Insert;
+import android.provider.ContactsContract;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
@@ -378,8 +380,12 @@
continue;
}
- // Test and remove this row if empty
- if (EntityModifier.isEmpty(entry, kind)) {
+ // Test and remove this row if empty and it isn't a photo from google
+ final boolean isGoogleSource = TextUtils.equals(GoogleSource.ACCOUNT_TYPE,
+ entry.getAsString(RawContacts.ACCOUNT_TYPE));
+ final boolean isPhoto = TextUtils.equals(Photo.CONTENT_ITEM_TYPE, kind.mimeType);
+ final boolean isGooglePhoto = isPhoto && isGoogleSource;
+ if (EntityModifier.isEmpty(entry, kind) && !isGooglePhoto) {
// TODO: remove this verbose logging
Log.w(TAG, "Trimming: " + entry.toString());
entry.markDeleted();
diff --git a/src/com/android/contacts/model/EntitySet.java b/src/com/android/contacts/model/EntitySet.java
index 02a127e..2137987 100644
--- a/src/com/android/contacts/model/EntitySet.java
+++ b/src/com/android/contacts/model/EntitySet.java
@@ -216,7 +216,7 @@
final int size = this.size();
for (int i = 0; i < size; i++) {
final Long currentId = getRawContactId(i);
- if (currentId == rawContactId) {
+ if (rawContactId.equals(currentId)) {
return i;
}
}
diff --git a/src/com/android/contacts/model/ExchangeSource.java b/src/com/android/contacts/model/ExchangeSource.java
index 5c2d024..0a7fb23 100644
--- a/src/com/android/contacts/model/ExchangeSource.java
+++ b/src/com/android/contacts/model/ExchangeSource.java
@@ -123,6 +123,8 @@
kind.typeList.add(buildPhoneType(Phone.TYPE_MMS).setSecondary(true).setSpecificMax(1));
kind.typeList
.add(buildPhoneType(Phone.TYPE_RADIO).setSecondary(true).setSpecificMax(1));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_ASSISTANT).setSecondary(true)
+ .setSpecificMax(1).setCustomColumn(Phone.LABEL));
kind.typeList.add(buildPhoneType(Phone.TYPE_CUSTOM).setSecondary(true)
.setSpecificMax(1).setCustomColumn(Phone.LABEL));
diff --git a/src/com/android/contacts/ui/DisplayGroupsActivity.java b/src/com/android/contacts/ui/DisplayGroupsActivity.java
index ffe423f..ab6f651 100644
--- a/src/com/android/contacts/ui/DisplayGroupsActivity.java
+++ b/src/com/android/contacts/ui/DisplayGroupsActivity.java
@@ -16,15 +16,24 @@
package com.android.contacts.ui;
+import com.android.contacts.R;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.Sources;
+import com.android.contacts.util.EmptyService;
+import com.android.contacts.util.WeakAsyncTask;
+import com.google.android.collect.Sets;
+
import android.accounts.Account;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ExpandableListActivity;
+import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
@@ -36,6 +45,7 @@
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.Settings;
import android.view.ContextMenu;
@@ -52,13 +62,7 @@
import android.widget.TextView;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
-import com.google.android.collect.Sets;
-
-import com.android.contacts.R;
-import com.android.contacts.model.ContactsSource;
-import com.android.contacts.model.Sources;
-import com.android.contacts.util.WeakAsyncTask;
-
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
@@ -91,6 +95,12 @@
private View mHeaderPhones;
private View mHeaderSeparator;
+ private static final Uri sDelayedSettings = Settings.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Contacts.DELAY_STARRED_UPDATE, "1").build();
+
+ private static final Uri sDelayedGroups = Groups.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Contacts.DELAY_STARRED_UPDATE, "1").build();
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -253,13 +263,12 @@
final ContentResolver resolver = getContentResolver();
final ContentValues values = new ContentValues();
- // TODO: heavy update, perhaps push to background query
if (id == UNGROUPED_ID) {
// Handle persisting for ungrouped through Settings
values.put(Settings.UNGROUPED_VISIBLE, checkbox.isChecked() ? 1 : 0);
final Cursor settings = mAdapter.getGroup(groupPosition);
- final int count = resolver.update(Settings.CONTENT_URI, values, Groups.ACCOUNT_NAME
+ final int count = resolver.update(sDelayedSettings, values, Groups.ACCOUNT_NAME
+ "=? AND " + Groups.ACCOUNT_TYPE + "=?", new String[] {
settings.getString(SettingsQuery.ACCOUNT_NAME),
settings.getString(SettingsQuery.ACCOUNT_TYPE)
@@ -271,7 +280,7 @@
// Handle persisting for normal group
values.put(Groups.GROUP_VISIBLE, checkbox.isChecked() ? 1 : 0);
- final Uri groupUri = ContentUris.withAppendedId(Groups.CONTENT_URI, id);
+ final Uri groupUri = ContentUris.withAppendedId(sDelayedGroups, id);
final int count = resolver.update(groupUri, values, null, null);
}
@@ -412,7 +421,7 @@
if (groupId == UNGROUPED_ID) {
// Updating the overall syncing flag for this account
values.put(Settings.SHOULD_SYNC, shouldSync ? 1 : 0);
- resolver.update(Settings.CONTENT_URI, values, Settings.ACCOUNT_NAME + "=? AND "
+ resolver.update(sDelayedSettings, values, Settings.ACCOUNT_NAME + "=? AND "
+ Settings.ACCOUNT_TYPE + "=?", new String[] {
account.name, account.type
});
@@ -421,7 +430,7 @@
// If syncing mode is everything, force-enable all children groups
values.clear();
values.put(Groups.SHOULD_SYNC, shouldSync ? 1 : 0);
- resolver.update(Groups.CONTENT_URI, values, Groups.ACCOUNT_NAME + "=? AND "
+ resolver.update(sDelayedGroups, values, Groups.ACCOUNT_NAME + "=? AND "
+ Groups.ACCOUNT_TYPE + "=?", new String[] {
account.name, account.type
});
@@ -429,13 +438,13 @@
} else {
// Treat as normal group
values.put(Groups.SHOULD_SYNC, shouldSync ? 1 : 0);
- resolver.update(Groups.CONTENT_URI, values, Groups._ID + "=" + groupId, null);
+ resolver.update(sDelayedGroups, values, Groups._ID + "=" + groupId, null);
if (syncMode == SYNC_MODE_EVERYTHING && !shouldSync) {
// Remove "everything" from sync, user has already been warned
values.clear();
values.put(Settings.SHOULD_SYNC, shouldSync ? 1 : 0);
- resolver.update(Settings.CONTENT_URI, values, Settings.ACCOUNT_NAME + "=? AND "
+ resolver.update(sDelayedSettings, values, Settings.ACCOUNT_NAME + "=? AND "
+ Settings.ACCOUNT_TYPE + "=?", new String[] {
account.name, account.type
});
@@ -443,6 +452,71 @@
}
}
+ /** {@inheritDoc} */
+ @Override
+ public void onBackPressed() {
+ // TODO: somehow update visibility when user leaves through a different
+ // path, never actually pressing the back key
+ new UpdateTask(this).execute();
+ }
+
+ /**
+ * Background task that uses {@link Contacts#FORCE_STARRED_UPDATE} to force
+ * update of {@link Contacts#IN_VISIBLE_GROUP}, showing spinner dialog to
+ * user while updating.
+ */
+ public static class UpdateTask extends WeakAsyncTask<Void, Void, Void, Activity> {
+ private WeakReference<ProgressDialog> mProgress;
+
+ public UpdateTask(Activity target) {
+ super(target);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onPreExecute(Activity target) {
+ final Context context = target;
+
+ mProgress = new WeakReference<ProgressDialog>(ProgressDialog.show(target, null,
+ target.getText(R.string.savingDisplayGroups)));
+
+ // Before starting this task, start an empty service to protect our
+ // process from being reclaimed by the system.
+ context.startService(new Intent(context, EmptyService.class));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected Void doInBackground(Activity target, Void... params) {
+ final Context context = target;
+
+ final ContentValues values = new ContentValues();
+ final ContentResolver resolver = context.getContentResolver();
+
+ // Push through an empty update to trigger forced refresh
+ final Uri forcedGroups = Groups.CONTENT_URI.buildUpon().appendQueryParameter(
+ Contacts.FORCE_STARRED_UPDATE, "1").build();
+ resolver.update(forcedGroups, values, null, null);
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onPostExecute(Activity target, Void result) {
+ final Context context = target;
+
+ final ProgressDialog dialog = mProgress.get();
+ if (dialog != null) dialog.dismiss();
+
+ target.finish();
+
+ // Stop the service that was protecting us
+ context.stopService(new Intent(context, EmptyService.class));
+ }
+ }
+
+
/**
* Return the best title for the {@link Groups} entry at the current
* {@link Cursor} position.
diff --git a/src/com/android/contacts/ui/EditContactActivity.java b/src/com/android/contacts/ui/EditContactActivity.java
index c3a3935..9b380df 100644
--- a/src/com/android/contacts/ui/EditContactActivity.java
+++ b/src/com/android/contacts/ui/EditContactActivity.java
@@ -765,8 +765,8 @@
final ContactsSource source = sources.getInflatedSource(account.type,
ContactsSource.LEVEL_SUMMARY);
- text1.setText(source.getDisplayLabel(target));
- text2.setText(account.name);
+ text1.setText(account.name);
+ text2.setText(source.getDisplayLabel(target));
return convertView;
}
diff --git a/src/com/android/contacts/ui/widget/GenericEditorView.java b/src/com/android/contacts/ui/widget/GenericEditorView.java
index 4490fbf..53dd2e0 100644
--- a/src/com/android/contacts/ui/widget/GenericEditorView.java
+++ b/src/com/android/contacts/ui/widget/GenericEditorView.java
@@ -74,6 +74,8 @@
protected boolean mHideOptional = true;
protected EditType mType;
+ // Used only when a user tries to use custom label.
+ private EditType mPendingType;
public GenericEditorView(Context context) {
super(context);
@@ -221,7 +223,7 @@
* If the final value is empty, this change request is ignored;
* no empty text is allowed in any custom label.
*/
- public Dialog createCustomDialog() {
+ private Dialog createCustomDialog() {
final EditText customType = new EditText(mContext);
customType.setInputType(INPUT_TYPE_CUSTOM);
customType.requestFocus();
@@ -234,6 +236,10 @@
public void onClick(DialogInterface dialog, int which) {
final String customText = customType.getText().toString().trim();
if (!TextUtils.isEmpty(customText)) {
+ // Now we're sure it's ok to actually change the type value.
+ mType = mPendingType;
+ mPendingType = null;
+ mEntry.put(mKind.typeColumn, mType.rawValue);
mEntry.put(mType.customColumn, customText);
rebuildLabel();
}
@@ -274,18 +280,22 @@
}
};
- final DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
+ final DialogInterface.OnClickListener clickListener =
+ new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
- // User picked type, so write to entry
- mType = validTypes.get(which);
- mEntry.put(mKind.typeColumn, mType.rawValue);
-
if (mType.customColumn != null) {
- // Show custom label dialog if requested by type
+ // Show custom label dialog if requested by type.
+ //
+ // Only when the custum value input in the next step is correct one.
+ // this method also set the type value to what the user requested here.
+ mPendingType = validTypes.get(which);
createCustomDialog().show();
} else {
+ // User picked type, and we're sure it's ok to actually write the entry.
+ mType = validTypes.get(which);
+ mEntry.put(mKind.typeColumn, mType.rawValue);
rebuildLabel();
}
}