Merge "Use ContactsContract.PhoneLookup to look up SIP addresses." into ics-mr1
diff --git a/src/com/android/contacts/ContactsApplication.java b/src/com/android/contacts/ContactsApplication.java
index f806c1d..16f9e57 100644
--- a/src/com/android/contacts/ContactsApplication.java
+++ b/src/com/android/contacts/ContactsApplication.java
@@ -23,6 +23,8 @@
import com.google.common.annotations.VisibleForTesting;
import android.app.Application;
+import android.app.FragmentManager;
+import android.app.LoaderManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
@@ -31,6 +33,9 @@
import android.util.Log;
public final class ContactsApplication extends Application {
+ private static final boolean ENABLE_LOADER_LOG = false; // Don't submit with true
+ private static final boolean ENABLE_FRAGMENT_LOG = false; // Don't submit with true
+
private static InjectedServices sInjectedServices;
private AccountTypeManager mAccountTypeManager;
private ContactPhotoManager mContactPhotoManager;
@@ -118,6 +123,8 @@
Context context = getApplicationContext();
PreferenceManager.getDefaultSharedPreferences(context);
AccountTypeManager.getInstance(context);
+ if (ENABLE_FRAGMENT_LOG) FragmentManager.enableDebugLogging(true);
+ if (ENABLE_LOADER_LOG) LoaderManager.enableDebugLogging(true);
if (Log.isLoggable(Constants.STRICT_MODE_TAG, Log.DEBUG)) {
StrictMode.setThreadPolicy(
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 96136a2..88aab4d 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -20,6 +20,7 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.activities.DialtactsActivity.ViewPagerVisibilityListener;
+import com.android.contacts.util.EmptyLoader;
import com.android.contacts.voicemail.VoicemailStatusHelper;
import com.android.contacts.voicemail.VoicemailStatusHelper.StatusMessage;
import com.android.contacts.voicemail.VoicemailStatusHelperImpl;
@@ -59,6 +60,11 @@
CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher {
private static final String TAG = "CallLogFragment";
+ /**
+ * ID of the empty loader to defer other fragments.
+ */
+ private static final int EMPTY_LOADER_ID = 0;
+
private CallLogAdapter mAdapter;
private CallLogQueryHandler mCallLogQueryHandler;
private boolean mScrollToTop;
@@ -75,6 +81,10 @@
private TextView mStatusMessageAction;
private KeyguardManager mKeyguardManager;
+ private boolean mEmptyLoaderRunning;
+ private boolean mCallLogFetched;
+ private boolean mVoicemailStatusFetched;
+
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
@@ -103,6 +113,8 @@
listView.smoothScrollToPosition(0);
mScrollToTop = false;
}
+ mCallLogFetched = true;
+ destroyEmptyLoaderIfAllDataFetched();
}
/**
@@ -118,6 +130,15 @@
int activeSources = mVoicemailStatusHelper.getNumberActivityVoicemailSources(statusCursor);
setVoicemailSourcesAvailable(activeSources != 0);
MoreCloseables.closeQuietly(statusCursor);
+ mVoicemailStatusFetched = true;
+ destroyEmptyLoaderIfAllDataFetched();
+ }
+
+ private void destroyEmptyLoaderIfAllDataFetched() {
+ if (mCallLogFetched && mVoicemailStatusFetched && mEmptyLoaderRunning) {
+ mEmptyLoaderRunning = false;
+ getLoaderManager().destroyLoader(EMPTY_LOADER_ID);
+ }
}
/** Sets whether there are any voicemail sources available in the platform. */
@@ -155,6 +176,12 @@
@Override
public void onStart() {
mScrollToTop = true;
+
+ // Start the empty loader now to defer other fragments. We destroy it when both calllog
+ // and the voicemail status are fetched.
+ getLoaderManager().initLoader(EMPTY_LOADER_ID, null,
+ new EmptyLoader.Callback(getActivity()));
+ mEmptyLoaderRunning = true;
super.onStart();
}
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 5d7ab93..e63ee28 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -387,6 +387,16 @@
}
/**
+ * Reset the list adapter in this {@link Fragment} to get rid of any saved scroll position
+ * from a previous contact.
+ */
+ public void resetAdapter() {
+ if (mListView != null) {
+ mListView.setAdapter(mAdapter);
+ }
+ }
+
+ /**
* Returns the top coordinate of the first item in the {@link ListView}. If the first item
* in the {@link ListView} is not visible or there are no children in the list, then return
* Integer.MIN_VALUE. Note that the returned value will be <= 0 because the first item in the
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index 2bcd1a0..74811e4 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -20,6 +20,7 @@
import com.android.contacts.NfcHandler;
import com.android.contacts.R;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
+import com.android.contacts.util.UriUtils;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
@@ -28,6 +29,7 @@
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
+import android.net.Uri;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
@@ -42,6 +44,7 @@
*/
public class ContactDetailLayoutController {
+ private static final String KEY_CONTACT_URI = "contactUri";
private static final String KEY_CONTACT_HAS_UPDATES = "contactHasUpdates";
private static final String KEY_CURRENT_PAGE_INDEX = "currentPageIndex";
@@ -78,6 +81,7 @@
private ContactDetailFragment.Listener mContactDetailFragmentListener;
private ContactLoader.Result mContactData;
+ private Uri mContactUri;
private boolean mTabCarouselIsAnimating;
private boolean mContactHasUpdates;
@@ -144,6 +148,7 @@
// Read from savedState if possible
int currentPageIndex = 0;
if (savedState != null) {
+ mContactUri = savedState.getParcelable(KEY_CONTACT_URI);
mContactHasUpdates = savedState.getBoolean(KEY_CONTACT_HAS_UPDATES);
currentPageIndex = savedState.getInt(KEY_CURRENT_PAGE_INDEX, 0);
}
@@ -269,13 +274,18 @@
}
/**
- * Setup the layout for the contact with updates. Pass in the index of the current page to
- * select or null if the current selection should be left as is.
+ * Setup the layout for the contact with updates.
+ * TODO: Clean up this method so it's easier to understand.
*/
private void showContactWithUpdates() {
if (mContactData == null) {
return;
}
+
+ Uri previousContactUri = mContactUri;
+ mContactUri = mContactData.getLookupUri();
+ boolean isDifferentContact = !UriUtils.areEqual(previousContactUri, mContactUri);
+
switch (mLayoutMode) {
case TWO_COLUMN: {
// Set the contact data (hide the static photo because the photo will already be in
@@ -292,6 +302,11 @@
mTabCarousel.setVisibility(View.VISIBLE);
// Update ViewPager to allow swipe between all the fragments (to see updates)
mViewPagerAdapter.enableSwipe(true);
+ // If this is a different contact than before, then reset some views.
+ if (isDifferentContact) {
+ resetViewPager();
+ resetTabCarousel();
+ }
break;
}
case FRAGMENT_CAROUSEL: {
@@ -303,14 +318,27 @@
throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
}
- mDetailFragment.setData(mContactData.getLookupUri(), mContactData);
- mUpdatesFragment.setData(mContactData.getLookupUri(), mContactData);
+ if (isDifferentContact) {
+ resetFragments();
+ }
+
+ mDetailFragment.setData(mContactUri, mContactData);
+ mUpdatesFragment.setData(mContactUri, mContactData);
}
+ /**
+ * Setup the layout for the contact without updates.
+ * TODO: Clean up this method so it's easier to understand.
+ */
private void showContactWithoutUpdates() {
if (mContactData == null) {
return;
}
+
+ Uri previousContactUri = mContactUri;
+ mContactUri = mContactData.getLookupUri();
+ boolean isDifferentContact = !UriUtils.areEqual(previousContactUri, mContactUri);
+
switch (mLayoutMode) {
case TWO_COLUMN:
// Show the static photo which is next to the list of scrolling contact details
@@ -336,7 +364,24 @@
throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
}
- mDetailFragment.setData(mContactData.getLookupUri(), mContactData);
+ if (isDifferentContact) {
+ resetFragments();
+ }
+
+ mDetailFragment.setData(mContactUri, mContactData);
+ }
+
+ private void resetTabCarousel() {
+ mTabCarousel.reset();
+ }
+
+ private void resetViewPager() {
+ mViewPager.setCurrentItem(0, false /* smooth transition */);
+ }
+
+ private void resetFragments() {
+ mDetailFragment.resetAdapter();
+ mUpdatesFragment.resetAdapter();
}
public FragmentKeyListener getCurrentPage() {
@@ -365,6 +410,7 @@
}
public void onSaveInstanceState(Bundle outState) {
+ outState.putParcelable(KEY_CONTACT_URI, mContactUri);
outState.putBoolean(KEY_CONTACT_HAS_UPDATES, mContactHasUpdates);
outState.putInt(KEY_CURRENT_PAGE_INDEX, getCurrentPageIndex());
}
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index 4700078..045e900 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -180,6 +180,16 @@
}
/**
+ * Reset the carousel to the start position (i.e. because new data will be loaded in for a
+ * different contact).
+ */
+ public void reset() {
+ scrollTo(0, 0);
+ setCurrentTab(0);
+ moveToYCoordinate(0, 0);
+ }
+
+ /**
* Set the current tab that should be restored when the view is first laid out.
*/
public void restoreCurrentTab(int position) {
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index afe159b..fd59674 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -158,6 +158,14 @@
}
}
+ /**
+ * Reset the list adapter in this {@link Fragment} to get rid of any saved scroll position
+ * from a previous contact.
+ */
+ public void resetAdapter() {
+ setListAdapter(mStreamItemAdapter);
+ }
+
@Override
public void setAlphaLayerValue(float alpha) {
// If the alpha layer is not ready yet, store it for later when the view is initialized
diff --git a/src/com/android/contacts/group/GroupDetailFragment.java b/src/com/android/contacts/group/GroupDetailFragment.java
index 5b275bd..f0e4175 100644
--- a/src/com/android/contacts/group/GroupDetailFragment.java
+++ b/src/com/android/contacts/group/GroupDetailFragment.java
@@ -193,7 +193,6 @@
* Start the loader to retrieve the metadata for this group.
*/
private void startGroupMetadataLoader() {
- getLoaderManager().destroyLoader(LOADER_METADATA);
getLoaderManager().restartLoader(LOADER_METADATA, null, mGroupMetadataLoaderListener);
}
@@ -201,7 +200,6 @@
* Start the loader to retrieve the list of group members.
*/
private void startGroupMembersLoader() {
- getLoaderManager().destroyLoader(LOADER_MEMBERS);
getLoaderManager().restartLoader(LOADER_MEMBERS, null, mGroupMemberListLoaderListener);
}
diff --git a/src/com/android/contacts/util/Constants.java b/src/com/android/contacts/util/Constants.java
index 3a43c40..eb68f5a 100644
--- a/src/com/android/contacts/util/Constants.java
+++ b/src/com/android/contacts/util/Constants.java
@@ -32,18 +32,6 @@
public static final String PERFORMANCE_TAG = "ContactsPerf";
/**
- * Log tag for enabling/disabling LoaderManager log.
- * To enable: adb shell setprop log.tag.ContactsLoaderManager DEBUG
- */
- public static final String LOADER_MANAGER_TAG = "ContactsLoaderManager";
-
- /**
- * Log tag for enabling/disabling FragmentManager log.
- * To enable: adb shell setprop log.tag.ContactsFragmentManager DEBUG
- */
- public static final String FRAGMENT_MANAGER_TAG = "ContactsFragmentManager";
-
- /**
* Log tag for enabling/disabling StrictMode violation log.
* To enable: adb shell setprop log.tag.ContactsStrictMode DEBUG
*/
diff --git a/src/com/android/contacts/util/EmptyLoader.java b/src/com/android/contacts/util/EmptyLoader.java
new file mode 100644
index 0000000..97478bd
--- /dev/null
+++ b/src/com/android/contacts/util/EmptyLoader.java
@@ -0,0 +1,60 @@
+/*
+ * 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 android.app.LoaderManager.LoaderCallbacks;
+import android.content.Context;
+import android.content.Loader;
+import android.os.Bundle;
+
+/**
+ * A {@link Loader} only used to make use of the {@link android.app.Fragment#setStartDeferred}
+ * feature from an old-style fragment which doesn't use {@link Loader}s to load data.
+ *
+ * This loader never delivers results. A caller fragment must destroy it when deferred fragments
+ * should be started.
+ */
+public class EmptyLoader extends Loader<Object> {
+ public EmptyLoader(Context context) {
+ super(context);
+ }
+
+ /**
+ * {@link LoaderCallbacks} which just generates {@link EmptyLoader}. {@link #onLoadFinished}
+ * and {@link #onLoaderReset} are no-op.
+ */
+ public static class Callback implements LoaderCallbacks<Object> {
+ private final Context mContext;
+
+ public Callback(Context context) {
+ mContext = context.getApplicationContext();
+ }
+
+ @Override
+ public Loader<Object> onCreateLoader(int id, Bundle args) {
+ return new EmptyLoader(mContext);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Object> loader, Object data) {
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Object> loader) {
+ }
+ }
+}