From d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9 Mon Sep 17 00:00:00 2001 From: Eric Erfanian Date: Wed, 15 Mar 2017 14:41:07 -0700 Subject: Update Dialer source from latest green build. * Refactor voicemail component * Add new enriched calling components Test: treehugger, manual aosp testing Change-Id: I521a0f86327d4b42e14d93927c7d613044ed5942 --- .../dialer/calllogutils/AndroidManifest.xml | 16 ++ .../dialer/calllogutils/CallEntryFormatter.java | 113 ++++++++++ .../dialer/calllogutils/CallTypeHelper.java | 135 ++++++++++++ .../dialer/calllogutils/CallTypeIconsView.java | 244 +++++++++++++++++++++ .../dialer/calllogutils/PhoneAccountUtils.java | 104 +++++++++ .../dialer/calllogutils/PhoneCallDetails.java | 206 +++++++++++++++++ .../calllogutils/PhoneNumberDisplayUtil.java | 83 +++++++ .../dialer/calllogutils/res/values/colors.xml | 24 ++ .../dialer/calllogutils/res/values/dimens.xml | 19 ++ .../dialer/calllogutils/res/values/strings.xml | 90 ++++++++ 10 files changed, 1034 insertions(+) create mode 100644 java/com/android/dialer/calllogutils/AndroidManifest.xml create mode 100644 java/com/android/dialer/calllogutils/CallEntryFormatter.java create mode 100644 java/com/android/dialer/calllogutils/CallTypeHelper.java create mode 100644 java/com/android/dialer/calllogutils/CallTypeIconsView.java create mode 100644 java/com/android/dialer/calllogutils/PhoneAccountUtils.java create mode 100644 java/com/android/dialer/calllogutils/PhoneCallDetails.java create mode 100644 java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java create mode 100644 java/com/android/dialer/calllogutils/res/values/colors.xml create mode 100644 java/com/android/dialer/calllogutils/res/values/dimens.xml create mode 100644 java/com/android/dialer/calllogutils/res/values/strings.xml (limited to 'java/com/android/dialer/calllogutils') 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 @@ + + \ 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. + * + *

For example, returns a string like "Wednesday, May 25, 2016, 8:02PM" or "Chorshanba, 2016 + * may 25,20:02". + * + *

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 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 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 getSubscriptionPhoneAccounts(Context context) { + List subscriptionAccountHandles = new ArrayList(); + final List 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}. + * + *

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. + * + *

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 @@ + + + + + #ff2e58 + + #00c853 + + @color/dialer_secondary_text_color + \ 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 @@ + + + + 12dp + \ 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 @@ + + + + + Incoming call + + + Incoming call transferred to another device + + + Outgoing call + + + Outgoing call transferred to another device + + + Missed call + + + Incoming video call + + + Incoming video call transferred to another device + + + Outgoing video call + + + Outgoing video call transferred to another device + + + Missed video call + + + Voicemail + + + Declined call + + + Blocked call + + + Call answered on another device + + + on ^1 + + + via %1$s + + + on %1$s, via %2$s + + + Voicemail + + + %s min %s sec + + + %s sec + \ No newline at end of file -- cgit v1.2.3