From b2b6365629aed422a006529fe7940612f778baed Mon Sep 17 00:00:00 2001 From: twyen Date: Mon, 7 May 2018 16:36:17 -0700 Subject: Place Duo calls with PreCall This CL consolidates common duo calling operations into precall, including checking reachability, falling back to carrier video call, placing the call to duo with startActivityForResult. TEST=TAP Bug: 78783816 Test: TAP PiperOrigin-RevId: 195742478 Change-Id: I9fea1e4999f604e1f3a153b28079cd0db77b7393 --- .../android/dialer/app/calllog/CallLogAdapter.java | 22 ----- .../app/calllog/CallLogListItemViewHolder.java | 53 +++--------- .../android/dialer/app/calllog/IntentProvider.java | 38 ++++++++- .../calldetails/CallDetailsActivityCommon.java | 24 ++---- .../dialer/callintent/CallIntentBuilder.java | 12 +++ .../dialer/calllogutils/CallLogRowActions.java | 7 +- java/com/android/dialer/duo/Duo.java | 18 +--- .../android/dialer/duo/PlaceDuoCallNotifier.java | 45 ---------- .../android/dialer/duo/PlaceDuoCallReceiver.java | 77 ----------------- java/com/android/dialer/duo/stub/DuoStub.java | 12 +-- .../dialer/historyitemactions/DuoCallModule.java | 56 ------------- .../HistoryItemActionModulesBuilder.java | 18 ++-- .../com/android/dialer/main/impl/MainActivity.java | 8 -- .../android/dialer/precall/PreCallCoordinator.java | 6 +- .../com/android/dialer/precall/impl/DuoAction.java | 97 ++++++++++++++++++++++ .../precall/impl/PreCallCoordinatorImpl.java | 20 ++++- .../android/dialer/precall/impl/PreCallModule.java | 3 +- .../searchfragment/list/NewSearchFragment.java | 9 +- .../android/dialer/speeddial/DisambigDialog.java | 10 +-- .../dialer/speeddial/SpeedDialFragment.java | 22 ++--- 20 files changed, 220 insertions(+), 337 deletions(-) delete mode 100644 java/com/android/dialer/duo/PlaceDuoCallNotifier.java delete mode 100644 java/com/android/dialer/duo/PlaceDuoCallReceiver.java delete mode 100644 java/com/android/dialer/historyitemactions/DuoCallModule.java create mode 100644 java/com/android/dialer/precall/impl/DuoAction.java (limited to 'java/com/android/dialer') diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java index b99cef11f..c2c753e43 100644 --- a/java/com/android/dialer/app/calllog/CallLogAdapter.java +++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java @@ -64,7 +64,6 @@ import com.android.dialer.app.voicemail.VoicemailPlaybackPresenter.OnVoicemailDe 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.PhoneCallDetails; import com.android.dialer.common.Assert; @@ -407,28 +406,7 @@ public class CallLogAdapter extends GroupingListAdapter } } expandViewHolderActions(viewHolder); - - if (isDuoCallButtonVisible(viewHolder.videoCallButtonView)) { - CallIntentBuilder.increaseLightbringerCallButtonAppearInExpandedCallLogItemCount(); - } - } - } - - private boolean isDuoCallButtonVisible(View videoCallButtonView) { - if (videoCallButtonView == null) { - return false; - } - if (videoCallButtonView.getVisibility() != View.VISIBLE) { - return false; - } - IntentProvider intentProvider = (IntentProvider) videoCallButtonView.getTag(); - if (intentProvider == null) { - return false; } - return DuoComponent.get(activity) - .getDuo() - .getIntentType(intentProvider.getIntent(activity)) - .isPresent(); } }; diff --git a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java index b7781f343..9b7741df4 100644 --- a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java +++ b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java @@ -19,7 +19,6 @@ package com.android.dialer.app.calllog; import android.Manifest.permission; import android.annotation.SuppressLint; import android.app.Activity; -import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.res.Resources; @@ -51,7 +50,6 @@ import android.view.ViewStub; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; -import android.widget.Toast; import com.android.contacts.common.dialog.CallSubjectDialog; import com.android.dialer.app.DialtactsActivity; import com.android.dialer.app.R; @@ -96,7 +94,6 @@ import com.android.dialer.telecom.TelecomUtil; import com.android.dialer.util.CallUtil; import com.android.dialer.util.DialerUtils; import com.android.dialer.util.UriUtils; -import com.google.common.base.Optional; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; @@ -550,7 +547,8 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder case CallbackAction.DUO: if (showDuoPrimaryButton()) { CallIntentBuilder.increaseLightbringerCallButtonAppearInCollapsedCallLogItemCount(); - primaryActionButtonView.setTag(IntentProvider.getDuoVideoIntentProvider(number)); + primaryActionButtonView.setTag( + IntentProvider.getDuoVideoIntentProvider(number, isNonContactEntry(info))); } else { primaryActionButtonView.setTag(IntentProvider.getReturnVideoCallIntentProvider(number)); } @@ -684,14 +682,17 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder boolean identifiedSpamCall = isSpamFeatureEnabled && isSpam; if (duo.isReachable(context, number)) { - videoCallButtonView.setTag(IntentProvider.getDuoVideoIntentProvider(number)); + videoCallButtonView.setTag( + IntentProvider.getDuoVideoIntentProvider(number, isNonContactEntry(info))); videoCallButtonView.setVisibility(View.VISIBLE); + CallIntentBuilder.increaseLightbringerCallButtonAppearInExpandedCallLogItemCount(); } else if (duo.isActivated(context) && !identifiedSpamCall) { if (ConfigProviderBindings.get(context) .getBoolean("enable_call_log_duo_invite_button", false)) { inviteVideoButtonView.setTag(IntentProvider.getDuoInviteIntentProvider(number)); inviteVideoButtonView.setVisibility(View.VISIBLE); Logger.get(context).logImpression(DialerImpression.Type.DUO_CALL_LOG_INVITE_SHOWN); + CallIntentBuilder.increaseLightbringerCallButtonAppearInExpandedCallLogItemCount(); } } else if (duo.isEnabled(context) && !identifiedSpamCall) { if (!duo.isInstalled(context)) { @@ -701,6 +702,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder setUpVideoButtonView.setVisibility(View.VISIBLE); Logger.get(context) .logImpression(DialerImpression.Type.DUO_CALL_LOG_SET_UP_INSTALL_SHOWN); + CallIntentBuilder.increaseLightbringerCallButtonAppearInExpandedCallLogItemCount(); } } else { if (ConfigProviderBindings.get(context) @@ -709,6 +711,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder setUpVideoButtonView.setVisibility(View.VISIBLE); Logger.get(context) .logImpression(DialerImpression.Type.DUO_CALL_LOG_SET_UP_ACTIVATE_SHOWN); + CallIntentBuilder.increaseLightbringerCallButtonAppearInExpandedCallLogItemCount(); } } } @@ -1024,20 +1027,13 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder if (intentProvider == null) { return; } - + intentProvider.logInteraction(context); final Intent intent = intentProvider.getIntent(context); // See IntentProvider.getCallDetailIntentProvider() for why this may be null. if (intent == null) { return; } - - // We check to see if we are starting a Duo intent. The reason is Duo - // intents need to be started using startActivityForResult instead of the usual startActivity - Optional duoIntentType = - DuoComponent.get(context).getDuo().getIntentType(intent); - if (duoIntentType.isPresent()) { - startDuoActivity(intent, duoIntentType.get()); - } else if (OldCallDetailsActivity.isLaunchIntent(intent)) { + if (OldCallDetailsActivity.isLaunchIntent(intent)) { PerformanceReport.recordClick(UiAction.Type.OPEN_CALL_DETAIL); ((Activity) context) .startActivityForResult(intent, ActivityRequestCodes.DIALTACTS_CALL_DETAILS); @@ -1046,9 +1042,6 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder && intent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, -1) == VideoProfile.STATE_BIDIRECTIONAL) { Logger.get(context).logImpression(DialerImpression.Type.IMS_VIDEO_REQUESTED_FROM_CALL_LOG); - } else if (intent.filterEquals( - DuoComponent.get(context).getDuo().getInstallDuoIntent().orNull())) { - Logger.get(context).logImpression(DialerImpression.Type.DUO_CALL_LOG_SET_UP_INSTALL); } DialerUtils.startActivityWithErrorToast(context, intent); @@ -1062,32 +1055,6 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder return false; } - private void startDuoActivity(Intent intent, Duo.IntentType intentType) { - switch (intentType) { - case CALL: - Logger.get(context) - .logImpression(DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FROM_CALL_LOG); - if (isNonContactEntry(info)) { - Logger.get(context) - .logImpression( - DialerImpression.Type.LIGHTBRINGER_NON_CONTACT_VIDEO_REQUESTED_FROM_CALL_LOG); - } - break; - case INVITE: - Logger.get(context).logImpression(DialerImpression.Type.DUO_CALL_LOG_INVITE); - break; - case ACTIVATE: - Logger.get(context).logImpression(DialerImpression.Type.DUO_CALL_LOG_SET_UP_ACTIVATE); - break; - } - try { - Activity activity = (Activity) context; - activity.startActivityForResult(intent, ActivityRequestCodes.DIALTACTS_DUO); - } catch (ActivityNotFoundException e) { - Toast.makeText(context, R.string.activity_not_available, Toast.LENGTH_SHORT).show(); - } - } - private DialerContact buildContact() { DialerContact.Builder contact = DialerContact.newBuilder(); contact.setPhotoId(info.photoId); diff --git a/java/com/android/dialer/app/calllog/IntentProvider.java b/java/com/android/dialer/app/calllog/IntentProvider.java index 1bc726f64..21f341815 100644 --- a/java/com/android/dialer/app/calllog/IntentProvider.java +++ b/java/com/android/dialer/app/calllog/IntentProvider.java @@ -32,6 +32,8 @@ import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.dialercontact.DialerContact; import com.android.dialer.duo.DuoComponent; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.logging.Logger; import com.android.dialer.precall.PreCall; import com.android.dialer.util.IntentUtil; import java.util.ArrayList; @@ -93,11 +95,26 @@ public abstract class IntentProvider { }; } - public static IntentProvider getDuoVideoIntentProvider(String number) { + public static IntentProvider getDuoVideoIntentProvider(String number, boolean isNonContact) { return new IntentProvider() { @Override public Intent getIntent(Context context) { - return DuoComponent.get(context).getDuo().getCallIntent(number).orNull(); + return PreCall.getIntent( + context, + new CallIntentBuilder(number, CallInitiationType.Type.CALL_LOG) + .setIsDuoCall(true) + .setIsVideoCall(true)); + } + + @Override + public void logInteraction(Context context) { + Logger.get(context) + .logImpression(DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FROM_CALL_LOG); + if (isNonContact) { + Logger.get(context) + .logImpression( + DialerImpression.Type.LIGHTBRINGER_NON_CONTACT_VIDEO_REQUESTED_FROM_CALL_LOG); + } } }; } @@ -108,6 +125,11 @@ public abstract class IntentProvider { public Intent getIntent(Context context) { return DuoComponent.get(context).getDuo().getInstallDuoIntent().orNull(); } + + @Override + public void logInteraction(Context context) { + Logger.get(context).logImpression(DialerImpression.Type.DUO_CALL_LOG_SET_UP_INSTALL); + } }; } @@ -117,6 +139,11 @@ public abstract class IntentProvider { public Intent getIntent(Context context) { return DuoComponent.get(context).getDuo().getActivateIntent().orNull(); } + + @Override + public void logInteraction(Context context) { + Logger.get(context).logImpression(DialerImpression.Type.DUO_CALL_LOG_SET_UP_ACTIVATE); + } }; } @@ -126,6 +153,11 @@ public abstract class IntentProvider { public Intent getIntent(Context context) { return DuoComponent.get(context).getDuo().getInviteIntent(number).orNull(); } + + @Override + public void logInteraction(Context context) { + Logger.get(context).logImpression(DialerImpression.Type.DUO_CALL_LOG_INVITE); + } }; } @@ -244,4 +276,6 @@ public abstract class IntentProvider { } public abstract Intent getIntent(Context context); + + public void logInteraction(Context context) {} } diff --git a/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java b/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java index 80a41919d..86a2676f5 100644 --- a/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java +++ b/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java @@ -19,7 +19,6 @@ package com.android.dialer.calldetails; import android.Manifest.permission; import android.annotation.SuppressLint; import android.app.Activity; -import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -35,7 +34,6 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.view.View; -import android.widget.Toast; import com.android.dialer.assisteddialing.ui.AssistedDialingSettingActivity; import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry; import com.android.dialer.callintent.CallInitiationType; @@ -48,9 +46,6 @@ import com.android.dialer.common.concurrent.DialerExecutor.Worker; import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.common.concurrent.UiListener; import com.android.dialer.common.database.Selection; -import com.android.dialer.constants.ActivityRequestCodes; -import com.android.dialer.duo.Duo; -import com.android.dialer.duo.DuoComponent; import com.android.dialer.enrichedcall.EnrichedCallComponent; import com.android.dialer.enrichedcall.EnrichedCallManager; import com.android.dialer.enrichedcall.historyquery.proto.HistoryResult; @@ -63,7 +58,6 @@ import com.android.dialer.postcall.PostCall; import com.android.dialer.precall.PreCall; import com.android.dialer.rtt.RttTranscriptActivity; import com.android.dialer.rtt.RttTranscriptUtil; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.i18n.phonenumbers.NumberParseException; @@ -327,19 +321,11 @@ abstract class CallDetailsActivityCommon extends AppCompatActivity { public void placeDuoVideoCall(String phoneNumber) { Logger.get(getActivity()) .logImpression(DialerImpression.Type.CALL_DETAILS_LIGHTBRINGER_CALL_BACK); - Duo duo = DuoComponent.get(getActivity()).getDuo(); - Optional intentOptional = duo.getCallIntent(phoneNumber); - if (!duo.isReachable(getActivity(), phoneNumber) || !intentOptional.isPresent()) { - placeImsVideoCall(phoneNumber); - return; - } - - try { - getActivity() - .startActivityForResult(intentOptional.get(), ActivityRequestCodes.DIALTACTS_DUO); - } catch (ActivityNotFoundException e) { - Toast.makeText(getActivity(), R.string.activity_not_available, Toast.LENGTH_SHORT).show(); - } + PreCall.start( + getActivity(), + new CallIntentBuilder(phoneNumber, CallInitiationType.Type.CALL_DETAILS) + .setIsDuoCall(true) + .setIsVideoCall(true)); } @Override diff --git a/java/com/android/dialer/callintent/CallIntentBuilder.java b/java/com/android/dialer/callintent/CallIntentBuilder.java index 92efd392b..613fdf6a3 100644 --- a/java/com/android/dialer/callintent/CallIntentBuilder.java +++ b/java/com/android/dialer/callintent/CallIntentBuilder.java @@ -43,6 +43,7 @@ public class CallIntentBuilder implements Parcelable { private final CallSpecificAppData callSpecificAppData; @Nullable private PhoneAccountHandle phoneAccountHandle; private boolean isVideoCall; + private boolean isDuoCall; private String callSubject; private boolean allowAssistedDial; @@ -109,6 +110,7 @@ public class CallIntentBuilder implements Parcelable { callSpecificAppData = data; phoneAccountHandle = parcel.readParcelable(classLoader); isVideoCall = parcel.readInt() != 0; + isDuoCall = parcel.readInt() != 0; callSubject = parcel.readString(); allowAssistedDial = parcel.readInt() != 0; inCallUiIntentExtras.putAll(parcel.readBundle(classLoader)); @@ -152,6 +154,15 @@ public class CallIntentBuilder implements Parcelable { return isVideoCall; } + public CallIntentBuilder setIsDuoCall(boolean isDuoCall) { + this.isDuoCall = isDuoCall; + return this; + } + + public boolean isDuoCall() { + return isDuoCall; + } + /** Default false. Should only be set to true if the number has a lookup URI. */ public CallIntentBuilder setAllowAssistedDial(boolean allowAssistedDial) { this.allowAssistedDial = allowAssistedDial; @@ -267,6 +278,7 @@ public class CallIntentBuilder implements Parcelable { dest.writeByteArray(callSpecificAppData.toByteArray()); dest.writeParcelable(phoneAccountHandle, flags); dest.writeInt(isVideoCall ? 1 : 0); + dest.writeInt(isDuoCall ? 1 : 0); dest.writeString(callSubject); dest.writeInt(allowAssistedDial ? 1 : 0); dest.writeBundle(inCallUiIntentExtras); diff --git a/java/com/android/dialer/calllogutils/CallLogRowActions.java b/java/com/android/dialer/calllogutils/CallLogRowActions.java index d23a15f78..65f3c5fd6 100644 --- a/java/com/android/dialer/calllogutils/CallLogRowActions.java +++ b/java/com/android/dialer/calllogutils/CallLogRowActions.java @@ -20,6 +20,7 @@ import android.provider.CallLog.Calls; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.calllog.model.CoalescedRow; +import com.android.dialer.duo.DuoComponent; import com.android.dialer.precall.PreCall; /** Actions which can be performed on a call log row. */ @@ -37,6 +38,10 @@ public final class CallLogRowActions { activity, new CallIntentBuilder( row.getNumber().getNormalizedNumber(), CallInitiationType.Type.CALL_LOG) - .setIsVideoCall((row.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO)); + .setIsVideoCall((row.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) + .setIsDuoCall( + DuoComponent.get(activity) + .getDuo() + .isDuoAccount(row.getPhoneAccountComponentName()))); } } diff --git a/java/com/android/dialer/duo/Duo.java b/java/com/android/dialer/duo/Duo.java index 06a3db063..85fe9fbc1 100644 --- a/java/com/android/dialer/duo/Duo.java +++ b/java/com/android/dialer/duo/Duo.java @@ -27,6 +27,8 @@ import android.telecom.Call; import android.telecom.PhoneAccountHandle; import com.google.auto.value.AutoValue; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.ListenableFuture; import java.util.List; /** Interface for Duo video call integration. */ @@ -61,7 +63,8 @@ public interface Duo { /** Starts a task to update the reachability of the parameter numbers asynchronously. */ @MainThread - void updateReachability(@NonNull Context context, @NonNull List numbers); + ListenableFuture> updateReachability( + @NonNull Context context, @NonNull List numbers); /** * Clears the current reachability data and starts a task to load the latest reachability data @@ -95,19 +98,6 @@ public interface Duo { */ Optional getInviteIntent(String number); - /** Return value of {@link #getIntentType(Intent)} */ - enum IntentType { - /** The intent is returned by {@link #getCallIntent(String)} */ - CALL, - /** The intent is returned by {@link #getActivateIntent()} */ - ACTIVATE, - /** The intent is returned by {@link #getInviteIntent(String)} */ - INVITE - } - - /** Classifies a Duo intent. Absent if the intent is not a Duo intent. */ - Optional getIntentType(Intent intent); - Optional getInstallDuoIntent(); /** Requests upgrading the parameter ongoing call to a Duo video call. */ diff --git a/java/com/android/dialer/duo/PlaceDuoCallNotifier.java b/java/com/android/dialer/duo/PlaceDuoCallNotifier.java deleted file mode 100644 index 8fde981a0..000000000 --- a/java/com/android/dialer/duo/PlaceDuoCallNotifier.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2018 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.duo; - -import android.content.Context; -import android.content.Intent; -import android.support.v4.content.LocalBroadcastManager; -import com.android.dialer.common.LogUtil; - -/** Notifies that a Duo video call should be started. */ -public final class PlaceDuoCallNotifier { - - private PlaceDuoCallNotifier() {} - - /** - * Broadcasts an intent notifying that a Duo call should be started. - * - *

See {@link PlaceDuoCallReceiver} for how the intent is handled. - * - * @param phoneNumber The number to start a Duo call. It can be of any format. - */ - public static void notify(Context context, String phoneNumber) { - LogUtil.enterBlock("PlaceDuoCallNotifier.notify"); - - Intent intent = new Intent(); - intent.setAction(PlaceDuoCallReceiver.ACTION_START_DUO_CALL); - intent.putExtra(PlaceDuoCallReceiver.EXTRA_PHONE_NUMBER, phoneNumber); - - LocalBroadcastManager.getInstance(context).sendBroadcast(intent); - } -} diff --git a/java/com/android/dialer/duo/PlaceDuoCallReceiver.java b/java/com/android/dialer/duo/PlaceDuoCallReceiver.java deleted file mode 100644 index f504aef57..000000000 --- a/java/com/android/dialer/duo/PlaceDuoCallReceiver.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2018 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.duo; - -import android.app.Activity; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import com.android.dialer.common.Assert; -import com.android.dialer.common.LogUtil; -import com.android.dialer.constants.ActivityRequestCodes; - -/** A {@link BroadcastReceiver} that starts a Duo video call. */ -public final class PlaceDuoCallReceiver extends BroadcastReceiver { - - static final String ACTION_START_DUO_CALL = "start_duo_call"; - static final String EXTRA_PHONE_NUMBER = "phone_number"; - - /** - * {@link Activity} needed to launch Duo. - * - *

A Duo call can only be placed via {@link Activity#startActivityForResult(Intent, int)}. - */ - private final Activity activity; - - /** Returns an {@link IntentFilter} containing all actions accepted by this broadcast receiver. */ - public static IntentFilter getIntentFilter() { - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(ACTION_START_DUO_CALL); - return intentFilter; - } - - public PlaceDuoCallReceiver(Activity activity) { - this.activity = activity; - } - - @Override - public void onReceive(Context context, Intent intent) { - LogUtil.enterBlock("PlaceDuoCallReceiver.onReceive"); - - String action = intent.getAction(); - - switch (Assert.isNotNull(action)) { - case ACTION_START_DUO_CALL: - startDuoCall(context, intent); - break; - default: - throw new IllegalStateException("Unsupported action: " + action); - } - } - - private void startDuoCall(Context context, Intent intent) { - LogUtil.enterBlock("PlaceDuoCallReceiver.startDuoCall"); - - Assert.checkArgument(intent.hasExtra(EXTRA_PHONE_NUMBER)); - String phoneNumber = intent.getStringExtra(EXTRA_PHONE_NUMBER); - - Duo duo = DuoComponent.get(context).getDuo(); - activity.startActivityForResult( - duo.getCallIntent(phoneNumber).orNull(), ActivityRequestCodes.DIALTACTS_DUO); - } -} diff --git a/java/com/android/dialer/duo/stub/DuoStub.java b/java/com/android/dialer/duo/stub/DuoStub.java index b0867148f..2131d16f7 100644 --- a/java/com/android/dialer/duo/stub/DuoStub.java +++ b/java/com/android/dialer/duo/stub/DuoStub.java @@ -29,6 +29,9 @@ import com.android.dialer.common.Assert; import com.android.dialer.duo.Duo; import com.android.dialer.duo.DuoListener; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import java.util.List; import javax.inject.Inject; @@ -72,10 +75,12 @@ public class DuoStub implements Duo { } @Override - public void updateReachability(@NonNull Context context, @NonNull List numbers) { + public ListenableFuture> updateReachability( + @NonNull Context context, @NonNull List numbers) { Assert.isMainThread(); Assert.isNotNull(context); Assert.isNotNull(numbers); + return Futures.immediateFuture(ImmutableMap.of()); } @Override @@ -114,11 +119,6 @@ public class DuoStub implements Duo { return Optional.absent(); } - @Override - public Optional getIntentType(Intent intent) { - return Optional.absent(); - } - @Override public Optional getInstallDuoIntent() { return null; diff --git a/java/com/android/dialer/historyitemactions/DuoCallModule.java b/java/com/android/dialer/historyitemactions/DuoCallModule.java deleted file mode 100644 index e6f31e293..000000000 --- a/java/com/android/dialer/historyitemactions/DuoCallModule.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2018 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.historyitemactions; - -import android.Manifest.permission; -import android.content.Context; -import android.support.annotation.RequiresPermission; -import com.android.dialer.duo.PlaceDuoCallNotifier; - -/** {@link HistoryItemActionModule} for making a Duo call. */ -public class DuoCallModule implements HistoryItemActionModule { - - private final Context context; - private final String phoneNumber; - - /** - * Creates a module for making a Duo call. - * - * @param phoneNumber The number to start a Duo call. It can be of any format. - */ - public DuoCallModule(Context context, String phoneNumber) { - this.context = context; - this.phoneNumber = phoneNumber; - } - - @Override - public int getStringId() { - return R.string.video_call; - } - - @Override - public int getDrawableId() { - return R.drawable.quantum_ic_videocam_vd_white_24; - } - - @Override - @RequiresPermission(permission.READ_PHONE_STATE) - public boolean onClick() { - PlaceDuoCallNotifier.notify(context, phoneNumber); - return true; // Close the bottom sheet. - } -} diff --git a/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java b/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java index 5da56a127..e1c6c9666 100644 --- a/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java +++ b/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java @@ -149,18 +149,14 @@ public final class HistoryItemActionModulesBuilder { // Do not set PhoneAccountHandle so that regular PreCall logic will be used. The account used to // place or receive the call should be ignored for carrier video calls. // TODO(a bug): figure out the correct video call behavior - HistoryItemActionModule carrierVideoCallModule = - IntentModule.newCallModule( - context, - new CallIntentBuilder(moduleInfo.getNormalizedNumber(), getCallInitiationType()) - .setAllowAssistedDial(moduleInfo.getCanSupportAssistedDialing()) - .setIsVideoCall(true)); - HistoryItemActionModule duoVideoCallModule = - new DuoCallModule(context, moduleInfo.getNormalizedNumber()); + CallIntentBuilder callIntentBuilder = + new CallIntentBuilder(moduleInfo.getNormalizedNumber(), getCallInitiationType()) + .setAllowAssistedDial(moduleInfo.getCanSupportAssistedDialing()) + .setIsVideoCall(true); // If the module info is for a video call, add an appropriate video call module. if ((moduleInfo.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) { - modules.add(isDuoCall() && canPlaceDuoCall() ? duoVideoCallModule : carrierVideoCallModule); + modules.add(IntentModule.newCallModule(context, callIntentBuilder.setIsDuoCall(isDuoCall()))); return this; } @@ -169,9 +165,9 @@ public final class HistoryItemActionModulesBuilder { // // The carrier video call module takes precedence over the Duo module. if (canPlaceCarrierVideoCall()) { - modules.add(carrierVideoCallModule); + modules.add(IntentModule.newCallModule(context, callIntentBuilder)); } else if (canPlaceDuoCall()) { - modules.add(duoVideoCallModule); + modules.add(IntentModule.newCallModule(context, callIntentBuilder.setIsDuoCall(true))); } return this; } diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java index 3f660f56c..2046b048f 100644 --- a/java/com/android/dialer/main/impl/MainActivity.java +++ b/java/com/android/dialer/main/impl/MainActivity.java @@ -24,7 +24,6 @@ import com.android.dialer.blockreportspam.ShowBlockReportSpamDialogReceiver; import com.android.dialer.calllog.config.CallLogConfigComponent; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; -import com.android.dialer.duo.PlaceDuoCallReceiver; import com.android.dialer.interactions.PhoneNumberInteraction.DisambigDialogDismissedListener; import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorCode; import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorListener; @@ -48,9 +47,6 @@ public class MainActivity extends TransactionSafeActivity */ private ShowBlockReportSpamDialogReceiver showBlockReportSpamDialogReceiver; - /** {@link android.content.BroadcastReceiver} that starts a Duo call. */ - private PlaceDuoCallReceiver placeDuoCallReceiver; - public static Intent getShowCallLogIntent(Context context) { return getShowTabIntent(context, TabIndex.CALL_LOG); } @@ -83,7 +79,6 @@ public class MainActivity extends TransactionSafeActivity activePeer.onActivityCreate(savedInstanceState); showBlockReportSpamDialogReceiver = new ShowBlockReportSpamDialogReceiver(getFragmentManager()); - placeDuoCallReceiver = new PlaceDuoCallReceiver(/* activity = */ this); } protected MainActivityPeer getNewPeer() { @@ -109,8 +104,6 @@ public class MainActivity extends TransactionSafeActivity LocalBroadcastManager.getInstance(this) .registerReceiver( showBlockReportSpamDialogReceiver, ShowBlockReportSpamDialogReceiver.getIntentFilter()); - LocalBroadcastManager.getInstance(this) - .registerReceiver(placeDuoCallReceiver, PlaceDuoCallReceiver.getIntentFilter()); } @Override @@ -125,7 +118,6 @@ public class MainActivity extends TransactionSafeActivity activePeer.onActivityPause(); LocalBroadcastManager.getInstance(this).unregisterReceiver(showBlockReportSpamDialogReceiver); - LocalBroadcastManager.getInstance(this).unregisterReceiver(placeDuoCallReceiver); } @Override diff --git a/java/com/android/dialer/precall/PreCallCoordinator.java b/java/com/android/dialer/precall/PreCallCoordinator.java index 9c24e0d69..4d4859a80 100644 --- a/java/com/android/dialer/precall/PreCallCoordinator.java +++ b/java/com/android/dialer/precall/PreCallCoordinator.java @@ -68,8 +68,8 @@ public interface PreCallCoordinator { @NonNull PendingAction startPendingAction(); - void listen( - ListenableFuture future, - Consumer successListener, + void listen( + ListenableFuture future, + Consumer successListener, Consumer failureListener); } diff --git a/java/com/android/dialer/precall/impl/DuoAction.java b/java/com/android/dialer/precall/impl/DuoAction.java new file mode 100644 index 000000000..c05fbe12f --- /dev/null +++ b/java/com/android/dialer/precall/impl/DuoAction.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2018 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.precall.impl; + +import android.content.Context; +import android.content.Intent; +import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.common.LogUtil; +import com.android.dialer.common.concurrent.Annotations.Ui; +import com.android.dialer.duo.Duo.ReachabilityData; +import com.android.dialer.duo.DuoComponent; +import com.android.dialer.precall.PreCallAction; +import com.android.dialer.precall.PreCallCoordinator; +import com.android.dialer.precall.PreCallCoordinator.PendingAction; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import javax.inject.Inject; + +/** + * Checks if a duo call is actually callable, and request an activity for {@link + * android.app.Activity#startActivityForResult(Intent, int)} + */ +public class DuoAction implements PreCallAction { + + private final ListeningExecutorService uiExecutor; + + @Inject + DuoAction(@Ui ListeningExecutorService uiExecutor) { + this.uiExecutor = uiExecutor; + } + + @Override + public boolean requiresUi(Context context, CallIntentBuilder builder) { + // Duo call must be started with startActivityForResult() which needs a activity. + return builder.isDuoCall(); + } + + @Override + public void runWithoutUi(Context context, CallIntentBuilder builder) {} + + @Override + public void runWithUi(PreCallCoordinator coordinator) { + if (!requiresUi(coordinator.getActivity(), coordinator.getBuilder())) { + return; + } + String number = coordinator.getBuilder().getUri().getSchemeSpecificPart(); + ListenableFuture> reachabilities = + DuoComponent.get(coordinator.getActivity()) + .getDuo() + .updateReachability(coordinator.getActivity(), ImmutableList.of(number)); + PendingAction pendingAction = coordinator.startPendingAction(); + + Futures.addCallback( + reachabilities, + new FutureCallback>() { + @Override + public void onSuccess(ImmutableMap result) { + if (!result.containsKey(number) || !result.get(number).videoCallable()) { + LogUtil.w( + "DuoAction.runWithUi", + number + " number no longer duo reachable, falling back to carrier video call"); + coordinator.getBuilder().setIsDuoCall(false); + } + pendingAction.finish(); + } + + @Override + public void onFailure(Throwable throwable) { + LogUtil.e("DuoAction.runWithUi", "reachability query failed", throwable); + coordinator.getBuilder().setIsDuoCall(false); + pendingAction.finish(); + } + }, + uiExecutor); + } + + @Override + public void onDiscard() {} +} diff --git a/java/com/android/dialer/precall/impl/PreCallCoordinatorImpl.java b/java/com/android/dialer/precall/impl/PreCallCoordinatorImpl.java index f2ff0e3e3..240549ca5 100644 --- a/java/com/android/dialer/precall/impl/PreCallCoordinatorImpl.java +++ b/java/com/android/dialer/precall/impl/PreCallCoordinatorImpl.java @@ -26,6 +26,7 @@ import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.common.concurrent.UiListener; +import com.android.dialer.duo.DuoComponent; import com.android.dialer.function.Consumer; import com.android.dialer.logging.DialerImpression.Type; import com.android.dialer.logging.Logger; @@ -33,6 +34,7 @@ import com.android.dialer.precall.PreCallAction; import com.android.dialer.precall.PreCallComponent; import com.android.dialer.precall.PreCallCoordinator; import com.android.dialer.telecom.TelecomUtil; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -101,7 +103,7 @@ public class PreCallCoordinatorImpl implements PreCallCoordinator { LogUtil.enterBlock("PreCallCoordinatorImpl.runNextAction"); Assert.checkArgument(currentAction == null); if (currentActionIndex >= actions.size()) { - TelecomUtil.placeCall(activity, builder.build()); + placeCall(); activity.finish(); return; } @@ -177,4 +179,20 @@ public class PreCallCoordinatorImpl implements PreCallCoordinator { output -> successListener.accept((OutputT) output), failureListener::accept); } + + private void placeCall() { + if (builder.isDuoCall()) { + Optional intent = + DuoComponent.get(activity) + .getDuo() + .getCallIntent(builder.getUri().getSchemeSpecificPart()); + if (intent.isPresent()) { + activity.startActivityForResult(intent.get(), 0); + return; + } else { + LogUtil.e("PreCallCoordinatorImpl.placeCall", "duo.getCallIntent() returned absent"); + } + } + TelecomUtil.placeCall(activity, builder.build()); + } } diff --git a/java/com/android/dialer/precall/impl/PreCallModule.java b/java/com/android/dialer/precall/impl/PreCallModule.java index 9820e2b66..455453ef3 100644 --- a/java/com/android/dialer/precall/impl/PreCallModule.java +++ b/java/com/android/dialer/precall/impl/PreCallModule.java @@ -37,12 +37,13 @@ public abstract class PreCallModule { @Provides @Singleton public static ImmutableList provideActions( - CallingAccountSelector callingAccountSelector) { + DuoAction duoAction, CallingAccountSelector callingAccountSelector) { return ImmutableList.of( new PermissionCheckAction(), new MalformedNumberRectifier( ImmutableList.of(new UkRegionPrefixInInternationalFormatHandler())), callingAccountSelector, + duoAction, new AssistedDialAction()); } } diff --git a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java index f1eed91ba..abb3aecd4 100644 --- a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java +++ b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java @@ -51,9 +51,7 @@ import com.android.dialer.common.Assert; import com.android.dialer.common.FragmentUtils; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.ThreadUtil; -import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.dialercontact.DialerContact; -import com.android.dialer.duo.DuoComponent; import com.android.dialer.enrichedcall.EnrichedCallComponent; import com.android.dialer.enrichedcall.EnrichedCallManager.CapabilitiesListener; import com.android.dialer.logging.DialerImpression; @@ -549,8 +547,11 @@ public final class NewSearchFragment extends Fragment public void placeDuoCall(String phoneNumber) { Logger.get(getContext()) .logImpression(DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FROM_SEARCH); - Intent intent = DuoComponent.get(getContext()).getDuo().getCallIntent(phoneNumber).orNull(); - getActivity().startActivityForResult(intent, ActivityRequestCodes.DIALTACTS_DUO); + PreCall.start( + getContext(), + new CallIntentBuilder(phoneNumber, CallInitiationType.Type.REGULAR_SEARCH) + .setIsVideoCall(true) + .setIsDuoCall(true)); FragmentUtils.getParentUnsafe(this, SearchFragmentListener.class).onCallPlacedFromSearch(); } diff --git a/java/com/android/dialer/speeddial/DisambigDialog.java b/java/com/android/dialer/speeddial/DisambigDialog.java index 98fc992f8..2dd43fa0a 100644 --- a/java/com/android/dialer/speeddial/DisambigDialog.java +++ b/java/com/android/dialer/speeddial/DisambigDialog.java @@ -18,7 +18,6 @@ package com.android.dialer.speeddial; import android.app.Dialog; import android.content.Context; -import android.content.Intent; import android.os.Bundle; import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; @@ -40,8 +39,6 @@ import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.DefaultFutureCallback; import com.android.dialer.common.concurrent.DialerExecutorComponent; -import com.android.dialer.constants.ActivityRequestCodes; -import com.android.dialer.duo.DuoComponent; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; import com.android.dialer.precall.PreCall; @@ -184,16 +181,13 @@ public class DisambigDialog extends DialogFragment { Logger.get(getContext()) .logImpression( DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FOR_FAVORITE_CONTACT_DISAMBIG); - Intent intent = - DuoComponent.get(getContext()).getDuo().getCallIntent(channel.number()).orNull(); - getActivity().startActivityForResult(intent, ActivityRequestCodes.DIALTACTS_DUO); - return; } PreCall.start( getContext(), new CallIntentBuilder(channel.number(), CallInitiationType.Type.SPEED_DIAL) - .setIsVideoCall(true)); + .setIsVideoCall(true) + .setIsDuoCall(channel.technology() == Channel.DUO)); dismiss(); } diff --git a/java/com/android/dialer/speeddial/SpeedDialFragment.java b/java/com/android/dialer/speeddial/SpeedDialFragment.java index aa306d214..fac9a13d2 100644 --- a/java/com/android/dialer/speeddial/SpeedDialFragment.java +++ b/java/com/android/dialer/speeddial/SpeedDialFragment.java @@ -41,7 +41,6 @@ import com.android.dialer.common.concurrent.DefaultFutureCallback; import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.common.concurrent.SupportUiListener; import com.android.dialer.constants.ActivityRequestCodes; -import com.android.dialer.duo.DuoComponent; import com.android.dialer.historyitemactions.DividerModule; import com.android.dialer.historyitemactions.HistoryItemActionBottomSheet; import com.android.dialer.historyitemactions.HistoryItemActionModule; @@ -243,16 +242,13 @@ public class SpeedDialFragment extends Fragment { if (channel.technology() == Channel.DUO) { Logger.get(activity) .logImpression(DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FOR_FAVORITE_CONTACT); - Intent intent = - DuoComponent.get(activity).getDuo().getCallIntent(channel.number()).orNull(); - activity.startActivityForResult(intent, ActivityRequestCodes.DIALTACTS_DUO); - return; } PreCall.start( activity, new CallIntentBuilder(channel.number(), CallInitiationType.Type.SPEED_DIAL) - .setIsVideoCall(channel.isVideoTechnology())); + .setIsVideoCall(channel.isVideoTechnology()) + .setIsDuoCall(channel.technology() == Channel.DUO)); } @Override @@ -341,15 +337,12 @@ public class SpeedDialFragment extends Fragment { Logger.get(getContext()) .logImpression( DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FOR_SUGGESTED_CONTACT); - Intent intent = - DuoComponent.get(getContext()).getDuo().getCallIntent(channel.number()).orNull(); - getActivity().startActivityForResult(intent, ActivityRequestCodes.DIALTACTS_DUO); - return; } PreCall.start( getContext(), new CallIntentBuilder(channel.number(), CallInitiationType.Type.SPEED_DIAL) - .setIsVideoCall(channel.isVideoTechnology())); + .setIsVideoCall(channel.isVideoTechnology()) + .setIsDuoCall(channel.technology() == Channel.DUO)); } private final class StarContactModule implements HistoryItemActionModule { @@ -426,15 +419,12 @@ public class SpeedDialFragment extends Fragment { if (channel.technology() == Channel.DUO) { Logger.get(activity) .logImpression(DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FOR_FAVORITE_CONTACT); - Intent intent = - DuoComponent.get(activity).getDuo().getCallIntent(channel.number()).orNull(); - activity.startActivityForResult(intent, ActivityRequestCodes.DIALTACTS_DUO); - return; } PreCall.start( activity, new CallIntentBuilder(channel.number(), CallInitiationType.Type.SPEED_DIAL) - .setIsVideoCall(channel.isVideoTechnology())); + .setIsVideoCall(channel.isVideoTechnology()) + .setIsDuoCall(channel.technology() == Channel.DUO)); } @Override -- cgit v1.2.3