summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcalderwoodra <calderwoodra@google.com>2018-03-27 06:45:58 +0000
committerandroid-build-merger <android-build-merger@google.com>2018-03-27 06:45:58 +0000
commit7ec046ccaf133eaafaab2f4acde76e7159c481ec (patch)
tree8588b9122e464ebe64930271c766a3120ee5ac60
parent8227ac10324359f28c936d6f6d4b216e4e4905ed (diff)
parent966800d977660c8ce78d988af5284647d02d6555 (diff)
Merge changes I1e9b61d7,I2720a252,I1b162f3e
am: 966800d977 Change-Id: I3d41da3f582a7bb0f23080ea4888658ea3881c37
-rw-r--r--AndroidManifest.xml2
-rw-r--r--java/com/android/contacts/common/dialog/CallSubjectDialog.java8
-rw-r--r--java/com/android/contacts/common/extensions/PhoneDirectoryExtender.java8
-rw-r--r--java/com/android/contacts/common/extensions/PhoneDirectoryExtenderStub.java8
-rw-r--r--java/com/android/contacts/common/format/TextHighlighter.java142
-rw-r--r--java/com/android/contacts/common/list/AutoScrollListView.java125
-rw-r--r--java/com/android/contacts/common/list/ContactEntryListAdapter.java772
-rw-r--r--java/com/android/contacts/common/list/ContactEntryListFragment.java860
-rw-r--r--java/com/android/contacts/common/list/ContactListAdapter.java232
-rw-r--r--java/com/android/contacts/common/list/ContactListItemView.java1508
-rw-r--r--java/com/android/contacts/common/list/ContactListPinnedHeaderView.java70
-rw-r--r--java/com/android/contacts/common/list/ContactsSectionIndexer.java119
-rw-r--r--java/com/android/contacts/common/list/DefaultContactListAdapter.java216
-rw-r--r--java/com/android/contacts/common/list/DirectoryListLoader.java210
-rw-r--r--java/com/android/contacts/common/list/DirectoryPartition.java179
-rw-r--r--java/com/android/contacts/common/list/IndexerListAdapter.java214
-rw-r--r--java/com/android/contacts/common/list/PhoneNumberListAdapter.java656
-rw-r--r--java/com/android/contacts/common/list/PhoneNumberPickerFragment.java465
-rw-r--r--java/com/android/contacts/common/list/PinnedHeaderListAdapter.java159
-rw-r--r--java/com/android/contacts/common/list/PinnedHeaderListView.java563
-rw-r--r--java/com/android/dialer/app/AndroidManifest.xml2
-rw-r--r--java/com/android/dialer/app/DialtactsActivity.java189
-rw-r--r--java/com/android/dialer/app/calllog/CallLogAsyncTaskUtil.java4
-rw-r--r--java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java6
-rw-r--r--java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java6
-rw-r--r--java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java9
-rw-r--r--java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java10
-rw-r--r--java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java47
-rw-r--r--java/com/android/dialer/app/legacybindings/DialerLegacyBindings.java3
-rw-r--r--java/com/android/dialer/app/legacybindings/DialerLegacyBindingsStub.java6
-rw-r--r--java/com/android/dialer/app/list/AllContactsFragment.java204
-rw-r--r--java/com/android/dialer/app/list/BlockedListSearchAdapter.java84
-rw-r--r--java/com/android/dialer/app/list/BlockedListSearchFragment.java248
-rw-r--r--java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java236
-rw-r--r--java/com/android/dialer/app/list/DialtactsPagerAdapter.java19
-rw-r--r--java/com/android/dialer/app/list/RegularSearchFragment.java199
-rw-r--r--java/com/android/dialer/app/list/RegularSearchListAdapter.java126
-rw-r--r--java/com/android/dialer/app/list/SearchFragment.java425
-rw-r--r--java/com/android/dialer/app/list/SmartDialNumberListAdapter.java118
-rw-r--r--java/com/android/dialer/app/list/SmartDialSearchFragment.java168
-rw-r--r--java/com/android/dialer/app/res/layout/all_contacts_fragment.xml56
-rw-r--r--java/com/android/dialer/app/res/layout/blocked_number_header.xml40
-rw-r--r--java/com/android/dialer/assisteddialing/AndroidManifest.xml2
-rw-r--r--java/com/android/dialer/assisteddialing/ui/AndroidManifest.xml2
-rw-r--r--java/com/android/dialer/binary/google/AndroidManifest.xml2
-rw-r--r--java/com/android/dialer/blocking/BlockedNumbersMigrator.java2
-rw-r--r--java/com/android/dialer/blocking/FilteredNumberAsyncQueryHandler.java7
-rw-r--r--java/com/android/dialer/blocking/FilteredNumberCompat.java26
-rw-r--r--java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java2
-rw-r--r--java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java2
-rw-r--r--java/com/android/dialer/calllog/AndroidManifest.xml2
-rw-r--r--java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java2
-rw-r--r--java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java6
-rw-r--r--java/com/android/dialer/calllogutils/CallLogDates.java8
-rw-r--r--java/com/android/dialer/compat/CompatUtils.java13
-rw-r--r--java/com/android/dialer/compat/SdkVersionOverride.java43
-rw-r--r--java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java13
-rw-r--r--java/com/android/dialer/database/CallLogQueryHandler.java6
-rw-r--r--java/com/android/dialer/oem/CequintCallerIdManager.java2
-rw-r--r--java/com/android/dialer/p13n/inference/P13nRanking.java90
-rw-r--r--java/com/android/dialer/p13n/inference/protocol/P13nRanker.java81
-rw-r--r--java/com/android/dialer/p13n/inference/protocol/P13nRankerFactory.java26
-rw-r--r--java/com/android/dialer/p13n/logging/P13nLogger.java35
-rw-r--r--java/com/android/dialer/p13n/logging/P13nLoggerFactory.java29
-rw-r--r--java/com/android/dialer/p13n/logging/P13nLogging.java60
-rw-r--r--java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java12
-rw-r--r--java/com/android/dialer/phonenumbercache/ContactInfoHelper.java22
-rw-r--r--java/com/android/dialer/preferredsim/PreferredAccountWorker.java5
-rw-r--r--java/com/android/dialer/shortcuts/AndroidManifest.xml2
-rw-r--r--java/com/android/dialer/smartdial/SmartDialCursorLoader.java60
-rw-r--r--java/com/android/dialer/spannable/AndroidManifest.xml2
-rw-r--r--java/com/android/dialer/voicemail/listui/error/VoicemailStatusWorker.java2
-rw-r--r--java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java20
-rw-r--r--java/com/android/dialer/voicemail/settings/res/values/strings.xml2
-rw-r--r--java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml5
-rw-r--r--java/com/android/incallui/AndroidManifest.xml2
-rw-r--r--java/com/android/incallui/CallerInfoAsyncQuery.java2
-rw-r--r--java/com/android/incallui/answer/impl/hint/PawImageLoaderImpl.java2
-rw-r--r--java/com/android/incallui/autoresizetext/AndroidManifest.xml2
-rw-r--r--java/com/android/incallui/legacyblocking/DeleteBlockedCallTask.java2
-rw-r--r--java/com/android/incallui/rtt/protocol/AndroidManifest.xml2
-rw-r--r--java/com/android/incallui/spam/SpamCallListListener.java2
-rw-r--r--java/com/android/incallui/video/protocol/AndroidManifest.xml2
-rw-r--r--java/com/android/incallui/videotech/ims/ImsVideoTech.java5
-rw-r--r--java/com/android/voicemail/AndroidManifest.xml2
-rw-r--r--java/com/android/voicemail/impl/PackageReplacedReceiver.java2
-rw-r--r--java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java2
-rw-r--r--java/com/android/voicemail/impl/transcribe/TranscriptionUtils.java2
88 files changed, 151 insertions, 9192 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 164dbc907..26fed40c5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,7 +20,7 @@
android:versionName="19.0">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
diff --git a/java/com/android/contacts/common/dialog/CallSubjectDialog.java b/java/com/android/contacts/common/dialog/CallSubjectDialog.java
index 48f292cfa..bbf31e844 100644
--- a/java/com/android/contacts/common/dialog/CallSubjectDialog.java
+++ b/java/com/android/contacts/common/dialog/CallSubjectDialog.java
@@ -23,8 +23,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.telecom.PhoneAccount;
@@ -519,12 +517,6 @@ public class CallSubjectDialog extends Activity {
* current phone account.
*/
private void loadConfiguration() {
- // Only attempt to load configuration from the phone account extras if the SDK is N or
- // later. If we've got a prior SDK the default encoding and message length will suffice.
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- return;
- }
-
if (mPhoneAccountHandle == null) {
return;
}
diff --git a/java/com/android/contacts/common/extensions/PhoneDirectoryExtender.java b/java/com/android/contacts/common/extensions/PhoneDirectoryExtender.java
index 6c932daf5..5e9753f7e 100644
--- a/java/com/android/contacts/common/extensions/PhoneDirectoryExtender.java
+++ b/java/com/android/contacts/common/extensions/PhoneDirectoryExtender.java
@@ -17,18 +17,10 @@ package com.android.contacts.common.extensions;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.Nullable;
-import com.android.contacts.common.list.DirectoryPartition;
-import java.util.List;
/** An interface for adding extended phone directories. */
public interface PhoneDirectoryExtender {
- /**
- * Return a list of extended directories to add. May return null if no directories are to be
- * added.
- */
- List<DirectoryPartition> getExtendedDirectories(Context context);
-
/** returns true if the nearby places directory is enabled. */
boolean isEnabled(Context context);
diff --git a/java/com/android/contacts/common/extensions/PhoneDirectoryExtenderStub.java b/java/com/android/contacts/common/extensions/PhoneDirectoryExtenderStub.java
index 4c3d3d14d..5b3cb9913 100644
--- a/java/com/android/contacts/common/extensions/PhoneDirectoryExtenderStub.java
+++ b/java/com/android/contacts/common/extensions/PhoneDirectoryExtenderStub.java
@@ -17,19 +17,11 @@ package com.android.contacts.common.extensions;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.Nullable;
-import com.android.contacts.common.list.DirectoryPartition;
-import java.util.Collections;
-import java.util.List;
/** No-op implementation for phone directory extender. */
class PhoneDirectoryExtenderStub implements PhoneDirectoryExtender {
@Override
- public List<DirectoryPartition> getExtendedDirectories(Context context) {
- return Collections.emptyList();
- }
-
- @Override
public boolean isEnabled(Context context) {
return false;
}
diff --git a/java/com/android/contacts/common/format/TextHighlighter.java b/java/com/android/contacts/common/format/TextHighlighter.java
deleted file mode 100644
index f397f0429..000000000
--- a/java/com/android/contacts/common/format/TextHighlighter.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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.common.format;
-
-import android.text.SpannableString;
-import android.text.style.CharacterStyle;
-import android.text.style.StyleSpan;
-import android.widget.TextView;
-
-/** Highlights the text in a text field. */
-public class TextHighlighter {
-
- private int mTextStyle;
-
- private CharacterStyle mTextStyleSpan;
-
- public TextHighlighter(int textStyle) {
- mTextStyle = textStyle;
- mTextStyleSpan = getStyleSpan();
- }
-
- /**
- * Sets the text on the given text view, highlighting the word that matches the given prefix.
- *
- * @param view the view on which to set the text
- * @param text the string to use as the text
- * @param prefix the prefix to look for
- */
- public void setPrefixText(TextView view, String text, String prefix) {
- view.setText(applyPrefixHighlight(text, prefix));
- }
-
- private CharacterStyle getStyleSpan() {
- return new StyleSpan(mTextStyle);
- }
-
- /**
- * Applies highlight span to the text.
- *
- * @param text Text sequence to be highlighted.
- * @param start Start position of the highlight sequence.
- * @param end End position of the highlight sequence.
- */
- public void applyMaskingHighlight(SpannableString text, int start, int end) {
- /** Sets text color of the masked locations to be highlighted. */
- text.setSpan(getStyleSpan(), start, end, 0);
- }
-
- /**
- * Returns a CharSequence which highlights the given prefix if found in the given text.
- *
- * @param text the text to which to apply the highlight
- * @param prefix the prefix to look for
- */
- public CharSequence applyPrefixHighlight(CharSequence text, String prefix) {
- if (prefix == null) {
- return text;
- }
-
- // Skip non-word characters at the beginning of prefix.
- int prefixStart = 0;
- while (prefixStart < prefix.length()
- && !Character.isLetterOrDigit(prefix.charAt(prefixStart))) {
- prefixStart++;
- }
- final String trimmedPrefix = prefix.substring(prefixStart);
-
- int index = indexOfWordPrefix(text, trimmedPrefix);
- if (index != -1) {
- final SpannableString result = new SpannableString(text);
- result.setSpan(mTextStyleSpan, index, index + trimmedPrefix.length(), 0 /* flags */);
- return result;
- } else {
- return text;
- }
- }
-
- /**
- * Finds the index of the first word that starts with the given prefix.
- *
- * <p>If not found, returns -1.
- *
- * @param text the text in which to search for the prefix
- * @param prefix the text to find, in upper case letters
- */
- public static int indexOfWordPrefix(CharSequence text, String prefix) {
- if (prefix == null || text == null) {
- return -1;
- }
-
- int textLength = text.length();
- int prefixLength = prefix.length();
-
- if (prefixLength == 0 || textLength < prefixLength) {
- return -1;
- }
-
- int i = 0;
- while (i < textLength) {
- // Skip non-word characters
- while (i < textLength && !Character.isLetterOrDigit(text.charAt(i))) {
- i++;
- }
-
- if (i + prefixLength > textLength) {
- return -1;
- }
-
- // Compare the prefixes
- int j;
- for (j = 0; j < prefixLength; j++) {
- if (Character.toUpperCase(text.charAt(i + j)) != prefix.charAt(j)) {
- break;
- }
- }
- if (j == prefixLength) {
- return i;
- }
-
- // Skip this word
- while (i < textLength && Character.isLetterOrDigit(text.charAt(i))) {
- i++;
- }
- }
-
- return -1;
- }
-}
diff --git a/java/com/android/contacts/common/list/AutoScrollListView.java b/java/com/android/contacts/common/list/AutoScrollListView.java
deleted file mode 100644
index 8d6455f7f..000000000
--- a/java/com/android/contacts/common/list/AutoScrollListView.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.Context;
-import android.os.Build;
-import android.util.AttributeSet;
-import android.widget.ListView;
-
-/**
- * A ListView that can be asked to scroll (smoothly or otherwise) to a specific position. This class
- * takes advantage of similar functionality that exists in {@link ListView} and enhances it.
- */
-public class AutoScrollListView extends ListView {
-
- /** Position the element at about 1/3 of the list height */
- private static final float PREFERRED_SELECTION_OFFSET_FROM_TOP = 0.33f;
-
- private int mRequestedScrollPosition = -1;
- private boolean mSmoothScrollRequested;
-
- public AutoScrollListView(Context context) {
- super(context);
- }
-
- public AutoScrollListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public AutoScrollListView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- /**
- * Brings the specified position to view by optionally performing a jump-scroll maneuver: first it
- * jumps to some position near the one requested and then does a smooth scroll to the requested
- * position. This creates an impression of full smooth scrolling without actually traversing the
- * entire list. If smooth scrolling is not requested, instantly positions the requested item at a
- * preferred offset.
- */
- public void requestPositionToScreen(int position, boolean smoothScroll) {
- mRequestedScrollPosition = position;
- mSmoothScrollRequested = smoothScroll;
- requestLayout();
- }
-
- @Override
- protected void layoutChildren() {
- super.layoutChildren();
- if (mRequestedScrollPosition == -1) {
- return;
- }
-
- final int position = mRequestedScrollPosition;
- mRequestedScrollPosition = -1;
-
- int firstPosition = getFirstVisiblePosition() + 1;
- int lastPosition = getLastVisiblePosition();
- if (position >= firstPosition && position <= lastPosition) {
- return; // Already on screen
- }
-
- final int offset = (int) (getHeight() * PREFERRED_SELECTION_OFFSET_FROM_TOP);
- if (!mSmoothScrollRequested) {
- setSelectionFromTop(position, offset);
-
- // Since we have changed the scrolling position, we need to redo child layout
- // Calling "requestLayout" in the middle of a layout pass has no effect,
- // so we call layoutChildren explicitly
- super.layoutChildren();
-
- } else {
- // We will first position the list a couple of screens before or after
- // the new selection and then scroll smoothly to it.
- int twoScreens = (lastPosition - firstPosition) * 2;
- int preliminaryPosition;
- if (position < firstPosition) {
- preliminaryPosition = position + twoScreens;
- if (preliminaryPosition >= getCount()) {
- preliminaryPosition = getCount() - 1;
- }
- if (preliminaryPosition < firstPosition) {
- setSelection(preliminaryPosition);
- super.layoutChildren();
- }
- } else {
- preliminaryPosition = position - twoScreens;
- if (preliminaryPosition < 0) {
- preliminaryPosition = 0;
- }
- if (preliminaryPosition > lastPosition) {
- setSelection(preliminaryPosition);
- super.layoutChildren();
- }
- }
-
- smoothScrollToPositionFromTop(position, offset);
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
-
- // Workaround for a bug and a bug.
- if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.N
- || android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
- layoutChildren();
- }
- }
-}
diff --git a/java/com/android/contacts/common/list/ContactEntryListAdapter.java b/java/com/android/contacts/common/list/ContactEntryListAdapter.java
deleted file mode 100644
index 413a1deff..000000000
--- a/java/com/android/contacts/common/list/ContactEntryListAdapter.java
+++ /dev/null
@@ -1,772 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.Context;
-import android.content.CursorLoader;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Directory;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.QuickContactBadge;
-import android.widget.SectionIndexer;
-import android.widget.TextView;
-import com.android.contacts.common.ContactsUtils;
-import com.android.contacts.common.R;
-import com.android.contacts.common.util.SearchUtil;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.cp2.DirectoryCompat;
-import com.android.dialer.compat.CompatUtils;
-import com.android.dialer.configprovider.ConfigProviderBindings;
-import com.android.dialer.contactphoto.ContactPhotoManager;
-import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
-import com.android.dialer.logging.InteractionEvent;
-import com.android.dialer.logging.Logger;
-import java.util.HashSet;
-
-/**
- * Common base class for various contact-related lists, e.g. contact list, phone number list etc.
- */
-public abstract class ContactEntryListAdapter extends IndexerListAdapter {
-
- /**
- * Indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should be included in the
- * search.
- */
- public static final boolean LOCAL_INVISIBLE_DIRECTORY_ENABLED = false;
-
- private int mDisplayOrder;
- private int mSortOrder;
-
- private boolean mDisplayPhotos;
- private boolean mCircularPhotos = true;
- private boolean mQuickContactEnabled;
- private boolean mAdjustSelectionBoundsEnabled;
-
- /** The root view of the fragment that this adapter is associated with. */
- private View mFragmentRootView;
-
- private ContactPhotoManager mPhotoLoader;
-
- private String mQueryString;
- private String mUpperCaseQueryString;
- private boolean mSearchMode;
- private int mDirectorySearchMode;
- private int mDirectoryResultLimit = Integer.MAX_VALUE;
-
- private boolean mEmptyListEnabled = true;
-
- private boolean mSelectionVisible;
-
- private ContactListFilter mFilter;
- private boolean mDarkTheme = false;
-
- public static final int SUGGESTIONS_LOADER_ID = 0;
-
- /** Resource used to provide header-text for default filter. */
- private CharSequence mDefaultFilterHeaderText;
-
- public ContactEntryListAdapter(Context context) {
- super(context);
- setDefaultFilterHeaderText(R.string.local_search_label);
- addPartitions();
- }
-
- /**
- * @param fragmentRootView Root view of the fragment. This is used to restrict the scope of image
- * loading requests that get cancelled on cursor changes.
- */
- protected void setFragmentRootView(View fragmentRootView) {
- mFragmentRootView = fragmentRootView;
- }
-
- protected void setDefaultFilterHeaderText(int resourceId) {
- mDefaultFilterHeaderText = getContext().getResources().getText(resourceId);
- }
-
- @Override
- protected ContactListItemView newView(
- Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
- final ContactListItemView view = new ContactListItemView(context, null);
- view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
- view.setAdjustSelectionBoundsEnabled(isAdjustSelectionBoundsEnabled());
- return view;
- }
-
- @Override
- protected void bindView(View itemView, int partition, Cursor cursor, int position) {
- final ContactListItemView view = (ContactListItemView) itemView;
- view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
- bindWorkProfileIcon(view, partition);
- }
-
- @Override
- protected View createPinnedSectionHeaderView(Context context, ViewGroup parent) {
- return new ContactListPinnedHeaderView(context, null, parent);
- }
-
- @Override
- protected void setPinnedSectionTitle(View pinnedHeaderView, String title) {
- ((ContactListPinnedHeaderView) pinnedHeaderView).setSectionHeaderTitle(title);
- }
-
- protected void addPartitions() {
- if (ConfigProviderBindings.get(getContext()).getBoolean("p13n_ranker_should_enable", false)) {
- addPartition(createSuggestionsDirectoryPartition());
- }
- addPartition(createDefaultDirectoryPartition());
- }
-
- protected DirectoryPartition createSuggestionsDirectoryPartition() {
- DirectoryPartition partition = new DirectoryPartition(true, true);
- partition.setDirectoryId(SUGGESTIONS_LOADER_ID);
- partition.setDirectoryType(getContext().getString(R.string.contact_suggestions));
- partition.setPriorityDirectory(true);
- partition.setPhotoSupported(true);
- partition.setLabel(getContext().getString(R.string.local_suggestions_search_label));
- return partition;
- }
-
- protected DirectoryPartition createDefaultDirectoryPartition() {
- DirectoryPartition partition = new DirectoryPartition(true, true);
- partition.setDirectoryId(Directory.DEFAULT);
- partition.setDirectoryType(getContext().getString(R.string.contactsList));
- partition.setPriorityDirectory(true);
- partition.setPhotoSupported(true);
- partition.setLabel(mDefaultFilterHeaderText.toString());
- return partition;
- }
-
- /**
- * Remove all directories after the default directory. This is typically used when contacts list
- * screens are asked to exit the search mode and thus need to remove all remote directory results
- * for the search.
- *
- * <p>This code assumes that the default directory and directories before that should not be
- * deleted (e.g. Join screen has "suggested contacts" directory before the default director, and
- * we should not remove the directory).
- */
- public void removeDirectoriesAfterDefault() {
- final int partitionCount = getPartitionCount();
- for (int i = partitionCount - 1; i >= 0; i--) {
- final Partition partition = getPartition(i);
- if ((partition instanceof DirectoryPartition)
- && ((DirectoryPartition) partition).getDirectoryId() == Directory.DEFAULT) {
- break;
- } else {
- removePartition(i);
- }
- }
- }
-
- protected int getPartitionByDirectoryId(long id) {
- int count = getPartitionCount();
- for (int i = 0; i < count; i++) {
- Partition partition = getPartition(i);
- if (partition instanceof DirectoryPartition) {
- if (((DirectoryPartition) partition).getDirectoryId() == id) {
- return i;
- }
- }
- }
- return -1;
- }
-
- protected DirectoryPartition getDirectoryById(long id) {
- int count = getPartitionCount();
- for (int i = 0; i < count; i++) {
- Partition partition = getPartition(i);
- if (partition instanceof DirectoryPartition) {
- final DirectoryPartition directoryPartition = (DirectoryPartition) partition;
- if (directoryPartition.getDirectoryId() == id) {
- return directoryPartition;
- }
- }
- }
- return null;
- }
-
- public abstract void configureLoader(CursorLoader loader, long directoryId);
-
- /** Marks all partitions as "loading" */
- public void onDataReload() {
- boolean notify = false;
- int count = getPartitionCount();
- for (int i = 0; i < count; i++) {
- Partition partition = getPartition(i);
- if (partition instanceof DirectoryPartition) {
- DirectoryPartition directoryPartition = (DirectoryPartition) partition;
- if (!directoryPartition.isLoading()) {
- notify = true;
- }
- directoryPartition.setStatus(DirectoryPartition.STATUS_NOT_LOADED);
- }
- }
- if (notify) {
- notifyDataSetChanged();
- }
- }
-
- @Override
- public void clearPartitions() {
- int count = getPartitionCount();
- for (int i = 0; i < count; i++) {
- Partition partition = getPartition(i);
- if (partition instanceof DirectoryPartition) {
- DirectoryPartition directoryPartition = (DirectoryPartition) partition;
- directoryPartition.setStatus(DirectoryPartition.STATUS_NOT_LOADED);
- }
- }
- super.clearPartitions();
- }
-
- public boolean isSearchMode() {
- return mSearchMode;
- }
-
- public void setSearchMode(boolean flag) {
- mSearchMode = flag;
- }
-
- public String getQueryString() {
- return mQueryString;
- }
-
- public void setQueryString(String queryString) {
- mQueryString = queryString;
- if (TextUtils.isEmpty(queryString)) {
- mUpperCaseQueryString = null;
- } else {
- mUpperCaseQueryString = SearchUtil.cleanStartAndEndOfSearchQuery(queryString.toUpperCase());
- }
-
- // Enable default partition header if in search mode (including zero-suggest).
- if (mQueryString != null) {
- setDefaultPartitionHeader(true);
- }
- }
-
- public String getUpperCaseQueryString() {
- return mUpperCaseQueryString;
- }
-
- public int getDirectorySearchMode() {
- return mDirectorySearchMode;
- }
-
- public void setDirectorySearchMode(int mode) {
- mDirectorySearchMode = mode;
- }
-
- public int getDirectoryResultLimit() {
- return mDirectoryResultLimit;
- }
-
- public void setDirectoryResultLimit(int limit) {
- this.mDirectoryResultLimit = limit;
- }
-
- public int getDirectoryResultLimit(DirectoryPartition directoryPartition) {
- final int limit = directoryPartition.getResultLimit();
- return limit == DirectoryPartition.RESULT_LIMIT_DEFAULT ? mDirectoryResultLimit : limit;
- }
-
- public int getContactNameDisplayOrder() {
- return mDisplayOrder;
- }
-
- public void setContactNameDisplayOrder(int displayOrder) {
- mDisplayOrder = displayOrder;
- }
-
- public int getSortOrder() {
- return mSortOrder;
- }
-
- public void setSortOrder(int sortOrder) {
- mSortOrder = sortOrder;
- }
-
- protected ContactPhotoManager getPhotoLoader() {
- return mPhotoLoader;
- }
-
- public void setPhotoLoader(ContactPhotoManager photoLoader) {
- mPhotoLoader = photoLoader;
- }
-
- public boolean getDisplayPhotos() {
- return mDisplayPhotos;
- }
-
- public void setDisplayPhotos(boolean displayPhotos) {
- mDisplayPhotos = displayPhotos;
- }
-
- public boolean getCircularPhotos() {
- return mCircularPhotos;
- }
-
- public boolean isSelectionVisible() {
- return mSelectionVisible;
- }
-
- public void setSelectionVisible(boolean flag) {
- this.mSelectionVisible = flag;
- }
-
- public boolean isQuickContactEnabled() {
- return mQuickContactEnabled;
- }
-
- public void setQuickContactEnabled(boolean quickContactEnabled) {
- mQuickContactEnabled = quickContactEnabled;
- }
-
- public boolean isAdjustSelectionBoundsEnabled() {
- return mAdjustSelectionBoundsEnabled;
- }
-
- public void setAdjustSelectionBoundsEnabled(boolean enabled) {
- mAdjustSelectionBoundsEnabled = enabled;
- }
-
- public void setProfileExists(boolean exists) {
- // Stick the "ME" header for the profile
- if (exists) {
- setSectionHeader(R.string.user_profile_contacts_list_header, /* # of ME */ 1);
- }
- }
-
- private void setSectionHeader(int resId, int numberOfItems) {
- SectionIndexer indexer = getIndexer();
- if (indexer != null) {
- ((ContactsSectionIndexer) indexer)
- .setProfileAndFavoritesHeader(getContext().getString(resId), numberOfItems);
- }
- }
-
- public void setDarkTheme(boolean value) {
- mDarkTheme = value;
- }
-
- /** Updates partitions according to the directory meta-data contained in the supplied cursor. */
- public void changeDirectories(Cursor cursor) {
- if (cursor.getCount() == 0) {
- // Directory table must have at least local directory, without which this adapter will
- // enter very weird state.
- LogUtil.i(
- "ContactEntryListAdapter.changeDirectories",
- "directory search loader returned an empty cursor, which implies we have "
- + "no directory entries.",
- new RuntimeException());
- return;
- }
- HashSet<Long> directoryIds = new HashSet<Long>();
-
- int idColumnIndex = cursor.getColumnIndex(Directory._ID);
- int directoryTypeColumnIndex = cursor.getColumnIndex(DirectoryListLoader.DIRECTORY_TYPE);
- int displayNameColumnIndex = cursor.getColumnIndex(Directory.DISPLAY_NAME);
- int photoSupportColumnIndex = cursor.getColumnIndex(Directory.PHOTO_SUPPORT);
-
- // TODO preserve the order of partition to match those of the cursor
- // Phase I: add new directories
- cursor.moveToPosition(-1);
- while (cursor.moveToNext()) {
- long id = cursor.getLong(idColumnIndex);
- directoryIds.add(id);
- if (getPartitionByDirectoryId(id) == -1) {
- DirectoryPartition partition = new DirectoryPartition(false, true);
- partition.setDirectoryId(id);
- if (DirectoryCompat.isRemoteDirectoryId(id)) {
- if (DirectoryCompat.isEnterpriseDirectoryId(id)) {
- partition.setLabel(mContext.getString(R.string.directory_search_label_work));
- } else {
- partition.setLabel(mContext.getString(R.string.directory_search_label));
- }
- } else {
- if (DirectoryCompat.isEnterpriseDirectoryId(id)) {
- partition.setLabel(mContext.getString(R.string.list_filter_phones_work));
- } else {
- partition.setLabel(mDefaultFilterHeaderText.toString());
- }
- }
- partition.setDirectoryType(cursor.getString(directoryTypeColumnIndex));
- partition.setDisplayName(cursor.getString(displayNameColumnIndex));
- int photoSupport = cursor.getInt(photoSupportColumnIndex);
- partition.setPhotoSupported(
- photoSupport == Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY
- || photoSupport == Directory.PHOTO_SUPPORT_FULL);
- addPartition(partition);
- }
- }
-
- // Phase II: remove deleted directories
- int count = getPartitionCount();
- for (int i = count; --i >= 0; ) {
- Partition partition = getPartition(i);
- if (partition instanceof DirectoryPartition) {
- long id = ((DirectoryPartition) partition).getDirectoryId();
- if (!directoryIds.contains(id)) {
- removePartition(i);
- }
- }
- }
-
- invalidate();
- notifyDataSetChanged();
- }
-
- @Override
- public void changeCursor(int partitionIndex, Cursor cursor) {
- if (partitionIndex >= getPartitionCount()) {
- // There is no partition for this data
- return;
- }
-
- Partition partition = getPartition(partitionIndex);
- if (partition instanceof DirectoryPartition) {
- ((DirectoryPartition) partition).setStatus(DirectoryPartition.STATUS_LOADED);
- }
-
- if (mDisplayPhotos && mPhotoLoader != null && isPhotoSupported(partitionIndex)) {
- mPhotoLoader.refreshCache();
- }
-
- super.changeCursor(partitionIndex, cursor);
-
- if (isSectionHeaderDisplayEnabled() && partitionIndex == getIndexedPartition()) {
- updateIndexer(cursor);
- }
-
- // When the cursor changes, cancel any pending asynchronous photo loads.
- mPhotoLoader.cancelPendingRequests(mFragmentRootView);
- }
-
- public void changeCursor(Cursor cursor) {
- changeCursor(0, cursor);
- }
-
- /** Updates the indexer, which is used to produce section headers. */
- private void updateIndexer(Cursor cursor) {
- if (cursor == null || cursor.isClosed()) {
- setIndexer(null);
- return;
- }
-
- Bundle bundle = cursor.getExtras();
- if (bundle.containsKey(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES)
- && bundle.containsKey(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS)) {
- String[] sections = bundle.getStringArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
- int[] counts = bundle.getIntArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
-
- if (getExtraStartingSection()) {
- // Insert an additional unnamed section at the top of the list.
- String[] allSections = new String[sections.length + 1];
- int[] allCounts = new int[counts.length + 1];
- for (int i = 0; i < sections.length; i++) {
- allSections[i + 1] = sections[i];
- allCounts[i + 1] = counts[i];
- }
- allCounts[0] = 1;
- allSections[0] = "";
- setIndexer(new ContactsSectionIndexer(allSections, allCounts));
- } else {
- setIndexer(new ContactsSectionIndexer(sections, counts));
- }
- } else {
- setIndexer(null);
- }
- }
-
- protected boolean getExtraStartingSection() {
- return false;
- }
-
- @Override
- public int getViewTypeCount() {
- // We need a separate view type for each item type, plus another one for
- // each type with header, plus one for "other".
- return getItemViewTypeCount() * 2 + 1;
- }
-
- @Override
- public int getItemViewType(int partitionIndex, int position) {
- int type = super.getItemViewType(partitionIndex, position);
- if (!isUserProfile(position)
- && isSectionHeaderDisplayEnabled()
- && partitionIndex == getIndexedPartition()) {
- Placement placement = getItemPlacementInSection(position);
- return placement.firstInSection ? type : getItemViewTypeCount() + type;
- } else {
- return type;
- }
- }
-
- @Override
- public boolean isEmpty() {
- // TODO
- // if (contactsListActivity.mProviderStatus != ProviderStatus.STATUS_NORMAL) {
- // return true;
- // }
-
- if (!mEmptyListEnabled) {
- return false;
- } else if (isSearchMode()) {
- return TextUtils.isEmpty(getQueryString());
- } else {
- return super.isEmpty();
- }
- }
-
- public boolean isLoading() {
- int count = getPartitionCount();
- for (int i = 0; i < count; i++) {
- Partition partition = getPartition(i);
- if (partition instanceof DirectoryPartition && ((DirectoryPartition) partition).isLoading()) {
- return true;
- }
- }
- return false;
- }
-
- /** Configures visibility parameters for the directory partitions. */
- public void configurePartitionsVisibility(boolean isInSearchMode) {
- for (int i = 0; i < getPartitionCount(); i++) {
- setShowIfEmpty(i, false);
- setHasHeader(i, isInSearchMode);
- }
- }
-
- // Sets header for the default partition.
- private void setDefaultPartitionHeader(boolean setHeader) {
- // Iterate in reverse here to ensure the first DEFAULT directory has header.
- // Both "Suggestions" and "All Contacts" directories have DEFAULT id.
- int defaultPartitionIndex = -1;
- for (int i = getPartitionCount() - 1; i >= 0; i--) {
- Partition partition = getPartition(i);
- if (partition instanceof DirectoryPartition
- && ((DirectoryPartition) partition).getDirectoryId() == Directory.DEFAULT) {
- defaultPartitionIndex = i;
- }
- }
- setHasHeader(defaultPartitionIndex, setHeader);
- }
-
- @Override
- protected View newHeaderView(Context context, int partition, Cursor cursor, ViewGroup parent) {
- LayoutInflater inflater = LayoutInflater.from(context);
- View view = inflater.inflate(R.layout.directory_header, parent, false);
- if (!getPinnedPartitionHeadersEnabled()) {
- // If the headers are unpinned, there is no need for their background
- // color to be non-transparent. Setting this transparent reduces maintenance for
- // non-pinned headers. We don't need to bother synchronizing the activity's
- // background color with the header background color.
- view.setBackground(null);
- }
- return view;
- }
-
- protected void bindWorkProfileIcon(final ContactListItemView view, int partitionId) {
- final Partition partition = getPartition(partitionId);
- if (partition instanceof DirectoryPartition) {
- final DirectoryPartition directoryPartition = (DirectoryPartition) partition;
- final long directoryId = directoryPartition.getDirectoryId();
- final long userType = ContactsUtils.determineUserType(directoryId, null);
- view.setWorkProfileIconEnabled(userType == ContactsUtils.USER_TYPE_WORK);
- }
- }
-
- @Override
- protected void bindHeaderView(View view, int partitionIndex, Cursor cursor) {
- Partition partition = getPartition(partitionIndex);
- if (!(partition instanceof DirectoryPartition)) {
- return;
- }
-
- DirectoryPartition directoryPartition = (DirectoryPartition) partition;
- long directoryId = directoryPartition.getDirectoryId();
- TextView labelTextView = (TextView) view.findViewById(R.id.label);
- TextView displayNameTextView = (TextView) view.findViewById(R.id.display_name);
- labelTextView.setText(directoryPartition.getLabel());
- if (!DirectoryCompat.isRemoteDirectoryId(directoryId)) {
- displayNameTextView.setText(null);
- } else {
- String directoryName = directoryPartition.getDisplayName();
- String displayName =
- !TextUtils.isEmpty(directoryName) ? directoryName : directoryPartition.getDirectoryType();
- displayNameTextView.setText(displayName);
- }
-
- final Resources res = getContext().getResources();
- final int headerPaddingTop =
- partitionIndex == 1 && getPartition(0).isEmpty()
- ? 0
- : res.getDimensionPixelOffset(R.dimen.directory_header_extra_top_padding);
- // There should be no extra padding at the top of the first directory header
- view.setPaddingRelative(
- view.getPaddingStart(), headerPaddingTop, view.getPaddingEnd(), view.getPaddingBottom());
- }
-
- /** Checks whether the contact entry at the given position represents the user's profile. */
- protected boolean isUserProfile(int position) {
- // The profile only ever appears in the first position if it is present. So if the position
- // is anything beyond 0, it can't be the profile.
- boolean isUserProfile = false;
- if (position == 0) {
- int partition = getPartitionForPosition(position);
- if (partition >= 0) {
- // Save the old cursor position - the call to getItem() may modify the cursor
- // position.
- int offset = getCursor(partition).getPosition();
- Cursor cursor = (Cursor) getItem(position);
- if (cursor != null) {
- int profileColumnIndex = cursor.getColumnIndex(Contacts.IS_USER_PROFILE);
- if (profileColumnIndex != -1) {
- isUserProfile = cursor.getInt(profileColumnIndex) == 1;
- }
- // Restore the old cursor position.
- cursor.moveToPosition(offset);
- }
- }
- }
- return isUserProfile;
- }
-
- public boolean isPhotoSupported(int partitionIndex) {
- Partition partition = getPartition(partitionIndex);
- if (partition instanceof DirectoryPartition) {
- return ((DirectoryPartition) partition).isPhotoSupported();
- }
- return true;
- }
-
- /** Returns the currently selected filter. */
- public ContactListFilter getFilter() {
- return mFilter;
- }
-
- public void setFilter(ContactListFilter filter) {
- mFilter = filter;
- }
-
- // TODO: move sharable logic (bindXX() methods) to here with extra arguments
-
- /**
- * Loads the photo for the quick contact view and assigns the contact uri.
- *
- * @param photoIdColumn Index of the photo id column
- * @param photoUriColumn Index of the photo uri column. Optional: Can be -1
- * @param contactIdColumn Index of the contact id column
- * @param lookUpKeyColumn Index of the lookup key column
- * @param displayNameColumn Index of the display name column
- */
- protected void bindQuickContact(
- final ContactListItemView view,
- int partitionIndex,
- Cursor cursor,
- int photoIdColumn,
- int photoUriColumn,
- int contactIdColumn,
- int lookUpKeyColumn,
- int displayNameColumn) {
- long photoId = 0;
- if (!cursor.isNull(photoIdColumn)) {
- photoId = cursor.getLong(photoIdColumn);
- }
-
- QuickContactBadge quickContact = view.getQuickContact();
- quickContact.assignContactUri(
- getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn));
- if (CompatUtils.hasPrioritizedMimeType()) {
- // The Contacts app never uses the QuickContactBadge. Therefore, it is safe to assume
- // that only Dialer will use this QuickContact badge. This means prioritizing the phone
- // mimetype here is reasonable.
- quickContact.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
- }
- Logger.get(mContext)
- .logQuickContactOnTouch(
- quickContact, InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_SEARCH, true);
-
- if (photoId != 0 || photoUriColumn == -1) {
- getPhotoLoader().loadThumbnail(quickContact, photoId, mDarkTheme, mCircularPhotos, null);
- } else {
- final String photoUriString = cursor.getString(photoUriColumn);
- final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
- DefaultImageRequest request = null;
- if (photoUri == null) {
- request = getDefaultImageRequestFromCursor(cursor, displayNameColumn, lookUpKeyColumn);
- }
- getPhotoLoader().loadPhoto(quickContact, photoUri, -1, mDarkTheme, mCircularPhotos, request);
- }
- }
-
- @Override
- public boolean hasStableIds() {
- // Whenever bindViewId() is called, the values passed into setId() are stable or
- // stable-ish. For example, when one contact is modified we don't expect a second
- // contact's Contact._ID values to change.
- return true;
- }
-
- protected void bindViewId(final ContactListItemView view, Cursor cursor, int idColumn) {
- // Set a semi-stable id, so that talkback won't get confused when the list gets
- // refreshed. There is little harm in inserting the same ID twice.
- long contactId = cursor.getLong(idColumn);
- view.setId((int) (contactId % Integer.MAX_VALUE));
- }
-
- protected Uri getContactUri(
- int partitionIndex, Cursor cursor, int contactIdColumn, int lookUpKeyColumn) {
- long contactId = cursor.getLong(contactIdColumn);
- String lookupKey = cursor.getString(lookUpKeyColumn);
- long directoryId = ((DirectoryPartition) getPartition(partitionIndex)).getDirectoryId();
- Uri uri = Contacts.getLookupUri(contactId, lookupKey);
- if (uri != null && directoryId != Directory.DEFAULT) {
- uri =
- uri.buildUpon()
- .appendQueryParameter(
- ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId))
- .build();
- }
- return uri;
- }
-
- /**
- * Retrieves the lookup key and display name from a cursor, and returns a {@link
- * DefaultImageRequest} containing these contact details
- *
- * @param cursor Contacts cursor positioned at the current row to retrieve contact details for
- * @param displayNameColumn Column index of the display name
- * @param lookupKeyColumn Column index of the lookup key
- * @return {@link DefaultImageRequest} with the displayName and identifier fields set to the
- * display name and lookup key of the contact.
- */
- public DefaultImageRequest getDefaultImageRequestFromCursor(
- Cursor cursor, int displayNameColumn, int lookupKeyColumn) {
- final String displayName = cursor.getString(displayNameColumn);
- final String lookupKey = cursor.getString(lookupKeyColumn);
- return new DefaultImageRequest(displayName, lookupKey, mCircularPhotos);
- }
-}
diff --git a/java/com/android/contacts/common/list/ContactEntryListFragment.java b/java/com/android/contacts/common/list/ContactEntryListFragment.java
deleted file mode 100644
index c807ea815..000000000
--- a/java/com/android/contacts/common/list/ContactEntryListFragment.java
+++ /dev/null
@@ -1,860 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.app.Fragment;
-import android.app.LoaderManager;
-import android.app.LoaderManager.LoaderCallbacks;
-import android.content.Context;
-import android.content.CursorLoader;
-import android.content.Loader;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Parcelable;
-import android.provider.ContactsContract.Directory;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnTouchListener;
-import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ListView;
-import com.android.common.widget.CompositeCursorAdapter.Partition;
-import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.common.util.ContactListViewUtils;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.contactphoto.ContactPhotoManager;
-import com.android.dialer.performancereport.PerformanceReport;
-import java.lang.ref.WeakReference;
-import java.util.Locale;
-
-/** Common base class for various contact-related list fragments. */
-public abstract class ContactEntryListFragment<T extends ContactEntryListAdapter> extends Fragment
- implements OnItemClickListener,
- OnScrollListener,
- OnFocusChangeListener,
- OnTouchListener,
- LoaderCallbacks<Cursor> {
- private static final String KEY_LIST_STATE = "liststate";
- private static final String KEY_SECTION_HEADER_DISPLAY_ENABLED = "sectionHeaderDisplayEnabled";
- private static final String KEY_PHOTO_LOADER_ENABLED = "photoLoaderEnabled";
- private static final String KEY_QUICK_CONTACT_ENABLED = "quickContactEnabled";
- private static final String KEY_ADJUST_SELECTION_BOUNDS_ENABLED = "adjustSelectionBoundsEnabled";
- private static final String KEY_INCLUDE_PROFILE = "includeProfile";
- private static final String KEY_SEARCH_MODE = "searchMode";
- private static final String KEY_VISIBLE_SCROLLBAR_ENABLED = "visibleScrollbarEnabled";
- private static final String KEY_SCROLLBAR_POSITION = "scrollbarPosition";
- private static final String KEY_QUERY_STRING = "queryString";
- private static final String KEY_DIRECTORY_SEARCH_MODE = "directorySearchMode";
- private static final String KEY_SELECTION_VISIBLE = "selectionVisible";
- private static final String KEY_DARK_THEME = "darkTheme";
- private static final String KEY_LEGACY_COMPATIBILITY = "legacyCompatibility";
- private static final String KEY_DIRECTORY_RESULT_LIMIT = "directoryResultLimit";
-
- private static final String DIRECTORY_ID_ARG_KEY = "directoryId";
-
- private static final int DIRECTORY_LOADER_ID = -1;
-
- private static final int DIRECTORY_SEARCH_DELAY_MILLIS = 300;
- private static final int DIRECTORY_SEARCH_MESSAGE = 1;
-
- private static final int DEFAULT_DIRECTORY_RESULT_LIMIT = 20;
- private static final int STATUS_NOT_LOADED = 0;
- private static final int STATUS_LOADING = 1;
- private static final int STATUS_LOADED = 2;
- protected boolean mUserProfileExists;
- private boolean mSectionHeaderDisplayEnabled;
- private boolean mPhotoLoaderEnabled;
- private boolean mQuickContactEnabled = true;
- private boolean mAdjustSelectionBoundsEnabled = true;
- private boolean mIncludeProfile;
- private boolean mSearchMode;
- private boolean mVisibleScrollbarEnabled;
- private boolean mShowEmptyListForEmptyQuery;
- private int mVerticalScrollbarPosition = getDefaultVerticalScrollbarPosition();
- private String mQueryString;
- private int mDirectorySearchMode = DirectoryListLoader.SEARCH_MODE_NONE;
- private boolean mSelectionVisible;
- private boolean mLegacyCompatibility;
- private boolean mEnabled = true;
- private T mAdapter;
- private View mView;
- private ListView mListView;
- /** Used to save the scrolling state of the list when the fragment is not recreated. */
- private int mListViewTopIndex;
-
- private int mListViewTopOffset;
- /** Used for keeping track of the scroll state of the list. */
- private Parcelable mListState;
-
- private int mDisplayOrder;
- private int mSortOrder;
- private int mDirectoryResultLimit = DEFAULT_DIRECTORY_RESULT_LIMIT;
- private ContactPhotoManager mPhotoManager;
- private ContactsPreferences mContactsPrefs;
- private boolean mForceLoad;
- private boolean mDarkTheme;
- private int mDirectoryListStatus = STATUS_NOT_LOADED;
-
- /**
- * Indicates whether we are doing the initial complete load of data (false) or a refresh caused by
- * a change notification (true)
- */
- private boolean mLoadPriorityDirectoriesOnly;
-
- private Context mContext;
-
- private LoaderManager mLoaderManager;
-
- private Handler mDelayedDirectorySearchHandler;
-
- private static class DelayedDirectorySearchHandler extends Handler {
- private final WeakReference<ContactEntryListFragment<?>> contactEntryListFragmentRef;
-
- private DelayedDirectorySearchHandler(ContactEntryListFragment<?> contactEntryListFragment) {
- this.contactEntryListFragmentRef = new WeakReference<>(contactEntryListFragment);
- }
-
- @Override
- public void handleMessage(Message msg) {
- ContactEntryListFragment<?> contactEntryListFragment = contactEntryListFragmentRef.get();
- if (contactEntryListFragment == null) {
- return;
- }
- if (msg.what == DIRECTORY_SEARCH_MESSAGE) {
- contactEntryListFragment.loadDirectoryPartition(msg.arg1, (DirectoryPartition) msg.obj);
- }
- }
- }
-
- private ContactsPreferences.ChangeListener mPreferencesChangeListener =
- new ContactsPreferences.ChangeListener() {
- @Override
- public void onChange() {
- loadPreferences();
- reloadData();
- }
- };
-
- protected ContactEntryListFragment() {
- mDelayedDirectorySearchHandler = new DelayedDirectorySearchHandler(this);
- }
-
- protected abstract View inflateView(LayoutInflater inflater, ViewGroup container);
-
- protected abstract T createListAdapter();
-
- /**
- * @param position Please note that the position is already adjusted for header views, so "0"
- * means the first list item below header views.
- */
- protected abstract void onItemClick(int position, long id);
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- setContext(context);
- setLoaderManager(super.getLoaderManager());
- }
-
- @Override
- public Context getContext() {
- return mContext;
- }
-
- /** Sets a context for the fragment in the unit test environment. */
- public void setContext(Context context) {
- mContext = context;
- configurePhotoLoader();
- }
-
- public void setEnabled(boolean enabled) {
- if (mEnabled != enabled) {
- mEnabled = enabled;
- if (mAdapter != null) {
- if (mEnabled) {
- reloadData();
- } else {
- mAdapter.clearPartitions();
- }
- }
- }
- }
-
- @Override
- public LoaderManager getLoaderManager() {
- return mLoaderManager;
- }
-
- /** Overrides a loader manager for use in unit tests. */
- public void setLoaderManager(LoaderManager loaderManager) {
- mLoaderManager = loaderManager;
- }
-
- public T getAdapter() {
- return mAdapter;
- }
-
- @Override
- public View getView() {
- return mView;
- }
-
- public ListView getListView() {
- return mListView;
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putBoolean(KEY_SECTION_HEADER_DISPLAY_ENABLED, mSectionHeaderDisplayEnabled);
- outState.putBoolean(KEY_PHOTO_LOADER_ENABLED, mPhotoLoaderEnabled);
- outState.putBoolean(KEY_QUICK_CONTACT_ENABLED, mQuickContactEnabled);
- outState.putBoolean(KEY_ADJUST_SELECTION_BOUNDS_ENABLED, mAdjustSelectionBoundsEnabled);
- outState.putBoolean(KEY_INCLUDE_PROFILE, mIncludeProfile);
- outState.putBoolean(KEY_SEARCH_MODE, mSearchMode);
- outState.putBoolean(KEY_VISIBLE_SCROLLBAR_ENABLED, mVisibleScrollbarEnabled);
- outState.putInt(KEY_SCROLLBAR_POSITION, mVerticalScrollbarPosition);
- outState.putInt(KEY_DIRECTORY_SEARCH_MODE, mDirectorySearchMode);
- outState.putBoolean(KEY_SELECTION_VISIBLE, mSelectionVisible);
- outState.putBoolean(KEY_LEGACY_COMPATIBILITY, mLegacyCompatibility);
- outState.putString(KEY_QUERY_STRING, mQueryString);
- outState.putInt(KEY_DIRECTORY_RESULT_LIMIT, mDirectoryResultLimit);
- outState.putBoolean(KEY_DARK_THEME, mDarkTheme);
-
- if (mListView != null) {
- outState.putParcelable(KEY_LIST_STATE, mListView.onSaveInstanceState());
- }
- }
-
- @Override
- public void onCreate(Bundle savedState) {
- super.onCreate(savedState);
- restoreSavedState(savedState);
- mAdapter = createListAdapter();
- mContactsPrefs = new ContactsPreferences(mContext);
- }
-
- public void restoreSavedState(Bundle savedState) {
- if (savedState == null) {
- return;
- }
-
- mSectionHeaderDisplayEnabled = savedState.getBoolean(KEY_SECTION_HEADER_DISPLAY_ENABLED);
- mPhotoLoaderEnabled = savedState.getBoolean(KEY_PHOTO_LOADER_ENABLED);
- mQuickContactEnabled = savedState.getBoolean(KEY_QUICK_CONTACT_ENABLED);
- mAdjustSelectionBoundsEnabled = savedState.getBoolean(KEY_ADJUST_SELECTION_BOUNDS_ENABLED);
- mIncludeProfile = savedState.getBoolean(KEY_INCLUDE_PROFILE);
- mSearchMode = savedState.getBoolean(KEY_SEARCH_MODE);
- mVisibleScrollbarEnabled = savedState.getBoolean(KEY_VISIBLE_SCROLLBAR_ENABLED);
- mVerticalScrollbarPosition = savedState.getInt(KEY_SCROLLBAR_POSITION);
- mDirectorySearchMode = savedState.getInt(KEY_DIRECTORY_SEARCH_MODE);
- mSelectionVisible = savedState.getBoolean(KEY_SELECTION_VISIBLE);
- mLegacyCompatibility = savedState.getBoolean(KEY_LEGACY_COMPATIBILITY);
- mQueryString = savedState.getString(KEY_QUERY_STRING);
- mDirectoryResultLimit = savedState.getInt(KEY_DIRECTORY_RESULT_LIMIT);
- mDarkTheme = savedState.getBoolean(KEY_DARK_THEME);
-
- // Retrieve list state. This will be applied in onLoadFinished
- mListState = savedState.getParcelable(KEY_LIST_STATE);
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- mContactsPrefs.registerChangeListener(mPreferencesChangeListener);
-
- mForceLoad = loadPreferences();
-
- mDirectoryListStatus = STATUS_NOT_LOADED;
- mLoadPriorityDirectoriesOnly = true;
-
- startLoading();
- }
-
- protected void startLoading() {
- if (mAdapter == null) {
- // The method was called before the fragment was started
- return;
- }
-
- configureAdapter();
- int partitionCount = mAdapter.getPartitionCount();
- for (int i = 0; i < partitionCount; i++) {
- Partition partition = mAdapter.getPartition(i);
- if (partition instanceof DirectoryPartition) {
- DirectoryPartition directoryPartition = (DirectoryPartition) partition;
- if (directoryPartition.getStatus() == DirectoryPartition.STATUS_NOT_LOADED) {
- if (directoryPartition.isPriorityDirectory() || !mLoadPriorityDirectoriesOnly) {
- startLoadingDirectoryPartition(i);
- }
- }
- } else {
- getLoaderManager().initLoader(i, null, this);
- }
- }
-
- // Next time this method is called, we should start loading non-priority directories
- mLoadPriorityDirectoriesOnly = false;
- }
-
- @Override
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- if (id == DIRECTORY_LOADER_ID) {
- DirectoryListLoader loader = new DirectoryListLoader(mContext);
- loader.setDirectorySearchMode(mAdapter.getDirectorySearchMode());
- loader.setLocalInvisibleDirectoryEnabled(
- ContactEntryListAdapter.LOCAL_INVISIBLE_DIRECTORY_ENABLED);
- return loader;
- } else {
- CursorLoader loader = createCursorLoader(mContext);
- long directoryId =
- args != null && args.containsKey(DIRECTORY_ID_ARG_KEY)
- ? args.getLong(DIRECTORY_ID_ARG_KEY)
- : Directory.DEFAULT;
- mAdapter.configureLoader(loader, directoryId);
- return loader;
- }
- }
-
- public CursorLoader createCursorLoader(Context context) {
- return new CursorLoader(context, null, null, null, null, null) {
- @Override
- protected Cursor onLoadInBackground() {
- try {
- return super.onLoadInBackground();
- } catch (RuntimeException e) {
- // We don't even know what the projection should be, so no point trying to
- // return an empty MatrixCursor with the correct projection here.
- LogUtil.w(
- "ContactEntryListFragment.onLoadInBackground",
- "RuntimeException while trying to query ContactsProvider.");
- return null;
- }
- }
- };
- }
-
- private void startLoadingDirectoryPartition(int partitionIndex) {
- DirectoryPartition partition = (DirectoryPartition) mAdapter.getPartition(partitionIndex);
- partition.setStatus(DirectoryPartition.STATUS_LOADING);
- long directoryId = partition.getDirectoryId();
- if (mForceLoad) {
- if (directoryId == Directory.DEFAULT) {
- loadDirectoryPartition(partitionIndex, partition);
- } else {
- loadDirectoryPartitionDelayed(partitionIndex, partition);
- }
- } else {
- Bundle args = new Bundle();
- args.putLong(DIRECTORY_ID_ARG_KEY, directoryId);
- getLoaderManager().initLoader(partitionIndex, args, this);
- }
- }
-
- /**
- * Queues up a delayed request to search the specified directory. Since directory search will
- * likely introduce a lot of network traffic, we want to wait for a pause in the user's typing
- * before sending a directory request.
- */
- private void loadDirectoryPartitionDelayed(int partitionIndex, DirectoryPartition partition) {
- mDelayedDirectorySearchHandler.removeMessages(DIRECTORY_SEARCH_MESSAGE, partition);
- Message msg =
- mDelayedDirectorySearchHandler.obtainMessage(
- DIRECTORY_SEARCH_MESSAGE, partitionIndex, 0, partition);
- mDelayedDirectorySearchHandler.sendMessageDelayed(msg, DIRECTORY_SEARCH_DELAY_MILLIS);
- }
-
- /** Loads the directory partition. */
- protected void loadDirectoryPartition(int partitionIndex, DirectoryPartition partition) {
- Bundle args = new Bundle();
- args.putLong(DIRECTORY_ID_ARG_KEY, partition.getDirectoryId());
- getLoaderManager().restartLoader(partitionIndex, args, this);
- }
-
- /** Cancels all queued directory loading requests. */
- private void removePendingDirectorySearchRequests() {
- mDelayedDirectorySearchHandler.removeMessages(DIRECTORY_SEARCH_MESSAGE);
- }
-
- @Override
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- if (!mEnabled) {
- return;
- }
-
- int loaderId = loader.getId();
- if (loaderId == DIRECTORY_LOADER_ID) {
- mDirectoryListStatus = STATUS_LOADED;
- mAdapter.changeDirectories(data);
- startLoading();
- } else {
- onPartitionLoaded(loaderId, data);
- if (isSearchMode()) {
- int directorySearchMode = getDirectorySearchMode();
- if (directorySearchMode != DirectoryListLoader.SEARCH_MODE_NONE) {
- if (mDirectoryListStatus == STATUS_NOT_LOADED) {
- mDirectoryListStatus = STATUS_LOADING;
- getLoaderManager().initLoader(DIRECTORY_LOADER_ID, null, this);
- } else {
- startLoading();
- }
- }
- } else {
- mDirectoryListStatus = STATUS_NOT_LOADED;
- getLoaderManager().destroyLoader(DIRECTORY_LOADER_ID);
- }
- }
- }
-
- @Override
- public void onLoaderReset(Loader<Cursor> loader) {}
-
- protected void onPartitionLoaded(int partitionIndex, Cursor data) {
- if (partitionIndex >= mAdapter.getPartitionCount()) {
- // When we get unsolicited data, ignore it. This could happen
- // when we are switching from search mode to the default mode.
- return;
- }
-
- // Return for non-"Suggestions" if on the zero-suggest screen.
- if (TextUtils.isEmpty(mQueryString) && partitionIndex > 0) {
- return;
- }
-
- mAdapter.changeCursor(partitionIndex, data);
- setProfileHeader();
-
- if (!isLoading()) {
- completeRestoreInstanceState();
- }
- }
-
- public boolean isLoading() {
- //noinspection SimplifiableIfStatement
- if (mAdapter != null && mAdapter.isLoading()) {
- return true;
- }
-
- return isLoadingDirectoryList();
-
- }
-
- public boolean isLoadingDirectoryList() {
- return isSearchMode()
- && getDirectorySearchMode() != DirectoryListLoader.SEARCH_MODE_NONE
- && (mDirectoryListStatus == STATUS_NOT_LOADED || mDirectoryListStatus == STATUS_LOADING);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- mContactsPrefs.unregisterChangeListener();
- mAdapter.clearPartitions();
- }
-
- protected void reloadData() {
- removePendingDirectorySearchRequests();
- mAdapter.onDataReload();
- mLoadPriorityDirectoriesOnly = true;
- mForceLoad = true;
- startLoading();
- }
-
- /**
- * Shows a view at the top of the list with a pseudo local profile prompting the user to add a
- * local profile. Default implementation does nothing.
- */
- protected void setProfileHeader() {
- mUserProfileExists = false;
- }
-
- /** Provides logic that dismisses this fragment. The default implementation does nothing. */
- protected void finish() {}
-
- public boolean isSectionHeaderDisplayEnabled() {
- return mSectionHeaderDisplayEnabled;
- }
-
- public void setSectionHeaderDisplayEnabled(boolean flag) {
- if (mSectionHeaderDisplayEnabled != flag) {
- mSectionHeaderDisplayEnabled = flag;
- if (mAdapter != null) {
- mAdapter.setSectionHeaderDisplayEnabled(flag);
- }
- configureVerticalScrollbar();
- }
- }
-
- public boolean isVisibleScrollbarEnabled() {
- return mVisibleScrollbarEnabled;
- }
-
- public void setVisibleScrollbarEnabled(boolean flag) {
- if (mVisibleScrollbarEnabled != flag) {
- mVisibleScrollbarEnabled = flag;
- configureVerticalScrollbar();
- }
- }
-
- private void configureVerticalScrollbar() {
- boolean hasScrollbar = isVisibleScrollbarEnabled() && isSectionHeaderDisplayEnabled();
-
- if (mListView != null) {
- mListView.setFastScrollEnabled(hasScrollbar);
- mListView.setVerticalScrollbarPosition(mVerticalScrollbarPosition);
- mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
- }
- }
-
- public boolean isPhotoLoaderEnabled() {
- return mPhotoLoaderEnabled;
- }
-
- public void setPhotoLoaderEnabled(boolean flag) {
- mPhotoLoaderEnabled = flag;
- configurePhotoLoader();
- }
-
- public void setQuickContactEnabled(boolean flag) {
- this.mQuickContactEnabled = flag;
- }
-
- public void setAdjustSelectionBoundsEnabled(boolean flag) {
- mAdjustSelectionBoundsEnabled = flag;
- }
-
- public final boolean isSearchMode() {
- return mSearchMode;
- }
-
- /**
- * Enter/exit search mode. This is method is tightly related to the current query, and should only
- * be called by {@link #setQueryString}.
- *
- * <p>Also note this method doesn't call {@link #reloadData()}; {@link #setQueryString} does it.
- */
- protected void setSearchMode(boolean flag) {
- if (mSearchMode != flag) {
- mSearchMode = flag;
-
- if (!flag) {
- mDirectoryListStatus = STATUS_NOT_LOADED;
- getLoaderManager().destroyLoader(DIRECTORY_LOADER_ID);
- }
-
- if (mAdapter != null) {
- mAdapter.setSearchMode(flag);
-
- mAdapter.clearPartitions();
- if (!flag) {
- // If we are switching from search to regular display, remove all directory
- // partitions after default one, assuming they are remote directories which
- // should be cleaned up on exiting the search mode.
- mAdapter.removeDirectoriesAfterDefault();
- }
- mAdapter.configurePartitionsVisibility(flag);
- }
-
- if (mListView != null) {
- mListView.setFastScrollEnabled(!flag);
- }
- }
- }
-
- @Nullable
- public final String getQueryString() {
- return mQueryString;
- }
-
- public void setQueryString(String queryString) {
- if (!TextUtils.equals(mQueryString, queryString)) {
- if (mShowEmptyListForEmptyQuery && mAdapter != null && mListView != null) {
- if (TextUtils.isEmpty(mQueryString)) {
- // Restore the adapter if the query used to be empty.
- mListView.setAdapter(mAdapter);
- } else if (TextUtils.isEmpty(queryString)) {
- // Instantly clear the list view if the new query is empty.
- mListView.setAdapter(null);
- }
- }
-
- mQueryString = queryString;
- setSearchMode(!TextUtils.isEmpty(mQueryString) || mShowEmptyListForEmptyQuery);
-
- if (mAdapter != null) {
- mAdapter.setQueryString(queryString);
- reloadData();
- }
- }
- }
-
- public void setShowEmptyListForNullQuery(boolean show) {
- mShowEmptyListForEmptyQuery = show;
- }
-
- public boolean getShowEmptyListForNullQuery() {
- return mShowEmptyListForEmptyQuery;
- }
-
- public int getDirectoryLoaderId() {
- return DIRECTORY_LOADER_ID;
- }
-
- public int getDirectorySearchMode() {
- return mDirectorySearchMode;
- }
-
- public void setDirectorySearchMode(int mode) {
- mDirectorySearchMode = mode;
- }
-
- protected int getContactNameDisplayOrder() {
- return mDisplayOrder;
- }
-
- protected void setContactNameDisplayOrder(int displayOrder) {
- mDisplayOrder = displayOrder;
- if (mAdapter != null) {
- mAdapter.setContactNameDisplayOrder(displayOrder);
- }
- }
-
- public int getSortOrder() {
- return mSortOrder;
- }
-
- public void setSortOrder(int sortOrder) {
- mSortOrder = sortOrder;
- if (mAdapter != null) {
- mAdapter.setSortOrder(sortOrder);
- }
- }
-
- public void setDirectoryResultLimit(int limit) {
- mDirectoryResultLimit = limit;
- }
-
- protected boolean loadPreferences() {
- boolean changed = false;
- if (getContactNameDisplayOrder() != mContactsPrefs.getDisplayOrder()) {
- setContactNameDisplayOrder(mContactsPrefs.getDisplayOrder());
- changed = true;
- }
-
- if (getSortOrder() != mContactsPrefs.getSortOrder()) {
- setSortOrder(mContactsPrefs.getSortOrder());
- changed = true;
- }
-
- return changed;
- }
-
- @Override
- public View onCreateView(
- LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- onCreateView(inflater, container);
-
- boolean searchMode = isSearchMode();
- mAdapter.setSearchMode(searchMode);
- mAdapter.configurePartitionsVisibility(searchMode);
- mAdapter.setPhotoLoader(mPhotoManager);
- mListView.setAdapter(mAdapter);
- return mView;
- }
-
- protected void onCreateView(LayoutInflater inflater, ViewGroup container) {
- mView = inflateView(inflater, container);
-
- mListView = mView.findViewById(android.R.id.list);
- if (mListView == null) {
- throw new RuntimeException(
- "Your content must have a ListView whose id attribute is " + "'android.R.id.list'");
- }
-
- View emptyView = mView.findViewById(android.R.id.empty);
- if (emptyView != null) {
- mListView.setEmptyView(emptyView);
- }
-
- mListView.setOnItemClickListener(this);
- mListView.setOnFocusChangeListener(this);
- mListView.setOnTouchListener(this);
- mListView.setFastScrollEnabled(!isSearchMode());
-
- // Tell list view to not show dividers. We'll do it ourself so that we can *not* show
- // them when an A-Z headers is visible.
- mListView.setDividerHeight(0);
-
- // We manually save/restore the listview state
- mListView.setSaveEnabled(false);
-
- configureVerticalScrollbar();
- configurePhotoLoader();
-
- getAdapter().setFragmentRootView(getView());
-
- ContactListViewUtils.applyCardPaddingToView(getResources(), mListView, mView);
- }
-
- @Override
- public void onHiddenChanged(boolean hidden) {
- super.onHiddenChanged(hidden);
- if (getActivity() != null && getView() != null && !hidden) {
- // If the padding was last applied when in a hidden state, it may have been applied
- // incorrectly. Therefore we need to reapply it.
- ContactListViewUtils.applyCardPaddingToView(getResources(), mListView, getView());
- }
- }
-
- protected void configurePhotoLoader() {
- if (isPhotoLoaderEnabled() && mContext != null) {
- if (mPhotoManager == null) {
- mPhotoManager = ContactPhotoManager.getInstance(mContext);
- }
- if (mListView != null) {
- mListView.setOnScrollListener(this);
- }
- if (mAdapter != null) {
- mAdapter.setPhotoLoader(mPhotoManager);
- }
- }
- }
-
- protected void configureAdapter() {
- if (mAdapter == null) {
- return;
- }
-
- mAdapter.setQuickContactEnabled(mQuickContactEnabled);
- mAdapter.setAdjustSelectionBoundsEnabled(mAdjustSelectionBoundsEnabled);
- mAdapter.setQueryString(mQueryString);
- mAdapter.setDirectorySearchMode(mDirectorySearchMode);
- mAdapter.setPinnedPartitionHeadersEnabled(false);
- mAdapter.setContactNameDisplayOrder(mDisplayOrder);
- mAdapter.setSortOrder(mSortOrder);
- mAdapter.setSectionHeaderDisplayEnabled(mSectionHeaderDisplayEnabled);
- mAdapter.setSelectionVisible(mSelectionVisible);
- mAdapter.setDirectoryResultLimit(mDirectoryResultLimit);
- mAdapter.setDarkTheme(mDarkTheme);
- }
-
- @Override
- public void onScroll(
- AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- PerformanceReport.recordScrollStateChange(scrollState);
- if (scrollState == OnScrollListener.SCROLL_STATE_FLING) {
- mPhotoManager.pause();
- } else if (isPhotoLoaderEnabled()) {
- mPhotoManager.resume();
- }
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- hideSoftKeyboard();
-
- int adjPosition = position - mListView.getHeaderViewsCount();
- if (adjPosition >= 0) {
- onItemClick(adjPosition, id);
- }
- }
-
- private void hideSoftKeyboard() {
- // Hide soft keyboard, if visible
- InputMethodManager inputMethodManager =
- (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
- inputMethodManager.hideSoftInputFromWindow(mListView.getWindowToken(), 0);
- }
-
- /** Dismisses the soft keyboard when the list takes focus. */
- @Override
- public void onFocusChange(View view, boolean hasFocus) {
- if (view == mListView && hasFocus) {
- hideSoftKeyboard();
- }
- }
-
- /** Dismisses the soft keyboard when the list is touched. */
- @Override
- public boolean onTouch(View view, MotionEvent event) {
- if (view == mListView) {
- hideSoftKeyboard();
- }
- return false;
- }
-
- @Override
- public void onPause() {
- // Save the scrolling state of the list view
- mListViewTopIndex = mListView.getFirstVisiblePosition();
- View v = mListView.getChildAt(0);
- mListViewTopOffset = (v == null) ? 0 : (v.getTop() - mListView.getPaddingTop());
-
- super.onPause();
- removePendingDirectorySearchRequests();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- // Restore the selection of the list view. See a bug.
- // This has to be done manually because if the list view has its emptyView set,
- // the scrolling state will be reset when clearPartitions() is called on the adapter.
- mListView.setSelectionFromTop(mListViewTopIndex, mListViewTopOffset);
- }
-
- /** Restore the list state after the adapter is populated. */
- protected void completeRestoreInstanceState() {
- if (mListState != null) {
- mListView.onRestoreInstanceState(mListState);
- mListState = null;
- }
- }
-
- public void setDarkTheme(boolean value) {
- mDarkTheme = value;
- if (mAdapter != null) {
- mAdapter.setDarkTheme(value);
- }
- }
-
- private int getDefaultVerticalScrollbarPosition() {
- final Locale locale = Locale.getDefault();
- final int layoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
- switch (layoutDirection) {
- case View.LAYOUT_DIRECTION_RTL:
- return View.SCROLLBAR_POSITION_LEFT;
- case View.LAYOUT_DIRECTION_LTR:
- default:
- return View.SCROLLBAR_POSITION_RIGHT;
- }
- }
-}
diff --git a/java/com/android/contacts/common/list/ContactListAdapter.java b/java/com/android/contacts/common/list/ContactListAdapter.java
deleted file mode 100644
index 721609d1d..000000000
--- a/java/com/android/contacts/common/list/ContactListAdapter.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Directory;
-import android.provider.ContactsContract.SearchSnippets;
-import android.view.ViewGroup;
-import com.android.contacts.common.R;
-import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
-
-/**
- * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type. Also
- * includes support for including the {@link ContactsContract.Profile} record in the list.
- */
-public abstract class ContactListAdapter extends ContactEntryListAdapter {
-
- private CharSequence mUnknownNameText;
-
- public ContactListAdapter(Context context) {
- super(context);
-
- mUnknownNameText = context.getText(R.string.missing_name);
- }
-
- protected static Uri buildSectionIndexerUri(Uri uri) {
- return uri.buildUpon().appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true").build();
- }
-
- public Uri getContactUri(int partitionIndex, Cursor cursor) {
- long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
- String lookupKey = cursor.getString(ContactQuery.CONTACT_LOOKUP_KEY);
- Uri uri = Contacts.getLookupUri(contactId, lookupKey);
- long directoryId = ((DirectoryPartition) getPartition(partitionIndex)).getDirectoryId();
- if (uri != null && directoryId != Directory.DEFAULT) {
- uri =
- uri.buildUpon()
- .appendQueryParameter(
- ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId))
- .build();
- }
- return uri;
- }
-
- @Override
- protected ContactListItemView newView(
- Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
- ContactListItemView view = super.newView(context, partition, cursor, position, parent);
- view.setUnknownNameText(mUnknownNameText);
- view.setQuickContactEnabled(isQuickContactEnabled());
- view.setAdjustSelectionBoundsEnabled(isAdjustSelectionBoundsEnabled());
- view.setActivatedStateSupported(isSelectionVisible());
- return view;
- }
-
- protected void bindSectionHeaderAndDivider(
- ContactListItemView view, int position, Cursor cursor) {
- view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
- if (isSectionHeaderDisplayEnabled()) {
- Placement placement = getItemPlacementInSection(position);
- view.setSectionHeader(placement.sectionHeader);
- } else {
- view.setSectionHeader(null);
- }
- }
-
- protected void bindPhoto(final ContactListItemView view, int partitionIndex, Cursor cursor) {
- if (!isPhotoSupported(partitionIndex)) {
- view.removePhotoView();
- return;
- }
-
- // Set the photo, if available
- long photoId = 0;
- if (!cursor.isNull(ContactQuery.CONTACT_PHOTO_ID)) {
- photoId = cursor.getLong(ContactQuery.CONTACT_PHOTO_ID);
- }
-
- if (photoId != 0) {
- getPhotoLoader()
- .loadThumbnail(view.getPhotoView(), photoId, false, getCircularPhotos(), null);
- } else {
- final String photoUriString = cursor.getString(ContactQuery.CONTACT_PHOTO_URI);
- final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
- DefaultImageRequest request = null;
- if (photoUri == null) {
- request =
- getDefaultImageRequestFromCursor(
- cursor, ContactQuery.CONTACT_DISPLAY_NAME, ContactQuery.CONTACT_LOOKUP_KEY);
- }
- getPhotoLoader()
- .loadDirectoryPhoto(view.getPhotoView(), photoUri, false, getCircularPhotos(), request);
- }
- }
-
- protected void bindNameAndViewId(final ContactListItemView view, Cursor cursor) {
- view.showDisplayName(cursor, ContactQuery.CONTACT_DISPLAY_NAME);
- // Note: we don't show phonetic any more (See issue 5265330)
-
- bindViewId(view, cursor, ContactQuery.CONTACT_ID);
- }
-
- protected void bindPresenceAndStatusMessage(final ContactListItemView view, Cursor cursor) {
- view.showPresenceAndStatusMessage(
- cursor, ContactQuery.CONTACT_PRESENCE_STATUS, ContactQuery.CONTACT_CONTACT_STATUS);
- }
-
- protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) {
- view.showSnippet(cursor, ContactQuery.CONTACT_SNIPPET);
- }
-
- @Override
- public void changeCursor(int partitionIndex, Cursor cursor) {
- super.changeCursor(partitionIndex, cursor);
-
- if (cursor == null || !cursor.moveToFirst()) {
- return;
- }
-
- // hasProfile tells whether the first row is a profile
- final boolean hasProfile = cursor.getInt(ContactQuery.CONTACT_IS_USER_PROFILE) == 1;
-
- // Add ME profile on top of favorites
- cursor.moveToFirst();
- setProfileExists(hasProfile);
- }
-
- /** @return Projection useful for children. */
- protected final String[] getProjection(boolean forSearch) {
- final int sortOrder = getContactNameDisplayOrder();
- if (forSearch) {
- if (sortOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
- return ContactQuery.FILTER_PROJECTION_PRIMARY;
- } else {
- return ContactQuery.FILTER_PROJECTION_ALTERNATIVE;
- }
- } else {
- if (sortOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
- return ContactQuery.CONTACT_PROJECTION_PRIMARY;
- } else {
- return ContactQuery.CONTACT_PROJECTION_ALTERNATIVE;
- }
- }
- }
-
- protected static class ContactQuery {
-
- public static final int CONTACT_ID = 0;
- public static final int CONTACT_DISPLAY_NAME = 1;
- public static final int CONTACT_PRESENCE_STATUS = 2;
- public static final int CONTACT_CONTACT_STATUS = 3;
- public static final int CONTACT_PHOTO_ID = 4;
- public static final int CONTACT_PHOTO_URI = 5;
- public static final int CONTACT_LOOKUP_KEY = 6;
- public static final int CONTACT_IS_USER_PROFILE = 7;
- public static final int CONTACT_PHONETIC_NAME = 8;
- public static final int CONTACT_STARRED = 9;
- public static final int CONTACT_SNIPPET = 10;
- private static final String[] CONTACT_PROJECTION_PRIMARY =
- new String[] {
- Contacts._ID, // 0
- Contacts.DISPLAY_NAME_PRIMARY, // 1
- Contacts.CONTACT_PRESENCE, // 2
- Contacts.CONTACT_STATUS, // 3
- Contacts.PHOTO_ID, // 4
- Contacts.PHOTO_THUMBNAIL_URI, // 5
- Contacts.LOOKUP_KEY, // 6
- Contacts.IS_USER_PROFILE, // 7
- Contacts.PHONETIC_NAME, // 8
- Contacts.STARRED, // 9
- };
- private static final String[] CONTACT_PROJECTION_ALTERNATIVE =
- new String[] {
- Contacts._ID, // 0
- Contacts.DISPLAY_NAME_ALTERNATIVE, // 1
- Contacts.CONTACT_PRESENCE, // 2
- Contacts.CONTACT_STATUS, // 3
- Contacts.PHOTO_ID, // 4
- Contacts.PHOTO_THUMBNAIL_URI, // 5
- Contacts.LOOKUP_KEY, // 6
- Contacts.IS_USER_PROFILE, // 7
- Contacts.PHONETIC_NAME, // 8
- Contacts.STARRED, // 9
- };
- private static final String[] FILTER_PROJECTION_PRIMARY =
- new String[] {
- Contacts._ID, // 0
- Contacts.DISPLAY_NAME_PRIMARY, // 1
- Contacts.CONTACT_PRESENCE, // 2
- Contacts.CONTACT_STATUS, // 3
- Contacts.PHOTO_ID, // 4
- Contacts.PHOTO_THUMBNAIL_URI, // 5
- Contacts.LOOKUP_KEY, // 6
- Contacts.IS_USER_PROFILE, // 7
- Contacts.PHONETIC_NAME, // 8
- Contacts.STARRED, // 9
- SearchSnippets.SNIPPET, // 10
- };
- private static final String[] FILTER_PROJECTION_ALTERNATIVE =
- new String[] {
- Contacts._ID, // 0
- Contacts.DISPLAY_NAME_ALTERNATIVE, // 1
- Contacts.CONTACT_PRESENCE, // 2
- Contacts.CONTACT_STATUS, // 3
- Contacts.PHOTO_ID, // 4
- Contacts.PHOTO_THUMBNAIL_URI, // 5
- Contacts.LOOKUP_KEY, // 6
- Contacts.IS_USER_PROFILE, // 7
- Contacts.PHONETIC_NAME, // 8
- Contacts.STARRED, // 9
- SearchSnippets.SNIPPET, // 10
- };
- }
-}
diff --git a/java/com/android/contacts/common/list/ContactListItemView.java b/java/com/android/contacts/common/list/ContactListItemView.java
deleted file mode 100644
index 409aa1b9e..000000000
--- a/java/com/android/contacts/common/list/ContactListItemView.java
+++ /dev/null
@@ -1,1508 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.database.Cursor;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.SearchSnippets;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
-import android.telephony.PhoneNumberUtils;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.TextUtils;
-import android.text.TextUtils.TruncateAt;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView.SelectionBoundsAdjuster;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import android.widget.QuickContactBadge;
-import android.widget.TextView;
-import com.android.contacts.common.ContactPresenceIconUtil;
-import com.android.contacts.common.ContactStatusUtil;
-import com.android.contacts.common.R;
-import com.android.contacts.common.format.TextHighlighter;
-import com.android.contacts.common.list.PhoneNumberListAdapter.Listener;
-import com.android.contacts.common.util.ContactDisplayUtils;
-import com.android.contacts.common.util.SearchUtil;
-import com.android.dialer.callintent.CallIntentBuilder;
-import com.android.dialer.util.ViewUtil;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A custom view for an item in the contact list. The view contains the contact's photo, a set of
- * text views (for name, status, etc...) and icons for presence and call. The view uses no XML file
- * for layout and all the measurements and layouts are done in the onMeasure and onLayout methods.
- *
- * <p>The layout puts the contact's photo on the right side of the view, the call icon (if present)
- * to the left of the photo, the text lines are aligned to the left and the presence icon (if
- * present) is set to the left of the status line.
- *
- * <p>The layout also supports a header (used as a header of a group of contacts) that is above the
- * contact's data and a divider between contact view.
- */
-public class ContactListItemView extends ViewGroup implements SelectionBoundsAdjuster {
-
- /** IntDef for indices of ViewPager tabs. */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({NONE, VIDEO, DUO, CALL_AND_SHARE})
- public @interface CallToAction {}
-
- public static final int NONE = 0;
- public static final int VIDEO = 1;
- public static final int DUO = 2;
- public static final int CALL_AND_SHARE = 3;
-
- private final PhotoPosition mPhotoPosition = getDefaultPhotoPosition();
- private static final Pattern SPLIT_PATTERN =
- Pattern.compile("([\\w-\\.]+)@((?:[\\w]+\\.)+)([a-zA-Z]{2,4})|[\\w]+");
- static final char SNIPPET_START_MATCH = '[';
- static final char SNIPPET_END_MATCH = ']';
- /** A helper used to highlight a prefix in a text field. */
- private final TextHighlighter mTextHighlighter;
- // Style values for layout and appearance
- // The initialized values are defaults if none is provided through xml.
- private int mPreferredHeight = 0;
- private int mGapBetweenImageAndText = 0;
- private int mGapBetweenLabelAndData = 0;
- private int mPresenceIconMargin = 4;
- private int mPresenceIconSize = 16;
- private int mTextIndent = 0;
- private int mTextOffsetTop;
- private int mNameTextViewTextSize;
- private int mHeaderWidth;
- private Drawable mActivatedBackgroundDrawable;
- private int mCallToActionSize = 48;
- private int mCallToActionMargin = 16;
- // Set in onLayout. Represent left and right position of the View on the screen.
- private int mLeftOffset;
- private int mRightOffset;
- /** Used with {@link #mLabelView}, specifying the width ratio between label and data. */
- private int mLabelViewWidthWeight = 3;
- /** Used with {@link #mDataView}, specifying the width ratio between label and data. */
- private int mDataViewWidthWeight = 5;
-
- private ArrayList<HighlightSequence> mNameHighlightSequence;
- private ArrayList<HighlightSequence> mNumberHighlightSequence;
- // Highlighting prefix for names.
- private String mHighlightedPrefix;
- /** Indicates whether the view should leave room for the "video call" icon. */
- private boolean mSupportVideoCall;
-
- // Header layout data
- private TextView mHeaderTextView;
- private boolean mIsSectionHeaderEnabled;
- // The views inside the contact view
- private boolean mQuickContactEnabled = true;
- private QuickContactBadge mQuickContact;
- private ImageView mPhotoView;
- private TextView mNameTextView;
- private TextView mLabelView;
- private TextView mDataView;
- private TextView mSnippetView;
- private TextView mStatusView;
- private ImageView mPresenceIcon;
- @NonNull private final ImageView mCallToActionView;
- private ImageView mWorkProfileIcon;
- private ColorStateList mSecondaryTextColor;
- private int mDefaultPhotoViewSize = 0;
- /**
- * Can be effective even when {@link #mPhotoView} is null, as we want to have horizontal padding
- * to align other data in this View.
- */
- private int mPhotoViewWidth;
- /**
- * Can be effective even when {@link #mPhotoView} is null, as we want to have vertical padding.
- */
- private int mPhotoViewHeight;
- /**
- * Only effective when {@link #mPhotoView} is null. When true all the Views on the right side of
- * the photo should have horizontal padding on those left assuming there is a photo.
- */
- private boolean mKeepHorizontalPaddingForPhotoView;
- /** Only effective when {@link #mPhotoView} is null. */
- private boolean mKeepVerticalPaddingForPhotoView;
- /**
- * True when {@link #mPhotoViewWidth} and {@link #mPhotoViewHeight} are ready for being used.
- * False indicates those values should be updated before being used in position calculation.
- */
- private boolean mPhotoViewWidthAndHeightAreReady = false;
-
- private int mNameTextViewHeight;
- private int mNameTextViewTextColor = Color.BLACK;
- private int mPhoneticNameTextViewHeight;
- private int mLabelViewHeight;
- private int mDataViewHeight;
- private int mSnippetTextViewHeight;
- private int mStatusTextViewHeight;
- private int mCheckBoxWidth;
- // Holds Math.max(mLabelTextViewHeight, mDataViewHeight), assuming Label and Data share the
- // same row.
- private int mLabelAndDataViewMaxHeight;
- private boolean mActivatedStateSupported;
- private boolean mAdjustSelectionBoundsEnabled = true;
- private Rect mBoundsWithoutHeader = new Rect();
- private CharSequence mUnknownNameText;
-
- private String mPhoneNumber;
- private int mPosition = -1;
- private @CallToAction int mCallToAction = NONE;
-
- public ContactListItemView(Context context, AttributeSet attrs, boolean supportVideoCallIcon) {
- this(context, attrs);
-
- mSupportVideoCall = supportVideoCallIcon;
- }
-
- public ContactListItemView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray a;
-
- if (R.styleable.ContactListItemView != null) {
- // Read all style values
- a = getContext().obtainStyledAttributes(attrs, R.styleable.ContactListItemView);
- mPreferredHeight =
- a.getDimensionPixelSize(
- R.styleable.ContactListItemView_list_item_height, mPreferredHeight);
- mActivatedBackgroundDrawable =
- a.getDrawable(R.styleable.ContactListItemView_activated_background);
- mGapBetweenImageAndText =
- a.getDimensionPixelOffset(
- R.styleable.ContactListItemView_list_item_gap_between_image_and_text,
- mGapBetweenImageAndText);
- mGapBetweenLabelAndData =
- a.getDimensionPixelOffset(
- R.styleable.ContactListItemView_list_item_gap_between_label_and_data,
- mGapBetweenLabelAndData);
- mPresenceIconMargin =
- a.getDimensionPixelOffset(
- R.styleable.ContactListItemView_list_item_presence_icon_margin, mPresenceIconMargin);
- mPresenceIconSize =
- a.getDimensionPixelOffset(
- R.styleable.ContactListItemView_list_item_presence_icon_size, mPresenceIconSize);
- mDefaultPhotoViewSize =
- a.getDimensionPixelOffset(
- R.styleable.ContactListItemView_list_item_photo_size, mDefaultPhotoViewSize);
- mTextIndent =
- a.getDimensionPixelOffset(
- R.styleable.ContactListItemView_list_item_text_indent, mTextIndent);
- mTextOffsetTop =
- a.getDimensionPixelOffset(
- R.styleable.ContactListItemView_list_item_text_offset_top, mTextOffsetTop);
- mDataViewWidthWeight =
- a.getInteger(
- R.styleable.ContactListItemView_list_item_data_width_weight, mDataViewWidthWeight);
- mLabelViewWidthWeight =
- a.getInteger(
- R.styleable.ContactListItemView_list_item_label_width_weight, mLabelViewWidthWeight);
- mNameTextViewTextColor =
- a.getColor(
- R.styleable.ContactListItemView_list_item_name_text_color, mNameTextViewTextColor);
- mNameTextViewTextSize =
- (int)
- a.getDimension(
- R.styleable.ContactListItemView_list_item_name_text_size,
- (int) getResources().getDimension(R.dimen.contact_browser_list_item_text_size));
- mCallToActionSize =
- a.getDimensionPixelOffset(
- R.styleable.ContactListItemView_list_item_video_call_icon_size, mCallToActionSize);
- mCallToActionMargin =
- a.getDimensionPixelOffset(
- R.styleable.ContactListItemView_list_item_video_call_icon_margin,
- mCallToActionMargin);
-
- setPaddingRelative(
- a.getDimensionPixelOffset(R.styleable.ContactListItemView_list_item_padding_left, 0),
- a.getDimensionPixelOffset(R.styleable.ContactListItemView_list_item_padding_top, 0),
- a.getDimensionPixelOffset(R.styleable.ContactListItemView_list_item_padding_right, 0),
- a.getDimensionPixelOffset(R.styleable.ContactListItemView_list_item_padding_bottom, 0));
-
- a.recycle();
- }
-
- mTextHighlighter = new TextHighlighter(Typeface.BOLD);
-
- if (R.styleable.Theme != null) {
- a = getContext().obtainStyledAttributes(R.styleable.Theme);
- mSecondaryTextColor = a.getColorStateList(R.styleable.Theme_android_textColorSecondary);
- a.recycle();
- }
-
- mHeaderWidth = getResources().getDimensionPixelSize(R.dimen.contact_list_section_header_width);
-
- if (mActivatedBackgroundDrawable != null) {
- mActivatedBackgroundDrawable.setCallback(this);
- }
-
- mNameHighlightSequence = new ArrayList<>();
- mNumberHighlightSequence = new ArrayList<>();
-
- mCallToActionView = new ImageView(getContext());
- mCallToActionView.setId(R.id.call_to_action);
- mCallToActionView.setLayoutParams(new LayoutParams(mCallToActionSize, mCallToActionSize));
- mCallToActionView.setScaleType(ScaleType.CENTER);
- mCallToActionView.setImageTintList(
- ContextCompat.getColorStateList(getContext(), R.color.search_video_call_icon_tint));
- addView(mCallToActionView);
-
- setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
- }
-
- public static PhotoPosition getDefaultPhotoPosition() {
- int layoutDirection = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
- return layoutDirection == View.LAYOUT_DIRECTION_RTL ? PhotoPosition.RIGHT : PhotoPosition.LEFT;
- }
-
- /**
- * Helper method for splitting a string into tokens. The lists passed in are populated with the
- * tokens and offsets into the content of each token. The tokenization function parses e-mail
- * addresses as a single token; otherwise it splits on any non-alphanumeric character.
- *
- * @param content Content to split.
- * @return List of token strings.
- */
- private static List<String> split(String content) {
- final Matcher matcher = SPLIT_PATTERN.matcher(content);
- final ArrayList<String> tokens = new ArrayList<>();
- while (matcher.find()) {
- tokens.add(matcher.group());
- }
- return tokens;
- }
-
- public void setUnknownNameText(CharSequence unknownNameText) {
- mUnknownNameText = unknownNameText;
- }
-
- public void setQuickContactEnabled(boolean flag) {
- mQuickContactEnabled = flag;
- }
-
- /**
- * Sets whether the call to action is shown. For the {@link CallToAction} to be shown, it must be
- * supported as well.
- *
- * @param action {@link CallToAction} you want to display (if it's supported).
- * @param listener Listener to notify when the call to action is clicked.
- * @param position The position in the adapter of the call to action.
- */
- public void setCallToAction(@CallToAction int action, Listener listener, int position) {
- mCallToAction = action;
- mPosition = position;
-
- Drawable drawable;
- int description;
- OnClickListener onClickListener;
- if (action == CALL_AND_SHARE) {
- drawable = ContextCompat.getDrawable(getContext(), R.drawable.ic_phone_attach);
- drawable.setAutoMirrored(true);
- description = R.string.description_search_call_and_share;
- onClickListener = v -> listener.onCallAndShareIconClicked(position);
- } else if (action == VIDEO && mSupportVideoCall) {
- drawable =
- ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_videocam_vd_theme_24);
- drawable.setAutoMirrored(true);
- description = R.string.description_search_video_call;
- onClickListener = v -> listener.onVideoCallIconClicked(position);
- } else if (action == DUO) {
- CallIntentBuilder.increaseLightbringerCallButtonAppearInSearchCount();
- drawable =
- ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_videocam_vd_theme_24);
- drawable.setAutoMirrored(true);
- description = R.string.description_search_video_call;
- onClickListener = v -> listener.onDuoVideoIconClicked(position);
- } else {
- mCallToActionView.setVisibility(View.GONE);
- mCallToActionView.setOnClickListener(null);
- return;
- }
-
- mCallToActionView.setContentDescription(getContext().getString(description));
- mCallToActionView.setOnClickListener(onClickListener);
- mCallToActionView.setImageDrawable(drawable);
- mCallToActionView.setVisibility(View.VISIBLE);
- }
-
- public @CallToAction int getCallToAction() {
- return mCallToAction;
- }
-
- public int getPosition() {
- return mPosition;
- }
-
- /**
- * Sets whether the view supports a video calling icon. This is independent of whether the view is
- * actually showing an icon. Support for the video calling icon ensures that the layout leaves
- * space for the video icon, should it be shown.
- *
- * @param supportVideoCall {@code true} if the video call icon is supported, {@code false}
- * otherwise.
- */
- public void setSupportVideoCallIcon(boolean supportVideoCall) {
- mSupportVideoCall = supportVideoCall;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // We will match parent's width and wrap content vertically, but make sure
- // height is no less than listPreferredItemHeight.
- final int specWidth = resolveSize(0, widthMeasureSpec);
- final int preferredHeight = mPreferredHeight;
-
- mNameTextViewHeight = 0;
- mPhoneticNameTextViewHeight = 0;
- mLabelViewHeight = 0;
- mDataViewHeight = 0;
- mLabelAndDataViewMaxHeight = 0;
- mSnippetTextViewHeight = 0;
- mStatusTextViewHeight = 0;
- mCheckBoxWidth = 0;
-
- ensurePhotoViewSize();
-
- // Width each TextView is able to use.
- int effectiveWidth;
- // All the other Views will honor the photo, so available width for them may be shrunk.
- if (mPhotoViewWidth > 0 || mKeepHorizontalPaddingForPhotoView) {
- effectiveWidth =
- specWidth
- - getPaddingLeft()
- - getPaddingRight()
- - (mPhotoViewWidth + mGapBetweenImageAndText);
- } else {
- effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight();
- }
-
- if (mIsSectionHeaderEnabled) {
- effectiveWidth -= mHeaderWidth + mGapBetweenImageAndText;
- }
-
- effectiveWidth -= (mCallToActionSize + mCallToActionMargin);
-
- // Go over all visible text views and measure actual width of each of them.
- // Also calculate their heights to get the total height for this entire view.
-
- if (isVisible(mNameTextView)) {
- // Calculate width for name text - this parallels similar measurement in onLayout.
- int nameTextWidth = effectiveWidth;
- if (mPhotoPosition != PhotoPosition.LEFT) {
- nameTextWidth -= mTextIndent;
- }
- mNameTextView.measure(
- MeasureSpec.makeMeasureSpec(nameTextWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mNameTextViewHeight = mNameTextView.getMeasuredHeight();
- }
-
- // If both data (phone number/email address) and label (type like "MOBILE") are quite long,
- // we should ellipsize both using appropriate ratio.
- final int dataWidth;
- final int labelWidth;
- if (isVisible(mDataView)) {
- if (isVisible(mLabelView)) {
- final int totalWidth = effectiveWidth - mGapBetweenLabelAndData;
- dataWidth =
- ((totalWidth * mDataViewWidthWeight) / (mDataViewWidthWeight + mLabelViewWidthWeight));
- labelWidth =
- ((totalWidth * mLabelViewWidthWeight) / (mDataViewWidthWeight + mLabelViewWidthWeight));
- } else {
- dataWidth = effectiveWidth;
- labelWidth = 0;
- }
- } else {
- dataWidth = 0;
- if (isVisible(mLabelView)) {
- labelWidth = effectiveWidth;
- } else {
- labelWidth = 0;
- }
- }
-
- if (isVisible(mDataView)) {
- mDataView.measure(
- MeasureSpec.makeMeasureSpec(dataWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mDataViewHeight = mDataView.getMeasuredHeight();
- }
-
- if (isVisible(mLabelView)) {
- mLabelView.measure(
- MeasureSpec.makeMeasureSpec(labelWidth, MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mLabelViewHeight = mLabelView.getMeasuredHeight();
- }
- mLabelAndDataViewMaxHeight = Math.max(mLabelViewHeight, mDataViewHeight);
-
- if (isVisible(mSnippetView)) {
- mSnippetView.measure(
- MeasureSpec.makeMeasureSpec(effectiveWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mSnippetTextViewHeight = mSnippetView.getMeasuredHeight();
- }
-
- // Status view height is the biggest of the text view and the presence icon
- if (isVisible(mPresenceIcon)) {
- mPresenceIcon.measure(
- MeasureSpec.makeMeasureSpec(mPresenceIconSize, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(mPresenceIconSize, MeasureSpec.EXACTLY));
- mStatusTextViewHeight = mPresenceIcon.getMeasuredHeight();
- }
-
- mCallToActionView.measure(
- MeasureSpec.makeMeasureSpec(mCallToActionSize, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(mCallToActionSize, MeasureSpec.EXACTLY));
-
- if (isVisible(mWorkProfileIcon)) {
- mWorkProfileIcon.measure(
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mNameTextViewHeight = Math.max(mNameTextViewHeight, mWorkProfileIcon.getMeasuredHeight());
- }
-
- if (isVisible(mStatusView)) {
- // Presence and status are in a same row, so status will be affected by icon size.
- final int statusWidth;
- if (isVisible(mPresenceIcon)) {
- statusWidth = (effectiveWidth - mPresenceIcon.getMeasuredWidth() - mPresenceIconMargin);
- } else {
- statusWidth = effectiveWidth;
- }
- mStatusView.measure(
- MeasureSpec.makeMeasureSpec(statusWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mStatusTextViewHeight = Math.max(mStatusTextViewHeight, mStatusView.getMeasuredHeight());
- }
-
- // Calculate height including padding.
- int height =
- (mNameTextViewHeight
- + mPhoneticNameTextViewHeight
- + mLabelAndDataViewMaxHeight
- + mSnippetTextViewHeight
- + mStatusTextViewHeight);
-
- // Make sure the height is at least as high as the photo
- height = Math.max(height, mPhotoViewHeight + getPaddingBottom() + getPaddingTop());
-
- // Make sure height is at least the preferred height
- height = Math.max(height, preferredHeight);
-
- // Measure the header if it is visible.
- if (mHeaderTextView != null && mHeaderTextView.getVisibility() == VISIBLE) {
- mHeaderTextView.measure(
- MeasureSpec.makeMeasureSpec(mHeaderWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- }
-
- setMeasuredDimension(specWidth, height);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- final int height = bottom - top;
- final int width = right - left;
-
- // Determine the vertical bounds by laying out the header first.
- int topBound = 0;
- int leftBound = getPaddingLeft();
- int rightBound = width - getPaddingRight();
-
- final boolean isLayoutRtl = ViewUtil.isViewLayoutRtl(this);
-
- // Put the section header on the left side of the contact view.
- if (mIsSectionHeaderEnabled) {
- // Align the text view all the way left, to be consistent with Contacts.
- if (isLayoutRtl) {
- rightBound = width;
- } else {
- leftBound = 0;
- }
- if (mHeaderTextView != null) {
- int headerHeight = mHeaderTextView.getMeasuredHeight();
- int headerTopBound = (height + topBound - headerHeight) / 2 + mTextOffsetTop;
-
- mHeaderTextView.layout(
- isLayoutRtl ? rightBound - mHeaderWidth : leftBound,
- headerTopBound,
- isLayoutRtl ? rightBound : leftBound + mHeaderWidth,
- headerTopBound + headerHeight);
- }
- if (isLayoutRtl) {
- rightBound -= mHeaderWidth;
- } else {
- leftBound += mHeaderWidth;
- }
- }
-
- mBoundsWithoutHeader.set(left + leftBound, topBound, left + rightBound, height);
- mLeftOffset = left + leftBound;
- mRightOffset = left + rightBound;
- if (mIsSectionHeaderEnabled) {
- if (isLayoutRtl) {
- rightBound -= mGapBetweenImageAndText;
- } else {
- leftBound += mGapBetweenImageAndText;
- }
- }
-
- if (mActivatedStateSupported && isActivated()) {
- mActivatedBackgroundDrawable.setBounds(mBoundsWithoutHeader);
- }
-
- final View photoView = mQuickContact != null ? mQuickContact : mPhotoView;
- if (mPhotoPosition == PhotoPosition.LEFT) {
- // Photo is the left most view. All the other Views should on the right of the photo.
- if (photoView != null) {
- // Center the photo vertically
- final int photoTop = topBound + (height - topBound - mPhotoViewHeight) / 2;
- photoView.layout(
- leftBound, photoTop, leftBound + mPhotoViewWidth, photoTop + mPhotoViewHeight);
- leftBound += mPhotoViewWidth + mGapBetweenImageAndText;
- } else if (mKeepHorizontalPaddingForPhotoView) {
- // Draw nothing but keep the padding.
- leftBound += mPhotoViewWidth + mGapBetweenImageAndText;
- }
- } else {
- // Photo is the right most view. Right bound should be adjusted that way.
- if (photoView != null) {
- // Center the photo vertically
- final int photoTop = topBound + (height - topBound - mPhotoViewHeight) / 2;
- photoView.layout(
- rightBound - mPhotoViewWidth, photoTop, rightBound, photoTop + mPhotoViewHeight);
- rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
- } else if (mKeepHorizontalPaddingForPhotoView) {
- // Draw nothing but keep the padding.
- rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
- }
-
- // Add indent between left-most padding and texts.
- leftBound += mTextIndent;
- }
-
- // Place the call to action at the end of the list (e.g. take into account RTL mode).
- // Center the icon vertically
- final int callToActionTop = topBound + (height - topBound - mCallToActionSize) / 2;
-
- if (!isLayoutRtl) {
- // When photo is on left, icon is placed on the right edge.
- mCallToActionView.layout(
- rightBound - mCallToActionSize,
- callToActionTop,
- rightBound,
- callToActionTop + mCallToActionSize);
- } else {
- // When photo is on right, icon is placed on the left edge.
- mCallToActionView.layout(
- leftBound,
- callToActionTop,
- leftBound + mCallToActionSize,
- callToActionTop + mCallToActionSize);
- }
-
- if (mPhotoPosition == PhotoPosition.LEFT) {
- rightBound -= (mCallToActionSize + mCallToActionMargin);
- } else {
- leftBound += mCallToActionSize + mCallToActionMargin;
- }
-
- // Center text vertically, then apply the top offset.
- final int totalTextHeight =
- mNameTextViewHeight
- + mPhoneticNameTextViewHeight
- + mLabelAndDataViewMaxHeight
- + mSnippetTextViewHeight
- + mStatusTextViewHeight;
- int textTopBound = (height + topBound - totalTextHeight) / 2 + mTextOffsetTop;
-
- // Work Profile icon align top
- int workProfileIconWidth = 0;
- if (isVisible(mWorkProfileIcon)) {
- workProfileIconWidth = mWorkProfileIcon.getMeasuredWidth();
- final int distanceFromEnd = mCheckBoxWidth > 0 ? mCheckBoxWidth + mGapBetweenImageAndText : 0;
- if (mPhotoPosition == PhotoPosition.LEFT) {
- // When photo is on left, label is placed on the right edge of the list item.
- mWorkProfileIcon.layout(
- rightBound - workProfileIconWidth - distanceFromEnd,
- textTopBound,
- rightBound - distanceFromEnd,
- textTopBound + mNameTextViewHeight);
- } else {
- // When photo is on right, label is placed on the left of data view.
- mWorkProfileIcon.layout(
- leftBound + distanceFromEnd,
- textTopBound,
- leftBound + workProfileIconWidth + distanceFromEnd,
- textTopBound + mNameTextViewHeight);
- }
- }
-
- // Layout all text view and presence icon
- // Put name TextView first
- if (isVisible(mNameTextView)) {
- final int distanceFromEnd =
- workProfileIconWidth
- + (mCheckBoxWidth > 0 ? mCheckBoxWidth + mGapBetweenImageAndText : 0);
- if (mPhotoPosition == PhotoPosition.LEFT) {
- mNameTextView.layout(
- leftBound,
- textTopBound,
- rightBound - distanceFromEnd,
- textTopBound + mNameTextViewHeight);
- } else {
- mNameTextView.layout(
- leftBound + distanceFromEnd,
- textTopBound,
- rightBound,
- textTopBound + mNameTextViewHeight);
- }
- }
-
- if (isVisible(mNameTextView) || isVisible(mWorkProfileIcon)) {
- textTopBound += mNameTextViewHeight;
- }
-
- // Presence and status
- if (isLayoutRtl) {
- int statusRightBound = rightBound;
- if (isVisible(mPresenceIcon)) {
- int iconWidth = mPresenceIcon.getMeasuredWidth();
- mPresenceIcon.layout(
- rightBound - iconWidth, textTopBound, rightBound, textTopBound + mStatusTextViewHeight);
- statusRightBound -= (iconWidth + mPresenceIconMargin);
- }
-
- if (isVisible(mStatusView)) {
- mStatusView.layout(
- leftBound, textTopBound, statusRightBound, textTopBound + mStatusTextViewHeight);
- }
- } else {
- int statusLeftBound = leftBound;
- if (isVisible(mPresenceIcon)) {
- int iconWidth = mPresenceIcon.getMeasuredWidth();
- mPresenceIcon.layout(
- leftBound, textTopBound, leftBound + iconWidth, textTopBound + mStatusTextViewHeight);
- statusLeftBound += (iconWidth + mPresenceIconMargin);
- }
-
- if (isVisible(mStatusView)) {
- mStatusView.layout(
- statusLeftBound, textTopBound, rightBound, textTopBound + mStatusTextViewHeight);
- }
- }
-
- if (isVisible(mStatusView) || isVisible(mPresenceIcon)) {
- textTopBound += mStatusTextViewHeight;
- }
-
- // Rest of text views
- int dataLeftBound = leftBound;
-
- // Label and Data align bottom.
- if (isVisible(mLabelView)) {
- if (!isLayoutRtl) {
- mLabelView.layout(
- dataLeftBound,
- textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
- rightBound,
- textTopBound + mLabelAndDataViewMaxHeight);
- dataLeftBound += mLabelView.getMeasuredWidth() + mGapBetweenLabelAndData;
- } else {
- dataLeftBound = leftBound + mLabelView.getMeasuredWidth();
- mLabelView.layout(
- rightBound - mLabelView.getMeasuredWidth(),
- textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
- rightBound,
- textTopBound + mLabelAndDataViewMaxHeight);
- rightBound -= (mLabelView.getMeasuredWidth() + mGapBetweenLabelAndData);
- }
- }
-
- if (isVisible(mDataView)) {
- if (!isLayoutRtl) {
- mDataView.layout(
- dataLeftBound,
- textTopBound + mLabelAndDataViewMaxHeight - mDataViewHeight,
- rightBound,
- textTopBound + mLabelAndDataViewMaxHeight);
- } else {
- mDataView.layout(
- rightBound - mDataView.getMeasuredWidth(),
- textTopBound + mLabelAndDataViewMaxHeight - mDataViewHeight,
- rightBound,
- textTopBound + mLabelAndDataViewMaxHeight);
- }
- }
- if (isVisible(mLabelView) || isVisible(mDataView)) {
- textTopBound += mLabelAndDataViewMaxHeight;
- }
-
- if (isVisible(mSnippetView)) {
- mSnippetView.layout(
- leftBound, textTopBound, rightBound, textTopBound + mSnippetTextViewHeight);
- }
- }
-
- @Override
- public void adjustListItemSelectionBounds(Rect bounds) {
- if (mAdjustSelectionBoundsEnabled) {
- bounds.top += mBoundsWithoutHeader.top;
- bounds.bottom = bounds.top + mBoundsWithoutHeader.height();
- bounds.left = mBoundsWithoutHeader.left;
- bounds.right = mBoundsWithoutHeader.right;
- }
- }
-
- protected boolean isVisible(View view) {
- return view != null && view.getVisibility() == View.VISIBLE;
- }
-
- /** Extracts width and height from the style */
- private void ensurePhotoViewSize() {
- if (!mPhotoViewWidthAndHeightAreReady) {
- mPhotoViewWidth = mPhotoViewHeight = getDefaultPhotoViewSize();
- if (!mQuickContactEnabled && mPhotoView == null) {
- if (!mKeepHorizontalPaddingForPhotoView) {
- mPhotoViewWidth = 0;
- }
- if (!mKeepVerticalPaddingForPhotoView) {
- mPhotoViewHeight = 0;
- }
- }
-
- mPhotoViewWidthAndHeightAreReady = true;
- }
- }
-
- protected int getDefaultPhotoViewSize() {
- return mDefaultPhotoViewSize;
- }
-
- /**
- * Gets a LayoutParam that corresponds to the default photo size.
- *
- * @return A new LayoutParam.
- */
- private LayoutParams getDefaultPhotoLayoutParams() {
- LayoutParams params = generateDefaultLayoutParams();
- params.width = getDefaultPhotoViewSize();
- params.height = params.width;
- return params;
- }
-
- @Override
- protected void drawableStateChanged() {
- super.drawableStateChanged();
- if (mActivatedStateSupported) {
- mActivatedBackgroundDrawable.setState(getDrawableState());
- }
- }
-
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return who == mActivatedBackgroundDrawable || super.verifyDrawable(who);
- }
-
- @Override
- public void jumpDrawablesToCurrentState() {
- super.jumpDrawablesToCurrentState();
- if (mActivatedStateSupported) {
- mActivatedBackgroundDrawable.jumpToCurrentState();
- }
- }
-
- @Override
- public void dispatchDraw(Canvas canvas) {
- if (mActivatedStateSupported && isActivated()) {
- mActivatedBackgroundDrawable.draw(canvas);
- }
-
- super.dispatchDraw(canvas);
- }
-
- /** Sets section header or makes it invisible if the title is null. */
- public void setSectionHeader(String title) {
- if (!TextUtils.isEmpty(title)) {
- if (mHeaderTextView == null) {
- mHeaderTextView = new TextView(getContext());
- mHeaderTextView.setTextAppearance(R.style.SectionHeaderStyle);
- mHeaderTextView.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
- addView(mHeaderTextView);
- }
- setMarqueeText(mHeaderTextView, title);
- mHeaderTextView.setVisibility(View.VISIBLE);
- mHeaderTextView.setAllCaps(true);
- } else if (mHeaderTextView != null) {
- mHeaderTextView.setVisibility(View.GONE);
- }
- }
-
- public void setIsSectionHeaderEnabled(boolean isSectionHeaderEnabled) {
- mIsSectionHeaderEnabled = isSectionHeaderEnabled;
- }
-
- /** Returns the quick contact badge, creating it if necessary. */
- public QuickContactBadge getQuickContact() {
- if (!mQuickContactEnabled) {
- throw new IllegalStateException("QuickContact is disabled for this view");
- }
- if (mQuickContact == null) {
- mQuickContact = new QuickContactBadge(getContext());
- mQuickContact.setOverlay(null);
- mQuickContact.setLayoutParams(getDefaultPhotoLayoutParams());
- if (mNameTextView != null) {
- mQuickContact.setContentDescription(
- getContext()
- .getString(R.string.description_quick_contact_for, mNameTextView.getText()));
- }
-
- addView(mQuickContact);
- mPhotoViewWidthAndHeightAreReady = false;
- }
- return mQuickContact;
- }
-
- /** Returns the photo view, creating it if necessary. */
- public ImageView getPhotoView() {
- if (mPhotoView == null) {
- mPhotoView = new ImageView(getContext());
- mPhotoView.setLayoutParams(getDefaultPhotoLayoutParams());
- // Quick contact style used above will set a background - remove it
- mPhotoView.setBackground(null);
- addView(mPhotoView);
- mPhotoViewWidthAndHeightAreReady = false;
- }
- return mPhotoView;
- }
-
- /** Removes the photo view. */
- public void removePhotoView() {
- removePhotoView(false, true);
- }
-
- /**
- * Removes the photo view.
- *
- * @param keepHorizontalPadding True means data on the right side will have padding on left,
- * pretending there is still a photo view.
- * @param keepVerticalPadding True means the View will have some height enough for accommodating a
- * photo view.
- */
- public void removePhotoView(boolean keepHorizontalPadding, boolean keepVerticalPadding) {
- mPhotoViewWidthAndHeightAreReady = false;
- mKeepHorizontalPaddingForPhotoView = keepHorizontalPadding;
- mKeepVerticalPaddingForPhotoView = keepVerticalPadding;
- if (mPhotoView != null) {
- removeView(mPhotoView);
- mPhotoView = null;
- }
- if (mQuickContact != null) {
- removeView(mQuickContact);
- mQuickContact = null;
- }
- }
-
- /**
- * Sets a word prefix that will be highlighted if encountered in fields like name and search
- * snippet. This will disable the mask highlighting for names.
- *
- * <p>NOTE: must be all upper-case
- */
- public void setHighlightedPrefix(String upperCasePrefix) {
- mHighlightedPrefix = upperCasePrefix;
- }
-
- /** Clears previously set highlight sequences for the view. */
- public void clearHighlightSequences() {
- mNameHighlightSequence.clear();
- mNumberHighlightSequence.clear();
- mHighlightedPrefix = null;
- }
-
- /**
- * Adds a highlight sequence to the name highlighter.
- *
- * @param start The start position of the highlight sequence.
- * @param end The end position of the highlight sequence.
- */
- public void addNameHighlightSequence(int start, int end) {
- mNameHighlightSequence.add(new HighlightSequence(start, end));
- }
-
- /**
- * Adds a highlight sequence to the number highlighter.
- *
- * @param start The start position of the highlight sequence.
- * @param end The end position of the highlight sequence.
- */
- public void addNumberHighlightSequence(int start, int end) {
- mNumberHighlightSequence.add(new HighlightSequence(start, end));
- }
-
- /** Returns the text view for the contact name, creating it if necessary. */
- public TextView getNameTextView() {
- if (mNameTextView == null) {
- mNameTextView = new TextView(getContext());
- mNameTextView.setSingleLine(true);
- mNameTextView.setEllipsize(getTextEllipsis());
- mNameTextView.setTextColor(mNameTextViewTextColor);
- mNameTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mNameTextViewTextSize);
- // Manually call setActivated() since this view may be added after the first
- // setActivated() call toward this whole item view.
- mNameTextView.setActivated(isActivated());
- mNameTextView.setGravity(Gravity.CENTER_VERTICAL);
- mNameTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
- mNameTextView.setId(R.id.cliv_name_textview);
- mNameTextView.setElegantTextHeight(false);
- addView(mNameTextView);
- }
- return mNameTextView;
- }
-
- /** Adds or updates a text view for the data label. */
- public void setLabel(CharSequence text) {
- if (TextUtils.isEmpty(text)) {
- if (mLabelView != null) {
- mLabelView.setVisibility(View.GONE);
- }
- } else {
- getLabelView();
- setMarqueeText(mLabelView, text);
- mLabelView.setVisibility(VISIBLE);
- }
- }
-
- /** Returns the text view for the data label, creating it if necessary. */
- public TextView getLabelView() {
- if (mLabelView == null) {
- mLabelView = new TextView(getContext());
- mLabelView.setLayoutParams(
- new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
-
- mLabelView.setSingleLine(true);
- mLabelView.setEllipsize(getTextEllipsis());
- mLabelView.setTextAppearance(R.style.TextAppearanceSmall);
- if (mPhotoPosition == PhotoPosition.LEFT) {
- mLabelView.setAllCaps(true);
- } else {
- mLabelView.setTypeface(mLabelView.getTypeface(), Typeface.BOLD);
- }
- mLabelView.setActivated(isActivated());
- mLabelView.setId(R.id.cliv_label_textview);
- addView(mLabelView);
- }
- return mLabelView;
- }
-
- /**
- * Sets phone number for a list item. This takes care of number highlighting if the highlight mask
- * exists.
- */
- public void setPhoneNumber(String text) {
- mPhoneNumber = text;
- if (text == null) {
- if (mDataView != null) {
- mDataView.setVisibility(View.GONE);
- }
- } else {
- getDataView();
-
- // TODO: Format number using PhoneNumberUtils.formatNumber before assigning it to
- // mDataView. Make sure that determination of the highlight sequences are done only
- // after number formatting.
-
- // Sets phone number texts for display after highlighting it, if applicable.
- // CharSequence textToSet = text;
- final SpannableString textToSet = new SpannableString(text);
-
- if (mNumberHighlightSequence.size() != 0) {
- final HighlightSequence highlightSequence = mNumberHighlightSequence.get(0);
- mTextHighlighter.applyMaskingHighlight(
- textToSet, highlightSequence.start, highlightSequence.end);
- }
-
- setMarqueeText(mDataView, textToSet);
- mDataView.setVisibility(VISIBLE);
-
- // We have a phone number as "mDataView" so make it always LTR and VIEW_START
- mDataView.setTextDirection(View.TEXT_DIRECTION_LTR);
- mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
- }
- }
-
- public String getPhoneNumber() {
- return mPhoneNumber;
- }
-
- private void setMarqueeText(TextView textView, CharSequence text) {
- if (getTextEllipsis() == TruncateAt.MARQUEE) {
- // To show MARQUEE correctly (with END effect during non-active state), we need
- // to build Spanned with MARQUEE in addition to TextView's ellipsize setting.
- final SpannableString spannable = new SpannableString(text);
- spannable.setSpan(
- TruncateAt.MARQUEE, 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- textView.setText(spannable);
- } else {
- textView.setText(text);
- }
- }
-
- /** Returns the text view for the data text, creating it if necessary. */
- public TextView getDataView() {
- if (mDataView == null) {
- mDataView = new TextView(getContext());
- mDataView.setSingleLine(true);
- mDataView.setEllipsize(getTextEllipsis());
- mDataView.setTextAppearance(R.style.TextAppearanceSmall);
- mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
- mDataView.setActivated(isActivated());
- mDataView.setId(R.id.cliv_data_view);
- mDataView.setElegantTextHeight(false);
- addView(mDataView);
- }
- return mDataView;
- }
-
- /** Adds or updates a text view for the search snippet. */
- public void setSnippet(String text) {
- if (TextUtils.isEmpty(text)) {
- if (mSnippetView != null) {
- mSnippetView.setVisibility(View.GONE);
- }
- } else {
- mTextHighlighter.setPrefixText(getSnippetView(), text, mHighlightedPrefix);
- mSnippetView.setVisibility(VISIBLE);
- if (ContactDisplayUtils.isPossiblePhoneNumber(text)) {
- // Give the text-to-speech engine a hint that it's a phone number
- mSnippetView.setContentDescription(PhoneNumberUtils.createTtsSpannable(text));
- } else {
- mSnippetView.setContentDescription(null);
- }
- }
- }
-
- /** Returns the text view for the search snippet, creating it if necessary. */
- public TextView getSnippetView() {
- if (mSnippetView == null) {
- mSnippetView = new TextView(getContext());
- mSnippetView.setSingleLine(true);
- mSnippetView.setEllipsize(getTextEllipsis());
- mSnippetView.setTextAppearance(android.R.style.TextAppearance_Small);
- mSnippetView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
- mSnippetView.setActivated(isActivated());
- addView(mSnippetView);
- }
- return mSnippetView;
- }
-
- /** Returns the text view for the status, creating it if necessary. */
- public TextView getStatusView() {
- if (mStatusView == null) {
- mStatusView = new TextView(getContext());
- mStatusView.setSingleLine(true);
- mStatusView.setEllipsize(getTextEllipsis());
- mStatusView.setTextAppearance(android.R.style.TextAppearance_Small);
- mStatusView.setTextColor(mSecondaryTextColor);
- mStatusView.setActivated(isActivated());
- mStatusView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
- addView(mStatusView);
- }
- return mStatusView;
- }
-
- /** Adds or updates a text view for the status. */
- public void setStatus(CharSequence text) {
- if (TextUtils.isEmpty(text)) {
- if (mStatusView != null) {
- mStatusView.setVisibility(View.GONE);
- }
- } else {
- getStatusView();
- setMarqueeText(mStatusView, text);
- mStatusView.setVisibility(VISIBLE);
- }
- }
-
- /** Adds or updates the presence icon view. */
- public void setPresence(Drawable icon) {
- if (icon != null) {
- if (mPresenceIcon == null) {
- mPresenceIcon = new ImageView(getContext());
- addView(mPresenceIcon);
- }
- mPresenceIcon.setImageDrawable(icon);
- mPresenceIcon.setScaleType(ScaleType.CENTER);
- mPresenceIcon.setVisibility(View.VISIBLE);
- } else {
- if (mPresenceIcon != null) {
- mPresenceIcon.setVisibility(View.GONE);
- }
- }
- }
-
- /**
- * Set to display work profile icon or not
- *
- * @param enabled set to display work profile icon or not
- */
- public void setWorkProfileIconEnabled(boolean enabled) {
- if (mWorkProfileIcon != null) {
- mWorkProfileIcon.setVisibility(enabled ? View.VISIBLE : View.GONE);
- } else if (enabled) {
- mWorkProfileIcon = new ImageView(getContext());
- addView(mWorkProfileIcon);
- mWorkProfileIcon.setImageResource(R.drawable.ic_work_profile);
- mWorkProfileIcon.setScaleType(ScaleType.CENTER_INSIDE);
- mWorkProfileIcon.setVisibility(View.VISIBLE);
- }
- }
-
- private TruncateAt getTextEllipsis() {
- return TruncateAt.MARQUEE;
- }
-
- public void showDisplayName(Cursor cursor, int nameColumnIndex) {
- CharSequence name = cursor.getString(nameColumnIndex);
- setDisplayName(name);
-
- // Since the quick contact content description is derived from the display name and there is
- // no guarantee that when the quick contact is initialized the display name is already set,
- // do it here too.
- if (mQuickContact != null) {
- mQuickContact.setContentDescription(
- getContext().getString(R.string.description_quick_contact_for, mNameTextView.getText()));
- }
- }
-
- public void setDisplayName(CharSequence name) {
- if (!TextUtils.isEmpty(name)) {
- // Chooses the available highlighting method for highlighting.
- if (mHighlightedPrefix != null) {
- name = mTextHighlighter.applyPrefixHighlight(name, mHighlightedPrefix);
- } else if (mNameHighlightSequence.size() != 0) {
- final SpannableString spannableName = new SpannableString(name);
- for (HighlightSequence highlightSequence : mNameHighlightSequence) {
- mTextHighlighter.applyMaskingHighlight(
- spannableName, highlightSequence.start, highlightSequence.end);
- }
- name = spannableName;
- }
- } else {
- name = mUnknownNameText;
- }
- setMarqueeText(getNameTextView(), name);
-
- if (ContactDisplayUtils.isPossiblePhoneNumber(name)) {
- // Give the text-to-speech engine a hint that it's a phone number
- mNameTextView.setTextDirection(View.TEXT_DIRECTION_LTR);
- mNameTextView.setContentDescription(PhoneNumberUtils.createTtsSpannable(name.toString()));
- } else {
- // Remove span tags of highlighting for talkback to avoid reading highlighting and rest
- // of the name into two separate parts.
- mNameTextView.setContentDescription(name.toString());
- }
- }
-
- public void hideDisplayName() {
- if (mNameTextView != null) {
- removeView(mNameTextView);
- mNameTextView = null;
- }
- }
-
- /** Sets the proper icon (star or presence or nothing) and/or status message. */
- public void showPresenceAndStatusMessage(
- Cursor cursor, int presenceColumnIndex, int contactStatusColumnIndex) {
- Drawable icon = null;
- int presence = 0;
- if (!cursor.isNull(presenceColumnIndex)) {
- presence = cursor.getInt(presenceColumnIndex);
- icon = ContactPresenceIconUtil.getPresenceIcon(getContext(), presence);
- }
- setPresence(icon);
-
- String statusMessage = null;
- if (contactStatusColumnIndex != 0 && !cursor.isNull(contactStatusColumnIndex)) {
- statusMessage = cursor.getString(contactStatusColumnIndex);
- }
- // If there is no status message from the contact, but there was a presence value, then use
- // the default status message string
- if (statusMessage == null && presence != 0) {
- statusMessage = ContactStatusUtil.getStatusString(getContext(), presence);
- }
- setStatus(statusMessage);
- }
-
- /** Shows search snippet. */
- public void showSnippet(Cursor cursor, int summarySnippetColumnIndex) {
- if (cursor.getColumnCount() <= summarySnippetColumnIndex
- || !SearchSnippets.SNIPPET.equals(cursor.getColumnName(summarySnippetColumnIndex))) {
- setSnippet(null);
- return;
- }
-
- String snippet = cursor.getString(summarySnippetColumnIndex);
-
- // Do client side snippeting if provider didn't do it
- final Bundle extras = cursor.getExtras();
- if (extras.getBoolean(ContactsContract.DEFERRED_SNIPPETING)) {
-
- final String query = extras.getString(ContactsContract.DEFERRED_SNIPPETING_QUERY);
-
- String displayName = null;
- int displayNameIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
- if (displayNameIndex >= 0) {
- displayName = cursor.getString(displayNameIndex);
- }
-
- snippet = updateSnippet(snippet, query, displayName);
-
- } else {
- if (snippet != null) {
- int from = 0;
- int to = snippet.length();
- int start = snippet.indexOf(SNIPPET_START_MATCH);
- if (start == -1) {
- snippet = null;
- } else {
- int firstNl = snippet.lastIndexOf('\n', start);
- if (firstNl != -1) {
- from = firstNl + 1;
- }
- int end = snippet.lastIndexOf(SNIPPET_END_MATCH);
- if (end != -1) {
- int lastNl = snippet.indexOf('\n', end);
- if (lastNl != -1) {
- to = lastNl;
- }
- }
-
- StringBuilder sb = new StringBuilder();
- for (int i = from; i < to; i++) {
- char c = snippet.charAt(i);
- if (c != SNIPPET_START_MATCH && c != SNIPPET_END_MATCH) {
- sb.append(c);
- }
- }
- snippet = sb.toString();
- }
- }
- }
-
- setSnippet(snippet);
- }
-
- /**
- * Used for deferred snippets from the database. The contents come back as large strings which
- * need to be extracted for display.
- *
- * @param snippet The snippet from the database.
- * @param query The search query substring.
- * @param displayName The contact display name.
- * @return The proper snippet to display.
- */
- private String updateSnippet(String snippet, String query, String displayName) {
-
- if (TextUtils.isEmpty(snippet) || TextUtils.isEmpty(query)) {
- return null;
- }
- query = SearchUtil.cleanStartAndEndOfSearchQuery(query.toLowerCase());
-
- // If the display name already contains the query term, return empty - snippets should
- // not be needed in that case.
- if (!TextUtils.isEmpty(displayName)) {
- final String lowerDisplayName = displayName.toLowerCase();
- final List<String> nameTokens = split(lowerDisplayName);
- for (String nameToken : nameTokens) {
- if (nameToken.startsWith(query)) {
- return null;
- }
- }
- }
-
- // The snippet may contain multiple data lines.
- // Show the first line that matches the query.
- final SearchUtil.MatchedLine matched = SearchUtil.findMatchingLine(snippet, query);
-
- if (matched != null && matched.line != null) {
- // Tokenize for long strings since the match may be at the end of it.
- // Skip this part for short strings since the whole string will be displayed.
- // Most contact strings are short so the snippetize method will be called infrequently.
- final int lengthThreshold =
- getResources().getInteger(R.integer.snippet_length_before_tokenize);
- if (matched.line.length() > lengthThreshold) {
- return snippetize(matched.line, matched.startIndex, lengthThreshold);
- } else {
- return matched.line;
- }
- }
-
- // No match found.
- return null;
- }
-
- private String snippetize(String line, int matchIndex, int maxLength) {
- // Show up to maxLength characters. But we only show full tokens so show the last full token
- // up to maxLength characters. So as many starting tokens as possible before trying ending
- // tokens.
- int remainingLength = maxLength;
- int tempRemainingLength = remainingLength;
-
- // Start the end token after the matched query.
- int index = matchIndex;
- int endTokenIndex = index;
-
- // Find the match token first.
- while (index < line.length()) {
- if (!Character.isLetterOrDigit(line.charAt(index))) {
- endTokenIndex = index;
- remainingLength = tempRemainingLength;
- break;
- }
- tempRemainingLength--;
- index++;
- }
-
- // Find as much content before the match.
- index = matchIndex - 1;
- tempRemainingLength = remainingLength;
- int startTokenIndex = matchIndex;
- while (index > -1 && tempRemainingLength > 0) {
- if (!Character.isLetterOrDigit(line.charAt(index))) {
- startTokenIndex = index;
- remainingLength = tempRemainingLength;
- }
- tempRemainingLength--;
- index--;
- }
-
- index = endTokenIndex;
- tempRemainingLength = remainingLength;
- // Find remaining content at after match.
- while (index < line.length() && tempRemainingLength > 0) {
- if (!Character.isLetterOrDigit(line.charAt(index))) {
- endTokenIndex = index;
- }
- tempRemainingLength--;
- index++;
- }
- // Append ellipse if there is content before or after.
- final StringBuilder sb = new StringBuilder();
- if (startTokenIndex > 0) {
- sb.append("...");
- }
- sb.append(line.substring(startTokenIndex, endTokenIndex));
- if (endTokenIndex < line.length()) {
- sb.append("...");
- }
- return sb.toString();
- }
-
- public void setActivatedStateSupported(boolean flag) {
- this.mActivatedStateSupported = flag;
- }
-
- public void setAdjustSelectionBoundsEnabled(boolean enabled) {
- mAdjustSelectionBoundsEnabled = enabled;
- }
-
- @Override
- public void requestLayout() {
- // We will assume that once measured this will not need to resize
- // itself, so there is no need to pass the layout request to the parent
- // view (ListView).
- forceLayout();
- }
-
- /**
- * Set drawable resources directly for the drawable resource of the photo view.
- *
- * @param drawable A drawable resource.
- */
- public void setDrawable(Drawable drawable) {
- ImageView photo = getPhotoView();
- photo.setScaleType(ImageView.ScaleType.CENTER);
- int iconColor = ContextCompat.getColor(getContext(), R.color.search_shortcut_icon_color);
- photo.setImageDrawable(drawable);
- photo.setImageTintList(ColorStateList.valueOf(iconColor));
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- final float x = event.getX();
- final float y = event.getY();
- // If the touch event's coordinates are not within the view's header, then delegate
- // to super.onTouchEvent so that regular view behavior is preserved. Otherwise, consume
- // and ignore the touch event.
- if (mBoundsWithoutHeader.contains((int) x, (int) y) || !pointIsInView(x, y)) {
- return super.onTouchEvent(event);
- } else {
- return true;
- }
- }
-
- private boolean pointIsInView(float localX, float localY) {
- return localX >= mLeftOffset
- && localX < mRightOffset
- && localY >= 0
- && localY < (getBottom() - getTop());
- }
-
- /**
- * Where to put contact photo. This affects the other Views' layout or look-and-feel.
- *
- * <p>TODO: replace enum with int constants
- */
- public enum PhotoPosition {
- LEFT,
- RIGHT
- }
-
- protected static class HighlightSequence {
-
- private final int start;
- private final int end;
-
- HighlightSequence(int start, int end) {
- this.start = start;
- this.end = end;
- }
- }
-}
diff --git a/java/com/android/contacts/common/list/ContactListPinnedHeaderView.java b/java/com/android/contacts/common/list/ContactListPinnedHeaderView.java
deleted file mode 100644
index 1f3e2bfe3..000000000
--- a/java/com/android/contacts/common/list/ContactListPinnedHeaderView.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.LinearLayout.LayoutParams;
-import android.widget.TextView;
-import com.android.contacts.common.R;
-
-/** A custom view for the pinned section header shown at the top of the contact list. */
-public class ContactListPinnedHeaderView extends TextView {
-
- public ContactListPinnedHeaderView(Context context, AttributeSet attrs, View parent) {
- super(context, attrs);
-
- if (R.styleable.ContactListItemView == null) {
- return;
- }
- TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ContactListItemView);
- int backgroundColor =
- a.getColor(R.styleable.ContactListItemView_list_item_background_color, Color.WHITE);
- int textOffsetTop =
- a.getDimensionPixelSize(R.styleable.ContactListItemView_list_item_text_offset_top, 0);
- int paddingStartOffset =
- a.getDimensionPixelSize(R.styleable.ContactListItemView_list_item_padding_left, 0);
- int textWidth = getResources().getDimensionPixelSize(R.dimen.contact_list_section_header_width);
- int widthIncludingPadding = paddingStartOffset + textWidth;
- a.recycle();
-
- setBackgroundColor(backgroundColor);
- setTextAppearance(getContext(), R.style.SectionHeaderStyle);
- setLayoutParams(new LayoutParams(textWidth, LayoutParams.WRAP_CONTENT));
- setLayoutDirection(parent.getLayoutDirection());
- setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
-
- // Apply text top offset. Multiply by two, because we are implementing this by padding for a
- // vertically centered view, rather than adjusting the position directly via a layout.
- setPaddingRelative(
- 0, getPaddingTop() + (textOffsetTop * 2), getPaddingEnd(), getPaddingBottom());
- }
-
- /** Sets section header or makes it invisible if the title is null. */
- public void setSectionHeaderTitle(String title) {
- if (!TextUtils.isEmpty(title)) {
- setText(title);
- } else {
- setVisibility(View.GONE);
- }
- }
-}
diff --git a/java/com/android/contacts/common/list/ContactsSectionIndexer.java b/java/com/android/contacts/common/list/ContactsSectionIndexer.java
deleted file mode 100644
index 3f0f2b7ee..000000000
--- a/java/com/android/contacts/common/list/ContactsSectionIndexer.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.text.TextUtils;
-import android.widget.SectionIndexer;
-import java.util.Arrays;
-
-/**
- * A section indexer that is configured with precomputed section titles and their respective counts.
- */
-public class ContactsSectionIndexer implements SectionIndexer {
-
- private static final String BLANK_HEADER_STRING = " ";
- private String[] mSections;
- private int[] mPositions;
- private int mCount;
-
- /**
- * Constructor.
- *
- * @param sections a non-null array
- * @param counts a non-null array of the same size as <code>sections</code>
- */
- public ContactsSectionIndexer(String[] sections, int[] counts) {
- if (sections == null || counts == null) {
- throw new NullPointerException();
- }
-
- if (sections.length != counts.length) {
- throw new IllegalArgumentException(
- "The sections and counts arrays must have the same length");
- }
-
- // TODO process sections/counts based on current locale and/or specific section titles
-
- this.mSections = sections;
- mPositions = new int[counts.length];
- int position = 0;
- for (int i = 0; i < counts.length; i++) {
- if (TextUtils.isEmpty(mSections[i])) {
- mSections[i] = BLANK_HEADER_STRING;
- } else if (!mSections[i].equals(BLANK_HEADER_STRING)) {
- mSections[i] = mSections[i].trim();
- }
-
- mPositions[i] = position;
- position += counts[i];
- }
- mCount = position;
- }
-
- public Object[] getSections() {
- return mSections;
- }
-
- public int getPositionForSection(int section) {
- if (section < 0 || section >= mSections.length) {
- return -1;
- }
-
- return mPositions[section];
- }
-
- public int getSectionForPosition(int position) {
- if (position < 0 || position >= mCount) {
- return -1;
- }
-
- int index = Arrays.binarySearch(mPositions, position);
-
- /*
- * Consider this example: section positions are 0, 3, 5; the supplied
- * position is 4. The section corresponding to position 4 starts at
- * position 3, so the expected return value is 1. Binary search will not
- * find 4 in the array and thus will return -insertPosition-1, i.e. -3.
- * To get from that number to the expected value of 1 we need to negate
- * and subtract 2.
- */
- return index >= 0 ? index : -index - 2;
- }
-
- public void setProfileAndFavoritesHeader(String header, int numberOfItemsToAdd) {
- 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] + numberOfItemsToAdd;
- }
- mSections = tempSections;
- mPositions = tempPositions;
- mCount = mCount + numberOfItemsToAdd;
- }
- }
-}
diff --git a/java/com/android/contacts/common/list/DefaultContactListAdapter.java b/java/com/android/contacts/common/list/DefaultContactListAdapter.java
deleted file mode 100644
index 7bcae0e0e..000000000
--- a/java/com/android/contacts/common/list/DefaultContactListAdapter.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.Context;
-import android.content.CursorLoader;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.net.Uri;
-import android.net.Uri.Builder;
-import android.preference.PreferenceManager;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Directory;
-import android.provider.ContactsContract.SearchSnippets;
-import android.text.TextUtils;
-import android.view.View;
-import com.android.contacts.common.compat.ContactsCompat;
-import com.android.contacts.common.preference.ContactsPreferences;
-import java.util.ArrayList;
-import java.util.List;
-
-/** A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type. */
-public class DefaultContactListAdapter extends ContactListAdapter {
-
- public DefaultContactListAdapter(Context context) {
- super(context);
- }
-
- @Override
- public void configureLoader(CursorLoader loader, long directoryId) {
- String sortOrder = null;
- if (isSearchMode()) {
- String query = getQueryString();
- if (query == null) {
- query = "";
- }
- query = query.trim();
- if (TextUtils.isEmpty(query)) {
- // Regardless of the directory, we don't want anything returned,
- // so let's just send a "nothing" query to the local directory.
- loader.setUri(Contacts.CONTENT_URI);
- loader.setProjection(getProjection(false));
- loader.setSelection("0");
- } else {
- final Builder builder = ContactsCompat.getContentUri().buildUpon();
- appendSearchParameters(builder, query, directoryId);
- loader.setUri(builder.build());
- loader.setProjection(getProjection(true));
- }
- } else {
- final ContactListFilter filter = getFilter();
- configureUri(loader, directoryId, filter);
- loader.setProjection(getProjection(false));
- configureSelection(loader, directoryId, filter);
- }
-
- if (getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY) {
- if (sortOrder == null) {
- sortOrder = Contacts.SORT_KEY_PRIMARY;
- } else {
- sortOrder += ", " + Contacts.SORT_KEY_PRIMARY;
- }
- } else {
- if (sortOrder == null) {
- sortOrder = Contacts.SORT_KEY_ALTERNATIVE;
- } else {
- sortOrder += ", " + Contacts.SORT_KEY_ALTERNATIVE;
- }
- }
- loader.setSortOrder(sortOrder);
- }
-
- private void appendSearchParameters(Builder builder, String query, long directoryId) {
- builder.appendPath(query); // Builder will encode the query
- builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId));
- if (directoryId != Directory.DEFAULT && directoryId != Directory.LOCAL_INVISIBLE) {
- builder.appendQueryParameter(
- ContactsContract.LIMIT_PARAM_KEY,
- String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
- }
- builder.appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY, "1");
- }
-
- protected void configureUri(CursorLoader loader, long directoryId, ContactListFilter filter) {
- Uri uri = Contacts.CONTENT_URI;
-
- if (directoryId == Directory.DEFAULT && isSectionHeaderDisplayEnabled()) {
- uri = ContactListAdapter.buildSectionIndexerUri(uri);
- }
-
- // The "All accounts" filter is the same as the entire contents of Directory.DEFAULT
- if (filter != null
- && filter.filterType != ContactListFilter.FILTER_TYPE_CUSTOM
- && filter.filterType != ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
- final Uri.Builder builder = uri.buildUpon();
- builder.appendQueryParameter(
- ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT));
- if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT) {
- filter.addAccountQueryParameterToUrl(builder);
- }
- uri = builder.build();
- }
-
- loader.setUri(uri);
- }
-
- private void configureSelection(CursorLoader loader, long directoryId, ContactListFilter filter) {
- if (filter == null) {
- return;
- }
-
- if (directoryId != Directory.DEFAULT) {
- return;
- }
-
- StringBuilder selection = new StringBuilder();
- List<String> selectionArgs = new ArrayList<String>();
-
- switch (filter.filterType) {
- case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS:
- {
- // We have already added directory=0 to the URI, which takes care of this
- // filter
- break;
- }
- case ContactListFilter.FILTER_TYPE_SINGLE_CONTACT:
- {
- // We have already added the lookup key to the URI, which takes care of this
- // filter
- break;
- }
- case ContactListFilter.FILTER_TYPE_STARRED:
- {
- selection.append(Contacts.STARRED + "!=0");
- break;
- }
- case ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY:
- {
- selection.append(Contacts.HAS_PHONE_NUMBER + "=1");
- break;
- }
- case ContactListFilter.FILTER_TYPE_CUSTOM:
- {
- selection.append(Contacts.IN_VISIBLE_GROUP + "=1");
- if (isCustomFilterForPhoneNumbersOnly()) {
- selection.append(" AND " + Contacts.HAS_PHONE_NUMBER + "=1");
- }
- break;
- }
- case ContactListFilter.FILTER_TYPE_ACCOUNT:
- {
- // We use query parameters for account filter, so no selection to add here.
- break;
- }
- }
- loader.setSelection(selection.toString());
- loader.setSelectionArgs(selectionArgs.toArray(new String[0]));
- }
-
- @Override
- protected void bindView(View itemView, int partition, Cursor cursor, int position) {
- super.bindView(itemView, partition, cursor, position);
- final ContactListItemView view = (ContactListItemView) itemView;
-
- view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);
-
- bindSectionHeaderAndDivider(view, position, cursor);
-
- if (isQuickContactEnabled()) {
- bindQuickContact(
- view,
- partition,
- cursor,
- ContactQuery.CONTACT_PHOTO_ID,
- ContactQuery.CONTACT_PHOTO_URI,
- ContactQuery.CONTACT_ID,
- ContactQuery.CONTACT_LOOKUP_KEY,
- ContactQuery.CONTACT_DISPLAY_NAME);
- } else {
- if (getDisplayPhotos()) {
- bindPhoto(view, partition, cursor);
- }
- }
-
- bindNameAndViewId(view, cursor);
- bindPresenceAndStatusMessage(view, cursor);
-
- if (isSearchMode()) {
- bindSearchSnippet(view, cursor);
- } else {
- view.setSnippet(null);
- }
- }
-
- private boolean isCustomFilterForPhoneNumbersOnly() {
- // TODO: this flag should not be stored in shared prefs. It needs to be in the db.
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
- return prefs.getBoolean(
- ContactsPreferences.PREF_DISPLAY_ONLY_PHONES,
- ContactsPreferences.PREF_DISPLAY_ONLY_PHONES_DEFAULT);
- }
-}
diff --git a/java/com/android/contacts/common/list/DirectoryListLoader.java b/java/com/android/contacts/common/list/DirectoryListLoader.java
deleted file mode 100644
index ce78d2cff..000000000
--- a/java/com/android/contacts/common/list/DirectoryListLoader.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.AsyncTaskLoader;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.net.Uri;
-import android.os.Handler;
-import android.provider.ContactsContract.Directory;
-import android.text.TextUtils;
-import com.android.contacts.common.R;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.cp2.DirectoryCompat;
-import com.android.dialer.util.PermissionsUtil;
-
-/** A specialized loader for the list of directories, see {@link Directory}. */
-public class DirectoryListLoader extends AsyncTaskLoader<Cursor> {
-
- public static final int SEARCH_MODE_NONE = 0;
- public static final int SEARCH_MODE_DEFAULT = 1;
- public static final int SEARCH_MODE_CONTACT_SHORTCUT = 2;
- public static final int SEARCH_MODE_DATA_SHORTCUT = 3;
- // This is a virtual column created for a MatrixCursor.
- public static final String DIRECTORY_TYPE = "directoryType";
- private static final String[] RESULT_PROJECTION = {
- Directory._ID, DIRECTORY_TYPE, Directory.DISPLAY_NAME, Directory.PHOTO_SUPPORT,
- };
- private final ContentObserver mObserver =
- new ContentObserver(new Handler()) {
- @Override
- public void onChange(boolean selfChange) {
- forceLoad();
- }
- };
- private int mDirectorySearchMode;
- private boolean mLocalInvisibleDirectoryEnabled;
- private MatrixCursor mDefaultDirectoryList;
-
- public DirectoryListLoader(Context context) {
- super(context);
- }
-
- public void setDirectorySearchMode(int mode) {
- mDirectorySearchMode = mode;
- }
-
- /**
- * A flag that indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should be
- * included in the results.
- */
- public void setLocalInvisibleDirectoryEnabled(boolean flag) {
- this.mLocalInvisibleDirectoryEnabled = flag;
- }
-
- @Override
- protected void onStartLoading() {
- if (PermissionsUtil.hasContactsReadPermissions(getContext())) {
- getContext()
- .getContentResolver()
- .registerContentObserver(DirectoryQuery.URI, false, mObserver);
- } else {
- LogUtil.w("DirectoryListLoader.onStartLoading", "contacts permission not available.");
- }
- forceLoad();
- }
-
- @Override
- protected void onStopLoading() {
- getContext().getContentResolver().unregisterContentObserver(mObserver);
- }
-
- @Override
- public Cursor loadInBackground() {
- if (mDirectorySearchMode == SEARCH_MODE_NONE) {
- return getDefaultDirectories();
- }
-
- MatrixCursor result = new MatrixCursor(RESULT_PROJECTION);
- Context context = getContext();
- PackageManager pm = context.getPackageManager();
- String selection;
- switch (mDirectorySearchMode) {
- case SEARCH_MODE_DEFAULT:
- selection = null;
- break;
-
- case SEARCH_MODE_CONTACT_SHORTCUT:
- selection = Directory.SHORTCUT_SUPPORT + "=" + Directory.SHORTCUT_SUPPORT_FULL;
- break;
-
- case SEARCH_MODE_DATA_SHORTCUT:
- selection =
- Directory.SHORTCUT_SUPPORT
- + " IN ("
- + Directory.SHORTCUT_SUPPORT_FULL
- + ", "
- + Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY
- + ")";
- break;
-
- default:
- throw new RuntimeException("Unsupported directory search mode: " + mDirectorySearchMode);
- }
- Cursor cursor = null;
- try {
- cursor =
- context
- .getContentResolver()
- .query(
- DirectoryQuery.URI,
- DirectoryQuery.PROJECTION,
- selection,
- null,
- DirectoryQuery.ORDER_BY);
-
- if (cursor == null) {
- return result;
- }
-
- while (cursor.moveToNext()) {
- long directoryId = cursor.getLong(DirectoryQuery.ID);
- if (!mLocalInvisibleDirectoryEnabled && DirectoryCompat.isInvisibleDirectory(directoryId)) {
- continue;
- }
- String directoryType = null;
-
- String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
- int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
- if (!TextUtils.isEmpty(packageName) && typeResourceId != 0) {
- try {
- directoryType = pm.getResourcesForApplication(packageName).getString(typeResourceId);
- } catch (Exception e) {
- LogUtil.e(
- "ContactEntryListAdapter.loadInBackground",
- "cannot obtain directory type from package: " + packageName);
- }
- }
- String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
- int photoSupport = cursor.getInt(DirectoryQuery.PHOTO_SUPPORT);
- result.addRow(new Object[] {directoryId, directoryType, displayName, photoSupport});
- }
- } catch (RuntimeException e) {
- LogUtil.w(
- "ContactEntryListAdapter.loadInBackground", "runtime exception when querying directory");
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
-
- return result;
- }
-
- private Cursor getDefaultDirectories() {
- if (mDefaultDirectoryList == null) {
- mDefaultDirectoryList = new MatrixCursor(RESULT_PROJECTION);
- mDefaultDirectoryList.addRow(
- new Object[] {Directory.DEFAULT, getContext().getString(R.string.contactsList), null});
- mDefaultDirectoryList.addRow(
- new Object[] {
- Directory.LOCAL_INVISIBLE,
- getContext().getString(R.string.local_invisible_directory),
- null
- });
- }
- return mDefaultDirectoryList;
- }
-
- @Override
- protected void onReset() {
- stopLoading();
- }
-
- private static final class DirectoryQuery {
-
- public static final Uri URI = DirectoryCompat.getContentUri();
- public static final String ORDER_BY = Directory._ID;
-
- public static final String[] PROJECTION = {
- Directory._ID,
- Directory.PACKAGE_NAME,
- Directory.TYPE_RESOURCE_ID,
- Directory.DISPLAY_NAME,
- Directory.PHOTO_SUPPORT,
- };
-
- public static final int ID = 0;
- public static final int PACKAGE_NAME = 1;
- public static final int TYPE_RESOURCE_ID = 2;
- public static final int DISPLAY_NAME = 3;
- public static final int PHOTO_SUPPORT = 4;
- }
-}
diff --git a/java/com/android/contacts/common/list/DirectoryPartition.java b/java/com/android/contacts/common/list/DirectoryPartition.java
deleted file mode 100644
index 26b851041..000000000
--- a/java/com/android/contacts/common/list/DirectoryPartition.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.provider.ContactsContract.Directory;
-import com.android.common.widget.CompositeCursorAdapter;
-
-/** Model object for a {@link Directory} row. */
-public final class DirectoryPartition extends CompositeCursorAdapter.Partition {
-
- public static final int STATUS_NOT_LOADED = 0;
- public static final int STATUS_LOADING = 1;
- public static final int STATUS_LOADED = 2;
-
- public static final int RESULT_LIMIT_DEFAULT = -1;
-
- private long mDirectoryId;
- private String mContentUri;
- private String mDirectoryType;
- private String mDisplayName;
- private int mStatus;
- private boolean mPriorityDirectory;
- private boolean mPhotoSupported;
- private int mResultLimit = RESULT_LIMIT_DEFAULT;
- private boolean mDisplayNumber = true;
-
- private String mLabel;
-
- public DirectoryPartition(boolean showIfEmpty, boolean hasHeader) {
- super(showIfEmpty, hasHeader);
- }
-
- /** Directory ID, see {@link Directory}. */
- public long getDirectoryId() {
- return mDirectoryId;
- }
-
- public void setDirectoryId(long directoryId) {
- this.mDirectoryId = directoryId;
- }
-
- /**
- * Directory type resolved from {@link Directory#PACKAGE_NAME} and {@link
- * Directory#TYPE_RESOURCE_ID};
- */
- public String getDirectoryType() {
- return mDirectoryType;
- }
-
- public void setDirectoryType(String directoryType) {
- this.mDirectoryType = directoryType;
- }
-
- /** See {@link Directory#DISPLAY_NAME}. */
- public String getDisplayName() {
- return mDisplayName;
- }
-
- public void setDisplayName(String displayName) {
- this.mDisplayName = displayName;
- }
-
- public int getStatus() {
- return mStatus;
- }
-
- public void setStatus(int status) {
- mStatus = status;
- }
-
- public boolean isLoading() {
- return mStatus == STATUS_NOT_LOADED || mStatus == STATUS_LOADING;
- }
-
- /** Returns true if this directory should be loaded before non-priority directories. */
- public boolean isPriorityDirectory() {
- return mPriorityDirectory;
- }
-
- public void setPriorityDirectory(boolean priorityDirectory) {
- mPriorityDirectory = priorityDirectory;
- }
-
- /** Returns true if this directory supports photos. */
- public boolean isPhotoSupported() {
- return mPhotoSupported;
- }
-
- public void setPhotoSupported(boolean flag) {
- this.mPhotoSupported = flag;
- }
-
- /**
- * Max number of results for this directory. Defaults to {@link #RESULT_LIMIT_DEFAULT} which
- * implies using the adapter's {@link
- * com.android.contacts.common.list.ContactListAdapter#getDirectoryResultLimit()}
- */
- public int getResultLimit() {
- return mResultLimit;
- }
-
- public void setResultLimit(int resultLimit) {
- mResultLimit = resultLimit;
- }
-
- /**
- * Used by extended directories to specify a custom content URI. Extended directories MUST have a
- * content URI
- */
- public String getContentUri() {
- return mContentUri;
- }
-
- public void setContentUri(String contentUri) {
- mContentUri = contentUri;
- }
-
- /** A label to display in the header next to the display name. */
- public String getLabel() {
- return mLabel;
- }
-
- public void setLabel(String label) {
- mLabel = label;
- }
-
- @Override
- public String toString() {
- return "DirectoryPartition{"
- + "mDirectoryId="
- + mDirectoryId
- + ", mContentUri='"
- + mContentUri
- + '\''
- + ", mDirectoryType='"
- + mDirectoryType
- + '\''
- + ", mDisplayName='"
- + mDisplayName
- + '\''
- + ", mStatus="
- + mStatus
- + ", mPriorityDirectory="
- + mPriorityDirectory
- + ", mPhotoSupported="
- + mPhotoSupported
- + ", mResultLimit="
- + mResultLimit
- + ", mLabel='"
- + mLabel
- + '\''
- + '}';
- }
-
- /**
- * Whether or not to display the phone number in app that have that option - Dialer. If false,
- * Phone Label should be used instead of Phone Number.
- */
- public boolean isDisplayNumber() {
- return mDisplayNumber;
- }
-
- public void setDisplayNumber(boolean displayNumber) {
- mDisplayNumber = displayNumber;
- }
-}
diff --git a/java/com/android/contacts/common/list/IndexerListAdapter.java b/java/com/android/contacts/common/list/IndexerListAdapter.java
deleted file mode 100644
index 2289f6e59..000000000
--- a/java/com/android/contacts/common/list/IndexerListAdapter.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ListView;
-import android.widget.SectionIndexer;
-
-/** A list adapter that supports section indexer and a pinned header. */
-public abstract class IndexerListAdapter extends PinnedHeaderListAdapter implements SectionIndexer {
-
- protected Context mContext;
- private SectionIndexer mIndexer;
- private int mIndexedPartition = 0;
- private boolean mSectionHeaderDisplayEnabled;
- private View mHeader;
- private Placement mPlacementCache = new Placement();
-
- /** Constructor. */
- public IndexerListAdapter(Context context) {
- super(context);
- mContext = context;
- }
-
- /**
- * Creates a section header view that will be pinned at the top of the list as the user scrolls.
- */
- protected abstract View createPinnedSectionHeaderView(Context context, ViewGroup parent);
-
- /** Sets the title in the pinned header as the user scrolls. */
- protected abstract void setPinnedSectionTitle(View pinnedHeaderView, String title);
-
- public boolean isSectionHeaderDisplayEnabled() {
- return mSectionHeaderDisplayEnabled;
- }
-
- public void setSectionHeaderDisplayEnabled(boolean flag) {
- this.mSectionHeaderDisplayEnabled = flag;
- }
-
- public int getIndexedPartition() {
- return mIndexedPartition;
- }
-
- public void setIndexedPartition(int partition) {
- this.mIndexedPartition = partition;
- }
-
- public SectionIndexer getIndexer() {
- return mIndexer;
- }
-
- public void setIndexer(SectionIndexer indexer) {
- mIndexer = indexer;
- mPlacementCache.invalidate();
- }
-
- public Object[] getSections() {
- if (mIndexer == null) {
- return new String[] {" "};
- } else {
- return mIndexer.getSections();
- }
- }
-
- /** @return relative position of the section in the indexed partition */
- public int getPositionForSection(int sectionIndex) {
- if (mIndexer == null) {
- return -1;
- }
-
- return mIndexer.getPositionForSection(sectionIndex);
- }
-
- /** @param position relative position in the indexed partition */
- public int getSectionForPosition(int position) {
- if (mIndexer == null) {
- return -1;
- }
-
- return mIndexer.getSectionForPosition(position);
- }
-
- @Override
- public int getPinnedHeaderCount() {
- if (isSectionHeaderDisplayEnabled()) {
- return super.getPinnedHeaderCount() + 1;
- } else {
- return super.getPinnedHeaderCount();
- }
- }
-
- @Override
- public View getPinnedHeaderView(int viewIndex, View convertView, ViewGroup parent) {
- if (isSectionHeaderDisplayEnabled() && viewIndex == getPinnedHeaderCount() - 1) {
- if (mHeader == null) {
- mHeader = createPinnedSectionHeaderView(mContext, parent);
- }
- return mHeader;
- } else {
- return super.getPinnedHeaderView(viewIndex, convertView, parent);
- }
- }
-
- @Override
- public void configurePinnedHeaders(PinnedHeaderListView listView) {
- super.configurePinnedHeaders(listView);
-
- if (!isSectionHeaderDisplayEnabled()) {
- return;
- }
-
- int index = getPinnedHeaderCount() - 1;
- if (mIndexer == null || getCount() == 0) {
- listView.setHeaderInvisible(index, false);
- } else {
- int listPosition = listView.getPositionAt(listView.getTotalTopPinnedHeaderHeight());
- int position = listPosition - listView.getHeaderViewsCount();
-
- int section = -1;
- int partition = getPartitionForPosition(position);
- if (partition == mIndexedPartition) {
- int offset = getOffsetInPartition(position);
- if (offset != -1) {
- section = getSectionForPosition(offset);
- }
- }
-
- if (section == -1) {
- listView.setHeaderInvisible(index, false);
- } else {
- View topChild = listView.getChildAt(listPosition);
- if (topChild != null) {
- // Match the pinned header's height to the height of the list item.
- mHeader.setMinimumHeight(topChild.getMeasuredHeight());
- }
- setPinnedSectionTitle(mHeader, (String) mIndexer.getSections()[section]);
-
- // Compute the item position where the current partition begins
- int partitionStart = getPositionForPartition(mIndexedPartition);
- if (hasHeader(mIndexedPartition)) {
- partitionStart++;
- }
-
- // Compute the item position where the next section begins
- int nextSectionPosition = partitionStart + getPositionForSection(section + 1);
- boolean isLastInSection = position == nextSectionPosition - 1;
- listView.setFadingHeader(index, listPosition, isLastInSection);
- }
- }
- }
-
- /**
- * Computes the item's placement within its section and populates the {@code placement} object
- * accordingly. Please note that the returned object is volatile and should be copied if the
- * result needs to be used later.
- */
- public Placement getItemPlacementInSection(int position) {
- if (mPlacementCache.position == position) {
- return mPlacementCache;
- }
-
- mPlacementCache.position = position;
- if (isSectionHeaderDisplayEnabled()) {
- int section = getSectionForPosition(position);
- if (section != -1 && getPositionForSection(section) == position) {
- mPlacementCache.firstInSection = true;
- mPlacementCache.sectionHeader = (String) getSections()[section];
- } else {
- mPlacementCache.firstInSection = false;
- mPlacementCache.sectionHeader = null;
- }
-
- mPlacementCache.lastInSection = (getPositionForSection(section + 1) - 1 == position);
- } else {
- mPlacementCache.firstInSection = false;
- mPlacementCache.lastInSection = false;
- mPlacementCache.sectionHeader = null;
- }
- return mPlacementCache;
- }
-
- /**
- * An item view is displayed differently depending on whether it is placed at the beginning,
- * middle or end of a section. It also needs to know the section header when it is at the
- * beginning of a section. This object captures all this configuration.
- */
- public static final class Placement {
-
- public boolean firstInSection;
- public boolean lastInSection;
- public String sectionHeader;
- private int position = ListView.INVALID_POSITION;
-
- public void invalidate() {
- position = ListView.INVALID_POSITION;
- }
- }
-}
diff --git a/java/com/android/contacts/common/list/PhoneNumberListAdapter.java b/java/com/android/contacts/common/list/PhoneNumberListAdapter.java
deleted file mode 100644
index 3c45abf37..000000000
--- a/java/com/android/contacts/common/list/PhoneNumberListAdapter.java
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.Context;
-import android.content.CursorLoader;
-import android.database.Cursor;
-import android.net.Uri;
-import android.net.Uri.Builder;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Callable;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.SipAddress;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Directory;
-import android.support.annotation.VisibleForTesting;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewGroup;
-import com.android.contacts.common.ContactsUtils;
-import com.android.contacts.common.R;
-import com.android.contacts.common.compat.CallableCompat;
-import com.android.contacts.common.compat.PhoneCompat;
-import com.android.contacts.common.extensions.PhoneDirectoryExtenderAccessor;
-import com.android.contacts.common.list.ContactListItemView.CallToAction;
-import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.common.util.Constants;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.cp2.DirectoryCompat;
-import com.android.dialer.compat.CompatUtils;
-import com.android.dialer.configprovider.ConfigProviderBindings;
-import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
-import com.android.dialer.dialercontact.DialerContact;
-import com.android.dialer.duo.DuoComponent;
-import com.android.dialer.enrichedcall.EnrichedCallCapabilities;
-import com.android.dialer.enrichedcall.EnrichedCallComponent;
-import com.android.dialer.enrichedcall.EnrichedCallManager;
-import com.android.dialer.lettertile.LetterTileDrawable;
-import com.android.dialer.phonenumberutil.PhoneNumberHelper;
-import com.android.dialer.util.CallUtil;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * A cursor adapter for the {@link Phone#CONTENT_ITEM_TYPE} and {@link
- * SipAddress#CONTENT_ITEM_TYPE}.
- *
- * <p>By default this adapter just handles phone numbers. When {@link #setUseCallableUri(boolean)}
- * is called with "true", this adapter starts handling SIP addresses too, by using {@link Callable}
- * API instead of {@link Phone}.
- */
-public class PhoneNumberListAdapter extends ContactEntryListAdapter {
-
- private static final String TAG = PhoneNumberListAdapter.class.getSimpleName();
- private static final String IGNORE_NUMBER_TOO_LONG_CLAUSE = "length(" + Phone.NUMBER + ") < 1000";
- // A list of extended directories to add to the directories from the database
- private final List<DirectoryPartition> mExtendedDirectories;
- private final CharSequence mUnknownNameText;
- protected final boolean mIsImsVideoEnabled;
-
- // Extended directories will have ID's that are higher than any of the id's from the database,
- // so that we can identify them and set them up properly. If no extended directories
- // exist, this will be Long.MAX_VALUE
- private long mFirstExtendedDirectoryId = Long.MAX_VALUE;
- private boolean mUseCallableUri;
- private Listener mListener;
-
- public PhoneNumberListAdapter(Context context) {
- super(context);
- setDefaultFilterHeaderText(R.string.list_filter_phones);
- mUnknownNameText = context.getText(android.R.string.unknownName);
-
- mExtendedDirectories =
- PhoneDirectoryExtenderAccessor.get(mContext).getExtendedDirectories(mContext);
-
- int videoCapabilities = CallUtil.getVideoCallingAvailability(context);
- mIsImsVideoEnabled =
- CallUtil.isVideoEnabled(context)
- && (videoCapabilities & CallUtil.VIDEO_CALLING_PRESENCE) != 0;
- }
-
- @Override
- public void configureLoader(CursorLoader loader, long directoryId) {
- String query = getQueryString();
- if (query == null) {
- query = "";
- }
- if (isExtendedDirectory(directoryId)) {
- final DirectoryPartition directory = getExtendedDirectoryFromId(directoryId);
- final String contentUri = directory.getContentUri();
- if (contentUri == null) {
- throw new IllegalStateException("Extended directory must have a content URL: " + directory);
- }
- final Builder builder = Uri.parse(contentUri).buildUpon();
- builder.appendPath(query);
- builder.appendQueryParameter(
- ContactsContract.LIMIT_PARAM_KEY, String.valueOf(getDirectoryResultLimit(directory)));
- loader.setUri(builder.build());
- loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
- } else {
- final boolean isRemoteDirectoryQuery = DirectoryCompat.isRemoteDirectoryId(directoryId);
- final Builder builder;
- if (isSearchMode()) {
- final Uri baseUri;
- if (isRemoteDirectoryQuery) {
- baseUri = PhoneCompat.getContentFilterUri();
- } else if (mUseCallableUri) {
- baseUri = CallableCompat.getContentFilterUri();
- } else {
- baseUri = PhoneCompat.getContentFilterUri();
- }
- builder = baseUri.buildUpon();
- builder.appendPath(query); // Builder will encode the query
- builder.appendQueryParameter(
- ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId));
- if (isRemoteDirectoryQuery) {
- builder.appendQueryParameter(
- ContactsContract.LIMIT_PARAM_KEY,
- String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
- }
- } else {
- Uri baseUri = mUseCallableUri ? Callable.CONTENT_URI : Phone.CONTENT_URI;
- builder =
- baseUri
- .buildUpon()
- .appendQueryParameter(
- ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT));
- if (isSectionHeaderDisplayEnabled()) {
- builder.appendQueryParameter(Phone.EXTRA_ADDRESS_BOOK_INDEX, "true");
- }
- applyFilter(loader, builder, directoryId, getFilter());
- }
-
- // Ignore invalid phone numbers that are too long. These can potentially cause freezes
- // in the UI and there is no reason to display them.
- final String prevSelection = loader.getSelection();
- final String newSelection;
- if (!TextUtils.isEmpty(prevSelection)) {
- newSelection = prevSelection + " AND " + IGNORE_NUMBER_TOO_LONG_CLAUSE;
- } else {
- newSelection = IGNORE_NUMBER_TOO_LONG_CLAUSE;
- }
- loader.setSelection(newSelection);
-
- // Remove duplicates when it is possible.
- builder.appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true");
- loader.setUri(builder.build());
-
- // TODO a projection that includes the search snippet
- if (getContactNameDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
- loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
- } else {
- loader.setProjection(PhoneQuery.PROJECTION_ALTERNATIVE);
- }
-
- if (getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY) {
- loader.setSortOrder(Phone.SORT_KEY_PRIMARY);
- } else {
- loader.setSortOrder(Phone.SORT_KEY_ALTERNATIVE);
- }
- }
- }
-
- protected boolean isExtendedDirectory(long directoryId) {
- return directoryId >= mFirstExtendedDirectoryId;
- }
-
- private DirectoryPartition getExtendedDirectoryFromId(long directoryId) {
- final int directoryIndex = (int) (directoryId - mFirstExtendedDirectoryId);
- return mExtendedDirectories.get(directoryIndex);
- }
-
- /**
- * Configure {@code loader} and {@code uriBuilder} according to {@code directoryId} and {@code
- * filter}.
- */
- private void applyFilter(
- CursorLoader loader, Uri.Builder uriBuilder, long directoryId, ContactListFilter filter) {
- if (filter == null || directoryId != Directory.DEFAULT) {
- return;
- }
-
- final StringBuilder selection = new StringBuilder();
- final List<String> selectionArgs = new ArrayList<String>();
-
- switch (filter.filterType) {
- case ContactListFilter.FILTER_TYPE_CUSTOM:
- {
- selection.append(Contacts.IN_VISIBLE_GROUP + "=1");
- selection.append(" AND " + Contacts.HAS_PHONE_NUMBER + "=1");
- break;
- }
- case ContactListFilter.FILTER_TYPE_ACCOUNT:
- {
- filter.addAccountQueryParameterToUrl(uriBuilder);
- break;
- }
- case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS:
- case ContactListFilter.FILTER_TYPE_DEFAULT:
- break; // No selection needed.
- case ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY:
- break; // This adapter is always "phone only", so no selection needed either.
- default:
- LogUtil.w(
- TAG,
- "Unsupported filter type came "
- + "(type: "
- + filter.filterType
- + ", toString: "
- + filter
- + ")"
- + " showing all contacts.");
- // No selection.
- break;
- }
- loader.setSelection(selection.toString());
- loader.setSelectionArgs(selectionArgs.toArray(new String[0]));
- }
-
- public String getPhoneNumber(int position) {
- final Cursor item = (Cursor) getItem(position);
- return item != null ? item.getString(PhoneQuery.PHONE_NUMBER) : null;
- }
-
- /**
- * Retrieves the lookup key for the given cursor position.
- *
- * @param position The cursor position.
- * @return The lookup key.
- */
- public String getLookupKey(int position) {
- final Cursor item = (Cursor) getItem(position);
- return item != null ? item.getString(PhoneQuery.LOOKUP_KEY) : null;
- }
-
- public DialerContact getDialerContact(int position) {
- Cursor cursor = (Cursor) getItem(position);
- if (cursor == null) {
- LogUtil.e("PhoneNumberListAdapter.getDialerContact", "cursor was null.");
- return null;
- }
-
- String displayName = cursor.getString(PhoneQuery.DISPLAY_NAME);
- String number = cursor.getString(PhoneQuery.PHONE_NUMBER);
- String photoUri = cursor.getString(PhoneQuery.PHOTO_URI);
- Uri contactUri =
- Contacts.getLookupUri(
- cursor.getLong(PhoneQuery.CONTACT_ID), cursor.getString(PhoneQuery.LOOKUP_KEY));
-
- DialerContact.Builder contact = DialerContact.newBuilder();
- contact
- .setNumber(number)
- .setPhotoId(cursor.getLong(PhoneQuery.PHOTO_ID))
- .setContactType(LetterTileDrawable.TYPE_DEFAULT)
- .setNameOrNumber(displayName)
- .setNumberLabel(
- Phone.getTypeLabel(
- mContext.getResources(),
- cursor.getInt(PhoneQuery.PHONE_TYPE),
- cursor.getString(PhoneQuery.PHONE_LABEL))
- .toString());
-
- if (photoUri != null) {
- contact.setPhotoUri(photoUri);
- }
-
- if (contactUri != null) {
- contact.setContactUri(contactUri.toString());
- }
-
- if (!TextUtils.isEmpty(displayName)) {
- contact.setDisplayNumber(number);
- }
-
- return contact.build();
- }
-
- @Override
- protected ContactListItemView newView(
- Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
- ContactListItemView view = super.newView(context, partition, cursor, position, parent);
- view.setUnknownNameText(mUnknownNameText);
- view.setQuickContactEnabled(isQuickContactEnabled());
- return view;
- }
-
- protected void setHighlight(ContactListItemView view, Cursor cursor) {
- view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);
- }
-
- @Override
- protected void bindView(View itemView, int partition, Cursor cursor, int position) {
- super.bindView(itemView, partition, cursor, position);
- ContactListItemView view = (ContactListItemView) itemView;
-
- setHighlight(view, cursor);
-
- // Look at elements before and after this position, checking if contact IDs are same.
- // If they have one same contact ID, it means they can be grouped.
- //
- // In one group, only the first entry will show its photo and its name, and the other
- // entries in the group show just their data (e.g. phone number, email address).
- cursor.moveToPosition(position);
- boolean isFirstEntry = true;
- final long currentContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
- if (cursor.moveToPrevious() && !cursor.isBeforeFirst()) {
- final long previousContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
- if (currentContactId == previousContactId) {
- isFirstEntry = false;
- }
- }
- cursor.moveToPosition(position);
-
- bindViewId(view, cursor, PhoneQuery.PHONE_ID);
-
- bindSectionHeaderAndDivider(view, position);
- if (isFirstEntry) {
- bindName(view, cursor);
- if (isQuickContactEnabled()) {
- bindQuickContact(
- view,
- partition,
- cursor,
- PhoneQuery.PHOTO_ID,
- PhoneQuery.PHOTO_URI,
- PhoneQuery.CONTACT_ID,
- PhoneQuery.LOOKUP_KEY,
- PhoneQuery.DISPLAY_NAME);
- } else {
- if (getDisplayPhotos()) {
- bindPhoto(view, partition, cursor);
- }
- }
- } else {
- unbindName(view);
-
- view.removePhotoView(true, false);
- }
-
- final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
- // All sections have headers, so scroll position is off by 1.
- position += getPositionForPartition(partition) + 1;
-
- bindPhoneNumber(view, cursor, directory.isDisplayNumber(), position);
- }
-
- @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
- public void bindPhoneNumber(
- ContactListItemView view, Cursor cursor, boolean displayNumber, int position) {
- CharSequence label = null;
- if (displayNumber && !cursor.isNull(PhoneQuery.PHONE_TYPE)) {
- final int type = cursor.getInt(PhoneQuery.PHONE_TYPE);
- final String customLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
-
- // TODO cache
- label = Phone.getTypeLabel(mContext.getResources(), type, customLabel);
- }
- view.setLabel(label);
- final String text;
- String number = cursor.getString(PhoneQuery.PHONE_NUMBER);
- if (displayNumber) {
- text = number;
- } else {
- // Display phone label. If that's null, display geocoded location for the number
- final String phoneLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
- if (phoneLabel != null) {
- text = phoneLabel;
- } else {
- final String phoneNumber = cursor.getString(PhoneQuery.PHONE_NUMBER);
- text =
- PhoneNumberHelper.getGeoDescription(
- mContext,
- phoneNumber,
- PhoneNumberHelper.getCurrentCountryIso(mContext, null /* PhoneAccountHandle */));
- }
- }
- view.setPhoneNumber(text);
-
- @CallToAction int action = ContactListItemView.NONE;
-
- if (CompatUtils.isVideoCompatible()) {
- // Determine if carrier presence indicates the number supports video calling.
- int carrierPresence = cursor.getInt(PhoneQuery.CARRIER_PRESENCE);
- boolean isPresent = (carrierPresence & Phone.CARRIER_PRESENCE_VT_CAPABLE) != 0;
-
- boolean showViewIcon = mIsImsVideoEnabled && isPresent;
- if (showViewIcon) {
- action = ContactListItemView.VIDEO;
- }
- }
-
- if (action == ContactListItemView.NONE
- && DuoComponent.get(mContext).getDuo().isReachable(mContext, number)) {
- action = ContactListItemView.DUO;
- }
-
- if (action == ContactListItemView.NONE) {
- EnrichedCallManager manager = EnrichedCallComponent.get(mContext).getEnrichedCallManager();
- EnrichedCallCapabilities capabilities = manager.getCapabilities(number);
- if (capabilities != null && capabilities.isCallComposerCapable()) {
- action = ContactListItemView.CALL_AND_SHARE;
- } else if (capabilities == null
- && getQueryString() != null
- && getQueryString().length() >= 3) {
- manager.requestCapabilities(number);
- }
- }
-
- view.setCallToAction(action, mListener, position);
- }
-
- protected void bindSectionHeaderAndDivider(final ContactListItemView view, int position) {
- if (isSectionHeaderDisplayEnabled()) {
- Placement placement = getItemPlacementInSection(position);
- view.setSectionHeader(placement.firstInSection ? placement.sectionHeader : null);
- } else {
- view.setSectionHeader(null);
- }
- }
-
- protected void bindName(final ContactListItemView view, Cursor cursor) {
- view.showDisplayName(cursor, PhoneQuery.DISPLAY_NAME);
- // Note: we don't show phonetic names any more (see issue 5265330)
- }
-
- protected void unbindName(final ContactListItemView view) {
- view.hideDisplayName();
- }
-
- @Override
- protected void bindWorkProfileIcon(final ContactListItemView view, int partition) {
- final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
- final long directoryId = directory.getDirectoryId();
- final long userType = ContactsUtils.determineUserType(directoryId, null);
- // Work directory must not be a extended directory. An extended directory is custom
- // directory in the app, but not a directory provided by framework. So it can't be
- // USER_TYPE_WORK.
- view.setWorkProfileIconEnabled(
- !isExtendedDirectory(directoryId) && userType == ContactsUtils.USER_TYPE_WORK);
- }
-
- protected void bindPhoto(final ContactListItemView view, int partitionIndex, Cursor cursor) {
- if (!isPhotoSupported(partitionIndex)) {
- view.removePhotoView();
- return;
- }
-
- long photoId = 0;
- if (!cursor.isNull(PhoneQuery.PHOTO_ID)) {
- photoId = cursor.getLong(PhoneQuery.PHOTO_ID);
- }
-
- if (photoId != 0) {
- getPhotoLoader()
- .loadThumbnail(view.getPhotoView(), photoId, false, getCircularPhotos(), null);
- } else {
- final String photoUriString = cursor.getString(PhoneQuery.PHOTO_URI);
- final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
-
- DefaultImageRequest request = null;
- if (photoUri == null) {
- final String displayName = cursor.getString(PhoneQuery.DISPLAY_NAME);
- final String lookupKey = cursor.getString(PhoneQuery.LOOKUP_KEY);
- request = new DefaultImageRequest(displayName, lookupKey, getCircularPhotos());
- }
- getPhotoLoader()
- .loadDirectoryPhoto(view.getPhotoView(), photoUri, false, getCircularPhotos(), request);
- }
- }
-
- public void setUseCallableUri(boolean useCallableUri) {
- mUseCallableUri = useCallableUri;
- }
-
- /**
- * Override base implementation to inject extended directories between local & remote directories.
- * This is done in the following steps: 1. Call base implementation to add directories from the
- * cursor. 2. Iterate all base directories and establish the following information: a. The highest
- * directory id so that we can assign unused id's to the extended directories. b. The index of the
- * last non-remote directory. This is where we will insert extended directories. 3. Iterate the
- * extended directories and for each one, assign an ID and insert it in the proper location.
- */
- @Override
- public void changeDirectories(Cursor cursor) {
- super.changeDirectories(cursor);
- if (getDirectorySearchMode() == DirectoryListLoader.SEARCH_MODE_NONE) {
- return;
- }
- int numExtendedDirectories = mExtendedDirectories.size();
-
- if (ConfigProviderBindings.get(getContext()).getBoolean("p13n_ranker_should_enable", false)) {
- // Suggested results wasn't formulated as an extended directory, so manually
- // increment the count here when the feature is enabled. Suggestions are
- // only shown when the ranker is enabled.
- numExtendedDirectories++;
- }
-
- if (getPartitionCount() == cursor.getCount() + numExtendedDirectories) {
- // already added all directories;
- return;
- }
-
- mFirstExtendedDirectoryId = Long.MAX_VALUE;
- if (!mExtendedDirectories.isEmpty()) {
- // The Directory.LOCAL_INVISIBLE is not in the cursor but we can't reuse it's
- // "special" ID.
- long maxId = Directory.LOCAL_INVISIBLE;
- int insertIndex = 0;
- for (int i = 0, n = getPartitionCount(); i < n; i++) {
- final DirectoryPartition partition = (DirectoryPartition) getPartition(i);
- final long id = partition.getDirectoryId();
- if (id > maxId) {
- maxId = id;
- }
- if (!DirectoryCompat.isRemoteDirectoryId(id)) {
- // assuming remote directories come after local, we will end up with the index
- // where we should insert extended directories. This also works if there are no
- // remote directories at all.
- insertIndex = i + 1;
- }
- }
- // Extended directories ID's cannot collide with base directories
- mFirstExtendedDirectoryId = maxId + 1;
- for (int i = 0; i < mExtendedDirectories.size(); i++) {
- final long id = mFirstExtendedDirectoryId + i;
- final DirectoryPartition directory = mExtendedDirectories.get(i);
- if (getPartitionByDirectoryId(id) == -1) {
- addPartition(insertIndex, directory);
- directory.setDirectoryId(id);
- }
- }
- }
- }
-
- @Override
- protected Uri getContactUri(
- int partitionIndex, Cursor cursor, int contactIdColumn, int lookUpKeyColumn) {
- final DirectoryPartition directory = (DirectoryPartition) getPartition(partitionIndex);
- final long directoryId = directory.getDirectoryId();
- if (!isExtendedDirectory(directoryId)) {
- return super.getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn);
- }
- return Contacts.CONTENT_LOOKUP_URI
- .buildUpon()
- .appendPath(Constants.LOOKUP_URI_ENCODED)
- .appendQueryParameter(Directory.DISPLAY_NAME, directory.getLabel())
- .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId))
- .encodedFragment(cursor.getString(lookUpKeyColumn))
- .build();
- }
-
- public Listener getListener() {
- return mListener;
- }
-
- public void setListener(Listener listener) {
- mListener = listener;
- }
-
- public interface Listener {
-
- void onVideoCallIconClicked(int position);
-
- void onDuoVideoIconClicked(int position);
-
- void onCallAndShareIconClicked(int position);
- }
-
- public static class PhoneQuery {
-
- /**
- * Optional key used as part of a JSON lookup key to specify an analytics category associated
- * with the row.
- */
- public static final String ANALYTICS_CATEGORY = "analytics_category";
-
- /**
- * Optional key used as part of a JSON lookup key to specify an analytics action associated with
- * the row.
- */
- public static final String ANALYTICS_ACTION = "analytics_action";
-
- /**
- * Optional key used as part of a JSON lookup key to specify an analytics value associated with
- * the row.
- */
- public static final String ANALYTICS_VALUE = "analytics_value";
-
- public static final String[] PROJECTION_PRIMARY_INTERNAL =
- new String[] {
- Phone._ID, // 0
- Phone.TYPE, // 1
- Phone.LABEL, // 2
- Phone.NUMBER, // 3
- Phone.CONTACT_ID, // 4
- Phone.LOOKUP_KEY, // 5
- Phone.PHOTO_ID, // 6
- Phone.DISPLAY_NAME_PRIMARY, // 7
- Phone.PHOTO_THUMBNAIL_URI, // 8
- };
-
- public static final String[] PROJECTION_PRIMARY;
- public static final String[] PROJECTION_ALTERNATIVE_INTERNAL =
- new String[] {
- Phone._ID, // 0
- Phone.TYPE, // 1
- Phone.LABEL, // 2
- Phone.NUMBER, // 3
- Phone.CONTACT_ID, // 4
- Phone.LOOKUP_KEY, // 5
- Phone.PHOTO_ID, // 6
- Phone.DISPLAY_NAME_ALTERNATIVE, // 7
- Phone.PHOTO_THUMBNAIL_URI, // 8
- };
- public static final String[] PROJECTION_ALTERNATIVE;
- public static final int PHONE_ID = 0;
- public static final int PHONE_TYPE = 1;
- public static final int PHONE_LABEL = 2;
- public static final int PHONE_NUMBER = 3;
- public static final int CONTACT_ID = 4;
- public static final int LOOKUP_KEY = 5;
- public static final int PHOTO_ID = 6;
- public static final int DISPLAY_NAME = 7;
- public static final int PHOTO_URI = 8;
- public static final int CARRIER_PRESENCE = 9;
-
- static {
- final List<String> projectionList =
- new ArrayList<>(Arrays.asList(PROJECTION_PRIMARY_INTERNAL));
- projectionList.add(Phone.CARRIER_PRESENCE); // 9
- PROJECTION_PRIMARY = projectionList.toArray(new String[projectionList.size()]);
- }
-
- static {
- final List<String> projectionList =
- new ArrayList<>(Arrays.asList(PROJECTION_ALTERNATIVE_INTERNAL));
- projectionList.add(Phone.CARRIER_PRESENCE); // 9
- PROJECTION_ALTERNATIVE = projectionList.toArray(new String[projectionList.size()]);
- }
- }
-}
diff --git a/java/com/android/contacts/common/list/PhoneNumberPickerFragment.java b/java/com/android/contacts/common/list/PhoneNumberPickerFragment.java
deleted file mode 100644
index 1a3b80f31..000000000
--- a/java/com/android/contacts/common/list/PhoneNumberPickerFragment.java
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.Loader;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.support.annotation.MainThread;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import com.android.contacts.common.R;
-import com.android.contacts.common.list.PhoneNumberListAdapter.Listener;
-import com.android.contacts.common.util.AccountFilterUtil;
-import com.android.dialer.callintent.CallInitiationType;
-import com.android.dialer.callintent.CallInitiationType.Type;
-import com.android.dialer.callintent.CallSpecificAppData;
-import com.android.dialer.common.Assert;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.dialercontact.DialerContact;
-import com.android.dialer.duo.DuoComponent;
-import com.android.dialer.enrichedcall.EnrichedCallComponent;
-import com.android.dialer.enrichedcall.EnrichedCallManager;
-import com.android.dialer.logging.DialerImpression;
-import com.android.dialer.logging.Logger;
-import com.android.dialer.performancereport.PerformanceReport;
-import com.android.dialer.protos.ProtoParsers;
-import java.util.Set;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/** Fragment containing a phone number list for picking. */
-public class PhoneNumberPickerFragment extends ContactEntryListFragment<ContactEntryListAdapter>
- implements PhoneNumberListAdapter.Listener, EnrichedCallManager.CapabilitiesListener {
-
- private static final String KEY_FILTER = "filter";
- private OnPhoneNumberPickerActionListener mListener;
- private ContactListFilter mFilter;
- private View mAccountFilterHeader;
- /**
- * Lives as ListView's header and is shown when {@link #mAccountFilterHeader} is set to View.GONE.
- */
- private View mPaddingView;
- /** true if the loader has started at least once. */
- private boolean mLoaderStarted;
-
- private boolean mUseCallableUri;
-
- private final Set<OnLoadFinishedListener> mLoadFinishedListeners = new ArraySet<>();
-
- private CursorReranker mCursorReranker;
-
- public PhoneNumberPickerFragment() {
- setQuickContactEnabled(false);
- setPhotoLoaderEnabled(true);
- setSectionHeaderDisplayEnabled(false);
- setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE);
-
- // Show nothing instead of letting caller Activity show something.
- setHasOptionsMenu(true);
- }
-
- /**
- * Handles a click on the video call icon for a row in the list.
- *
- * @param position The position in the list where the click ocurred.
- */
- @Override
- public void onVideoCallIconClicked(int position) {
- Logger.get(getContext()).logImpression(DialerImpression.Type.IMS_VIDEO_REQUESTED_FROM_SEARCH);
- callNumber(position, true /* isVideoCall */);
- }
-
- @Override
- public void onDuoVideoIconClicked(int position) {
- PerformanceReport.stopRecording();
- String phoneNumber = getPhoneNumber(position);
- Intent intent = DuoComponent.get(getContext()).getDuo().getIntent(getContext(), phoneNumber);
- // DialtactsActivity.ACTIVITY_REQUEST_CODE_LIGHTBRINGER
- // Cannot reference because of cyclic dependencies
- Logger.get(getContext())
- .logImpression(DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FROM_SEARCH);
- int dialactsActivityRequestCode = 3;
- getActivity().startActivityForResult(intent, dialactsActivityRequestCode);
- }
-
- @Override
- public void onCallAndShareIconClicked(int position) {
- // Required because of cyclic dependencies of everything depending on contacts/common.
- String componentName = "com.android.dialer.callcomposer.CallComposerActivity";
- Intent intent = new Intent();
- intent.setComponent(new ComponentName(getContext(), componentName));
- DialerContact contact = ((PhoneNumberListAdapter) getAdapter()).getDialerContact(position);
- ProtoParsers.put(intent, "CALL_COMPOSER_CONTACT", contact);
- startActivity(intent);
- }
-
- public void setDirectorySearchEnabled(boolean flag) {
- setDirectorySearchMode(
- flag ? DirectoryListLoader.SEARCH_MODE_DEFAULT : DirectoryListLoader.SEARCH_MODE_NONE);
- }
-
- public void setOnPhoneNumberPickerActionListener(OnPhoneNumberPickerActionListener listener) {
- this.mListener = listener;
- }
-
- public OnPhoneNumberPickerActionListener getOnPhoneNumberPickerListener() {
- return mListener;
- }
-
- @Override
- protected void onCreateView(LayoutInflater inflater, ViewGroup container) {
- super.onCreateView(inflater, container);
-
- View paddingView = inflater.inflate(R.layout.contact_detail_list_padding, null, false);
- mPaddingView = paddingView.findViewById(R.id.contact_detail_list_padding);
- getListView().addHeaderView(paddingView);
-
- mAccountFilterHeader = getView().findViewById(R.id.account_filter_header_container);
- updateFilterHeaderView();
-
- setVisibleScrollbarEnabled(getVisibleScrollbarEnabled());
- }
-
- @Override
- public void onPause() {
- super.onPause();
- EnrichedCallComponent.get(getContext())
- .getEnrichedCallManager()
- .unregisterCapabilitiesListener(this);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- EnrichedCallComponent.get(getContext())
- .getEnrichedCallManager()
- .registerCapabilitiesListener(this);
- }
-
- protected boolean getVisibleScrollbarEnabled() {
- return true;
- }
-
- @Override
- protected void setSearchMode(boolean flag) {
- super.setSearchMode(flag);
- updateFilterHeaderView();
- }
-
- private void updateFilterHeaderView() {
- final ContactListFilter filter = getFilter();
- if (mAccountFilterHeader == null || filter == null) {
- return;
- }
- final boolean shouldShowHeader =
- !isSearchMode()
- && AccountFilterUtil.updateAccountFilterTitleForPhone(
- mAccountFilterHeader, filter, false);
- if (shouldShowHeader) {
- mPaddingView.setVisibility(View.GONE);
- mAccountFilterHeader.setVisibility(View.VISIBLE);
- } else {
- mPaddingView.setVisibility(View.VISIBLE);
- mAccountFilterHeader.setVisibility(View.GONE);
- }
- }
-
- @Override
- public void restoreSavedState(Bundle savedState) {
- super.restoreSavedState(savedState);
-
- if (savedState == null) {
- return;
- }
-
- mFilter = savedState.getParcelable(KEY_FILTER);
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putParcelable(KEY_FILTER, mFilter);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- final int itemId = item.getItemId();
- if (itemId == android.R.id.home) { // See ActionBar#setDisplayHomeAsUpEnabled()
- if (mListener != null) {
- mListener.onHomeInActionBarSelected();
- }
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- protected void onItemClick(int position, long id) {
- callNumber(position, false /* isVideoCall */);
- }
-
- /**
- * Initiates a call to the number at the specified position.
- *
- * @param position The position.
- * @param isVideoCall {@code true} if the call should be initiated as a video call, {@code false}
- * otherwise.
- */
- private void callNumber(int position, boolean isVideoCall) {
- final String number = getPhoneNumber(position);
- if (!TextUtils.isEmpty(number)) {
- cacheContactInfo(position);
- CallSpecificAppData callSpecificAppData =
- CallSpecificAppData.newBuilder()
- .setAllowAssistedDialing(true)
- .setCallInitiationType(getCallInitiationType(true /* isRemoteDirectory */))
- .setPositionOfSelectedSearchResult(position)
- .setCharactersInSearchString(getQueryString() == null ? 0 : getQueryString().length())
- .build();
- mListener.onPickPhoneNumber(number, isVideoCall, callSpecificAppData);
- } else {
- LogUtil.i(
- "PhoneNumberPickerFragment.callNumber",
- "item at %d was clicked before adapter is ready, ignoring",
- position);
- }
-
- // Get the lookup key and track any analytics
- final String lookupKey = getLookupKey(position);
- if (!TextUtils.isEmpty(lookupKey)) {
- maybeTrackAnalytics(lookupKey);
- }
- }
-
- protected void cacheContactInfo(int position) {
- // Not implemented. Hook for child classes
- }
-
- protected String getPhoneNumber(int position) {
- final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter();
- return adapter.getPhoneNumber(position);
- }
-
- protected String getLookupKey(int position) {
- final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter();
- return adapter.getLookupKey(position);
- }
-
- @Override
- protected void startLoading() {
- mLoaderStarted = true;
- super.startLoading();
- }
-
- @Override
- @MainThread
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- Assert.isMainThread();
- // TODO(strongarm): define and verify behavior for "Nearby places", corp directories,
- // and dividers listed in UI between these categories
- if (mCursorReranker != null
- && data != null
- && !data.isClosed()
- && data.getCount() > 0
- && loader.getId() == 0) { // only re-rank if a suggestions loader with id of 0.
- data = mCursorReranker.rerankCursor(data);
- }
- super.onLoadFinished(loader, data);
-
- // disable scroll bar if there is no data
- setVisibleScrollbarEnabled(data != null && !data.isClosed() && data.getCount() > 0);
-
- if (data != null) {
- notifyListeners();
- }
- }
-
- /** Ranks cursor data rows and returns reference to new cursor object with reordered data. */
- public interface CursorReranker {
- @MainThread
- Cursor rerankCursor(Cursor data);
- }
-
- @MainThread
- public void setReranker(@Nullable CursorReranker reranker) {
- Assert.isMainThread();
- mCursorReranker = reranker;
- }
-
- /** Listener that is notified when cursor has finished loading data. */
- public interface OnLoadFinishedListener {
- void onLoadFinished();
- }
-
- @MainThread
- public void addOnLoadFinishedListener(OnLoadFinishedListener listener) {
- Assert.isMainThread();
- mLoadFinishedListeners.add(listener);
- }
-
- @MainThread
- public void removeOnLoadFinishedListener(OnLoadFinishedListener listener) {
- Assert.isMainThread();
- mLoadFinishedListeners.remove(listener);
- }
-
- @MainThread
- protected void notifyListeners() {
- Assert.isMainThread();
- for (OnLoadFinishedListener listener : mLoadFinishedListeners) {
- listener.onLoadFinished();
- }
- }
-
- @Override
- public void onCapabilitiesUpdated() {
- if (getAdapter() != null) {
- EnrichedCallManager manager =
- EnrichedCallComponent.get(getContext()).getEnrichedCallManager();
- Listener listener = ((PhoneNumberListAdapter) getAdapter()).getListener();
-
- for (int i = 0; i < getListView().getChildCount(); i++) {
- if (!(getListView().getChildAt(i) instanceof ContactListItemView)) {
- continue;
- }
-
- // Since call and share is the lowest priority call to action, if any others are set,
- // do not reset the call to action. Also do not set the call and share call to action if
- // the number doesn't support call composer.
- ContactListItemView view = (ContactListItemView) getListView().getChildAt(i);
- if (view.getCallToAction() != ContactListItemView.NONE
- || view.getPhoneNumber() == null
- || manager.getCapabilities(view.getPhoneNumber()) == null
- || !manager.getCapabilities(view.getPhoneNumber()).isCallComposerCapable()) {
- continue;
- }
- view.setCallToAction(ContactListItemView.CALL_AND_SHARE, listener, view.getPosition());
- }
- }
- }
-
- @MainThread
- @Override
- public void onDetach() {
- Assert.isMainThread();
- mLoadFinishedListeners.clear();
- super.onDetach();
- }
-
- public void setUseCallableUri(boolean useCallableUri) {
- mUseCallableUri = useCallableUri;
- }
-
- public boolean usesCallableUri() {
- return mUseCallableUri;
- }
-
- @Override
- protected ContactEntryListAdapter createListAdapter() {
- PhoneNumberListAdapter adapter = new PhoneNumberListAdapter(getActivity());
- adapter.setDisplayPhotos(true);
- adapter.setUseCallableUri(mUseCallableUri);
- return adapter;
- }
-
- @Override
- protected void configureAdapter() {
- super.configureAdapter();
-
- final ContactEntryListAdapter adapter = getAdapter();
- if (adapter == null) {
- return;
- }
-
- if (!isSearchMode() && mFilter != null) {
- adapter.setFilter(mFilter);
- }
- }
-
- @Override
- protected View inflateView(LayoutInflater inflater, ViewGroup container) {
- return inflater.inflate(R.layout.contact_list_content, null);
- }
-
- public ContactListFilter getFilter() {
- return mFilter;
- }
-
- public void setFilter(ContactListFilter filter) {
- if ((mFilter == null && filter == null) || (mFilter != null && mFilter.equals(filter))) {
- return;
- }
-
- mFilter = filter;
- if (mLoaderStarted) {
- reloadData();
- }
- updateFilterHeaderView();
- }
-
- /**
- * @param isRemoteDirectory {@code true} if the call was initiated using a contact/phone number
- * not in the local contacts database
- */
- protected CallInitiationType.Type getCallInitiationType(boolean isRemoteDirectory) {
- return Type.UNKNOWN_INITIATION;
- }
-
- /**
- * Where a lookup key contains analytic event information, logs the associated analytics event.
- *
- * @param lookupKey The lookup key JSON object.
- */
- private void maybeTrackAnalytics(String lookupKey) {
- try {
- JSONObject json = new JSONObject(lookupKey);
-
- String analyticsCategory =
- json.getString(PhoneNumberListAdapter.PhoneQuery.ANALYTICS_CATEGORY);
- String analyticsAction = json.getString(PhoneNumberListAdapter.PhoneQuery.ANALYTICS_ACTION);
- String analyticsValue = json.getString(PhoneNumberListAdapter.PhoneQuery.ANALYTICS_VALUE);
-
- if (TextUtils.isEmpty(analyticsCategory)
- || TextUtils.isEmpty(analyticsAction)
- || TextUtils.isEmpty(analyticsValue)) {
- return;
- }
-
- // Assume that the analytic value being tracked could be a float value, but just cast
- // to a long so that the analytic server can handle it.
- long value;
- try {
- float floatValue = Float.parseFloat(analyticsValue);
- value = (long) floatValue;
- } catch (NumberFormatException nfe) {
- return;
- }
-
- Logger.get(getActivity())
- .sendHitEventAnalytics(analyticsCategory, analyticsAction, "" /* label */, value);
- } catch (JSONException e) {
- // Not an error; just a lookup key that doesn't have the right information.
- }
- }
-}
diff --git a/java/com/android/contacts/common/list/PinnedHeaderListAdapter.java b/java/com/android/contacts/common/list/PinnedHeaderListAdapter.java
deleted file mode 100644
index 0bdcef084..000000000
--- a/java/com/android/contacts/common/list/PinnedHeaderListAdapter.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import com.android.common.widget.CompositeCursorAdapter;
-
-/** A subclass of {@link CompositeCursorAdapter} that manages pinned partition headers. */
-public abstract class PinnedHeaderListAdapter extends CompositeCursorAdapter
- implements PinnedHeaderListView.PinnedHeaderAdapter {
-
- public static final int PARTITION_HEADER_TYPE = 0;
-
- private boolean mPinnedPartitionHeadersEnabled;
- private boolean[] mHeaderVisibility;
-
- public PinnedHeaderListAdapter(Context context) {
- super(context);
- }
-
- public boolean getPinnedPartitionHeadersEnabled() {
- return mPinnedPartitionHeadersEnabled;
- }
-
- public void setPinnedPartitionHeadersEnabled(boolean flag) {
- this.mPinnedPartitionHeadersEnabled = flag;
- }
-
- @Override
- public int getPinnedHeaderCount() {
- if (mPinnedPartitionHeadersEnabled) {
- return getPartitionCount();
- } else {
- return 0;
- }
- }
-
- protected boolean isPinnedPartitionHeaderVisible(int partition) {
- return getPinnedPartitionHeadersEnabled()
- && hasHeader(partition)
- && !isPartitionEmpty(partition);
- }
-
- /** The default implementation creates the same type of view as a normal partition header. */
- @Override
- public View getPinnedHeaderView(int partition, View convertView, ViewGroup parent) {
- if (hasHeader(partition)) {
- View view = null;
- if (convertView != null) {
- Integer headerType = (Integer) convertView.getTag();
- if (headerType != null && headerType == PARTITION_HEADER_TYPE) {
- view = convertView;
- }
- }
- if (view == null) {
- view = newHeaderView(getContext(), partition, null, parent);
- view.setTag(PARTITION_HEADER_TYPE);
- view.setFocusable(false);
- view.setEnabled(false);
- }
- bindHeaderView(view, partition, getCursor(partition));
- view.setLayoutDirection(parent.getLayoutDirection());
- return view;
- } else {
- return null;
- }
- }
-
- @Override
- public void configurePinnedHeaders(PinnedHeaderListView listView) {
- if (!getPinnedPartitionHeadersEnabled()) {
- return;
- }
-
- int size = getPartitionCount();
-
- // Cache visibility bits, because we will need them several times later on
- if (mHeaderVisibility == null || mHeaderVisibility.length != size) {
- mHeaderVisibility = new boolean[size];
- }
- for (int i = 0; i < size; i++) {
- boolean visible = isPinnedPartitionHeaderVisible(i);
- mHeaderVisibility[i] = visible;
- if (!visible) {
- listView.setHeaderInvisible(i, true);
- }
- }
-
- int headerViewsCount = listView.getHeaderViewsCount();
-
- // Starting at the top, find and pin headers for partitions preceding the visible one(s)
- int maxTopHeader = -1;
- int topHeaderHeight = 0;
- for (int i = 0; i < size; i++) {
- if (mHeaderVisibility[i]) {
- int position = listView.getPositionAt(topHeaderHeight) - headerViewsCount;
- int partition = getPartitionForPosition(position);
- if (i > partition) {
- break;
- }
-
- listView.setHeaderPinnedAtTop(i, topHeaderHeight, false);
- topHeaderHeight += listView.getPinnedHeaderHeight(i);
- maxTopHeader = i;
- }
- }
-
- // Starting at the bottom, find and pin headers for partitions following the visible one(s)
- int maxBottomHeader = size;
- int bottomHeaderHeight = 0;
- int listHeight = listView.getHeight();
- for (int i = size; --i > maxTopHeader; ) {
- if (mHeaderVisibility[i]) {
- int position = listView.getPositionAt(listHeight - bottomHeaderHeight) - headerViewsCount;
- if (position < 0) {
- break;
- }
-
- int partition = getPartitionForPosition(position - 1);
- if (partition == -1 || i <= partition) {
- break;
- }
-
- int height = listView.getPinnedHeaderHeight(i);
- bottomHeaderHeight += height;
-
- listView.setHeaderPinnedAtBottom(i, listHeight - bottomHeaderHeight, false);
- maxBottomHeader = i;
- }
- }
-
- // Headers in between the top-pinned and bottom-pinned should be hidden
- for (int i = maxTopHeader + 1; i < maxBottomHeader; i++) {
- if (mHeaderVisibility[i]) {
- listView.setHeaderInvisible(i, isPartitionEmpty(i));
- }
- }
- }
-
- @Override
- public int getScrollPositionForHeader(int viewIndex) {
- return getPositionForPartition(viewIndex);
- }
-}
diff --git a/java/com/android/contacts/common/list/PinnedHeaderListView.java b/java/com/android/contacts/common/list/PinnedHeaderListView.java
deleted file mode 100644
index a801624b4..000000000
--- a/java/com/android/contacts/common/list/PinnedHeaderListView.java
+++ /dev/null
@@ -1,563 +0,0 @@
-/*
- * Copyright (C) 2010 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.common.list;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.RectF;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ListAdapter;
-import com.android.dialer.util.ViewUtil;
-
-/**
- * A ListView that maintains a header pinned at the top of the list. The pinned header can be pushed
- * up and dissolved as needed.
- */
-public class PinnedHeaderListView extends AutoScrollListView
- implements OnScrollListener, OnItemSelectedListener {
-
- private static final int MAX_ALPHA = 255;
- private static final int TOP = 0;
- private static final int BOTTOM = 1;
- private static final int FADING = 2;
- private static final int DEFAULT_ANIMATION_DURATION = 20;
- private static final int DEFAULT_SMOOTH_SCROLL_DURATION = 100;
- private PinnedHeaderAdapter mAdapter;
- private int mSize;
- private PinnedHeader[] mHeaders;
- private RectF mBounds = new RectF();
- private OnScrollListener mOnScrollListener;
- private OnItemSelectedListener mOnItemSelectedListener;
- private int mScrollState;
- private boolean mScrollToSectionOnHeaderTouch = false;
- private boolean mHeaderTouched = false;
- private int mAnimationDuration = DEFAULT_ANIMATION_DURATION;
- private boolean mAnimating;
- private long mAnimationTargetTime;
- private int mHeaderPaddingStart;
- private int mHeaderWidth;
-
- public PinnedHeaderListView(Context context) {
- this(context, null, android.R.attr.listViewStyle);
- }
-
- public PinnedHeaderListView(Context context, AttributeSet attrs) {
- this(context, attrs, android.R.attr.listViewStyle);
- }
-
- public PinnedHeaderListView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- super.setOnScrollListener(this);
- super.setOnItemSelectedListener(this);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- mHeaderPaddingStart = getPaddingStart();
- mHeaderWidth = r - l - mHeaderPaddingStart - getPaddingEnd();
- }
-
- @Override
- public void setAdapter(ListAdapter adapter) {
- mAdapter = (PinnedHeaderAdapter) adapter;
- super.setAdapter(adapter);
- }
-
- @Override
- public void setOnScrollListener(OnScrollListener onScrollListener) {
- mOnScrollListener = onScrollListener;
- super.setOnScrollListener(this);
- }
-
- @Override
- public void setOnItemSelectedListener(OnItemSelectedListener listener) {
- mOnItemSelectedListener = listener;
- super.setOnItemSelectedListener(this);
- }
-
- public void setScrollToSectionOnHeaderTouch(boolean value) {
- mScrollToSectionOnHeaderTouch = value;
- }
-
- @Override
- public void onScroll(
- AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- if (mAdapter != null) {
- int count = mAdapter.getPinnedHeaderCount();
- if (count != mSize) {
- mSize = count;
- if (mHeaders == null) {
- mHeaders = new PinnedHeader[mSize];
- } else if (mHeaders.length < mSize) {
- PinnedHeader[] headers = mHeaders;
- mHeaders = new PinnedHeader[mSize];
- System.arraycopy(headers, 0, mHeaders, 0, headers.length);
- }
- }
-
- for (int i = 0; i < mSize; i++) {
- if (mHeaders[i] == null) {
- mHeaders[i] = new PinnedHeader();
- }
- mHeaders[i].view = mAdapter.getPinnedHeaderView(i, mHeaders[i].view, this);
- }
-
- mAnimationTargetTime = System.currentTimeMillis() + mAnimationDuration;
- mAdapter.configurePinnedHeaders(this);
- invalidateIfAnimating();
- }
- if (mOnScrollListener != null) {
- mOnScrollListener.onScroll(this, firstVisibleItem, visibleItemCount, totalItemCount);
- }
- }
-
- @Override
- protected float getTopFadingEdgeStrength() {
- // Disable vertical fading at the top when the pinned header is present
- return mSize > 0 ? 0 : super.getTopFadingEdgeStrength();
- }
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- mScrollState = scrollState;
- if (mOnScrollListener != null) {
- mOnScrollListener.onScrollStateChanged(this, scrollState);
- }
- }
-
- /**
- * Ensures that the selected item is positioned below the top-pinned headers and above the
- * bottom-pinned ones.
- */
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- int height = getHeight();
-
- int windowTop = 0;
- int windowBottom = height;
-
- for (int i = 0; i < mSize; i++) {
- PinnedHeader header = mHeaders[i];
- if (header.visible) {
- if (header.state == TOP) {
- windowTop = header.y + header.height;
- } else if (header.state == BOTTOM) {
- windowBottom = header.y;
- break;
- }
- }
- }
-
- View selectedView = getSelectedView();
- if (selectedView != null) {
- if (selectedView.getTop() < windowTop) {
- setSelectionFromTop(position, windowTop);
- } else if (selectedView.getBottom() > windowBottom) {
- setSelectionFromTop(position, windowBottom - selectedView.getHeight());
- }
- }
-
- if (mOnItemSelectedListener != null) {
- mOnItemSelectedListener.onItemSelected(parent, view, position, id);
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- if (mOnItemSelectedListener != null) {
- mOnItemSelectedListener.onNothingSelected(parent);
- }
- }
-
- public int getPinnedHeaderHeight(int viewIndex) {
- ensurePinnedHeaderLayout(viewIndex);
- return mHeaders[viewIndex].view.getHeight();
- }
-
- /**
- * Set header to be pinned at the top.
- *
- * @param viewIndex index of the header view
- * @param y is position of the header in pixels.
- * @param animate true if the transition to the new coordinate should be animated
- */
- public void setHeaderPinnedAtTop(int viewIndex, int y, boolean animate) {
- ensurePinnedHeaderLayout(viewIndex);
- PinnedHeader header = mHeaders[viewIndex];
- header.visible = true;
- header.y = y;
- header.state = TOP;
-
- // TODO perhaps we should animate at the top as well
- header.animating = false;
- }
-
- /**
- * Set header to be pinned at the bottom.
- *
- * @param viewIndex index of the header view
- * @param y is position of the header in pixels.
- * @param animate true if the transition to the new coordinate should be animated
- */
- public void setHeaderPinnedAtBottom(int viewIndex, int y, boolean animate) {
- ensurePinnedHeaderLayout(viewIndex);
- PinnedHeader header = mHeaders[viewIndex];
- header.state = BOTTOM;
- if (header.animating) {
- header.targetTime = mAnimationTargetTime;
- header.sourceY = header.y;
- header.targetY = y;
- } else if (animate && (header.y != y || !header.visible)) {
- if (header.visible) {
- header.sourceY = header.y;
- } else {
- header.visible = true;
- header.sourceY = y + header.height;
- }
- header.animating = true;
- header.targetVisible = true;
- header.targetTime = mAnimationTargetTime;
- header.targetY = y;
- } else {
- header.visible = true;
- header.y = y;
- }
- }
-
- /**
- * Set header to be pinned at the top of the first visible item.
- *
- * @param viewIndex index of the header view
- * @param position is position of the header in pixels.
- */
- public void setFadingHeader(int viewIndex, int position, boolean fade) {
- ensurePinnedHeaderLayout(viewIndex);
-
- View child = getChildAt(position - getFirstVisiblePosition());
- if (child == null) {
- return;
- }
-
- PinnedHeader header = mHeaders[viewIndex];
- header.visible = true;
- header.state = FADING;
- header.alpha = MAX_ALPHA;
- header.animating = false;
-
- int top = getTotalTopPinnedHeaderHeight();
- header.y = top;
- if (fade) {
- int bottom = child.getBottom() - top;
- int headerHeight = header.height;
- if (bottom < headerHeight) {
- int portion = bottom - headerHeight;
- header.alpha = MAX_ALPHA * (headerHeight + portion) / headerHeight;
- header.y = top + portion;
- }
- }
- }
-
- /**
- * Makes header invisible.
- *
- * @param viewIndex index of the header view
- * @param animate true if the transition to the new coordinate should be animated
- */
- public void setHeaderInvisible(int viewIndex, boolean animate) {
- PinnedHeader header = mHeaders[viewIndex];
- if (header.visible && (animate || header.animating) && header.state == BOTTOM) {
- header.sourceY = header.y;
- if (!header.animating) {
- header.visible = true;
- header.targetY = getBottom() + header.height;
- }
- header.animating = true;
- header.targetTime = mAnimationTargetTime;
- header.targetVisible = false;
- } else {
- header.visible = false;
- }
- }
-
- private void ensurePinnedHeaderLayout(int viewIndex) {
- View view = mHeaders[viewIndex].view;
- if (view.isLayoutRequested()) {
- ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
- int widthSpec;
- int heightSpec;
-
- if (layoutParams != null && layoutParams.width > 0) {
- widthSpec = View.MeasureSpec.makeMeasureSpec(layoutParams.width, View.MeasureSpec.EXACTLY);
- } else {
- widthSpec = View.MeasureSpec.makeMeasureSpec(mHeaderWidth, View.MeasureSpec.EXACTLY);
- }
-
- if (layoutParams != null && layoutParams.height > 0) {
- heightSpec =
- View.MeasureSpec.makeMeasureSpec(layoutParams.height, View.MeasureSpec.EXACTLY);
- } else {
- heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
- }
- view.measure(widthSpec, heightSpec);
- int height = view.getMeasuredHeight();
- mHeaders[viewIndex].height = height;
- view.layout(0, 0, view.getMeasuredWidth(), height);
- }
- }
-
- /** Returns the sum of heights of headers pinned to the top. */
- public int getTotalTopPinnedHeaderHeight() {
- for (int i = mSize; --i >= 0; ) {
- PinnedHeader header = mHeaders[i];
- if (header.visible && header.state == TOP) {
- return header.y + header.height;
- }
- }
- return 0;
- }
-
- /** Returns the list item position at the specified y coordinate. */
- public int getPositionAt(int y) {
- do {
- int position = pointToPosition(getPaddingLeft() + 1, y);
- if (position != -1) {
- return position;
- }
- // If position == -1, we must have hit a separator. Let's examine
- // a nearby pixel
- y--;
- } while (y > 0);
- return 0;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- mHeaderTouched = false;
- if (super.onInterceptTouchEvent(ev)) {
- return true;
- }
-
- if (mScrollState == SCROLL_STATE_IDLE) {
- final int y = (int) ev.getY();
- final int x = (int) ev.getX();
- for (int i = mSize; --i >= 0; ) {
- PinnedHeader header = mHeaders[i];
- // For RTL layouts, this also takes into account that the scrollbar is on the left
- // side.
- final int padding = getPaddingLeft();
- if (header.visible
- && header.y <= y
- && header.y + header.height > y
- && x >= padding
- && padding + header.view.getWidth() >= x) {
- mHeaderTouched = true;
- if (mScrollToSectionOnHeaderTouch && ev.getAction() == MotionEvent.ACTION_DOWN) {
- return smoothScrollToPartition(i);
- } else {
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (mHeaderTouched) {
- if (ev.getAction() == MotionEvent.ACTION_UP) {
- mHeaderTouched = false;
- }
- return true;
- }
- return super.onTouchEvent(ev);
- }
-
- private boolean smoothScrollToPartition(int partition) {
- if (mAdapter == null) {
- return false;
- }
- final int position = mAdapter.getScrollPositionForHeader(partition);
- if (position == -1) {
- return false;
- }
-
- int offset = 0;
- for (int i = 0; i < partition; i++) {
- PinnedHeader header = mHeaders[i];
- if (header.visible) {
- offset += header.height;
- }
- }
- smoothScrollToPositionFromTop(
- position + getHeaderViewsCount(), offset, DEFAULT_SMOOTH_SCROLL_DURATION);
- return true;
- }
-
- private void invalidateIfAnimating() {
- mAnimating = false;
- for (int i = 0; i < mSize; i++) {
- if (mHeaders[i].animating) {
- mAnimating = true;
- invalidate();
- return;
- }
- }
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- long currentTime = mAnimating ? System.currentTimeMillis() : 0;
-
- int top = 0;
- int bottom = getBottom();
- boolean hasVisibleHeaders = false;
- for (int i = 0; i < mSize; i++) {
- PinnedHeader header = mHeaders[i];
- if (header.visible) {
- hasVisibleHeaders = true;
- if (header.state == BOTTOM && header.y < bottom) {
- bottom = header.y;
- } else if (header.state == TOP || header.state == FADING) {
- int newTop = header.y + header.height;
- if (newTop > top) {
- top = newTop;
- }
- }
- }
- }
-
- if (hasVisibleHeaders) {
- canvas.save();
- }
-
- super.dispatchDraw(canvas);
-
- if (hasVisibleHeaders) {
- canvas.restore();
-
- // If the first item is visible and if it has a positive top that is greater than the
- // first header's assigned y-value, use that for the first header's y value. This way,
- // the header inherits any padding applied to the list view.
- if (mSize > 0 && getFirstVisiblePosition() == 0) {
- View firstChild = getChildAt(0);
- PinnedHeader firstHeader = mHeaders[0];
-
- if (firstHeader != null) {
- int firstHeaderTop = firstChild != null ? firstChild.getTop() : 0;
- firstHeader.y = Math.max(firstHeader.y, firstHeaderTop);
- }
- }
-
- // First draw top headers, then the bottom ones to handle the Z axis correctly
- for (int i = mSize; --i >= 0; ) {
- PinnedHeader header = mHeaders[i];
- if (header.visible && (header.state == TOP || header.state == FADING)) {
- drawHeader(canvas, header, currentTime);
- }
- }
-
- for (int i = 0; i < mSize; i++) {
- PinnedHeader header = mHeaders[i];
- if (header.visible && header.state == BOTTOM) {
- drawHeader(canvas, header, currentTime);
- }
- }
- }
-
- invalidateIfAnimating();
- }
-
- private void drawHeader(Canvas canvas, PinnedHeader header, long currentTime) {
- if (header.animating) {
- int timeLeft = (int) (header.targetTime - currentTime);
- if (timeLeft <= 0) {
- header.y = header.targetY;
- header.visible = header.targetVisible;
- header.animating = false;
- } else {
- header.y =
- header.targetY + (header.sourceY - header.targetY) * timeLeft / mAnimationDuration;
- }
- }
- if (header.visible) {
- View view = header.view;
- int saveCount = canvas.save();
- int translateX =
- ViewUtil.isViewLayoutRtl(this)
- ? getWidth() - mHeaderPaddingStart - view.getWidth()
- : mHeaderPaddingStart;
- canvas.translate(translateX, header.y);
- if (header.state == FADING) {
- mBounds.set(0, 0, view.getWidth(), view.getHeight());
- canvas.saveLayerAlpha(mBounds, header.alpha);
- }
- view.draw(canvas);
- canvas.restoreToCount(saveCount);
- }
- }
-
- /** Adapter interface. The list adapter must implement this interface. */
- public interface PinnedHeaderAdapter {
-
- /** Returns the overall number of pinned headers, visible or not. */
- int getPinnedHeaderCount();
-
- /** Creates or updates the pinned header view. */
- View getPinnedHeaderView(int viewIndex, View convertView, ViewGroup parent);
-
- /**
- * Configures the pinned headers to match the visible list items. The adapter should call {@link
- * PinnedHeaderListView#setHeaderPinnedAtTop}, {@link
- * PinnedHeaderListView#setHeaderPinnedAtBottom}, {@link PinnedHeaderListView#setFadingHeader}
- * or {@link PinnedHeaderListView#setHeaderInvisible}, for each header that needs to change its
- * position or visibility.
- */
- void configurePinnedHeaders(PinnedHeaderListView listView);
-
- /**
- * Returns the list position to scroll to if the pinned header is touched. Return -1 if the list
- * does not need to be scrolled.
- */
- int getScrollPositionForHeader(int viewIndex);
- }
-
- private static final class PinnedHeader {
-
- View view;
- boolean visible;
- int y;
- int height;
- int alpha;
- int state;
-
- boolean animating;
- boolean targetVisible;
- int sourceY;
- int targetY;
- long targetTime;
- }
-}
diff --git a/java/com/android/dialer/app/AndroidManifest.xml b/java/com/android/dialer/app/AndroidManifest.xml
index 0c1a362bb..e77bbe250 100644
--- a/java/com/android/dialer/app/AndroidManifest.xml
+++ b/java/com/android/dialer/app/AndroidManifest.xml
@@ -55,7 +55,7 @@
<uses-permission android:name="android.permission.STOP_APP_SWITCHES"/>
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
<application android:theme="@style/Theme.AppCompat">
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index 1a8e5cc9c..a9a11e008 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -26,7 +26,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
@@ -34,7 +33,6 @@ import android.os.Trace;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract.QuickContact;
import android.speech.RecognizerIntent;
-import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
import android.support.design.widget.CoordinatorLayout;
@@ -66,9 +64,6 @@ import android.widget.TextView;
import android.widget.Toast;
import com.android.contacts.common.dialog.ClearFrequentsDialog;
import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
-import com.android.contacts.common.list.PhoneNumberListAdapter;
-import com.android.contacts.common.list.PhoneNumberPickerFragment.CursorReranker;
-import com.android.contacts.common.list.PhoneNumberPickerFragment.OnLoadFinishedListener;
import com.android.dialer.animation.AnimUtils;
import com.android.dialer.animation.AnimationListenerAdapter;
import com.android.dialer.app.calllog.CallLogActivity;
@@ -84,9 +79,6 @@ import com.android.dialer.app.list.OldSpeedDialFragment;
import com.android.dialer.app.list.OnDragDropListener;
import com.android.dialer.app.list.OnListFragmentScrolledListener;
import com.android.dialer.app.list.PhoneFavoriteSquareTileView;
-import com.android.dialer.app.list.RegularSearchFragment;
-import com.android.dialer.app.list.SearchFragment;
-import com.android.dialer.app.list.SmartDialSearchFragment;
import com.android.dialer.app.settings.DialerSettingsActivity;
import com.android.dialer.app.widget.ActionBarController;
import com.android.dialer.app.widget.SearchEditTextLayout;
@@ -120,11 +112,6 @@ import com.android.dialer.logging.ScreenEvent;
import com.android.dialer.logging.UiAction;
import com.android.dialer.metrics.Metrics;
import com.android.dialer.metrics.MetricsComponent;
-import com.android.dialer.p13n.inference.P13nRanking;
-import com.android.dialer.p13n.inference.protocol.P13nRanker;
-import com.android.dialer.p13n.inference.protocol.P13nRanker.P13nRefreshCompleteListener;
-import com.android.dialer.p13n.logging.P13nLogger;
-import com.android.dialer.p13n.logging.P13nLogging;
import com.android.dialer.performancereport.PerformanceReport;
import com.android.dialer.postcall.PostCall;
import com.android.dialer.precall.PreCall;
@@ -161,7 +148,6 @@ public class DialtactsActivity extends TransactionSafeActivity
ContactsFragment.OnContactsListScrolledListener,
DialpadFragment.HostInterface,
OldSpeedDialFragment.HostInterface,
- SearchFragment.HostInterface,
OnDragDropListener,
OnPhoneNumberPickerActionListener,
PopupMenu.OnMenuItemClickListener,
@@ -192,8 +178,6 @@ public class DialtactsActivity extends TransactionSafeActivity
private static final String KEY_IS_DIALPAD_SHOWN = "is_dialpad_shown";
private static final String KEY_FAB_VISIBLE = "fab_visible";
private static final String TAG_NEW_SEARCH_FRAGMENT = "new_search";
- private static final String TAG_REGULAR_SEARCH_FRAGMENT = "search";
- private static final String TAG_SMARTDIAL_SEARCH_FRAGMENT = "smartdial";
private static final String TAG_FAVORITES_FRAGMENT = "favorites";
/** Just for backward compatibility. Should behave as same as {@link Intent#ACTION_DIAL}. */
private static final String ACTION_TOUCH_DIALER = "com.android.phone.action.TOUCH_DIALER";
@@ -212,11 +196,6 @@ public class DialtactsActivity extends TransactionSafeActivity
/** Root layout of DialtactsActivity */
private CoordinatorLayout parentLayout;
- /** Fragment for searching phone numbers using the alphanumeric keyboard. */
- private RegularSearchFragment regularSearchFragment;
-
- /** Fragment for searching phone numbers using the dialpad. */
- private SmartDialSearchFragment smartDialSearchFragment;
/** new Fragment for search phone numbers using the keyboard and the dialpad. */
private NewSearchFragment newSearchFragment;
@@ -267,8 +246,6 @@ public class DialtactsActivity extends TransactionSafeActivity
private boolean wasConfigurationChange;
private long timeTabSelected;
- private P13nLogger p13nLogger;
- private P13nRanker p13nRanker;
public boolean isMultiSelectModeEnabled;
private boolean isLastTabEnabled;
@@ -312,7 +289,6 @@ public class DialtactsActivity extends TransactionSafeActivity
LogUtil.v("DialtactsActivity.onTextChanged", "previous query: " + searchQuery);
searchQuery = newText;
- // TODO(calderwoodra): show p13n when newText is empty.
// Show search fragment only when the query string is changed to non-empty text.
if (!TextUtils.isEmpty(newText)) {
// Call enterSearchUi only if we are switching search modes, or showing a search
@@ -324,11 +300,7 @@ public class DialtactsActivity extends TransactionSafeActivity
}
}
- if (smartDialSearchFragment != null && smartDialSearchFragment.isVisible()) {
- smartDialSearchFragment.setQueryString(searchQuery);
- } else if (regularSearchFragment != null && regularSearchFragment.isVisible()) {
- regularSearchFragment.setQueryString(searchQuery);
- } else if (newSearchFragment != null && newSearchFragment.isVisible()) {
+ if (newSearchFragment != null && newSearchFragment.isVisible()) {
newSearchFragment.setQuery(searchQuery, getCallInitiationType());
}
}
@@ -496,14 +468,9 @@ public class DialtactsActivity extends TransactionSafeActivity
SmartDialPrefix.initializeNanpSettings(this);
Trace.endSection();
- p13nLogger = P13nLogging.get(getApplicationContext());
- p13nRanker = P13nRanking.get(getApplicationContext());
Trace.endSection();
- // Update the new search fragment to the correct position and the ActionBar's visibility.
- if (ConfigProviderBindings.get(this).getBoolean("enable_new_search_fragment", false)) {
- updateSearchFragmentPosition();
- }
+ updateSearchFragmentPosition();
}
@NonNull
@@ -624,14 +591,6 @@ public class DialtactsActivity extends TransactionSafeActivity
setSearchBoxHint();
timeTabSelected = SystemClock.elapsedRealtime();
- p13nLogger.reset();
- p13nRanker.refresh(
- new P13nRefreshCompleteListener() {
- @Override
- public void onP13nRefreshComplete() {
- // TODO(strongarm): make zero-query search results visible
- }
- });
Trace.endSection();
}
@@ -696,15 +655,6 @@ public class DialtactsActivity extends TransactionSafeActivity
LogUtil.i("DialtactsActivity.onAttachFragment", "fragment: %s", fragment);
if (fragment instanceof DialpadFragment) {
dialpadFragment = (DialpadFragment) fragment;
- } else if (fragment instanceof SmartDialSearchFragment) {
- smartDialSearchFragment = (SmartDialSearchFragment) fragment;
- smartDialSearchFragment.setOnPhoneNumberPickerActionListener(this);
- if (!TextUtils.isEmpty(dialpadQuery)) {
- smartDialSearchFragment.setAddToContactNumber(dialpadQuery);
- }
- } else if (fragment instanceof SearchFragment) {
- regularSearchFragment = (RegularSearchFragment) fragment;
- regularSearchFragment.setOnPhoneNumberPickerActionListener(this);
} else if (fragment instanceof ListsFragment) {
listsFragment = (ListsFragment) fragment;
listsFragment.addOnPageChangeListener(this);
@@ -712,28 +662,6 @@ public class DialtactsActivity extends TransactionSafeActivity
newSearchFragment = (NewSearchFragment) fragment;
updateSearchFragmentPosition();
}
- if (fragment instanceof SearchFragment) {
- final SearchFragment searchFragment = (SearchFragment) fragment;
- searchFragment.setReranker(
- new CursorReranker() {
- @Override
- @MainThread
- public Cursor rerankCursor(Cursor data) {
- Assert.isMainThread();
- String queryString = searchFragment.getQueryString();
- return p13nRanker.rankCursor(data, queryString == null ? 0 : queryString.length());
- }
- });
- searchFragment.addOnLoadFinishedListener(
- new OnLoadFinishedListener() {
- @Override
- public void onLoadFinished() {
- p13nLogger.onSearchQuery(
- searchFragment.getQueryString(),
- (PhoneNumberListAdapter) searchFragment.getAdapter());
- }
- });
- }
}
protected void handleMenuSettings() {
@@ -1001,24 +929,7 @@ public class DialtactsActivity extends TransactionSafeActivity
}
private void updateSearchFragmentPosition() {
- SearchFragment fragment = null;
- if (smartDialSearchFragment != null) {
- fragment = smartDialSearchFragment;
- } else if (regularSearchFragment != null) {
- fragment = regularSearchFragment;
- }
- LogUtil.d(
- "DialtactsActivity.updateSearchFragmentPosition",
- "fragment: %s, isVisible: %b",
- fragment,
- fragment != null && fragment.isVisible());
- if (fragment != null) {
- // We need to force animation here even when fragment is not visible since it might not be
- // visible immediately after screen orientation change and dialpad height would not be
- // available immediately which is required to update position. By forcing an animation,
- // position will be updated after a delay by when the dialpad height would be available.
- fragment.updatePosition(true /* animate */);
- } else if (newSearchFragment != null) {
+ if (newSearchFragment != null) {
int animationDuration = getResources().getInteger(R.integer.dialpad_slide_in_duration);
int actionbarHeight = getResources().getDimensionPixelSize(R.dimen.action_bar_height_large);
int shadowHeight = getResources().getDrawable(R.drawable.search_shadow).getIntrinsicHeight();
@@ -1208,29 +1119,9 @@ public class DialtactsActivity extends TransactionSafeActivity
return;
}
- final FragmentTransaction transaction = getFragmentManager().beginTransaction();
- if (inDialpadSearch && smartDialSearchFragment != null) {
- transaction.remove(smartDialSearchFragment);
- } else if (inRegularSearch && regularSearchFragment != null) {
- transaction.remove(regularSearchFragment);
- }
-
- final String tag;
- inDialpadSearch = false;
- inRegularSearch = false;
- inNewSearch = false;
- boolean useNewSearch =
- ConfigProviderBindings.get(this).getBoolean("enable_new_search_fragment", false);
- if (useNewSearch) {
- tag = TAG_NEW_SEARCH_FRAGMENT;
- inNewSearch = true;
- } else if (smartDialSearch) {
- tag = TAG_SMARTDIAL_SEARCH_FRAGMENT;
- inDialpadSearch = true;
- } else {
- tag = TAG_REGULAR_SEARCH_FRAGMENT;
- inRegularSearch = true;
- }
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ String tag = TAG_NEW_SEARCH_FRAGMENT;
+ inNewSearch = true;
floatingActionButtonController.scaleOut();
@@ -1240,59 +1131,23 @@ public class DialtactsActivity extends TransactionSafeActivity
transaction.setTransition(FragmentTransaction.TRANSIT_NONE);
}
- Fragment fragment = getFragmentManager().findFragmentByTag(tag);
+ NewSearchFragment fragment = (NewSearchFragment) getFragmentManager().findFragmentByTag(tag);
if (fragment == null) {
- if (useNewSearch) {
- fragment = NewSearchFragment.newInstance(!isDialpadShown());
- } else if (smartDialSearch) {
- fragment = new SmartDialSearchFragment();
- } else {
- fragment = Bindings.getLegacy(this).newRegularSearchFragment();
- ((SearchFragment) fragment)
- .setOnTouchListener(
- (v, event) -> {
- // Show the FAB when the user touches the lists fragment and the soft
- // keyboard is hidden.
- hideDialpadFragment(true, false);
- v.performClick();
- return false;
- });
- }
+ fragment = NewSearchFragment.newInstance(!isDialpadShown());
transaction.add(R.id.dialtacts_frame, fragment, tag);
} else {
- // TODO(calderwoodra): if this is a transition from dialpad to searchbar, animate fragment
- // down, and vice versa. Perhaps just add a coordinator behavior with the search bar.
transaction.show(fragment);
}
// DialtactsActivity will provide the options menu
fragment.setHasOptionsMenu(false);
-
- // Will show empty list if P13nRanker is not enabled. Else, re-ranked list by the ranker.
- if (!useNewSearch) {
- ((SearchFragment) fragment)
- .setShowEmptyListForNullQuery(p13nRanker.shouldShowEmptyListForNullQuery());
- } else {
- // TODO(calderwoodra): add p13n ranker to new search.
- }
-
- if (!smartDialSearch && !useNewSearch) {
- ((SearchFragment) fragment).setQueryString(query);
- } else if (useNewSearch) {
- ((NewSearchFragment) fragment).setQuery(query, getCallInitiationType());
- }
+ fragment.setQuery(query, getCallInitiationType());
transaction.commit();
if (animate) {
Assert.isNotNull(listsFragment.getView()).animate().alpha(0).withLayer();
}
listsFragment.setUserVisibleHint(false);
-
- if (smartDialSearch) {
- Logger.get(this).logScreenView(ScreenEvent.Type.SMART_DIAL_SEARCH, this);
- } else {
- Logger.get(this).logScreenView(ScreenEvent.Type.REGULAR_SEARCH, this);
- }
}
/** Hides the search fragment */
@@ -1336,12 +1191,6 @@ public class DialtactsActivity extends TransactionSafeActivity
}
final FragmentTransaction transaction = getFragmentManager().beginTransaction();
- if (smartDialSearchFragment != null) {
- transaction.remove(smartDialSearchFragment);
- }
- if (regularSearchFragment != null) {
- transaction.remove(regularSearchFragment);
- }
if (newSearchFragment != null) {
transaction.remove(newSearchFragment);
}
@@ -1405,9 +1254,6 @@ public class DialtactsActivity extends TransactionSafeActivity
@Override
public void onDialpadQueryChanged(String query) {
dialpadQuery = query;
- if (smartDialSearchFragment != null) {
- smartDialSearchFragment.setAddToContactNumber(query);
- }
if (newSearchFragment != null) {
newSearchFragment.setRawNumber(query);
}
@@ -1443,13 +1289,6 @@ public class DialtactsActivity extends TransactionSafeActivity
@Override
public boolean onDialpadSpacerTouchWithEmptyQuery() {
- if (inDialpadSearch
- && smartDialSearchFragment != null
- && !smartDialSearchFragment.isShowingPermissionRequest()) {
- PerformanceReport.recordClick(UiAction.Type.CLOSE_DIALPAD);
- hideDialpadFragment(true /* animate */, true /* clearDialpad */);
- return true;
- }
return false;
}
@@ -1625,25 +1464,15 @@ public class DialtactsActivity extends TransactionSafeActivity
@Override
public void onPageScrollStateChanged(int state) {}
- @Override
public boolean isActionBarShowing() {
return actionBarController.isActionBarShowing();
}
- @Override
public boolean isDialpadShown() {
return isDialpadShown;
}
@Override
- public int getDialpadHeight() {
- if (dialpadFragment != null) {
- return dialpadFragment.getDialpadHeight();
- }
- return 0;
- }
-
- @Override
public void setActionBarHideOffset(int offset) {
getActionBarSafely().setHideOffset(offset);
}
diff --git a/java/com/android/dialer/app/calllog/CallLogAsyncTaskUtil.java b/java/com/android/dialer/app/calllog/CallLogAsyncTaskUtil.java
index 08f5585b0..b306e756a 100644
--- a/java/com/android/dialer/app/calllog/CallLogAsyncTaskUtil.java
+++ b/java/com/android/dialer/app/calllog/CallLogAsyncTaskUtil.java
@@ -34,7 +34,8 @@ import com.android.dialer.common.concurrent.AsyncTaskExecutors;
import com.android.dialer.util.PermissionsUtil;
import com.android.voicemail.VoicemailClient;
-@TargetApi(VERSION_CODES.M)
+/** TODO(calderwoodra): documentation */
+@TargetApi(VERSION_CODES.N)
public class CallLogAsyncTaskUtil {
private static final String TAG = "CallLogAsyncTaskUtil";
@@ -155,6 +156,7 @@ public class CallLogAsyncTaskUtil {
UPDATE_DURATION,
}
+ /** TODO(calderwoodra): documentation */
public interface CallLogAsyncTaskListener {
void onDeleteVoicemail();
}
diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
index 3afb6bb87..ce6e5baf4 100644
--- a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
+++ b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
@@ -51,7 +51,7 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
/** Helper class operating on call log notifications. */
-@TargetApi(Build.VERSION_CODES.M)
+@TargetApi(Build.VERSION_CODES.N)
public class CallLogNotificationsQueryHelper {
@VisibleForTesting
@@ -341,14 +341,14 @@ public class CallLogNotificationsQueryHelper {
@Override
@Nullable
- @TargetApi(Build.VERSION_CODES.M)
+ @TargetApi(Build.VERSION_CODES.N)
public List<NewCall> query(int type) {
return query(type, NO_THRESHOLD);
}
@Override
@Nullable
- @TargetApi(Build.VERSION_CODES.M)
+ @TargetApi(Build.VERSION_CODES.N)
@SuppressWarnings("MissingPermission")
public List<NewCall> query(int type, long thresholdMillis) {
if (!PermissionsUtil.hasPermission(context, Manifest.permission.READ_CALL_LOG)) {
diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java b/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
index 78d307521..cba389cc3 100644
--- a/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
+++ b/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
@@ -233,9 +233,6 @@ final class VisualVoicemailNotifier {
@Nullable
private static Uri getVoicemailRingtoneUri(
@NonNull Context context, @Nullable PhoneAccountHandle handle) {
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- return null;
- }
if (handle == null) {
LogUtil.i("VisualVoicemailNotifier.getVoicemailRingtoneUri", "null handle, getting fallback");
handle = getFallbackAccount(context);
@@ -251,9 +248,6 @@ final class VisualVoicemailNotifier {
private static int getNotificationDefaultFlags(
@NonNull Context context, @Nullable PhoneAccountHandle handle) {
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- return Notification.DEFAULT_ALL;
- }
if (handle == null) {
LogUtil.i(
"VisualVoicemailNotifier.getNotificationDefaultFlags", "null handle, getting fallback");
diff --git a/java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java b/java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java
index ba61601ae..754ab2727 100644
--- a/java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java
+++ b/java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java
@@ -22,7 +22,6 @@ import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
-import android.os.Build;
import android.provider.VoicemailContract;
import com.android.dialer.common.LogUtil;
import com.android.dialer.constants.ScheduledJobIds;
@@ -37,12 +36,8 @@ public class VoicemailNotificationJobService extends JobService {
* notification is visible.
*/
public static void scheduleJob(Context context) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
- LogUtil.i("VoicemailNotificationJobService.scheduleJob", "not supported");
- } else {
- context.getSystemService(JobScheduler.class).schedule(getJobInfo(context));
- LogUtil.i("VoicemailNotificationJobService.scheduleJob", "job scheduled");
- }
+ context.getSystemService(JobScheduler.class).schedule(getJobInfo(context));
+ LogUtil.i("VoicemailNotificationJobService.scheduleJob", "job scheduled");
}
/**
diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java
index cae35d5b6..270ec6d03 100644
--- a/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java
+++ b/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java
@@ -29,7 +29,6 @@ import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageView;
import android.widget.TextView;
import com.android.dialer.app.R;
import com.android.dialer.blocking.BlockedNumbersMigrator;
@@ -73,13 +72,11 @@ public class BlockedNumbersFragment extends ListFragment
getListView().addHeaderView(inflater.inflate(R.layout.blocked_number_header, null));
getListView().addFooterView(inflater.inflate(R.layout.blocked_number_footer, null));
//replace the icon for add number with LetterTileDrawable(), so it will have identical style
- ImageView addNumberIcon = (ImageView) getActivity().findViewById(R.id.add_number_icon);
LetterTileDrawable drawable = new LetterTileDrawable(getResources());
drawable.setLetter(ADD_BLOCKED_NUMBER_ICON_LETTER);
drawable.setColor(
ActivityCompat.getColor(getActivity(), R.color.add_blocked_number_icon_color));
drawable.setIsCircular(true);
- addNumberIcon.setImageDrawable(drawable);
if (adapter == null) {
adapter =
@@ -97,7 +94,6 @@ public class BlockedNumbersFragment extends ListFragment
blockedNumberListDivider = getActivity().findViewById(R.id.blocked_number_list_divider);
getListView().findViewById(R.id.import_button).setOnClickListener(this);
getListView().findViewById(R.id.view_numbers_button).setOnClickListener(this);
- getListView().findViewById(R.id.add_number_linear_layout).setOnClickListener(this);
footerText = (TextView) getActivity().findViewById(R.id.blocked_number_footer_textview);
voicemailEnabledChecker = new VisualVoicemailEnabledChecker(getContext(), this);
@@ -137,8 +133,6 @@ public class BlockedNumbersFragment extends ListFragment
if (FilteredNumberCompat.canUseNewFiltering()) {
migratePromoView.setVisibility(View.VISIBLE);
blockedNumbersText.setVisibility(View.GONE);
- getListView().findViewById(R.id.add_number_linear_layout).setVisibility(View.GONE);
- getListView().findViewById(R.id.add_number_linear_layout).setOnClickListener(null);
blockedNumberListDivider.setVisibility(View.GONE);
importSettings.setVisibility(View.GONE);
getListView().findViewById(R.id.import_button).setOnClickListener(null);
@@ -218,9 +212,7 @@ public class BlockedNumbersFragment extends ListFragment
}
int resId = view.getId();
- if (resId == R.id.add_number_linear_layout) {
- activity.showSearchUi();
- } else if (resId == R.id.view_numbers_button) {
+ if (resId == R.id.view_numbers_button) {
activity.showNumbersToImportPreviewUi();
} else if (resId == R.id.import_button) {
FilteredNumbersUtil.importSendToVoicemailContacts(
diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java
index 858d28355..5475b4ea3 100644
--- a/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java
+++ b/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java
@@ -19,17 +19,13 @@ import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import com.android.dialer.app.R;
-import com.android.dialer.app.list.BlockedListSearchFragment;
-import com.android.dialer.app.list.SearchFragment;
import com.android.dialer.logging.Logger;
import com.android.dialer.logging.ScreenEvent;
/** TODO(calderwoodra): documentation */
-public class BlockedNumbersSettingsActivity extends AppCompatActivity
- implements SearchFragment.HostInterface {
+public class BlockedNumbersSettingsActivity extends AppCompatActivity {
private static final String TAG_BLOCKED_MANAGEMENT_FRAGMENT = "blocked_management";
- private static final String TAG_BLOCKED_SEARCH_FRAGMENT = "blocked_search";
private static final String TAG_VIEW_NUMBERS_TO_IMPORT_FRAGMENT = "view_numbers_to_import";
@Override
@@ -60,27 +56,6 @@ public class BlockedNumbersSettingsActivity extends AppCompatActivity
Logger.get(this).logScreenView(ScreenEvent.Type.BLOCKED_NUMBER_MANAGEMENT, this);
}
- /** Shows fragment with search UI for browsing/finding numbers to block. */
- public void showSearchUi() {
- BlockedListSearchFragment fragment =
- (BlockedListSearchFragment)
- getFragmentManager().findFragmentByTag(TAG_BLOCKED_SEARCH_FRAGMENT);
- if (fragment == null) {
- fragment = new BlockedListSearchFragment();
- fragment.setHasOptionsMenu(false);
- fragment.setShowEmptyListForNullQuery(true);
- fragment.setDirectorySearchEnabled(false);
- }
-
- getFragmentManager()
- .beginTransaction()
- .replace(R.id.blocked_numbers_activity_container, fragment, TAG_BLOCKED_SEARCH_FRAGMENT)
- .addToBackStack(null)
- .commit();
-
- Logger.get(this).logScreenView(ScreenEvent.Type.BLOCKED_NUMBER_ADD_NUMBER, this);
- }
-
/**
* Shows fragment with UI to preview the numbers of contacts currently marked as send-to-voicemail
* in Contacts. These numbers can be imported into Dialer's blocked number list.
@@ -119,24 +94,4 @@ public class BlockedNumbersSettingsActivity extends AppCompatActivity
super.onBackPressed();
}
}
-
- @Override
- public boolean isActionBarShowing() {
- return false;
- }
-
- @Override
- public boolean isDialpadShown() {
- return false;
- }
-
- @Override
- public int getDialpadHeight() {
- return 0;
- }
-
- @Override
- public int getActionBarHeight() {
- return 0;
- }
}
diff --git a/java/com/android/dialer/app/legacybindings/DialerLegacyBindings.java b/java/com/android/dialer/app/legacybindings/DialerLegacyBindings.java
index a483af9e9..6eaa2b6b9 100644
--- a/java/com/android/dialer/app/legacybindings/DialerLegacyBindings.java
+++ b/java/com/android/dialer/app/legacybindings/DialerLegacyBindings.java
@@ -22,7 +22,6 @@ import android.view.ViewGroup;
import com.android.dialer.app.calllog.CallLogAdapter;
import com.android.dialer.app.calllog.calllogcache.CallLogCache;
import com.android.dialer.app.contactinfo.ContactInfoCache;
-import com.android.dialer.app.list.RegularSearchFragment;
import com.android.dialer.app.voicemail.VoicemailPlaybackPresenter;
import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
@@ -47,6 +46,4 @@ public interface DialerLegacyBindings {
VoicemailPlaybackPresenter voicemailPlaybackPresenter,
@NonNull FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler,
int activityType);
-
- RegularSearchFragment newRegularSearchFragment();
}
diff --git a/java/com/android/dialer/app/legacybindings/DialerLegacyBindingsStub.java b/java/com/android/dialer/app/legacybindings/DialerLegacyBindingsStub.java
index 488fbad68..e95c4709d 100644
--- a/java/com/android/dialer/app/legacybindings/DialerLegacyBindingsStub.java
+++ b/java/com/android/dialer/app/legacybindings/DialerLegacyBindingsStub.java
@@ -22,7 +22,6 @@ import android.view.ViewGroup;
import com.android.dialer.app.calllog.CallLogAdapter;
import com.android.dialer.app.calllog.calllogcache.CallLogCache;
import com.android.dialer.app.contactinfo.ContactInfoCache;
-import com.android.dialer.app.list.RegularSearchFragment;
import com.android.dialer.app.voicemail.VoicemailPlaybackPresenter;
import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
@@ -53,9 +52,4 @@ public class DialerLegacyBindingsStub implements DialerLegacyBindings {
filteredNumberAsyncQueryHandler,
activityType);
}
-
- @Override
- public RegularSearchFragment newRegularSearchFragment() {
- return new RegularSearchFragment();
- }
}
diff --git a/java/com/android/dialer/app/list/AllContactsFragment.java b/java/com/android/dialer/app/list/AllContactsFragment.java
deleted file mode 100644
index 5076fd9cf..000000000
--- a/java/com/android/dialer/app/list/AllContactsFragment.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2013 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.dialer.app.list;
-
-import static android.Manifest.permission.READ_CONTACTS;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.Loader;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.QuickContact;
-import android.support.v13.app.FragmentCompat;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import com.android.contacts.common.list.ContactEntryListAdapter;
-import com.android.contacts.common.list.ContactEntryListFragment;
-import com.android.contacts.common.list.ContactListFilter;
-import com.android.contacts.common.list.DefaultContactListAdapter;
-import com.android.dialer.app.R;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.compat.CompatUtils;
-import com.android.dialer.logging.InteractionEvent;
-import com.android.dialer.logging.Logger;
-import com.android.dialer.util.DialerUtils;
-import com.android.dialer.util.IntentUtil;
-import com.android.dialer.util.PermissionsUtil;
-import com.android.dialer.widget.EmptyContentView;
-import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener;
-import java.util.Arrays;
-
-/** Fragments to show all contacts with phone numbers. */
-public class AllContactsFragment extends ContactEntryListFragment<ContactEntryListAdapter>
- implements OnEmptyViewActionButtonClickedListener,
- FragmentCompat.OnRequestPermissionsResultCallback {
-
- private static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 1;
-
- private EmptyContentView emptyListView;
-
- /**
- * Listen to broadcast events about permissions in order to be notified if the READ_CONTACTS
- * permission is granted via the UI in another fragment.
- */
- private BroadcastReceiver readContactsPermissionGrantedReceiver =
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- reloadData();
- }
- };
-
- public AllContactsFragment() {
- setQuickContactEnabled(false);
- setAdjustSelectionBoundsEnabled(true);
- setPhotoLoaderEnabled(true);
- setSectionHeaderDisplayEnabled(true);
- setDarkTheme(false);
- setVisibleScrollbarEnabled(true);
- }
-
- @Override
- public void onViewCreated(View view, android.os.Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- emptyListView = (EmptyContentView) view.findViewById(R.id.empty_list_view);
- emptyListView.setImage(R.drawable.empty_contacts);
- emptyListView.setDescription(R.string.all_contacts_empty);
- emptyListView.setActionClickedListener(this);
- getListView().setEmptyView(emptyListView);
- emptyListView.setVisibility(View.GONE);
- }
-
- @Override
- public void onStart() {
- super.onStart();
- PermissionsUtil.registerPermissionReceiver(
- getActivity(), readContactsPermissionGrantedReceiver, READ_CONTACTS);
- }
-
- @Override
- public void onStop() {
- PermissionsUtil.unregisterPermissionReceiver(
- getActivity(), readContactsPermissionGrantedReceiver);
- super.onStop();
- }
-
- @Override
- protected void startLoading() {
- if (PermissionsUtil.hasPermission(getActivity(), READ_CONTACTS)) {
- super.startLoading();
- emptyListView.setDescription(R.string.all_contacts_empty);
- emptyListView.setActionLabel(R.string.all_contacts_empty_add_contact_action);
- } else {
- emptyListView.setDescription(R.string.permission_no_contacts);
- emptyListView.setActionLabel(R.string.permission_single_turn_on);
- emptyListView.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- super.onLoadFinished(loader, data);
-
- if (data == null || data.getCount() == 0) {
- emptyListView.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- protected ContactEntryListAdapter createListAdapter() {
- final DefaultContactListAdapter adapter =
- new DefaultContactListAdapter(getActivity()) {
- @Override
- protected void bindView(View itemView, int partition, Cursor cursor, int position) {
- super.bindView(itemView, partition, cursor, position);
- itemView.setTag(this.getContactUri(partition, cursor));
- }
- };
- adapter.setDisplayPhotos(true);
- adapter.setFilter(
- ContactListFilter.createFilterWithType(ContactListFilter.FILTER_TYPE_DEFAULT));
- adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
- return adapter;
- }
-
- @Override
- protected View inflateView(LayoutInflater inflater, ViewGroup container) {
- return inflater.inflate(R.layout.all_contacts_fragment, null);
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- final Uri uri = (Uri) view.getTag();
- if (uri != null) {
- Logger.get(getContext())
- .logInteraction(InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_ALL_CONTACTS_GENERAL);
- if (CompatUtils.hasPrioritizedMimeType()) {
- QuickContact.showQuickContact(getContext(), view, uri, null, Phone.CONTENT_ITEM_TYPE);
- } else {
- QuickContact.showQuickContact(getActivity(), view, uri, QuickContact.MODE_LARGE, null);
- }
- }
- }
-
- @Override
- protected void onItemClick(int position, long id) {
- // Do nothing. Implemented to satisfy ContactEntryListFragment.
- }
-
- @Override
- public void onEmptyViewActionButtonClicked() {
- final Activity activity = getActivity();
- if (activity == null) {
- return;
- }
-
- String[] deniedPermissions =
- PermissionsUtil.getPermissionsCurrentlyDenied(
- getContext(), PermissionsUtil.allContactsGroupPermissionsUsedInDialer);
- if (deniedPermissions.length > 0) {
- LogUtil.i(
- "AllContactsFragment.onEmptyViewActionButtonClicked",
- "Requesting permissions: " + Arrays.toString(deniedPermissions));
- FragmentCompat.requestPermissions(
- this, deniedPermissions, READ_CONTACTS_PERMISSION_REQUEST_CODE);
- } else {
- // Add new contact
- DialerUtils.startActivityWithErrorToast(
- activity, IntentUtil.getNewContactIntent(), R.string.add_contact_not_available);
- }
- }
-
- @Override
- public void onRequestPermissionsResult(
- int requestCode, String[] permissions, int[] grantResults) {
- if (requestCode == READ_CONTACTS_PERMISSION_REQUEST_CODE) {
- if (grantResults.length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) {
- // Force a refresh of the data since we were missing the permission before this.
- reloadData();
- }
- }
- }
-}
diff --git a/java/com/android/dialer/app/list/BlockedListSearchAdapter.java b/java/com/android/dialer/app/list/BlockedListSearchAdapter.java
deleted file mode 100644
index 575d6e63f..000000000
--- a/java/com/android/dialer/app/list/BlockedListSearchAdapter.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2015 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.dialer.app.list;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.view.View;
-import com.android.contacts.common.list.ContactListItemView;
-import com.android.dialer.app.R;
-import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
-import com.android.dialer.location.GeoUtil;
-
-/** List adapter to display search results for adding a blocked number. */
-public class BlockedListSearchAdapter extends RegularSearchListAdapter {
-
- private Resources resources;
- private FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler;
-
- public BlockedListSearchAdapter(Context context) {
- super(context);
- resources = context.getResources();
- disableAllShortcuts();
- setShortcutEnabled(SHORTCUT_BLOCK_NUMBER, true);
-
- filteredNumberAsyncQueryHandler = new FilteredNumberAsyncQueryHandler(context);
- }
-
- @Override
- protected boolean isChanged(boolean showNumberShortcuts) {
- return setShortcutEnabled(SHORTCUT_BLOCK_NUMBER, showNumberShortcuts || isQuerySipAddress);
- }
-
- public void setViewBlocked(ContactListItemView view, Integer id) {
- view.setTag(R.id.block_id, id);
- final int textColor = resources.getColor(R.color.blocked_number_block_color);
- view.getDataView().setTextColor(textColor);
- view.getLabelView().setTextColor(textColor);
- //TODO: Add icon
- }
-
- public void setViewUnblocked(ContactListItemView view) {
- view.setTag(R.id.block_id, null);
- final int textColor = resources.getColor(R.color.dialer_secondary_text_color);
- view.getDataView().setTextColor(textColor);
- view.getLabelView().setTextColor(textColor);
- //TODO: Remove icon
- }
-
- @Override
- protected void bindView(View itemView, int partition, Cursor cursor, int position) {
- super.bindView(itemView, partition, cursor, position);
-
- final ContactListItemView view = (ContactListItemView) itemView;
- // Reset view state to unblocked.
- setViewUnblocked(view);
-
- final String number = getPhoneNumber(position);
- final String countryIso = GeoUtil.getCurrentCountryIso(mContext);
- final FilteredNumberAsyncQueryHandler.OnCheckBlockedListener onCheckListener =
- new FilteredNumberAsyncQueryHandler.OnCheckBlockedListener() {
- @Override
- public void onCheckComplete(Integer id) {
- if (id != null && id != FilteredNumberAsyncQueryHandler.INVALID_ID) {
- setViewBlocked(view, id);
- }
- }
- };
- filteredNumberAsyncQueryHandler.isBlockedNumber(onCheckListener, number, countryIso);
- }
-}
diff --git a/java/com/android/dialer/app/list/BlockedListSearchFragment.java b/java/com/android/dialer/app/list/BlockedListSearchFragment.java
deleted file mode 100644
index ce812af6e..000000000
--- a/java/com/android/dialer/app/list/BlockedListSearchFragment.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2015 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.dialer.app.list;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.util.TypedValue;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.EditText;
-import android.widget.Toast;
-import com.android.contacts.common.list.ContactEntryListAdapter;
-import com.android.contacts.common.util.ContactDisplayUtils;
-import com.android.dialer.app.R;
-import com.android.dialer.app.widget.SearchEditTextLayout;
-import com.android.dialer.blocking.BlockNumberDialogFragment;
-import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
-import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler.OnCheckBlockedListener;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.location.GeoUtil;
-import com.android.dialer.logging.InteractionEvent;
-import com.android.dialer.logging.Logger;
-import com.android.dialer.phonenumberutil.PhoneNumberHelper;
-
-/** TODO(calderwoodra): documentation */
-public class BlockedListSearchFragment extends RegularSearchFragment
- implements BlockNumberDialogFragment.Callback {
-
- private final TextWatcher phoneSearchQueryTextListener =
- new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- setQueryString(s.toString());
- }
-
- @Override
- public void afterTextChanged(Editable s) {}
- };
- private final SearchEditTextLayout.Callback searchLayoutCallback =
- new SearchEditTextLayout.Callback() {
- @Override
- public void onBackButtonClicked() {
- getActivity().onBackPressed();
- }
-
- @Override
- public void onSearchViewClicked() {}
- };
- private FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler;
- private EditText searchView;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setShowEmptyListForNullQuery(true);
- /*
- * Pass in the empty string here so ContactEntryListFragment#setQueryString interprets it as
- * an empty search query, rather than as an uninitalized value. In the latter case, the
- * adapter returned by #createListAdapter is used, which populates the view with contacts.
- * Passing in the empty string forces ContactEntryListFragment to interpret it as an empty
- * query, which results in showing an empty view
- */
- setQueryString(getQueryString() == null ? "" : getQueryString());
- filteredNumberAsyncQueryHandler = new FilteredNumberAsyncQueryHandler(getContext());
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
- actionBar.setCustomView(R.layout.search_edittext);
- actionBar.setDisplayShowCustomEnabled(true);
- actionBar.setDisplayHomeAsUpEnabled(false);
- actionBar.setDisplayShowHomeEnabled(false);
-
- final SearchEditTextLayout searchEditTextLayout =
- (SearchEditTextLayout) actionBar.getCustomView().findViewById(R.id.search_view_container);
- searchEditTextLayout.expand(false, true);
- searchEditTextLayout.setCallback(searchLayoutCallback);
- searchEditTextLayout.setBackgroundDrawable(null);
-
- searchView = (EditText) searchEditTextLayout.findViewById(R.id.search_view);
- searchView.addTextChangedListener(phoneSearchQueryTextListener);
- searchView.setHint(R.string.block_number_search_hint);
-
- searchEditTextLayout
- .findViewById(R.id.search_box_expanded)
- .setBackgroundColor(getContext().getResources().getColor(android.R.color.white));
-
- if (!TextUtils.isEmpty(getQueryString())) {
- searchView.setText(getQueryString());
- }
-
- // TODO: Don't set custom text size; use default search text size.
- searchView.setTextSize(
- TypedValue.COMPLEX_UNIT_PX,
- getResources().getDimension(R.dimen.blocked_number_search_text_size));
- }
-
- @Override
- protected ContactEntryListAdapter createListAdapter() {
- BlockedListSearchAdapter adapter = new BlockedListSearchAdapter(getActivity());
- adapter.setDisplayPhotos(true);
- // Don't show SIP addresses.
- adapter.setUseCallableUri(false);
- // Keep in sync with the queryString set in #onCreate
- adapter.setQueryString(getQueryString() == null ? "" : getQueryString());
- return adapter;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- super.onItemClick(parent, view, position, id);
- final int adapterPosition = position - getListView().getHeaderViewsCount();
- final BlockedListSearchAdapter adapter = (BlockedListSearchAdapter) getAdapter();
- final int shortcutType = adapter.getShortcutTypeFromPosition(adapterPosition);
- final Integer blockId = (Integer) view.getTag(R.id.block_id);
- final String number;
- switch (shortcutType) {
- case DialerPhoneNumberListAdapter.SHORTCUT_INVALID:
- // Handles click on a search result, either contact or nearby places result.
- number = adapter.getPhoneNumber(adapterPosition);
- blockContactNumber(number, blockId);
- break;
- case DialerPhoneNumberListAdapter.SHORTCUT_BLOCK_NUMBER:
- // Handles click on 'Block number' shortcut to add the user query as a number.
- number = adapter.getQueryString();
- blockNumber(number);
- break;
- default:
- LogUtil.w(
- "BlockedListSearchFragment.onItemClick",
- "ignoring unsupported shortcut type: " + shortcutType);
- break;
- }
- }
-
- @Override
- protected void onItemClick(int position, long id) {
- // Prevent SearchFragment.onItemClicked from being called.
- }
-
- private void blockNumber(final String number) {
- final String countryIso = GeoUtil.getCurrentCountryIso(getContext());
- final OnCheckBlockedListener onCheckListener =
- new OnCheckBlockedListener() {
- @Override
- public void onCheckComplete(Integer id) {
- if (id == null) {
- BlockNumberDialogFragment.show(
- id,
- number,
- countryIso,
- PhoneNumberHelper.formatNumber(getContext(), number, countryIso),
- R.id.blocked_numbers_activity_container,
- getFragmentManager(),
- BlockedListSearchFragment.this);
- } else if (id == FilteredNumberAsyncQueryHandler.INVALID_ID) {
- Toast.makeText(
- getContext(),
- ContactDisplayUtils.getTtsSpannedPhoneNumber(
- getResources(), R.string.invalidNumber, number),
- Toast.LENGTH_SHORT)
- .show();
- } else {
- Toast.makeText(
- getContext(),
- ContactDisplayUtils.getTtsSpannedPhoneNumber(
- getResources(), R.string.alreadyBlocked, number),
- Toast.LENGTH_SHORT)
- .show();
- }
- }
- };
- filteredNumberAsyncQueryHandler.isBlockedNumber(onCheckListener, number, countryIso);
- }
-
- @Override
- public void onFilterNumberSuccess() {
- Logger.get(getContext()).logInteraction(InteractionEvent.Type.BLOCK_NUMBER_MANAGEMENT_SCREEN);
- goBack();
- }
-
- @Override
- public void onUnfilterNumberSuccess() {
- LogUtil.e(
- "BlockedListSearchFragment.onUnfilterNumberSuccess",
- "unblocked a number from the BlockedListSearchFragment");
- goBack();
- }
-
- private void goBack() {
- Activity activity = getActivity();
- if (activity == null) {
- return;
- }
- activity.onBackPressed();
- }
-
- @Override
- public void onChangeFilteredNumberUndo() {
- getAdapter().notifyDataSetChanged();
- }
-
- private void blockContactNumber(final String number, final Integer blockId) {
- if (blockId != null) {
- Toast.makeText(
- getContext(),
- ContactDisplayUtils.getTtsSpannedPhoneNumber(
- getResources(), R.string.alreadyBlocked, number),
- Toast.LENGTH_SHORT)
- .show();
- return;
- }
-
- BlockNumberDialogFragment.show(
- blockId,
- number,
- GeoUtil.getCurrentCountryIso(getContext()),
- number,
- R.id.blocked_numbers_activity_container,
- getFragmentManager(),
- this);
- }
-}
diff --git a/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java b/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java
deleted file mode 100644
index d5609b856..000000000
--- a/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2016 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.dialer.app.list;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.drawable.Drawable;
-import android.support.v4.content.ContextCompat;
-import android.telephony.PhoneNumberUtils;
-import android.text.BidiFormatter;
-import android.text.TextDirectionHeuristics;
-import android.view.View;
-import android.view.ViewGroup;
-import com.android.contacts.common.list.ContactListItemView;
-import com.android.contacts.common.list.PhoneNumberListAdapter;
-import com.android.contacts.common.util.ContactDisplayUtils;
-import com.android.dialer.app.R;
-import com.android.dialer.location.GeoUtil;
-import com.android.dialer.phonenumberutil.PhoneNumberHelper;
-
-/**
- * {@link PhoneNumberListAdapter} with the following added shortcuts, that are displayed as list
- * items: 1) Directly calling the phone number query 2) Adding the phone number query to a contact
- *
- * <p>These shortcuts can be enabled or disabled to toggle whether or not they show up in the list.
- */
-public class DialerPhoneNumberListAdapter extends PhoneNumberListAdapter {
-
- public static final int SHORTCUT_INVALID = -1;
- public static final int SHORTCUT_DIRECT_CALL = 0;
- public static final int SHORTCUT_CREATE_NEW_CONTACT = 1;
- public static final int SHORTCUT_ADD_TO_EXISTING_CONTACT = 2;
- public static final int SHORTCUT_SEND_SMS_MESSAGE = 3;
- public static final int SHORTCUT_MAKE_VIDEO_CALL = 4;
- public static final int SHORTCUT_BLOCK_NUMBER = 5;
- public static final int SHORTCUT_COUNT = 6;
-
- private final boolean[] shortcutEnabled = new boolean[SHORTCUT_COUNT];
- private final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
- private final String countryIso;
-
- private String formattedQueryString;
-
- public DialerPhoneNumberListAdapter(Context context) {
- super(context);
-
- countryIso = GeoUtil.getCurrentCountryIso(context);
- }
-
- @Override
- public int getCount() {
- return super.getCount() + getShortcutCount();
- }
-
- /** @return The number of enabled shortcuts. Ranges from 0 to a maximum of SHORTCUT_COUNT */
- public int getShortcutCount() {
- int count = 0;
- for (int i = 0; i < shortcutEnabled.length; i++) {
- if (shortcutEnabled[i]) {
- count++;
- }
- }
- return count;
- }
-
- public void disableAllShortcuts() {
- for (int i = 0; i < shortcutEnabled.length; i++) {
- shortcutEnabled[i] = false;
- }
- }
-
- @Override
- public int getItemViewType(int position) {
- final int shortcut = getShortcutTypeFromPosition(position);
- if (shortcut >= 0) {
- // shortcutPos should always range from 1 to SHORTCUT_COUNT
- return super.getViewTypeCount() + shortcut;
- } else {
- return super.getItemViewType(position);
- }
- }
-
- @Override
- public int getViewTypeCount() {
- // Number of item view types in the super implementation + 2 for the 2 new shortcuts
- return super.getViewTypeCount() + SHORTCUT_COUNT;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final int shortcutType = getShortcutTypeFromPosition(position);
- if (shortcutType >= 0) {
- if (convertView != null) {
- assignShortcutToView((ContactListItemView) convertView, shortcutType);
- return convertView;
- } else {
- final ContactListItemView v =
- new ContactListItemView(getContext(), null, mIsImsVideoEnabled);
- assignShortcutToView(v, shortcutType);
- return v;
- }
- } else {
- return super.getView(position, convertView, parent);
- }
- }
-
- @Override
- protected ContactListItemView newView(
- Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
- final ContactListItemView view = super.newView(context, partition, cursor, position, parent);
-
- view.setSupportVideoCallIcon(mIsImsVideoEnabled);
- return view;
- }
-
- /**
- * @param position The position of the item
- * @return The enabled shortcut type matching the given position if the item is a shortcut, -1
- * otherwise
- */
- public int getShortcutTypeFromPosition(int position) {
- int shortcutCount = position - super.getCount();
- if (shortcutCount >= 0) {
- // Iterate through the array of shortcuts, looking only for shortcuts where
- // mShortcutEnabled[i] is true
- for (int i = 0; shortcutCount >= 0 && i < shortcutEnabled.length; i++) {
- if (shortcutEnabled[i]) {
- shortcutCount--;
- if (shortcutCount < 0) {
- return i;
- }
- }
- }
- throw new IllegalArgumentException(
- "Invalid position - greater than cursor count " + " but not a shortcut.");
- }
- return SHORTCUT_INVALID;
- }
-
- @Override
- public boolean isEmpty() {
- return getShortcutCount() == 0 && super.isEmpty();
- }
-
- @Override
- public boolean isEnabled(int position) {
- final int shortcutType = getShortcutTypeFromPosition(position);
- if (shortcutType >= 0) {
- return true;
- } else {
- return super.isEnabled(position);
- }
- }
-
- private void assignShortcutToView(ContactListItemView v, int shortcutType) {
- final CharSequence text;
- final Drawable drawable;
- final Resources resources = getContext().getResources();
- final String number = getFormattedQueryString();
- switch (shortcutType) {
- case SHORTCUT_DIRECT_CALL:
- text =
- ContactDisplayUtils.getTtsSpannedPhoneNumber(
- resources,
- R.string.search_shortcut_call_number,
- bidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR));
- drawable = ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_call_vd_theme_24);
- break;
- case SHORTCUT_CREATE_NEW_CONTACT:
- text = resources.getString(R.string.search_shortcut_create_new_contact);
- drawable =
- ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_person_add_vd_theme_24);
- drawable.setAutoMirrored(true);
- break;
- case SHORTCUT_ADD_TO_EXISTING_CONTACT:
- text = resources.getString(R.string.search_shortcut_add_to_contact);
- drawable =
- ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_person_add_vd_theme_24);
- break;
- case SHORTCUT_SEND_SMS_MESSAGE:
- text = resources.getString(R.string.search_shortcut_send_sms_message);
- drawable =
- ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_message_vd_theme_24);
- break;
- case SHORTCUT_MAKE_VIDEO_CALL:
- text = resources.getString(R.string.search_shortcut_make_video_call);
- drawable =
- ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_videocam_vd_theme_24);
- break;
- case SHORTCUT_BLOCK_NUMBER:
- text = resources.getString(R.string.search_shortcut_block_number);
- drawable =
- ContextCompat.getDrawable(getContext(), R.drawable.ic_not_interested_googblue_24dp);
- break;
- default:
- throw new IllegalArgumentException("Invalid shortcut type");
- }
- v.setDrawable(drawable);
- v.setDisplayName(text);
- v.setAdjustSelectionBoundsEnabled(false);
- }
-
- /** @return True if the shortcut state (disabled vs enabled) was changed by this operation */
- public boolean setShortcutEnabled(int shortcutType, boolean visible) {
- final boolean changed = shortcutEnabled[shortcutType] != visible;
- shortcutEnabled[shortcutType] = visible;
- return changed;
- }
-
- public String getFormattedQueryString() {
- return formattedQueryString;
- }
-
- @Override
- public void setQueryString(String queryString) {
- formattedQueryString =
- PhoneNumberHelper.formatNumber(
- getContext(), PhoneNumberUtils.normalizeNumber(queryString), countryIso);
- super.setQueryString(queryString);
- }
-}
diff --git a/java/com/android/dialer/app/list/DialtactsPagerAdapter.java b/java/com/android/dialer/app/list/DialtactsPagerAdapter.java
index d27293244..364ae6fad 100644
--- a/java/com/android/dialer/app/list/DialtactsPagerAdapter.java
+++ b/java/com/android/dialer/app/list/DialtactsPagerAdapter.java
@@ -56,11 +56,9 @@ public class DialtactsPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragments = new ArrayList<>();
private final String[] tabTitles;
private final boolean useNewSpeedDialTab;
- private final boolean useNewContactsTab;
private OldSpeedDialFragment oldSpeedDialFragment;
private SpeedDialFragment speedDialFragment;
private CallLogFragment callLogFragment;
- private AllContactsFragment oldContactsFragment;
private ContactsFragment contactsFragment;
private CallLogFragment voicemailFragment;
@@ -71,8 +69,6 @@ public class DialtactsPagerAdapter extends FragmentPagerAdapter {
super(fm);
useNewSpeedDialTab =
ConfigProviderBindings.get(context).getBoolean("enable_new_favorites_tab", false);
- useNewContactsTab =
- ConfigProviderBindings.get(context).getBoolean("enable_new_contacts_tab", true);
this.tabTitles = tabTitles;
hasActiveVoicemailProvider = hasVoicemailProvider;
fragments.addAll(Collections.nCopies(TAB_COUNT_WITH_VOICEMAIL, null));
@@ -105,17 +101,10 @@ public class DialtactsPagerAdapter extends FragmentPagerAdapter {
}
return callLogFragment;
case TAB_INDEX_ALL_CONTACTS:
- if (useNewContactsTab) {
- if (contactsFragment == null) {
- contactsFragment = ContactsFragment.newInstance(Header.ADD_CONTACT);
- }
- return contactsFragment;
- } else {
- if (oldContactsFragment == null) {
- oldContactsFragment = new AllContactsFragment();
- }
- return oldContactsFragment;
+ if (contactsFragment == null) {
+ contactsFragment = ContactsFragment.newInstance(Header.ADD_CONTACT);
}
+ return contactsFragment;
case TAB_INDEX_VOICEMAIL:
if (voicemailFragment == null) {
voicemailFragment = new VisualVoicemailCallLogFragment();
@@ -145,8 +134,6 @@ public class DialtactsPagerAdapter extends FragmentPagerAdapter {
callLogFragment = (CallLogFragment) fragment;
} else if (fragment instanceof ContactsFragment) {
contactsFragment = (ContactsFragment) fragment;
- } else if (fragment instanceof AllContactsFragment) {
- oldContactsFragment = (AllContactsFragment) fragment;
} else if (fragment instanceof CallLogFragment && position == TAB_INDEX_VOICEMAIL) {
voicemailFragment = (CallLogFragment) fragment;
LogUtil.v("ViewPagerAdapter.instantiateItem", voicemailFragment.toString());
diff --git a/java/com/android/dialer/app/list/RegularSearchFragment.java b/java/com/android/dialer/app/list/RegularSearchFragment.java
deleted file mode 100644
index d1927f08a..000000000
--- a/java/com/android/dialer/app/list/RegularSearchFragment.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2013 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.dialer.app.list;
-
-import static android.Manifest.permission.READ_CONTACTS;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v13.app.FragmentCompat;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-import com.android.contacts.common.list.ContactEntryListAdapter;
-import com.android.contacts.common.list.PinnedHeaderListView;
-import com.android.dialer.app.R;
-import com.android.dialer.callintent.CallInitiationType;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.concurrent.DialerExecutor;
-import com.android.dialer.common.concurrent.DialerExecutor.Worker;
-import com.android.dialer.common.concurrent.DialerExecutorComponent;
-import com.android.dialer.phonenumbercache.CachedNumberLookupService;
-import com.android.dialer.phonenumbercache.CachedNumberLookupService.CachedContactInfo;
-import com.android.dialer.phonenumbercache.PhoneNumberCache;
-import com.android.dialer.util.PermissionsUtil;
-import com.android.dialer.widget.EmptyContentView;
-import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener;
-import java.util.Arrays;
-
-public class RegularSearchFragment extends SearchFragment
- implements OnEmptyViewActionButtonClickedListener,
- FragmentCompat.OnRequestPermissionsResultCallback {
-
- public static final int PERMISSION_REQUEST_CODE = 1;
-
- private static final int SEARCH_DIRECTORY_RESULT_LIMIT = 5;
- protected String permissionToRequest;
-
- private DialerExecutor<CachedContactInfo> addContactTask;
-
- public RegularSearchFragment() {
- configureDirectorySearch();
- }
-
- public void configureDirectorySearch() {
- setDirectorySearchEnabled(true);
- setDirectoryResultLimit(SEARCH_DIRECTORY_RESULT_LIMIT);
- }
-
- @Override
- public void onCreate(Bundle savedState) {
- super.onCreate(savedState);
-
- addContactTask =
- DialerExecutorComponent.get(getContext())
- .dialerExecutorFactory()
- .createUiTaskBuilder(
- getFragmentManager(),
- "RegularSearchFragment.addContact",
- new AddContactWorker(getContext().getApplicationContext()))
- .build();
- }
-
- @Override
- protected void onCreateView(LayoutInflater inflater, ViewGroup container) {
- super.onCreateView(inflater, container);
- ((PinnedHeaderListView) getListView()).setScrollToSectionOnHeaderTouch(true);
- }
-
- @Override
- protected ContactEntryListAdapter createListAdapter() {
- RegularSearchListAdapter adapter = new RegularSearchListAdapter(getActivity());
- adapter.setDisplayPhotos(true);
- adapter.setUseCallableUri(usesCallableUri());
- adapter.setListener(this);
- return adapter;
- }
-
- @Override
- protected void cacheContactInfo(int position) {
- CachedNumberLookupService cachedNumberLookupService =
- PhoneNumberCache.get(getContext()).getCachedNumberLookupService();
- if (cachedNumberLookupService != null) {
- final RegularSearchListAdapter adapter = (RegularSearchListAdapter) getAdapter();
- CachedContactInfo cachedContactInfo =
- adapter.getContactInfo(cachedNumberLookupService, position);
- addContactTask.executeSerial(cachedContactInfo);
- }
- }
-
- @Override
- protected void setupEmptyView() {
- if (emptyView != null && getActivity() != null) {
- final int imageResource;
- final int actionLabelResource;
- final int descriptionResource;
- final OnEmptyViewActionButtonClickedListener listener;
- if (!PermissionsUtil.hasPermission(getActivity(), READ_CONTACTS)) {
- imageResource = R.drawable.empty_contacts;
- actionLabelResource = R.string.permission_single_turn_on;
- descriptionResource = R.string.permission_no_search;
- listener = this;
- permissionToRequest = READ_CONTACTS;
- } else {
- imageResource = EmptyContentView.NO_IMAGE;
- actionLabelResource = EmptyContentView.NO_LABEL;
- descriptionResource = EmptyContentView.NO_LABEL;
- listener = null;
- permissionToRequest = null;
- }
-
- emptyView.setImage(imageResource);
- emptyView.setActionLabel(actionLabelResource);
- emptyView.setDescription(descriptionResource);
- if (listener != null) {
- emptyView.setActionClickedListener(listener);
- }
- }
- }
-
- @Override
- public void onEmptyViewActionButtonClicked() {
- final Activity activity = getActivity();
- if (activity == null) {
- return;
- }
-
- if (READ_CONTACTS.equals(permissionToRequest)) {
- String[] deniedPermissions =
- PermissionsUtil.getPermissionsCurrentlyDenied(
- getContext(), PermissionsUtil.allContactsGroupPermissionsUsedInDialer);
- if (deniedPermissions.length > 0) {
- LogUtil.i(
- "RegularSearchFragment.onEmptyViewActionButtonClicked",
- "Requesting permissions: " + Arrays.toString(deniedPermissions));
- FragmentCompat.requestPermissions(this, deniedPermissions, PERMISSION_REQUEST_CODE);
- }
- }
- }
-
- @Override
- public void onRequestPermissionsResult(
- int requestCode, String[] permissions, int[] grantResults) {
- if (requestCode == PERMISSION_REQUEST_CODE) {
- setupEmptyView();
- if (grantResults != null
- && grantResults.length == 1
- && PackageManager.PERMISSION_GRANTED == grantResults[0]) {
- PermissionsUtil.notifyPermissionGranted(getActivity(), permissions[0]);
- }
- }
- }
-
- @Override
- protected CallInitiationType.Type getCallInitiationType(boolean isRemoteDirectory) {
- return isRemoteDirectory
- ? CallInitiationType.Type.REMOTE_DIRECTORY
- : CallInitiationType.Type.REGULAR_SEARCH;
- }
-
- public interface CapabilityChecker {
-
- boolean isNearbyPlacesSearchEnabled();
- }
-
- private static class AddContactWorker implements Worker<CachedContactInfo, Void> {
-
- private final Context appContext;
-
- private AddContactWorker(Context appContext) {
- this.appContext = appContext;
- }
-
- @Nullable
- @Override
- public Void doInBackground(@Nullable CachedContactInfo contactInfo) throws Throwable {
- CachedNumberLookupService cachedNumberLookupService =
- PhoneNumberCache.get(appContext).getCachedNumberLookupService();
- if (cachedNumberLookupService != null) {
- cachedNumberLookupService.addContact(appContext, contactInfo);
- }
- return null;
- }
- }
-}
diff --git a/java/com/android/dialer/app/list/RegularSearchListAdapter.java b/java/com/android/dialer/app/list/RegularSearchListAdapter.java
deleted file mode 100644
index c92f48c8b..000000000
--- a/java/com/android/dialer/app/list/RegularSearchListAdapter.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2013 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.dialer.app.list;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.text.TextUtils;
-import com.android.contacts.common.ContactsUtils;
-import com.android.contacts.common.list.DirectoryPartition;
-import com.android.dialer.common.cp2.DirectoryCompat;
-import com.android.dialer.phonenumbercache.CachedNumberLookupService;
-import com.android.dialer.phonenumbercache.CachedNumberLookupService.CachedContactInfo;
-import com.android.dialer.phonenumbercache.ContactInfo;
-import com.android.dialer.phonenumberutil.PhoneNumberHelper;
-import com.android.dialer.util.CallUtil;
-
-/** List adapter to display regular search results. */
-public class RegularSearchListAdapter extends DialerPhoneNumberListAdapter {
-
- protected boolean isQuerySipAddress;
-
- public RegularSearchListAdapter(Context context) {
- super(context);
- setShortcutEnabled(SHORTCUT_CREATE_NEW_CONTACT, false);
- setShortcutEnabled(SHORTCUT_ADD_TO_EXISTING_CONTACT, false);
- }
-
- public CachedContactInfo getContactInfo(CachedNumberLookupService lookupService, int position) {
- ContactInfo info = new ContactInfo();
- CachedContactInfo cacheInfo = lookupService.buildCachedContactInfo(info);
- final Cursor item = (Cursor) getItem(position);
- if (item != null) {
- final DirectoryPartition partition =
- (DirectoryPartition) getPartition(getPartitionForPosition(position));
- final long directoryId = partition.getDirectoryId();
- final boolean isExtendedDirectory = isExtendedDirectory(directoryId);
-
- info.name = item.getString(PhoneQuery.DISPLAY_NAME);
- info.type = item.getInt(PhoneQuery.PHONE_TYPE);
- info.label = item.getString(PhoneQuery.PHONE_LABEL);
- info.number = item.getString(PhoneQuery.PHONE_NUMBER);
- final String photoUriStr = item.getString(PhoneQuery.PHOTO_URI);
- info.photoUri = photoUriStr == null ? null : Uri.parse(photoUriStr);
- /*
- * An extended directory is custom directory in the app, but not a directory provided by
- * framework. So it can't be USER_TYPE_WORK.
- *
- * When a search result is selected, RegularSearchFragment calls getContactInfo and
- * cache the resulting @{link ContactInfo} into local db. Set usertype to USER_TYPE_WORK
- * only if it's NOT extended directory id and is enterprise directory.
- */
- info.userType =
- !isExtendedDirectory && DirectoryCompat.isEnterpriseDirectoryId(directoryId)
- ? ContactsUtils.USER_TYPE_WORK
- : ContactsUtils.USER_TYPE_CURRENT;
-
- cacheInfo.setLookupKey(item.getString(PhoneQuery.LOOKUP_KEY));
-
- final String sourceName = partition.getLabel();
- if (isExtendedDirectory) {
- cacheInfo.setExtendedSource(sourceName, directoryId);
- } else {
- cacheInfo.setDirectorySource(sourceName, directoryId);
- }
- }
- return cacheInfo;
- }
-
- @Override
- public String getFormattedQueryString() {
- if (isQuerySipAddress) {
- // Return unnormalized SIP address
- return getQueryString();
- }
- return super.getFormattedQueryString();
- }
-
- @Override
- public void setQueryString(String queryString) {
- // Don't show actions if the query string contains a letter.
- final boolean showNumberShortcuts =
- !TextUtils.isEmpty(getFormattedQueryString()) && hasDigitsInQueryString();
- isQuerySipAddress = PhoneNumberHelper.isUriNumber(queryString);
-
- if (isChanged(showNumberShortcuts)) {
- notifyDataSetChanged();
- }
- super.setQueryString(queryString);
- }
-
- protected boolean isChanged(boolean showNumberShortcuts) {
- boolean changed = false;
- changed |= setShortcutEnabled(SHORTCUT_DIRECT_CALL, showNumberShortcuts || isQuerySipAddress);
- changed |= setShortcutEnabled(SHORTCUT_SEND_SMS_MESSAGE, showNumberShortcuts);
- changed |=
- setShortcutEnabled(
- SHORTCUT_MAKE_VIDEO_CALL, showNumberShortcuts && CallUtil.isVideoEnabled(getContext()));
- return changed;
- }
-
- /** Whether there is at least one digit in the query string. */
- private boolean hasDigitsInQueryString() {
- String queryString = getQueryString();
- int length = queryString.length();
- for (int i = 0; i < length; i++) {
- if (Character.isDigit(queryString.charAt(i))) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/java/com/android/dialer/app/list/SearchFragment.java b/java/com/android/dialer/app/list/SearchFragment.java
deleted file mode 100644
index afb678969..000000000
--- a/java/com/android/dialer/app/list/SearchFragment.java
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * Copyright (C) 2013 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.dialer.app.list;
-
-import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorListenerAdapter;
-import android.app.Activity;
-import android.app.DialogFragment;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.Interpolator;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.Space;
-import com.android.contacts.common.list.ContactEntryListAdapter;
-import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
-import com.android.contacts.common.list.PhoneNumberPickerFragment;
-import com.android.dialer.animation.AnimUtils;
-import com.android.dialer.app.R;
-import com.android.dialer.app.widget.DialpadSearchEmptyContentView;
-import com.android.dialer.callintent.CallSpecificAppData;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.dialpadview.DialpadFragment.ErrorDialogFragment;
-import com.android.dialer.logging.DialerImpression;
-import com.android.dialer.logging.Logger;
-import com.android.dialer.util.DialerUtils;
-import com.android.dialer.util.IntentUtil;
-import com.android.dialer.util.PermissionsUtil;
-import com.android.dialer.widget.EmptyContentView;
-
-public class SearchFragment extends PhoneNumberPickerFragment {
-
- protected EmptyContentView emptyView;
- private OnListFragmentScrolledListener activityScrollListener;
- private View.OnTouchListener activityOnTouchListener;
- /*
- * Stores the untouched user-entered string that is used to populate the add to contacts
- * intent.
- */
- private String addToContactNumber;
- private int actionBarHeight;
- private int shadowHeight;
- private int paddingTop;
- private int showDialpadDuration;
- private int hideDialpadDuration;
- /**
- * Used to resize the list view containing search results so that it fits the available space
- * above the dialpad. Does not have a user-visible effect in regular touch usage (since the
- * dialpad hides that portion of the ListView anyway), but improves usability in accessibility
- * mode.
- */
- private Space spacer;
-
- private HostInterface activity;
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- setQuickContactEnabled(true);
- setAdjustSelectionBoundsEnabled(false);
- setDarkTheme(false);
- setUseCallableUri(true);
-
- try {
- activityScrollListener = (OnListFragmentScrolledListener) activity;
- } catch (ClassCastException e) {
- LogUtil.v(
- "SearchFragment.onAttach",
- activity.toString()
- + " doesn't implement OnListFragmentScrolledListener. "
- + "Ignoring.");
- }
- }
-
- @Override
- public void onStart() {
- LogUtil.d("SearchFragment.onStart", "");
- super.onStart();
-
- activity = (HostInterface) getActivity();
-
- final Resources res = getResources();
- actionBarHeight = activity.getActionBarHeight();
- shadowHeight = res.getDrawable(R.drawable.search_shadow).getIntrinsicHeight();
- paddingTop = res.getDimensionPixelSize(R.dimen.search_list_padding_top);
- showDialpadDuration = res.getInteger(R.integer.dialpad_slide_in_duration);
- hideDialpadDuration = res.getInteger(R.integer.dialpad_slide_out_duration);
-
- final ListView listView = getListView();
-
- if (emptyView == null) {
- if (this instanceof SmartDialSearchFragment) {
- emptyView = new DialpadSearchEmptyContentView(getActivity());
- } else {
- emptyView = new EmptyContentView(getActivity());
- }
- ((ViewGroup) getListView().getParent()).addView(emptyView);
- getListView().setEmptyView(emptyView);
- setupEmptyView();
- }
-
- listView.setBackgroundColor(res.getColor(R.color.background_dialer_results));
- listView.setClipToPadding(false);
- setVisibleScrollbarEnabled(false);
-
- //Turn of accessibility live region as the list constantly update itself and spam messages.
- listView.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_NONE);
- ContentChangedFilter.addToParent(listView);
-
- listView.setOnScrollListener(
- new OnScrollListener() {
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- if (activityScrollListener != null) {
- activityScrollListener.onListFragmentScrollStateChange(scrollState);
- }
- }
-
- @Override
- public void onScroll(
- AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}
- });
- if (activityOnTouchListener != null) {
- listView.setOnTouchListener(activityOnTouchListener);
- }
-
- updatePosition(false /* animate */);
- }
-
- @Override
- public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
- Animator animator = null;
- if (nextAnim != 0) {
- animator = AnimatorInflater.loadAnimator(getActivity(), nextAnim);
- }
- if (animator != null) {
- final View view = getView();
- final int oldLayerType = view.getLayerType();
- animator.addListener(
- new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- view.setLayerType(oldLayerType, null);
- }
- });
- }
- return animator;
- }
-
- public void setAddToContactNumber(String addToContactNumber) {
- this.addToContactNumber = addToContactNumber;
- }
-
- /**
- * Return true if phone number is prohibited by a value -
- * (R.string.config_prohibited_phone_number_regexp) in the config files. False otherwise.
- */
- public boolean checkForProhibitedPhoneNumber(String number) {
- // Regular expression prohibiting manual phone call. Can be empty i.e. "no rule".
- String prohibitedPhoneNumberRegexp =
- getResources().getString(R.string.config_prohibited_phone_number_regexp);
-
- // "persist.radio.otaspdial" is a temporary hack needed for one carrier's automated
- // test equipment.
- if (number != null
- && !TextUtils.isEmpty(prohibitedPhoneNumberRegexp)
- && number.matches(prohibitedPhoneNumberRegexp)) {
- LogUtil.i(
- "SearchFragment.checkForProhibitedPhoneNumber",
- "the phone number is prohibited explicitly by a rule");
- if (getActivity() != null) {
- DialogFragment dialogFragment =
- ErrorDialogFragment.newInstance(R.string.dialog_phone_call_prohibited_message);
- dialogFragment.show(getFragmentManager(), "phone_prohibited_dialog");
- }
-
- return true;
- }
- return false;
- }
-
- @Override
- protected ContactEntryListAdapter createListAdapter() {
- DialerPhoneNumberListAdapter adapter = new DialerPhoneNumberListAdapter(getActivity());
- adapter.setDisplayPhotos(true);
- adapter.setUseCallableUri(super.usesCallableUri());
- adapter.setListener(this);
- return adapter;
- }
-
- @Override
- protected void onItemClick(int position, long id) {
- final DialerPhoneNumberListAdapter adapter = (DialerPhoneNumberListAdapter) getAdapter();
- final int shortcutType = adapter.getShortcutTypeFromPosition(position);
- final OnPhoneNumberPickerActionListener listener;
- final Intent intent;
- final String number;
-
- LogUtil.i("SearchFragment.onItemClick", "shortcutType: " + shortcutType);
-
- switch (shortcutType) {
- case DialerPhoneNumberListAdapter.SHORTCUT_DIRECT_CALL:
- number = adapter.getQueryString();
- listener = getOnPhoneNumberPickerListener();
- if (listener != null && !checkForProhibitedPhoneNumber(number)) {
- CallSpecificAppData callSpecificAppData =
- CallSpecificAppData.newBuilder()
- .setCallInitiationType(getCallInitiationType(false /* isRemoteDirectory */))
- .setPositionOfSelectedSearchResult(position)
- .setCharactersInSearchString(
- getQueryString() == null ? 0 : getQueryString().length())
- .build();
- listener.onPickPhoneNumber(number, false /* isVideoCall */, callSpecificAppData);
- }
- break;
- case DialerPhoneNumberListAdapter.SHORTCUT_CREATE_NEW_CONTACT:
- if (this instanceof SmartDialSearchFragment) {
- Logger.get(getContext())
- .logImpression(DialerImpression.Type.CREATE_NEW_CONTACT_FROM_DIALPAD);
- }
- number =
- TextUtils.isEmpty(addToContactNumber)
- ? adapter.getFormattedQueryString()
- : addToContactNumber;
- intent = IntentUtil.getNewContactIntent(number);
- DialerUtils.startActivityWithErrorToast(getActivity(), intent);
- break;
- case DialerPhoneNumberListAdapter.SHORTCUT_ADD_TO_EXISTING_CONTACT:
- if (this instanceof SmartDialSearchFragment) {
- Logger.get(getContext())
- .logImpression(DialerImpression.Type.ADD_TO_A_CONTACT_FROM_DIALPAD);
- }
- number =
- TextUtils.isEmpty(addToContactNumber)
- ? adapter.getFormattedQueryString()
- : addToContactNumber;
- intent = IntentUtil.getAddToExistingContactIntent(number);
- DialerUtils.startActivityWithErrorToast(
- getActivity(), intent, R.string.add_contact_not_available);
- break;
- case DialerPhoneNumberListAdapter.SHORTCUT_SEND_SMS_MESSAGE:
- number =
- TextUtils.isEmpty(addToContactNumber)
- ? adapter.getFormattedQueryString()
- : addToContactNumber;
- intent = IntentUtil.getSendSmsIntent(number);
- DialerUtils.startActivityWithErrorToast(getActivity(), intent);
- break;
- case DialerPhoneNumberListAdapter.SHORTCUT_MAKE_VIDEO_CALL:
- number =
- TextUtils.isEmpty(addToContactNumber) ? adapter.getQueryString() : addToContactNumber;
- listener = getOnPhoneNumberPickerListener();
- if (listener != null && !checkForProhibitedPhoneNumber(number)) {
- CallSpecificAppData callSpecificAppData =
- CallSpecificAppData.newBuilder()
- .setCallInitiationType(getCallInitiationType(false /* isRemoteDirectory */))
- .setPositionOfSelectedSearchResult(position)
- .setCharactersInSearchString(
- getQueryString() == null ? 0 : getQueryString().length())
- .build();
- listener.onPickPhoneNumber(number, true /* isVideoCall */, callSpecificAppData);
- }
- break;
- case DialerPhoneNumberListAdapter.SHORTCUT_INVALID:
- default:
- super.onItemClick(position, id);
- break;
- }
- }
-
- /**
- * Updates the position and padding of the search fragment, depending on whether the dialpad is
- * shown. This can be optionally animated.
- */
- public void updatePosition(boolean animate) {
- LogUtil.d("SearchFragment.updatePosition", "animate: %b", animate);
- if (activity == null) {
- // Activity will be set in onStart, and this method will be called again
- return;
- }
-
- // Use negative shadow height instead of 0 to account for the 9-patch's shadow.
- int startTranslationValue =
- activity.isDialpadShown() ? actionBarHeight - shadowHeight : -shadowHeight;
- int endTranslationValue = 0;
- // Prevents ListView from being translated down after a rotation when the ActionBar is up.
- if (animate || activity.isActionBarShowing()) {
- endTranslationValue = activity.isDialpadShown() ? 0 : actionBarHeight - shadowHeight;
- }
- if (animate) {
- // If the dialpad will be shown, then this animation involves sliding the list up.
- final boolean slideUp = activity.isDialpadShown();
-
- Interpolator interpolator = slideUp ? AnimUtils.EASE_IN : AnimUtils.EASE_OUT;
- int duration = slideUp ? showDialpadDuration : hideDialpadDuration;
- getView().setTranslationY(startTranslationValue);
- getView()
- .animate()
- .translationY(endTranslationValue)
- .setInterpolator(interpolator)
- .setDuration(duration)
- .setListener(
- new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- if (!slideUp) {
- resizeListView();
- }
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (slideUp) {
- resizeListView();
- }
- }
- });
-
- } else {
- getView().setTranslationY(endTranslationValue);
- resizeListView();
- }
-
- // There is padding which should only be applied when the dialpad is not shown.
- int paddingTop = activity.isDialpadShown() ? 0 : this.paddingTop;
- final ListView listView = getListView();
- listView.setPaddingRelative(
- listView.getPaddingStart(),
- paddingTop,
- listView.getPaddingEnd(),
- listView.getPaddingBottom());
- }
-
- public void resizeListView() {
- if (spacer == null) {
- return;
- }
- int spacerHeight = activity.isDialpadShown() ? activity.getDialpadHeight() : 0;
- LogUtil.d(
- "SearchFragment.resizeListView",
- "spacerHeight: %d -> %d, isDialpadShown: %b, dialpad height: %d",
- spacer.getHeight(),
- spacerHeight,
- activity.isDialpadShown(),
- activity.getDialpadHeight());
- if (spacerHeight != spacer.getHeight()) {
- final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) spacer.getLayoutParams();
- lp.height = spacerHeight;
- spacer.setLayoutParams(lp);
- }
- }
-
- @Override
- protected void startLoading() {
- if (getActivity() == null) {
- return;
- }
-
- if (PermissionsUtil.hasContactsReadPermissions(getActivity())) {
- super.startLoading();
- } else if (TextUtils.isEmpty(getQueryString())) {
- // Clear out any existing call shortcuts.
- final DialerPhoneNumberListAdapter adapter = (DialerPhoneNumberListAdapter) getAdapter();
- adapter.disableAllShortcuts();
- } else {
- // The contact list is not going to change (we have no results since permissions are
- // denied), but the shortcuts might because of the different query, so update the
- // list.
- getAdapter().notifyDataSetChanged();
- }
-
- setupEmptyView();
- }
-
- public void setOnTouchListener(View.OnTouchListener onTouchListener) {
- activityOnTouchListener = onTouchListener;
- }
-
- @Override
- protected View inflateView(LayoutInflater inflater, ViewGroup container) {
- final LinearLayout parent = (LinearLayout) super.inflateView(inflater, container);
- final int orientation = getResources().getConfiguration().orientation;
- if (orientation == Configuration.ORIENTATION_PORTRAIT) {
- spacer = new Space(getActivity());
- parent.addView(
- spacer, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0));
- }
- return parent;
- }
-
- protected void setupEmptyView() {}
-
- public interface HostInterface {
-
- boolean isActionBarShowing();
-
- boolean isDialpadShown();
-
- int getDialpadHeight();
-
- int getActionBarHeight();
- }
-}
diff --git a/java/com/android/dialer/app/list/SmartDialNumberListAdapter.java b/java/com/android/dialer/app/list/SmartDialNumberListAdapter.java
deleted file mode 100644
index c84bff7fc..000000000
--- a/java/com/android/dialer/app/list/SmartDialNumberListAdapter.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2013 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.dialer.app.list;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-import com.android.contacts.common.list.ContactListItemView;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.smartdial.SmartDialCursorLoader;
-import com.android.dialer.smartdial.util.SmartDialMatchPosition;
-import com.android.dialer.smartdial.util.SmartDialNameMatcher;
-import com.android.dialer.util.CallUtil;
-import java.util.ArrayList;
-
-/** List adapter to display the SmartDial search results. */
-public class SmartDialNumberListAdapter extends DialerPhoneNumberListAdapter {
-
- private static final String TAG = SmartDialNumberListAdapter.class.getSimpleName();
- private static final boolean DEBUG = false;
-
- private final Context context;
- @NonNull private final SmartDialNameMatcher nameMatcher;
-
- public SmartDialNumberListAdapter(Context context) {
- super(context);
- this.context = context;
- nameMatcher = new SmartDialNameMatcher("");
- setShortcutEnabled(SmartDialNumberListAdapter.SHORTCUT_DIRECT_CALL, false);
-
- if (DEBUG) {
- LogUtil.v(TAG, "Constructing List Adapter");
- }
- }
-
- /** Sets query for the SmartDialCursorLoader. */
- public void configureLoader(SmartDialCursorLoader loader) {
- if (DEBUG) {
- LogUtil.v(TAG, "Configure Loader with query" + getQueryString());
- }
-
- if (getQueryString() == null) {
- loader.configureQuery("");
- nameMatcher.setQuery("");
- } else {
- loader.configureQuery(getQueryString());
- nameMatcher.setQuery(PhoneNumberUtils.normalizeNumber(getQueryString()));
- }
- }
-
- /**
- * Sets highlight options for a List item in the SmartDial search results.
- *
- * @param view ContactListItemView where the result will be displayed.
- * @param cursor Object containing information of the associated List item.
- */
- @Override
- protected void setHighlight(ContactListItemView view, Cursor cursor) {
- view.clearHighlightSequences();
-
- if (nameMatcher.matches(context, cursor.getString(PhoneQuery.DISPLAY_NAME))) {
- final ArrayList<SmartDialMatchPosition> nameMatches = nameMatcher.getMatchPositions();
- for (SmartDialMatchPosition match : nameMatches) {
- view.addNameHighlightSequence(match.start, match.end);
- if (DEBUG) {
- LogUtil.v(
- TAG,
- cursor.getString(PhoneQuery.DISPLAY_NAME)
- + " "
- + nameMatcher.getQuery()
- + " "
- + String.valueOf(match.start));
- }
- }
- }
-
- final SmartDialMatchPosition numberMatch =
- nameMatcher.matchesNumber(context, cursor.getString(PhoneQuery.PHONE_NUMBER));
- if (numberMatch != null) {
- view.addNumberHighlightSequence(numberMatch.start, numberMatch.end);
- }
- }
-
- @Override
- public void setQueryString(String queryString) {
- final boolean showNumberShortcuts = !TextUtils.isEmpty(getFormattedQueryString());
- boolean changed = false;
- changed |= setShortcutEnabled(SHORTCUT_CREATE_NEW_CONTACT, showNumberShortcuts);
- changed |= setShortcutEnabled(SHORTCUT_ADD_TO_EXISTING_CONTACT, showNumberShortcuts);
- changed |= setShortcutEnabled(SHORTCUT_SEND_SMS_MESSAGE, showNumberShortcuts);
- changed |=
- setShortcutEnabled(
- SHORTCUT_MAKE_VIDEO_CALL, showNumberShortcuts && CallUtil.isVideoEnabled(getContext()));
- if (changed) {
- notifyDataSetChanged();
- }
- super.setQueryString(queryString);
- }
-
- public void setShowEmptyListForNullQuery(boolean show) {
- nameMatcher.setShouldMatchEmptyQuery(!show);
- }
-}
diff --git a/java/com/android/dialer/app/list/SmartDialSearchFragment.java b/java/com/android/dialer/app/list/SmartDialSearchFragment.java
deleted file mode 100644
index fdf0b5a56..000000000
--- a/java/com/android/dialer/app/list/SmartDialSearchFragment.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2013 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.dialer.app.list;
-
-import static android.Manifest.permission.CALL_PHONE;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.Loader;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.support.v13.app.FragmentCompat;
-import com.android.contacts.common.list.ContactEntryListAdapter;
-import com.android.dialer.app.R;
-import com.android.dialer.callintent.CallInitiationType;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.database.DialerDatabaseHelper;
-import com.android.dialer.smartdial.SmartDialCursorLoader;
-import com.android.dialer.util.PermissionsUtil;
-import com.android.dialer.widget.EmptyContentView;
-import java.util.Arrays;
-
-/** Implements a fragment to load and display SmartDial search results. */
-public class SmartDialSearchFragment extends SearchFragment
- implements EmptyContentView.OnEmptyViewActionButtonClickedListener,
- FragmentCompat.OnRequestPermissionsResultCallback {
-
- private static final int CALL_PHONE_PERMISSION_REQUEST_CODE = 1;
-
- private final BroadcastReceiver smartDialUpdatedReceiver =
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- LogUtil.i("SmartDialSearchFragment.onReceive", "smart dial update broadcast received");
- reloadData();
- }
- };
-
- /** Creates a SmartDialListAdapter to display and operate on search results. */
- @Override
- protected ContactEntryListAdapter createListAdapter() {
- SmartDialNumberListAdapter adapter = new SmartDialNumberListAdapter(getActivity());
- adapter.setUseCallableUri(super.usesCallableUri());
- adapter.setQuickContactEnabled(true);
- adapter.setShowEmptyListForNullQuery(getShowEmptyListForNullQuery());
- // Set adapter's query string to restore previous instance state.
- adapter.setQueryString(getQueryString());
- adapter.setListener(this);
- return adapter;
- }
-
- /** Creates a SmartDialCursorLoader object to load query results. */
- @Override
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- // Smart dialing does not support Directory Load, falls back to normal search instead.
- if (id == getDirectoryLoaderId()) {
- return super.onCreateLoader(id, args);
- } else {
- final SmartDialNumberListAdapter adapter = (SmartDialNumberListAdapter) getAdapter();
- SmartDialCursorLoader loader = new SmartDialCursorLoader(super.getContext());
- loader.setShowEmptyListForNullQuery(getShowEmptyListForNullQuery());
- adapter.configureLoader(loader);
- return loader;
- }
- }
-
- @Override
- public boolean getShowEmptyListForNullQuery() {
- return true;
- }
-
- @Override
- protected void setupEmptyView() {
- if (emptyView != null && getActivity() != null) {
- if (!PermissionsUtil.hasPermission(getActivity(), CALL_PHONE)) {
- emptyView.setImage(R.drawable.empty_contacts);
- emptyView.setActionLabel(R.string.permission_single_turn_on);
- emptyView.setDescription(R.string.permission_place_call);
- emptyView.setActionClickedListener(this);
- } else {
- emptyView.setImage(EmptyContentView.NO_IMAGE);
- emptyView.setActionLabel(EmptyContentView.NO_LABEL);
- emptyView.setDescription(EmptyContentView.NO_LABEL);
- }
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- LogUtil.i("SmartDialSearchFragment.onStart", "registering smart dial update receiver");
-
- getActivity()
- .registerReceiver(
- smartDialUpdatedReceiver,
- new IntentFilter(DialerDatabaseHelper.ACTION_SMART_DIAL_UPDATED));
- }
-
- @Override
- public void onStop() {
- super.onStop();
-
- LogUtil.i("SmartDialSearchFragment.onStop", "unregistering smart dial update receiver");
-
- getActivity().unregisterReceiver(smartDialUpdatedReceiver);
- }
-
- @Override
- public void onEmptyViewActionButtonClicked() {
- final Activity activity = getActivity();
- if (activity == null) {
- return;
- }
-
- String[] deniedPermissions =
- PermissionsUtil.getPermissionsCurrentlyDenied(
- getContext(), PermissionsUtil.allPhoneGroupPermissionsUsedInDialer);
- if (deniedPermissions.length > 0) {
- LogUtil.i(
- "SmartDialSearchFragment.onEmptyViewActionButtonClicked",
- "Requesting permissions: " + Arrays.toString(deniedPermissions));
- FragmentCompat.requestPermissions(
- this, deniedPermissions, CALL_PHONE_PERMISSION_REQUEST_CODE);
- }
- }
-
- @Override
- public void onRequestPermissionsResult(
- int requestCode, String[] permissions, int[] grantResults) {
- if (requestCode == CALL_PHONE_PERMISSION_REQUEST_CODE) {
- setupEmptyView();
- }
- }
-
- @Override
- protected CallInitiationType.Type getCallInitiationType(boolean isRemoteDirectory) {
- return CallInitiationType.Type.SMART_DIAL;
- }
-
- public boolean isShowingPermissionRequest() {
- return emptyView != null && emptyView.isShowingContent();
- }
-
- @Override
- public void setShowEmptyListForNullQuery(boolean show) {
- if (getAdapter() != null) {
- ((SmartDialNumberListAdapter) getAdapter()).setShowEmptyListForNullQuery(show);
- }
- super.setShowEmptyListForNullQuery(show);
- }
-}
diff --git a/java/com/android/dialer/app/res/layout/all_contacts_fragment.xml b/java/com/android/dialer/app/res/layout/all_contacts_fragment.xml
deleted file mode 100644
index 422c52991..000000000
--- a/java/com/android/dialer/app/res/layout/all_contacts_fragment.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/pinned_header_list_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <!-- Shown only when an Account filter is set.
- - paddingTop should be here to show "shade" effect correctly. -->
- <!-- TODO: Remove the filter header. -->
- <include layout="@layout/account_filter_header"/>
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1">
- <view
- android:id="@android:id/list"
- style="@style/DialtactsTheme"
- class="com.android.contacts.common.list.PinnedHeaderListView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginStart="?attr/contact_browser_list_padding_left"
- android:layout_marginEnd="?attr/contact_browser_list_padding_right"
- android:paddingTop="18dp"
- android:fadingEdge="none"
- android:fastScrollEnabled="true"
- android:nestedScrollingEnabled="true"
- android:cropToPadding="false"
- android:clipToPadding="false"/>
-
- <com.android.dialer.widget.EmptyContentView
- android:id="@+id/empty_list_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:visibility="gone"/>
-
- </FrameLayout>
-</LinearLayout>
diff --git a/java/com/android/dialer/app/res/layout/blocked_number_header.xml b/java/com/android/dialer/app/res/layout/blocked_number_header.xml
index e34510b73..e1019d1eb 100644
--- a/java/com/android/dialer/app/res/layout/blocked_number_header.xml
+++ b/java/com/android/dialer/app/res/layout/blocked_number_header.xml
@@ -166,46 +166,6 @@
</LinearLayout>
- <LinearLayout
- android:id="@+id/add_number_linear_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/blocked_number_add_top_margin"
- android:paddingBottom="@dimen/blocked_number_add_bottom_margin"
- android:paddingStart="@dimen/blocked_number_horizontal_margin"
- android:background="?android:attr/selectableItemBackground"
- android:baselineAligned="false"
- android:clickable="true"
- android:contentDescription="@string/addBlockedNumber"
- android:focusable="true"
- android:gravity="center_vertical"
- android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/add_number_icon"
- android:layout_width="@dimen/contact_photo_size"
- android:layout_height="@dimen/contact_photo_size"
- android:importantForAccessibility="no"/>
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/blocked_number_horizontal_margin"
- android:gravity="center_vertical"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/add_number_textview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:includeFontPadding="false"
- android:text="@string/addBlockedNumber"
- android:textColor="@color/blocked_number_primary_text_color"
- android:textSize="@dimen/blocked_number_primary_text_size"/>
- </LinearLayout>
-
- </LinearLayout>
-
<View
android:id="@+id/blocked_number_list_divider"
android:layout_width="match_parent"
diff --git a/java/com/android/dialer/assisteddialing/AndroidManifest.xml b/java/com/android/dialer/assisteddialing/AndroidManifest.xml
index a19af3b72..0a5b613d7 100644
--- a/java/com/android/dialer/assisteddialing/AndroidManifest.xml
+++ b/java/com/android/dialer/assisteddialing/AndroidManifest.xml
@@ -16,7 +16,7 @@
package="com.android.dialer.assisteddialing">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
</manifest>
diff --git a/java/com/android/dialer/assisteddialing/ui/AndroidManifest.xml b/java/com/android/dialer/assisteddialing/ui/AndroidManifest.xml
index 3e79de38a..d59056eb0 100644
--- a/java/com/android/dialer/assisteddialing/ui/AndroidManifest.xml
+++ b/java/com/android/dialer/assisteddialing/ui/AndroidManifest.xml
@@ -16,7 +16,7 @@
package="com.android.dialer.assisteddialing.ui">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
<application>
diff --git a/java/com/android/dialer/binary/google/AndroidManifest.xml b/java/com/android/dialer/binary/google/AndroidManifest.xml
index c1f1a59bf..f6ac430b3 100644
--- a/java/com/android/dialer/binary/google/AndroidManifest.xml
+++ b/java/com/android/dialer/binary/google/AndroidManifest.xml
@@ -20,7 +20,7 @@
android:versionName="19.0">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
diff --git a/java/com/android/dialer/blocking/BlockedNumbersMigrator.java b/java/com/android/dialer/blocking/BlockedNumbersMigrator.java
index 88f474a84..61ebf2f56 100644
--- a/java/com/android/dialer/blocking/BlockedNumbersMigrator.java
+++ b/java/com/android/dialer/blocking/BlockedNumbersMigrator.java
@@ -35,7 +35,7 @@ import java.util.Objects;
* Class which should be used to migrate numbers from {@link FilteredNumberContract} blocking to
* {@link android.provider.BlockedNumberContract} blocking.
*/
-@TargetApi(VERSION_CODES.M)
+@TargetApi(VERSION_CODES.N)
public class BlockedNumbersMigrator {
private final Context context;
diff --git a/java/com/android/dialer/blocking/FilteredNumberAsyncQueryHandler.java b/java/com/android/dialer/blocking/FilteredNumberAsyncQueryHandler.java
index 09fd5f0a8..8be479c99 100644
--- a/java/com/android/dialer/blocking/FilteredNumberAsyncQueryHandler.java
+++ b/java/com/android/dialer/blocking/FilteredNumberAsyncQueryHandler.java
@@ -37,6 +37,7 @@ import com.android.dialer.database.FilteredNumberContract.FilteredNumberTypes;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+/** TODO(calderwoodra): documentation */
public class FilteredNumberAsyncQueryHandler extends AsyncQueryHandler {
public static final int INVALID_ID = -1;
@@ -199,7 +200,7 @@ public class FilteredNumberAsyncQueryHandler extends AsyncQueryHandler {
*
* @return blocked id.
*/
- @TargetApi(VERSION_CODES.M)
+ @TargetApi(VERSION_CODES.N)
@Nullable
public Integer getBlockedIdSynchronous(@Nullable String number, String countryIso) {
Assert.isWorkerThread();
@@ -382,6 +383,7 @@ public class FilteredNumberAsyncQueryHandler extends AsyncQueryHandler {
null);
}
+ /** TODO(calderwoodra): documentation */
public interface OnCheckBlockedListener {
/**
@@ -392,6 +394,7 @@ public class FilteredNumberAsyncQueryHandler extends AsyncQueryHandler {
void onCheckComplete(Integer id);
}
+ /** TODO(calderwoodra): documentation */
public interface OnBlockNumberListener {
/**
@@ -402,6 +405,7 @@ public class FilteredNumberAsyncQueryHandler extends AsyncQueryHandler {
void onBlockComplete(Uri uri);
}
+ /** TODO(calderwoodra): documentation */
public interface OnUnblockNumberListener {
/**
@@ -413,6 +417,7 @@ public class FilteredNumberAsyncQueryHandler extends AsyncQueryHandler {
void onUnblockComplete(int rows, ContentValues values);
}
+ /** TODO(calderwoodra): documentation */
interface OnHasBlockedNumbersListener {
/**
diff --git a/java/com/android/dialer/blocking/FilteredNumberCompat.java b/java/com/android/dialer/blocking/FilteredNumberCompat.java
index bea84e8db..b0af45c97 100644
--- a/java/com/android/dialer/blocking/FilteredNumberCompat.java
+++ b/java/com/android/dialer/blocking/FilteredNumberCompat.java
@@ -16,16 +16,12 @@
package com.android.dialer.blocking;
-import android.annotation.TargetApi;
import android.app.FragmentManager;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.os.UserManager;
import android.preference.PreferenceManager;
import android.provider.BlockedNumberContract;
import android.provider.BlockedNumberContract.BlockedNumbers;
@@ -110,7 +106,7 @@ public class FilteredNumberCompat {
* otherwise.
*/
public static boolean canUseNewFiltering() {
- return VERSION.SDK_INT >= VERSION_CODES.N;
+ return true;
}
/**
@@ -162,16 +158,14 @@ public class FilteredNumberCompat {
private static Uri getBaseUri(Context context) {
// Explicit version check to aid static analysis
- return useNewFiltering(context) && VERSION.SDK_INT >= VERSION_CODES.N
- ? BlockedNumbers.CONTENT_URI
- : FilteredNumber.CONTENT_URI;
+ return useNewFiltering(context) ? BlockedNumbers.CONTENT_URI : FilteredNumber.CONTENT_URI;
}
/**
* Removes any null column names from the given projection array. This method is intended to be
* used to strip out any column names that aren't available in every version of number blocking.
* Example: {@literal getContext().getContentResolver().query( someUri, // Filtering ensures that
- * no non-existant columns are queried FilteredNumberCompat.filter(new String[]
+ * no non-existent columns are queried FilteredNumberCompat.filter(new String[]
* {FilteredNumberCompat.getIdColumnName(), FilteredNumberCompat.getTypeColumnName()},
* FilteredNumberCompat.getE164NumberColumnName() + " = ?", new String[] {e164Number}); }
*
@@ -249,9 +243,7 @@ public class FilteredNumberCompat {
*/
public static Intent createManageBlockedNumbersIntent(Context context) {
// Explicit version check to aid static analysis
- if (canUseNewFiltering()
- && hasMigratedToNewBlocking(context)
- && VERSION.SDK_INT >= VERSION_CODES.N) {
+ if (canUseNewFiltering() && hasMigratedToNewBlocking(context)) {
return context.getSystemService(TelecomManager.class).createManageBlockedNumbersIntent();
}
Intent intent = new Intent("com.android.dialer.action.BLOCKED_NUMBERS_SETTINGS");
@@ -270,11 +262,6 @@ public class FilteredNumberCompat {
return canAttemptBlockOperationsForTest;
}
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- // Dialer blocking, must be primary user
- return context.getSystemService(UserManager.class).isSystemUser();
- }
-
// Great Wall blocking, must be primary user and the default or system dialer
// TODO(maxwelb): check that we're the system Dialer
return TelecomUtil.isDefaultDialer(context)
@@ -294,10 +281,6 @@ public class FilteredNumberCompat {
* otherwise.
*/
public static boolean canCurrentUserOpenBlockSettings(Context context) {
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- // Dialer blocking, must be primary user
- return context.getSystemService(UserManager.class).isSystemUser();
- }
// BlockedNumberContract blocking, verify through Contract API
return TelecomUtil.isDefaultDialer(context)
&& safeBlockedNumbersContractCanCurrentUserBlockNumbers(context);
@@ -312,7 +295,6 @@ public class FilteredNumberCompat {
* @return the result of BlockedNumberContract#canCurrentUserBlockNumbers, or {@code false} if an
* exception was thrown.
*/
- @TargetApi(VERSION_CODES.N)
private static boolean safeBlockedNumbersContractCanCurrentUserBlockNumbers(Context context) {
try {
return BlockedNumberContract.canCurrentUserBlockNumbers(context);
diff --git a/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java b/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java
index 725cea723..0f1ab5f25 100644
--- a/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java
+++ b/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java
@@ -37,7 +37,7 @@ import java.io.InputStream;
import java.io.OutputStream;
/** Task for copying and resizing images to be shared with RCS process. */
-@TargetApi(VERSION_CODES.M)
+@TargetApi(VERSION_CODES.N)
class CopyAndResizeImageWorker implements Worker<Uri, Pair<File, String>> {
private static final String MIME_TYPE = "image/jpeg";
diff --git a/java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java b/java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java
index 69f546929..c18e22d56 100644
--- a/java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java
+++ b/java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java
@@ -38,7 +38,7 @@ import java.io.IOException;
import java.io.OutputStream;
/** Persisting image routine. */
-@TargetApi(VERSION_CODES.M)
+@TargetApi(VERSION_CODES.N)
public class ImagePersistWorker implements Worker<Void, Result> {
private int width;
private int height;
diff --git a/java/com/android/dialer/calllog/AndroidManifest.xml b/java/com/android/dialer/calllog/AndroidManifest.xml
index 69731fe39..7c904d993 100644
--- a/java/com/android/dialer/calllog/AndroidManifest.xml
+++ b/java/com/android/dialer/calllog/AndroidManifest.xml
@@ -17,7 +17,7 @@
package="com.android.dialer.calllog">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
<application>
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
index 9a80af2f7..7fc474a98 100644
--- a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
+++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
@@ -92,7 +92,7 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
return true;
}
- @TargetApi(Build.VERSION_CODES.M) // Uses try-with-resources
+ @TargetApi(Build.VERSION_CODES.N) // Uses try-with-resources
@Nullable
@Override
public Cursor query(
diff --git a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
index 6fd19dd17..dce51b750 100644
--- a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
@@ -256,7 +256,7 @@ public class SystemCallLogDataSource implements CallLogDataSource {
}
}
- @TargetApi(Build.VERSION_CODES.M) // Uses try-with-resources
+ @TargetApi(Build.VERSION_CODES.N) // Uses try-with-resources
private void handleInsertsAndUpdates(
Context appContext, CallLogMutations mutations, Set<Long> existingAnnotatedCallLogIds) {
long previousTimestampProcessed = sharedPreferences.getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L);
@@ -481,7 +481,7 @@ public class SystemCallLogDataSource implements CallLogDataSource {
}
}
- @TargetApi(Build.VERSION_CODES.M) // Uses try-with-resources
+ @TargetApi(Build.VERSION_CODES.N) // Uses try-with-resources
private static Set<Long> getAnnotatedCallLogIds(Context appContext) {
ArraySet<Long> ids = new ArraySet<>();
@@ -510,7 +510,7 @@ public class SystemCallLogDataSource implements CallLogDataSource {
return ids;
}
- @TargetApi(Build.VERSION_CODES.M) // Uses try-with-resources
+ @TargetApi(Build.VERSION_CODES.N) // Uses try-with-resources
private static Set<Long> getIdsFromSystemCallLogThatMatch(
Context appContext, Set<Long> matchingIds) {
ArraySet<Long> ids = new ArraySet<>();
diff --git a/java/com/android/dialer/calllogutils/CallLogDates.java b/java/com/android/dialer/calllogutils/CallLogDates.java
index fe3c0c3ad..5a63c3c8d 100644
--- a/java/com/android/dialer/calllogutils/CallLogDates.java
+++ b/java/com/android/dialer/calllogutils/CallLogDates.java
@@ -19,8 +19,6 @@ package com.android.dialer.calllogutils;
import android.content.Context;
import android.icu.lang.UCharacter;
import android.icu.text.BreakIterator;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
import android.text.format.DateUtils;
import java.util.Calendar;
import java.util.Locale;
@@ -145,12 +143,6 @@ public final class CallLogDates {
// of the string is not usually capitalized. For example, "Wednesdsay" in Uzbek is "chorshanba”
// (not capitalized). To handle this issue we apply title casing to the start of the sentence so
// that "chorshanba, 2016 may 25,20:02" becomes "Chorshanba, 2016 may 25,20:02".
- //
- // The ICU library was not available in Android until N, so we can only do this in N+ devices.
- // Pre-N devices will still see incorrect capitalization in some languages.
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- return value;
- }
// Using the ICU library is safer than just applying toUpperCase() on the first letter of the
// word because in some languages, there can be multiple starting characters which should be
diff --git a/java/com/android/dialer/compat/CompatUtils.java b/java/com/android/dialer/compat/CompatUtils.java
index 584f20549..d09f8b0e1 100644
--- a/java/com/android/dialer/compat/CompatUtils.java
+++ b/java/com/android/dialer/compat/CompatUtils.java
@@ -16,17 +16,17 @@
package com.android.dialer.compat;
import android.content.Context;
-import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.LocaleList;
import java.util.Locale;
+/** TODO(calderwoodra): documentation */
public final class CompatUtils {
/** PrioritizedMimeType is added in API level 23. */
public static boolean hasPrioritizedMimeType() {
- return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M;
+ return true;
}
/**
@@ -36,8 +36,7 @@ public final class CompatUtils {
* @return {@code true} if multi-SIM capability is available, {@code false} otherwise.
*/
public static boolean isMSIMCompatible() {
- return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
- >= Build.VERSION_CODES.LOLLIPOP_MR1;
+ return true;
}
/**
@@ -47,7 +46,7 @@ public final class CompatUtils {
* @return {@code true} if video calling is allowed, {@code false} otherwise.
*/
public static boolean isVideoCompatible() {
- return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP) >= Build.VERSION_CODES.M;
+ return true;
}
/**
@@ -57,7 +56,7 @@ public final class CompatUtils {
* @return {@code true} if video presence checking is allowed, {@code false} otherwise.
*/
public static boolean isVideoPresenceCompatible() {
- return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) > Build.VERSION_CODES.M;
+ return true;
}
/**
@@ -67,7 +66,7 @@ public final class CompatUtils {
* @return {@code true} if call subject is a feature on this device, {@code false} otherwise.
*/
public static boolean isCallSubjectCompatible() {
- return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP) >= Build.VERSION_CODES.M;
+ return true;
}
/** Returns locale of the device. */
diff --git a/java/com/android/dialer/compat/SdkVersionOverride.java b/java/com/android/dialer/compat/SdkVersionOverride.java
deleted file mode 100644
index 1d253a355..000000000
--- a/java/com/android/dialer/compat/SdkVersionOverride.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2015 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.dialer.compat;
-
-import android.os.Build.VERSION;
-
-/**
- * Class used to override the current sdk version to test specific branches of compatibility logic.
- * When such branching occurs, use {@link #getSdkVersion(int)} rather than explicitly calling {@link
- * VERSION#SDK_INT}. This allows the sdk version to be forced to a specific value.
- */
-public class SdkVersionOverride {
-
- /** Flag used to determine if override sdk versions are returned. */
- private static final boolean ALLOW_OVERRIDE_VERSION = false;
-
- private SdkVersionOverride() {}
-
- /**
- * Gets the sdk version
- *
- * @param overrideVersion the version to attempt using
- * @return overrideVersion if the {@link #ALLOW_OVERRIDE_VERSION} flag is set to {@code true},
- * otherwise the current version
- */
- public static int getSdkVersion(int overrideVersion) {
- return ALLOW_OVERRIDE_VERSION ? overrideVersion : VERSION.SDK_INT;
- }
-}
diff --git a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
index c4ed6e6ed..655540bba 100644
--- a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
+++ b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
@@ -25,7 +25,6 @@ import android.support.annotation.Nullable;
import android.support.v4.os.BuildCompat;
import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
-import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.telecom.TelecomUtil;
import java.lang.reflect.InvocationTargetException;
@@ -133,9 +132,6 @@ public class TelephonyManagerCompat {
@Nullable
public static Uri getVoicemailRingtoneUri(
TelephonyManager telephonyManager, PhoneAccountHandle accountHandle) {
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- return null;
- }
return telephonyManager.getVoicemailRingtoneUri(accountHandle);
}
@@ -149,8 +145,7 @@ public class TelephonyManagerCompat {
*/
public static boolean isVoicemailVibrationEnabled(
TelephonyManager telephonyManager, PhoneAccountHandle accountHandle) {
- return VERSION.SDK_INT < VERSION_CODES.N
- || telephonyManager.isVoicemailVibrationEnabled(accountHandle);
+ return telephonyManager.isVoicemailVibrationEnabled(accountHandle);
}
/**
@@ -159,9 +154,6 @@ public class TelephonyManagerCompat {
*/
public static void setVisualVoicemailEnabled(
TelephonyManager telephonyManager, PhoneAccountHandle handle, boolean enabled) {
- if (VERSION.SDK_INT < VERSION_CODES.N_MR1) {
- Assert.fail("setVisualVoicemailEnabled called on pre-NMR1");
- }
try {
TelephonyManager.class
.getMethod("setVisualVoicemailEnabled", PhoneAccountHandle.class, boolean.class)
@@ -177,9 +169,6 @@ public class TelephonyManagerCompat {
*/
public static boolean isVisualVoicemailEnabled(
TelephonyManager telephonyManager, PhoneAccountHandle handle) {
- if (VERSION.SDK_INT < VERSION_CODES.N_MR1) {
- Assert.fail("isVisualVoicemailEnabled called on pre-NMR1");
- }
try {
return (boolean)
TelephonyManager.class
diff --git a/java/com/android/dialer/database/CallLogQueryHandler.java b/java/com/android/dialer/database/CallLogQueryHandler.java
index 92c49a09e..e974cc48f 100644
--- a/java/com/android/dialer/database/CallLogQueryHandler.java
+++ b/java/com/android/dialer/database/CallLogQueryHandler.java
@@ -26,7 +26,6 @@ import android.database.sqlite.SQLiteDiskIOException;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteFullException;
import android.net.Uri;
-import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -36,7 +35,6 @@ import android.provider.VoicemailContract.Voicemails;
import com.android.contacts.common.database.NoNullCursorAsyncQueryHandler;
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.AppCompatConstants;
-import com.android.dialer.compat.SdkVersionOverride;
import com.android.dialer.phonenumbercache.CallLogQuery;
import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.PermissionsUtil;
@@ -157,9 +155,7 @@ public class CallLogQueryHandler extends NoNullCursorAsyncQueryHandler {
selectionArgs.add(Integer.toString(AppCompatConstants.CALLS_BLOCKED_TYPE));
// Ignore voicemails marked as deleted
- if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
- where.append(" AND (").append(Voicemails.DELETED).append(" = 0)");
- }
+ where.append(" AND (").append(Voicemails.DELETED).append(" = 0)");
if (newOnly) {
where.append(" AND (").append(Calls.NEW).append(" = 1)");
diff --git a/java/com/android/dialer/oem/CequintCallerIdManager.java b/java/com/android/dialer/oem/CequintCallerIdManager.java
index 48a5985ce..ee865bc14 100644
--- a/java/com/android/dialer/oem/CequintCallerIdManager.java
+++ b/java/com/android/dialer/oem/CequintCallerIdManager.java
@@ -41,7 +41,7 @@ import java.util.concurrent.ConcurrentHashMap;
* Cequint Caller ID. It also caches any information fetched in static map, which lives through
* whole application lifecycle.
*/
-@TargetApi(VERSION_CODES.M)
+@TargetApi(VERSION_CODES.N)
public class CequintCallerIdManager {
private static final String CONFIG_CALLER_ID_ENABLED = "config_caller_id_enabled";
diff --git a/java/com/android/dialer/p13n/inference/P13nRanking.java b/java/com/android/dialer/p13n/inference/P13nRanking.java
deleted file mode 100644
index 79b4d7136..000000000
--- a/java/com/android/dialer/p13n/inference/P13nRanking.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2016 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.dialer.p13n.inference;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.support.annotation.MainThread;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import com.android.dialer.common.Assert;
-import com.android.dialer.configprovider.ConfigProviderBindings;
-import com.android.dialer.p13n.inference.protocol.P13nRanker;
-import com.android.dialer.p13n.inference.protocol.P13nRankerFactory;
-import java.util.List;
-
-/** Single entry point for all personalized ranking. */
-public final class P13nRanking {
-
- private static P13nRanker ranker;
-
- private P13nRanking() {}
-
- @MainThread
- @NonNull
- public static P13nRanker get(@NonNull Context context) {
- Assert.isNotNull(context);
- Assert.isMainThread();
-
- if (ranker != null) {
- return ranker;
- }
-
- if (!ConfigProviderBindings.get(context).getBoolean("p13n_ranker_should_enable", false)) {
- setToIdentityRanker();
- return ranker;
- }
-
- Context application = context.getApplicationContext();
- if (application instanceof P13nRankerFactory) {
- ranker = ((P13nRankerFactory) application).newP13nRanker();
- }
-
- if (ranker == null) {
- setToIdentityRanker();
- }
- return ranker;
- }
-
- private static void setToIdentityRanker() {
- ranker =
- new P13nRanker() {
- @Override
- public void refresh(@Nullable P13nRefreshCompleteListener listener) {}
-
- @Override
- public List<String> rankList(List<String> phoneNumbers) {
- return phoneNumbers;
- }
-
- @NonNull
- @Override
- public Cursor rankCursor(@NonNull Cursor phoneQueryResults, int queryLength) {
- return phoneQueryResults;
- }
-
- @Override
- public boolean shouldShowEmptyListForNullQuery() {
- return true;
- }
- };
- }
-
- public static void setForTesting(@NonNull P13nRanker ranker) {
- P13nRanking.ranker = ranker;
- }
-}
diff --git a/java/com/android/dialer/p13n/inference/protocol/P13nRanker.java b/java/com/android/dialer/p13n/inference/protocol/P13nRanker.java
deleted file mode 100644
index 41f1de49d..000000000
--- a/java/com/android/dialer/p13n/inference/protocol/P13nRanker.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2016 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.dialer.p13n.inference.protocol;
-
-import android.database.Cursor;
-import android.support.annotation.MainThread;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import java.util.List;
-
-/** Provides personalized ranking of outgoing call targets. */
-public interface P13nRanker {
-
- /**
- * Re-orders a list of phone numbers according to likelihood they will be the next outgoing call.
- *
- * @param phoneNumbers the list of candidate numbers to call (may be in contacts list or not)
- */
- @NonNull
- @MainThread
- List<String> rankList(@NonNull List<String> phoneNumbers);
-
- /**
- * Re-orders a retrieved contact list according to likelihood they will be the next outgoing call.
- *
- * <p>A new cursor with reordered data is returned; the input cursor is unmodified except for its
- * position. If the order is unchanged, this method may return a reference to the unmodified input
- * cursor directly. The order would be unchanged if the ranking cache is not yet ready, or if the
- * input cursor is closed or invalid, or if any other error occurs in the ranking process.
- *
- * @param phoneQueryResults cursor of results of a Dialer search query
- * @param queryLength length of the search query that resulted in the cursor data, if below 0,
- * assumes no length is specified, thus applies the default behavior which is same as when
- * queryLength is greater than zero.
- * @return new cursor of data reordered by ranking (or reference to input cursor if order
- * unchanged)
- */
- @NonNull
- @MainThread
- Cursor rankCursor(@NonNull Cursor phoneQueryResults, int queryLength);
-
- /**
- * Refreshes ranking cache (pulls fresh contextual features, pre-caches inference results, etc.).
- *
- * <p>Asynchronously runs in background as the process might take a few seconds, notifying a
- * listener upon completion; meanwhile, any calls to {@link #rankList} will simply return the
- * input in same order.
- *
- * @param listener callback for when ranking refresh has completed; null value skips notification.
- */
- @MainThread
- void refresh(@Nullable P13nRefreshCompleteListener listener);
-
- /** Decides if results should be displayed for no-query search. */
- @MainThread
- boolean shouldShowEmptyListForNullQuery();
-
- /**
- * Callback class for when ranking refresh has completed.
- *
- * <p>Primary use is to notify {@link com.android.dialer.app.DialtactsActivity} that the ranking
- * functions {@link #rankList} and {@link #rankCursor(Cursor, int)} will now give useful results.
- */
- interface P13nRefreshCompleteListener {
-
- /** Callback for when ranking refresh has completed. */
- void onP13nRefreshComplete();
- }
-}
diff --git a/java/com/android/dialer/p13n/inference/protocol/P13nRankerFactory.java b/java/com/android/dialer/p13n/inference/protocol/P13nRankerFactory.java
deleted file mode 100644
index 7038cf456..000000000
--- a/java/com/android/dialer/p13n/inference/protocol/P13nRankerFactory.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 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.dialer.p13n.inference.protocol;
-
-import android.support.annotation.Nullable;
-
-/**
- * This interface should be implemented by the Application subclass. It allows this module to get
- * references to the {@link P13nRanker}.
- */
-public interface P13nRankerFactory {
- @Nullable
- P13nRanker newP13nRanker();
-}
diff --git a/java/com/android/dialer/p13n/logging/P13nLogger.java b/java/com/android/dialer/p13n/logging/P13nLogger.java
deleted file mode 100644
index 069a29328..000000000
--- a/java/com/android/dialer/p13n/logging/P13nLogger.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2016 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.dialer.p13n.logging;
-
-import com.android.contacts.common.list.PhoneNumberListAdapter;
-
-/** Allows logging of data for personalization. */
-public interface P13nLogger {
-
- /**
- * Logs a search query (text or digits) entered by user.
- *
- * @param query search text (or digits) entered by user
- * @param adapter list adapter providing access to contacts matching search query
- */
- void onSearchQuery(String query, PhoneNumberListAdapter adapter);
-
- /**
- * Resets logging session (clears searches, re-initializes app entry timestamp, etc.) Should be
- * called when Dialer app is resumed.
- */
- void reset();
-}
diff --git a/java/com/android/dialer/p13n/logging/P13nLoggerFactory.java b/java/com/android/dialer/p13n/logging/P13nLoggerFactory.java
deleted file mode 100644
index 7350e99e1..000000000
--- a/java/com/android/dialer/p13n/logging/P13nLoggerFactory.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 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.dialer.p13n.logging;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-/**
- * This interface should be implemented by the Application subclass. It allows this module to get
- * references to the P13nLogger.
- */
-public interface P13nLoggerFactory {
-
- @Nullable
- P13nLogger newP13nLogger(@NonNull Context context);
-}
diff --git a/java/com/android/dialer/p13n/logging/P13nLogging.java b/java/com/android/dialer/p13n/logging/P13nLogging.java
deleted file mode 100644
index 21b97257b..000000000
--- a/java/com/android/dialer/p13n/logging/P13nLogging.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2016 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.dialer.p13n.logging;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import com.android.contacts.common.list.PhoneNumberListAdapter;
-import com.android.dialer.common.Assert;
-
-/** Single entry point for all logging for personalization. */
-public final class P13nLogging {
-
- private static P13nLogger logger;
-
- private P13nLogging() {}
-
- @NonNull
- public static P13nLogger get(@NonNull Context context) {
- Assert.isNotNull(context);
- Assert.isMainThread();
- if (logger != null) {
- return logger;
- }
-
- Context application = context.getApplicationContext();
- if (application instanceof P13nLoggerFactory) {
- logger = ((P13nLoggerFactory) application).newP13nLogger(context);
- }
-
- if (logger == null) {
- logger =
- new P13nLogger() {
- @Override
- public void onSearchQuery(String query, PhoneNumberListAdapter adapter) {}
-
- @Override
- public void reset() {}
- };
- }
- return logger;
- }
-
- public static void setForTesting(@NonNull P13nLogger logger) {
- P13nLogging.logger = logger;
- }
-}
diff --git a/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java b/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java
index a3d51a78f..fe6642eef 100644
--- a/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java
@@ -16,11 +16,8 @@
package com.android.dialer.phonelookup.blockednumber;
-import android.annotation.TargetApi;
import android.content.Context;
import android.database.Cursor;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
import android.provider.BlockedNumberContract.BlockedNumbers;
import android.support.annotation.NonNull;
import android.support.annotation.WorkerThread;
@@ -72,10 +69,7 @@ public class SystemBlockedNumberPhoneLookup implements PhoneLookup<SystemBlocked
if (!FilteredNumberCompat.useNewFiltering(appContext)) {
return Futures.immediateFuture(SystemBlockedNumberInfo.getDefaultInstance());
}
- return executorService.submit(
- () -> {
- return queryNumbers(ImmutableSet.of(number)).get(number);
- });
+ return executorService.submit(() -> queryNumbers(ImmutableSet.of(number)).get(number));
}
@Override
@@ -96,7 +90,6 @@ public class SystemBlockedNumberPhoneLookup implements PhoneLookup<SystemBlocked
}
@WorkerThread
- @TargetApi(VERSION_CODES.N)
private ImmutableMap<DialerPhoneNumber, SystemBlockedNumberInfo> queryNumbers(
ImmutableSet<DialerPhoneNumber> numbers) {
Assert.isWorkerThread();
@@ -171,9 +164,6 @@ public class SystemBlockedNumberPhoneLookup implements PhoneLookup<SystemBlocked
@Override
public void registerContentObservers() {
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- return;
- }
appContext
.getContentResolver()
.registerContentObserver(
diff --git a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
index 01f9669cb..d6e378cf2 100644
--- a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
+++ b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
@@ -14,14 +14,11 @@
package com.android.dialer.phonenumbercache;
-import android.annotation.TargetApi;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteFullException;
import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -53,8 +50,6 @@ import org.json.JSONException;
import org.json.JSONObject;
/** Utility class to look up the contact information for a given number. */
-// This class uses Java 7 language features, so it must target M+
-@TargetApi(VERSION_CODES.M)
public class ContactInfoHelper {
private static final String TAG = ContactInfoHelper.class.getSimpleName();
@@ -153,15 +148,6 @@ public class ContactInfoHelper {
// Get URI for the number in the PhoneLookup table, with a parameter to indicate whether
// the number is a SIP number.
Uri uri = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI;
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- if (directoryId != -1) {
- // ENTERPRISE_CONTENT_FILTER_URI in M doesn't support directory lookup
- uri = PhoneLookup.CONTENT_FILTER_URI;
- } else {
- // a bug in M. PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, encodes twice.
- number = Uri.encode(number);
- }
- }
Uri.Builder builder =
uri.buildUpon()
.appendPath(number)
@@ -187,8 +173,7 @@ public class ContactInfoHelper {
info.type = c.getInt(CallLogQuery.CACHED_NUMBER_TYPE);
info.label = c.getString(CallLogQuery.CACHED_NUMBER_LABEL);
String matchedNumber = c.getString(CallLogQuery.CACHED_MATCHED_NUMBER);
- String postDialDigits =
- (VERSION.SDK_INT >= VERSION_CODES.N) ? c.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
+ String postDialDigits = c.getString(CallLogQuery.POST_DIAL_DIGITS);
info.number =
(matchedNumber == null) ? c.getString(CallLogQuery.NUMBER) + postDialDigits : matchedNumber;
@@ -294,10 +279,7 @@ public class ContactInfoHelper {
private List<Long> getRemoteDirectories(Context context) {
List<Long> remoteDirectories = new ArrayList<>();
- Uri uri =
- VERSION.SDK_INT >= VERSION_CODES.N
- ? Directory.ENTERPRISE_CONTENT_URI
- : Directory.CONTENT_URI;
+ Uri uri = Directory.ENTERPRISE_CONTENT_URI;
Cursor cursor =
context.getContentResolver().query(uri, new String[] {Directory._ID}, null, null, null);
if (cursor == null) {
diff --git a/java/com/android/dialer/preferredsim/PreferredAccountWorker.java b/java/com/android/dialer/preferredsim/PreferredAccountWorker.java
index bfaaa7cde..aa617889e 100644
--- a/java/com/android/dialer/preferredsim/PreferredAccountWorker.java
+++ b/java/com/android/dialer/preferredsim/PreferredAccountWorker.java
@@ -24,8 +24,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.PhoneLookup;
@@ -130,9 +128,6 @@ public class PreferredAccountWorker implements Worker<Context, Result> {
private static Optional<String> getDataId(
@NonNull Context context, @Nullable String phoneNumber) {
Assert.isWorkerThread();
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- return Optional.absent();
- }
try (Cursor cursor =
context
.getContentResolver()
diff --git a/java/com/android/dialer/shortcuts/AndroidManifest.xml b/java/com/android/dialer/shortcuts/AndroidManifest.xml
index 117005841..36f61feff 100644
--- a/java/com/android/dialer/shortcuts/AndroidManifest.xml
+++ b/java/com/android/dialer/shortcuts/AndroidManifest.xml
@@ -17,7 +17,7 @@
package="com.android.dialer.shortcuts">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
<application android:theme="@style/Theme.AppCompat">
diff --git a/java/com/android/dialer/smartdial/SmartDialCursorLoader.java b/java/com/android/dialer/smartdial/SmartDialCursorLoader.java
index f2e41b22b..205362c14 100644
--- a/java/com/android/dialer/smartdial/SmartDialCursorLoader.java
+++ b/java/com/android/dialer/smartdial/SmartDialCursorLoader.java
@@ -20,7 +20,7 @@ import android.content.AsyncTaskLoader;
import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
-import com.android.contacts.common.list.PhoneNumberListAdapter.PhoneQuery;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
import com.android.dialer.common.LogUtil;
import com.android.dialer.database.Database;
import com.android.dialer.database.DialerDatabaseHelper;
@@ -28,6 +28,8 @@ import com.android.dialer.database.DialerDatabaseHelper.ContactNumber;
import com.android.dialer.smartdial.util.SmartDialNameMatcher;
import com.android.dialer.util.PermissionsUtil;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
/** Implements a Loader<Cursor> class to asynchronously load SmartDial search results. */
public class SmartDialCursorLoader extends AsyncTaskLoader<Cursor> {
@@ -179,4 +181,60 @@ public class SmartDialCursorLoader extends AsyncTaskLoader<Cursor> {
nameMatcher.setShouldMatchEmptyQuery(!show);
}
}
+
+ /** Moved from contacts/common, contains all of the projections needed for Smart Dial queries. */
+ public static class PhoneQuery {
+
+ public static final String[] PROJECTION_PRIMARY_INTERNAL =
+ new String[] {
+ Phone._ID, // 0
+ Phone.TYPE, // 1
+ Phone.LABEL, // 2
+ Phone.NUMBER, // 3
+ Phone.CONTACT_ID, // 4
+ Phone.LOOKUP_KEY, // 5
+ Phone.PHOTO_ID, // 6
+ Phone.DISPLAY_NAME_PRIMARY, // 7
+ Phone.PHOTO_THUMBNAIL_URI, // 8
+ };
+
+ public static final String[] PROJECTION_PRIMARY;
+ public static final String[] PROJECTION_ALTERNATIVE_INTERNAL =
+ new String[] {
+ Phone._ID, // 0
+ Phone.TYPE, // 1
+ Phone.LABEL, // 2
+ Phone.NUMBER, // 3
+ Phone.CONTACT_ID, // 4
+ Phone.LOOKUP_KEY, // 5
+ Phone.PHOTO_ID, // 6
+ Phone.DISPLAY_NAME_ALTERNATIVE, // 7
+ Phone.PHOTO_THUMBNAIL_URI, // 8
+ };
+ public static final String[] PROJECTION_ALTERNATIVE;
+ public static final int PHONE_ID = 0;
+ public static final int PHONE_TYPE = 1;
+ public static final int PHONE_LABEL = 2;
+ public static final int PHONE_NUMBER = 3;
+ public static final int CONTACT_ID = 4;
+ public static final int LOOKUP_KEY = 5;
+ public static final int PHOTO_ID = 6;
+ public static final int DISPLAY_NAME = 7;
+ public static final int PHOTO_URI = 8;
+ public static final int CARRIER_PRESENCE = 9;
+
+ static {
+ final List<String> projectionList =
+ new ArrayList<>(Arrays.asList(PROJECTION_PRIMARY_INTERNAL));
+ projectionList.add(Phone.CARRIER_PRESENCE); // 9
+ PROJECTION_PRIMARY = projectionList.toArray(new String[projectionList.size()]);
+ }
+
+ static {
+ final List<String> projectionList =
+ new ArrayList<>(Arrays.asList(PROJECTION_ALTERNATIVE_INTERNAL));
+ projectionList.add(Phone.CARRIER_PRESENCE); // 9
+ PROJECTION_ALTERNATIVE = projectionList.toArray(new String[projectionList.size()]);
+ }
+ }
}
diff --git a/java/com/android/dialer/spannable/AndroidManifest.xml b/java/com/android/dialer/spannable/AndroidManifest.xml
index e256dc1bb..5fa6407f7 100644
--- a/java/com/android/dialer/spannable/AndroidManifest.xml
+++ b/java/com/android/dialer/spannable/AndroidManifest.xml
@@ -17,6 +17,6 @@
package="com.android.dialer.spannable">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
</manifest>
diff --git a/java/com/android/dialer/voicemail/listui/error/VoicemailStatusWorker.java b/java/com/android/dialer/voicemail/listui/error/VoicemailStatusWorker.java
index df58d419f..e87dee3b0 100644
--- a/java/com/android/dialer/voicemail/listui/error/VoicemailStatusWorker.java
+++ b/java/com/android/dialer/voicemail/listui/error/VoicemailStatusWorker.java
@@ -32,7 +32,7 @@ import java.util.List;
/**
* Worker for {@link com.android.dialer.common.concurrent.DialerExecutors} to fetch voicemail status
*/
-@TargetApi(VERSION_CODES.M)
+@TargetApi(VERSION_CODES.N)
public class VoicemailStatusWorker implements Worker<Context, List<VoicemailStatus>> {
@Nullable
diff --git a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
index 2e76b70fe..007ab202d 100644
--- a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
+++ b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
@@ -75,7 +75,7 @@ public class VoicemailSettingsFragment extends PreferenceFragment
// Settings that are supported by dialer only if the carrier configurations are valid.
private SwitchPreference visualVoicemailPreference;
private SwitchPreference voicemailAutoArchivePreference;
- private SwitchPreference transcribeVoicemailPreference;
+ private SwitchPreferenceWithClickableSummary transcribeVoicemailPreference;
// Voicemail transcription analysis toggle
private SwitchPreferenceWithClickableSummary donateTranscribedVoicemailPreference;
private Preference voicemailChangePinPreference;
@@ -148,12 +148,24 @@ public class VoicemailSettingsFragment extends PreferenceFragment
transcribeVoicemailPreference.setOnPreferenceChangeListener(this);
transcribeVoicemailPreference.setChecked(
voicemailClient.isVoicemailTranscriptionEnabled(getContext(), phoneAccountHandle));
- transcribeVoicemailPreference.setSummary(
- R.string.voicemail_transcription_preference_summary_info);
+ transcribeVoicemailPreference.setSummary(getVoicemailTranscriptionInformationalText());
transcribeVoicemailPreference.setEnabled(true);
getPreferenceScreen().addPreference(transcribeVoicemailPreference);
}
+ /**
+ * Builds a spannable string containing the voicemail transcription informational text containing
+ * the appropriate "Learn More" urls.
+ *
+ * @return The voicemail transcription information text.
+ */
+ private CharSequence getVoicemailTranscriptionInformationalText() {
+ return new ContentWithLearnMoreSpanner(getContext())
+ .create(
+ getContext().getString(R.string.voicemail_transcription_preference_summary_info),
+ getContext().getString(R.string.transcription_learn_more_url));
+ }
+
private void updateTranscriptionDonationPreference() {
if (!VoicemailComponent.get(getContext())
.getVoicemailClient()
@@ -231,7 +243,7 @@ public class VoicemailSettingsFragment extends PreferenceFragment
voicemailAutoArchivePreference.setOrder(VMSettingOrdering.VOICEMAIL_AUTO_ARCHIVE);
transcribeVoicemailPreference =
- (SwitchPreference)
+ (SwitchPreferenceWithClickableSummary)
findPreference(getString(R.string.voicemail_visual_voicemail_transcription_key));
transcribeVoicemailPreference.setOrder(VMSettingOrdering.VOICEMAIL_TRANSCRIPTION);
diff --git a/java/com/android/dialer/voicemail/settings/res/values/strings.xml b/java/com/android/dialer/voicemail/settings/res/values/strings.xml
index 7df8a0192..ad245ee47 100644
--- a/java/com/android/dialer/voicemail/settings/res/values/strings.xml
+++ b/java/com/android/dialer/voicemail/settings/res/values/strings.xml
@@ -119,7 +119,7 @@
<string name="voicemail_activating_summary_info">Activating voicemail</string>
<!-- Summary information for visual voicemail transcription setting [CHAR LIMIT=NONE] -->
- <string name="voicemail_transcription_preference_summary_info">Get transcripts of your voicemail using Google\'s transcription service.</string>
+ <string name="voicemail_transcription_preference_summary_info">Get transcripts of your voicemail using Google\'s transcription service. <xliff:g example="Learn more">%1$s</xliff:g></string>
<!-- Summary information for visual voicemail donation setting [CHAR LIMIT=NONE] -->
<string name="voicemail_donate_preference_summary_info">Let Google review your voicemail messages to improve transcription accuracy. Your voicemail messages are stored anonymously. <xliff:g example="Learn more">%1$s</xliff:g></string>
diff --git a/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml b/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
index e5af813b6..fc839ee3e 100644
--- a/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
+++ b/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
@@ -31,10 +31,11 @@
android:key="@string/voicemail_visual_voicemail_archive_key"
android:title="@string/voicemail_visual_voicemail_auto_archive_switch_title"/>"
- <SwitchPreference
+ <com.android.dialer.common.preference.SwitchPreferenceWithClickableSummary
android:dependency="@string/voicemail_visual_voicemail_key"
android:key="@string/voicemail_visual_voicemail_transcription_key"
- android:title="@string/voicemail_visual_voicemail_transcription_switch_title"/>"
+ android:title="@string/voicemail_visual_voicemail_transcription_switch_title"
+ app:urlToOpen="@string/transcription_learn_more_url"/>
<com.android.dialer.common.preference.SwitchPreferenceWithClickableSummary
android:dependency="@string/voicemail_visual_voicemail_transcription_key"
diff --git a/java/com/android/incallui/AndroidManifest.xml b/java/com/android/incallui/AndroidManifest.xml
index 24177979e..9a762feea 100644
--- a/java/com/android/incallui/AndroidManifest.xml
+++ b/java/com/android/incallui/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.android.incallui">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
<uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
diff --git a/java/com/android/incallui/CallerInfoAsyncQuery.java b/java/com/android/incallui/CallerInfoAsyncQuery.java
index 87dcc4f40..4170cc318 100644
--- a/java/com/android/incallui/CallerInfoAsyncQuery.java
+++ b/java/com/android/incallui/CallerInfoAsyncQuery.java
@@ -53,7 +53,7 @@ import java.util.Arrays;
*
* @see CallerInfo
*/
-@TargetApi(VERSION_CODES.M)
+@TargetApi(VERSION_CODES.N)
public class CallerInfoAsyncQuery {
/** Interface for a CallerInfoAsyncQueryHandler result return. */
diff --git a/java/com/android/incallui/answer/impl/hint/PawImageLoaderImpl.java b/java/com/android/incallui/answer/impl/hint/PawImageLoaderImpl.java
index 31b17112b..aef56872a 100644
--- a/java/com/android/incallui/answer/impl/hint/PawImageLoaderImpl.java
+++ b/java/com/android/incallui/answer/impl/hint/PawImageLoaderImpl.java
@@ -29,7 +29,7 @@ import com.android.dialer.storage.StorageComponent;
import com.android.incallui.answer.impl.hint.PawSecretCodeListener.PawType;
/** Decrypt the event payload to be shown if in a specific time range and the key is received. */
-@TargetApi(VERSION_CODES.M)
+@TargetApi(VERSION_CODES.N)
public final class PawImageLoaderImpl implements PawImageLoader {
@Override
diff --git a/java/com/android/incallui/autoresizetext/AndroidManifest.xml b/java/com/android/incallui/autoresizetext/AndroidManifest.xml
index e26670e52..1ba8b7c04 100644
--- a/java/com/android/incallui/autoresizetext/AndroidManifest.xml
+++ b/java/com/android/incallui/autoresizetext/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.android.incallui.autoresizetext">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
<application />
diff --git a/java/com/android/incallui/legacyblocking/DeleteBlockedCallTask.java b/java/com/android/incallui/legacyblocking/DeleteBlockedCallTask.java
index a3f2dfa4d..f9fe6a68a 100644
--- a/java/com/android/incallui/legacyblocking/DeleteBlockedCallTask.java
+++ b/java/com/android/incallui/legacyblocking/DeleteBlockedCallTask.java
@@ -34,7 +34,7 @@ import java.util.Objects;
* versions of the OS, call blocking is implemented in the system and there's no need to mess with
* the call log.
*/
-@TargetApi(VERSION_CODES.M)
+@TargetApi(VERSION_CODES.N)
public class DeleteBlockedCallTask extends AsyncTask<Void, Void, Long> {
public static final String IDENTIFIER = "DeleteBlockedCallTask";
diff --git a/java/com/android/incallui/rtt/protocol/AndroidManifest.xml b/java/com/android/incallui/rtt/protocol/AndroidManifest.xml
index 52514a501..c0d39b091 100644
--- a/java/com/android/incallui/rtt/protocol/AndroidManifest.xml
+++ b/java/com/android/incallui/rtt/protocol/AndroidManifest.xml
@@ -17,6 +17,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.incallui.rtt.protocol">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="26"/>
</manifest> \ No newline at end of file
diff --git a/java/com/android/incallui/spam/SpamCallListListener.java b/java/com/android/incallui/spam/SpamCallListListener.java
index 22b383332..9ef65d877 100644
--- a/java/com/android/incallui/spam/SpamCallListListener.java
+++ b/java/com/android/incallui/spam/SpamCallListListener.java
@@ -87,7 +87,7 @@ public class SpamCallListListener implements CallList.Listener {
}
/** Checks if the number is in the call history. */
- @TargetApi(VERSION_CODES.M)
+ @TargetApi(VERSION_CODES.N)
private static final class NumberInCallHistoryWorker implements Worker<Void, Integer> {
private final Context appContext;
diff --git a/java/com/android/incallui/video/protocol/AndroidManifest.xml b/java/com/android/incallui/video/protocol/AndroidManifest.xml
index 6f6558278..f059b191f 100644
--- a/java/com/android/incallui/video/protocol/AndroidManifest.xml
+++ b/java/com/android/incallui/video/protocol/AndroidManifest.xml
@@ -17,6 +17,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.incallui.video.protocol">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
</manifest>
diff --git a/java/com/android/incallui/videotech/ims/ImsVideoTech.java b/java/com/android/incallui/videotech/ims/ImsVideoTech.java
index a2fb73bd2..d9660e192 100644
--- a/java/com/android/incallui/videotech/ims/ImsVideoTech.java
+++ b/java/com/android/incallui/videotech/ims/ImsVideoTech.java
@@ -17,7 +17,6 @@
package com.android.incallui.videotech.ims;
import android.content.Context;
-import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
@@ -61,10 +60,6 @@ public class ImsVideoTech implements VideoTech {
@Override
public boolean isAvailable(Context context, PhoneAccountHandle phoneAccountHandle) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- return false;
- }
-
if (call.getVideoCall() == null) {
return false;
}
diff --git a/java/com/android/voicemail/AndroidManifest.xml b/java/com/android/voicemail/AndroidManifest.xml
index d64fb2504..23c746a80 100644
--- a/java/com/android/voicemail/AndroidManifest.xml
+++ b/java/com/android/voicemail/AndroidManifest.xml
@@ -17,7 +17,7 @@
package="com.android.voicemail">
<uses-sdk
- android:minSdkVersion="23"
+ android:minSdkVersion="24"
android:targetSdkVersion="27"/>
<!-- Applications using this module should merge these permissions using android_manifest_merge -->
diff --git a/java/com/android/voicemail/impl/PackageReplacedReceiver.java b/java/com/android/voicemail/impl/PackageReplacedReceiver.java
index bc56286fb..9fa9f75c7 100644
--- a/java/com/android/voicemail/impl/PackageReplacedReceiver.java
+++ b/java/com/android/voicemail/impl/PackageReplacedReceiver.java
@@ -91,7 +91,7 @@ public class PackageReplacedReceiver extends BroadcastReceiver {
this.context = context;
}
- @TargetApi(android.os.Build.VERSION_CODES.M) // used for try with resources
+ @TargetApi(android.os.Build.VERSION_CODES.N) // used for try with resources
@Override
public Void doInBackground(Void arg) throws Throwable {
LogUtil.i("PackageReplacedReceiver.ExistingVoicemailCheck.doInBackground", "");
diff --git a/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java b/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java
index c47b40dab..be11c4453 100644
--- a/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java
+++ b/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java
@@ -256,7 +256,7 @@ public class VoicemailsQueryHelper {
}
/** Find the oldest voicemails that are on the device, and also on the server. */
- @TargetApi(VERSION_CODES.M) // used for try with resources
+ @TargetApi(VERSION_CODES.N) // used for try with resources
public List<Voicemail> oldestVoicemailsOnServer(int numVoicemails) {
if (numVoicemails <= 0) {
Assert.fail("Query for remote voicemails cannot be <= 0");
diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionUtils.java b/java/com/android/voicemail/impl/transcribe/TranscriptionUtils.java
index 3bd14731f..d8c00ed91 100644
--- a/java/com/android/voicemail/impl/transcribe/TranscriptionUtils.java
+++ b/java/com/android/voicemail/impl/transcribe/TranscriptionUtils.java
@@ -34,7 +34,7 @@ public class TranscriptionUtils {
static final String AMR_PREFIX = "#!AMR\n";
// Uses try-with-resource
- @TargetApi(android.os.Build.VERSION_CODES.M)
+ @TargetApi(android.os.Build.VERSION_CODES.N)
static ByteString getAudioData(Context context, Uri voicemailUri) {
try (InputStream in = context.getContentResolver().openInputStream(voicemailUri)) {
return ByteString.readFrom(in);