summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/calllogutils
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2017-03-15 14:41:07 -0700
committerEric Erfanian <erfanian@google.com>2017-03-15 16:24:23 -0700
commitd5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9 (patch)
treeb54abbb51fb7d66e7755a1fbb5db023ff601090b /java/com/android/dialer/calllogutils
parent30436e7e6d3f2c8755a91b2b6222b74d465a9e87 (diff)
Update Dialer source from latest green build.
* Refactor voicemail component * Add new enriched calling components Test: treehugger, manual aosp testing Change-Id: I521a0f86327d4b42e14d93927c7d613044ed5942
Diffstat (limited to 'java/com/android/dialer/calllogutils')
-rw-r--r--java/com/android/dialer/calllogutils/AndroidManifest.xml16
-rw-r--r--java/com/android/dialer/calllogutils/CallEntryFormatter.java113
-rw-r--r--java/com/android/dialer/calllogutils/CallTypeHelper.java135
-rw-r--r--java/com/android/dialer/calllogutils/CallTypeIconsView.java244
-rw-r--r--java/com/android/dialer/calllogutils/PhoneAccountUtils.java104
-rw-r--r--java/com/android/dialer/calllogutils/PhoneCallDetails.java206
-rw-r--r--java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java83
-rw-r--r--java/com/android/dialer/calllogutils/res/values/colors.xml24
-rw-r--r--java/com/android/dialer/calllogutils/res/values/dimens.xml19
-rw-r--r--java/com/android/dialer/calllogutils/res/values/strings.xml90
10 files changed, 1034 insertions, 0 deletions
diff --git a/java/com/android/dialer/calllogutils/AndroidManifest.xml b/java/com/android/dialer/calllogutils/AndroidManifest.xml
new file mode 100644
index 000000000..228865a38
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<!--
+ ~ Copyright (C) 2017 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
+ -->
+<manifest package="com.android.dialer.calllogutils"/> \ No newline at end of file
diff --git a/java/com/android/dialer/calllogutils/CallEntryFormatter.java b/java/com/android/dialer/calllogutils/CallEntryFormatter.java
new file mode 100644
index 000000000..bd6d53f48
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/CallEntryFormatter.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 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.calllogutils;
+
+import android.content.Context;
+import android.icu.lang.UCharacter;
+import android.icu.text.BreakIterator;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.text.format.DateUtils;
+import android.text.format.Formatter;
+import com.android.dialer.util.DialerUtils;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/** Utility class for formatting data and data usage in call log entries. */
+public class CallEntryFormatter {
+
+ /**
+ * Formats the provided date into a value suitable for display in the current locale.
+ *
+ * <p>For example, returns a string like "Wednesday, May 25, 2016, 8:02PM" or "Chorshanba, 2016
+ * may 25,20:02".
+ *
+ * <p>For pre-N devices, the returned value may not start with a capital if the local convention
+ * is to not capitalize day names. On N+ devices, the returned value is always capitalized.
+ */
+ public static CharSequence formatDate(Context context, long callDateMillis) {
+ CharSequence dateValue =
+ DateUtils.formatDateRange(
+ context,
+ callDateMillis /* startDate */,
+ callDateMillis /* endDate */,
+ DateUtils.FORMAT_SHOW_TIME
+ | DateUtils.FORMAT_SHOW_DATE
+ | DateUtils.FORMAT_SHOW_WEEKDAY
+ | DateUtils.FORMAT_SHOW_YEAR);
+
+ // We want the beginning of the date string to be capitalized, even if the word at the beginning
+ // of the string is not usually capitalized. For example, "Wednesdsay" in Uzbek is "chorshanba”
+ // (not capitalized). To handle this issue we apply title casing to the start of the sentence so
+ // that "chorshanba, 2016 may 25,20:02" becomes "Chorshanba, 2016 may 25,20:02".
+ //
+ // The ICU library was not available in Android until N, so we can only do this in N+ devices.
+ // Pre-N devices will still see incorrect capitalization in some languages.
+ if (VERSION.SDK_INT < VERSION_CODES.N) {
+ return dateValue;
+ }
+
+ // Using the ICU library is safer than just applying toUpperCase() on the first letter of the
+ // word because in some languages, there can be multiple starting characters which should be
+ // upper-cased together. For example in Dutch "ij" is a digraph in which both letters should be
+ // capitalized together.
+
+ // TITLECASE_NO_LOWERCASE is necessary so that things that are already capitalized like the
+ // month ("May") are not lower-cased as part of the conversion.
+ return UCharacter.toTitleCase(
+ Locale.getDefault(),
+ dateValue.toString(),
+ BreakIterator.getSentenceInstance(),
+ UCharacter.TITLECASE_NO_LOWERCASE);
+ }
+
+ private static CharSequence formatDuration(Context context, long elapsedSeconds) {
+ long minutes = 0;
+ long seconds = 0;
+
+ if (elapsedSeconds >= 60) {
+ minutes = elapsedSeconds / 60;
+ elapsedSeconds -= minutes * 60;
+ seconds = elapsedSeconds;
+ return context.getString(R.string.call_details_duration_format, minutes, seconds);
+ } else {
+ seconds = elapsedSeconds;
+ return context.getString(R.string.call_details_short_duration_format, seconds);
+ }
+ }
+
+ /**
+ * Formats a string containing the call duration and the data usage (if specified).
+ *
+ * @param elapsedSeconds Total elapsed seconds.
+ * @param dataUsage Data usage in bytes, or null if not specified.
+ * @return String containing call duration and data usage.
+ */
+ public static CharSequence formatDurationAndDataUsage(
+ Context context, long elapsedSeconds, Long dataUsage) {
+ CharSequence duration = formatDuration(context, elapsedSeconds);
+ List<CharSequence> durationItems = new ArrayList<>();
+ if (dataUsage != null) {
+ durationItems.add(duration);
+ durationItems.add(Formatter.formatShortFileSize(context, dataUsage));
+ return DialerUtils.join(durationItems);
+ } else {
+ return duration;
+ }
+ }
+}
diff --git a/java/com/android/dialer/calllogutils/CallTypeHelper.java b/java/com/android/dialer/calllogutils/CallTypeHelper.java
new file mode 100644
index 000000000..d3b5b67d7
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/CallTypeHelper.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.calllogutils;
+
+import android.content.res.Resources;
+import com.android.dialer.compat.AppCompatConstants;
+
+/** Helper class to perform operations related to call types. */
+public class CallTypeHelper {
+
+ /** Name used to identify incoming calls. */
+ private final CharSequence mIncomingName;
+ /** Name used to identify incoming calls which were transferred to another device. */
+ private final CharSequence mIncomingPulledName;
+ /** Name used to identify outgoing calls. */
+ private final CharSequence mOutgoingName;
+ /** Name used to identify outgoing calls which were transferred to another device. */
+ private final CharSequence mOutgoingPulledName;
+ /** Name used to identify missed calls. */
+ private final CharSequence mMissedName;
+ /** Name used to identify incoming video calls. */
+ private final CharSequence mIncomingVideoName;
+ /** Name used to identify incoming video calls which were transferred to another device. */
+ private final CharSequence mIncomingVideoPulledName;
+ /** Name used to identify outgoing video calls. */
+ private final CharSequence mOutgoingVideoName;
+ /** Name used to identify outgoing video calls which were transferred to another device. */
+ private final CharSequence mOutgoingVideoPulledName;
+ /** Name used to identify missed video calls. */
+ private final CharSequence mMissedVideoName;
+ /** Name used to identify voicemail calls. */
+ private final CharSequence mVoicemailName;
+ /** Name used to identify rejected calls. */
+ private final CharSequence mRejectedName;
+ /** Name used to identify blocked calls. */
+ private final CharSequence mBlockedName;
+ /** Name used to identify calls which were answered on another device. */
+ private final CharSequence mAnsweredElsewhereName;
+
+ public CallTypeHelper(Resources resources) {
+ // Cache these values so that we do not need to look them up each time.
+ mIncomingName = resources.getString(R.string.type_incoming);
+ mIncomingPulledName = resources.getString(R.string.type_incoming_pulled);
+ mOutgoingName = resources.getString(R.string.type_outgoing);
+ mOutgoingPulledName = resources.getString(R.string.type_outgoing_pulled);
+ mMissedName = resources.getString(R.string.type_missed);
+ mIncomingVideoName = resources.getString(R.string.type_incoming_video);
+ mIncomingVideoPulledName = resources.getString(R.string.type_incoming_video_pulled);
+ mOutgoingVideoName = resources.getString(R.string.type_outgoing_video);
+ mOutgoingVideoPulledName = resources.getString(R.string.type_outgoing_video_pulled);
+ mMissedVideoName = resources.getString(R.string.type_missed_video);
+ mVoicemailName = resources.getString(R.string.type_voicemail);
+ mRejectedName = resources.getString(R.string.type_rejected);
+ mBlockedName = resources.getString(R.string.type_blocked);
+ mAnsweredElsewhereName = resources.getString(R.string.type_answered_elsewhere);
+ }
+
+ public static boolean isMissedCallType(int callType) {
+ return (callType != AppCompatConstants.CALLS_INCOMING_TYPE
+ && callType != AppCompatConstants.CALLS_OUTGOING_TYPE
+ && callType != AppCompatConstants.CALLS_VOICEMAIL_TYPE
+ && callType != AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE);
+ }
+
+ /** Returns the text used to represent the given call type. */
+ public CharSequence getCallTypeText(int callType, boolean isVideoCall, boolean isPulledCall) {
+ switch (callType) {
+ case AppCompatConstants.CALLS_INCOMING_TYPE:
+ if (isVideoCall) {
+ if (isPulledCall) {
+ return mIncomingVideoPulledName;
+ } else {
+ return mIncomingVideoName;
+ }
+ } else {
+ if (isPulledCall) {
+ return mIncomingPulledName;
+ } else {
+ return mIncomingName;
+ }
+ }
+
+ case AppCompatConstants.CALLS_OUTGOING_TYPE:
+ if (isVideoCall) {
+ if (isPulledCall) {
+ return mOutgoingVideoPulledName;
+ } else {
+ return mOutgoingVideoName;
+ }
+ } else {
+ if (isPulledCall) {
+ return mOutgoingPulledName;
+ } else {
+ return mOutgoingName;
+ }
+ }
+
+ case AppCompatConstants.CALLS_MISSED_TYPE:
+ if (isVideoCall) {
+ return mMissedVideoName;
+ } else {
+ return mMissedName;
+ }
+
+ case AppCompatConstants.CALLS_VOICEMAIL_TYPE:
+ return mVoicemailName;
+
+ case AppCompatConstants.CALLS_REJECTED_TYPE:
+ return mRejectedName;
+
+ case AppCompatConstants.CALLS_BLOCKED_TYPE:
+ return mBlockedName;
+
+ case AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE:
+ return mAnsweredElsewhereName;
+
+ default:
+ return mMissedName;
+ }
+ }
+}
diff --git a/java/com/android/dialer/calllogutils/CallTypeIconsView.java b/java/com/android/dialer/calllogutils/CallTypeIconsView.java
new file mode 100644
index 000000000..61208bc9a
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/CallTypeIconsView.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.calllogutils;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import com.android.contacts.common.util.BitmapUtil;
+import com.android.dialer.compat.AppCompatConstants;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * View that draws one or more symbols for different types of calls (missed calls, outgoing etc).
+ * The symbols are set up horizontally. As this view doesn't create subviews, it is better suited
+ * for ListView-recycling that a regular LinearLayout using ImageViews.
+ */
+public class CallTypeIconsView extends View {
+
+ private static Resources sResources;
+ private List<Integer> mCallTypes = new ArrayList<>(3);
+ private boolean mShowVideo = false;
+ private boolean mShowHd = false;
+ private int mWidth;
+ private int mHeight;
+
+ public CallTypeIconsView(Context context) {
+ this(context, null);
+ }
+
+ public CallTypeIconsView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ if (sResources == null) {
+ sResources = new Resources(context);
+ }
+ }
+
+ public void clear() {
+ mCallTypes.clear();
+ mWidth = 0;
+ mHeight = 0;
+ invalidate();
+ }
+
+ public void add(int callType) {
+ mCallTypes.add(callType);
+
+ final Drawable drawable = getCallTypeDrawable(callType);
+ mWidth += drawable.getIntrinsicWidth() + sResources.iconMargin;
+ mHeight = Math.max(mHeight, drawable.getIntrinsicHeight());
+ invalidate();
+ }
+
+ /**
+ * Determines whether the video call icon will be shown.
+ *
+ * @param showVideo True where the video icon should be shown.
+ */
+ public void setShowVideo(boolean showVideo) {
+ mShowVideo = showVideo;
+ if (showVideo) {
+ mWidth += sResources.videoCall.getIntrinsicWidth();
+ mHeight = Math.max(mHeight, sResources.videoCall.getIntrinsicHeight());
+ invalidate();
+ }
+ }
+
+ /**
+ * Determines if the video icon should be shown.
+ *
+ * @return True if the video icon should be shown.
+ */
+ public boolean isVideoShown() {
+ return mShowVideo;
+ }
+
+ public void setShowHd(boolean showHd) {
+ mShowHd = showHd;
+ if (showHd) {
+ mWidth += sResources.hdCall.getIntrinsicWidth();
+ mHeight = Math.max(mHeight, sResources.hdCall.getIntrinsicHeight());
+ invalidate();
+ }
+ }
+
+ public int getCount() {
+ return mCallTypes.size();
+ }
+
+ public int getCallType(int index) {
+ return mCallTypes.get(index);
+ }
+
+ private Drawable getCallTypeDrawable(int callType) {
+ switch (callType) {
+ case AppCompatConstants.CALLS_INCOMING_TYPE:
+ case AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE:
+ return sResources.incoming;
+ case AppCompatConstants.CALLS_OUTGOING_TYPE:
+ return sResources.outgoing;
+ case AppCompatConstants.CALLS_MISSED_TYPE:
+ return sResources.missed;
+ case AppCompatConstants.CALLS_VOICEMAIL_TYPE:
+ return sResources.voicemail;
+ case AppCompatConstants.CALLS_BLOCKED_TYPE:
+ return sResources.blocked;
+ default:
+ // It is possible for users to end up with calls with unknown call types in their
+ // call history, possibly due to 3rd party call log implementations (e.g. to
+ // distinguish between rejected and missed calls). Instead of crashing, just
+ // assume that all unknown call types are missed calls.
+ return sResources.missed;
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(mWidth, mHeight);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int left = 0;
+ for (Integer callType : mCallTypes) {
+ final Drawable drawable = getCallTypeDrawable(callType);
+ final int right = left + drawable.getIntrinsicWidth();
+ drawable.setBounds(left, 0, right, drawable.getIntrinsicHeight());
+ drawable.draw(canvas);
+ left = right + sResources.iconMargin;
+ }
+
+ // If showing the video call icon, draw it scaled appropriately.
+ if (mShowVideo) {
+ final Drawable drawable = sResources.videoCall;
+ final int right = left + sResources.videoCall.getIntrinsicWidth();
+ drawable.setBounds(left, 0, right, sResources.videoCall.getIntrinsicHeight());
+ drawable.draw(canvas);
+ }
+ // If showing HD call icon, draw it scaled appropriately.
+ if (mShowHd) {
+ final Drawable drawable = sResources.hdCall;
+ final int right = left + sResources.hdCall.getIntrinsicWidth();
+ drawable.setBounds(left, 0, right, sResources.hdCall.getIntrinsicHeight());
+ drawable.draw(canvas);
+ }
+ }
+
+ private static class Resources {
+
+ // Drawable representing an incoming answered call.
+ public final Drawable incoming;
+
+ // Drawable respresenting an outgoing call.
+ public final Drawable outgoing;
+
+ // Drawable representing an incoming missed call.
+ public final Drawable missed;
+
+ // Drawable representing a voicemail.
+ public final Drawable voicemail;
+
+ // Drawable representing a blocked call.
+ public final Drawable blocked;
+
+ // Drawable repesenting a video call.
+ public final Drawable videoCall;
+
+ // Drawable represeting a hd call.
+ public final Drawable hdCall;
+
+ /** The margin to use for icons. */
+ public final int iconMargin;
+
+ /**
+ * Configures the call icon drawables. A single white call arrow which points down and left is
+ * used as a basis for all of the call arrow icons, applying rotation and colors as needed.
+ *
+ * @param context The current context.
+ */
+ public Resources(Context context) {
+ final android.content.res.Resources r = context.getResources();
+
+ incoming = r.getDrawable(R.drawable.ic_call_arrow);
+ incoming.setColorFilter(r.getColor(R.color.answered_call), PorterDuff.Mode.MULTIPLY);
+
+ // Create a rotated instance of the call arrow for outgoing calls.
+ outgoing = BitmapUtil.getRotatedDrawable(r, R.drawable.ic_call_arrow, 180f);
+ outgoing.setColorFilter(r.getColor(R.color.answered_call), PorterDuff.Mode.MULTIPLY);
+
+ // Need to make a copy of the arrow drawable, otherwise the same instance colored
+ // above will be recolored here.
+ missed = r.getDrawable(R.drawable.ic_call_arrow).mutate();
+ missed.setColorFilter(r.getColor(R.color.missed_call), PorterDuff.Mode.MULTIPLY);
+
+ voicemail = r.getDrawable(R.drawable.quantum_ic_voicemail_white_18);
+ voicemail.setColorFilter(
+ r.getColor(R.color.dialer_secondary_text_color), PorterDuff.Mode.MULTIPLY);
+
+ blocked = getScaledBitmap(context, R.drawable.ic_block_24dp);
+ blocked.setColorFilter(r.getColor(R.color.blocked_call), PorterDuff.Mode.MULTIPLY);
+
+ videoCall = getScaledBitmap(context, R.drawable.quantum_ic_videocam_white_24);
+ videoCall.setColorFilter(
+ r.getColor(R.color.dialer_secondary_text_color), PorterDuff.Mode.MULTIPLY);
+
+ hdCall = getScaledBitmap(context, R.drawable.quantum_ic_hd_white_24);
+ hdCall.setColorFilter(
+ r.getColor(R.color.dialer_secondary_text_color), PorterDuff.Mode.MULTIPLY);
+
+ iconMargin = r.getDimensionPixelSize(R.dimen.call_log_icon_margin);
+ }
+
+ // Gets the icon, scaled to the height of the call type icons. This helps display all the
+ // icons to be the same height, while preserving their width aspect ratio.
+ private Drawable getScaledBitmap(Context context, int resourceId) {
+ Bitmap icon = BitmapFactory.decodeResource(context.getResources(), resourceId);
+ int scaledHeight = context.getResources().getDimensionPixelSize(R.dimen.call_type_icon_size);
+ int scaledWidth =
+ (int) ((float) icon.getWidth() * ((float) scaledHeight / (float) icon.getHeight()));
+ Bitmap scaledIcon = Bitmap.createScaledBitmap(icon, scaledWidth, scaledHeight, false);
+ return new BitmapDrawable(context.getResources(), scaledIcon);
+ }
+ }
+}
diff --git a/java/com/android/dialer/calllogutils/PhoneAccountUtils.java b/java/com/android/dialer/calllogutils/PhoneAccountUtils.java
new file mode 100644
index 000000000..c639893ef
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/PhoneAccountUtils.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.calllogutils;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.text.TextUtils;
+import com.android.dialer.telecom.TelecomUtil;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Methods to help extract {@code PhoneAccount} information from database and Telecomm sources. */
+public class PhoneAccountUtils {
+
+ /** Return a list of phone accounts that are subscription/SIM accounts. */
+ public static List<PhoneAccountHandle> getSubscriptionPhoneAccounts(Context context) {
+ List<PhoneAccountHandle> subscriptionAccountHandles = new ArrayList<PhoneAccountHandle>();
+ final List<PhoneAccountHandle> accountHandles =
+ TelecomUtil.getCallCapablePhoneAccounts(context);
+ for (PhoneAccountHandle accountHandle : accountHandles) {
+ PhoneAccount account = TelecomUtil.getPhoneAccount(context, accountHandle);
+ if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+ subscriptionAccountHandles.add(accountHandle);
+ }
+ }
+ return subscriptionAccountHandles;
+ }
+
+ /** Compose PhoneAccount object from component name and account id. */
+ @Nullable
+ public static PhoneAccountHandle getAccount(
+ @Nullable String componentString, @Nullable String accountId) {
+ if (TextUtils.isEmpty(componentString) || TextUtils.isEmpty(accountId)) {
+ return null;
+ }
+ final ComponentName componentName = ComponentName.unflattenFromString(componentString);
+ if (componentName == null) {
+ return null;
+ }
+ return new PhoneAccountHandle(componentName, accountId);
+ }
+
+ /** Extract account label from PhoneAccount object. */
+ @Nullable
+ public static String getAccountLabel(
+ Context context, @Nullable PhoneAccountHandle accountHandle) {
+ PhoneAccount account = getAccountOrNull(context, accountHandle);
+ if (account != null && account.getLabel() != null) {
+ return account.getLabel().toString();
+ }
+ return null;
+ }
+
+ /** Extract account color from PhoneAccount object. */
+ public static int getAccountColor(Context context, @Nullable PhoneAccountHandle accountHandle) {
+ final PhoneAccount account = TelecomUtil.getPhoneAccount(context, accountHandle);
+
+ // For single-sim devices the PhoneAccount will be NO_HIGHLIGHT_COLOR by default, so it is
+ // safe to always use the account highlight color.
+ return account == null ? PhoneAccount.NO_HIGHLIGHT_COLOR : account.getHighlightColor();
+ }
+
+ /**
+ * Determine whether a phone account supports call subjects.
+ *
+ * @return {@code true} if call subjects are supported, {@code false} otherwise.
+ */
+ public static boolean getAccountSupportsCallSubject(
+ Context context, @Nullable PhoneAccountHandle accountHandle) {
+ final PhoneAccount account = TelecomUtil.getPhoneAccount(context, accountHandle);
+
+ return account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT);
+ }
+
+ /**
+ * Retrieve the account metadata, but if the account does not exist or the device has only a
+ * single registered and enabled account, return null.
+ */
+ @Nullable
+ private static PhoneAccount getAccountOrNull(
+ Context context, @Nullable PhoneAccountHandle accountHandle) {
+ if (TelecomUtil.getCallCapablePhoneAccounts(context).size() <= 1) {
+ return null;
+ }
+ return TelecomUtil.getPhoneAccount(context, accountHandle);
+ }
+}
diff --git a/java/com/android/dialer/calllogutils/PhoneCallDetails.java b/java/com/android/dialer/calllogutils/PhoneCallDetails.java
new file mode 100644
index 000000000..ba05a87e2
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/PhoneCallDetails.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.calllogutils;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.provider.CallLog;
+import android.provider.CallLog.Calls;
+import android.support.annotation.Nullable;
+import android.telecom.PhoneAccountHandle;
+import android.text.TextUtils;
+import com.android.contacts.common.ContactsUtils.UserType;
+import com.android.contacts.common.preference.ContactsPreferences;
+import com.android.contacts.common.util.ContactDisplayUtils;
+import com.android.dialer.phonenumbercache.ContactInfo;
+
+/** The details of a phone call to be shown in the UI. */
+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 secondary line number the call was received via.
+ public String viaNumber;
+ // The number presenting rules set by the network, e.g., {@link Calls#PRESENTATION_ALLOWED}
+ public int numberPresentation;
+ // The country corresponding with the phone number.
+ public String countryIso;
+ // The geocoded location for the phone number.
+ public String geocode;
+
+ /**
+ * The type of calls, as defined in the call log table, e.g., {@link Calls#INCOMING_TYPE}.
+ *
+ * <p>There might be multiple types if this represents a set of entries grouped together.
+ */
+ public int[] callTypes;
+
+ // The date of the call, in milliseconds since the epoch.
+ public long date;
+ // The duration of the call in milliseconds, or 0 for missed calls.
+ public long duration;
+ // The name of the contact, or the empty string.
+ public CharSequence namePrimary;
+ // The alternative name of the contact, e.g. last name first, or the empty string
+ public CharSequence nameAlternative;
+ /**
+ * The user's preference on name display order, last name first or first time first. {@see
+ * ContactsPreferences}
+ */
+ public int nameDisplayOrder;
+ // The type of phone, e.g., {@link Phone#TYPE_HOME}, 0 if not available.
+ public int numberType;
+ // The custom label associated with the phone number in the contact, or the empty string.
+ public CharSequence numberLabel;
+ // The URI of the contact associated with this phone call.
+ public Uri contactUri;
+
+ /**
+ * The photo URI of the picture of the contact that is associated with this phone call or null if
+ * there is none.
+ *
+ * <p>This is meant to store the high-res photo only.
+ */
+ public Uri photoUri;
+
+ // The source type of the contact associated with this call.
+ public int sourceType;
+
+ // The object id type of the contact associated with this call.
+ public String objectId;
+
+ // The unique identifier for the account associated with the call.
+ public PhoneAccountHandle accountHandle;
+
+ // Features applicable to this call.
+ public int features;
+
+ // Total data usage for this call.
+ public Long dataUsage;
+
+ // Voicemail transcription
+ public String transcription;
+
+ // The display string for the number.
+ public String displayNumber;
+
+ // Whether the contact number is a voicemail number.
+ public boolean isVoicemail;
+
+ /** The {@link UserType} of the contact */
+ public @UserType long contactUserType;
+
+ /**
+ * If this is a voicemail, whether the message is read. For other types of calls, this defaults to
+ * {@code true}.
+ */
+ public boolean isRead = true;
+
+ // If this call is a spam number.
+ public boolean isSpam = false;
+
+ // If this call is a blocked number.
+ public boolean isBlocked = false;
+
+ // Call location and date text.
+ public CharSequence callLocationAndDate;
+
+ // Call description.
+ public CharSequence callDescription;
+ public String accountComponentName;
+ public String accountId;
+ public ContactInfo cachedContactInfo;
+ public int voicemailId;
+ public int previousGroup;
+
+ /**
+ * Constructor with required fields for the details of a call with a number associated with a
+ * contact.
+ */
+ public PhoneCallDetails(
+ CharSequence number, int numberPresentation, CharSequence postDialDigits) {
+ this.number = number;
+ this.numberPresentation = numberPresentation;
+ this.postDialDigits = postDialDigits.toString();
+ }
+ /**
+ * Construct the "on {accountLabel} via {viaNumber}" accessibility description for the account
+ * list item, depending on the existence of the accountLabel and viaNumber.
+ *
+ * @param viaNumber The number that this call is being placed via.
+ * @param accountLabel The {@link PhoneAccount} label that this call is being placed with.
+ * @return The description of the account that this call has been placed on.
+ */
+ public static CharSequence createAccountLabelDescription(
+ Resources resources, @Nullable String viaNumber, @Nullable CharSequence accountLabel) {
+
+ if ((!TextUtils.isEmpty(viaNumber)) && !TextUtils.isEmpty(accountLabel)) {
+ String msg =
+ resources.getString(
+ R.string.description_via_number_phone_account, accountLabel, viaNumber);
+ CharSequence accountNumberLabel =
+ ContactDisplayUtils.getTelephoneTtsSpannable(msg, viaNumber);
+ return (accountNumberLabel == null) ? msg : accountNumberLabel;
+ } else if (!TextUtils.isEmpty(viaNumber)) {
+ CharSequence viaNumberLabel =
+ ContactDisplayUtils.getTtsSpannedPhoneNumber(
+ resources, R.string.description_via_number, viaNumber);
+ return (viaNumberLabel == null) ? viaNumber : viaNumberLabel;
+ } else if (!TextUtils.isEmpty(accountLabel)) {
+ return TextUtils.expandTemplate(
+ resources.getString(R.string.description_phone_account), accountLabel);
+ }
+ return "";
+ }
+
+ /**
+ * Returns the preferred name for the call details as specified by the {@link #nameDisplayOrder}
+ *
+ * @return the preferred name
+ */
+ public CharSequence getPreferredName() {
+ if (nameDisplayOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY
+ || TextUtils.isEmpty(nameAlternative)) {
+ return namePrimary;
+ }
+ return nameAlternative;
+ }
+
+ public void updateDisplayNumber(
+ Context context, CharSequence formattedNumber, boolean isVoicemail) {
+ displayNumber =
+ PhoneNumberDisplayUtil.getDisplayNumber(
+ context, number, numberPresentation, formattedNumber, postDialDigits, isVoicemail)
+ .toString();
+ }
+
+ public boolean hasIncomingCalls() {
+ for (int i = 0; i < callTypes.length; i++) {
+ if (callTypes[i] == CallLog.Calls.INCOMING_TYPE
+ || callTypes[i] == CallLog.Calls.MISSED_TYPE
+ || callTypes[i] == CallLog.Calls.VOICEMAIL_TYPE
+ || callTypes[i] == CallLog.Calls.REJECTED_TYPE
+ || callTypes[i] == CallLog.Calls.BLOCKED_TYPE) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java b/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java
new file mode 100644
index 000000000..9bebfacac
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.calllogutils;
+
+import android.content.Context;
+import android.provider.CallLog.Calls;
+import android.text.BidiFormatter;
+import android.text.TextDirectionHeuristics;
+import android.text.TextUtils;
+import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
+
+/** Helper for formatting and managing the display of phone numbers. */
+public class PhoneNumberDisplayUtil {
+
+ /** Returns the string to display for the given phone number if there is no matching contact. */
+ public static CharSequence getDisplayName(
+ Context context, CharSequence number, int presentation, boolean isVoicemail) {
+ if (presentation == Calls.PRESENTATION_UNKNOWN) {
+ return context.getResources().getString(R.string.unknown);
+ }
+ if (presentation == Calls.PRESENTATION_RESTRICTED) {
+ return PhoneNumberHelper.getDisplayNameForRestrictedNumber(context);
+ }
+ if (presentation == Calls.PRESENTATION_PAYPHONE) {
+ return context.getResources().getString(R.string.payphone);
+ }
+ if (isVoicemail) {
+ return context.getResources().getString(R.string.voicemail_string);
+ }
+ if (PhoneNumberHelper.isLegacyUnknownNumbers(number)) {
+ return context.getResources().getString(R.string.unknown);
+ }
+ return "";
+ }
+
+ /**
+ * Returns the string to display for the given phone number.
+ *
+ * @param number the number to display
+ * @param formattedNumber the formatted number if available, may be null
+ */
+ public static CharSequence getDisplayNumber(
+ Context context,
+ CharSequence number,
+ int presentation,
+ CharSequence formattedNumber,
+ CharSequence postDialDigits,
+ boolean isVoicemail) {
+ final CharSequence displayName = getDisplayName(context, number, presentation, isVoicemail);
+ if (!TextUtils.isEmpty(displayName)) {
+ return getTtsSpannableLtrNumber(displayName);
+ }
+
+ if (!TextUtils.isEmpty(formattedNumber)) {
+ return getTtsSpannableLtrNumber(formattedNumber);
+ } else if (!TextUtils.isEmpty(number)) {
+ return getTtsSpannableLtrNumber(number.toString() + postDialDigits);
+ } else {
+ return context.getResources().getString(R.string.unknown);
+ }
+ }
+
+ /** Returns number annotated as phone number in LTR direction. */
+ public static CharSequence getTtsSpannableLtrNumber(CharSequence number) {
+ return PhoneNumberUtilsCompat.createTtsSpannable(
+ BidiFormatter.getInstance().unicodeWrap(number.toString(), TextDirectionHeuristics.LTR));
+ }
+}
diff --git a/java/com/android/dialer/calllogutils/res/values/colors.xml b/java/com/android/dialer/calllogutils/res/values/colors.xml
new file mode 100644
index 000000000..dc4ec2493
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/res/values/colors.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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
+ -->
+<resources>
+ <!-- Color for missed call icons. -->
+ <color name="missed_call">#ff2e58</color>
+ <!-- Color for answered or outgoing call icons. -->
+ <color name="answered_call">#00c853</color>
+ <!-- Color for blocked call icons. -->
+ <color name="blocked_call">@color/dialer_secondary_text_color</color>
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/calllogutils/res/values/dimens.xml b/java/com/android/dialer/calllogutils/res/values/dimens.xml
new file mode 100644
index 000000000..0935ac188
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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
+ -->
+<resources>
+ <dimen name="call_type_icon_size">12dp</dimen>
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/calllogutils/res/values/strings.xml b/java/com/android/dialer/calllogutils/res/values/strings.xml
new file mode 100644
index 000000000..6a6f10113
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/res/values/strings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Title for incoming call type. [CHAR LIMIT=40] -->
+ <string name="type_incoming">Incoming call</string>
+
+ <!-- Title for incoming call which was transferred to another device. [CHAR LIMIT=60] -->
+ <string name="type_incoming_pulled">Incoming call transferred to another device</string>
+
+ <!-- Title for outgoing call type. [CHAR LIMIT=40] -->
+ <string name="type_outgoing">Outgoing call</string>
+
+ <!-- Title for outgoing call which was transferred to another device. [CHAR LIMIT=60] -->
+ <string name="type_outgoing_pulled">Outgoing call transferred to another device</string>
+
+ <!-- Title for missed call type. [CHAR LIMIT=40] -->
+ <string name="type_missed">Missed call</string>
+
+ <!-- Title for incoming video call in call details screen [CHAR LIMIT=60] -->
+ <string name="type_incoming_video">Incoming video call</string>
+
+ <!-- Title for incoming video call in call details screen which was transferred to another device.
+ [CHAR LIMIT=60] -->
+ <string name="type_incoming_video_pulled">Incoming video call transferred to another device</string>
+
+ <!-- Title for outgoing video call in call details screen [CHAR LIMIT=60] -->
+ <string name="type_outgoing_video">Outgoing video call</string>
+
+ <!-- Title for outgoing video call in call details screen which was transferred to another device.
+ [CHAR LIMIT=60] -->
+ <string name="type_outgoing_video_pulled">Outgoing video call transferred to another device</string>
+
+ <!-- Title for missed video call in call details screen [CHAR LIMIT=60] -->
+ <string name="type_missed_video">Missed video call</string>
+
+ <!-- Title for voicemail details screen -->
+ <string name="type_voicemail">Voicemail</string>
+
+ <!-- Title for rejected call type. [CHAR LIMIT=40] -->
+ <string name="type_rejected">Declined call</string>
+
+ <!-- Title for blocked call type. [CHAR LIMIT=40] -->
+ <string name="type_blocked">Blocked call</string>
+
+ <!-- Title for "answered elsewhere" call type. This will happen if a call was ringing
+ simultaneously on multiple devices, and the user answered it on a device other than the
+ current device. [CHAR LIMIT=60] -->
+ <string name="type_answered_elsewhere">Call answered on another device</string>
+
+ <!-- String describing the phone account the call was made on or to. This string will be used
+ in description_incoming_missed_call, description_incoming_answered_call, and
+ description_outgoing_call.
+ Note: AccessibilityServices uses this attribute to announce what the view represents.
+ [CHAR LIMIT=NONE] -->
+ <string name="description_phone_account">on <xliff:g example="SIM 1" id="phoneAccount">^1</xliff:g></string>
+
+ <!-- String describing the secondary line number the call was received via.
+ Note: AccessibilityServices use this attribute to announce what the view represents.
+ [CHAR LIMIT=NONE]-->
+ <string name="description_via_number">via <xliff:g example="(555) 555-5555" id="number">%1$s</xliff:g></string>
+
+ <!-- String describing the PhoneAccount and via number that a call was received on, if both are
+ visible.
+ Note: AccessibilityServices use this attribute to announce what the view represents.
+ [CHAR LIMIT=NONE]-->
+ <string name="description_via_number_phone_account">on <xliff:g example="SIM 1" id="phoneAccount">%1$s</xliff:g>, via <xliff:g example="(555) 555-5555" id="number">%2$s</xliff:g></string>
+
+ <!-- String used for displaying calls to the voicemail number in the call log -->
+ <string name="voicemail_string">Voicemail</string>
+
+ <!-- A nicely formatted call duration displayed when viewing call details. For example "42 min 28 sec" -->
+ <string name="call_details_duration_format"><xliff:g example="42" id="minutes">%s</xliff:g> min <xliff:g example="28" id="seconds">%s</xliff:g> sec</string>
+
+ <!-- A nicely formatted call duration displayed when viewing call details for duration less than 1 minute. For example "28 sec" -->
+ <string name="call_details_short_duration_format"><xliff:g example="28" id="seconds">%s</xliff:g> sec</string>
+</resources> \ No newline at end of file