Merge "Show group headers correctly"
diff --git a/res/layout/call_detail.xml b/res/layout/call_detail.xml
index 157c761..df1ec62 100644
--- a/res/layout/call_detail.xml
+++ b/res/layout/call_detail.xml
@@ -163,12 +163,14 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?attr/call_log_primary_text_color"
/>
<TextView android:id="@+id/call_and_sms_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?attr/call_log_primary_text_color"
android:textAllCaps="true"
/>
diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml
index 7cfcef3..26689be 100644
--- a/res/layout/call_log_fragment.xml
+++ b/res/layout/call_log_fragment.xml
@@ -39,6 +39,7 @@
android:layout_height="match_parent"
android:fadingEdge="none"
android:scrollbarStyle="outsideOverlay"
+ android:divider="@null"
/>
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index 734e1b8..3458dd9 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -19,6 +19,7 @@
class="com.android.contacts.calllog.CallLogListItemView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:orientation="vertical"
>
<!--
This layout may represent either a call log item or one of the
@@ -170,4 +171,13 @@
android:layout_height="2dip"
android:background="@color/call_log_voicemail_highlight_color"/>
</LinearLayout>
+
+ <View
+ android:id="@+id/call_log_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
+ android:background="#1a1a1a"
+ />
</view>
diff --git a/res/layout/stream_item_row_image_and_text.xml b/res/layout/stream_item_row_image_and_text.xml
index 3642592..882a23b 100644
--- a/res/layout/stream_item_row_image_and_text.xml
+++ b/res/layout/stream_item_row_image_and_text.xml
@@ -57,10 +57,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/stream_item_attribution"
- android:layout_width="wrap_content"
+ android:layout_width="0dip"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary" />
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:layout_weight="1" />
<TextView android:id="@+id/stream_item_comments"
android:layout_width="wrap_content"
@@ -68,7 +71,8 @@
android:layout_marginLeft="@dimen/detail_update_section_attribution_comments_padding"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
- android:visibility="gone" />
+ android:visibility="gone"
+ android:maxLines="1" />
</LinearLayout>
</LinearLayout>
diff --git a/res/layout/stream_item_row_text_only.xml b/res/layout/stream_item_row_text_only.xml
index 7b1f255..919ee52 100644
--- a/res/layout/stream_item_row_text_only.xml
+++ b/res/layout/stream_item_row_text_only.xml
@@ -29,17 +29,21 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
+
<TextView android:id="@+id/stream_item_attribution"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary" />
-
+ android:textColor="?android:attr/textColorSecondary"
+ android:ellipsize="end"
+ android:maxLines="1" />
<TextView android:id="@+id/stream_item_comments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/detail_update_section_attribution_comments_padding"
android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary" />
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="1"/>
+
</LinearLayout>
</LinearLayout>
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index 0dbb22c..0addb07 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -1264,7 +1264,7 @@
@Override
protected void onForceLoad() {
final LoadContactTask task = new LoadContactTask();
- task.execute((Void[])null);
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
}
@Override
diff --git a/src/com/android/contacts/ContactPhotoManager.java b/src/com/android/contacts/ContactPhotoManager.java
index 0f7065d..fd2e6a2 100644
--- a/src/com/android/contacts/ContactPhotoManager.java
+++ b/src/com/android/contacts/ContactPhotoManager.java
@@ -21,6 +21,7 @@
import com.google.android.collect.Sets;
import android.content.ContentResolver;
+import android.content.ContentUris;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
@@ -642,7 +643,6 @@
ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT))
.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
String.valueOf(MAX_PHOTOS_TO_PRELOAD))
- .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "1")
.build();
cursor = mResolver.query(uri, new String[] { Contacts.PHOTO_ID },
Contacts.PHOTO_ID + " NOT NULL AND " + Contacts.PHOTO_ID + "!=0",
@@ -698,8 +698,7 @@
Cursor cursor = null;
try {
- cursor = mResolver.query(Data.CONTENT_URI.buildUpon()
- .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "1").build(),
+ cursor = mResolver.query(Data.CONTENT_URI,
COLUMNS,
mStringBuilder.toString(),
mPhotoIdsAsStrings.toArray(EMPTY_STRING_ARRAY),
@@ -719,9 +718,30 @@
}
}
- // Remaining photos were not found in the database - mark the cache accordingly.
+ // Remaining photos were not found in the contacts database (but might be in profile).
for (Long id : mPhotoIds) {
- cacheBitmap(id, null, preloading);
+ if (ContactsContract.isProfileId(id)) {
+ Cursor profileCursor = null;
+ try {
+ profileCursor = mResolver.query(
+ ContentUris.withAppendedId(Data.CONTENT_URI, id),
+ COLUMNS, null, null, null);
+ if (profileCursor != null && profileCursor.moveToFirst()) {
+ cacheBitmap(profileCursor.getLong(0), profileCursor.getBlob(1),
+ preloading);
+ } else {
+ // Couldn't load a photo this way either.
+ cacheBitmap(id, null, preloading);
+ }
+ } finally {
+ if (profileCursor != null) {
+ profileCursor.close();
+ }
+ }
+ } else {
+ // Not a profile photo and not found - mark the cache accordingly
+ cacheBitmap(id, null, preloading);
+ }
}
mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
diff --git a/src/com/android/contacts/calllog/CallLogAdapter.java b/src/com/android/contacts/calllog/CallLogAdapter.java
index 94daf06..604d528 100644
--- a/src/com/android/contacts/calllog/CallLogAdapter.java
+++ b/src/com/android/contacts/calllog/CallLogAdapter.java
@@ -541,6 +541,7 @@
if (section == CallLogQuery.SECTION_NEW_HEADER
|| section == CallLogQuery.SECTION_OLD_HEADER) {
views.listItemView.setVisibility(View.GONE);
+ views.bottomDivider.setVisibility(View.GONE);
views.listHeaderView.setVisibility(View.VISIBLE);
views.listHeaderTextView.setText(
section == CallLogQuery.SECTION_NEW_HEADER
@@ -551,6 +552,7 @@
}
// Default case: an item in the call log.
views.listItemView.setVisibility(View.VISIBLE);
+ views.bottomDivider.setVisibility(isLastOfSection(c) ? View.GONE : View.VISIBLE);
views.listHeaderView.setVisibility(View.GONE);
final String number = c.getString(CallLogQuery.NUMBER);
@@ -654,6 +656,16 @@
}
}
+ /** Returns true if this is the last item of a section. */
+ private boolean isLastOfSection(Cursor c) {
+ if (c.isLast()) return true;
+ final int section = c.getInt(CallLogQuery.SECTION);
+ if (!c.moveToNext()) return true;
+ final int nextSection = c.getInt(CallLogQuery.SECTION);
+ c.moveToPrevious();
+ return section != nextSection;
+ }
+
/** Checks whether the contact info from the call log matches the one from the contacts db. */
private boolean callLogInfoMatches(ContactInfo callLogInfo, ContactInfo info) {
// The call log only contains a subset of the fields in the contacts db.
diff --git a/src/com/android/contacts/calllog/CallLogListItemViews.java b/src/com/android/contacts/calllog/CallLogListItemViews.java
index 847e354..938b2e3 100644
--- a/src/com/android/contacts/calllog/CallLogListItemViews.java
+++ b/src/com/android/contacts/calllog/CallLogListItemViews.java
@@ -47,11 +47,13 @@
public final View listHeaderView;
/** The text of the header of a section. */
public final TextView listHeaderTextView;
+ /** The divider to be shown below items. */
+ public final View bottomDivider;
private CallLogListItemViews(QuickContactBadge quickContactView, View primaryActionView,
ImageView secondaryActionView, View unheardView, View dividerView,
PhoneCallDetailsViews phoneCallDetailsViews, View listItemView,
- View listHeaderView, TextView listHeaderTextView) {
+ View listHeaderView, TextView listHeaderTextView, View bottomDivider) {
this.quickContactView = quickContactView;
this.primaryActionView = primaryActionView;
this.secondaryActionView = secondaryActionView;
@@ -61,6 +63,7 @@
this.listItemView = listItemView;
this.listHeaderView = listHeaderView;
this.listHeaderTextView = listHeaderTextView;
+ this.bottomDivider = bottomDivider;
}
public static CallLogListItemViews fromView(View view) {
@@ -73,7 +76,8 @@
PhoneCallDetailsViews.fromView(view),
view.findViewById(R.id.call_log_item),
view.findViewById(R.id.call_log_header),
- (TextView) view.findViewById(R.id.call_log_header_text));
+ (TextView) view.findViewById(R.id.call_log_header_text),
+ view.findViewById(R.id.call_log_divider));
}
public static CallLogListItemViews createForTest(Context context) {
@@ -86,6 +90,7 @@
PhoneCallDetailsViews.createForTest(context),
new View(context),
new View(context),
- new TextView(context));
+ new TextView(context),
+ new View(context));
}
}
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index e3e8875..1ff16d2 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -21,6 +21,7 @@
import com.android.contacts.SpecialCharSequenceMgr;
import com.android.contacts.activities.DialtactsActivity;
import com.android.contacts.activities.DialtactsActivity.ViewPagerVisibilityListener;
+import com.android.contacts.util.PhoneNumberFormatter;
import com.android.internal.telephony.ITelephony;
import com.android.phone.CallLogAsync;
import com.android.phone.HapticFeedback;
@@ -150,33 +151,6 @@
private String mCurrentCountryIso;
- /**
- * May be null for a moment and filled by AsyncTask. Must not be touched outside UI thread.
- */
- private PhoneNumberFormattingTextWatcher mTextWatcher;
-
- /**
- * Delays {@link PhoneNumberFormattingTextWatcher} creation as it may cause disk read operation.
- */
- private final AsyncTask<Void, Void, Void> mTextWatcherLoadAsyncTask =
- new AsyncTask<Void, Void, Void>() {
-
- private PhoneNumberFormattingTextWatcher mTemporaryWatcher;
-
- @Override
- protected Void doInBackground(Void... params) {
- mTemporaryWatcher = new PhoneNumberFormattingTextWatcher(mCurrentCountryIso);
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- // Should be in UI thread.
- mTextWatcher = mTemporaryWatcher;
- mDigits.addTextChangedListener(mTextWatcher);
- }
- };
-
private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
/**
* Listen for phone state changes so that we can take down the
@@ -261,14 +235,7 @@
mDigits.setOnKeyListener(this);
mDigits.addTextChangedListener(this);
- if (mTextWatcher == null) {
- if (mTextWatcherLoadAsyncTask.getStatus() == AsyncTask.Status.PENDING) {
- // Start loading text watcher for phone number, which requires disk read.
- mTextWatcherLoadAsyncTask.execute();
- }
- } else {
- mDigits.addTextChangedListener(mTextWatcher);
- }
+ PhoneNumberFormatter.setPhoneNumberFormattingTextWatcher(getActivity(), mDigits);
// Soft menu button should appear only when there's no hardware menu button.
final View overflowMenuButton = fragmentView.findViewById(R.id.overflow_menu);
diff --git a/src/com/android/contacts/editor/TextFieldsEditorView.java b/src/com/android/contacts/editor/TextFieldsEditorView.java
index a448f4e..a4ad53a 100644
--- a/src/com/android/contacts/editor/TextFieldsEditorView.java
+++ b/src/com/android/contacts/editor/TextFieldsEditorView.java
@@ -23,6 +23,7 @@
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.util.NameConverter;
+import com.android.contacts.util.PhoneNumberFormatter;
import android.content.Context;
import android.content.Entity;
@@ -185,8 +186,7 @@
int inputType = field.inputType;
fieldView.setInputType(inputType);
if (inputType == InputType.TYPE_CLASS_PHONE) {
- fieldView.addTextChangedListener(new PhoneNumberFormattingTextWatcher(
- ContactsUtils.getCurrentCountryIso(mContext)));
+ PhoneNumberFormatter.setPhoneNumberFormattingTextWatcher(mContext, fieldView);
}
fieldView.setMinLines(field.minLines);
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index a4163fd..528e246 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -351,7 +351,7 @@
mAdapter.configureDirectoryLoader(loader);
return loader;
} else {
- CursorLoader loader = new CursorLoader(mContext, null, null, null, null, null);
+ CursorLoader loader = createCursorLoader();
long directoryId = args != null && args.containsKey(DIRECTORY_ID_ARG_KEY)
? args.getLong(DIRECTORY_ID_ARG_KEY)
: Directory.DEFAULT;
@@ -360,6 +360,10 @@
}
}
+ public CursorLoader createCursorLoader() {
+ return new CursorLoader(mContext, null, null, null, null, null);
+ }
+
private void startLoadingDirectoryPartition(int partitionIndex) {
DirectoryPartition partition = (DirectoryPartition)mAdapter.getPartition(partitionIndex);
partition.setStatus(DirectoryPartition.STATUS_LOADING);
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index c057a48..0553909 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -144,11 +144,6 @@
.appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build();
}
- protected static Uri includeProfileEntry(Uri uri) {
- return uri.buildUpon()
- .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "true").build();
- }
-
public boolean getHasPhoneNumber(int position) {
return ((Cursor)getItem(position)).getInt(CONTACT_HAS_PHONE_COLUMN_INDEX) != 0;
}
diff --git a/src/com/android/contacts/list/ContactsSectionIndexer.java b/src/com/android/contacts/list/ContactsSectionIndexer.java
index 109b8ba..5ecb31c 100644
--- a/src/com/android/contacts/list/ContactsSectionIndexer.java
+++ b/src/com/android/contacts/list/ContactsSectionIndexer.java
@@ -26,9 +26,9 @@
*/
public class ContactsSectionIndexer implements SectionIndexer {
- private final String[] mSections;
- private final int[] mPositions;
- private final int mCount;
+ private String[] mSections;
+ private int[] mPositions;
+ private int mCount;
/**
* Constructor.
@@ -95,8 +95,25 @@
}
public void setProfileHeader(String header) {
- if (mSections != null && mSections.length > 0) {
- mSections[0] = header;
+ if (mSections != null) {
+ // Don't do anything if the header is already set properly.
+ if (mSections.length > 0 && header.equals(mSections[0])) {
+ return;
+ }
+
+ // Since the section indexer isn't aware of the profile at the top, we need to add a
+ // special section at the top for it and shift everything else down.
+ String[] tempSections = new String[mSections.length + 1];
+ int[] tempPositions = new int[mPositions.length + 1];
+ tempSections[0] = header;
+ tempPositions[0] = 0;
+ for (int i = 1; i <= mPositions.length; i++) {
+ tempSections[i] = mSections[i - 1];
+ tempPositions[i] = mPositions[i - 1] + 1;
+ }
+ mSections = tempSections;
+ mPositions = tempPositions;
+ mCount++;
}
}
}
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 306e244..9ddc4b7 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -18,6 +18,7 @@
import com.android.contacts.R;
import com.android.contacts.editor.ContactEditorFragment;
+import android.content.CursorLoader;
import android.content.Intent;
import android.database.Cursor;
import android.provider.ContactsContract.Contacts;
@@ -56,6 +57,11 @@
}
@Override
+ public CursorLoader createCursorLoader() {
+ return new ProfileAndContactsLoader(getActivity());
+ }
+
+ @Override
protected void onItemClick(int position, long id) {
viewContact(getAdapter().getContactUri(position));
}
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
index 007af6c..9a3f05e 100644
--- a/src/com/android/contacts/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -57,6 +57,9 @@
@Override
public void configureLoader(CursorLoader loader, long directoryId) {
+ if (loader instanceof ProfileAndContactsLoader) {
+ ((ProfileAndContactsLoader) loader).setLoadProfile(shouldIncludeProfile());
+ }
ContactListFilter filter = getFilter();
if (isSearchMode()) {
@@ -129,11 +132,6 @@
.build();
}
- // Include the user's personal profile.
- if (shouldIncludeProfile()) {
- uri = includeProfileEntry(uri);
- }
-
loader.setUri(uri);
}
diff --git a/src/com/android/contacts/list/ProfileAndContactsLoader.java b/src/com/android/contacts/list/ProfileAndContactsLoader.java
new file mode 100644
index 0000000..7f85ea6
--- /dev/null
+++ b/src/com/android/contacts/list/ProfileAndContactsLoader.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 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.list;
+
+import com.google.android.collect.Lists;
+
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MergeCursor;
+import android.os.Bundle;
+import android.provider.ContactsContract.Profile;
+
+import java.util.List;
+
+/**
+ * A loader for use in the default contact list, which will also query for the user's profile
+ * if configured to do so.
+ */
+public class ProfileAndContactsLoader extends CursorLoader {
+
+ private boolean mLoadProfile;
+ private String[] mProjection;
+
+ public ProfileAndContactsLoader(Context context) {
+ super(context);
+ }
+
+ public void setLoadProfile(boolean flag) {
+ mLoadProfile = flag;
+ }
+
+ public void setProjection(String[] projection) {
+ super.setProjection(projection);
+ mProjection = projection;
+ }
+
+ @Override
+ public Cursor loadInBackground() {
+ // First load the profile, if enabled.
+ List<Cursor> cursors = Lists.newArrayList();
+ if (mLoadProfile) {
+ cursors.add(loadProfile());
+ }
+ final Cursor contactsCursor = super.loadInBackground();
+ cursors.add(contactsCursor);
+ return new MergeCursor(cursors.toArray(new Cursor[cursors.size()])) {
+ @Override
+ public Bundle getExtras() {
+ // Need to get the extras from the contacts cursor.
+ return contactsCursor.getExtras();
+ }
+ };
+ }
+
+ /**
+ * Loads the profile into a MatrixCursor.
+ */
+ private MatrixCursor loadProfile() {
+ Cursor cursor = getContext().getContentResolver().query(Profile.CONTENT_URI, mProjection,
+ null, null, null);
+ try {
+ MatrixCursor matrix = new MatrixCursor(mProjection);
+ Object[] row = new Object[mProjection.length];
+ while (cursor.moveToNext()) {
+ for (int i = 0; i < row.length; i++) {
+ row[i] = cursor.getString(i);
+ }
+ matrix.addRow(row);
+ }
+ return matrix;
+ } finally {
+ cursor.close();
+ }
+ }
+}
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index 65af3ee..33d6c97 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -45,6 +45,7 @@
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.util.Log;
+import android.util.TimingLogger;
import java.util.Collection;
import java.util.Collections;
@@ -275,7 +276,9 @@
if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
Log.d(Constants.PERFORMANCE_TAG, "AccountTypeManager.loadAccountsInBackground start");
}
- long startTime = SystemClock.currentThreadTimeMillis();
+ TimingLogger timings = new TimingLogger(TAG, "loadAccountsInBackground");
+ final long startTime = SystemClock.currentThreadTimeMillis();
+ final long startTimeWall = SystemClock.elapsedRealtime();
// Account types, keyed off the account type and data set concatenation.
Map<AccountTypeWithDataSet, AccountType> accountTypesByTypeAndDataSet = Maps.newHashMap();
@@ -371,6 +374,7 @@
} catch (RemoteException e) {
Log.w(TAG, "Problem loading accounts: " + e.toString());
}
+ timings.addSplit("Loaded account types");
// Map in accounts to associate the account names with each account type entry.
Account[] accounts = mAccountManager.getAccounts();
@@ -402,11 +406,7 @@
Collections.sort(allAccounts, ACCOUNT_COMPARATOR);
Collections.sort(writableAccounts, ACCOUNT_COMPARATOR);
- // The UI will need a phone number formatter. We can preload meta data for the
- // current locale to prevent a delay later on.
- PhoneNumberUtil.getInstance().getAsYouTypeFormatter(Locale.getDefault().getCountry());
-
- long endTime = SystemClock.currentThreadTimeMillis();
+ timings.addSplit("Loaded accounts");
synchronized (this) {
mAccountTypesWithDataSets = accountTypesByTypeAndDataSet;
@@ -416,8 +416,13 @@
mContext, allAccounts, accountTypesByTypeAndDataSet);
}
+ timings.dumpToLog();
+ final long endTimeWall = SystemClock.elapsedRealtime();
+ final long endTime = SystemClock.currentThreadTimeMillis();
+
Log.i(TAG, "Loaded meta-data for " + mAccountTypesWithDataSets.size() + " account types, "
- + mAccounts.size() + " accounts in " + (endTime - startTime) + "ms");
+ + mAccounts.size() + " accounts in " + (endTimeWall - startTimeWall) + "ms(wall) "
+ + (endTime - startTime) + "ms(cpu)");
if (mInitializationLatch != null) {
mInitializationLatch.countDown();
@@ -527,8 +532,7 @@
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Type " + accountTypeWithDataSet
- + " inviteClass=" + type.getInviteContactActivityClassName()
- + " inviteAction=" + type.getInviteContactActionLabel(context));
+ + " inviteClass=" + type.getInviteContactActivityClassName());
}
if (!TextUtils.isEmpty(type.getInviteContactActivityClassName())) {
result.put(accountTypeWithDataSet, type);
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index f22369f..472f701 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -432,7 +432,7 @@
if (result == null) return;
photoView.setImageBitmap(result);
}
- }.execute();
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
final int photoColumnIndex = cursor.getColumnIndex(Photo.PHOTO);
final byte[] photoBlob = cursor.getBlob(photoColumnIndex);
diff --git a/src/com/android/contacts/util/PhoneNumberFormatter.java b/src/com/android/contacts/util/PhoneNumberFormatter.java
new file mode 100644
index 0000000..6e63aac
--- /dev/null
+++ b/src/com/android/contacts/util/PhoneNumberFormatter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 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.util;
+
+import com.android.contacts.ContactsUtils;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.telephony.PhoneNumberFormattingTextWatcher;
+import android.widget.TextView;
+
+public final class PhoneNumberFormatter {
+ private PhoneNumberFormatter() {}
+
+ /**
+ * Load {@link TextWatcherLoadAsyncTask} in a worker thread and set it to a {@link TextView}.
+ */
+ private static class TextWatcherLoadAsyncTask extends
+ AsyncTask<Void, Void, PhoneNumberFormattingTextWatcher> {
+ private final String mCountryCode;
+ private final TextView mTextView;
+
+ public TextWatcherLoadAsyncTask(String countryCode, TextView textView) {
+ mCountryCode = countryCode;
+ mTextView = textView;
+ }
+
+ @Override
+ protected PhoneNumberFormattingTextWatcher doInBackground(Void... params) {
+ return new PhoneNumberFormattingTextWatcher(mCountryCode);
+ }
+
+ @Override
+ protected void onPostExecute(PhoneNumberFormattingTextWatcher watcher) {
+ if (watcher == null || isCancelled()) {
+ return; // May happen if we cancel the task.
+ }
+ if (mTextView.getHandler() == null) {
+ return; // View is already detached.
+ }
+ mTextView.addTextChangedListener(watcher);
+
+ // Note changes the user made before onPostExecute() will not be formatted, but
+ // once they type the next letter we format the entire text, so it's not a big deal.
+ // (And loading PhoneNumberFormattingTextWatcher is usually fast enough.)
+ // We could use watcher.afterTextChanged(mTextView.getEditableText()) to force format
+ // the existing content here, but that could cause unwanted results.
+ // (e.g. the contact editor thinks the user changed the content, and would save
+ // when closed even when the user didn't make other changes.)
+ }
+ }
+
+ /**
+ * Delay-set {@link PhoneNumberFormattingTextWatcher} to a {@link TextView}.
+ */
+ public static final void setPhoneNumberFormattingTextWatcher(Context context,
+ TextView textView) {
+ new TextWatcherLoadAsyncTask(ContactsUtils.getCurrentCountryIso(context), textView)
+ .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ }
+}
diff --git a/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java b/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java
index ef7913d..9e481f8 100644
--- a/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java
+++ b/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java
@@ -25,6 +25,7 @@
import static android.provider.VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK;
import com.android.contacts.R;
+import com.android.contacts.util.UriUtils;
import android.database.Cursor;
import android.net.Uri;
@@ -219,9 +220,9 @@
Uri actionUri = null;
if (action == Action.CALL_VOICEMAIL) {
- actionUri = Uri.parse(cursor.getString(VOICEMAIL_ACCESS_URI_INDEX));
+ actionUri = UriUtils.parseUriOrNull(cursor.getString(VOICEMAIL_ACCESS_URI_INDEX));
} else if (action == Action.CONFIGURE_VOICEMAIL) {
- actionUri = Uri.parse(cursor.getString(SETTINGS_URI_INDEX));
+ actionUri = UriUtils.parseUriOrNull(cursor.getString(SETTINGS_URI_INDEX));
}
return new MessageStatusWithPriority(
new StatusMessage(sourcePackage, overallState.getCallLogMessageId(),
diff --git a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
index f624113..4d24f54 100644
--- a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
+++ b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
@@ -516,12 +516,13 @@
}
final Intent intent = new Intent("android.intent.action.VIEW");
intent.setData(uri);
- bindIntentToClass(intent, "CallDetailActivity");
+ bindIntentToClass(intent, "com.android.contacts.CallDetailActivity");
startActivity(intent);
break;
}
case LEGACY_CALL_LOG_ACTIVITY: {
- startActivity(bindIntentToClass(new Intent(), "activities.CallLogActivity"));
+ startActivity(bindIntentToClass(new Intent(),
+ "com.android.contacts.activities.CallLogActivity"));
break;
}