From 45e4573bb6ab234d57a921a73095fd18e453e261 Mon Sep 17 00:00:00 2001 From: yueg Date: Mon, 9 Oct 2017 14:35:06 -0700 Subject: Show "Incoming video call" instead of "Incoming call" for ViLTE notification. Test: StatusBarNotifierTest PiperOrigin-RevId: 171588023 Change-Id: I05e176ef1032da00c4b75a83e92f39e8293d598e --- java/com/android/incallui/StatusBarNotifier.java | 2 ++ java/com/android/incallui/res/values/strings.xml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/java/com/android/incallui/StatusBarNotifier.java b/java/com/android/incallui/StatusBarNotifier.java index 6ddba1613..7146c7235 100644 --- a/java/com/android/incallui/StatusBarNotifier.java +++ b/java/com/android/incallui/StatusBarNotifier.java @@ -711,6 +711,8 @@ public class StatusBarNotifier resId = R.string.notification_incoming_call_wifi_template; } else if (call.getAccountHandle() != null && hasMultiplePhoneAccounts()) { return getMultiSimIncomingText(call); + } else if (call.isVideoCall()) { + resId = R.string.notification_incoming_video_call; } else { resId = R.string.notification_incoming_call; } diff --git a/java/com/android/incallui/res/values/strings.xml b/java/com/android/incallui/res/values/strings.xml index afadbf828..2f1542a08 100644 --- a/java/com/android/incallui/res/values/strings.xml +++ b/java/com/android/incallui/res/values/strings.xml @@ -65,6 +65,8 @@ On hold Incoming call + + Incoming video call Incoming call via %1$s -- cgit v1.2.3 From 04ac93d3c9d2f3f4c157bfa1d23d225aa34db9df Mon Sep 17 00:00:00 2001 From: erfanian Date: Mon, 9 Oct 2017 15:12:22 -0700 Subject: Add assisted dialing to outbound calls that qualify. * Add missing assisted dialing to calls from contacts in the call log. * Add missing assisted dialing to calls from dialpad and normal search. Bug: 63995025,63995261 Test: unit test PiperOrigin-RevId: 171593967 Change-Id: I4e63ef1dcd7ee1b2b5cbb8ecb4d8da744d90bd66 --- java/com/android/dialer/app/DialtactsActivity.java | 19 +++--- .../app/calllog/CallLogListItemViewHolder.java | 34 ++++++----- .../android/dialer/app/calllog/IntentProvider.java | 15 +++++ .../assisteddialing/AssistedDialingMediator.java | 57 +----------------- .../AssistedDialingMediatorImpl.java | 70 ++++++++++++++++++++++ .../AssistedDialingMediatorStub.java | 34 +++++++++++ .../dialer/assisteddialing/ConcreteCreator.java | 16 ++++- .../dialer/assisteddialing/Constraints.java | 26 ++++++-- .../dialer/assisteddialing/TransformationInfo.java | 10 ++-- .../dialer/callintent/CallIntentBuilder.java | 41 +++++++++++-- .../compat/telephony/TelephonyManagerCompat.java | 5 ++ .../interactions/PhoneNumberInteraction.java | 8 ++- .../dialer/searchfragment/list/SearchAdapter.java | 19 ++++-- 13 files changed, 253 insertions(+), 101 deletions(-) create mode 100644 java/com/android/dialer/assisteddialing/AssistedDialingMediatorImpl.java create mode 100644 java/com/android/dialer/assisteddialing/AssistedDialingMediatorStub.java diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java index 04f1431e4..5f3620b1c 100644 --- a/java/com/android/dialer/app/DialtactsActivity.java +++ b/java/com/android/dialer/app/DialtactsActivity.java @@ -43,7 +43,7 @@ import android.support.v4.app.ActivityCompat; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; import android.telecom.PhoneAccount; -import android.telecom.TelecomManager; +import android.telephony.TelephonyManager; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; @@ -90,6 +90,7 @@ import com.android.dialer.app.list.SmartDialSearchFragment; import com.android.dialer.app.settings.DialerSettingsActivity; import com.android.dialer.app.widget.ActionBarController; import com.android.dialer.app.widget.SearchEditTextLayout; +import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.callcomposer.CallComposerActivity; import com.android.dialer.calldetails.CallDetailsActivity; import com.android.dialer.callintent.CallInitiationType; @@ -97,7 +98,6 @@ import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.callintent.CallSpecificAppData; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; -import com.android.dialer.compat.telephony.TelephonyManagerCompat; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.contactsfragment.ContactsFragment; @@ -1488,13 +1488,14 @@ public class DialtactsActivity extends TransactionSafeActivity } Intent intent = - new CallIntentBuilder(phoneNumber, callSpecificAppData).setIsVideoCall(isVideoCall).build(); - - if (callSpecificAppData.getAllowAssistedDialing()) { - Bundle extras = new Bundle(); - extras.putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true); - intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras); - } + new CallIntentBuilder(phoneNumber, callSpecificAppData) + .setIsVideoCall(isVideoCall) + .setAllowAssistedDial( + callSpecificAppData.getAllowAssistedDialing(), + ConcreteCreator.createNewAssistedDialingMediator( + getApplication().getSystemService(TelephonyManager.class), + getApplicationContext())) + .build(); DialerUtils.startActivityWithErrorToast(this, intent); mClearSearchOnPause = true; diff --git a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java index 60acb55fc..f0eee112b 100644 --- a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java +++ b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java @@ -23,7 +23,6 @@ import android.content.Intent; import android.content.res.Resources; import android.net.Uri; import android.os.AsyncTask; -import android.os.Bundle; import android.provider.CallLog; import android.provider.CallLog.Calls; import android.provider.ContactsContract.CommonDataKinds.Phone; @@ -38,6 +37,7 @@ import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telecom.VideoProfile; import android.telephony.PhoneNumberUtils; +import android.telephony.TelephonyManager; import android.text.BidiFormatter; import android.text.TextDirectionHeuristics; import android.text.TextUtils; @@ -69,7 +69,6 @@ import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.CompatUtils; -import com.android.dialer.compat.telephony.TelephonyManagerCompat; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.contactphoto.ContactPhotoManager; @@ -532,8 +531,16 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder // Call to generic voicemail number, in case there are multiple accounts. primaryActionButtonView.setTag(IntentProvider.getReturnVoicemailCallIntentProvider()); } else { - primaryActionButtonView.setTag( - IntentProvider.getReturnCallIntentProvider(number + postDialDigits)); + if (this.info != null && this.info.lookupKey != null) { + primaryActionButtonView.setTag( + IntentProvider.getAssistedDialIntentProvider( + number + postDialDigits, + mContext, + mContext.getSystemService(TelephonyManager.class))); + } else { + primaryActionButtonView.setTag( + IntentProvider.getReturnCallIntentProvider(number + postDialDigits)); + } } primaryActionButtonView.setContentDescription( @@ -592,8 +599,14 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder ((TextView) callButtonView.findViewById(R.id.call_type_or_location_text)); if (canPlaceCallToNumber) { - callButtonView.setTag(IntentProvider.getReturnCallIntentProvider(number)); - callTypeOrLocationView.setVisibility(View.GONE); + if (this.info != null && this.info.lookupKey != null) { + callButtonView.setTag( + IntentProvider.getAssistedDialIntentProvider( + number, mContext, mContext.getSystemService(TelephonyManager.class))); + } else { + callButtonView.setTag(IntentProvider.getReturnCallIntentProvider(number)); + callTypeOrLocationView.setVisibility(View.GONE); + } } if (!TextUtils.isEmpty(voicemailUri) && canPlaceCallToNumber) { @@ -911,15 +924,6 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder return; } - if (info != null && info.lookupKey != null) { - Bundle extras = new Bundle(); - if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) { - extras = intent.getParcelableExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS); - } - extras.putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true); - intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras); - } - // We check to see if we are starting a Lightbringer intent. The reason is Lightbringer // intents need to be started using startActivityForResult instead of the usual startActivity String packageName = intent.getPackage(); diff --git a/java/com/android/dialer/app/calllog/IntentProvider.java b/java/com/android/dialer/app/calllog/IntentProvider.java index 55fdbbace..52a7b0faf 100644 --- a/java/com/android/dialer/app/calllog/IntentProvider.java +++ b/java/com/android/dialer/app/calllog/IntentProvider.java @@ -22,8 +22,10 @@ import android.content.Intent; import android.net.Uri; import android.provider.ContactsContract; import android.telecom.PhoneAccountHandle; +import android.telephony.TelephonyManager; import com.android.contacts.common.model.Contact; import com.android.contacts.common.model.ContactLoader; +import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.calldetails.CallDetailsActivity; import com.android.dialer.calldetails.CallDetailsEntries; import com.android.dialer.callintent.CallInitiationType; @@ -59,6 +61,19 @@ public abstract class IntentProvider { }; } + public static IntentProvider getAssistedDialIntentProvider( + final String number, final Context context, final TelephonyManager telephonyManager) { + return new IntentProvider() { + @Override + public Intent getIntent(Context context) { + return new CallIntentBuilder(number, CallInitiationType.Type.CALL_LOG) + .setAllowAssistedDial( + true, ConcreteCreator.createNewAssistedDialingMediator(telephonyManager, context)) + .build(); + } + }; + } + public static IntentProvider getReturnVideoCallIntentProvider(final String number) { return getReturnVideoCallIntentProvider(number, null); } diff --git a/java/com/android/dialer/assisteddialing/AssistedDialingMediator.java b/java/com/android/dialer/assisteddialing/AssistedDialingMediator.java index 3d027296c..4dc87a772 100644 --- a/java/com/android/dialer/assisteddialing/AssistedDialingMediator.java +++ b/java/com/android/dialer/assisteddialing/AssistedDialingMediator.java @@ -19,63 +19,12 @@ package com.android.dialer.assisteddialing; import android.annotation.TargetApi; import android.os.Build.VERSION_CODES; import android.support.annotation.NonNull; -import com.android.dialer.common.LogUtil; import java.util.Optional; -/** - * The Mediator for Assisted Dialing. - * - *

This class is responsible for mediating location discovery of the user, determining if the - * call is eligible for assisted dialing, and performing the transformation of numbers eligible for - * assisted dialing. - */ -public final class AssistedDialingMediator { - - private final LocationDetector locationDetector; - private final NumberTransformer numberTransformer; - - protected AssistedDialingMediator( - @NonNull LocationDetector locationDetector, @NonNull NumberTransformer numberTransformer) { - if (locationDetector == null) { - throw new NullPointerException("locationDetector was null"); - } +/** The core interface for the AssistedDialingMediator. */ +public interface AssistedDialingMediator { - if (numberTransformer == null) { - throw new NullPointerException("numberTransformer was null"); - } - this.locationDetector = locationDetector; - this.numberTransformer = numberTransformer; - } - - /** - * Returns a boolean for callers to quickly determine whether or not the AssistedDialingMediator - * thinks an attempt at assisted dialing is likely to succeed. - */ - public boolean conditionsEligibleForAssistedDialing( - @NonNull String numberToCheck, - @NonNull String userHomeCountryCode, - @NonNull String userRoamingCountryCode) { - return numberTransformer.canDoAssistedDialingTransformation( - numberToCheck, userHomeCountryCode, userRoamingCountryCode); - } - - /** - * Returns an Optional of type String containing the transformed number that was provided. The - * transformed number should be capable of dialing out of the User's current country and - * successfully connecting with a contact in the User's home country. - */ @SuppressWarnings("AndroidApiChecker") // Use of optional @TargetApi(VERSION_CODES.N) - public Optional attemptAssistedDial(@NonNull String numberToTransform) { - Optional userHomeCountryCode = locationDetector.getUpperCaseUserHomeCountry(); - Optional userRoamingCountryCode = locationDetector.getUpperCaseUserRoamingCountry(); - - if (!userHomeCountryCode.isPresent() || !userRoamingCountryCode.isPresent()) { - LogUtil.i("AssistedDialingMediator.attemptAssistedDial", "Unable to determine country codes"); - return Optional.empty(); - } - - return numberTransformer.doAssistedDialingTransformation( - numberToTransform, userHomeCountryCode.get(), userRoamingCountryCode.get()); - } + public Optional attemptAssistedDial(@NonNull String numberToTransform); } diff --git a/java/com/android/dialer/assisteddialing/AssistedDialingMediatorImpl.java b/java/com/android/dialer/assisteddialing/AssistedDialingMediatorImpl.java new file mode 100644 index 000000000..1692614bb --- /dev/null +++ b/java/com/android/dialer/assisteddialing/AssistedDialingMediatorImpl.java @@ -0,0 +1,70 @@ +/* + * 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.assisteddialing; + +import android.annotation.TargetApi; +import android.os.Build.VERSION_CODES; +import android.support.annotation.NonNull; +import com.android.dialer.common.LogUtil; +import java.util.Optional; + +/** + * The Mediator for Assisted Dialing. + * + *

This class is responsible for mediating location discovery of the user, determining if the + * call is eligible for assisted dialing, and performing the transformation of numbers eligible for + * assisted dialing. + */ +final class AssistedDialingMediatorImpl implements AssistedDialingMediator { + + private final LocationDetector locationDetector; + private final NumberTransformer numberTransformer; + + AssistedDialingMediatorImpl( + @NonNull LocationDetector locationDetector, @NonNull NumberTransformer numberTransformer) { + if (locationDetector == null) { + throw new NullPointerException("locationDetector was null"); + } + + if (numberTransformer == null) { + throw new NullPointerException("numberTransformer was null"); + } + this.locationDetector = locationDetector; + this.numberTransformer = numberTransformer; + } + + /** + * Returns an Optional of type String containing the transformed number that was provided. The + * transformed number should be capable of dialing out of the User's current country and + * successfully connecting with a contact in the User's home country. + */ + @SuppressWarnings("AndroidApiChecker") // Use of optional + @TargetApi(VERSION_CODES.N) + @Override + public Optional attemptAssistedDial(@NonNull String numberToTransform) { + Optional userHomeCountryCode = locationDetector.getUpperCaseUserHomeCountry(); + Optional userRoamingCountryCode = locationDetector.getUpperCaseUserRoamingCountry(); + + if (!userHomeCountryCode.isPresent() || !userRoamingCountryCode.isPresent()) { + LogUtil.i("AssistedDialingMediator.attemptAssistedDial", "Unable to determine country codes"); + return Optional.empty(); + } + + return numberTransformer.doAssistedDialingTransformation( + numberToTransform, userHomeCountryCode.get(), userRoamingCountryCode.get()); + } +} diff --git a/java/com/android/dialer/assisteddialing/AssistedDialingMediatorStub.java b/java/com/android/dialer/assisteddialing/AssistedDialingMediatorStub.java new file mode 100644 index 000000000..c7a821214 --- /dev/null +++ b/java/com/android/dialer/assisteddialing/AssistedDialingMediatorStub.java @@ -0,0 +1,34 @@ +/* + * 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.assisteddialing; + +import android.annotation.TargetApi; +import android.os.Build.VERSION_CODES; +import android.support.annotation.NonNull; +import java.util.Optional; + +/** A stub assisted dialing implementation. */ +public final class AssistedDialingMediatorStub implements AssistedDialingMediator { + + /** Always returns an empty Optional. */ + @Override + @SuppressWarnings("AndroidApiChecker") // Use of optional + @TargetApi(VERSION_CODES.N) + public Optional attemptAssistedDial(@NonNull String numberToTransform) { + return Optional.empty(); + } +} diff --git a/java/com/android/dialer/assisteddialing/ConcreteCreator.java b/java/com/android/dialer/assisteddialing/ConcreteCreator.java index f51216a69..49d3b1f87 100644 --- a/java/com/android/dialer/assisteddialing/ConcreteCreator.java +++ b/java/com/android/dialer/assisteddialing/ConcreteCreator.java @@ -18,10 +18,12 @@ package com.android.dialer.assisteddialing; import android.annotation.TargetApi; import android.content.Context; +import android.os.Build; import android.os.Build.VERSION_CODES; import android.support.annotation.NonNull; import android.telephony.TelephonyManager; import com.android.dialer.common.LogUtil; +import com.android.dialer.configprovider.ConfigProviderBindings; /** * A Creator for AssistedDialingMediators. @@ -32,6 +34,11 @@ import com.android.dialer.common.LogUtil; @TargetApi(VERSION_CODES.N) public final class ConcreteCreator { + // Floor set at N due to use of Optional. + protected static final int BUILD_CODE_FLOOR = Build.VERSION_CODES.N; + // Ceiling set at O because this feature will ship as part of the framework in P. + protected static final int BUILD_CODE_CEILING = Build.VERSION_CODES.O; + /** * Creates a new AssistedDialingMediator * @@ -42,6 +49,7 @@ public final class ConcreteCreator { */ public static AssistedDialingMediator createNewAssistedDialingMediator( @NonNull TelephonyManager telephonyManager, @NonNull Context context) { + if (telephonyManager == null) { LogUtil.i( "ConcreteCreator.createNewAssistedDialingMediator", "provided TelephonyManager was null"); @@ -51,8 +59,14 @@ public final class ConcreteCreator { LogUtil.i("ConcreteCreator.createNewAssistedDialingMediator", "provided context was null"); throw new NullPointerException("Provided context was null"); } + + if ((Build.VERSION.SDK_INT < BUILD_CODE_FLOOR || Build.VERSION.SDK_INT > BUILD_CODE_CEILING) + || !ConfigProviderBindings.get(context).getBoolean("assisted_dialing_enabled", false)) { + return new AssistedDialingMediatorStub(); + } + Constraints constraints = new Constraints(context); - return new AssistedDialingMediator( + return new AssistedDialingMediatorImpl( new LocationDetector(telephonyManager), new NumberTransformer(constraints)); } } diff --git a/java/com/android/dialer/assisteddialing/Constraints.java b/java/com/android/dialer/assisteddialing/Constraints.java index 6bcab9963..023be1c4c 100644 --- a/java/com/android/dialer/assisteddialing/Constraints.java +++ b/java/com/android/dialer/assisteddialing/Constraints.java @@ -62,7 +62,7 @@ final class Constraints { "GB" /* United Kingdom */, "JP" /* Japan */, "MX" /* Mexico */, - "US" /* United States*/, + "US" /* United States */, }; private final Set supportedCountryCodes = @@ -115,7 +115,8 @@ final class Constraints { && isUserRoaming(userHomeCountryCode, userRoamingCountryCode) && isNotInternationalNumber(parsedPhoneNumber) && isNotEmergencyNumber(numberToCheck, context) - && isValidNumber(parsedPhoneNumber); + && isValidNumber(parsedPhoneNumber) + && doesNotHaveExtension(parsedPhoneNumber); } /** Returns a boolean indicating the value equivalence of the provided country codes. */ @@ -165,10 +166,7 @@ final class Constraints { } } - /** - * Returns a boolean indicating if the provided number and home country code are already - * internationally formatted. - */ + /** Returns a boolean indicating if the provided number is already internationally formatted. */ private boolean isNotInternationalNumber(@NonNull Optional parsedPhoneNumber) { if (parsedPhoneNumber.get().hasCountryCode() @@ -181,6 +179,22 @@ final class Constraints { return true; } + /** + * Returns a boolean indicating if the provided number has an extension. + * + *

Extensions are currently stripped when formatting a number for mobile dialing, so we don't + * want to purposefully truncate a number. + */ + private boolean doesNotHaveExtension(@NonNull Optional parsedPhoneNumber) { + + if (parsedPhoneNumber.get().hasExtension() + && !TextUtils.isEmpty(parsedPhoneNumber.get().getExtension())) { + LogUtil.i("Constraints.doesNotHaveExtension", "phone number has an extension"); + return false; + } + return true; + } + /** Returns a boolean indicating if the provided number is considered to be a valid number. */ private boolean isValidNumber(@NonNull Optional parsedPhoneNumber) { boolean result = PhoneNumberUtil.getInstance().isValidNumber(parsedPhoneNumber.get()); diff --git a/java/com/android/dialer/assisteddialing/TransformationInfo.java b/java/com/android/dialer/assisteddialing/TransformationInfo.java index 7149d71cc..03e565c51 100644 --- a/java/com/android/dialer/assisteddialing/TransformationInfo.java +++ b/java/com/android/dialer/assisteddialing/TransformationInfo.java @@ -43,15 +43,15 @@ public abstract class TransformationInfo { private static final String TRANSFORMED_NUMBER_COUNTRY_CALLING_CODE_KEY = "TRANSFORMED_NUMBER_COUNTRY_CALLING_CODE"; - abstract String originalNumber(); + public abstract String originalNumber(); - abstract String transformedNumber(); + public abstract String transformedNumber(); - abstract String userHomeCountryCode(); + public abstract String userHomeCountryCode(); - abstract String userRoamingCountryCode(); + public abstract String userRoamingCountryCode(); - abstract int transformedNumberCountryCallingCode(); + public abstract int transformedNumberCountryCallingCode(); public static Builder builder() { return new AutoValue_TransformationInfo.Builder(); diff --git a/java/com/android/dialer/callintent/CallIntentBuilder.java b/java/com/android/dialer/callintent/CallIntentBuilder.java index b5b680e48..dc239dc6b 100644 --- a/java/com/android/dialer/callintent/CallIntentBuilder.java +++ b/java/com/android/dialer/callintent/CallIntentBuilder.java @@ -16,21 +16,27 @@ package com.android.dialer.callintent; +import android.annotation.TargetApi; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.SystemClock; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; +import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telecom.VideoProfile; import android.text.TextUtils; +import com.android.dialer.assisteddialing.AssistedDialingMediator; +import com.android.dialer.assisteddialing.TransformationInfo; import com.android.dialer.common.Assert; import com.android.dialer.compat.telephony.TelephonyManagerCompat; import com.android.dialer.performancereport.PerformanceReport; import com.android.dialer.util.CallUtil; +import java.util.Optional; /** Creates an intent to start a new outgoing call. */ public class CallIntentBuilder { @@ -40,6 +46,7 @@ public class CallIntentBuilder { private boolean isVideoCall; private String callSubject; private boolean allowAssistedDial; + private AssistedDialingMediator assistedDialingMediator; private static int lightbringerButtonAppearInExpandedCallLogItemCount = 0; private static int lightbringerButtonAppearInCollapsedCallLogItemCount = 0; @@ -103,7 +110,9 @@ public class CallIntentBuilder { return this; } - public CallIntentBuilder setAllowAssistedDial(boolean allowAssistedDial) { + public CallIntentBuilder setAllowAssistedDial( + boolean allowAssistedDial, @NonNull AssistedDialingMediator assistedDialingMediator) { + this.assistedDialingMediator = Assert.isNotNull(assistedDialingMediator); this.allowAssistedDial = allowAssistedDial; return this; } @@ -115,18 +124,18 @@ public class CallIntentBuilder { public Intent build() { Intent intent = new Intent(Intent.ACTION_CALL, uri); + Bundle extras = new Bundle(); + + if (allowAssistedDial && this.assistedDialingMediator != null) { + intent = buildAssistedDialingParameters(intent, extras); + } intent.putExtra( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, isVideoCall ? VideoProfile.STATE_BIDIRECTIONAL : VideoProfile.STATE_AUDIO_ONLY); - Bundle extras = new Bundle(); extras.putLong(Constants.EXTRA_CALL_CREATED_TIME_MILLIS, SystemClock.elapsedRealtime()); CallIntentParser.putCallSpecificAppData(extras, callSpecificAppData); - if (allowAssistedDial) { - extras.putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true); - } - intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras); if (phoneAccountHandle != null) { @@ -140,6 +149,26 @@ public class CallIntentBuilder { return intent; } + @SuppressWarnings("AndroidApiChecker") // Use of optional + @TargetApi(Build.VERSION_CODES.N) + private Intent buildAssistedDialingParameters(Intent intent, Bundle extras) { + extras.putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true); + String phoneNumber = + uri.getScheme().equals(PhoneAccount.SCHEME_TEL) ? uri.getSchemeSpecificPart() : ""; + Optional transformedNumber = + assistedDialingMediator.attemptAssistedDial(phoneNumber); + if (transformedNumber.isPresent()) { + Bundle assistedDialingExtras = transformedNumber.get().toBundle(); + extras.putBoolean(TelephonyManagerCompat.IS_ASSISTED_DIALED, true); + extras.putBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS, assistedDialingExtras); + intent = + new Intent( + Intent.ACTION_CALL, + CallUtil.getCallUri(Assert.isNotNull(transformedNumber.get().transformedNumber()))); + } + return intent; + } + private static @NonNull CallSpecificAppData createCallSpecificAppData( CallInitiationType.Type callInitiationType) { CallSpecificAppData callSpecificAppData = diff --git a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java index ecd36d359..61c44b9f4 100644 --- a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java +++ b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java @@ -68,6 +68,11 @@ public class TelephonyManagerCompat { */ public static final String IS_ASSISTED_DIALED = "android.telecom.extra.IS_ASSISTED_DIALED"; + // TODO(erfanian): b/63995261 Replace with the platform/telecom API when available. + /** Additional information relating to the assisted dialing transformation. */ + public static final String ASSISTED_DIALING_EXTRAS = + "android.telecom.extra.ASSISTED_DIALING_EXTRAS"; + /** * Returns the number of phones available. Returns 1 for Single standby mode (Single SIM * functionality) Returns 2 for Dual standby mode.(Dual SIM functionality) diff --git a/java/com/android/dialer/interactions/PhoneNumberInteraction.java b/java/com/android/dialer/interactions/PhoneNumberInteraction.java index c42be42ec..9692dae0f 100644 --- a/java/com/android/dialer/interactions/PhoneNumberInteraction.java +++ b/java/com/android/dialer/interactions/PhoneNumberInteraction.java @@ -40,6 +40,7 @@ import android.provider.ContactsContract.RawContacts; import android.support.annotation.IntDef; import android.support.annotation.VisibleForTesting; import android.support.v4.app.ActivityCompat; +import android.telephony.TelephonyManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -51,6 +52,7 @@ import com.android.contacts.common.Collapser; import com.android.contacts.common.Collapser.Collapsible; import com.android.contacts.common.MoreContactUtils; import com.android.contacts.common.util.ContactDisplayUtils; +import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.callintent.CallIntentParser; @@ -83,6 +85,7 @@ public class PhoneNumberInteraction implements OnLoadCompleteListener { private static final String TAG = PhoneNumberInteraction.class.getSimpleName(); /** The identifier for a permissions request if one is generated. */ public static final int REQUEST_READ_CONTACTS = 1; + public static final int REQUEST_CALL_PHONE = 2; @VisibleForTesting @@ -183,7 +186,10 @@ public class PhoneNumberInteraction implements OnLoadCompleteListener { intent = new CallIntentBuilder(phoneNumber, callSpecificAppData) .setIsVideoCall(isVideoCall) - .setAllowAssistedDial(callSpecificAppData.getAllowAssistedDialing()) + .setAllowAssistedDial( + callSpecificAppData.getAllowAssistedDialing(), + ConcreteCreator.createNewAssistedDialingMediator( + context.getSystemService(TelephonyManager.class), context)) .build(); break; } diff --git a/java/com/android/dialer/searchfragment/list/SearchAdapter.java b/java/com/android/dialer/searchfragment/list/SearchAdapter.java index 22bfa6dbd..1ca29e072 100644 --- a/java/com/android/dialer/searchfragment/list/SearchAdapter.java +++ b/java/com/android/dialer/searchfragment/list/SearchAdapter.java @@ -21,11 +21,13 @@ import android.content.Intent; import android.support.annotation.VisibleForTesting; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.ViewHolder; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.callcomposer.CallComposerActivity; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; @@ -209,23 +211,32 @@ public final class SearchAdapter extends RecyclerView.Adapter @Override public void placeVoiceCall(String phoneNumber, int ranking) { - placeCall(phoneNumber, ranking, false); + placeCall(phoneNumber, ranking, false, true); } @Override public void placeVideoCall(String phoneNumber, int ranking) { - placeCall(phoneNumber, ranking, true); + placeCall(phoneNumber, ranking, true, false); } - private void placeCall(String phoneNumber, int position, boolean isVideoCall) { + private void placeCall( + String phoneNumber, int position, boolean isVideoCall, boolean allowAssistedDial) { CallSpecificAppData callSpecificAppData = CallSpecificAppData.newBuilder() .setCallInitiationType(callInitiationType) .setPositionOfSelectedSearchResult(position) .setCharactersInSearchString(query == null ? 0 : query.length()) + .setAllowAssistedDialing(allowAssistedDial) .build(); Intent intent = - new CallIntentBuilder(phoneNumber, callSpecificAppData).setIsVideoCall(isVideoCall).build(); + new CallIntentBuilder(phoneNumber, callSpecificAppData) + .setIsVideoCall(isVideoCall) + .setAllowAssistedDial( + allowAssistedDial, + ConcreteCreator.createNewAssistedDialingMediator( + activity.getSystemService(TelephonyManager.class), + activity.getApplicationContext())) + .build(); DialerUtils.startActivityWithErrorToast(activity, intent); } -- cgit v1.2.3 From 19e6dbd30ae88e68cd68f3d3873440d50d19d902 Mon Sep 17 00:00:00 2001 From: Android Dialer Date: Mon, 9 Oct 2017 16:15:53 -0700 Subject: Group calls in the call log according to their corresponding actions. Currently different types of calls can be grouped together (e.g., 1 voice call and 1 IMS call to/from the same number), which makes it difficult to choose the icon for the call detail UI's call back button. This CL adds an extra constraint that separates different call types (Lightbringer, IMS, and voice). This way calls in the call detail UI are in the same category and an appropriate icon can be set. Bug: 66026167 Test: CallLogGroupBuilderTest.addGroups_MixedEntries_PartiallyGroupedByAction PiperOrigin-RevId: 171602617 Change-Id: Id8170206009ba836a40c38a86914c71d5c7701dc --- .../android/dialer/app/calllog/CallLogAdapter.java | 67 +++++++++++---- .../dialer/app/calllog/CallLogGroupBuilder.java | 49 +++++++++-- .../app/calllog/CallLogListItemViewHolder.java | 71 ++++++++++------ .../dialer/calllogutils/CallbackActionHelper.java | 95 ++++++++++++++++++++++ 4 files changed, 232 insertions(+), 50 deletions(-) create mode 100644 java/com/android/dialer/calllogutils/CallbackActionHelper.java diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java index e79c89c57..228321581 100644 --- a/java/com/android/dialer/app/calllog/CallLogAdapter.java +++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java @@ -64,6 +64,7 @@ import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler; import com.android.dialer.calldetails.CallDetailsEntries; import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry; import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction; import com.android.dialer.calllogutils.PhoneAccountUtils; import com.android.dialer.calllogutils.PhoneCallDetails; import com.android.dialer.common.Assert; @@ -479,8 +480,17 @@ public class CallLogAdapter extends GroupingListAdapter @NonNull private final Set mHiddenItemUris = new ArraySet<>(); private CallLogListItemViewHolder.OnClickListener mBlockReportSpamListener; + + /** + * Map, keyed by call ID, used to track the callback action for a call. Calls associated with the + * same callback action will be put into the same primary call group in {@link + * com.android.dialer.app.calllog.CallLogGroupBuilder}. This information is used to set the + * callback icon and trigger the corresponding action. + */ + private final Map mCallbackActions = new ArrayMap<>(); + /** - * Map, keyed by call Id, used to track the day group for a call. As call log entries are put into + * Map, keyed by call ID, used to track the day group for a call. As call log entries are put into * the primary call groups in {@link com.android.dialer.app.calllog.CallLogGroupBuilder}, they are * also assigned a secondary "day group". This map tracks the day group assigned to all calls in * the call log. This information is used to trigger the display of a day group header above the @@ -491,7 +501,7 @@ public class CallLogAdapter extends GroupingListAdapter * previous day group without having to reverse the cursor to the start of the previous day call * log entry. */ - private Map mDayGroups = new ArrayMap<>(); + private final Map mDayGroups = new ArrayMap<>(); private boolean mLoading = true; private ContactsPreferences mContactsPreferences; @@ -688,7 +698,7 @@ public class CallLogAdapter extends GroupingListAdapter @Override protected void addGroups(Cursor cursor) { - mCallLogGroupBuilder.addGroups(cursor); + mCallLogGroupBuilder.addGroups(cursor, mActivity); } @Override @@ -865,10 +875,11 @@ public class CallLogAdapter extends GroupingListAdapter protected void onPostExecute(Boolean success) { views.isLoaded = true; if (success) { - int currentGroup = getDayGroupForCall(views.rowId); - if (currentGroup != details.previousGroup) { + views.callbackAction = getCallbackAction(views.rowId); + int currentDayGroup = getDayGroup(views.rowId); + if (currentDayGroup != details.previousGroup) { views.dayGroupHeaderVisibility = View.VISIBLE; - views.dayGroupHeaderText = getGroupDescription(currentGroup); + views.dayGroupHeaderText = getGroupDescription(currentDayGroup); } else { views.dayGroupHeaderVisibility = View.GONE; } @@ -1226,7 +1237,7 @@ public class CallLogAdapter extends GroupingListAdapter cursor.moveToPosition(startingPosition); return CallLogGroupBuilder.DAY_GROUP_NONE; } - int result = getDayGroupForCall(cursor.getLong(CallLogQuery.ID)); + int result = getDayGroup(cursor.getLong(CallLogQuery.ID)); cursor.moveToPosition(startingPosition); return result; } @@ -1236,14 +1247,30 @@ public class CallLogAdapter extends GroupingListAdapter } /** - * Given a call Id, look up the day group that the call belongs to. The day group data is - * populated in {@link com.android.dialer.app.calllog.CallLogGroupBuilder}. + * Given a call ID, look up its callback action. Callback action data are populated in {@link + * com.android.dialer.app.calllog.CallLogGroupBuilder}. * - * @param callId The call to retrieve the day group for. + * @param callId The call ID to retrieve the callback action. + * @return The callback action for the call. + */ + @MainThread + private int getCallbackAction(long callId) { + Integer result = mCallbackActions.get(callId); + if (result != null) { + return result; + } + return CallbackAction.NONE; + } + + /** + * Given a call ID, look up the day group the call belongs to. Day group data are populated in + * {@link com.android.dialer.app.calllog.CallLogGroupBuilder}. + * + * @param callId The call ID to retrieve the day group. * @return The day group for the call. */ @MainThread - private int getDayGroupForCall(long callId) { + private int getDayGroup(long callId) { Integer result = mDayGroups.get(callId); if (result != null) { return result; @@ -1305,18 +1332,28 @@ public class CallLogAdapter extends GroupingListAdapter mContactInfoCache.injectContactInfoForTest(number, countryIso, contactInfo); } + /** + * Stores the callback action associated with a call in the call log. + * + * @param rowId The row ID of the current call. + * @param callbackAction The current call's callback action. + */ + @Override + @MainThread + public void setCallbackAction(long rowId, @CallbackAction int callbackAction) { + mCallbackActions.put(rowId, callbackAction); + } + /** * Stores the day group associated with a call in the call log. * - * @param rowId The row Id of the current call. + * @param rowId The row ID of the current call. * @param dayGroup The day group the call belongs in. */ @Override @MainThread public void setDayGroup(long rowId, int dayGroup) { - if (!mDayGroups.containsKey(rowId)) { - mDayGroups.put(rowId, dayGroup); - } + mDayGroups.put(rowId, dayGroup); } /** Clears the day group associations on re-bind of the call log. */ diff --git a/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java b/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java index 45ff3783d..57a8be730 100644 --- a/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java +++ b/java/com/android/dialer/app/calllog/CallLogGroupBuilder.java @@ -16,6 +16,7 @@ package com.android.dialer.app.calllog; +import android.content.Context; import android.database.Cursor; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; @@ -25,6 +26,8 @@ import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import android.text.format.Time; import com.android.contacts.common.util.DateUtils; +import com.android.dialer.calllogutils.CallbackActionHelper; +import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction; import com.android.dialer.compat.AppCompatConstants; import com.android.dialer.phonenumbercache.CallLogQuery; import com.android.dialer.phonenumberutil.PhoneNumberHelper; @@ -71,7 +74,7 @@ public class CallLogGroupBuilder { * * @see GroupingListAdapter#addGroups(Cursor) */ - public void addGroups(Cursor cursor) { + public void addGroups(Cursor cursor, Context context) { final int count = cursor.getCount(); if (count == 0) { return; @@ -90,23 +93,32 @@ public class CallLogGroupBuilder { int groupDayGroup = getDayGroup(firstDate, currentTime); mGroupCreator.setDayGroup(firstRowId, groupDayGroup); - // Instantiate the group values to those of the first call in the cursor. + // Determine the callback action for the first call in the cursor. String groupNumber = cursor.getString(CallLogQuery.NUMBER); + String groupAccountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME); + int groupFeatures = cursor.getInt(CallLogQuery.FEATURES); + int groupCallbackAction = + CallbackActionHelper.getCallbackAction( + groupNumber, groupFeatures, groupAccountComponentName, context); + mGroupCreator.setCallbackAction(firstRowId, groupCallbackAction); + + // Instantiate other group values to those of the first call in the cursor. + String groupAccountId = cursor.getString(CallLogQuery.ACCOUNT_ID); String groupPostDialDigits = (VERSION.SDK_INT >= VERSION_CODES.N) ? cursor.getString(CallLogQuery.POST_DIAL_DIGITS) : ""; String groupViaNumbers = (VERSION.SDK_INT >= VERSION_CODES.N) ? cursor.getString(CallLogQuery.VIA_NUMBER) : ""; 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; String numberViaNumbers; int callType; + int features; String accountComponentName; String accountId; + int callbackAction; while (cursor.moveToNext()) { // Obtain the values for the current call to group. @@ -118,21 +130,28 @@ public class CallLogGroupBuilder { numberViaNumbers = (VERSION.SDK_INT >= VERSION_CODES.N) ? cursor.getString(CallLogQuery.VIA_NUMBER) : ""; callType = cursor.getInt(CallLogQuery.CALL_TYPE); + features = cursor.getInt(CallLogQuery.FEATURES); accountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME); accountId = cursor.getString(CallLogQuery.ACCOUNT_ID); + callbackAction = + CallbackActionHelper.getCallbackAction(number, features, accountComponentName, context); final boolean isSameNumber = equalNumbers(groupNumber, number); final boolean isSamePostDialDigits = groupPostDialDigits.equals(numberPostDialDigits); final boolean isSameViaNumbers = groupViaNumbers.equals(numberViaNumbers); final boolean isSameAccount = isSameAccount(groupAccountComponentName, accountComponentName, groupAccountId, accountId); + final boolean isSameCallbackAction = (groupCallbackAction == callbackAction); - // Group with the same number and account. Never group voicemails. Only group blocked - // calls with other blocked calls. + // Group calls with the following criteria: + // (1) Calls with the same number, account, and callback action should be in the same group; + // (2) Never group voice mails; and + // (3) Only group blocked calls with other blocked calls. if (isSameNumber && isSameAccount && isSamePostDialDigits && isSameViaNumbers + && isSameCallbackAction && areBothNotVoicemail(callType, groupCallType) && (areBothNotBlocked(callType, groupCallType) || areBothBlocked(callType, groupCallType))) { @@ -158,10 +177,12 @@ public class CallLogGroupBuilder { groupCallType = callType; groupAccountComponentName = accountComponentName; groupAccountId = accountId; + groupCallbackAction = callbackAction; } - // Save the day group associated with the current call. + // Save the callback action and the day group associated with the current call. final long currentCallId = cursor.getLong(CallLogQuery.ID); + mGroupCreator.setCallbackAction(currentCallId, groupCallbackAction); mGroupCreator.setDayGroup(currentCallId, groupDayGroup); } @@ -258,13 +279,23 @@ public class CallLogGroupBuilder { */ void addGroup(int cursorPosition, int size); + /** + * Defines the interface for tracking each call's callback action. Calls in a call group are + * associated with the same callback action as the first call in the group. The value of a + * callback action should be one of the categories in {@link CallbackAction}. + * + * @param rowId The row ID of the current call. + * @param callbackAction The current call's callback action. + */ + void setCallbackAction(long rowId, @CallbackAction int callbackAction); + /** * Defines the interface for tracking the day group each call belongs to. Calls in a call group * are assigned the same day group as the first call in the group. The day group assigns calls * to the buckets: Today, Yesterday, Last week, and Other * - * @param rowId The row Id of the current call. - * @param dayGroup The day group the call belongs in. + * @param rowId The row ID of the current call. + * @param dayGroup The day group the call belongs to. */ void setDayGroup(long rowId, int dayGroup); diff --git a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java index f0eee112b..225b6527e 100644 --- a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java +++ b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java @@ -66,6 +66,7 @@ import com.android.dialer.callcomposer.CallComposerActivity; import com.android.dialer.calldetails.CallDetailsActivity; import com.android.dialer.calldetails.CallDetailsEntries; import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.CompatUtils; @@ -228,6 +229,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder private final View.OnLongClickListener longPressListener; private boolean mVoicemailPrimaryActionButtonClicked; + public int callbackAction; public int dayGroupHeaderVisibility; public CharSequence dayGroupHeaderText; public boolean isAttachedToWindow; @@ -511,36 +513,53 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder } else { primaryActionButtonView.setVisibility(View.GONE); } - } else { - // Treat as normal list item; show call button, if possible. - if (PhoneNumberHelper.canPlaceCallsTo(number, numberPresentation)) { - boolean isVoicemailNumber = mCallLogCache.isVoicemailNumber(accountHandle, number); + return; + } + + // Treat as normal list item; show call button, if possible. + if (!PhoneNumberHelper.canPlaceCallsTo(number, numberPresentation)) { + primaryActionButtonView.setTag(null); + primaryActionButtonView.setVisibility(View.GONE); + return; + } - if (!isVoicemailNumber && showLightbringerPrimaryButton()) { + switch (callbackAction) { + case CallbackAction.IMS_VIDEO: + primaryActionButtonView.setTag( + IntentProvider.getReturnVideoCallIntentProvider(number, accountHandle)); + primaryActionButtonView.setContentDescription( + TextUtils.expandTemplate( + mContext.getString(R.string.description_video_call_action), validNameOrNumber)); + primaryActionButtonView.setImageResource(R.drawable.quantum_ic_videocam_vd_theme_24); + primaryActionButtonView.setVisibility(View.VISIBLE); + break; + case CallbackAction.LIGHTBRINGER: + if (showLightbringerPrimaryButton()) { CallIntentBuilder.increaseLightbringerCallButtonAppearInCollapsedCallLogItemCount(); primaryActionButtonView.setTag(IntentProvider.getLightbringerIntentProvider(number)); - primaryActionButtonView.setContentDescription( - TextUtils.expandTemplate( - mContext.getString(R.string.description_video_call_action), validNameOrNumber)); - primaryActionButtonView.setImageResource(R.drawable.quantum_ic_videocam_vd_theme_24); - primaryActionButtonView.setVisibility(View.VISIBLE); - return; + } else { + primaryActionButtonView.setTag( + IntentProvider.getReturnVideoCallIntentProvider(number, accountHandle)); } - - if (isVoicemailNumber) { - // Call to generic voicemail number, in case there are multiple accounts. + primaryActionButtonView.setContentDescription( + TextUtils.expandTemplate( + mContext.getString(R.string.description_video_call_action), validNameOrNumber)); + primaryActionButtonView.setImageResource(R.drawable.quantum_ic_videocam_vd_theme_24); + primaryActionButtonView.setVisibility(View.VISIBLE); + break; + case CallbackAction.VOICE: + if (mCallLogCache.isVoicemailNumber(accountHandle, number)) { + // Call to generic voicemail number, in case there are multiple accounts primaryActionButtonView.setTag(IntentProvider.getReturnVoicemailCallIntentProvider()); + } else if (this.info != null && this.info.lookupKey != null) { + primaryActionButtonView.setTag( + IntentProvider.getAssistedDialIntentProvider( + number + postDialDigits, + mContext, + mContext.getSystemService(TelephonyManager.class))); } else { - if (this.info != null && this.info.lookupKey != null) { - primaryActionButtonView.setTag( - IntentProvider.getAssistedDialIntentProvider( - number + postDialDigits, - mContext, - mContext.getSystemService(TelephonyManager.class))); - } else { - primaryActionButtonView.setTag( - IntentProvider.getReturnCallIntentProvider(number + postDialDigits)); - } + primaryActionButtonView.setTag( + IntentProvider.getReturnCallIntentProvider(number + postDialDigits)); } primaryActionButtonView.setContentDescription( @@ -548,10 +567,10 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder mContext.getString(R.string.description_call_action), validNameOrNumber)); primaryActionButtonView.setImageResource(R.drawable.quantum_ic_call_vd_theme_24); primaryActionButtonView.setVisibility(View.VISIBLE); - } else { + break; + default: primaryActionButtonView.setTag(null); primaryActionButtonView.setVisibility(View.GONE); - } } } diff --git a/java/com/android/dialer/calllogutils/CallbackActionHelper.java b/java/com/android/dialer/calllogutils/CallbackActionHelper.java new file mode 100644 index 000000000..297d5e649 --- /dev/null +++ b/java/com/android/dialer/calllogutils/CallbackActionHelper.java @@ -0,0 +1,95 @@ +/* + * 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.provider.CallLog.Calls; +import android.support.annotation.IntDef; +import android.text.TextUtils; +import com.android.dialer.lightbringer.Lightbringer; +import com.android.dialer.lightbringer.LightbringerComponent; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** Helper class to determine the callback action associated with a call in the call log. */ +public class CallbackActionHelper { + + /** Specifies the action a user can take to make a callback. */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + CallbackAction.NONE, + CallbackAction.IMS_VIDEO, + CallbackAction.LIGHTBRINGER, + CallbackAction.VOICE + }) + public @interface CallbackAction { + int NONE = 0; + int IMS_VIDEO = 1; + int LIGHTBRINGER = 2; + int VOICE = 3; + } + + /** + * Returns the {@link CallbackAction} that can be associated with a call. + * + * @param number The phone number in column {@link android.provider.CallLog.Calls#NUMBER}. + * @param features Value of features in column {@link android.provider.CallLog.Calls#FEATURES}. + * @param phoneAccountComponentName Account name in column {@link + * android.provider.CallLog.Calls#PHONE_ACCOUNT_COMPONENT_NAME}. + * @param context The context in which the method is called. + * @return One of the values in {@link CallbackAction} + */ + public static @CallbackAction int getCallbackAction( + String number, int features, String phoneAccountComponentName, Context context) { + return getCallbackAction( + number, features, isLightbringerCall(phoneAccountComponentName, context)); + } + + /** + * Returns the {@link CallbackAction} that can be associated with a call. + * + * @param number The phone number in column {@link android.provider.CallLog.Calls#NUMBER}. + * @param features Value of features in column {@link android.provider.CallLog.Calls#FEATURES}. + * @param isLightbringerCall Whether the call is a Lightbringer call. + * @return One of the values in {@link CallbackAction} + */ + public static @CallbackAction int getCallbackAction( + String number, int features, boolean isLightbringerCall) { + if (TextUtils.isEmpty(number)) { + return CallbackAction.NONE; + } + if (isLightbringerCall) { + return CallbackAction.LIGHTBRINGER; + } + + boolean isVideoCall = (features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO; + if (isVideoCall) { + return CallbackAction.IMS_VIDEO; + } + + return CallbackAction.VOICE; + } + + private static boolean isLightbringerCall(String phoneAccountComponentName, Context context) { + Lightbringer lightBringer = LightbringerComponent.get(context).getLightbringer(); + return lightBringer.getPhoneAccountComponentName() != null + && lightBringer + .getPhoneAccountComponentName() + .flattenToString() + .equals(phoneAccountComponentName); + } +} -- cgit v1.2.3