summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2017-09-07 14:58:36 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2017-09-07 14:58:36 +0000
commit4662229bb3c8053a27b0030a0da359f4d99b042e (patch)
tree862d8001fffab8adc8b0dd13b68d9871bd14068a
parent54601a6cc03220108ac93c0663667d09b83eb074 (diff)
parentcc2cde0555bd49362f7631c64d24221b24ed71c8 (diff)
Merge changes I4b5a494b,I4b6f7ca8
* changes: Added logging to aid debugging of issue where dialer shows blank screen. NewSearchFragment contact photos now properly open quick contact cards.
-rw-r--r--java/com/android/dialer/app/DialtactsActivity.java43
-rw-r--r--java/com/android/dialer/app/calllog/CallLogFragment.java12
-rw-r--r--java/com/android/dialer/dialpadview/DialpadFragment.java22
-rw-r--r--java/com/android/dialer/searchfragment/common/SearchCursor.java7
-rw-r--r--java/com/android/dialer/searchfragment/cp2/SearchContactsCursor.java8
-rw-r--r--java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java2
-rw-r--r--java/com/android/dialer/searchfragment/list/NewSearchFragment.java38
-rw-r--r--java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java25
-rw-r--r--java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlacesCursor.java18
-rw-r--r--java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlacesCursorLoader.java38
-rw-r--r--java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java9
-rw-r--r--java/com/android/dialer/searchfragment/remote/RemoteContactsCursor.java40
-rw-r--r--java/com/android/dialer/searchfragment/remote/RemoteDirectoriesCursorLoader.java2
-rw-r--r--java/com/android/dialer/searchfragment/testing/TestSearchCursor.java5
14 files changed, 216 insertions, 53 deletions
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index 01bdfc223..3e6b50cae 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -516,7 +516,7 @@ public class DialtactsActivity extends TransactionSafeActivity
@Override
protected void onResume() {
- LogUtil.d("DialtactsActivity.onResume", "");
+ LogUtil.enterBlock("DialtactsActivity.onResume");
Trace.beginSection(TAG + " onResume");
super.onResume();
@@ -529,11 +529,14 @@ public class DialtactsActivity extends TransactionSafeActivity
mStateSaved = false;
if (mFirstLaunch) {
+ LogUtil.i("DialtactsActivity.onResume", "mFirstLaunch true, displaying fragment");
displayFragment(getIntent());
} else if (!phoneIsInUse() && mInCallDialpadUp) {
+ LogUtil.i("DialtactsActivity.onResume", "phone not in use, hiding dialpad fragment");
hideDialpadFragment(false, true);
mInCallDialpadUp = false;
} else if (mShowDialpadOnResume) {
+ LogUtil.i("DialtactsActivity.onResume", "showing dialpad on resume");
showDialpadFragment(false);
mShowDialpadOnResume = false;
} else {
@@ -662,10 +665,11 @@ public class DialtactsActivity extends TransactionSafeActivity
@Override
public void onAttachFragment(final Fragment fragment) {
- LogUtil.d("DialtactsActivity.onAttachFragment", "fragment: %s", fragment);
+ LogUtil.i("DialtactsActivity.onAttachFragment", "fragment: %s", fragment);
if (fragment instanceof DialpadFragment) {
mDialpadFragment = (DialpadFragment) fragment;
if (!mIsDialpadShown && !mShowDialpadOnResume) {
+ LogUtil.i("DialtactsActivity.onAttachFragment", "hiding dialpad fragment");
final FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.hide(mDialpadFragment);
transaction.commit();
@@ -830,8 +834,13 @@ public class DialtactsActivity extends TransactionSafeActivity
* @see #onDialpadShown
*/
private void showDialpadFragment(boolean animate) {
- LogUtil.d("DialtactActivity.showDialpadFragment", "animate: %b", animate);
- if (mIsDialpadShown || mStateSaved) {
+ LogUtil.i("DialtactActivity.showDialpadFragment", "animate: %b", animate);
+ if (mIsDialpadShown) {
+ LogUtil.i("DialtactsActivity.showDialpadFragment", "dialpad already shown");
+ return;
+ }
+ if (mStateSaved) {
+ LogUtil.i("DialtactsActivity.showDialpadFragment", "state already saved");
return;
}
mIsDialpadShown = true;
@@ -875,7 +884,7 @@ public class DialtactsActivity extends TransactionSafeActivity
/** Callback from child DialpadFragment when the dialpad is shown. */
@Override
public void onDialpadShown() {
- LogUtil.d("DialtactsActivity.onDialpadShown", "");
+ LogUtil.enterBlock("DialtactsActivity.onDialpadShown");
Assert.isNotNull(mDialpadFragment);
if (mDialpadFragment.getAnimate()) {
Assert.isNotNull(mDialpadFragment.getView()).startAnimation(mSlideIn);
@@ -894,6 +903,7 @@ public class DialtactsActivity extends TransactionSafeActivity
*/
@Override
public void hideDialpadFragment(boolean animate, boolean clearDialpad) {
+ LogUtil.enterBlock("DialtactsActivity.hideDialpadFragment");
if (mDialpadFragment == null || mDialpadFragment.getView() == null) {
return;
}
@@ -1081,11 +1091,17 @@ public class DialtactsActivity extends TransactionSafeActivity
return;
}
- final boolean showDialpadChooser =
+ boolean showDialpadChooser =
!ACTION_SHOW_TAB.equals(intent.getAction())
&& phoneIsInUse()
&& !DialpadFragment.isAddCallMode(intent);
- if (showDialpadChooser || (intent.getData() != null && isDialIntent(intent))) {
+ boolean isDialIntent = intent.getData() != null && isDialIntent(intent);
+ if (showDialpadChooser || isDialIntent) {
+ LogUtil.i(
+ "DialtactsActivity.displayFragment",
+ "showing dialpad fragment (showDialpadChooser: %b, isDialIntent: %b)",
+ showDialpadChooser,
+ isDialIntent);
showDialpadFragment(false);
mDialpadFragment.setStartedFromNewIntent(true);
if (showDialpadChooser && !mDialpadFragment.isVisible()) {
@@ -1109,6 +1125,7 @@ public class DialtactsActivity extends TransactionSafeActivity
@Override
public void onNewIntent(Intent newIntent) {
+ LogUtil.enterBlock("DialtactsActivity.onNewIntent");
setIntent(newIntent);
mFirstLaunch = true;
@@ -1135,17 +1152,19 @@ public class DialtactsActivity extends TransactionSafeActivity
/** Shows the search fragment */
private void enterSearchUi(boolean smartDialSearch, String query, boolean animate) {
+ LogUtil.i("DialtactsActivity.enterSearchUi", "smart dial: %b", smartDialSearch);
if (mStateSaved || getFragmentManager().isDestroyed()) {
// Weird race condition where fragment is doing work after the activity is destroyed
// due to talkback being on (b/10209937). Just return since we can't do any
// constructive here.
+ LogUtil.i(
+ "DialtactsActivity.enterSearchUi",
+ "not entering search UI (mStateSaved: %b, isDestroyed: %b)",
+ mStateSaved,
+ getFragmentManager().isDestroyed());
return;
}
- if (DEBUG) {
- LogUtil.v("DialtactsActivity.enterSearchUi", "smart dial " + smartDialSearch);
- }
-
final FragmentTransaction transaction = getFragmentManager().beginTransaction();
if (mInDialpadSearch && mSmartDialSearchFragment != null) {
transaction.remove(mSmartDialSearchFragment);
@@ -1232,6 +1251,8 @@ public class DialtactsActivity extends TransactionSafeActivity
/** Hides the search fragment */
private void exitSearchUi() {
+ LogUtil.enterBlock("DialtactsActivity.exitSearchUi");
+
// See related bug in enterSearchUI();
if (getFragmentManager().isDestroyed() || mStateSaved) {
return;
diff --git a/java/com/android/dialer/app/calllog/CallLogFragment.java b/java/com/android/dialer/app/calllog/CallLogFragment.java
index 6d4aea91f..441cb4a5c 100644
--- a/java/com/android/dialer/app/calllog/CallLogFragment.java
+++ b/java/com/android/dialer/app/calllog/CallLogFragment.java
@@ -201,7 +201,7 @@ public class CallLogFragment extends Fragment
@Override
public void onCreate(Bundle state) {
- LogUtil.d("CallLogFragment.onCreate", toString());
+ LogUtil.enterBlock("CallLogFragment.onCreate");
super.onCreate(state);
mRefreshDataRequired = true;
if (state != null) {
@@ -362,6 +362,7 @@ public class CallLogFragment extends Fragment
@Override
public void onActivityCreated(Bundle savedInstanceState) {
+ LogUtil.enterBlock("CallLogFragment.onActivityCreated");
super.onActivityCreated(savedInstanceState);
setupData();
updateSelectAllState(savedInstanceState);
@@ -384,7 +385,7 @@ public class CallLogFragment extends Fragment
@Override
public void onResume() {
- LogUtil.d("CallLogFragment.onResume", toString());
+ LogUtil.enterBlock("CallLogFragment.onResume");
super.onResume();
final boolean hasReadCallLogPermission =
PermissionsUtil.hasPermission(getActivity(), READ_CALL_LOG);
@@ -411,7 +412,7 @@ public class CallLogFragment extends Fragment
@Override
public void onPause() {
- LogUtil.d("CallLogFragment.onPause", toString());
+ LogUtil.enterBlock("CallLogFragment.onPause");
cancelDisplayUpdate();
mAdapter.onPause();
super.onPause();
@@ -419,6 +420,7 @@ public class CallLogFragment extends Fragment
@Override
public void onStart() {
+ LogUtil.enterBlock("CallLogFragment.onStart");
super.onStart();
CequintCallerIdManager cequintCallerIdManager = null;
if (CequintCallerIdManager.isCequintCallerIdEnabled(getContext())) {
@@ -429,6 +431,7 @@ public class CallLogFragment extends Fragment
@Override
public void onStop() {
+ LogUtil.enterBlock("CallLogFragment.onStop");
super.onStop();
mAdapter.onStop();
mContactInfoCache.stop();
@@ -436,7 +439,7 @@ public class CallLogFragment extends Fragment
@Override
public void onDestroy() {
- LogUtil.d("CallLogFragment.onDestroy", toString());
+ LogUtil.enterBlock("CallLogFragment.onDestroy");
mAdapter.changeCursor(null);
getActivity().getContentResolver().unregisterContentObserver(mCallLogObserver);
@@ -552,6 +555,7 @@ public class CallLogFragment extends Fragment
"Requesting permissions: " + Arrays.toString(deniedPermissions));
FragmentCompat.requestPermissions(this, deniedPermissions, PHONE_PERMISSIONS_REQUEST_CODE);
} else if (!mIsCallLogActivity) {
+ LogUtil.i("CallLogFragment.onEmptyViewActionButtonClicked", "showing dialpad");
// Show dialpad if we are not in the call log activity.
((HostInterface) activity).showDialpad();
}
diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java
index c15014fd0..e22250c6f 100644
--- a/java/com/android/dialer/dialpadview/DialpadFragment.java
+++ b/java/com/android/dialer/dialpadview/DialpadFragment.java
@@ -317,6 +317,7 @@ public class DialpadFragment extends Fragment
@Override
public void onCreate(Bundle state) {
Trace.beginSection(TAG + " onCreate");
+ LogUtil.enterBlock("DialpadFragment.onCreate");
super.onCreate(state);
mFirstLaunch = state == null;
@@ -352,6 +353,7 @@ public class DialpadFragment extends Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
Trace.beginSection(TAG + " onCreateView");
+ LogUtil.enterBlock("DialpadFragment.onCreateView");
Trace.beginSection(TAG + " inflate view");
View fragmentView = inflater.inflate(R.layout.dialpad_fragment, container, false);
Trace.endSection();
@@ -393,6 +395,7 @@ public class DialpadFragment extends Fragment
(v, event) -> {
if (isDigitsEmpty()) {
if (getActivity() != null) {
+ LogUtil.i("DialpadFragment.onCreateView", "dialpad spacer touched");
return ((HostInterface) getActivity()).onDialpadSpacerTouchWithEmptyQuery();
}
return true;
@@ -486,12 +489,16 @@ public class DialpadFragment extends Fragment
* screen to enter "Add Call" mode, this method will show correct UI for the mode.
*/
private void configureScreenFromIntent(Activity parent) {
+ LogUtil.enterBlock("DialpadFragment.configureScreenFromIntent");
+
// If we were not invoked with a DIAL intent
if (!Intent.ACTION_DIAL.equals(parent.getIntent().getAction())) {
setStartedFromNewIntent(false);
return;
}
+ LogUtil.i("DialpadFragment.configureScreenFromIntent", "dial intent");
+
// See if we were invoked with a DIAL intent. If we were, fill in the appropriate
// digits in the dialer field.
Intent intent = parent.getIntent();
@@ -521,6 +528,7 @@ public class DialpadFragment extends Fragment
if (!(mStartedFromNewIntent && digitsFilled)) {
final String action = intent.getAction();
+ LogUtil.i("DialpadFragment.configureScreenFromIntent", "action: %s", action);
if (Intent.ACTION_DIAL.equals(action)
|| Intent.ACTION_VIEW.equals(action)
|| Intent.ACTION_MAIN.equals(action)) {
@@ -532,6 +540,10 @@ public class DialpadFragment extends Fragment
}
}
}
+ LogUtil.i(
+ "DialpadFragment.configureScreenFromIntent",
+ "needToShowDialpadChooser? %b",
+ needToShowDialpadChooser);
showDialpadChooser(needToShowDialpadChooser);
setStartedFromNewIntent(false);
}
@@ -595,7 +607,7 @@ public class DialpadFragment extends Fragment
@Override
public void onStart() {
- LogUtil.d("DialpadFragment.onStart", "first launch: %b", mFirstLaunch);
+ LogUtil.i("DialpadFragment.onStart", "first launch: %b", mFirstLaunch);
Trace.beginSection(TAG + " onStart");
super.onStart();
// if the mToneGenerator creation fails, just continue without it. It is
@@ -622,7 +634,7 @@ public class DialpadFragment extends Fragment
@Override
public void onResume() {
- LogUtil.d("DialpadFragment.onResume", "");
+ LogUtil.enterBlock("DialpadFragment.onResume");
Trace.beginSection(TAG + " onResume");
super.onResume();
@@ -662,6 +674,7 @@ public class DialpadFragment extends Fragment
stopWatch.lap("fdin");
if (!isPhoneInUse()) {
+ LogUtil.i("DialpadFragment.onResume", "phone not in use");
// A sanity-check: the "dialpad chooser" UI should not be visible if the phone is idle.
showDialpadChooser(false);
}
@@ -711,6 +724,7 @@ public class DialpadFragment extends Fragment
@Override
public void onStop() {
+ LogUtil.enterBlock("DialpadFragment.onStop");
super.onStop();
synchronized (mToneGeneratorLock) {
@@ -991,6 +1005,7 @@ public class DialpadFragment extends Fragment
}
private void hideAndClearDialpad(boolean animate) {
+ LogUtil.enterBlock("DialpadFragment.hideAndClearDialpad");
FragmentUtils.getParentUnsafe(this, DialpadListener.class).hideDialpadFragment(animate, true);
}
@@ -1194,8 +1209,10 @@ public class DialpadFragment extends Fragment
} else {
LogUtil.i("DialpadFragment.showDialpadChooser", "Displaying normal Dialer UI.");
if (mDialpadView != null) {
+ LogUtil.i("DialpadFragment.showDialpadChooser", "mDialpadView not null");
mDialpadView.setVisibility(View.VISIBLE);
} else {
+ LogUtil.i("DialpadFragment.showDialpadChooser", "mDialpadView null");
mDigits.setVisibility(View.VISIBLE);
}
@@ -1681,6 +1698,7 @@ public class DialpadFragment extends Fragment
// one of the choices, which would be confusing. (But at
// least that's better than leaving the dialpad chooser
// onscreen, but useless...)
+ LogUtil.i("CallStateReceiver.onReceive", "hiding dialpad chooser, state: %s", state);
showDialpadChooser(false);
}
}
diff --git a/java/com/android/dialer/searchfragment/common/SearchCursor.java b/java/com/android/dialer/searchfragment/common/SearchCursor.java
index 368ee09d6..7ad19aabd 100644
--- a/java/com/android/dialer/searchfragment/common/SearchCursor.java
+++ b/java/com/android/dialer/searchfragment/common/SearchCursor.java
@@ -35,4 +35,11 @@ public interface SearchCursor extends Cursor {
* @return true if the data set has changed.
*/
boolean updateQuery(@NonNull String query);
+
+ /**
+ * Returns an ID unique to the directory this cursor reads from. Generally this value will be
+ * related to {@link android.provider.ContactsContract.Directory} but could differ depending on
+ * the implementation.
+ */
+ long getDirectoryId();
}
diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursor.java b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursor.java
index 18c9ecd7f..508ca7f57 100644
--- a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursor.java
+++ b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursor.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.MergeCursor;
+import android.provider.ContactsContract.Directory;
import android.support.annotation.Nullable;
import com.android.dialer.searchfragment.common.SearchCursor;
@@ -32,7 +33,7 @@ final class SearchContactsCursor extends MergeCursor implements SearchCursor {
private final ContactFilterCursor contactFilterCursor;
- public static SearchContactsCursor newInstnace(
+ static SearchContactsCursor newInstance(
Context context, ContactFilterCursor contactFilterCursor) {
MatrixCursor headerCursor = new MatrixCursor(HEADER_PROJECTION);
headerCursor.addRow(new String[] {context.getString(R.string.all_contacts)});
@@ -56,6 +57,11 @@ final class SearchContactsCursor extends MergeCursor implements SearchCursor {
}
@Override
+ public long getDirectoryId() {
+ return Directory.DEFAULT;
+ }
+
+ @Override
public int getCount() {
// If we don't have any contents, we don't want to show the header
int count = contactFilterCursor.getCount();
diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java
index 84fd64ae5..b7fc9b5c5 100644
--- a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java
+++ b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java
@@ -47,6 +47,6 @@ public final class SearchContactsCursorLoader extends CursorLoader {
// Filtering logic
ContactFilterCursor contactFilterCursor = new ContactFilterCursor(cursor, query);
// Header logic
- return SearchContactsCursor.newInstnace(getContext(), contactFilterCursor);
+ return SearchContactsCursor.newInstance(getContext(), contactFilterCursor);
}
}
diff --git a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
index 7fee9699a..910e454f8 100644
--- a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
+++ b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
@@ -120,7 +120,6 @@ public final class NewSearchFragment extends Fragment
private void initLoaders() {
getLoaderManager().initLoader(CONTACTS_LOADER_ID, null, this);
- loadNearbyPlacesCursor();
loadRemoteDirectoriesCursor();
}
@@ -129,7 +128,14 @@ public final class NewSearchFragment extends Fragment
if (id == CONTACTS_LOADER_ID) {
return new SearchContactsCursorLoader(getContext(), query);
} else if (id == NEARBY_PLACES_LOADER_ID) {
- return new NearbyPlacesCursorLoader(getContext(), query);
+ // Directories represent contact data sources on the device, but since nearby places aren't
+ // stored on the device, they don't have a directory ID. We pass the list of all existing IDs
+ // so that we can find one that doesn't collide.
+ List<Integer> directoryIds = new ArrayList<>();
+ for (Directory directory : directories) {
+ directoryIds.add(directory.getId());
+ }
+ return new NearbyPlacesCursorLoader(getContext(), query, directoryIds);
} else if (id == REMOTE_DIRECTORIES_LOADER_ID) {
return new RemoteDirectoriesCursorLoader(getContext());
} else if (id == REMOTE_CONTACTS_LOADER_ID) {
@@ -162,6 +168,7 @@ public final class NewSearchFragment extends Fragment
while (cursor.moveToNext()) {
directories.add(RemoteDirectoriesCursorLoader.readDirectory(cursor));
}
+ loadNearbyPlacesCursor();
loadRemoteContactsCursors();
} else {
@@ -212,18 +219,6 @@ public final class NewSearchFragment extends Fragment
ThreadUtil.getUiThreadHandler().removeCallbacks(capabilitiesUpdatedRunnable);
}
- private void loadNearbyPlacesCursor() {
- // Cancel existing load if one exists.
- ThreadUtil.getUiThreadHandler().removeCallbacks(loadNearbyPlacesRunnable);
-
- // If nearby places is not enabled, do not try to load them.
- if (!PhoneDirectoryExtenderAccessor.get(getContext()).isEnabled(getContext())) {
- return;
- }
- ThreadUtil.getUiThreadHandler()
- .postDelayed(loadNearbyPlacesRunnable, NETWORK_SEARCH_DELAY_MILLIS);
- }
-
@Override
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
@@ -250,12 +245,14 @@ public final class NewSearchFragment extends Fragment
}
}
+ // Loads remote directories.
private void loadRemoteDirectoriesCursor() {
if (!remoteDirectoriesDisabledForTesting) {
getLoaderManager().initLoader(REMOTE_DIRECTORIES_LOADER_ID, null, this);
}
}
+ // Should not be called before remote directories have finished loading.
private void loadRemoteContactsCursors() {
if (remoteDirectoriesDisabledForTesting) {
return;
@@ -267,6 +264,19 @@ public final class NewSearchFragment extends Fragment
.postDelayed(loadRemoteContactsRunnable, NETWORK_SEARCH_DELAY_MILLIS);
}
+ // Should not be called before remote directories (not contacts) have finished loading.
+ private void loadNearbyPlacesCursor() {
+ // Cancel existing load if one exists.
+ ThreadUtil.getUiThreadHandler().removeCallbacks(loadNearbyPlacesRunnable);
+
+ // If nearby places is not enabled, do not try to load them.
+ if (!PhoneDirectoryExtenderAccessor.get(getContext()).isEnabled(getContext())) {
+ return;
+ }
+ ThreadUtil.getUiThreadHandler()
+ .postDelayed(loadNearbyPlacesRunnable, NETWORK_SEARCH_DELAY_MILLIS);
+ }
+
@Override
public void onResume() {
super.onResume();
diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java b/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java
index 575582e07..fa0782623 100644
--- a/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java
+++ b/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java
@@ -17,13 +17,14 @@
package com.android.dialer.searchfragment.nearbyplaces;
import android.content.Context;
-import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.QuickContactBadge;
import android.widget.TextView;
+import com.android.contacts.common.util.Constants;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.contactphoto.ContactPhotoManager;
@@ -31,6 +32,7 @@ import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.searchfragment.common.Projections;
import com.android.dialer.searchfragment.common.QueryBoldingUtil;
import com.android.dialer.searchfragment.common.R;
+import com.android.dialer.searchfragment.common.SearchCursor;
import com.android.dialer.telecom.TelecomUtil;
/** ViewHolder for a nearby place row. */
@@ -57,14 +59,13 @@ public final class NearbyPlaceViewHolder extends RecyclerView.ViewHolder
* Binds the ViewHolder with a cursor from {@link NearbyPlacesCursorLoader} with the data found at
* the cursors set position.
*/
- public void bind(Cursor cursor, String query) {
+ public void bind(SearchCursor cursor, String query) {
number = cursor.getString(Projections.PHONE_NUMBER);
String name = cursor.getString(Projections.PHONE_DISPLAY_NAME);
String address = cursor.getString(Projections.PHONE_LABEL);
placeName.setText(QueryBoldingUtil.getNameWithQueryBolded(query, name));
placeAddress.setText(QueryBoldingUtil.getNameWithQueryBolded(query, address));
-
String photoUri = cursor.getString(Projections.PHONE_PHOTO_URI);
ContactPhotoManager.getInstance(context)
.loadDialerThumbnailOrPhoto(
@@ -73,13 +74,21 @@ public final class NearbyPlaceViewHolder extends RecyclerView.ViewHolder
cursor.getLong(Projections.PHONE_PHOTO_ID),
photoUri == null ? null : Uri.parse(photoUri),
name,
- LetterTileDrawable.TYPE_DEFAULT);
+ LetterTileDrawable.TYPE_BUSINESS);
}
- private static Uri getContactUri(Cursor cursor) {
- long contactId = cursor.getLong(Projections.PHONE_ID);
- String lookupKey = cursor.getString(Projections.PHONE_LOOKUP_KEY);
- return ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
+ private static Uri getContactUri(SearchCursor cursor) {
+ // Since the lookup key for Nearby Places is actually a JSON representation of the information,
+ // we need to pass it in as an encoded fragment in our contact uri.
+ // It includes information like display name, photo uri, phone number, ect.
+ String businessInfoJson = cursor.getString(Projections.PHONE_LOOKUP_KEY);
+ return Contacts.CONTENT_LOOKUP_URI
+ .buildUpon()
+ .appendPath(Constants.LOOKUP_URI_ENCODED)
+ .appendQueryParameter(
+ ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(cursor.getDirectoryId()))
+ .encodedFragment(businessInfoJson)
+ .build();
}
@Override
diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlacesCursor.java b/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlacesCursor.java
index a4142a41d..3be59b672 100644
--- a/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlacesCursor.java
+++ b/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlacesCursor.java
@@ -27,16 +27,23 @@ import com.android.dialer.searchfragment.common.SearchCursor;
final class NearbyPlacesCursor extends MergeCursor implements SearchCursor {
private final Cursor nearbyPlacesCursor;
+ private final long directoryId;
- public static NearbyPlacesCursor newInstnace(Context context, Cursor nearbyPlacesCursor) {
+ /**
+ * @param directoryId unique directory id that doesn't collide with other remote/local
+ * directories. directoryIds are needed to load the correct quick contact card.
+ */
+ static NearbyPlacesCursor newInstance(
+ Context context, Cursor nearbyPlacesCursor, long directoryId) {
MatrixCursor headerCursor = new MatrixCursor(HEADER_PROJECTION);
headerCursor.addRow(new String[] {context.getString(R.string.nearby_places)});
- return new NearbyPlacesCursor(new Cursor[] {headerCursor, nearbyPlacesCursor});
+ return new NearbyPlacesCursor(new Cursor[] {headerCursor, nearbyPlacesCursor}, directoryId);
}
- private NearbyPlacesCursor(Cursor[] cursors) {
+ private NearbyPlacesCursor(Cursor[] cursors, long directoryId) {
super(cursors);
nearbyPlacesCursor = cursors[1];
+ this.directoryId = directoryId;
}
@Override
@@ -61,4 +68,9 @@ final class NearbyPlacesCursor extends MergeCursor implements SearchCursor {
int count = nearbyPlacesCursor.getCount();
return count == 0 ? 0 : count + 1;
}
+
+ @Override
+ public long getDirectoryId() {
+ return directoryId;
+ }
}
diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlacesCursorLoader.java b/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlacesCursorLoader.java
index 6807a6e6b..c8bb36a73 100644
--- a/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlacesCursorLoader.java
+++ b/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlacesCursorLoader.java
@@ -21,21 +21,37 @@ import android.content.CursorLoader;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
+import android.support.annotation.NonNull;
import com.android.contacts.common.extensions.PhoneDirectoryExtenderAccessor;
+import com.android.dialer.common.LogUtil;
import com.android.dialer.searchfragment.common.Projections;
+import java.util.List;
/** Cursor loader for nearby places search results. */
public final class NearbyPlacesCursorLoader extends CursorLoader {
private static final String MAX_RESULTS = "3";
+ private static final long INVALID_DIRECTORY_ID = Long.MAX_VALUE;
+ private final long directoryId;
- public NearbyPlacesCursorLoader(Context context, String query) {
+ /**
+ * @param directoryIds List of directoryIds associated with all directories on device. Required in
+ * order to find a directory ID for the nearby places cursor that doesn't collide with
+ * existing directories.
+ */
+ public NearbyPlacesCursorLoader(
+ Context context, String query, @NonNull List<Integer> directoryIds) {
super(context, getContentUri(context, query), Projections.PHONE_PROJECTION, null, null, null);
+ this.directoryId = getDirectoryId(directoryIds);
}
@Override
public Cursor loadInBackground() {
- return NearbyPlacesCursor.newInstnace(getContext(), super.loadInBackground());
+ if (directoryId == INVALID_DIRECTORY_ID) {
+ LogUtil.i("NearbyPlacesCursorLoader.loadInBackground", "directory id not set.");
+ return null;
+ }
+ return NearbyPlacesCursor.newInstance(getContext(), super.loadInBackground(), directoryId);
}
private static Uri getContentUri(Context context, String query) {
@@ -46,4 +62,22 @@ public final class NearbyPlacesCursorLoader extends CursorLoader {
.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, MAX_RESULTS)
.build();
}
+
+ private static long getDirectoryId(List<Integer> directoryIds) {
+ if (directoryIds.isEmpty()) {
+ return INVALID_DIRECTORY_ID;
+ }
+
+ // The Directory.LOCAL_INVISIBLE might not be a directory we use, but we can't reuse it's
+ // "special" ID.
+ long maxId = ContactsContract.Directory.LOCAL_INVISIBLE;
+ for (int i = 0, n = directoryIds.size(); i < n; i++) {
+ long id = directoryIds.get(i);
+ if (id > maxId) {
+ maxId = id;
+ }
+ }
+ // Add one so that the nearby places ID doesn't collide with extended directory IDs.
+ return maxId + 1;
+ }
}
diff --git a/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java b/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java
index 5fb12d349..df3eacc5b 100644
--- a/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java
+++ b/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java
@@ -22,6 +22,7 @@ import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
@@ -119,10 +120,14 @@ public final class RemoteContactViewHolder extends RecyclerView.ViewHolder
return (String) Phone.getTypeLabel(resources, numberType, numberLabel);
}
- private static Uri getContactUri(Cursor cursor) {
+ private static Uri getContactUri(SearchCursor cursor) {
long contactId = cursor.getLong(Projections.PHONE_ID);
String lookupKey = cursor.getString(Projections.PHONE_LOOKUP_KEY);
- return ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
+ return Contacts.getLookupUri(contactId, lookupKey)
+ .buildUpon()
+ .appendQueryParameter(
+ ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(cursor.getDirectoryId()))
+ .build();
}
@Override
diff --git a/java/com/android/dialer/searchfragment/remote/RemoteContactsCursor.java b/java/com/android/dialer/searchfragment/remote/RemoteContactsCursor.java
index d7c4f3805..e6f3c2607 100644
--- a/java/com/android/dialer/searchfragment/remote/RemoteContactsCursor.java
+++ b/java/com/android/dialer/searchfragment/remote/RemoteContactsCursor.java
@@ -26,6 +26,7 @@ import com.android.dialer.common.Assert;
import com.android.dialer.searchfragment.common.SearchCursor;
import com.android.dialer.searchfragment.remote.RemoteDirectoriesCursorLoader.Directory;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -41,6 +42,16 @@ import java.util.List;
public final class RemoteContactsCursor extends MergeCursor implements SearchCursor {
/**
+ * {@link SearchCursor#HEADER_PROJECTION} with {@link #COLUMN_DIRECTORY_ID} appended on the end.
+ *
+ * <p>This is needed to get the directoryId associated with each contact. directoryIds are needed
+ * to load the correct quick contact card.
+ */
+ private static final String[] PROJECTION = buildProjection();
+
+ private static final String COLUMN_DIRECTORY_ID = "directory_id";
+
+ /**
* Returns a single cursor with headers inserted between each non-empty cursor. If all cursors are
* empty, null or closed, this method returns null.
*/
@@ -78,18 +89,24 @@ public final class RemoteContactsCursor extends MergeCursor implements SearchCur
continue;
}
- cursorList.add(createHeaderCursor(context, directory.getDisplayName()));
+ cursorList.add(createHeaderCursor(context, directory.getDisplayName(), directory.getId()));
cursorList.add(cursor);
}
return cursorList.toArray(new Cursor[cursorList.size()]);
}
- private static MatrixCursor createHeaderCursor(Context context, String name) {
- MatrixCursor headerCursor = new MatrixCursor(HEADER_PROJECTION, 1);
- headerCursor.addRow(new String[] {context.getString(R.string.directory, name)});
+ private static MatrixCursor createHeaderCursor(Context context, String name, int id) {
+ MatrixCursor headerCursor = new MatrixCursor(PROJECTION, 1);
+ headerCursor.addRow(new Object[] {context.getString(R.string.directory, name), id});
return headerCursor;
}
+ private static String[] buildProjection() {
+ String[] projection = Arrays.copyOf(HEADER_PROJECTION, HEADER_PROJECTION.length + 1);
+ projection[projection.length - 1] = COLUMN_DIRECTORY_ID;
+ return projection;
+ }
+
/** Returns true if the current position is a header row. */
@Override
public boolean isHeader() {
@@ -97,6 +114,21 @@ public final class RemoteContactsCursor extends MergeCursor implements SearchCur
}
@Override
+ public long getDirectoryId() {
+ int position = getPosition();
+ // proceed backwards until we reach the header row, which contains the directory ID.
+ while (moveToPrevious()) {
+ int id = getInt(getColumnIndex(COLUMN_DIRECTORY_ID));
+ if (id != -1) {
+ // return the cursor to it's original position/state
+ moveToPosition(position);
+ return id;
+ }
+ }
+ throw Assert.createIllegalStateFailException("No directory id for contact at: " + position);
+ }
+
+ @Override
public boolean updateQuery(@Nullable String query) {
// When the query changes, a new network request is made for nearby places. Meaning this cursor
// will be closed and another created, so return false.
diff --git a/java/com/android/dialer/searchfragment/remote/RemoteDirectoriesCursorLoader.java b/java/com/android/dialer/searchfragment/remote/RemoteDirectoriesCursorLoader.java
index 327a62c7b..de71025cd 100644
--- a/java/com/android/dialer/searchfragment/remote/RemoteDirectoriesCursorLoader.java
+++ b/java/com/android/dialer/searchfragment/remote/RemoteDirectoriesCursorLoader.java
@@ -67,7 +67,7 @@ public final class RemoteDirectoriesCursorLoader extends CursorLoader {
return new AutoValue_RemoteDirectoriesCursorLoader_Directory(id, displayName, supportsPhotos);
}
- abstract int getId();
+ public abstract int getId();
/** Returns a user facing display name of the directory. Null if none exists. */
abstract @Nullable String getDisplayName();
diff --git a/java/com/android/dialer/searchfragment/testing/TestSearchCursor.java b/java/com/android/dialer/searchfragment/testing/TestSearchCursor.java
index 9a0b95789..7e6299eac 100644
--- a/java/com/android/dialer/searchfragment/testing/TestSearchCursor.java
+++ b/java/com/android/dialer/searchfragment/testing/TestSearchCursor.java
@@ -44,4 +44,9 @@ public final class TestSearchCursor extends MergeCursor implements SearchCursor
public boolean updateQuery(@Nullable String query) {
return false;
}
+
+ @Override
+ public long getDirectoryId() {
+ return 0;
+ }
}