Merge change 26770 into eclair
* changes:
Show a line at the bottom of favorites.
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 624885c..f4e3465 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -21,7 +21,7 @@
<!-- Title for the activity that dials the phone. This is the name
used in the Launcher icon. -->
- <string name="launcherDialer">Dialer</string>
+ <string name="launcherDialer">Phone</string>
<!-- Name of activity that allows users to create shortcuts on the home screen to a contact.
This shows up in a list of things like bookmark, folder, music playlist, etc -->
@@ -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>
@@ -408,7 +411,7 @@
<string name="contactsFavoritesLabel">Favorites</string>
<!-- The description text for the dialer tab. Space is limited for this string, so the shorter the better -->
- <string name="dialerIconLabel">Dialer</string>
+ <string name="dialerIconLabel">Phone</string>
<!-- The description text for the call log tab. Space is limited for this string, so the shorter the better -->
<string name="recentCallsIconLabel">Call log</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/DialtactsActivity.java b/src/com/android/contacts/DialtactsActivity.java
index 9fb5f41..208fbf4 100644
--- a/src/com/android/contacts/DialtactsActivity.java
+++ b/src/com/android/contacts/DialtactsActivity.java
@@ -33,9 +33,11 @@
import android.widget.TabHost;
/**
- * The dialer activity that has one tab with the virtual 12key dialer,
- * and another tab with recent calls in it. This is the container and the tabs
- * are embedded using intents.
+ * The dialer activity that has one tab with the virtual 12key
+ * dialer, a tab with recent calls in it, a tab with the contacts and
+ * a tab with the favorite. This is the container and the tabs are
+ * embedded using intents.
+ * The dialer tab's title is 'phone', a more common name (see strings.xml).
*/
public class DialtactsActivity extends TabActivity implements TabHost.OnTabChangeListener {
private static final String TAG = "Dailtacts";
@@ -46,7 +48,7 @@
private static final int TAB_INDEX_CALL_LOG = 1;
private static final int TAB_INDEX_CONTACTS = 2;
private static final int TAB_INDEX_FAVORITES = 3;
-
+
static final String EXTRA_IGNORE_STATE = "ignore-state";
/** Name of the dialtacts shared preferences */
@@ -56,7 +58,7 @@
static final boolean PREF_FAVORITES_AS_CONTACTS_DEFAULT = false;
private TabHost mTabHost;
- private String mFilterText;
+ private String mFilterText;
private Uri mDialUri;
@Override
@@ -65,7 +67,7 @@
final Intent intent = getIntent();
fixIntent(intent);
-
+
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.dialer_activity);
@@ -89,7 +91,7 @@
@Override
protected void onPause() {
super.onPause();
-
+
int currentTabIndex = mTabHost.getCurrentTab();
if (currentTabIndex == TAB_INDEX_CONTACTS || currentTabIndex == TAB_INDEX_FAVORITES) {
SharedPreferences.Editor editor = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE)
@@ -98,7 +100,7 @@
editor.commit();
}
}
-
+
private void fixIntent(Intent intent) {
// This should be cleaned up: the call key used to send an Intent
// that just said to go to the recent calls list. It now sends this
@@ -109,7 +111,7 @@
setIntent(intent);
}
}
-
+
private void setupCallLogTab() {
// Force the class since overriding tab entries doesn't work
Intent intent = new Intent("com.android.phone.action.RECENT_CALLS");
@@ -153,10 +155,10 @@
/**
* Returns true if the intent is due to hitting the green send key while in a call.
- *
+ *
* @param intent the intent that launched this activity
* @param recentCallsRequest true if the intent is requesting to view recent calls
- * @return true if the intent is due to hitting the green send key while in a call
+ * @return true if the intent is due to hitting the green send key while in a call
*/
private boolean isSendKeyWhileInCall(final Intent intent, final boolean recentCallsRequest) {
// If there is a call in progress go to the call screen
@@ -178,7 +180,7 @@
/**
* Sets the current tab based on the intent's request type
- *
+ *
* @param recentCallsRequest true is the recent calls tab is desired, false otherwise
*/
private void setCurrentTab(Intent intent) {
@@ -188,7 +190,7 @@
finish();
return;
}
-
+
// Dismiss menu provided by any children activities
Activity activity = getLocalActivityManager().
getActivity(mTabHost.getCurrentTabTag());
@@ -253,13 +255,13 @@
}
return false;
}
-
+
/**
* Retrieves the filter text stored in {@link #setupFilterText(Intent)}.
* This text originally came from a FILTER_CONTACTS_ACTION intent received
* by this activity. The stored text will then be cleared after after this
* method returns.
- *
+ *
* @return The stored filter text
*/
public String getAndClearFilterText() {
@@ -271,7 +273,7 @@
/**
* Stores the filter text associated with a FILTER_CONTACTS_ACTION intent.
* This is so child activities can check if they are supposed to display a filter.
- *
+ *
* @param intent The intent received in {@link #onNewIntent(Intent)}
*/
private void setupFilterText(Intent intent) {
@@ -289,7 +291,7 @@
* Retrieves the uri stored in {@link #setupDialUri(Intent)}. This uri
* originally came from a dial intent received by this activity. The stored
* uri will then be cleared after after this method returns.
- *
+ *
* @return The stored uri
*/
public Uri getAndClearDialUri() {
@@ -301,7 +303,7 @@
/**
* Stores the uri associated with a dial intent. This is so child activities can
* check if they are supposed to display new dial info.
- *
+ *
* @param intent The intent received in {@link #onNewIntent(Intent)}
*/
private void setupDialUri(Intent intent) {
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/FastTrackWindow.java b/src/com/android/contacts/ui/FastTrackWindow.java
index 9d5740a..769b957 100644
--- a/src/com/android/contacts/ui/FastTrackWindow.java
+++ b/src/com/android/contacts/ui/FastTrackWindow.java
@@ -1175,6 +1175,8 @@
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// Only try detecting outside events on down-press
mDecor.getHitRect(mRect);
+ mRect.top = mRect.top + mDecor.getPaddingTop();
+ mRect.bottom = mRect.bottom - mDecor.getPaddingBottom();
final int x = (int)event.getX();
final int y = (int)event.getY();
if (!mRect.contains(x, y)) {
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();
}
}