Merge "[DO NOT MERGE] Bump version number from 2.3.14 to 2.3.15" into ub-contactsdialer-a-dev
am: dfad2c5a1d -s ours
* commit 'dfad2c5a1d88b4b843f0d4c618339da0af9a0299':
[DO NOT MERGE] Bump version number from 2.3.14 to 2.3.15
diff --git a/Android.mk b/Android.mk
index bd0c9de..47648db 100644
--- a/Android.mk
+++ b/Android.mk
@@ -60,7 +60,7 @@
# Uncomment the following line to build against the current SDK
# This is required for building an unbundled app.
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := system_current
include $(BUILD_PACKAGE)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 496e5f2..9d5af42 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -17,8 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.dialer"
coreApp="true"
- android:versionCode="20315"
- android:versionName="2.3.15">
+ android:versionCode="20314"
+ android:versionName="2.3.14">
<uses-sdk
android:minSdkVersion="23"
diff --git a/src/com/android/dialer/CallDetailActivity.java b/src/com/android/dialer/CallDetailActivity.java
index 88d3fe2..c045967 100644
--- a/src/com/android/dialer/CallDetailActivity.java
+++ b/src/com/android/dialer/CallDetailActivity.java
@@ -43,6 +43,7 @@
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.GeoUtil;
+import com.android.contacts.common.compat.CompatUtils;
import com.android.contacts.common.interactions.TouchPointManager;
import com.android.contacts.common.preference.ContactsPreferences;
import com.android.contacts.common.testing.NeededForTesting;
@@ -109,11 +110,19 @@
// All calls are from the same number and same contact, so pick the first detail.
mDetails = details[0];
mNumber = TextUtils.isEmpty(mDetails.number) ? null : mDetails.number.toString();
+ mPostDialDigits = TextUtils.isEmpty(mDetails.postDialDigits)
+ ? "" : mDetails.postDialDigits;
mDisplayNumber = mDetails.displayNumber;
final CharSequence callLocationOrType = getNumberTypeOrLocation(mDetails);
- final CharSequence displayNumber = mDetails.displayNumber;
+ final CharSequence displayNumber;
+ if (!TextUtils.isEmpty(mDetails.postDialDigits)) {
+ displayNumber = mDetails.number + mDetails.postDialDigits;
+ } else {
+ displayNumber = mDetails.displayNumber;
+ }
+
final String displayNumberStr = mBidiFormatter.unicodeWrap(
displayNumber.toString(), TextDirectionHeuristics.LTR);
@@ -199,6 +208,7 @@
private PhoneCallDetails mDetails;
protected String mNumber;
private Uri mVoicemailUri;
+ private String mPostDialDigits = "";
private String mDisplayNumber;
private ListView mHistoryList;
@@ -240,7 +250,9 @@
mQuickContactBadge = (QuickContactBadge) findViewById(R.id.quick_contact_photo);
mQuickContactBadge.setOverlay(null);
- mQuickContactBadge.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
+ if (CompatUtils.hasPrioritizedMimeType()) {
+ mQuickContactBadge.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
+ }
mCallerName = (TextView) findViewById(R.id.caller_name);
mCallerNumber = (TextView) findViewById(R.id.caller_number);
mAccountLabel = (TextView) findViewById(R.id.phone_account_label);
@@ -254,7 +266,7 @@
return;
}
mContext.startActivity(
- new CallIntentBuilder(mNumber)
+ new CallIntentBuilder(getDialableNumber())
.setCallInitiationType(LogState.INITIATION_CALL_DETAILS)
.build());
}
@@ -372,7 +384,8 @@
ClipboardUtils.copyText(mContext, null, mNumber, true);
break;
case R.id.call_detail_action_edit_before_call:
- Intent dialIntent = new Intent(Intent.ACTION_DIAL, CallUtil.getCallUri(mNumber));
+ Intent dialIntent = new Intent(Intent.ACTION_DIAL,
+ CallUtil.getCallUri(getDialableNumber()));
DialerUtils.startActivityWithErrorToast(mContext, dialIntent);
break;
default:
@@ -468,6 +481,10 @@
sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
}
+ private String getDialableNumber() {
+ return mNumber + mPostDialDigits;
+ }
+
@NeededForTesting
public boolean hasVoicemail() {
return mVoicemailUri != null;
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index 6de1fdc..a6fb98c 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -787,7 +787,13 @@
return;
}
if (clearDialpad) {
+ // Temporarily disable accessibility when we clear the dialpad, since it should be
+ // invisible and should not announce anything.
+ mDialpadFragment.getDigitsWidget().setImportantForAccessibility(
+ View.IMPORTANT_FOR_ACCESSIBILITY_NO);
mDialpadFragment.clearDialpad();
+ mDialpadFragment.getDigitsWidget().setImportantForAccessibility(
+ View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
}
if (!mIsDialpadShown) {
return;
diff --git a/src/com/android/dialer/PhoneCallDetails.java b/src/com/android/dialer/PhoneCallDetails.java
index fb1827d..71aa26d 100644
--- a/src/com/android/dialer/PhoneCallDetails.java
+++ b/src/com/android/dialer/PhoneCallDetails.java
@@ -31,6 +31,8 @@
public class PhoneCallDetails {
// The number of the other party involved in the call.
public CharSequence number;
+ // Post-dial digits associated with the outgoing call.
+ public String postDialDigits;
// The number presenting rules set by the network, e.g., {@link Calls#PRESENTATION_ALLOWED}
public int numberPresentation;
// The formatted version of {@link #number}.
@@ -114,16 +116,19 @@
CharSequence number,
int numberPresentation,
CharSequence formattedNumber,
+ CharSequence postDialDigits,
boolean isVoicemail) {
this.number = number;
this.numberPresentation = numberPresentation;
this.formattedNumber = formattedNumber;
this.isVoicemail = isVoicemail;
+ this.postDialDigits = postDialDigits.toString();
this.displayNumber = PhoneNumberDisplayUtil.getDisplayNumber(
context,
this.number,
this.numberPresentation,
this.formattedNumber,
+ this.postDialDigits,
this.isVoicemail).toString();
}
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 55e2fa0..dac50ff 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -41,10 +41,12 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
+import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
import com.android.contacts.common.preference.ContactsPreferences;
import com.android.contacts.common.util.PermissionsUtil;
import com.android.dialer.PhoneCallDetails;
import com.android.dialer.R;
+import com.android.dialer.calllog.calllogcache.CallLogCache;
import com.android.dialer.contactinfo.ContactInfoCache;
import com.android.dialer.contactinfo.ContactInfoCache.OnContactInfoChangedListener;
import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
@@ -131,8 +133,8 @@
/** Instance of helper class for managing views. */
private final CallLogListItemHelper mCallLogListItemHelper;
- /** Cache for repeated requests to TelecomManager. */
- protected final TelecomCallLogCache mTelecomCallLogCache;
+ /** Cache for repeated requests to Telecom/Telephony. */
+ protected final CallLogCache mCallLogCache;
/** Helper to group call log entries. */
private final CallLogGroupBuilder mCallLogGroupBuilder;
@@ -260,11 +262,12 @@
Resources resources = mContext.getResources();
CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
- mTelecomCallLogCache = new TelecomCallLogCache(mContext);
+ mCallLogCache = CallLogCache.getCallLogCache(mContext);
+
PhoneCallDetailsHelper phoneCallDetailsHelper =
- new PhoneCallDetailsHelper(mContext, resources, mTelecomCallLogCache);
+ new PhoneCallDetailsHelper(mContext, resources, mCallLogCache);
mCallLogListItemHelper =
- new CallLogListItemHelper(phoneCallDetailsHelper, resources, mTelecomCallLogCache);
+ new CallLogListItemHelper(phoneCallDetailsHelper, resources, mCallLogCache);
mCallLogGroupBuilder = new CallLogGroupBuilder(this);
mFilteredNumberAsyncQueryHandler =
new FilteredNumberAsyncQueryHandler(mContext.getContentResolver());
@@ -331,7 +334,7 @@
@VisibleForTesting
/* package */ void pauseCache() {
mContactInfoCache.stop();
- mTelecomCallLogCache.reset();
+ mCallLogCache.reset();
}
@Override
@@ -360,7 +363,7 @@
view,
mContext,
mExpandCollapseListener,
- mTelecomCallLogCache,
+ mCallLogCache,
mCallLogListItemHelper,
mVoicemailPlaybackPresenter,
mFilteredNumberAsyncQueryHandler,
@@ -441,6 +444,9 @@
int count = getGroupSize(position);
final String number = c.getString(CallLogQuery.NUMBER);
+ final String postDialDigits = PhoneNumberDisplayUtil.canShowPostDial()
+ ? c.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
+
final int numberPresentation = c.getInt(CallLogQuery.NUMBER_PRESENTATION);
final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount(
c.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME),
@@ -448,7 +454,7 @@
final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
final ContactInfo cachedContactInfo = ContactInfoHelper.getContactInfo(c);
final boolean isVoicemailNumber =
- mTelecomCallLogCache.isVoicemailNumber(accountHandle, number);
+ mCallLogCache.isVoicemailNumber(accountHandle, number);
// Note: Binding of the action buttons is done as required in configureActionViews when the
// user expands the actions ViewStub.
@@ -456,13 +462,15 @@
ContactInfo info = ContactInfo.EMPTY;
if (PhoneNumberUtil.canPlaceCallsTo(number, numberPresentation) && !isVoicemailNumber) {
// Lookup contacts with this number
- info = mContactInfoCache.getValue(number, countryIso, cachedContactInfo);
+ info = mContactInfoCache.getValue(number + postDialDigits,
+ countryIso, cachedContactInfo);
}
CharSequence formattedNumber = info.formattedNumber == null
- ? null : PhoneNumberUtils.createTtsSpannable(info.formattedNumber);
+ ? null : PhoneNumberUtilsCompat.createTtsSpannable(info.formattedNumber);
final PhoneCallDetails details = new PhoneCallDetails(
- mContext, number, numberPresentation, formattedNumber, isVoicemailNumber);
+ mContext, number, numberPresentation, formattedNumber,
+ postDialDigits, isVoicemailNumber);
details.accountHandle = accountHandle;
details.callTypes = getCallTypes(c, count);
details.countryIso = countryIso;
@@ -496,6 +504,7 @@
views.rowId = c.getLong(CallLogQuery.ID);
// Store values used when the actions ViewStub is inflated on expansion.
views.number = number;
+ views.postDialDigits = details.postDialDigits;
views.displayNumber = details.displayNumber;
views.numberPresentation = numberPresentation;
views.callType = c.getInt(CallLogQuery.CALL_TYPE);
diff --git a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
index 7771563..bb7bdbd 100644
--- a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
+++ b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
@@ -39,6 +39,9 @@
import com.google.common.annotations.VisibleForTesting;
+import java.util.ArrayList;
+import java.util.Arrays;
+
public class CallLogAsyncTaskUtil {
private static String TAG = CallLogAsyncTaskUtil.class.getSimpleName();
@@ -51,8 +54,9 @@
GET_CALL_DETAILS,
}
- private static class CallDetailQuery {
- static final String[] CALL_LOG_PROJECTION = new String[] {
+ private static final class CallDetailQuery {
+
+ private static final String[] CALL_LOG_PROJECTION_INTERNAL = new String[] {
CallLog.Calls.DATE,
CallLog.Calls.DURATION,
CallLog.Calls.NUMBER,
@@ -66,6 +70,7 @@
CallLog.Calls.DATA_USAGE,
CallLog.Calls.TRANSCRIPTION
};
+ public static final String[] CALL_LOG_PROJECTION;
static final int DATE_COLUMN_INDEX = 0;
static final int DURATION_COLUMN_INDEX = 1;
@@ -79,6 +84,17 @@
static final int FEATURES = 9;
static final int DATA_USAGE = 10;
static final int TRANSCRIPTION_COLUMN_INDEX = 11;
+ static final int POST_DIAL_DIGITS = 12;
+
+ static {
+ ArrayList<String> projectionList = new ArrayList<>();
+ projectionList.addAll(Arrays.asList(CALL_LOG_PROJECTION_INTERNAL));
+ if (PhoneNumberDisplayUtil.canShowPostDial()) {
+ projectionList.add(AppCompatConstants.POST_DIAL_DIGITS);
+ }
+ projectionList.trimToSize();
+ CALL_LOG_PROJECTION = projectionList.toArray(new String[projectionList.size()]);
+ }
}
private static class CallLogDeleteBlockedCallQuery {
@@ -164,6 +180,8 @@
// Read call log.
final String countryIso = cursor.getString(CallDetailQuery.COUNTRY_ISO_COLUMN_INDEX);
final String number = cursor.getString(CallDetailQuery.NUMBER_COLUMN_INDEX);
+ final String postDialDigits = PhoneNumberDisplayUtil.canShowPostDial()
+ ? cursor.getString(CallDetailQuery.POST_DIAL_DIGITS) : "";
final int numberPresentation =
cursor.getInt(CallDetailQuery.NUMBER_PRESENTATION_COLUMN_INDEX);
@@ -185,7 +203,8 @@
}
PhoneCallDetails details = new PhoneCallDetails(
- context, number, numberPresentation, info.formattedNumber, isVoicemail);
+ context, number, numberPresentation, info.formattedNumber,
+ postDialDigits, isVoicemail);
details.accountHandle = accountHandle;
details.contactUri = info.lookupUri;
diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java
index ab5bd43..fa6deaf 100644
--- a/src/com/android/dialer/calllog/CallLogFragment.java
+++ b/src/com/android/dialer/calllog/CallLogFragment.java
@@ -33,6 +33,7 @@
import android.provider.CallLog.Calls;
import android.provider.ContactsContract;
import android.provider.VoicemailContract.Status;
+import android.support.v13.app.FragmentCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -55,7 +56,8 @@
* (all, missed or voicemails), specify it in the constructor.
*/
public class CallLogFragment extends Fragment implements CallLogQueryHandler.Listener,
- CallLogAdapter.CallFetcher, OnEmptyViewActionButtonClickedListener {
+ CallLogAdapter.CallFetcher, OnEmptyViewActionButtonClickedListener,
+ FragmentCompat.OnRequestPermissionsResultCallback {
private static final String TAG = "CallLogFragment";
/**
@@ -513,7 +515,8 @@
}
if (!PermissionsUtil.hasPermission(activity, READ_CALL_LOG)) {
- requestPermissions(new String[] {READ_CALL_LOG}, READ_CALL_LOG_PERMISSION_REQUEST_CODE);
+ FragmentCompat.requestPermissions(this, new String[] {READ_CALL_LOG},
+ READ_CALL_LOG_PERMISSION_REQUEST_CODE);
} else if (!mIsCallLogActivity) {
// Show dialpad if we are not in the call log activity.
((HostInterface) activity).showDialpad();
diff --git a/src/com/android/dialer/calllog/CallLogGroupBuilder.java b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
index 5eea096..194231b 100644
--- a/src/com/android/dialer/calllog/CallLogGroupBuilder.java
+++ b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
@@ -17,7 +17,6 @@
package com.android.dialer.calllog;
import android.database.Cursor;
-import android.provider.CallLog.Calls;
import android.telephony.PhoneNumberUtils;
import android.text.format.Time;
import android.text.TextUtils;
@@ -28,8 +27,6 @@
import com.google.common.annotations.VisibleForTesting;
-import java.util.Objects;
-
/**
* Groups together calls in the call log. The primary grouping attempts to group together calls
* to and from the same number into a single row on the call log.
@@ -125,12 +122,15 @@
// Instantiate the group values to those of the first call in the cursor.
String groupNumber = cursor.getString(CallLogQuery.NUMBER);
+ String groupPostDialDigits = PhoneNumberDisplayUtil.canShowPostDial()
+ ? cursor.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
int groupCallType = cursor.getInt(CallLogQuery.CALL_TYPE);
String groupAccountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
String groupAccountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
int groupSize = 1;
String number;
+ String numberPostDialDigits;
int callType;
String accountComponentName;
String accountId;
@@ -138,17 +138,21 @@
while (cursor.moveToNext()) {
// Obtain the values for the current call to group.
number = cursor.getString(CallLogQuery.NUMBER);
+ numberPostDialDigits = PhoneNumberDisplayUtil.canShowPostDial()
+ ? cursor.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
callType = cursor.getInt(CallLogQuery.CALL_TYPE);
accountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
accountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
final boolean isSameNumber = equalNumbers(groupNumber, number);
+ final boolean isSamePostDialDigits = groupPostDialDigits.equals(numberPostDialDigits);
final boolean isSameAccount = isSameAccount(
groupAccountComponentName, accountComponentName, groupAccountId, accountId);
// Group with the same number and account. Never group voicemails. Only group blocked
// calls with other blocked calls.
- if (isSameNumber && isSameAccount && areBothNotVoicemail(callType, groupCallType)
+ if (isSameNumber && isSameAccount && isSamePostDialDigits
+ && areBothNotVoicemail(callType, groupCallType)
&& (areBothNotBlocked(callType, groupCallType)
|| areBothBlocked(callType, groupCallType))) {
// Increment the size of the group to include the current call, but do not create
@@ -168,6 +172,7 @@
// Update the group values to those of the current call.
groupNumber = number;
+ groupPostDialDigits = numberPostDialDigits;
groupCallType = callType;
groupAccountComponentName = accountComponentName;
groupAccountId = accountId;
diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java
index be0e146..5d2bc85 100644
--- a/src/com/android/dialer/calllog/CallLogListItemHelper.java
+++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java
@@ -16,7 +16,6 @@
package com.android.dialer.calllog;
-import android.content.Context;
import android.content.res.Resources;
import android.provider.CallLog.Calls;
import android.text.SpannableStringBuilder;
@@ -26,6 +25,7 @@
import com.android.dialer.PhoneCallDetails;
import com.android.dialer.util.AppCompatConstants;
import com.android.dialer.R;
+import com.android.dialer.calllog.calllogcache.CallLogCache;
/**
* Helper class to fill in the views of a call log entry.
@@ -37,21 +37,22 @@
private final PhoneCallDetailsHelper mPhoneCallDetailsHelper;
/** Resources to look up strings. */
private final Resources mResources;
- private final TelecomCallLogCache mTelecomCallLogCache;
+ private final CallLogCache mCallLogCache;
/**
* Creates a new helper instance.
*
* @param phoneCallDetailsHelper used to set the details of a phone call
- * @param phoneNumberHelper used to process phone number
+ * @param resources The object from which resources can be retrieved
+ * @param callLogCache A cache for values retrieved from telecom/telephony
*/
public CallLogListItemHelper(
PhoneCallDetailsHelper phoneCallDetailsHelper,
Resources resources,
- TelecomCallLogCache telecomCallLogCache) {
+ CallLogCache callLogCache) {
mPhoneCallDetailsHelper = phoneCallDetailsHelper;
mResources = resources;
- mTelecomCallLogCache = telecomCallLogCache;
+ mCallLogCache = callLogCache;
}
/**
@@ -188,7 +189,7 @@
}
int stringID = getCallDescriptionStringID(details.callTypes, details.isRead);
- String accountLabel = mTelecomCallLogCache.getAccountLabel(details.accountHandle);
+ String accountLabel = mCallLogCache.getAccountLabel(details.accountHandle);
// Use chosen string resource to build up the message.
CharSequence onAccountLabel = accountLabel == null
@@ -263,7 +264,7 @@
if (!TextUtils.isEmpty(details.getPreferredName())) {
recipient = details.getPreferredName();
} else {
- recipient = details.displayNumber;
+ recipient = details.displayNumber + details.postDialDigits;
}
return recipient;
}
diff --git a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
index 63fbe29..21f3213 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
@@ -27,7 +27,6 @@
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.telecom.PhoneAccountHandle;
-import android.telephony.PhoneNumberUtils;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
@@ -43,11 +42,14 @@
import com.android.contacts.common.ClipboardUtils;
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
import com.android.contacts.common.dialog.CallSubjectDialog;
import com.android.contacts.common.testing.NeededForTesting;
import com.android.contacts.common.util.UriUtils;
import com.android.dialer.DialtactsActivity;
import com.android.dialer.R;
+import com.android.dialer.calllog.calllogcache.CallLogCache;
import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
import com.android.dialer.filterednumber.BlockNumberDialogFragment;
import com.android.dialer.filterednumber.FilteredNumbersUtil;
@@ -114,6 +116,11 @@
public String number;
/**
+ * The post-dial numbers that are dialed following the phone number.
+ */
+ public String postDialDigits;
+
+ /**
* The formatted phone number to display.
*/
public String displayNumber;
@@ -183,7 +190,7 @@
public ContactInfo info;
private final Context mContext;
- private final TelecomCallLogCache mTelecomCallLogCache;
+ private final CallLogCache mCallLogCache;
private final CallLogListItemHelper mCallLogListItemHelper;
private final VoicemailPlaybackPresenter mVoicemailPlaybackPresenter;
private final FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
@@ -197,7 +204,7 @@
private CallLogListItemViewHolder(
Context context,
View.OnClickListener expandCollapseListener,
- TelecomCallLogCache telecomCallLogCache,
+ CallLogCache callLogCache,
CallLogListItemHelper callLogListItemHelper,
VoicemailPlaybackPresenter voicemailPlaybackPresenter,
FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler,
@@ -213,7 +220,7 @@
mContext = context;
mExpandCollapseListener = expandCollapseListener;
- mTelecomCallLogCache = telecomCallLogCache;
+ mCallLogCache = callLogCache;
mCallLogListItemHelper = callLogListItemHelper;
mVoicemailPlaybackPresenter = voicemailPlaybackPresenter;
mFilteredNumberAsyncQueryHandler = filteredNumberAsyncQueryHandler;
@@ -235,8 +242,9 @@
phoneCallDetailsViews.callLocationAndDate.setElegantTextHeight(false);
quickContactView.setOverlay(null);
- quickContactView.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
-
+ if (CompatUtils.hasPrioritizedMimeType()) {
+ quickContactView.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
+ }
primaryActionButtonView.setOnClickListener(this);
primaryActionView.setOnClickListener(mExpandCollapseListener);
primaryActionView.setOnCreateContextMenuListener(this);
@@ -246,7 +254,7 @@
View view,
Context context,
View.OnClickListener expandCollapseListener,
- TelecomCallLogCache telecomCallLogCache,
+ CallLogCache callLogCache,
CallLogListItemHelper callLogListItemHelper,
VoicemailPlaybackPresenter voicemailPlaybackPresenter,
FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler,
@@ -255,7 +263,7 @@
return new CallLogListItemViewHolder(
context,
expandCollapseListener,
- telecomCallLogCache,
+ callLogCache,
callLogListItemHelper,
voicemailPlaybackPresenter,
filteredNumberAsyncQueryHandler,
@@ -279,7 +287,7 @@
if (callType == CallLog.Calls.VOICEMAIL_TYPE) {
menu.setHeaderTitle(mContext.getResources().getText(R.string.voicemail));
} else {
- menu.setHeaderTitle(PhoneNumberUtils.createTtsSpannable(
+ menu.setHeaderTitle(PhoneNumberUtilsCompat.createTtsSpannable(
BidiFormatter.getInstance().unicodeWrap(number, TextDirectionHeuristics.LTR)));
}
@@ -293,7 +301,7 @@
// 3) Number is a SIP address
if (PhoneNumberUtil.canPlaceCallsTo(number, numberPresentation)
- && !mTelecomCallLogCache.isVoicemailNumber(accountHandle, number)
+ && !mCallLogCache.isVoicemailNumber(accountHandle, number)
&& !PhoneNumberUtil.isSipNumber(number)) {
menu.add(ContextMenu.NONE, R.id.context_menu_edit_before_call, ContextMenu.NONE,
R.string.action_edit_number_before_call)
@@ -414,14 +422,14 @@
// Treat as normal list item; show call button, if possible.
if (PhoneNumberUtil.canPlaceCallsTo(number, numberPresentation)) {
boolean isVoicemailNumber =
- mTelecomCallLogCache.isVoicemailNumber(accountHandle, number);
+ mCallLogCache.isVoicemailNumber(accountHandle, number);
if (isVoicemailNumber) {
// Call to generic voicemail number, in case there are multiple accounts.
primaryActionButtonView.setTag(
IntentProvider.getReturnVoicemailCallIntentProvider());
} else {
primaryActionButtonView.setTag(
- IntentProvider.getReturnCallIntentProvider(number));
+ IntentProvider.getReturnCallIntentProvider(number + postDialDigits));
}
primaryActionButtonView.setContentDescription(TextUtils.expandTemplate(
@@ -463,7 +471,7 @@
}
// If one of the calls had video capabilities, show the video call button.
- if (mTelecomCallLogCache.isVideoEnabled() && canPlaceCallToNumber &&
+ if (mCallLogCache.isVideoEnabled() && canPlaceCallToNumber &&
phoneCallDetailsViews.callTypeIcons.isVideoShown()) {
videoCallButtonView.setTag(IntentProvider.getReturnVideoCallIntentProvider(number));
videoCallButtonView.setVisibility(View.VISIBLE);
@@ -517,9 +525,9 @@
mCallLogListItemHelper.setActionContentDescriptions(this);
boolean supportsCallSubject =
- mTelecomCallLogCache.doesAccountSupportCallSubject(accountHandle);
+ mCallLogCache.doesAccountSupportCallSubject(accountHandle);
boolean isVoicemailNumber =
- mTelecomCallLogCache.isVoicemailNumber(accountHandle, number);
+ mCallLogCache.isVoicemailNumber(accountHandle, number);
callWithNoteButtonView.setVisibility(
supportsCallSubject && !isVoicemailNumber ? View.VISIBLE : View.GONE);
}
@@ -565,7 +573,7 @@
public void updatePhoto() {
quickContactView.assignContactUri(info.lookupUri);
- final boolean isVoicemail = mTelecomCallLogCache.isVoicemailNumber(accountHandle, number);
+ final boolean isVoicemail = mCallLogCache.isVoicemailNumber(accountHandle, number);
int contactType = ContactPhotoManager.TYPE_DEFAULT;
if (isVoicemail) {
contactType = ContactPhotoManager.TYPE_VOICEMAIL;
@@ -601,7 +609,7 @@
info.lookupUri,
(String) nameOrNumber /* top line of contact view in call subject dialog */,
isBusiness,
- number, /* callable number used for ACTION_CALL intent */
+ number,
TextUtils.isEmpty(info.name) ? null : displayNumber, /* second line of contact
view in dialog. */
numberType, /* phone number type (e.g. mobile) in second line of contact view */
@@ -621,15 +629,16 @@
@NeededForTesting
public static CallLogListItemViewHolder createForTest(Context context) {
Resources resources = context.getResources();
- TelecomCallLogCache telecomCallLogCache = new TelecomCallLogCache(context);
+ CallLogCache callLogCache =
+ CallLogCache.getCallLogCache(context);
PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
- context, resources, telecomCallLogCache);
+ context, resources, callLogCache);
CallLogListItemViewHolder viewHolder = new CallLogListItemViewHolder(
context,
null /* expandCollapseListener */,
- telecomCallLogCache,
- new CallLogListItemHelper(phoneCallDetailsHelper, resources, telecomCallLogCache),
+ callLogCache,
+ new CallLogListItemHelper(phoneCallDetailsHelper, resources, callLogCache),
null /* voicemailPlaybackPresenter */,
null /* filteredNumberAsyncQueryHandler */,
null /* filteredNumberDialogCallback */,
diff --git a/src/com/android/dialer/calllog/CallLogNotificationsService.java b/src/com/android/dialer/calllog/CallLogNotificationsService.java
index 9a67b61..d2a494d 100644
--- a/src/com/android/dialer/calllog/CallLogNotificationsService.java
+++ b/src/com/android/dialer/calllog/CallLogNotificationsService.java
@@ -67,12 +67,6 @@
}
@Override
- public void onCreate() {
- super.onCreate();
- mVoicemailQueryHandler = new VoicemailQueryHandler(this, getContentResolver());
- }
-
- @Override
protected void onHandleIntent(Intent intent) {
if (intent == null) {
Log.d(TAG, "onHandleIntent: could not handle null intent");
@@ -84,6 +78,9 @@
}
if (ACTION_MARK_NEW_VOICEMAILS_AS_OLD.equals(intent.getAction())) {
+ if (mVoicemailQueryHandler == null) {
+ mVoicemailQueryHandler = new VoicemailQueryHandler(this, getContentResolver());
+ }
mVoicemailQueryHandler.markNewVoicemailsAsOld();
} else if (ACTION_UPDATE_NOTIFICATIONS.equals(intent.getAction())) {
Uri voicemailUri = (Uri) intent.getParcelableExtra(EXTRA_NEW_VOICEMAIL_URI);
diff --git a/src/com/android/dialer/calllog/CallLogQuery.java b/src/com/android/dialer/calllog/CallLogQuery.java
index 2b43c28..905a4b7 100644
--- a/src/com/android/dialer/calllog/CallLogQuery.java
+++ b/src/com/android/dialer/calllog/CallLogQuery.java
@@ -18,11 +18,19 @@
import android.provider.CallLog.Calls;
+import com.android.dialer.compat.DialerCompatUtils;
+import com.android.dialer.util.AppCompatConstants;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
/**
* The query for the call log table.
*/
public final class CallLogQuery {
- public static final String[] _PROJECTION = new String[] {
+
+ private static final String[] _PROJECTION_INTERNAL = new String[] {
Calls._ID, // 0
Calls.NUMBER, // 1
Calls.DATE, // 2
@@ -46,7 +54,6 @@
Calls.FEATURES, // 20
Calls.DATA_USAGE, // 21
Calls.TRANSCRIPTION, // 22
- Calls.CACHED_PHOTO_URI // 23
};
public static final int ID = 0;
@@ -72,5 +79,33 @@
public static final int FEATURES = 20;
public static final int DATA_USAGE = 21;
public static final int TRANSCRIPTION = 22;
- public static final int CACHED_PHOTO_URI = 23;
+
+ // Indices for columns that may not be available, depending on the Sdk Version
+ /**
+ * Only available in versions >= M
+ * Call {@link DialerCompatUtils#isCallsCachedPhotoUriCompatible()} prior to use
+ */
+ public static int CACHED_PHOTO_URI = -1;
+
+ /**
+ * Only available in versions > M
+ * Call {@link PhoneNumberDisplayUtil#canShowPostDial()} prior to use
+ */
+ public static int POST_DIAL_DIGITS = -1;
+
+ public static final String[] _PROJECTION;
+
+ static {
+ List<String> projectionList = Lists.newArrayList(_PROJECTION_INTERNAL);
+ if (DialerCompatUtils.isCallsCachedPhotoUriCompatible()) {
+ projectionList.add(Calls.CACHED_PHOTO_URI);
+ CACHED_PHOTO_URI = projectionList.size() - 1;
+ }
+ if (PhoneNumberDisplayUtil.canShowPostDial()) {
+ projectionList.add(AppCompatConstants.POST_DIAL_DIGITS);
+ POST_DIAL_DIGITS = projectionList.size() - 1;
+ }
+ _PROJECTION = projectionList.toArray(new String[projectionList.size()]);
+ }
+
}
diff --git a/src/com/android/dialer/calllog/CallLogQueryHandler.java b/src/com/android/dialer/calllog/CallLogQueryHandler.java
index 3efdce7..4cb835b 100644
--- a/src/com/android/dialer/calllog/CallLogQueryHandler.java
+++ b/src/com/android/dialer/calllog/CallLogQueryHandler.java
@@ -26,6 +26,7 @@
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;
@@ -34,9 +35,9 @@
import android.provider.VoicemailContract.Voicemails;
import android.util.Log;
+import com.android.contacts.common.compat.SdkVersionOverride;
import com.android.contacts.common.database.NoNullCursorAsyncQueryHandler;
import com.android.contacts.common.util.PermissionsUtil;
-import com.android.dialer.filterednumber.FilteredNumbersUtil;
import com.android.dialer.util.AppCompatConstants;
import com.android.dialer.util.TelecomUtil;
import com.android.dialer.voicemail.VoicemailStatusHelperImpl;
@@ -48,8 +49,6 @@
/** Handles asynchronous queries to the call log. */
public class CallLogQueryHandler extends NoNullCursorAsyncQueryHandler {
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
-
private static final String TAG = "CallLogQueryHandler";
private static final int NUM_LOGS_TO_DISPLAY = 1000;
@@ -160,25 +159,25 @@
/** Fetches the list of calls in the call log. */
private void fetchCalls(int token, int callType, boolean newOnly, long newerThan) {
- // We need to check for NULL explicitly otherwise entries with where READ is NULL
- // may not match either the query or its negation.
- // We consider the calls that are not yet consumed (i.e. IS_READ = 0) as "new".
StringBuilder where = new StringBuilder();
List<String> selectionArgs = Lists.newArrayList();
+ // Always hide blocked calls.
+ where.append("(").append(Calls.TYPE).append(" != ?)");
+ selectionArgs.add(Integer.toString(AppCompatConstants.CALLS_BLOCKED_TYPE));
+
// Ignore voicemails marked as deleted
- where.append(Voicemails.DELETED);
- where.append(" = 0");
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
+ >= Build.VERSION_CODES.M) {
+ where.append(" AND (").append(Voicemails.DELETED).append(" = 0)");
+ }
if (newOnly) {
- where.append(" AND ");
- where.append(Calls.NEW);
- where.append(" = 1");
+ where.append(" AND (").append(Calls.NEW).append(" = 1)");
}
if (callType > CALL_TYPE_ALL) {
- where.append(" AND ");
- where.append("(" + Calls.TYPE + " = ?)");
+ where.append(" AND (").append(Calls.TYPE).append(" = ?)");
selectionArgs.add(Integer.toString(callType));
} else {
where.append(" AND NOT ");
@@ -186,24 +185,17 @@
}
if (newerThan > 0) {
- where.append(" AND ");
- where.append("(" + Calls.DATE + " > ?)");
+ where.append(" AND (").append(Calls.DATE).append(" > ?)");
selectionArgs.add(Long.toString(newerThan));
}
- // Always hide blocked calls.
- where.append(" AND ");
- where.append("(" + Calls.TYPE + " != ?)");
- selectionArgs.add(Integer.toString(AppCompatConstants.CALLS_BLOCKED_TYPE));
-
final int limit = (mLogLimit == -1) ? NUM_LOGS_TO_DISPLAY : mLogLimit;
final String selection = where.length() > 0 ? where.toString() : null;
Uri uri = TelecomUtil.getCallLogUri(mContext).buildUpon()
.appendQueryParameter(Calls.LIMIT_PARAM_KEY, Integer.toString(limit))
.build();
- startQuery(token, null, uri,
- CallLogQuery._PROJECTION, selection, selectionArgs.toArray(EMPTY_STRING_ARRAY),
- Calls.DEFAULT_SORT_ORDER);
+ startQuery(token, null, uri, CallLogQuery._PROJECTION, selection, selectionArgs.toArray(
+ new String[selectionArgs.size()]), Calls.DEFAULT_SORT_ORDER);
}
/** Cancel any pending fetch request. */
diff --git a/src/com/android/dialer/calllog/ContactInfoHelper.java b/src/com/android/dialer/calllog/ContactInfoHelper.java
index 2da6840..2ecb1e8 100644
--- a/src/com/android/dialer/calllog/ContactInfoHelper.java
+++ b/src/com/android/dialer/calllog/ContactInfoHelper.java
@@ -19,6 +19,7 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteFullException;
import android.net.Uri;
+import android.os.Build;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -29,10 +30,12 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.util.Constants;
import com.android.contacts.common.util.PermissionsUtil;
import com.android.contacts.common.util.PhoneNumberHelper;
import com.android.contacts.common.util.UriUtils;
+import com.android.dialer.compat.DialerCompatUtils;
import com.android.dialer.service.CachedNumberLookupService;
import com.android.dialer.service.CachedNumberLookupService.CachedContactInfo;
import com.android.dialer.util.TelecomUtil;
@@ -157,9 +160,14 @@
return ContactInfo.EMPTY;
}
- Cursor phoneLookupCursor = mContext.getContentResolver().query(uri,
- PhoneQuery.PHONE_LOOKUP_PROJECTION, null, null, null);
-
+ Cursor phoneLookupCursor = null;
+ try {
+ phoneLookupCursor = mContext.getContentResolver().query(uri,
+ PhoneQuery.PHONE_LOOKUP_PROJECTION, null, null, null);
+ } catch (NullPointerException e) {
+ // Trap NPE from pre-N CP2
+ return null;
+ }
if (phoneLookupCursor == null) {
return null;
}
@@ -330,7 +338,8 @@
final Uri updatedPhotoUriContactsOnly =
UriUtils.nullForNonContactsUri(updatedInfo.photoUri);
- if (!UriUtils.areEqual(updatedPhotoUriContactsOnly, callLogInfo.photoUri)) {
+ if (DialerCompatUtils.isCallsCachedPhotoUriCompatible() &&
+ !UriUtils.areEqual(updatedPhotoUriContactsOnly, callLogInfo.photoUri)) {
values.put(Calls.CACHED_PHOTO_URI,
UriUtils.uriToString(updatedPhotoUriContactsOnly));
needsUpdate = true;
@@ -349,8 +358,10 @@
values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number);
values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber);
values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId);
- values.put(Calls.CACHED_PHOTO_URI, UriUtils.uriToString(
- UriUtils.nullForNonContactsUri(updatedInfo.photoUri)));
+ if (DialerCompatUtils.isCallsCachedPhotoUriCompatible()) {
+ values.put(Calls.CACHED_PHOTO_URI, UriUtils.uriToString(
+ UriUtils.nullForNonContactsUri(updatedInfo.photoUri)));
+ }
values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber);
needsUpdate = true;
}
@@ -379,13 +390,31 @@
}
public static Uri getContactInfoLookupUri(String number) {
+ return getContactInfoLookupUri(number, -1);
+ }
+
+ public static Uri getContactInfoLookupUri(String number, long directoryId) {
// Get URI for the number in the PhoneLookup table, with a parameter to indicate whether
// the number is a SIP number.
- return PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
- .appendPath(Uri.encode(number))
+ Uri uri = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI;
+ if (!ContactsUtils.FLAG_N_FEATURE) {
+ if (directoryId != -1) {
+ // ENTERPRISE_CONTENT_FILTER_URI in M doesn't support directory lookup
+ uri = PhoneLookup.CONTENT_FILTER_URI;
+ } else {
+ // b/25900607 in M. PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, encodes twice.
+ number = Uri.encode(number);
+ }
+ }
+ Uri.Builder builder = uri.buildUpon()
+ .appendPath(number)
.appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS,
- String.valueOf(PhoneNumberHelper.isUriNumber(number)))
- .build();
+ String.valueOf(PhoneNumberHelper.isUriNumber(number)));
+ if (directoryId != -1) {
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ }
+ return builder.build();
}
/**
@@ -400,11 +429,17 @@
info.type = c.getInt(CallLogQuery.CACHED_NUMBER_TYPE);
info.label = c.getString(CallLogQuery.CACHED_NUMBER_LABEL);
String matchedNumber = c.getString(CallLogQuery.CACHED_MATCHED_NUMBER);
- info.number = matchedNumber == null ? c.getString(CallLogQuery.NUMBER) : matchedNumber;
+ String postDialDigits = PhoneNumberDisplayUtil.canShowPostDial()
+ ? c.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
+ info.number = (matchedNumber == null) ?
+ c.getString(CallLogQuery.NUMBER) + postDialDigits : matchedNumber;
+
info.normalizedNumber = c.getString(CallLogQuery.CACHED_NORMALIZED_NUMBER);
info.photoId = c.getLong(CallLogQuery.CACHED_PHOTO_ID);
- info.photoUri = UriUtils.nullForNonContactsUri(
- UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_PHOTO_URI)));
+ info.photoUri = DialerCompatUtils.isCallsCachedPhotoUriCompatible() ?
+ UriUtils.nullForNonContactsUri(
+ UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_PHOTO_URI)))
+ : null;
info.formattedNumber = c.getString(CallLogQuery.CACHED_FORMATTED_NUMBER);
return info;
diff --git a/src/com/android/dialer/calllog/PhoneAccountUtils.java b/src/com/android/dialer/calllog/PhoneAccountUtils.java
index ceadabc..7dc3292 100644
--- a/src/com/android/dialer/calllog/PhoneAccountUtils.java
+++ b/src/com/android/dialer/calllog/PhoneAccountUtils.java
@@ -23,7 +23,6 @@
import android.telecom.TelecomManager;
import android.text.TextUtils;
-import com.android.contacts.common.util.PermissionsUtil;
import com.android.dialer.util.TelecomUtil;
import java.util.ArrayList;
diff --git a/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java b/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java
index 96dbf82..e6b8508 100644
--- a/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java
+++ b/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java
@@ -24,6 +24,7 @@
import android.graphics.Typeface;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.support.v4.content.ContextCompat;
import android.telecom.PhoneAccount;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -34,6 +35,7 @@
import com.android.contacts.common.util.PhoneNumberHelper;
import com.android.dialer.PhoneCallDetails;
import com.android.dialer.R;
+import com.android.dialer.calllog.calllogcache.CallLogCache;
import com.android.dialer.util.DialerUtils;
import java.util.ArrayList;
@@ -54,7 +56,7 @@
private CharSequence mPhoneTypeLabelForTest;
- private final TelecomCallLogCache mTelecomCallLogCache;
+ private final CallLogCache mCallLogCache;
/** Calendar used to construct dates */
private final Calendar mCalendar;
@@ -74,10 +76,10 @@
public PhoneCallDetailsHelper(
Context context,
Resources resources,
- TelecomCallLogCache telecomCallLogCache) {
+ CallLogCache callLogCache) {
mContext = context;
mResources = resources;
- mTelecomCallLogCache = telecomCallLogCache;
+ mCallLogCache = callLogCache;
mCalendar = Calendar.getInstance();
}
@@ -114,12 +116,12 @@
setCallCountAndDate(views, callCount, callLocationAndDate);
// Set the account label if it exists.
- String accountLabel = mTelecomCallLogCache.getAccountLabel(details.accountHandle);
+ String accountLabel = mCallLogCache.getAccountLabel(details.accountHandle);
if (accountLabel != null) {
views.callAccountLabel.setVisibility(View.VISIBLE);
views.callAccountLabel.setText(accountLabel);
- int color = mTelecomCallLogCache.getAccountColor(details.accountHandle);
+ int color = mCallLogCache.getAccountColor(details.accountHandle);
if (color == PhoneAccount.NO_HIGHLIGHT_COLOR) {
int defaultColor = R.color.dialtacts_secondary_text_color;
views.callAccountLabel.setTextColor(mContext.getResources().getColor(defaultColor));
@@ -152,9 +154,8 @@
views.nameView.setTypeface(typeface);
views.voicemailTranscriptionView.setTypeface(typeface);
views.callLocationAndDate.setTypeface(typeface);
- views.callLocationAndDate.setTextColor(mResources.getColor(
- details.isRead ? R.color.call_log_detail_color : R.color.call_log_unread_text_color,
- mContext.getTheme()));
+ views.callLocationAndDate.setTextColor(ContextCompat.getColor(mContext, details.isRead ?
+ R.color.call_log_detail_color : R.color.call_log_unread_text_color));
}
/**
@@ -198,7 +199,7 @@
// Only show a label if the number is shown and it is not a SIP address.
if (!TextUtils.isEmpty(details.number)
&& !PhoneNumberHelper.isUriNumber(details.number.toString())
- && !mTelecomCallLogCache.isVoicemailNumber(details.accountHandle, details.number)) {
+ && !mCallLogCache.isVoicemailNumber(details.accountHandle, details.number)) {
if (TextUtils.isEmpty(details.namePrimary) && !TextUtils.isEmpty(details.geocode)) {
numberFormattedLabel = details.geocode;
diff --git a/src/com/android/dialer/calllog/PhoneNumberDisplayUtil.java b/src/com/android/dialer/calllog/PhoneNumberDisplayUtil.java
index 5030efd..91cd3e1 100644
--- a/src/com/android/dialer/calllog/PhoneNumberDisplayUtil.java
+++ b/src/com/android/dialer/calllog/PhoneNumberDisplayUtil.java
@@ -17,10 +17,9 @@
package com.android.dialer.calllog;
import android.content.Context;
-import android.content.res.Resources;
+import android.os.Build;
import android.provider.CallLog.Calls;
import android.text.TextUtils;
-import android.util.Log;
import com.android.dialer.R;
import com.android.dialer.util.PhoneNumberUtil;
@@ -67,6 +66,7 @@
CharSequence number,
int presentation,
CharSequence formattedNumber,
+ CharSequence postDialDigits,
boolean isVoicemail) {
final CharSequence displayName = getDisplayName(context, number, presentation, isVoicemail);
if (!TextUtils.isEmpty(displayName)) {
@@ -76,9 +76,18 @@
if (!TextUtils.isEmpty(formattedNumber)) {
return formattedNumber;
} else if (!TextUtils.isEmpty(number)) {
- return number;
+ return number.toString() + postDialDigits;
} else {
return "";
}
}
+
+ /**
+ * Returns whether we can expect the post-dial digits to be in the call log.
+ *
+ * These digits will be present in versions N+.
+ */
+ public static boolean canShowPostDial() {
+ return Build.VERSION.SDK_INT > Build.VERSION_CODES.M;
+ }
}
diff --git a/src/com/android/dialer/calllog/calllogcache/CallLogCache.java b/src/com/android/dialer/calllog/calllogcache/CallLogCache.java
new file mode 100644
index 0000000..e64c012
--- /dev/null
+++ b/src/com/android/dialer/calllog/calllogcache/CallLogCache.java
@@ -0,0 +1,96 @@
+/*
+ * 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.calllog.calllogcache;
+
+import android.content.Context;
+import android.telecom.PhoneAccountHandle;
+
+import com.android.contacts.common.CallUtil;
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.dialer.calllog.CallLogAdapter;
+
+/**
+ * This is the base class for the CallLogCaches.
+ *
+ * Keeps a cache of recently made queries to the Telecom/Telephony processes. The aim of this cache
+ * is to reduce the number of cross-process requests to TelecomManager, which can negatively affect
+ * performance.
+ *
+ * This is designed with the specific use case of the {@link CallLogAdapter} in mind.
+ */
+public abstract class CallLogCache {
+ // TODO: Dialer should be fixed so as not to check isVoicemail() so often but at the time of
+ // this writing, that was a much larger undertaking than creating this cache.
+
+ protected final Context mContext;
+
+ private boolean mHasCheckedForVideoEnabled;
+ private boolean mIsVideoEnabled;
+
+ public CallLogCache(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Return the most compatible version of the TelecomCallLogCache.
+ */
+ public static CallLogCache getCallLogCache(Context context) {
+ if (CompatUtils.isMSIMCompatible()) {
+ return new CallLogCacheLollipopMr1(context);
+ }
+ return new CallLogCacheLollipop(context);
+ }
+
+ public void reset() {
+ mHasCheckedForVideoEnabled = false;
+ mIsVideoEnabled = false;
+ }
+
+ /**
+ * Returns true if the given number is the number of the configured voicemail. To be able to
+ * mock-out this, it is not a static method.
+ */
+ public abstract boolean isVoicemailNumber(PhoneAccountHandle accountHandle,
+ CharSequence number);
+
+ public boolean isVideoEnabled() {
+ if (!mHasCheckedForVideoEnabled) {
+ mIsVideoEnabled = CallUtil.isVideoEnabled(mContext);
+ mHasCheckedForVideoEnabled = true;
+ }
+ return mIsVideoEnabled;
+ }
+
+ /**
+ * Extract account label from PhoneAccount object.
+ */
+ public abstract String getAccountLabel(PhoneAccountHandle accountHandle);
+
+ /**
+ * Extract account color from PhoneAccount object.
+ */
+ public abstract int getAccountColor(PhoneAccountHandle accountHandle);
+
+ /**
+ * Determines if the PhoneAccount supports specifying a call subject (i.e. calling with a note)
+ * for outgoing calls.
+ *
+ * @param accountHandle The PhoneAccount handle.
+ * @return {@code true} if calling with a note is supported, {@code false} otherwise.
+ */
+ public abstract boolean doesAccountSupportCallSubject(PhoneAccountHandle accountHandle);
+}
diff --git a/src/com/android/dialer/calllog/calllogcache/CallLogCacheLollipop.java b/src/com/android/dialer/calllog/calllogcache/CallLogCacheLollipop.java
new file mode 100644
index 0000000..770cc9d
--- /dev/null
+++ b/src/com/android/dialer/calllog/calllogcache/CallLogCacheLollipop.java
@@ -0,0 +1,73 @@
+/*
+ * 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.calllog.calllogcache;
+
+import android.content.Context;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+
+/**
+ * This is a compatibility class for the CallLogCache for versions of dialer before Lollipop Mr1
+ * (the introduction of phone accounts).
+ *
+ * This class should not be initialized directly and instead be acquired from
+ * {@link CallLogCache#getCallLogCache}.
+ */
+class CallLogCacheLollipop extends CallLogCache {
+ private String mVoicemailNumber;
+
+ /* package */ CallLogCacheLollipop(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean isVoicemailNumber(PhoneAccountHandle accountHandle, CharSequence number) {
+ if (TextUtils.isEmpty(number)) {
+ return false;
+ }
+
+ String numberString = number.toString();
+
+ if (!TextUtils.isEmpty(mVoicemailNumber)) {
+ return PhoneNumberUtils.compare(numberString, mVoicemailNumber);
+ }
+
+ if (PhoneNumberUtils.isVoiceMailNumber(numberString)) {
+ mVoicemailNumber = numberString;
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String getAccountLabel(PhoneAccountHandle accountHandle) {
+ return null;
+ }
+
+ @Override
+ public int getAccountColor(PhoneAccountHandle accountHandle) {
+ return PhoneAccount.NO_HIGHLIGHT_COLOR;
+ }
+
+ @Override
+ public boolean doesAccountSupportCallSubject(PhoneAccountHandle accountHandle) {
+ return false;
+ }
+}
diff --git a/src/com/android/dialer/calllog/TelecomCallLogCache.java b/src/com/android/dialer/calllog/calllogcache/CallLogCacheLollipopMr1.java
similarity index 64%
rename from src/com/android/dialer/calllog/TelecomCallLogCache.java
rename to src/com/android/dialer/calllog/calllogcache/CallLogCacheLollipopMr1.java
index 6363b91..d1e3f7b 100644
--- a/src/com/android/dialer/calllog/TelecomCallLogCache.java
+++ b/src/com/android/dialer/calllog/calllogcache/CallLogCacheLollipopMr1.java
@@ -14,67 +14,50 @@
* limitations under the License
*/
-package com.android.dialer.calllog;
+package com.android.dialer.calllog.calllogcache;
import android.content.Context;
-import android.provider.CallLog;
-import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
import android.text.TextUtils;
-import android.util.Log;
import android.util.Pair;
-import com.android.contacts.common.CallUtil;
-import com.android.contacts.common.util.PhoneNumberHelper;
+import com.android.dialer.calllog.PhoneAccountUtils;
import com.android.dialer.util.PhoneNumberUtil;
-import com.google.common.collect.Sets;
import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
/**
- * Keeps a cache of recently made queries to the Telecom process. The aim of this cache is to
- * reduce the number of cross-process requests to TelecomManager, which can negatively affect
- * performance.
+ * This is the CallLogCache for versions of dialer Lollipop Mr1 and above with support for
+ * multi-SIM devices.
*
- * This is designed with the specific use case of the {@link CallLogAdapter} in mind.
+ * This class should not be initialized directly and instead be acquired from
+ * {@link CallLogCache#getCallLogCache}.
*/
-public class TelecomCallLogCache {
- private final Context mContext;
-
+class CallLogCacheLollipopMr1 extends CallLogCache {
// Maps from a phone-account/number pair to a boolean because multiple numbers could return true
// for the voicemail number if those numbers are not pre-normalized.
- // TODO: Dialer should be fixed so as not to check isVoicemail() so often but at the time of
- // this writing, that was a much larger undertaking than creating this cache.
private final Map<Pair<PhoneAccountHandle, CharSequence>, Boolean> mVoicemailQueryCache =
new HashMap<>();
private final Map<PhoneAccountHandle, String> mPhoneAccountLabelCache = new HashMap<>();
private final Map<PhoneAccountHandle, Integer> mPhoneAccountColorCache = new HashMap<>();
private final Map<PhoneAccountHandle, Boolean> mPhoneAccountCallWithNoteCache = new HashMap<>();
- private boolean mHasCheckedForVideoEnabled;
- private boolean mIsVideoEnabled;
-
- public TelecomCallLogCache(Context context) {
- mContext = context;
+ /* package */ CallLogCacheLollipopMr1(Context context) {
+ super(context);
}
+ @Override
public void reset() {
mVoicemailQueryCache.clear();
mPhoneAccountLabelCache.clear();
mPhoneAccountColorCache.clear();
mPhoneAccountCallWithNoteCache.clear();
- mHasCheckedForVideoEnabled = false;
- mIsVideoEnabled = false;
+ super.reset();
}
- /**
- * Returns true if the given number is the number of the configured voicemail. To be able to
- * mock-out this, it is not a static method.
- */
+ @Override
public boolean isVoicemailNumber(PhoneAccountHandle accountHandle, CharSequence number) {
if (TextUtils.isEmpty(number)) {
return false;
@@ -91,9 +74,7 @@
}
}
- /**
- * Extract account label from PhoneAccount object.
- */
+ @Override
public String getAccountLabel(PhoneAccountHandle accountHandle) {
if (mPhoneAccountLabelCache.containsKey(accountHandle)) {
return mPhoneAccountLabelCache.get(accountHandle);
@@ -104,9 +85,7 @@
}
}
- /**
- * Extract account color from PhoneAccount object.
- */
+ @Override
public int getAccountColor(PhoneAccountHandle accountHandle) {
if (mPhoneAccountColorCache.containsKey(accountHandle)) {
return mPhoneAccountColorCache.get(accountHandle);
@@ -117,21 +96,7 @@
}
}
- public boolean isVideoEnabled() {
- if (!mHasCheckedForVideoEnabled) {
- mIsVideoEnabled = CallUtil.isVideoEnabled(mContext);
- mHasCheckedForVideoEnabled = true;
- }
- return mIsVideoEnabled;
- }
-
- /**
- * Determines if the PhoneAccount supports specifying a call subject (i.e. calling with a note)
- * for outgoing calls.
- *
- * @param accountHandle The PhoneAccount handle.
- * @return {@code true} if calling with a note is supported, {@code false} otherwise.
- */
+ @Override
public boolean doesAccountSupportCallSubject(PhoneAccountHandle accountHandle) {
if (mPhoneAccountCallWithNoteCache.containsKey(accountHandle)) {
return mPhoneAccountCallWithNoteCache.get(accountHandle);
diff --git a/src/com/android/dialer/compat/CallAudioStateCompat.java b/src/com/android/dialer/compat/CallAudioStateCompat.java
new file mode 100644
index 0000000..51009d0
--- /dev/null
+++ b/src/com/android/dialer/compat/CallAudioStateCompat.java
@@ -0,0 +1,331 @@
+/*
+ * 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;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telecom.CallAudioState;
+
+import com.android.contacts.common.compat.SdkVersionOverride;
+
+import java.util.Locale;
+
+/**
+ * Compatibility class for {@link CallAudioState}
+ */
+public class CallAudioStateCompat {
+
+ /**
+ * Direct the audio stream through the device's earpiece.
+ */
+ public static final int ROUTE_EARPIECE = CallAudioState.ROUTE_EARPIECE;
+
+ /**
+ * Direct the audio stream through Bluetooth.
+ */
+ public static final int ROUTE_BLUETOOTH = CallAudioState.ROUTE_BLUETOOTH;
+
+ /**
+ * Direct the audio stream through a wired headset.
+ */
+ public static final int ROUTE_WIRED_HEADSET = CallAudioState.ROUTE_WIRED_HEADSET;
+
+ /**
+ * Direct the audio stream through the device's speakerphone.
+ */
+ public static final int ROUTE_SPEAKER = CallAudioState.ROUTE_SPEAKER;
+
+ /**
+ * Direct the audio stream through the device's earpiece or wired headset if one is connected.
+ */
+ public static final int ROUTE_WIRED_OR_EARPIECE = CallAudioState.ROUTE_WIRED_OR_EARPIECE;
+
+ private final CallAudioStateImpl mCallAudioState;
+
+ /**
+ * Constructor for a {@link CallAudioStateCompat} object.
+ *
+ * @param muted {@code true} if the call is muted, {@code false} otherwise.
+ * @param route The current audio route being used. Allowed values: {@link #ROUTE_EARPIECE}
+ * {@link #ROUTE_BLUETOOTH} {@link #ROUTE_WIRED_HEADSET} {@link #ROUTE_SPEAKER}
+ * @param supportedRouteMask Bit mask of all routes supported by this call. This should be a
+ * bitwise combination of the following values: {@link #ROUTE_EARPIECE} {@link #ROUTE_BLUETOOTH}
+ * {@link #ROUTE_WIRED_HEADSET} {@link #ROUTE_SPEAKER}
+ */
+ public CallAudioStateCompat(boolean muted, int route, int supportedRouteMask) {
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
+ < Build.VERSION_CODES.M) {
+ mCallAudioState = new CallAudioStateBase(muted, route, supportedRouteMask);
+ } else {
+ mCallAudioState = new CallAudioStateMarshmallow(muted, route, supportedRouteMask);
+ }
+ }
+
+ /**
+ * @return {@code true} if the call is muted, {@code false} otherwise.
+ */
+ public boolean isMuted() {
+ return mCallAudioState.isMuted();
+ }
+
+ /**
+ * @return The current audio route being used.
+ */
+ public int getRoute() {
+ return mCallAudioState.getRoute();
+ }
+
+ /**
+ * @return Bit mask of all routes supported by this call.
+ */
+ public int getSupportedRouteMask() {
+ return mCallAudioState.getSupportedRouteMask();
+ }
+
+ /**
+ * Converts the provided audio route into a human readable string representation.
+ *
+ * @param route to convert into a string.
+ * @return String representation of the provided audio route.
+ */
+ public static String audioRouteToString(int route) {
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
+ < Build.VERSION_CODES.M) {
+ return CallAudioStateBase.audioRouteToString(route);
+ }
+ return CallAudioStateMarshmallow.audioRouteToString(route);
+ }
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ CallAudioStateCompat that = (CallAudioStateCompat) o;
+
+ return mCallAudioState.equals(that.mCallAudioState);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return mCallAudioState.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return mCallAudioState.toString();
+ }
+
+ private interface CallAudioStateImpl {
+ boolean isMuted();
+ int getRoute();
+ int getSupportedRouteMask();
+ }
+
+ /**
+ * CallAudioStateImpl to use if the Sdk version is lower than
+ * {@link android.os.Build.VERSION_CODES.M}
+ *
+ * Coped from {@link android.telecom.CallAudioState}
+ *
+ * Encapsulates the telecom audio state, including the current audio routing, supported audio
+ * routing and mute.
+ */
+ private static class CallAudioStateBase implements CallAudioStateImpl, Parcelable {
+
+ /**
+ * Bit mask of all possible audio routes.
+ */
+ private static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET
+ | ROUTE_SPEAKER;
+
+ private final boolean isMuted;
+ private final int route;
+ private final int supportedRouteMask;
+
+ /**
+ * Constructor for a {@link CallAudioStateBase} object.
+ *
+ * @param muted {@code true} if the call is muted, {@code false} otherwise.
+ * @param route The current audio route being used. Allowed values: {@link #ROUTE_EARPIECE}
+ * {@link #ROUTE_BLUETOOTH}, {@link #ROUTE_WIRED_HEADSET}, {@link #ROUTE_SPEAKER}
+ * @param supportedRouteMask Bit mask of all routes supported by this call. This should be a
+ * bitwise combination of the following values: {@link #ROUTE_EARPIECE},
+ * {@link #ROUTE_BLUETOOTH}, {@link #ROUTE_WIRED_HEADSET}, {@link #ROUTE_SPEAKER}
+ */
+ public CallAudioStateBase(boolean muted, int route, int supportedRouteMask) {
+ this.isMuted = muted;
+ this.route = route;
+ this.supportedRouteMask = supportedRouteMask;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof CallAudioStateBase)) {
+ return false;
+ }
+ CallAudioStateBase state = (CallAudioStateBase) obj;
+ return isMuted() == state.isMuted() && getRoute() == state.getRoute() &&
+ getSupportedRouteMask() == state.getSupportedRouteMask();
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.US,
+ "[AudioState isMuted: %b, route: %s, supportedRouteMask: %s]",
+ isMuted,
+ audioRouteToString(route),
+ audioRouteToString(supportedRouteMask));
+ }
+
+ /**
+ * @return {@code true} if the call is muted, {@code false} otherwise.
+ */
+ @Override
+ public boolean isMuted() {
+ return isMuted;
+ }
+
+ /**
+ * @return The current audio route being used.
+ */
+ public int getRoute() {
+ return route;
+ }
+
+ /**
+ * @return Bit mask of all routes supported by this call.
+ */
+ public int getSupportedRouteMask() {
+ return supportedRouteMask;
+ }
+
+ /**
+ * Converts the provided audio route into a human readable string representation.
+ *
+ * @param route to convert into a string.
+ * @return String representation of the provided audio route.
+ */
+ public static String audioRouteToString(int route) {
+ if (route == 0 || (route & ~ROUTE_ALL) != 0x0) {
+ return "UNKNOWN";
+ }
+
+ StringBuffer buffer = new StringBuffer();
+ if ((route & ROUTE_EARPIECE) == ROUTE_EARPIECE) {
+ listAppend(buffer, "EARPIECE");
+ }
+ if ((route & ROUTE_BLUETOOTH) == ROUTE_BLUETOOTH) {
+ listAppend(buffer, "BLUETOOTH");
+ }
+ if ((route & ROUTE_WIRED_HEADSET) == ROUTE_WIRED_HEADSET) {
+ listAppend(buffer, "WIRED_HEADSET");
+ }
+ if ((route & ROUTE_SPEAKER) == ROUTE_SPEAKER) {
+ listAppend(buffer, "SPEAKER");
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * Responsible for creating AudioState objects for deserialized Parcels.
+ */
+ public static final Parcelable.Creator<CallAudioStateBase> CREATOR =
+ new Parcelable.Creator<CallAudioStateBase>() {
+
+ @Override
+ public CallAudioStateBase createFromParcel(Parcel source) {
+ boolean isMuted = source.readByte() == 0 ? false : true;
+ int route = source.readInt();
+ int supportedRouteMask = source.readInt();
+ return new CallAudioStateBase(isMuted, route, supportedRouteMask);
+ }
+
+ @Override
+ public CallAudioStateBase[] newArray(int size) {
+ return new CallAudioStateBase[size];
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Writes AudioState object into a serializeable Parcel.
+ */
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeByte((byte) (isMuted ? 1 : 0));
+ destination.writeInt(route);
+ destination.writeInt(supportedRouteMask);
+ }
+
+ private static void listAppend(StringBuffer buffer, String str) {
+ if (buffer.length() > 0) {
+ buffer.append(", ");
+ }
+ buffer.append(str);
+ }
+ }
+
+ /**
+ * CallAudioStateImpl to use if the Sdk version is at least
+ * {@link android.os.Build.VERSION_CODES.M}
+ */
+ private static class CallAudioStateMarshmallow implements CallAudioStateImpl {
+
+ private final CallAudioState mCallAudioStateDelegate;
+
+ public CallAudioStateMarshmallow(boolean muted, int route, int supportedRouteMask) {
+ mCallAudioStateDelegate = new CallAudioState(muted, route, supportedRouteMask);
+ }
+
+ @Override
+ public boolean isMuted() {
+ return mCallAudioStateDelegate.isMuted();
+ }
+
+ @Override
+ public int getRoute() {
+ return mCallAudioStateDelegate.getRoute();
+ }
+
+ @Override
+ public int getSupportedRouteMask() {
+ return mCallAudioStateDelegate.getSupportedRouteMask();
+ }
+
+ public static String audioRouteToString(int route) {
+ return CallAudioState.audioRouteToString(route);
+ }
+ }
+}
diff --git a/src/com/android/dialer/compat/DialerCompatUtils.java b/src/com/android/dialer/compat/DialerCompatUtils.java
new file mode 100644
index 0000000..07a279a
--- /dev/null
+++ b/src/com/android/dialer/compat/DialerCompatUtils.java
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+import com.android.contacts.common.compat.SdkVersionOverride;
+
+public final class DialerCompatUtils {
+ /**
+ * Determines if this version is compatible with video calling. Can also force the version to be
+ * lower through SdkVersionOverride.
+ *
+ * @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;
+ }
+
+ /**
+ * Determines if this version is compatible with a default dialer. Can also force the version to
+ * be lower through SdkVersionOverride.
+ *
+ * @return {@code true} if default dialer is a feature on this device, {@code false} otherwise.
+ */
+ public static boolean isDefaultDialerCompatible() {
+ return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
+ >= Build.VERSION_CODES.M;
+ }
+
+ /**
+ * Determines if this version has access to the
+ * {@link android.provider.CallLog.Calls.CACHED_PHOTO_URI} column
+ *
+ * @return {@code true} if {@link android.provider.CallLog.Calls.CACHED_PHOTO_URI} is available,
+ * {@code false} otherwise
+ */
+ public static boolean isCallsCachedPhotoUriCompatible() {
+ return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
+ >= Build.VERSION_CODES.M;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/dialer/compat/SettingsCompat.java b/src/com/android/dialer/compat/SettingsCompat.java
new file mode 100644
index 0000000..474a600
--- /dev/null
+++ b/src/com/android/dialer/compat/SettingsCompat.java
@@ -0,0 +1,47 @@
+/*
+ * 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.content.Context;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.provider.Settings;
+
+import com.android.contacts.common.compat.SdkVersionOverride;
+
+/**
+ * Compatibility class for {@link android.provider.Settings}
+ */
+public class SettingsCompat {
+
+ public static class System {
+
+ /**
+ * Compatibility version of {@link android.provider.Settings.System#canWrite(Context)}
+ *
+ * Note: Since checking preferences at runtime started in M, this method always returns
+ * {@code true} for SDK versions prior to 23. In those versions, the app wouldn't be
+ * installed if it didn't have the proper permission
+ */
+ public static boolean canWrite(Context context) {
+ if (SdkVersionOverride.getSdkVersion(VERSION_CODES.LOLLIPOP) >= Build.VERSION_CODES.M) {
+ return Settings.System.canWrite(context);
+ }
+ return true;
+ }
+ }
+
+}
diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java
index 760b020..246b0d7 100644
--- a/src/com/android/dialer/dialpad/DialpadFragment.java
+++ b/src/com/android/dialer/dialpad/DialpadFragment.java
@@ -274,6 +274,11 @@
}
@Override
+ public Context getContext() {
+ return getActivity();
+ }
+
+ @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
mWasEmptyBeforeTextChange = TextUtils.isEmpty(s);
}
diff --git a/src/com/android/dialer/dialpad/SmartDialNameMatcher.java b/src/com/android/dialer/dialpad/SmartDialNameMatcher.java
index 0126864..a54fe16 100644
--- a/src/com/android/dialer/dialpad/SmartDialNameMatcher.java
+++ b/src/com/android/dialer/dialpad/SmartDialNameMatcher.java
@@ -16,6 +16,7 @@
package com.android.dialer.dialpad;
+import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.android.dialer.dialpad.SmartDialPrefix.PhoneNumberTokens;
@@ -123,7 +124,11 @@
* SmartDialMatchPosition with the matching positions otherwise
*/
@VisibleForTesting
+ @Nullable
public SmartDialMatchPosition matchesNumber(String phoneNumber, String query, boolean useNanp) {
+ if (TextUtils.isEmpty(phoneNumber)) {
+ return null;
+ }
StringBuilder builder = new StringBuilder();
constructEmptyMask(builder, phoneNumber.length());
mPhoneNumberMatchMask = builder.toString();
diff --git a/src/com/android/dialer/filterednumber/BlockNumberDialogFragment.java b/src/com/android/dialer/filterednumber/BlockNumberDialogFragment.java
index 0f4bd74..de4fe99 100644
--- a/src/com/android/dialer/filterednumber/BlockNumberDialogFragment.java
+++ b/src/com/android/dialer/filterednumber/BlockNumberDialogFragment.java
@@ -123,6 +123,11 @@
}
@Override
+ public Context getContext() {
+ return getActivity();
+ }
+
+ @Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
super.onCreateDialog(savedInstanceState);
final boolean isBlocked = getArguments().containsKey(ARG_BLOCK_ID);
diff --git a/src/com/android/dialer/filterednumber/BlockedNumbersAdapter.java b/src/com/android/dialer/filterednumber/BlockedNumbersAdapter.java
index e33b0f8..10a4f5a 100644
--- a/src/com/android/dialer/filterednumber/BlockedNumbersAdapter.java
+++ b/src/com/android/dialer/filterednumber/BlockedNumbersAdapter.java
@@ -67,7 +67,7 @@
number,
countryIso,
PhoneNumberUtils.formatNumber(number, countryIso),
- R.id.blocked_number_fragment,
+ R.id.blocked_numbers_activity_container,
getFragmentManager(),
new BlockNumberDialogFragment.Callback() {
@Override
diff --git a/src/com/android/dialer/filterednumber/BlockedNumbersFragment.java b/src/com/android/dialer/filterednumber/BlockedNumbersFragment.java
index 881ec04..e231c6a 100644
--- a/src/com/android/dialer/filterednumber/BlockedNumbersFragment.java
+++ b/src/com/android/dialer/filterednumber/BlockedNumbersFragment.java
@@ -23,6 +23,7 @@
import android.database.Cursor;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
@@ -51,6 +52,11 @@
private View mBlockedNumberListDivider;
@Override
+ public Context getContext() {
+ return getActivity();
+ }
+
+ @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -62,8 +68,8 @@
ImageView addNumberIcon = (ImageView) getActivity().findViewById(R.id.add_number_icon);
LetterTileDrawable drawable = new LetterTileDrawable(getResources());
drawable.setLetter(ADD_BLOCKED_NUMBER_ICON_LETTER);
- drawable.setColor(getResources().getColor(R.color.add_blocked_number_icon_color,
- getActivity().getTheme()));
+ drawable.setColor(ActivityCompat.getColor(getActivity(),
+ R.color.add_blocked_number_icon_color));
drawable.setIsCircular(true);
addNumberIcon.setImageDrawable(drawable);
@@ -103,8 +109,8 @@
super.onResume();
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
- ColorDrawable backgroundDrawable =
- new ColorDrawable(getActivity().getColor(R.color.dialer_theme_color));
+ ColorDrawable backgroundDrawable = new ColorDrawable(
+ ActivityCompat.getColor(getActivity(), R.color.dialer_theme_color));
actionBar.setBackgroundDrawable(backgroundDrawable);
actionBar.setDisplayShowCustomEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(true);
diff --git a/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java b/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java
index 23ce8a8..e3870de 100644
--- a/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java
+++ b/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java
@@ -31,10 +31,6 @@
import android.text.TextUtils;
import android.widget.Toast;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
import com.android.contacts.common.testing.NeededForTesting;
import com.android.dialer.R;
import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
@@ -44,6 +40,8 @@
import com.android.dialer.logging.InteractionEvent;
import com.android.dialer.logging.Logger;
+import java.util.concurrent.TimeUnit;
+
/**
* Utility to help with tasks related to filtered numbers.
*/
@@ -53,11 +51,11 @@
private static final long RECENT_EMERGENCY_CALL_THRESHOLD_MS = 1000 * 60 * 60 * 24 * 2;
// Pref key for storing the time of end of the last emergency call in milliseconds after epoch.
- private static final String LAST_EMERGENCY_CALL_MS_PREF_KEY = "last_emergency_call_ms";
+ protected static final String LAST_EMERGENCY_CALL_MS_PREF_KEY = "last_emergency_call_ms";
// Pref key for storing whether a notification has been dispatched to notify the user that call
// blocking has been disabled because of a recent emergency call.
- private static final String NOTIFIED_CALL_BLOCKING_DISABLED_BY_EMERGENCY_CALL_PREF_KEY =
+ protected static final String NOTIFIED_CALL_BLOCKING_DISABLED_BY_EMERGENCY_CALL_PREF_KEY =
"notified_call_blocking_disabled_by_emergency_call";
public static final String CALL_BLOCKING_NOTIFICATION_TAG = "call_blocking";
@@ -241,6 +239,10 @@
return false;
}
+ if (hasRecentEmergencyCall(context)) {
+ return false;
+ }
+
final Cursor cursor = context.getContentResolver().query(
FilteredNumber.CONTENT_URI,
new String[] {
diff --git a/src/com/android/dialer/filterednumber/NumbersAdapter.java b/src/com/android/dialer/filterednumber/NumbersAdapter.java
index 1706107..4e2e578 100644
--- a/src/com/android/dialer/filterednumber/NumbersAdapter.java
+++ b/src/com/android/dialer/filterednumber/NumbersAdapter.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
@@ -30,6 +31,7 @@
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+import com.android.contacts.common.compat.CompatUtils;
import com.android.contacts.common.util.UriUtils;
import com.android.dialer.R;
import com.android.dialer.calllog.ContactInfo;
@@ -63,9 +65,9 @@
final QuickContactBadge quickContactBadge =
(QuickContactBadge) view.findViewById(R.id.quick_contact_photo);
quickContactBadge.setOverlay(null);
- quickContactBadge.setPrioritizedMimeType(
- ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
-
+ if (CompatUtils.hasPrioritizedMimeType()) {
+ quickContactBadge.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
+ }
final ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso);
final CharSequence locationOrType = getNumberTypeOrLocation(info);
final String displayNumber = getDisplayNumber(info);
diff --git a/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java b/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java
index 9912416..153d73c 100644
--- a/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java
+++ b/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java
@@ -44,6 +44,11 @@
private ViewNumbersToImportAdapter mAdapter;
@Override
+ public Context getContext() {
+ return getActivity();
+ }
+
+ @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
diff --git a/src/com/android/dialer/list/AllContactsFragment.java b/src/com/android/dialer/list/AllContactsFragment.java
index 0f31ff8..7e76279 100644
--- a/src/com/android/dialer/list/AllContactsFragment.java
+++ b/src/com/android/dialer/list/AllContactsFragment.java
@@ -28,11 +28,13 @@
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.compat.CompatUtils;
import com.android.contacts.common.list.ContactEntryListAdapter;
import com.android.contacts.common.list.ContactEntryListFragment;
import com.android.contacts.common.list.ContactListFilter;
@@ -49,7 +51,8 @@
* Fragments to show all contacts with phone numbers.
*/
public class AllContactsFragment extends ContactEntryListFragment<ContactEntryListAdapter>
- implements OnEmptyViewActionButtonClickedListener {
+ implements OnEmptyViewActionButtonClickedListener,
+ FragmentCompat.OnRequestPermissionsResultCallback {
private static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 1;
@@ -150,8 +153,13 @@
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final Uri uri = (Uri) view.getTag();
if (uri != null) {
- QuickContact.showQuickContact(getContext(), view, uri, null,
- Phone.CONTENT_ITEM_TYPE);
+ if (CompatUtils.hasPrioritizedMimeType()) {
+ QuickContact.showQuickContact(getContext(), view, uri, null,
+ Phone.CONTENT_ITEM_TYPE);
+ } else {
+ QuickContact.showQuickContact(getActivity(), view, uri, QuickContact.MODE_LARGE,
+ null);
+ }
}
}
@@ -168,7 +176,8 @@
}
if (!PermissionsUtil.hasPermission(activity, READ_CONTACTS)) {
- requestPermissions(new String[] {READ_CONTACTS}, READ_CONTACTS_PERMISSION_REQUEST_CODE);
+ FragmentCompat.requestPermissions(this, new String[] {READ_CONTACTS},
+ READ_CONTACTS_PERMISSION_REQUEST_CODE);
} else {
// Add new contact
DialerUtils.startActivityWithErrorToast(activity, IntentUtil.getNewContactIntent(),
diff --git a/src/com/android/dialer/list/PhoneFavoriteSquareTileView.java b/src/com/android/dialer/list/PhoneFavoriteSquareTileView.java
index c12bed7..69a230c 100644
--- a/src/com/android/dialer/list/PhoneFavoriteSquareTileView.java
+++ b/src/com/android/dialer/list/PhoneFavoriteSquareTileView.java
@@ -24,6 +24,7 @@
import android.widget.ImageButton;
import android.widget.TextView;
+import com.android.contacts.common.compat.CompatUtils;
import com.android.contacts.common.list.ContactEntry;
import com.android.dialer.R;
@@ -63,8 +64,13 @@
}
private void launchQuickContact() {
- QuickContact.showQuickContact(getContext(), PhoneFavoriteSquareTileView.this,
- getLookupUri(), null, Phone.CONTENT_ITEM_TYPE);
+ if (CompatUtils.hasPrioritizedMimeType()) {
+ QuickContact.showQuickContact(getContext(), PhoneFavoriteSquareTileView.this,
+ getLookupUri(), null, Phone.CONTENT_ITEM_TYPE);
+ } else {
+ QuickContact.showQuickContact(getContext(), PhoneFavoriteSquareTileView.this,
+ getLookupUri(), QuickContact.MODE_LARGE, null);
+ }
}
@Override
diff --git a/src/com/android/dialer/list/RegularSearchFragment.java b/src/com/android/dialer/list/RegularSearchFragment.java
index 30b01c0..d067b65 100644
--- a/src/com/android/dialer/list/RegularSearchFragment.java
+++ b/src/com/android/dialer/list/RegularSearchFragment.java
@@ -19,6 +19,7 @@
import android.app.Activity;
import android.content.pm.PackageManager;
+import android.support.v13.app.FragmentCompat;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -37,7 +38,8 @@
import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener;
public class RegularSearchFragment extends SearchFragment
- implements OnEmptyViewActionButtonClickedListener {
+ implements OnEmptyViewActionButtonClickedListener,
+ FragmentCompat.OnRequestPermissionsResultCallback {
public static final int PERMISSION_REQUEST_CODE = 1;
@@ -123,7 +125,8 @@
}
if (READ_CONTACTS.equals(mPermissionToRequest)) {
- requestPermissions(new String[] {mPermissionToRequest}, PERMISSION_REQUEST_CODE);
+ FragmentCompat.requestPermissions(this, new String[] {mPermissionToRequest},
+ PERMISSION_REQUEST_CODE);
}
}
diff --git a/src/com/android/dialer/list/SmartDialSearchFragment.java b/src/com/android/dialer/list/SmartDialSearchFragment.java
index a230e6e..4984d95 100644
--- a/src/com/android/dialer/list/SmartDialSearchFragment.java
+++ b/src/com/android/dialer/list/SmartDialSearchFragment.java
@@ -22,6 +22,7 @@
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
+import android.support.v13.app.FragmentCompat;
import android.util.Log;
import android.view.View;
@@ -40,7 +41,8 @@
* Implements a fragment to load and display SmartDial search results.
*/
public class SmartDialSearchFragment extends SearchFragment
- implements EmptyContentView.OnEmptyViewActionButtonClickedListener {
+ implements EmptyContentView.OnEmptyViewActionButtonClickedListener,
+ FragmentCompat.OnRequestPermissionsResultCallback {
private static final String TAG = SmartDialSearchFragment.class.getSimpleName();
private static final int CALL_PHONE_PERMISSION_REQUEST_CODE = 1;
@@ -108,7 +110,8 @@
return;
}
- requestPermissions(new String[] {CALL_PHONE}, CALL_PHONE_PERMISSION_REQUEST_CODE);
+ FragmentCompat.requestPermissions(this, new String[] {CALL_PHONE},
+ CALL_PHONE_PERMISSION_REQUEST_CODE);
}
@Override
diff --git a/src/com/android/dialer/list/SpeedDialFragment.java b/src/com/android/dialer/list/SpeedDialFragment.java
index 19180f8..fcfff21 100644
--- a/src/com/android/dialer/list/SpeedDialFragment.java
+++ b/src/com/android/dialer/list/SpeedDialFragment.java
@@ -31,6 +31,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Trace;
+import android.support.v13.app.FragmentCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -63,7 +64,8 @@
*/
public class SpeedDialFragment extends Fragment implements OnItemClickListener,
PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener,
- EmptyContentView.OnEmptyViewActionButtonClickedListener {
+ EmptyContentView.OnEmptyViewActionButtonClickedListener,
+ FragmentCompat.OnRequestPermissionsResultCallback {
private static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 1;
@@ -482,7 +484,8 @@
}
if (!PermissionsUtil.hasPermission(activity, READ_CONTACTS)) {
- requestPermissions(new String[] {READ_CONTACTS}, READ_CONTACTS_PERMISSION_REQUEST_CODE);
+ FragmentCompat.requestPermissions(this, new String[] {READ_CONTACTS},
+ READ_CONTACTS_PERMISSION_REQUEST_CODE);
} else {
// Switch tabs
((HostInterface) activity).showAllContactsTab();
diff --git a/src/com/android/dialer/settings/DefaultRingtonePreference.java b/src/com/android/dialer/settings/DefaultRingtonePreference.java
index a174381..a8a23fd 100644
--- a/src/com/android/dialer/settings/DefaultRingtonePreference.java
+++ b/src/com/android/dialer/settings/DefaultRingtonePreference.java
@@ -16,17 +16,16 @@
package com.android.dialer.settings;
-import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.preference.RingtonePreference;
-import android.provider.Settings;
import android.util.AttributeSet;
import android.widget.Toast;
import com.android.dialer.R;
+import com.android.dialer.compat.SettingsCompat;
/**
* RingtonePreference which doesn't show default ringtone setting.
@@ -49,7 +48,7 @@
@Override
protected void onSaveRingtone(Uri ringtoneUri) {
- if (!Settings.System.canWrite(getContext())) {
+ if (!SettingsCompat.System.canWrite(getContext())) {
Toast.makeText(
getContext(),
getContext().getResources().getString(R.string.toast_cannot_write_system_settings),
diff --git a/src/com/android/dialer/settings/DialerSettingsActivity.java b/src/com/android/dialer/settings/DialerSettingsActivity.java
index d0bfbc2..d7b8e11 100644
--- a/src/com/android/dialer/settings/DialerSettingsActivity.java
+++ b/src/com/android/dialer/settings/DialerSettingsActivity.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.os.Build;
import android.os.Bundle;
import android.os.UserManager;
import android.preference.PreferenceManager;
@@ -27,7 +28,9 @@
import android.view.MenuItem;
import android.widget.Toast;
+import com.android.contacts.common.compat.SdkVersionOverride;
import com.android.dialer.R;
+import com.android.dialer.compat.SettingsCompat;
import com.android.dialer.filterednumber.BlockedNumbersSettingsActivity;
import java.util.List;
@@ -54,45 +57,53 @@
soundSettingsHeader.id = R.id.settings_header_sounds_and_vibration;
target.add(soundSettingsHeader);
- Header quickResponseSettingsHeader = new Header();
- Intent quickResponseSettingsIntent =
- new Intent(TelecomManager.ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS);
- quickResponseSettingsHeader.titleRes = R.string.respond_via_sms_setting_title;
- quickResponseSettingsHeader.intent = quickResponseSettingsIntent;
- target.add(quickResponseSettingsHeader);
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
+ >= Build.VERSION_CODES.M) {
+ Header quickResponseSettingsHeader = new Header();
+ Intent quickResponseSettingsIntent =
+ new Intent(TelecomManager.ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS);
+ quickResponseSettingsHeader.titleRes = R.string.respond_via_sms_setting_title;
+ quickResponseSettingsHeader.intent = quickResponseSettingsIntent;
+ target.add(quickResponseSettingsHeader);
+ }
+
TelephonyManager telephonyManager =
(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
- // Only show call setting menus if the current user is the primary/owner user.
- if (isPrimaryUser()) {
- // Show "Call Settings" if there is one SIM and "Phone Accounts" if there are more.
- if (telephonyManager.getPhoneCount() <= 1) {
- Header callSettingsHeader = new Header();
- Intent callSettingsIntent = new Intent(TelecomManager.ACTION_SHOW_CALL_SETTINGS);
- callSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ // "Call Settings" (full settings) is shown if the current user is primary user and there
+ // is only one SIM. Before N, "Calling accounts" setting is shown if the current user is
+ // primary user and there are multiple SIMs. In N+, "Calling accounts" is shown whenever
+ // "Call Settings" is not shown.
+ boolean isPrimaryUser = isPrimaryUser();
+ if (isPrimaryUser && telephonyManager.getPhoneCount() <= 1) {
+ Header callSettingsHeader = new Header();
+ Intent callSettingsIntent = new Intent(TelecomManager.ACTION_SHOW_CALL_SETTINGS);
+ callSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- callSettingsHeader.titleRes = R.string.call_settings_label;
- callSettingsHeader.intent = callSettingsIntent;
- target.add(callSettingsHeader);
- } else {
- Header phoneAccountSettingsHeader = new Header();
- Intent phoneAccountSettingsIntent =
- new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS);
- phoneAccountSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ callSettingsHeader.titleRes = R.string.call_settings_label;
+ callSettingsHeader.intent = callSettingsIntent;
+ target.add(callSettingsHeader);
+ } else if (android.os.Build.VERSION.CODENAME.startsWith("N") || isPrimaryUser) {
+ Header phoneAccountSettingsHeader = new Header();
+ Intent phoneAccountSettingsIntent =
+ new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS);
+ phoneAccountSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- phoneAccountSettingsHeader.titleRes = R.string.phone_account_settings_label;
- phoneAccountSettingsHeader.intent = phoneAccountSettingsIntent;
- target.add(phoneAccountSettingsHeader);
- }
-
+ phoneAccountSettingsHeader.titleRes = R.string.phone_account_settings_label;
+ phoneAccountSettingsHeader.intent = phoneAccountSettingsIntent;
+ target.add(phoneAccountSettingsHeader);
+ }
+ if (isPrimaryUser) {
Header blockedCallsHeader = new Header();
blockedCallsHeader.titleRes = R.string.manage_blocked_numbers_label;
blockedCallsHeader.intent = new Intent(this, BlockedNumbersSettingsActivity.class);
target.add(blockedCallsHeader);
- if (telephonyManager.isTtyModeSupported()
- || telephonyManager.isHearingAidCompatibilitySupported()) {
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
+ >= Build.VERSION_CODES.M
+ && (telephonyManager.isTtyModeSupported()
+ || telephonyManager.isHearingAidCompatibilitySupported())) {
Header accessibilitySettingsHeader = new Header();
Intent accessibilitySettingsIntent =
new Intent(TelecomManager.ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS);
@@ -109,7 +120,7 @@
// If we don't have the permission to write to system settings, go to system sound
// settings instead. Otherwise, perform the super implementation (which launches our
// own preference fragment.
- if (!Settings.System.canWrite(this)) {
+ if (!SettingsCompat.System.canWrite(this)) {
Toast.makeText(
this,
getResources().getString(R.string.toast_cannot_write_system_settings),
diff --git a/src/com/android/dialer/settings/SoundSettingsFragment.java b/src/com/android/dialer/settings/SoundSettingsFragment.java
index 8384700..59f8798 100644
--- a/src/com/android/dialer/settings/SoundSettingsFragment.java
+++ b/src/com/android/dialer/settings/SoundSettingsFragment.java
@@ -16,10 +16,9 @@
package com.android.dialer.settings;
-import android.app.AppOpsManager;
import android.content.Context;
-import android.content.Intent;
import android.media.RingtoneManager;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -32,21 +31,13 @@
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
-import android.view.MenuItem;
import android.widget.Toast;
-import com.android.contacts.common.util.PermissionsUtil;
+import com.android.contacts.common.compat.SdkVersionOverride;
import com.android.dialer.R;
+import com.android.dialer.compat.SettingsCompat;
import com.android.phone.common.util.SettingsUtil;
-import java.lang.Boolean;
-import java.lang.CharSequence;
-import java.lang.Object;
-import java.lang.Override;
-import java.lang.Runnable;
-import java.lang.String;
-import java.lang.Thread;
-
public class SoundSettingsFragment extends PreferenceFragment
implements Preference.OnPreferenceChangeListener {
@@ -88,6 +79,11 @@
};
@Override
+ public Context getContext() {
+ return getActivity();
+ }
+
+ @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -115,7 +111,8 @@
TelephonyManager telephonyManager =
(TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
- if (telephonyManager.canChangeDtmfToneLength()
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M
+ && telephonyManager.canChangeDtmfToneLength()
&& (telephonyManager.isWorldPhone() || !shouldHideCarrierSettings())) {
mDtmfToneLength.setOnPreferenceChangeListener(this);
mDtmfToneLength.setValueIndex(
@@ -132,7 +129,7 @@
public void onResume() {
super.onResume();
- if (!Settings.System.canWrite(getContext())) {
+ if (!SettingsCompat.System.canWrite(getContext())) {
// If the user launches this setting fragment, then toggles the WRITE_SYSTEM_SETTINGS
// AppOp, then close the fragment since there is nothing useful to do.
getActivity().onBackPressed();
@@ -155,7 +152,7 @@
*/
@Override
public boolean onPreferenceChange(Preference preference, Object objValue) {
- if (!Settings.System.canWrite(getContext())) {
+ if (!SettingsCompat.System.canWrite(getContext())) {
// A user shouldn't be able to get here, but this protects against monkey crashes.
Toast.makeText(
getContext(),
@@ -181,7 +178,7 @@
*/
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- if (!Settings.System.canWrite(getContext())) {
+ if (!SettingsCompat.System.canWrite(getContext())) {
Toast.makeText(
getContext(),
getResources().getString(R.string.toast_cannot_write_system_settings),
diff --git a/src/com/android/dialer/util/AppCompatConstants.java b/src/com/android/dialer/util/AppCompatConstants.java
index 1d52eee..0bb78df 100644
--- a/src/com/android/dialer/util/AppCompatConstants.java
+++ b/src/com/android/dialer/util/AppCompatConstants.java
@@ -27,4 +27,6 @@
public static final int CALLS_REJECTED_TYPE = 5;
// Added to android.provider.CallLog.Calls in N+.
public static final int CALLS_BLOCKED_TYPE = 6;
+ // Added to android.provider.CallLog.Calls in N+.
+ public static final String POST_DIAL_DIGITS = "post_dial_digits";
}
diff --git a/src/com/android/dialer/util/TelecomUtil.java b/src/com/android/dialer/util/TelecomUtil.java
index bab1ade..a0c8334 100644
--- a/src/com/android/dialer/util/TelecomUtil.java
+++ b/src/com/android/dialer/util/TelecomUtil.java
@@ -22,11 +22,14 @@
import android.net.Uri;
import android.os.Bundle;
import android.provider.CallLog.Calls;
+import android.support.v4.content.ContextCompat;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.Log;
+import com.android.dialer.compat.DialerCompatUtils;
+
import java.util.ArrayList;
import java.util.List;
@@ -181,11 +184,15 @@
}
private static boolean hasPermission(Context context, String permission) {
- return context.checkSelfPermission(permission)
+ return ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED;
}
public static boolean isDefaultDialer(Context context) {
+ if (!DialerCompatUtils.isDefaultDialerCompatible()) {
+ return false;
+ }
+
final boolean result = TextUtils.equals(context.getPackageName(),
getTelecomManager(context).getDefaultDialerPackage());
if (result) {
diff --git a/src/com/android/dialer/voicemail/VoicemailAudioManager.java b/src/com/android/dialer/voicemail/VoicemailAudioManager.java
index 267eeca..712b20b 100644
--- a/src/com/android/dialer/voicemail/VoicemailAudioManager.java
+++ b/src/com/android/dialer/voicemail/VoicemailAudioManager.java
@@ -19,10 +19,10 @@
import android.content.Context;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
-import android.telecom.CallAudioState;
import android.util.Log;
-import java.util.Objects;
+import com.android.dialer.compat.CallAudioStateCompat;
+
import java.util.concurrent.RejectedExecutionException;
/**
@@ -38,7 +38,7 @@
private VoicemailPlaybackPresenter mVoicemailPlaybackPresenter;
private WiredHeadsetManager mWiredHeadsetManager;
private boolean mWasSpeakerOn;
- private CallAudioState mCallAudioState;
+ private CallAudioStateCompat mCallAudioState;
public VoicemailAudioManager(Context context,
VoicemailPlaybackPresenter voicemailPlaybackPresenter) {
@@ -82,25 +82,26 @@
int newRoute = mCallAudioState.getRoute(); // start out with existing route
if (newIsPluggedIn) {
- newRoute = CallAudioState.ROUTE_WIRED_HEADSET;
+ newRoute = CallAudioStateCompat.ROUTE_WIRED_HEADSET;
} else {
if (mWasSpeakerOn) {
- newRoute = CallAudioState.ROUTE_SPEAKER;
+ newRoute = CallAudioStateCompat.ROUTE_SPEAKER;
} else {
- newRoute = CallAudioState.ROUTE_EARPIECE;
+ newRoute = CallAudioStateCompat.ROUTE_EARPIECE;
}
}
- mVoicemailPlaybackPresenter.setSpeakerphoneOn(newRoute == CallAudioState.ROUTE_SPEAKER);
+ mVoicemailPlaybackPresenter.setSpeakerphoneOn(newRoute == CallAudioStateCompat.ROUTE_SPEAKER);
// We need to call this every time even if we do not change the route because the supported
// routes changed either to include or not include WIRED_HEADSET.
setSystemAudioState(
- new CallAudioState(false /* muted */, newRoute, calculateSupportedRoutes()));
+ new CallAudioStateCompat(false /* muted */, newRoute, calculateSupportedRoutes()));
}
public void setSpeakerphoneOn(boolean on) {
- setAudioRoute(on ? CallAudioState.ROUTE_SPEAKER : CallAudioState.ROUTE_WIRED_OR_EARPIECE);
+ setAudioRoute(on ? CallAudioStateCompat.ROUTE_SPEAKER
+ : CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE);
}
public boolean isWiredHeadsetPluggedIn() {
@@ -119,10 +120,10 @@
/**
* Change the audio route, for example from earpiece to speakerphone.
*
- * @param route The new audio route to use. See {@link CallAudioState}.
+ * @param route The new audio route to use. See {@link CallAudioStateCompat}.
*/
void setAudioRoute(int route) {
- Log.v(TAG, "setAudioRoute, route: " + CallAudioState.audioRouteToString(route));
+ Log.v(TAG, "setAudioRoute, route: " + CallAudioStateCompat.audioRouteToString(route));
// Change ROUTE_WIRED_OR_EARPIECE to a single entry.
int newRoute = selectWiredOrEarpiece(route, mCallAudioState.getSupportedRouteMask());
@@ -136,25 +137,25 @@
if (mCallAudioState.getRoute() != newRoute) {
// Remember the new speaker state so it can be restored when the user plugs and unplugs
// a headset.
- mWasSpeakerOn = newRoute == CallAudioState.ROUTE_SPEAKER;
- setSystemAudioState(new CallAudioState(false /* muted */, newRoute,
+ mWasSpeakerOn = newRoute == CallAudioStateCompat.ROUTE_SPEAKER;
+ setSystemAudioState(new CallAudioStateCompat(false /* muted */, newRoute,
mCallAudioState.getSupportedRouteMask()));
}
}
- private CallAudioState getInitialAudioState() {
+ private CallAudioStateCompat getInitialAudioState() {
int supportedRouteMask = calculateSupportedRoutes();
- int route = selectWiredOrEarpiece(CallAudioState.ROUTE_WIRED_OR_EARPIECE,
+ int route = selectWiredOrEarpiece(CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE,
supportedRouteMask);
- return new CallAudioState(false /* muted */, route, supportedRouteMask);
+ return new CallAudioStateCompat(false /* muted */, route, supportedRouteMask);
}
private int calculateSupportedRoutes() {
- int routeMask = CallAudioState.ROUTE_SPEAKER;
+ int routeMask = CallAudioStateCompat.ROUTE_SPEAKER;
if (mWiredHeadsetManager.isPluggedIn()) {
- routeMask |= CallAudioState.ROUTE_WIRED_HEADSET;
+ routeMask |= CallAudioStateCompat.ROUTE_WIRED_HEADSET;
} else {
- routeMask |= CallAudioState.ROUTE_EARPIECE;
+ routeMask |= CallAudioStateCompat.ROUTE_EARPIECE;
}
return routeMask;
}
@@ -163,29 +164,29 @@
// Since they are mutually exclusive and one is ALWAYS valid, we allow a special input of
// ROUTE_WIRED_OR_EARPIECE so that callers don't have to make a call to check which is
// supported before calling setAudioRoute.
- if (route == CallAudioState.ROUTE_WIRED_OR_EARPIECE) {
- route = CallAudioState.ROUTE_WIRED_OR_EARPIECE & supportedRouteMask;
+ if (route == CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE) {
+ route = CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE & supportedRouteMask;
if (route == 0) {
Log.wtf(TAG, "One of wired headset or earpiece should always be valid.");
// assume earpiece in this case.
- route = CallAudioState.ROUTE_EARPIECE;
+ route = CallAudioStateCompat.ROUTE_EARPIECE;
}
}
return route;
}
- private void setSystemAudioState(CallAudioState callAudioState) {
- CallAudioState oldAudioState = mCallAudioState;
+ private void setSystemAudioState(CallAudioStateCompat callAudioState) {
+ CallAudioStateCompat oldAudioState = mCallAudioState;
mCallAudioState = callAudioState;
Log.i(TAG, "setSystemAudioState: changing from " + oldAudioState + " to "
+ mCallAudioState);
// Audio route.
- if (mCallAudioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
+ if (mCallAudioState.getRoute() == CallAudioStateCompat.ROUTE_SPEAKER) {
turnOnSpeaker(true);
- } else if (mCallAudioState.getRoute() == CallAudioState.ROUTE_EARPIECE ||
- mCallAudioState.getRoute() == CallAudioState.ROUTE_WIRED_HEADSET) {
+ } else if (mCallAudioState.getRoute() == CallAudioStateCompat.ROUTE_EARPIECE ||
+ mCallAudioState.getRoute() == CallAudioStateCompat.ROUTE_WIRED_HEADSET) {
// Just handle turning off the speaker, the system will handle switching between wired
// headset and earpiece.
turnOnSpeaker(false);
diff --git a/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java b/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
index a5a61ad..80dfe35 100644
--- a/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
@@ -64,6 +64,7 @@
private static final String TEST_NUMBER_1 = "12345678";
private static final String TEST_NUMBER_2 = "87654321";
private static final String TEST_NUMBER_3 = "18273645";
+ private static final String TEST_POST_DIAL_DIGITS = ";12345";
private static final String TEST_FORMATTED_NUMBER = "1 212-555-1000";
// The object under test.
@@ -233,6 +234,18 @@
}
@MediumTest
+ public void testBindView_CallButtonWithPostDialDigits() {
+ createCallLogEntry(TEST_NUMBER, TEST_POST_DIAL_DIGITS, NO_VALUE_SET, NO_VALUE_SET);
+
+ mAdapter.changeCursor(mCursor);
+ mAdapter.onBindViewHolder(mViewHolder, 0);
+
+ if (PhoneNumberDisplayUtil.canShowPostDial()) {
+ assertHasCallActionToGivenNumber(mViewHolder, TEST_NUMBER + TEST_POST_DIAL_DIGITS);
+ }
+ }
+
+ @MediumTest
public void testBindView_VoicemailUri() {
createVoicemailCallLogEntry();
@@ -245,6 +258,32 @@
}
@MediumTest
+ public void testBindView_NumberWithPostDialDigits() {
+ createCallLogEntry(TEST_NUMBER, TEST_POST_DIAL_DIGITS, NO_VALUE_SET, NO_VALUE_SET);
+
+ mAdapter.changeCursor(mCursor);
+ mAdapter.onBindViewHolder(mViewHolder, 0);
+
+ if (PhoneNumberDisplayUtil.canShowPostDial()) {
+ assertNameIs(mViewHolder, TEST_NUMBER + TEST_POST_DIAL_DIGITS);
+ }
+ }
+
+ @MediumTest
+ public void testBindView_ContactWithPostDialDigits() {
+ createCallLogEntry(TEST_NUMBER, TEST_POST_DIAL_DIGITS, NO_VALUE_SET, NO_VALUE_SET);
+ mAdapter.injectContactInfoForTest(TEST_NUMBER + TEST_POST_DIAL_DIGITS, TEST_COUNTRY_ISO,
+ createContactInfo());
+
+ mAdapter.changeCursor(mCursor);
+ mAdapter.onBindViewHolder(mViewHolder, 0);
+
+ if (PhoneNumberDisplayUtil.canShowPostDial()) {
+ assertNameIs(mViewHolder, TEST_CACHED_NAME_PRIMARY);
+ }
+ }
+
+ @MediumTest
public void testPresentationAfterRebindingViewHolders() {
final int increment = 10;
final int size = increment * 4;
@@ -513,12 +552,13 @@
}
private void createCallLogEntry(String testNumber) {
- createCallLogEntry(testNumber, NO_VALUE_SET, NO_VALUE_SET);
+ createCallLogEntry(testNumber, EMPTY_STRING, NO_VALUE_SET, NO_VALUE_SET);
}
private void createPrivateCallLogEntry() {
createCallLogEntry(
EMPTY_STRING,
+ EMPTY_STRING,
Calls.PRESENTATION_RESTRICTED,
AppCompatConstants.CALLS_INCOMING_TYPE);
}
@@ -526,16 +566,17 @@
private void createUnknownCallLogEntry() {
createCallLogEntry(
EMPTY_STRING,
+ EMPTY_STRING,
Calls.PRESENTATION_UNKNOWN,
AppCompatConstants.CALLS_INCOMING_TYPE);
}
private void createVoicemailCallLogEntry() {
- createCallLogEntry(TEST_NUMBER, NO_VALUE_SET, Calls.VOICEMAIL_TYPE);
+ createCallLogEntry(TEST_NUMBER, EMPTY_STRING, NO_VALUE_SET, Calls.VOICEMAIL_TYPE);
}
- private void createCallLogEntry(String number, int presentation, int type) {
- Object[] values = getValues(number, presentation, type);
+ private void createCallLogEntry(String number, String postDialDigits, int presentation, int type) {
+ Object[] values = getValues(number, postDialDigits, presentation, type);
mCursor.addRow(values);
}
@@ -583,7 +624,7 @@
String cachedNumberLabel,
String cachedFormattedNumber,
boolean inject) {
- Object[] values = getValues(number, NO_VALUE_SET, type);
+ Object[] values = getValues(number, EMPTY_STRING, NO_VALUE_SET, type);
values[CallLogQuery.CACHED_NAME] = cachedName;
values[CallLogQuery.CACHED_NUMBER_TYPE] = cachedNumberType;
values[CallLogQuery.CACHED_NUMBER_LABEL] = cachedNumberLabel;
@@ -600,12 +641,14 @@
/**
* @param number The phone number.
+ * @param postDialDigits The post dial digits dialed (if any)
* @param presentation Number representing display rules for "allowed",
* "payphone", "restricted", or "unknown".
- * @param date In millisec since epoch. Use NOW to use the current time.
+ * @param type The type of the call (outgoing/ingoing)
*/
private Object[] getValues(
String number,
+ String postDialDigits,
int presentation,
int type) {
Object[] values = CallLogQueryTestUtils.createTestValues();
@@ -618,6 +661,9 @@
if (!TextUtils.isEmpty(number)) {
values[CallLogQuery.NUMBER] = number;
}
+ if (!TextUtils.isEmpty(postDialDigits) && PhoneNumberDisplayUtil.canShowPostDial()) {
+ values[CallLogQuery.POST_DIAL_DIGITS] = postDialDigits;
+ }
if (presentation != NO_VALUE_SET) {
values[CallLogQuery.NUMBER_PRESENTATION] = presentation;
}
@@ -676,14 +722,16 @@
}
private void assertHasCallAction(CallLogListItemViewHolder viewHolder) {
- // The primaryActionView tag is set when the ViewHolder is binded. If it is possible
- // to place a call to the phone number, a call intent will have been created which
- // starts a phone call to the entry's number.
+ assertHasCallActionToGivenNumber(viewHolder, TEST_NUMBER);
+ }
+
+ private void assertHasCallActionToGivenNumber(CallLogListItemViewHolder viewHolder,
+ String number) {
IntentProvider intentProvider =
(IntentProvider) viewHolder.primaryActionButtonView.getTag();
Intent intent = intentProvider.getIntent(getContext());
assertEquals(TestConstants.CALL_INTENT_ACTION, intent.getAction());
- assertEquals(Uri.parse("tel:" + TEST_NUMBER), intent.getData());
+ assertEquals(Uri.parse("tel:" + Uri.encode(number)), intent.getData());
}
/** Returns the label associated with a given phone type. */
diff --git a/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java b/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
index 5d0b6be..04463c2 100644
--- a/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
@@ -35,6 +35,8 @@
private static final String TEST_NUMBER1 = "14125551234";
/** A phone number for testing. */
private static final String TEST_NUMBER2 = "14125555555";
+ /** A post-dial string for testing */
+ private static final String TEST_POST_DIAL_DIGITS = ";12435;0987";
/** The object under test. */
private CallLogGroupBuilder mBuilder;
@@ -86,6 +88,26 @@
assertGroupIs(0, 3, mFakeGroupCreator.groups.get(0));
}
+ public void testAddGroups_WithPostDialMatching() {
+ addCallLogEntryWithPostDialDigits(TEST_NUMBER1, TEST_POST_DIAL_DIGITS,
+ AppCompatConstants.CALLS_OUTGOING_TYPE);
+ addCallLogEntryWithPostDialDigits(TEST_NUMBER1, TEST_POST_DIAL_DIGITS,
+ AppCompatConstants.CALLS_OUTGOING_TYPE);
+ addCallLogEntryWithPostDialDigits(TEST_NUMBER1, "",
+ AppCompatConstants.CALLS_OUTGOING_TYPE);
+
+ mBuilder.addGroups(mCursor);
+
+ if (PhoneNumberDisplayUtil.canShowPostDial()) {
+ assertEquals(2, mFakeGroupCreator.groups.size());
+ assertGroupIs(0, 2, mFakeGroupCreator.groups.get(0));
+ assertGroupIs(2, 1, mFakeGroupCreator.groups.get(1));
+ } else {
+ assertEquals(1, mFakeGroupCreator.groups.size());
+ assertGroupIs(0, 3, mFakeGroupCreator.groups.get(0));
+ }
+ }
+
public void testAddGroups_MatchingIncomingAndOutgoing() {
addCallLogEntry(TEST_NUMBER1, AppCompatConstants.CALLS_INCOMING_TYPE);
addCallLogEntry(TEST_NUMBER1, AppCompatConstants.CALLS_OUTGOING_TYPE);
@@ -312,11 +334,19 @@
}
/** Adds a call log entry with the given number and type to the cursor. */
private void addCallLogEntry(String number, int type) {
+ addCallLogEntryWithPostDialDigits(number, "", type);
+ }
+
+ /** Adds a call log entry with the given number, post-dial digits, and type to the cursor. */
+ private void addCallLogEntryWithPostDialDigits(String number, String postDialDigits, int type) {
mCursor.moveToNext();
Object[] values = CallLogQueryTestUtils.createTestValues();
values[CallLogQuery.ID] = mCursor.getPosition();
values[CallLogQuery.NUMBER] = number;
values[CallLogQuery.CALL_TYPE] = type;
+ if (PhoneNumberDisplayUtil.canShowPostDial()) {
+ values[CallLogQuery.POST_DIAL_DIGITS] = postDialDigits;
+ }
mCursor.addRow(values);
}
diff --git a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
index c9d8264..a97fce3 100644
--- a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
@@ -246,26 +246,34 @@
/** Sets the details of a phone call using the specified phone number. */
private void setPhoneCallDetailsWithNumber(String number,
int presentation, String formattedNumber) {
- setPhoneCallDetailsWithNumberAndType(number, presentation,
+ setPhoneCallDetailsWithNumberTypeAndPostDialDigits(number, "", presentation,
formattedNumber, Calls.INCOMING_TYPE);
}
/** Sets the details of a phone call using the specified phone number. */
private void setPhoneCallDetailsWithNumberAndType(String number,
int presentation, String formattedNumber, int callType) {
+ setPhoneCallDetailsWithNumberTypeAndPostDialDigits(number, "", presentation,
+ formattedNumber, callType);
+ }
+
+ /** Sets the details of a phone call using the specified phone number and post-dial digits. */
+ private void setPhoneCallDetailsWithNumberTypeAndPostDialDigits(String number,
+ String postDialDigits, int presentation, String formattedNumber, int callType) {
PhoneCallDetails details = getPhoneCallDetails(
- number, presentation, formattedNumber);
+ number, postDialDigits, presentation, formattedNumber);
details.callTypes = new int[] {callType};
mHelper.setPhoneCallDetails(mViewHolder, details);
}
private PhoneCallDetails getPhoneCallDetails(
- String number, int presentation, String formattedNumber) {
+ String number, String postDialDigits, int presentation, String formattedNumber) {
PhoneCallDetails details = new PhoneCallDetails(
mContext,
number,
presentation,
formattedNumber,
+ postDialDigits,
false /* isVoicemail */);
setDefaultDetails(details);
return details;
@@ -278,6 +286,7 @@
TEST_NUMBER,
Calls.PRESENTATION_ALLOWED,
TEST_FORMATTED_NUMBER,
+ "",
false /* isVoicemail */);
setDefaultDetails(details);
details.callTypes = types;
diff --git a/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java b/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
index 5b46293..1e4a000 100644
--- a/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
+++ b/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
@@ -20,17 +20,24 @@
import android.provider.CallLog.Calls;
-import junit.framework.Assert;
-
/**
* Helper class to create test values for {@link CallLogQuery}.
*/
public class CallLogQueryTestUtils {
public static Object[] createTestValues() {
- Object[] values = new Object[]{
- 0L, "", 0L, 0L, Calls.INCOMING_TYPE, "", "", "", null, 0, null, null, null, null,
- 0L, null, 0, Calls.PRESENTATION_ALLOWED, null, null, 0, null, null, null
- };
+ Object[] values;
+ if (PhoneNumberDisplayUtil.canShowPostDial()) {
+ values = new Object[]{
+ 0L, "", 0L, 0L, Calls.INCOMING_TYPE, "", "", "", null, 0, null, null, null,
+ null, 0L, null, 0, Calls.PRESENTATION_ALLOWED, null, null, 0, null, null,
+ null, ""
+ };
+ } else {
+ values = new Object[]{
+ 0L, "", 0L, 0L, Calls.INCOMING_TYPE, "", "", "", null, 0, null, null, null,
+ null, 0L, null, 0, Calls.PRESENTATION_ALLOWED, null, null, 0, null, null, null
+ };
+ }
assertEquals(CallLogQuery._PROJECTION.length, values.length);
return values;
}
diff --git a/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java b/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java
index c30861c..23ee7b3 100644
--- a/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java
+++ b/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java
@@ -58,6 +58,8 @@
private static final String TEST_GEOCODE = "United States";
/** Empty geocode label */
private static final String EMPTY_GEOCODE = "";
+ /** Empty post-dial digits label */
+ private static final String EMPTY_POSTDIAL = "";
/** The object under test. */
private PhoneCallDetailsHelper mHelper;
@@ -428,6 +430,7 @@
TEST_NUMBER,
Calls.PRESENTATION_ALLOWED,
TEST_FORMATTED_NUMBER,
+ EMPTY_POSTDIAL,
false /* isVoicemail */);
setDefaultDetails(details);
return details;
@@ -440,6 +443,7 @@
number,
presentation,
formattedNumber,
+ EMPTY_POSTDIAL,
isVoicemail(number));
setDefaultDetails(details);
return details;
diff --git a/tests/src/com/android/dialer/calllog/TestTelecomCallLogCache.java b/tests/src/com/android/dialer/calllog/TestTelecomCallLogCache.java
index 5475ec3..fcf9884 100644
--- a/tests/src/com/android/dialer/calllog/TestTelecomCallLogCache.java
+++ b/tests/src/com/android/dialer/calllog/TestTelecomCallLogCache.java
@@ -17,13 +17,20 @@
package com.android.dialer.calllog;
import android.content.Context;
+import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
+import com.android.dialer.calllog.calllogcache.CallLogCache;
+
/**
- * Modified version of {@link com.android.dialer.calllog.PhoneNumberDisplayHelper} to be used in
+ * Modified version of {@link com.android.dialer.calllog.calllogcache.CallLogCache} to be used in
* tests that allows injecting the voicemail number.
+ *
+ * NOTE: This tests the pre-LMR1 version because currently none of the tests involve multi-SIM,
+ * but...
+ * TODO: write tests to test multi-SIM functionality in TelecomCallLogCache.
*/
-public final class TestTelecomCallLogCache extends TelecomCallLogCache {
+public final class TestTelecomCallLogCache extends CallLogCache {
private CharSequence mVoicemailNumber;
public TestTelecomCallLogCache(Context context, CharSequence voicemailNumber) {
@@ -35,4 +42,19 @@
public boolean isVoicemailNumber(PhoneAccountHandle accountHandle, CharSequence number) {
return mVoicemailNumber.equals(number);
}
+
+ @Override
+ public String getAccountLabel(PhoneAccountHandle accountHandle) {
+ return null;
+ }
+
+ @Override
+ public int getAccountColor(PhoneAccountHandle accountHandle) {
+ return PhoneAccount.NO_HIGHLIGHT_COLOR;
+ }
+
+ @Override
+ public boolean doesAccountSupportCallSubject(PhoneAccountHandle accountHandle) {
+ return false;
+ }
}
diff --git a/tests/src/com/android/dialer/filterednumber/FilteredNumbersUtilTest.java b/tests/src/com/android/dialer/filterednumber/FilteredNumbersUtilTest.java
index 180295c..ccd95ab 100644
--- a/tests/src/com/android/dialer/filterednumber/FilteredNumbersUtilTest.java
+++ b/tests/src/com/android/dialer/filterednumber/FilteredNumbersUtilTest.java
@@ -15,6 +15,7 @@
*/
package com.android.dialer.filterednumber;
+import android.preference.PreferenceManager;
import android.test.AndroidTestCase;
import com.android.contacts.common.test.mocks.ContactsMockContext;
@@ -46,6 +47,12 @@
public void setUp() throws Exception {
super.setUp();
mContext = new ContactsMockContext(getContext(), FilteredNumberContract.AUTHORITY);
+
+ // Reset whether an emergency number was dialed
+ PreferenceManager.getDefaultSharedPreferences(mContext)
+ .edit()
+ .putLong(FilteredNumbersUtil.LAST_EMERGENCY_CALL_MS_PREF_KEY, 0)
+ .apply();
}
public void testShouldBlockVoicemail_NotBlocked() {
@@ -78,6 +85,17 @@
COUNTRY_ISO, EARLIER_TIME + 30000));
}
+ public void testShouldBlockVoicemail_AfterEmergencyCall() {
+ // Just called emergency services
+ PreferenceManager.getDefaultSharedPreferences(mContext)
+ .edit()
+ .putLong(FilteredNumbersUtil.LAST_EMERGENCY_CALL_MS_PREF_KEY,
+ System.currentTimeMillis())
+ .apply();
+ assertFalse(FilteredNumbersUtil.shouldBlockVoicemail(mContext, NORMALIZED_NUMBER,
+ COUNTRY_ISO, 0));
+ }
+
private void setupShouldBlockVoicemailQuery(long creationTimeMs) {
Query query = mContext.getContactsProvider().expectQuery(FilteredNumber.CONTENT_URI)
.withProjection(FILTERED_NUMBER_PROJECTION)