From 27c3718f9e3c3297376cfa45f6a67d83a4bb7bcc Mon Sep 17 00:00:00 2001 From: twyen Date: Tue, 24 Apr 2018 11:48:12 -0700 Subject: Expose active calls from in call UI Dual SIM features need to know what phone account the current call is using because usually only one SIM can be in a call at the same time. TEST=TAP Bug: 69675796,72618783 Test: TAP PiperOrigin-RevId: 194121273 Change-Id: I512eb7aca2050f38449b0a911dea9cee9b5ffdb5 --- .../android/dialer/activecalls/ActiveCallInfo.java | 48 ++++++++++++++ .../android/dialer/activecalls/ActiveCalls.java | 34 ++++++++++ .../dialer/activecalls/ActiveCallsComponent.java | 40 ++++++++++++ .../dialer/activecalls/ActiveCallsModule.java | 34 ++++++++++ .../dialer/activecalls/impl/ActiveCallsImpl.java | 45 +++++++++++++ .../binary/aosp/AospDialerRootComponent.java | 2 + .../basecomponent/BaseDialerRootComponent.java | 4 +- .../google/GoogleStubDialerRootComponent.java | 2 + .../dialer/commandline/CommandLineModule.java | 7 ++- .../commandline/impl/ActiveCallsCommand.java | 67 ++++++++++++++++++++ .../incallui/ActiveCallsCallListListener.java | 73 ++++++++++++++++++++++ java/com/android/incallui/InCallPresenter.java | 4 ++ java/com/android/incallui/call/DialerCall.java | 2 +- 13 files changed, 359 insertions(+), 3 deletions(-) create mode 100644 java/com/android/dialer/activecalls/ActiveCallInfo.java create mode 100644 java/com/android/dialer/activecalls/ActiveCalls.java create mode 100644 java/com/android/dialer/activecalls/ActiveCallsComponent.java create mode 100644 java/com/android/dialer/activecalls/ActiveCallsModule.java create mode 100644 java/com/android/dialer/activecalls/impl/ActiveCallsImpl.java create mode 100644 java/com/android/dialer/commandline/impl/ActiveCallsCommand.java create mode 100644 java/com/android/incallui/ActiveCallsCallListListener.java (limited to 'java') diff --git a/java/com/android/dialer/activecalls/ActiveCallInfo.java b/java/com/android/dialer/activecalls/ActiveCallInfo.java new file mode 100644 index 000000000..d4f76b393 --- /dev/null +++ b/java/com/android/dialer/activecalls/ActiveCallInfo.java @@ -0,0 +1,48 @@ +/* + * 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.activecalls; + +import android.support.annotation.Nullable; +import android.telecom.PhoneAccountHandle; +import com.google.auto.value.AutoValue; +import com.google.common.base.Optional; + +/** Info of an active call */ +@AutoValue +@SuppressWarnings("Guava") +public abstract class ActiveCallInfo { + + /** The {@link PhoneAccountHandle} the call is made with */ + public abstract Optional phoneAccountHandle(); + + public static Builder builder() { + return new AutoValue_ActiveCallInfo.Builder(); + } + + /** Builder for {@link ActiveCallInfo}. Only In Call UI should create ActiveCallInfo */ + @AutoValue.Builder + public abstract static class Builder { + + public Builder setPhoneAccountHandle(@Nullable PhoneAccountHandle phoneAccountHandle) { + return setPhoneAccountHandle(Optional.fromNullable(phoneAccountHandle)); + } + + public abstract Builder setPhoneAccountHandle(Optional phoneAccountHandle); + + public abstract ActiveCallInfo build(); + } +} diff --git a/java/com/android/dialer/activecalls/ActiveCalls.java b/java/com/android/dialer/activecalls/ActiveCalls.java new file mode 100644 index 000000000..600839c73 --- /dev/null +++ b/java/com/android/dialer/activecalls/ActiveCalls.java @@ -0,0 +1,34 @@ +/* + * 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.activecalls; + +import android.support.annotation.MainThread; +import com.google.common.collect.ImmutableList; + +/** Exposes information about current active calls to the whole dialer. */ +public interface ActiveCalls { + + /** + * Return a list of current active calls. Any call that is not disconnected is regarded as active. + * Ordering of elements are not guaranteed. + */ + ImmutableList getActiveCalls(); + + /** Should only be called by in call UI. */ + @MainThread + void setActiveCalls(ImmutableList activeCalls); +} diff --git a/java/com/android/dialer/activecalls/ActiveCallsComponent.java b/java/com/android/dialer/activecalls/ActiveCallsComponent.java new file mode 100644 index 000000000..99e0e9493 --- /dev/null +++ b/java/com/android/dialer/activecalls/ActiveCallsComponent.java @@ -0,0 +1,40 @@ +/* + * 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.activecalls; + +import android.content.Context; +import com.android.dialer.inject.HasRootComponent; +import com.android.dialer.inject.IncludeInDialerRoot; +import dagger.Subcomponent; + +/** Component for {@link ActiveCalls} */ +@Subcomponent +public abstract class ActiveCallsComponent { + + public abstract ActiveCalls activeCalls(); + + public static ActiveCallsComponent get(Context context) { + return ((HasComponent) ((HasRootComponent) context.getApplicationContext()).component()) + .activeCallsComponent(); + } + + /** Used to refer to the root application component. */ + @IncludeInDialerRoot + public interface HasComponent { + ActiveCallsComponent activeCallsComponent(); + } +} diff --git a/java/com/android/dialer/activecalls/ActiveCallsModule.java b/java/com/android/dialer/activecalls/ActiveCallsModule.java new file mode 100644 index 000000000..4d7f44858 --- /dev/null +++ b/java/com/android/dialer/activecalls/ActiveCallsModule.java @@ -0,0 +1,34 @@ +/* + * 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.activecalls; + +import com.android.dialer.activecalls.impl.ActiveCallsImpl; +import com.android.dialer.inject.DialerVariant; +import com.android.dialer.inject.InstallIn; +import dagger.Binds; +import dagger.Module; +import javax.inject.Singleton; + +/** Module for {@link ActiveCallsComponent} */ +@Module +@InstallIn(variants = DialerVariant.DIALER_TEST) // TODO(weijiaxu): put all variants. +public abstract class ActiveCallsModule { + + @Singleton + @Binds + public abstract ActiveCalls to(ActiveCallsImpl impl); +} diff --git a/java/com/android/dialer/activecalls/impl/ActiveCallsImpl.java b/java/com/android/dialer/activecalls/impl/ActiveCallsImpl.java new file mode 100644 index 000000000..3449cc8b0 --- /dev/null +++ b/java/com/android/dialer/activecalls/impl/ActiveCallsImpl.java @@ -0,0 +1,45 @@ +/* + * 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.activecalls.impl; + +import android.support.annotation.MainThread; +import com.android.dialer.activecalls.ActiveCallInfo; +import com.android.dialer.activecalls.ActiveCalls; +import com.android.dialer.common.Assert; +import com.google.common.collect.ImmutableList; +import javax.inject.Inject; + +/** Implementation of {@link ActiveCalls} */ +public class ActiveCallsImpl implements ActiveCalls { + + ImmutableList activeCalls = ImmutableList.of(); + + @Inject + ActiveCallsImpl() {} + + @Override + public ImmutableList getActiveCalls() { + return activeCalls; + } + + @Override + @MainThread + public void setActiveCalls(ImmutableList activeCalls) { + Assert.isMainThread(); + this.activeCalls = Assert.isNotNull(activeCalls); + } +} diff --git a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java index 21a282ded..e1021894f 100644 --- a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java +++ b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java @@ -17,6 +17,7 @@ package com.android.dialer.binary.aosp; import com.android.bubble.stub.StubBubbleModule; +import com.android.dialer.activecalls.ActiveCallsModule; import com.android.dialer.binary.basecomponent.BaseDialerRootComponent; import com.android.dialer.calllog.CallLogModule; import com.android.dialer.calllog.config.CallLogConfigModule; @@ -49,6 +50,7 @@ import javax.inject.Singleton; @Singleton @Component( modules = { + ActiveCallsModule.class, CallLogModule.class, CallLogConfigModule.class, CommandLineModule.class, diff --git a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java index 11e952cbc..75ddaf7f0 100644 --- a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java +++ b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java @@ -17,6 +17,7 @@ package com.android.dialer.binary.basecomponent; import com.android.bubble.BubbleComponent; +import com.android.dialer.activecalls.ActiveCallsComponent; import com.android.dialer.calllog.CallLogComponent; import com.android.dialer.calllog.config.CallLogConfigComponent; import com.android.dialer.calllog.database.CallLogDatabaseComponent; @@ -50,7 +51,8 @@ import com.android.voicemail.VoicemailComponent; * from this component. */ public interface BaseDialerRootComponent - extends BluetoothDeviceProviderComponent.HasComponent, + extends ActiveCallsComponent.HasComponent, + BluetoothDeviceProviderComponent.HasComponent, BubbleComponent.HasComponent, CallLocationComponent.HasComponent, CallLogComponent.HasComponent, diff --git a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java index 0da2f9577..bdbdeb9dd 100644 --- a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java +++ b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java @@ -17,6 +17,7 @@ package com.android.dialer.binary.google; import com.android.bubble.stub.StubBubbleModule; +import com.android.dialer.activecalls.ActiveCallsModule; import com.android.dialer.binary.basecomponent.BaseDialerRootComponent; import com.android.dialer.calllog.CallLogModule; import com.android.dialer.calllog.config.CallLogConfigModule; @@ -52,6 +53,7 @@ import javax.inject.Singleton; @Singleton @Component( modules = { + ActiveCallsModule.class, CallLocationModule.class, CallLogModule.class, CallLogConfigModule.class, diff --git a/java/com/android/dialer/commandline/CommandLineModule.java b/java/com/android/dialer/commandline/CommandLineModule.java index 915578722..c78de21e5 100644 --- a/java/com/android/dialer/commandline/CommandLineModule.java +++ b/java/com/android/dialer/commandline/CommandLineModule.java @@ -16,6 +16,7 @@ package com.android.dialer.commandline; +import com.android.dialer.commandline.impl.ActiveCallsCommand; import com.android.dialer.commandline.impl.BlockingCommand; import com.android.dialer.commandline.impl.CallCommand; import com.android.dialer.commandline.impl.Echo; @@ -45,6 +46,7 @@ public abstract class CommandLineModule { private final Echo echo; private final BlockingCommand blockingCommand; private final CallCommand callCommand; + private final ActiveCallsCommand activeCallsCommand; @Inject AospCommandInjector( @@ -52,12 +54,14 @@ public abstract class CommandLineModule { Version version, Echo echo, BlockingCommand blockingCommand, - CallCommand callCommand) { + CallCommand callCommand, + ActiveCallsCommand activeCallsCommand) { this.help = help; this.version = version; this.echo = echo; this.blockingCommand = blockingCommand; this.callCommand = callCommand; + this.activeCallsCommand = activeCallsCommand; } public CommandSupplier.Builder inject(CommandSupplier.Builder builder) { @@ -66,6 +70,7 @@ public abstract class CommandLineModule { builder.addCommand("echo", echo); builder.addCommand("blocking", blockingCommand); builder.addCommand("call", callCommand); + builder.addCommand("activecalls", activeCallsCommand); return builder; } } diff --git a/java/com/android/dialer/commandline/impl/ActiveCallsCommand.java b/java/com/android/dialer/commandline/impl/ActiveCallsCommand.java new file mode 100644 index 000000000..81641ed50 --- /dev/null +++ b/java/com/android/dialer/commandline/impl/ActiveCallsCommand.java @@ -0,0 +1,67 @@ +/* + * 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.commandline.impl; + +import android.content.Context; +import android.support.annotation.NonNull; +import com.android.dialer.activecalls.ActiveCallsComponent; +import com.android.dialer.commandline.Arguments; +import com.android.dialer.commandline.Command; +import com.android.dialer.inject.ApplicationContext; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import javax.inject.Inject; + +/** Manipulates {@link com.android.dialer.activecalls.ActiveCalls} */ +public class ActiveCallsCommand implements Command { + + private final Context appContext; + + @Inject + ActiveCallsCommand(@ApplicationContext Context appContext) { + this.appContext = appContext; + } + + @NonNull + @Override + public String getShortDescription() { + return "manipulate active calls"; + } + + @NonNull + @Override + public String getUsage() { + return "activecalls list"; + } + + @Override + public ListenableFuture run(Arguments args) throws IllegalCommandLineArgumentException { + if (args.getPositionals().isEmpty()) { + return Futures.immediateFuture(getUsage()); + } + + String command = args.getPositionals().get(0); + + switch (command) { + case "list": + return Futures.immediateFuture( + ActiveCallsComponent.get(appContext).activeCalls().getActiveCalls().toString()); + default: + throw new IllegalCommandLineArgumentException("unknown command " + command); + } + } +} diff --git a/java/com/android/incallui/ActiveCallsCallListListener.java b/java/com/android/incallui/ActiveCallsCallListListener.java new file mode 100644 index 000000000..ce9f9a36d --- /dev/null +++ b/java/com/android/incallui/ActiveCallsCallListListener.java @@ -0,0 +1,73 @@ +/* + * 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.incallui; + +import android.content.Context; +import android.support.annotation.NonNull; +import com.android.dialer.activecalls.ActiveCallInfo; +import com.android.dialer.activecalls.ActiveCallsComponent; +import com.android.incallui.call.CallList; +import com.android.incallui.call.DialerCall; +import com.android.incallui.call.DialerCall.State; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; + +/** Updates {@link com.android.dialer.activecalls.ActiveCalls} */ +@SuppressWarnings("Guava") +public class ActiveCallsCallListListener implements CallList.Listener { + + private final Context appContext; + + ActiveCallsCallListListener(Context appContext) { + this.appContext = appContext; + } + + @Override + public void onIncomingCall(DialerCall call) {} + + @Override + public void onUpgradeToVideo(DialerCall call) {} + + @Override + public void onSessionModificationStateChange(DialerCall call) {} + + @Override + public void onCallListChange(CallList callList) { + ImmutableList.Builder activeCalls = ImmutableList.builder(); + for (DialerCall call : callList.getAllCalls()) { + if (call.getState() != State.DISCONNECTED) { + activeCalls.add( + ActiveCallInfo.builder() + .setPhoneAccountHandle(Optional.fromNullable(call.getAccountHandle())) + .build()); + } + } + ActiveCallsComponent.get(appContext).activeCalls().setActiveCalls(activeCalls.build()); + } + + @Override + public void onDisconnect(DialerCall call) {} + + @Override + public void onWiFiToLteHandover(DialerCall call) {} + + @Override + public void onHandoverToWifiFailed(DialerCall call) {} + + @Override + public void onInternationalCallOnWifi(@NonNull DialerCall call) {} +} diff --git a/java/com/android/incallui/InCallPresenter.java b/java/com/android/incallui/InCallPresenter.java index 5e08c6969..a67dab513 100644 --- a/java/com/android/incallui/InCallPresenter.java +++ b/java/com/android/incallui/InCallPresenter.java @@ -197,6 +197,7 @@ public class InCallPresenter implements CallList.Listener, AudioModeProvider.Aud private InCallCameraManager inCallCameraManager; private FilteredNumberAsyncQueryHandler filteredQueryHandler; private CallList.Listener spamCallListListener; + private CallList.Listener activeCallsListener; /** Whether or not we are currently bound and waiting for Telecom to send us a new call. */ private boolean boundAndWaitingForOutgoingCall; /** Determines if the InCall UI is in fullscreen mode or not. */ @@ -383,6 +384,8 @@ public class InCallPresenter implements CallList.Listener, AudioModeProvider.Aud new SpamCallListListener( context, DialerExecutorComponent.get(context).dialerExecutorFactory()); this.callList.addListener(spamCallListListener); + activeCallsListener = new ActiveCallsCallListListener(context); + this.callList.addListener(activeCallsListener); VideoPauseController.getInstance().setUp(this); @@ -858,6 +861,7 @@ public class InCallPresenter implements CallList.Listener, AudioModeProvider.Aud callList.getActiveOrBackgroundCall() != null || callList.getOutgoingCall() != null; inCallActivity.dismissKeyguard(hasCall); } + Trace.endSection(); } diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java index c153503ac..9dfe7abcb 100644 --- a/java/com/android/incallui/call/DialerCall.java +++ b/java/com/android/incallui/call/DialerCall.java @@ -157,7 +157,7 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa private String lastForwardedNumber; private boolean isCallForwarded; private String callSubject; - private PhoneAccountHandle phoneAccountHandle; + @Nullable private PhoneAccountHandle phoneAccountHandle; @CallHistoryStatus private int callHistoryStatus = CALL_HISTORY_STATUS_UNKNOWN; private boolean isSpam; private boolean isBlocked; -- cgit v1.2.3 From b47528e0ed4260fd72b163e2e5dfb0668ea5ca15 Mon Sep 17 00:00:00 2001 From: yueg Date: Tue, 24 Apr 2018 12:12:57 -0700 Subject: Show international call on wifi dialog without InCallActivity. Bug: 74022483 Test: InCallPresenterTest PiperOrigin-RevId: 194125192 Change-Id: Ie7c50554079fe3a0a23b18ac44fc81b913c3e619 --- java/com/android/incallui/InCallActivity.java | 42 +-------- java/com/android/incallui/InCallPresenter.java | 16 ++++ .../incallui/telecomeventui/AndroidManifest.xml | 13 ++- .../InternationalCallOnWifiDialogActivity.java | 101 +++++++++++++++++++++ .../InternationalCallOnWifiDialogFragment.java | 82 ++++++++--------- 5 files changed, 171 insertions(+), 83 deletions(-) create mode 100644 java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogActivity.java (limited to 'java') diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java index 91f557bd5..86799bfe4 100644 --- a/java/com/android/incallui/InCallActivity.java +++ b/java/com/android/incallui/InCallActivity.java @@ -129,9 +129,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity private static Optional audioRouteForTesting = Optional.absent(); - private final InternationalCallOnWifiCallback internationalCallOnWifiCallback = - new InternationalCallOnWifiCallback(); - private SelectPhoneAccountListener selectPhoneAccountListener; private Animation dialpadSlideInAnimation; @@ -245,13 +242,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity } } - InternationalCallOnWifiDialogFragment existingInternationalCallOnWifiDialogFragment = - (InternationalCallOnWifiDialogFragment) - getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI); - if (existingInternationalCallOnWifiDialogFragment != null) { - existingInternationalCallOnWifiDialogFragment.setCallback(internationalCallOnWifiCallback); - } - inCallOrientationEventListener = new InCallOrientationEventListener(this); getWindow() @@ -1201,16 +1191,8 @@ public class InCallActivity extends TransactionSafeFragmentActivity } public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) { - if (!InternationalCallOnWifiDialogFragment.shouldShow(this)) { - LogUtil.i( - "InCallActivity.showDialogForInternationalCallOnWifi", - "InternationalCallOnWifiDialogFragment.shouldShow returned false"); - return; - } - InternationalCallOnWifiDialogFragment fragment = - InternationalCallOnWifiDialogFragment.newInstance( - call.getId(), internationalCallOnWifiCallback); + InternationalCallOnWifiDialogFragment.newInstance(call.getId()); fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI); } @@ -1785,28 +1767,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled"; } - private static final class InternationalCallOnWifiCallback - implements InternationalCallOnWifiDialogFragment.Callback { - private static final String TAG = InternationalCallOnWifiCallback.class.getCanonicalName(); - - @Override - public void continueCall(@NonNull String callId) { - LogUtil.i(TAG, "Continuing call with ID: %s", callId); - } - - @Override - public void cancelCall(@NonNull String callId) { - DialerCall call = CallList.getInstance().getCallById(callId); - if (call == null) { - LogUtil.i(TAG, "Call destroyed before the dialog is closed"); - return; - } - - LogUtil.i(TAG, "Disconnecting international call on WiFi"); - call.disconnect(); - } - } - private static final class SelectPhoneAccountListener extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener { private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName(); diff --git a/java/com/android/incallui/InCallPresenter.java b/java/com/android/incallui/InCallPresenter.java index a67dab513..526cc64d3 100644 --- a/java/com/android/incallui/InCallPresenter.java +++ b/java/com/android/incallui/InCallPresenter.java @@ -71,6 +71,8 @@ import com.android.incallui.latencyreport.LatencyReport; import com.android.incallui.legacyblocking.BlockedNumberContentObserver; import com.android.incallui.spam.SpamCallListListener; import com.android.incallui.speakeasy.SpeakEasyCallManager; +import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogActivity; +import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment; import com.android.incallui.videosurface.bindings.VideoSurfaceBindings; import com.android.incallui.videosurface.protocol.VideoSurfaceTexture; import com.android.incallui.videotech.utils.VideoUtils; @@ -775,8 +777,22 @@ public class InCallPresenter implements CallList.Listener, AudioModeProvider.Aud @Override public void onInternationalCallOnWifi(@NonNull DialerCall call) { LogUtil.enterBlock("InCallPresenter.onInternationalCallOnWifi"); + + if (!InternationalCallOnWifiDialogFragment.shouldShow(context)) { + LogUtil.i( + "InCallPresenter.onInternationalCallOnWifi", + "InternationalCallOnWifiDialogFragment.shouldShow returned false"); + return; + } + if (inCallActivity != null) { inCallActivity.showDialogForInternationalCallOnWifi(call); + } else { + Intent intent = new Intent(context, InternationalCallOnWifiDialogActivity.class); + // Prevent showing MainActivity with InternationalCallOnWifiDialogActivity on above + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + intent.putExtra(InternationalCallOnWifiDialogActivity.EXTRA_CALL_ID, call.getId()); + context.startActivity(intent); } } diff --git a/java/com/android/incallui/telecomeventui/AndroidManifest.xml b/java/com/android/incallui/telecomeventui/AndroidManifest.xml index 861b9368a..a2134a3bd 100644 --- a/java/com/android/incallui/telecomeventui/AndroidManifest.xml +++ b/java/com/android/incallui/telecomeventui/AndroidManifest.xml @@ -12,4 +12,15 @@ See the License for the specific language governing permissions and limitations under the License. --> - \ No newline at end of file + + + + + diff --git a/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogActivity.java b/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogActivity.java new file mode 100644 index 000000000..192c1603a --- /dev/null +++ b/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogActivity.java @@ -0,0 +1,101 @@ +/* + * 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.incallui.telecomeventui; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import com.android.incallui.call.CallList; +import com.android.incallui.call.DialerCall; + +/** + * Activity containing dialog that may be shown when users place an outgoing call to an + * international number while on Wifi. + */ +public class InternationalCallOnWifiDialogActivity extends AppCompatActivity + implements CallList.Listener { + + public static final String EXTRA_CALL_ID = "extra_call_id"; + private static final String TAG_INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi"; + + private String callId; + + @Override + protected void onCreate(@Nullable Bundle bundle) { + super.onCreate(bundle); + + callId = getIntent().getStringExtra(EXTRA_CALL_ID); + if (TextUtils.isEmpty(callId)) { + finish(); + return; + } + + InternationalCallOnWifiDialogFragment fragment = + InternationalCallOnWifiDialogFragment.newInstance(callId); + fragment.show(getSupportFragmentManager(), TAG_INTERNATIONAL_CALL_ON_WIFI); + + CallList.getInstance().addListener(this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + CallList.getInstance().removeListener(this); + } + + @Override + protected void onPause() { + super.onPause(); + // We don't expect the activity to resume, except for orientation change. + if (!isChangingConfigurations()) { + finish(); + } + } + + @Override + public void onDisconnect(DialerCall call) { + if (callId.equals(call.getId())) { + finish(); + } + } + + @Override + public void onIncomingCall(DialerCall call) {} + + @Override + public void onUpgradeToVideo(DialerCall call) {} + + @Override + public void onUpgradeToRtt(DialerCall call, int rttRequestId) {} + + @Override + public void onSessionModificationStateChange(DialerCall call) {} + + @Override + public void onCallListChange(CallList callList) {} + + @Override + public void onWiFiToLteHandover(DialerCall call) {} + + @Override + public void onHandoverToWifiFailed(DialerCall call) {} + + @Override + public void onInternationalCallOnWifi(@NonNull DialerCall call) {} +} diff --git a/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogFragment.java b/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogFragment.java index 2b602f876..71a8be483 100644 --- a/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogFragment.java +++ b/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogFragment.java @@ -21,16 +21,18 @@ import android.app.Dialog; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.PreferenceManager; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.support.v4.app.DialogFragment; import android.support.v4.os.UserManagerCompat; import android.view.View; import android.widget.CheckBox; import com.android.dialer.common.Assert; +import com.android.dialer.common.FragmentUtils; import com.android.dialer.common.LogUtil; +import com.android.dialer.storage.StorageComponent; +import com.android.incallui.call.CallList; +import com.android.incallui.call.DialerCall; /** * Dialog that may be shown when users place an outgoing call to an international number while on @@ -53,35 +55,21 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment { return false; } - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences preferences = StorageComponent.get(context).unencryptedSharedPrefs(); boolean shouldShow = preferences.getBoolean(ALWAYS_SHOW_WARNING_PREFERENCE_KEY, true); LogUtil.i("InternationalCallOnWifiDialogFragment.shouldShow", "result: %b", shouldShow); return shouldShow; } - /** - * Called in response to user interaction with the {@link InternationalCallOnWifiDialogFragment}. - */ - public interface Callback { - - /** Indicates that the user wishes to proceed with the call represented by the given call id. */ - void continueCall(@NonNull String callId); - - /** Indicates that the user wishes to cancel the call represented by the given call id. */ - void cancelCall(@NonNull String callId); - } - /** * Returns a new instance of {@link InternationalCallOnWifiDialogFragment} with the given * callback. * *

Prefer this method over the default constructor. */ - public static InternationalCallOnWifiDialogFragment newInstance( - @NonNull String callId, @NonNull Callback callback) { + public static InternationalCallOnWifiDialogFragment newInstance(@NonNull String callId) { InternationalCallOnWifiDialogFragment fragment = new InternationalCallOnWifiDialogFragment(); - fragment.setCallback(callback); Bundle args = new Bundle(); args.putString(ARG_CALL_ID, Assert.isNotNull(callId)); fragment.setArguments(args); @@ -93,31 +81,12 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment { * InternationalCallOnWifiDialogFragment InternationalCallOnWifiDialogFragments}. */ @VisibleForTesting - static final String ALWAYS_SHOW_WARNING_PREFERENCE_KEY = + public static final String ALWAYS_SHOW_WARNING_PREFERENCE_KEY = "ALWAYS_SHOW_INTERNATIONAL_CALL_ON_WIFI_WARNING"; /** Key in the arguments bundle for call id. */ private static final String ARG_CALL_ID = "call_id"; - /** - * Callback which will receive information about user interactions with this dialog. - * - *

This is Nullable in the event that the dialog is destroyed by the framework, but doesn't - * have a callback reattached. Ideally, the InCallActivity would implement the callback and we - * would use FragmentUtils.getParentUnsafe instead of holding onto the callback here, but that's - * not possible with the existing InCallActivity/InCallActivityCommon implementation. - */ - @Nullable private Callback callback; - - /** - * Sets the callback for this dialog. - * - *

Used to reset the callback after state changes. - */ - public void setCallback(@NonNull Callback callback) { - this.callback = Assert.isNotNull(callback); - } - @NonNull @Override public Dialog onCreateDialog(Bundle bundle) { @@ -134,7 +103,7 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment { CheckBox alwaysWarn = dialogView.findViewById(R.id.always_warn); - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + SharedPreferences preferences = StorageComponent.get(getActivity()).unencryptedSharedPrefs(); // The default is set to false in this case to ensure that the first time the dialog opens, // the checkbox is unchecked. alwaysWarn.setChecked(preferences.getBoolean(ALWAYS_SHOW_WARNING_PREFERENCE_KEY, false)); @@ -163,7 +132,7 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment { preferences.edit().putBoolean(ALWAYS_SHOW_WARNING_PREFERENCE_KEY, alwaysWarn).apply(); // Neither callback nor callId are null in normal circumstances. See comments on callback - callback.continueCall(getArguments().getString(ARG_CALL_ID)); + continueCall(getArguments().getString(ARG_CALL_ID)); } private void onNegativeButtonClick(@NonNull SharedPreferences preferences, boolean alwaysWarn) { @@ -174,6 +143,37 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment { preferences.edit().putBoolean(ALWAYS_SHOW_WARNING_PREFERENCE_KEY, alwaysWarn).apply(); // Neither callback nor callId are null in normal circumstances. See comments on callback - callback.cancelCall(getArguments().getString(ARG_CALL_ID)); + cancelCall(getArguments().getString(ARG_CALL_ID)); + } + + private void continueCall(@NonNull String callId) { + LogUtil.i( + "InternationalCallOnWifiDialogFragment.continueCall", + "Continuing call with ID: %s", + callId); + InternationalCallOnWifiDialogActivity activity = + FragmentUtils.getParent(this, InternationalCallOnWifiDialogActivity.class); + if (activity != null) { + activity.finish(); + } + } + + private void cancelCall(@NonNull String callId) { + DialerCall call = CallList.getInstance().getCallById(callId); + if (call == null) { + LogUtil.i( + "InternationalCallOnWifiDialogFragment.cancelCall", + "Call destroyed before the dialog is closed"); + } else { + LogUtil.i( + "InternationalCallOnWifiDialogFragment.cancelCall", + "Disconnecting international call on WiFi"); + call.disconnect(); + } + InternationalCallOnWifiDialogActivity activity = + FragmentUtils.getParent(this, InternationalCallOnWifiDialogActivity.class); + if (activity != null) { + activity.finish(); + } } } -- cgit v1.2.3 From da39087e6271733b4a02393521db21d868c31324 Mon Sep 17 00:00:00 2001 From: wangqi Date: Tue, 24 Apr 2018 12:38:59 -0700 Subject: Log send button impressions for RTT call. Bug: 78243122 Test: none PiperOrigin-RevId: 194128823 Change-Id: Ic886fd9c2236bbac4cbc884b7d777cea20451f0b --- java/com/android/dialer/logging/dialer_impression.proto | 6 +++++- java/com/android/incallui/rtt/impl/RttChatFragment.java | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'java') diff --git a/java/com/android/dialer/logging/dialer_impression.proto b/java/com/android/dialer/logging/dialer_impression.proto index 5d40bb1ea..c6c93eee6 100644 --- a/java/com/android/dialer/logging/dialer_impression.proto +++ b/java/com/android/dialer/logging/dialer_impression.proto @@ -12,7 +12,7 @@ message DialerImpression { // Event enums to be used for Impression Logging in Dialer. // It's perfectly acceptable for this enum to be large // Values should be from 1000 to 100000. - // Next Tag: 1387 + // Next Tag: 1389 enum Type { UNKNOWN_AOSP_EVENT_TYPE = 1000; @@ -764,5 +764,9 @@ message DialerImpression { RTT_MID_CALL_ACCEPTED = 1385; // Mid call RTT request rejected. RTT_MID_CALL_REJECTED = 1386; + + // Send button clicked in RTT call, this includes send button on keyboard. + RTT_SEND_BUTTON_CLICKED = 1387; + RTT_KEYBOARD_SEND_BUTTON_CLICKED = 1388; } } diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java index 2d70b6b12..7bfa100ea 100644 --- a/java/com/android/incallui/rtt/impl/RttChatFragment.java +++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java @@ -49,6 +49,8 @@ import com.android.dialer.common.FragmentUtils; import com.android.dialer.common.LogUtil; import com.android.dialer.common.UiUtil; import com.android.dialer.lettertile.LetterTileDrawable; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.logging.Logger; import com.android.dialer.rtt.RttTranscript; import com.android.dialer.rtt.RttTranscriptMessage; import com.android.dialer.util.DrawableConverter; @@ -219,6 +221,7 @@ public class RttChatFragment extends Fragment submitButton = view.findViewById(R.id.rtt_chat_submit_button); submitButton.setOnClickListener( v -> { + Logger.get(getContext()).logImpression(DialerImpression.Type.RTT_SEND_BUTTON_CLICKED); adapter.submitLocalMessage(); resumeInput(""); rttCallScreenDelegate.onLocalMessage(Constants.BUBBLE_BREAKER); @@ -254,6 +257,8 @@ public class RttChatFragment extends Fragment public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_SEND) { if (!TextUtils.isEmpty(editText.getText())) { + Logger.get(getContext()) + .logImpression(DialerImpression.Type.RTT_KEYBOARD_SEND_BUTTON_CLICKED); submitButton.performClick(); } return true; -- cgit v1.2.3 From 05d17bda619dfdb7a729959dad098c10d67f84c8 Mon Sep 17 00:00:00 2001 From: linyuh Date: Tue, 24 Apr 2018 13:09:55 -0700 Subject: Add skeleton for CequintPhoneLookup Bug: 70989584 Test: CequintPhoneLookupTest PiperOrigin-RevId: 194133375 Change-Id: I10fb22c0c92b2d79f4d8287316e7a0373c09a72e --- .../dialer/phonelookup/PhoneLookupModule.java | 3 + .../phonelookup/cequint/CequintPhoneLookup.java | 90 ++++++++++++++++++++++ .../dialer/phonelookup/phone_lookup_info.proto | 14 +++- 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java (limited to 'java') diff --git a/java/com/android/dialer/phonelookup/PhoneLookupModule.java b/java/com/android/dialer/phonelookup/PhoneLookupModule.java index 86e6991c1..c6e91c4a4 100644 --- a/java/com/android/dialer/phonelookup/PhoneLookupModule.java +++ b/java/com/android/dialer/phonelookup/PhoneLookupModule.java @@ -17,6 +17,7 @@ package com.android.dialer.phonelookup; import com.android.dialer.phonelookup.blockednumber.SystemBlockedNumberPhoneLookup; +import com.android.dialer.phonelookup.cequint.CequintPhoneLookup; import com.android.dialer.phonelookup.cnap.CnapPhoneLookup; import com.android.dialer.phonelookup.cp2.Cp2DefaultDirectoryPhoneLookup; import com.android.dialer.phonelookup.cp2.Cp2ExtendedDirectoryPhoneLookup; @@ -32,12 +33,14 @@ public abstract class PhoneLookupModule { @Provides @SuppressWarnings({"unchecked", "rawtype"}) static ImmutableList providePhoneLookupList( + CequintPhoneLookup cequintPhoneLookup, CnapPhoneLookup cnapPhoneLookup, Cp2DefaultDirectoryPhoneLookup cp2DefaultDirectoryPhoneLookup, Cp2ExtendedDirectoryPhoneLookup cp2ExtendedDirectoryPhoneLookup, SystemBlockedNumberPhoneLookup systemBlockedNumberPhoneLookup, SpamPhoneLookup spamPhoneLookup) { return ImmutableList.of( + cequintPhoneLookup, cnapPhoneLookup, cp2DefaultDirectoryPhoneLookup, cp2ExtendedDirectoryPhoneLookup, diff --git a/java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java b/java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java new file mode 100644 index 000000000..ce2cd18ad --- /dev/null +++ b/java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java @@ -0,0 +1,90 @@ +/* + * 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.phonelookup.cequint; + +import android.content.Context; +import android.telecom.Call; +import com.android.dialer.DialerPhoneNumber; +import com.android.dialer.phonelookup.PhoneLookup; +import com.android.dialer.phonelookup.PhoneLookupInfo; +import com.android.dialer.phonelookup.PhoneLookupInfo.CequintInfo; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import javax.inject.Inject; + +/** PhoneLookup implementation for Cequint. */ +public class CequintPhoneLookup implements PhoneLookup { + + @Inject + CequintPhoneLookup() {} + + @Override + public ListenableFuture lookup(Context appContext, Call call) { + // TODO(a bug): Override the default implementation in the PhoneLookup interface + // as a Cequint lookup requires info in the provided call. + return Futures.immediateFuture(CequintInfo.getDefaultInstance()); + } + + @Override + public ListenableFuture lookup(DialerPhoneNumber dialerPhoneNumber) { + // TODO(a bug): Implement this method. + return Futures.immediateFuture(CequintInfo.getDefaultInstance()); + } + + @Override + public ListenableFuture isDirty(ImmutableSet phoneNumbers) { + return Futures.immediateFuture(false); + } + + @Override + public ListenableFuture> getMostRecentInfo( + ImmutableMap existingInfoMap) { + return Futures.immediateFuture(existingInfoMap); + } + + @Override + public void setSubMessage(PhoneLookupInfo.Builder destination, CequintInfo subMessage) { + destination.setCequintInfo(subMessage); + } + + @Override + public CequintInfo getSubMessage(PhoneLookupInfo phoneLookupInfo) { + return phoneLookupInfo.getCequintInfo(); + } + + @Override + public ListenableFuture onSuccessfulBulkUpdate() { + return Futures.immediateFuture(null); + } + + @Override + public void registerContentObservers() { + // No content observers for Cequint info. + } + + @Override + public void unregisterContentObservers() { + // No content observers for Cequint info. + } + + @Override + public ListenableFuture clearData() { + return Futures.immediateFuture(null); + } +} diff --git a/java/com/android/dialer/phonelookup/phone_lookup_info.proto b/java/com/android/dialer/phonelookup/phone_lookup_info.proto index 1beff6ca9..50817c4e3 100644 --- a/java/com/android/dialer/phonelookup/phone_lookup_info.proto +++ b/java/com/android/dialer/phonelookup/phone_lookup_info.proto @@ -14,7 +14,7 @@ package com.android.dialer.phonelookup; // "cp2_info_in_default_directory" corresponds to class // Cp2DefaultDirectoryPhoneLookup, and class Cp2DefaultDirectoryPhoneLookup // alone is responsible for populating it. -// Next ID: 8 +// Next ID: 9 message PhoneLookupInfo { // Information about a PhoneNumber retrieved from CP2. message Cp2Info { @@ -163,4 +163,16 @@ message PhoneLookupInfo { optional string name = 1; } optional CnapInfo cnap_info = 7; + + // Information obtained via Cequint + // Next ID: 4 + message CequintInfo { + optional string name = 1; + + // Description of the geolocation (e.g., "Mountain View, CA") + optional string geolocation = 2; + + optional string photo_uri = 3; + } + optional CequintInfo cequint_info = 8; } \ No newline at end of file -- cgit v1.2.3 From 66adad0ab9921afcf3aefab270c030ceee9888df Mon Sep 17 00:00:00 2001 From: twyen Date: Tue, 24 Apr 2018 13:51:08 -0700 Subject: Add "enabled" to SelectPhoneAccountDialogFragment. This is used to inform the user an account cannot be used right now. On most dual SIM devices, only a single SIM can make calls at the same time. The UI will be implemented in a followup CL. This CL also packs the parameters of SelectPhoneAccountDialogFragment into a proto. There are too many arguments and it needs structured representation. TEST=TAP Bug: 69675796,72618783 Test: TAP PiperOrigin-RevId: 194139636 Change-Id: I7d9f92c73b650654fff28ba625a2c8e3dfa0b96c --- .../widget/SelectPhoneAccountDialogFragment.java | 167 +++++++-------------- .../SelectPhoneAccountDialogOptionsUtil.java | 55 +++++++ .../select_phone_account_dialog_options.proto | 54 +++++++ .../dialer/dialpadview/SpecialCharSequenceMgr.java | 11 +- .../precall/impl/CallingAccountSelector.java | 33 ++-- .../suggestion/SuggestionProvider.java | 45 +++--- java/com/android/incallui/InCallActivity.java | 32 +++- 7 files changed, 235 insertions(+), 162 deletions(-) create mode 100644 java/com/android/contacts/common/widget/SelectPhoneAccountDialogOptionsUtil.java create mode 100644 java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto (limited to 'java') diff --git a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java index 295aa963a..e1fdd913b 100644 --- a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java +++ b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java @@ -47,10 +47,9 @@ import com.android.contacts.common.R; import com.android.contacts.common.compat.PhoneAccountCompat; import com.android.dialer.location.GeoUtil; import com.android.dialer.phonenumberutil.PhoneNumberHelper; +import com.android.dialer.protos.ProtoParsers; import com.android.dialer.telecom.TelecomUtil; import com.google.common.base.Optional; -import java.util.ArrayList; -import java.util.List; /** * Dialog that allows the user to select a phone accounts for a given action. Optionally provides @@ -58,128 +57,73 @@ import java.util.List; */ public class SelectPhoneAccountDialogFragment extends DialogFragment { - private static final String ARG_TITLE_RES_ID = "title_res_id"; - private static final String ARG_CAN_SET_DEFAULT = "can_set_default"; - private static final String ARG_SET_DEFAULT_RES_ID = "set_default_res_id"; - private static final String ARG_ACCOUNT_HANDLES = "account_handles"; + private static final String ARG_OPTIONS = "options"; private static final String ARG_IS_DEFAULT_CHECKED = "is_default_checked"; - private static final String ARG_LISTENER = "listener"; - private static final String ARG_CALL_ID = "call_id"; - private static final String ARG_HINTS = "hints"; - - private List mAccountHandles; - private List mHints; - private boolean mIsSelected; - private boolean mIsDefaultChecked; - private SelectPhoneAccountListener mListener; - - public SelectPhoneAccountDialogFragment() {} - - /** - * Create new fragment instance with default title and no option to set as default. - * - * @param accountHandles The {@code PhoneAccountHandle}s available to select from. - * @param listener The listener for the results of the account selection. - */ - public static SelectPhoneAccountDialogFragment newInstance( - List accountHandles, - SelectPhoneAccountListener listener, - @Nullable String callId) { - return newInstance( - R.string.select_account_dialog_title, false, 0, accountHandles, listener, callId, null); - } - /** - * Create new fragment instance. This method also allows specifying a custom title and "set - * default" checkbox. - * - * @param titleResId The resource ID for the string to use in the title of the dialog. - * @param canSetDefault {@code true} if the dialog should include an option to set the selection - * as the default. False otherwise. - * @param setDefaultResId The resource ID for the string to use in the "set as default" checkbox - * @param accountHandles The {@code PhoneAccountHandle}s available to select from. - * @param listener The listener for the results of the account selection. - * @param callId The callId to be passed back to the listener in {@link - * SelectPhoneAccountListener#EXTRA_CALL_ID} - * @param hints Additional information to be shown underneath the phone account to help user - * choose. Index must match {@code accountHandles} - */ + private SelectPhoneAccountDialogOptions options = + SelectPhoneAccountDialogOptions.getDefaultInstance(); + private SelectPhoneAccountListener listener; + + private boolean isDefaultChecked; + private boolean isSelected; + + /** Create new fragment instance. */ public static SelectPhoneAccountDialogFragment newInstance( - int titleResId, - boolean canSetDefault, - int setDefaultResId, - List accountHandles, - SelectPhoneAccountListener listener, - @Nullable String callId, - @Nullable List hints) { - ArrayList accountHandlesCopy = new ArrayList<>(); - if (accountHandles != null) { - accountHandlesCopy.addAll(accountHandles); - } + SelectPhoneAccountDialogOptions options, SelectPhoneAccountListener listener) { SelectPhoneAccountDialogFragment fragment = new SelectPhoneAccountDialogFragment(); - final Bundle args = new Bundle(); - args.putInt(ARG_TITLE_RES_ID, titleResId); - args.putBoolean(ARG_CAN_SET_DEFAULT, canSetDefault); - if (setDefaultResId != 0) { - args.putInt(ARG_SET_DEFAULT_RES_ID, setDefaultResId); - } - args.putParcelableArrayList(ARG_ACCOUNT_HANDLES, accountHandlesCopy); - args.putParcelable(ARG_LISTENER, listener); - args.putString(ARG_CALL_ID, callId); - if (hints != null) { - args.putStringArrayList(ARG_HINTS, new ArrayList<>(hints)); - } - fragment.setArguments(args); fragment.setListener(listener); + Bundle arguments = new Bundle(); + ProtoParsers.put(arguments, ARG_OPTIONS, options); + fragment.setArguments(arguments); return fragment; } public void setListener(SelectPhoneAccountListener listener) { - mListener = listener; + this.listener = listener; } @Nullable @VisibleForTesting public SelectPhoneAccountListener getListener() { - return mListener; + return listener; } @VisibleForTesting public boolean canSetDefault() { - return getArguments().getBoolean(ARG_CAN_SET_DEFAULT); + return options.getCanSetDefault(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - outState.putBoolean(ARG_IS_DEFAULT_CHECKED, mIsDefaultChecked); + outState.putBoolean(ARG_IS_DEFAULT_CHECKED, isDefaultChecked); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - int titleResId = getArguments().getInt(ARG_TITLE_RES_ID); - boolean canSetDefault = getArguments().getBoolean(ARG_CAN_SET_DEFAULT); - mAccountHandles = getArguments().getParcelableArrayList(ARG_ACCOUNT_HANDLES); - mListener = getArguments().getParcelable(ARG_LISTENER); - mHints = getArguments().getStringArrayList(ARG_HINTS); + options = + ProtoParsers.getTrusted( + getArguments(), ARG_OPTIONS, SelectPhoneAccountDialogOptions.getDefaultInstance()); if (savedInstanceState != null) { - mIsDefaultChecked = savedInstanceState.getBoolean(ARG_IS_DEFAULT_CHECKED); + isDefaultChecked = savedInstanceState.getBoolean(ARG_IS_DEFAULT_CHECKED); } - mIsSelected = false; + isSelected = false; final DialogInterface.OnClickListener selectionListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mIsSelected = true; - PhoneAccountHandle selectedAccountHandle = mAccountHandles.get(which); + isSelected = true; + PhoneAccountHandle selectedAccountHandle = + SelectPhoneAccountDialogOptionsUtil.getPhoneAccountHandle( + options.getEntriesList().get(which)); Bundle result = new Bundle(); result.putParcelable( SelectPhoneAccountListener.EXTRA_SELECTED_ACCOUNT_HANDLE, selectedAccountHandle); - result.putBoolean(SelectPhoneAccountListener.EXTRA_SET_DEFAULT, mIsDefaultChecked); + result.putBoolean(SelectPhoneAccountListener.EXTRA_SET_DEFAULT, isDefaultChecked); result.putString(SelectPhoneAccountListener.EXTRA_CALL_ID, getCallId()); - if (mListener != null) { - mListener.onReceiveResult(SelectPhoneAccountListener.RESULT_SELECTED, result); + if (listener != null) { + listener.onReceiveResult(SelectPhoneAccountListener.RESULT_SELECTED, result); } } }; @@ -188,22 +132,23 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton check, boolean isChecked) { - mIsDefaultChecked = isChecked; + isDefaultChecked = isChecked; } }; AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); ListAdapter selectAccountListAdapter = new SelectAccountListAdapter( - builder.getContext(), R.layout.select_account_list_item, mAccountHandles, mHints); + builder.getContext(), R.layout.select_account_list_item, options); AlertDialog dialog = builder - .setTitle(titleResId) + .setTitle( + options.hasTitle() ? options.getTitle() : R.string.select_account_dialog_title) .setAdapter(selectAccountListAdapter, selectionListener) .create(); - if (canSetDefault) { + if (options.getCanSetDefault()) { // Generate custom checkbox view, lint suppressed since no appropriate parent (is dialog) @SuppressLint("InflateParams") LinearLayout checkboxLayout = @@ -213,11 +158,13 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { CheckBox checkBox = checkboxLayout.findViewById(R.id.default_account_checkbox_view); checkBox.setOnCheckedChangeListener(checkListener); - checkBox.setChecked(mIsDefaultChecked); + checkBox.setChecked(isDefaultChecked); TextView textView = checkboxLayout.findViewById(R.id.default_account_checkbox_text); int setDefaultResId = - getArguments().getInt(ARG_SET_DEFAULT_RES_ID, R.string.set_default_account); + options.hasSetDefaultLabel() + ? options.getSetDefaultLabel() + : R.string.set_default_account; textView.setText(setDefaultResId); textView.setOnClickListener((view) -> checkBox.performClick()); checkboxLayout.setOnClickListener((view) -> checkBox.performClick()); @@ -230,17 +177,17 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { @Override public void onCancel(DialogInterface dialog) { - if (!mIsSelected && mListener != null) { + if (!isSelected && listener != null) { Bundle result = new Bundle(); result.putString(SelectPhoneAccountListener.EXTRA_CALL_ID, getCallId()); - mListener.onReceiveResult(SelectPhoneAccountListener.RESULT_DISMISSED, result); + listener.onReceiveResult(SelectPhoneAccountListener.RESULT_DISMISSED, result); } super.onCancel(dialog); } @Nullable private String getCallId() { - return getArguments().getString(ARG_CALL_ID); + return options.getCallId(); } public static class SelectPhoneAccountListener extends ResultReceiver { @@ -274,18 +221,14 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { public void onDialogDismissed(@Nullable String callId) {} } - private static class SelectAccountListAdapter extends ArrayAdapter { + private static class SelectAccountListAdapter + extends ArrayAdapter { private int mResId; - private final List mHints; SelectAccountListAdapter( - Context context, - int resource, - List accountHandles, - @Nullable List hints) { - super(context, resource, accountHandles); - mHints = hints; + Context context, int resource, SelectPhoneAccountDialogOptions options) { + super(context, resource, options.getEntriesList()); mResId = resource; } @@ -311,7 +254,9 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { holder = (ViewHolder) rowView.getTag(); } - PhoneAccountHandle accountHandle = getItem(position); + SelectPhoneAccountDialogOptions.Entry entry = getItem(position); + PhoneAccountHandle accountHandle = + SelectPhoneAccountDialogOptionsUtil.getPhoneAccountHandle(entry); PhoneAccount account = getContext().getSystemService(TelecomManager.class).getPhoneAccount(accountHandle); if (account == null) { @@ -331,16 +276,12 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { } holder.imageView.setImageDrawable( PhoneAccountCompat.createIconDrawable(account, getContext())); - if (mHints != null && position < mHints.size()) { - String hint = mHints.get(position); - if (TextUtils.isEmpty(hint)) { - holder.hintTextView.setVisibility(View.GONE); - } else { - holder.hintTextView.setVisibility(View.VISIBLE); - holder.hintTextView.setText(hint); - } - } else { + + if (TextUtils.isEmpty(entry.getHint())) { holder.hintTextView.setVisibility(View.GONE); + } else { + holder.hintTextView.setVisibility(View.VISIBLE); + holder.hintTextView.setText(entry.getHint()); } return rowView; diff --git a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogOptionsUtil.java b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogOptionsUtil.java new file mode 100644 index 000000000..5a44ae7f8 --- /dev/null +++ b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogOptionsUtil.java @@ -0,0 +1,55 @@ +/* + * 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.contacts.common.widget; + +import android.telecom.PhoneAccountHandle; +import com.android.dialer.common.Assert; +import com.android.dialer.telecom.TelecomUtil; +import java.util.Collection; + +/** Provides common operation on a {@link SelectPhoneAccountDialogOptions} */ +public final class SelectPhoneAccountDialogOptionsUtil { + private SelectPhoneAccountDialogOptionsUtil() {} + + public static PhoneAccountHandle getPhoneAccountHandle( + SelectPhoneAccountDialogOptions.Entry entry) { + return Assert.isNotNull( + TelecomUtil.composePhoneAccountHandle( + entry.getPhoneAccountHandleComponentName(), entry.getPhoneAccountHandleId())); + } + + public static SelectPhoneAccountDialogOptions.Entry.Builder setPhoneAccountHandle( + SelectPhoneAccountDialogOptions.Entry.Builder entryBuilder, + PhoneAccountHandle phoneAccountHandle) { + entryBuilder.setPhoneAccountHandleComponentName( + phoneAccountHandle.getComponentName().flattenToString()); + entryBuilder.setPhoneAccountHandleId(phoneAccountHandle.getId()); + return entryBuilder; + } + + public static SelectPhoneAccountDialogOptions.Builder builderWithAccounts( + Collection phoneAccountHandles) { + SelectPhoneAccountDialogOptions.Builder optionsBuilder = + SelectPhoneAccountDialogOptions.newBuilder(); + for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) { + optionsBuilder.addEntries( + SelectPhoneAccountDialogOptionsUtil.setPhoneAccountHandle( + SelectPhoneAccountDialogOptions.Entry.newBuilder(), phoneAccountHandle)); + } + return optionsBuilder; + } +} diff --git a/java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto b/java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto new file mode 100644 index 000000000..9938f57ae --- /dev/null +++ b/java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto @@ -0,0 +1,54 @@ +// 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 + +syntax = "proto2"; + +option java_package = "com.android.contacts.common.widget"; +option java_multiple_files = true; +option optimize_for = LITE_RUNTIME; + + +package com.android.contacts.common.widget; + +// Parameters for SelectPhoneAccountDialogFragment +message SelectPhoneAccountDialogOptions { + // The resource ID for the title. Defaults to + // R.string.select_account_dialog_title + optional int32 title = 1; + // Whether the dialog should include a "set as default" checkbox. Defaults to + // false + optional bool can_set_default = 2; + // The label on the "set as default" checkbox. Defaults + // R.string.set_default_account + optional int32 set_default_label = 3; + // The call ID to pass back to the callback + optional string call_id = 4; + // Phone accounts to show in the dialog + repeated Entry entries = 5; + + message Entry { + // PhoneAccountHandle.getComponentName().flattenToString() + optional string phone_account_handle_component_name = 1; + // PhoneAccountHandle.getId() + optional string phone_account_handle_id = 2; + // The hint to show under the phone account, for example showing the user + // the account was selected frequently before. + optional string hint = 3; + // Whether the account is actually selectable. Defaults to true Sometimes an + // account will be temporarily unusable, for example the user is already in + // a call so the other SIM cannot be used. Hint should also be set to inform + // the user why the account is unavailable. + optional bool enabled = 4; + } +} \ No newline at end of file diff --git a/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java b/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java index 9929ddd3b..d2652ee66 100644 --- a/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java +++ b/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java @@ -56,6 +56,7 @@ import com.android.contacts.common.database.NoNullCursorAsyncQueryHandler; import com.android.contacts.common.util.ContactDisplayUtils; import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment; import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener; +import com.android.contacts.common.widget.SelectPhoneAccountDialogOptionsUtil; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.telephony.TelephonyManagerCompat; @@ -234,10 +235,12 @@ public class SpecialCharSequenceMgr { } else { SelectPhoneAccountListener callback = new HandleAdnEntryAccountSelectedCallback(applicationContext, handler, sc); - DialogFragment dialogFragment = SelectPhoneAccountDialogFragment.newInstance( - subscriptionAccountHandles, callback, null); + SelectPhoneAccountDialogOptionsUtil.builderWithAccounts( + subscriptionAccountHandles) + .build(), + callback); dialogFragment.show(((Activity) context).getFragmentManager(), TAG_SELECT_ACCT_FRAGMENT); } @@ -292,7 +295,9 @@ public class SpecialCharSequenceMgr { DialogFragment dialogFragment = SelectPhoneAccountDialogFragment.newInstance( - subscriptionAccountHandles, listener, null); + SelectPhoneAccountDialogOptionsUtil.builderWithAccounts(subscriptionAccountHandles) + .build(), + listener); dialogFragment.show(((Activity) context).getFragmentManager(), TAG_SELECT_ACCT_FRAGMENT); } return true; diff --git a/java/com/android/dialer/precall/impl/CallingAccountSelector.java b/java/com/android/dialer/precall/impl/CallingAccountSelector.java index 16e7641ba..6514a4941 100644 --- a/java/com/android/dialer/precall/impl/CallingAccountSelector.java +++ b/java/com/android/dialer/precall/impl/CallingAccountSelector.java @@ -28,6 +28,8 @@ import android.telecom.TelecomManager; import android.telephony.PhoneNumberUtils; import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment; import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener; +import com.android.contacts.common.widget.SelectPhoneAccountDialogOptions; +import com.android.contacts.common.widget.SelectPhoneAccountDialogOptionsUtil; import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; @@ -44,6 +46,7 @@ import com.android.dialer.preferredsim.PreferredAccountWorker; import com.android.dialer.preferredsim.suggestion.SuggestionProvider; import com.android.dialer.preferredsim.suggestion.SuggestionProvider.Suggestion; import com.android.dialer.telecom.TelecomUtil; +import com.google.common.base.Optional; import java.util.List; /** PreCallAction to select which phone account to call with. Ignored if there's only one account */ @@ -211,24 +214,34 @@ public class CallingAccountSelector implements PreCallAction { default: } } - List phoneAccountHandles = + SelectPhoneAccountDialogOptions.Builder optionsBuilder = + SelectPhoneAccountDialogOptions.newBuilder() + .setTitle(R.string.pre_call_select_phone_account) + .setCanSetDefault(dataId != null) + .setSetDefaultLabel(R.string.pre_call_select_phone_account_remember); + + for (PhoneAccountHandle phoneAccountHandle : coordinator .getActivity() .getSystemService(TelecomManager.class) - .getCallCapablePhoneAccounts(); + .getCallCapablePhoneAccounts()) { + SelectPhoneAccountDialogOptions.Entry.Builder entryBuilder = + SelectPhoneAccountDialogOptions.Entry.newBuilder(); + SelectPhoneAccountDialogOptionsUtil.setPhoneAccountHandle(entryBuilder, phoneAccountHandle); + Optional hint = + SuggestionProvider.getHint(coordinator.getActivity(), phoneAccountHandle, suggestion); + if (hint.isPresent()) { + entryBuilder.setHint(hint.get()); + } + optionsBuilder.addEntries(entryBuilder); + } selectPhoneAccountDialogFragment = SelectPhoneAccountDialogFragment.newInstance( - R.string.pre_call_select_phone_account, - dataId != null /* canSetDefault */, - R.string.pre_call_select_phone_account_remember, - phoneAccountHandles, + optionsBuilder.build(), new SelectedListener( coordinator, pendingAction, - new PreferredAccountRecorder(number, suggestion, dataId)), - null /* call ID */, - SuggestionProvider.buildHint( - coordinator.getActivity(), phoneAccountHandles, suggestion)); + new PreferredAccountRecorder(number, suggestion, dataId))); selectPhoneAccountDialogFragment.show( coordinator.getActivity().getFragmentManager(), TAG_CALLING_ACCOUNT_SELECTOR); } diff --git a/java/com/android/dialer/preferredsim/suggestion/SuggestionProvider.java b/java/com/android/dialer/preferredsim/suggestion/SuggestionProvider.java index f710f734c..50ae01fd0 100644 --- a/java/com/android/dialer/preferredsim/suggestion/SuggestionProvider.java +++ b/java/com/android/dialer/preferredsim/suggestion/SuggestionProvider.java @@ -24,10 +24,9 @@ import android.telecom.PhoneAccountHandle; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.google.common.base.Optional; -import java.util.ArrayList; -import java.util.List; /** Provides hints to the user when selecting a SIM to make a call. */ +@SuppressWarnings("Guava") public interface SuggestionProvider { String EXTRA_SIM_SUGGESTION_REASON = "sim_suggestion_reason"; @@ -80,35 +79,25 @@ public interface SuggestionProvider { @NonNull Context context, @NonNull String number, @NonNull PhoneAccountHandle newAccount); /** - * Return a list of suggestion strings matching the list position of the {@code - * phoneAccountHandles}. The list will contain {@code null} if the PhoneAccountHandle does not - * have suggestions. + * Return the hint for {@code phoneAccountHandle}. Absent if no hint is available for the account. */ - @Nullable - static List buildHint( - Context context, - List phoneAccountHandles, - @Nullable Suggestion suggestion) { + static Optional getHint( + Context context, PhoneAccountHandle phoneAccountHandle, @Nullable Suggestion suggestion) { if (suggestion == null) { - return null; + return Optional.absent(); } - List hints = new ArrayList<>(); - for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) { - if (!phoneAccountHandle.equals(suggestion.phoneAccountHandle)) { - hints.add(null); - continue; - } - switch (suggestion.reason) { - case INTRA_CARRIER: - hints.add(context.getString(R.string.pre_call_select_phone_account_hint_intra_carrier)); - break; - case FREQUENT: - hints.add(context.getString(R.string.pre_call_select_phone_account_hint_frequent)); - break; - default: - LogUtil.w("CallingAccountSelector.buildHint", "unhandled reason " + suggestion.reason); - } + if (!phoneAccountHandle.equals(suggestion.phoneAccountHandle)) { + return Optional.absent(); + } + switch (suggestion.reason) { + case INTRA_CARRIER: + return Optional.of( + context.getString(R.string.pre_call_select_phone_account_hint_intra_carrier)); + case FREQUENT: + return Optional.of(context.getString(R.string.pre_call_select_phone_account_hint_frequent)); + default: + LogUtil.w("CallingAccountSelector.getHint", "unhandled reason " + suggestion.reason); + return Optional.absent(); } - return hints; } } diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java index 86799bfe4..68de8dcc3 100644 --- a/java/com/android/incallui/InCallActivity.java +++ b/java/com/android/incallui/InCallActivity.java @@ -55,6 +55,8 @@ import android.view.animation.AnimationUtils; import android.widget.CheckBox; import android.widget.Toast; import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment; +import com.android.contacts.common.widget.SelectPhoneAccountDialogOptions; +import com.android.contacts.common.widget.SelectPhoneAccountDialogOptionsUtil; import com.android.dialer.animation.AnimUtils; import com.android.dialer.animation.AnimationListenerAdapter; import com.android.dialer.common.Assert; @@ -395,16 +397,30 @@ public class InCallActivity extends TransactionSafeFragmentActivity waitingForAccountCall.getNumber(), result.getSuggestion().orNull(), result.getDataId().orNull())); + SelectPhoneAccountDialogOptions.Builder optionsBuilder = + SelectPhoneAccountDialogOptions.newBuilder() + .setTitle(R.string.select_phone_account_for_calls) + .setCanSetDefault(result.getDataId().isPresent()) + .setSetDefaultLabel(R.string.select_phone_account_for_calls_remember) + .setCallId(waitingForAccountCall.getId()); + + for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) { + SelectPhoneAccountDialogOptions.Entry.Builder entryBuilder = + SelectPhoneAccountDialogOptions.Entry.newBuilder(); + SelectPhoneAccountDialogOptionsUtil.setPhoneAccountHandle( + entryBuilder, phoneAccountHandle); + Optional hint = + SuggestionProvider.getHint( + this, phoneAccountHandle, result.getSuggestion().orNull()); + if (hint.isPresent()) { + entryBuilder.setHint(hint.get()); + } + optionsBuilder.addEntries(entryBuilder); + } + selectPhoneAccountDialogFragment = SelectPhoneAccountDialogFragment.newInstance( - R.string.select_phone_account_for_calls, - result.getDataId().isPresent() /* canSetDefault */, - R.string.select_phone_account_for_calls_remember /* setDefaultResId */, - phoneAccountHandles, - selectPhoneAccountListener, - waitingForAccountCall.getId(), - SuggestionProvider.buildHint( - this, phoneAccountHandles, result.getSuggestion().orNull() /* hints */)); + optionsBuilder.build(), selectPhoneAccountListener); selectPhoneAccountDialogFragment.show( getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT); })) -- cgit v1.2.3 From 0a5c34d103dc8701e55035e98e6d9fd6c2caf33e Mon Sep 17 00:00:00 2001 From: twyen Date: Tue, 24 Apr 2018 14:34:33 -0700 Subject: Disable entries in CallingAccountSelector that are not selectable This CL also unifies the disabled color for primary and secondary text. The in call UI dialog will be implemented in a followup CL. TEST=TAP DEFAULT_VALUE_OK=no server. Bug: 69675796,72618783 Test: TAP PiperOrigin-RevId: 194147061 Change-Id: I5be5a45a7df09061a3bf391f6ae2a32d9c73b6e3 --- .../common/res/layout/select_account_list_item.xml | 2 + .../widget/SelectPhoneAccountDialogFragment.java | 24 ++- .../select_phone_account_dialog_options.proto | 10 +- .../android/dialer/logging/dialer_impression.proto | 8 +- .../precall/impl/CallingAccountSelector.java | 178 ++++++++++++++++----- .../dialer/precall/impl/res/values/strings.xml | 6 +- .../theme/res/color/dialer_primary_text_color.xml | 21 +++ .../res/color/dialer_secondary_text_color.xml | 21 +++ .../com/android/dialer/theme/res/values/colors.xml | 6 +- .../incallui/ConferenceParticipantListAdapter.java | 2 +- .../incallui/res/layout/caller_in_conference.xml | 2 +- 11 files changed, 221 insertions(+), 59 deletions(-) create mode 100644 java/com/android/dialer/theme/res/color/dialer_primary_text_color.xml create mode 100644 java/com/android/dialer/theme/res/color/dialer_secondary_text_color.xml (limited to 'java') diff --git a/java/com/android/contacts/common/res/layout/select_account_list_item.xml b/java/com/android/contacts/common/res/layout/select_account_list_item.xml index 84cb1fd66..bf52d6f09 100644 --- a/java/com/android/contacts/common/res/layout/select_account_list_item.xml +++ b/java/com/android/contacts/common/res/layout/select_account_list_item.xml @@ -54,6 +54,7 @@ android:includeFontPadding="false" android:maxLines="1" android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/dialer_secondary_text_color" android:visibility="gone"/> diff --git a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java index e1fdd913b..3ee21ccea 100644 --- a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java +++ b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java @@ -57,7 +57,8 @@ import com.google.common.base.Optional; */ public class SelectPhoneAccountDialogFragment extends DialogFragment { - private static final String ARG_OPTIONS = "options"; + @VisibleForTesting public static final String ARG_OPTIONS = "options"; + private static final String ARG_IS_DEFAULT_CHECKED = "is_default_checked"; private SelectPhoneAccountDialogOptions options = @@ -221,17 +222,29 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { public void onDialogDismissed(@Nullable String callId) {} } - private static class SelectAccountListAdapter + static class SelectAccountListAdapter extends ArrayAdapter { private int mResId; + private final SelectPhoneAccountDialogOptions options; SelectAccountListAdapter( Context context, int resource, SelectPhoneAccountDialogOptions options) { super(context, resource, options.getEntriesList()); + this.options = options; mResId = resource; } + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int position) { + return options.getEntries(position).getEnabled(); + } + @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = @@ -283,7 +296,10 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { holder.hintTextView.setVisibility(View.VISIBLE); holder.hintTextView.setText(entry.getHint()); } - + holder.labelTextView.setEnabled(entry.getEnabled()); + holder.numberTextView.setEnabled(entry.getEnabled()); + holder.hintTextView.setEnabled(entry.getEnabled()); + holder.imageView.setImageAlpha(entry.getEnabled() ? 255 : 97 /* 38%*/); return rowView; } @@ -297,7 +313,7 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { return info.get().getCountryIso().toUpperCase(); } - private static final class ViewHolder { + static final class ViewHolder { TextView labelTextView; TextView numberTextView; diff --git a/java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto b/java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto index 9938f57ae..cc40c64b4 100644 --- a/java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto +++ b/java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto @@ -45,10 +45,10 @@ message SelectPhoneAccountDialogOptions { // The hint to show under the phone account, for example showing the user // the account was selected frequently before. optional string hint = 3; - // Whether the account is actually selectable. Defaults to true Sometimes an - // account will be temporarily unusable, for example the user is already in - // a call so the other SIM cannot be used. Hint should also be set to inform - // the user why the account is unavailable. - optional bool enabled = 4; + // Whether the account is actually selectable. Defaults to true. Sometimes + // an account will be temporarily unusable, for example the user is already + // in a call so the other SIM cannot be used. Hint should also be set to + // inform the user why the account is unavailable. + optional bool enabled = 4 [default = true]; } } \ No newline at end of file diff --git a/java/com/android/dialer/logging/dialer_impression.proto b/java/com/android/dialer/logging/dialer_impression.proto index c6c93eee6..7cd22079c 100644 --- a/java/com/android/dialer/logging/dialer_impression.proto +++ b/java/com/android/dialer/logging/dialer_impression.proto @@ -12,7 +12,7 @@ message DialerImpression { // Event enums to be used for Impression Logging in Dialer. // It's perfectly acceptable for this enum to be large // Values should be from 1000 to 100000. - // Next Tag: 1389 + // Next Tag: 1392 enum Type { UNKNOWN_AOSP_EVENT_TYPE = 1000; @@ -626,7 +626,11 @@ message DialerImpression { DUAL_SIM_SELECTION_NON_SUGGESTED_SIM_SELECTED = 1304; DUAL_SIM_SELECTION_PREFERRED_SET = 1305; DUAL_SIM_SELECTION_PREFERRED_USED = 1306; + DUAL_SIM_SELECTION_PREFERRED_NOT_SELECTABLE = 1389; DUAL_SIM_SELECTION_GLOBAL_USED = 1307; + DUAL_SIM_SELECTION_GLOBAL_NOT_SELECTABLE = 1390; + DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED = 1322; + DUAL_SIM_SELECTION_SUGGESTION_AUTO_NOT_SELECTABLE = 1391; DUO_CALL_LOG_SET_UP_INSTALL = 1308; DUO_CALL_LOG_SET_UP_ACTIVATE = 1309; @@ -655,8 +659,6 @@ message DialerImpression { // Drag bubble to bottom and end call BUBBLE_V2_BOTTOM_ACTION_END_CALL = 1321; - DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED = 1322; - // Bubble appears BUBBLE_V2_SHOW = 1323; diff --git a/java/com/android/dialer/precall/impl/CallingAccountSelector.java b/java/com/android/dialer/precall/impl/CallingAccountSelector.java index 6514a4941..8f63fa0db 100644 --- a/java/com/android/dialer/precall/impl/CallingAccountSelector.java +++ b/java/com/android/dialer/precall/impl/CallingAccountSelector.java @@ -30,12 +30,13 @@ import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment; import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener; import com.android.contacts.common.widget.SelectPhoneAccountDialogOptions; import com.android.contacts.common.widget.SelectPhoneAccountDialogOptionsUtil; +import com.android.dialer.activecalls.ActiveCallInfo; +import com.android.dialer.activecalls.ActiveCallsComponent; import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.configprovider.ConfigProviderBindings; -import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.DialerImpression.Type; import com.android.dialer.logging.Logger; import com.android.dialer.precall.PreCallAction; @@ -43,11 +44,13 @@ import com.android.dialer.precall.PreCallCoordinator; import com.android.dialer.precall.PreCallCoordinator.PendingAction; import com.android.dialer.preferredsim.PreferredAccountRecorder; import com.android.dialer.preferredsim.PreferredAccountWorker; +import com.android.dialer.preferredsim.PreferredAccountWorker.Result; import com.android.dialer.preferredsim.suggestion.SuggestionProvider; import com.android.dialer.preferredsim.suggestion.SuggestionProvider.Suggestion; -import com.android.dialer.telecom.TelecomUtil; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; import java.util.List; +import java.util.Objects; /** PreCallAction to select which phone account to call with. Ignored if there's only one account */ @SuppressWarnings("MissingPermission") @@ -78,17 +81,6 @@ public class CallingAccountSelector implements PreCallAction { if (accounts.size() <= 1) { return false; } - - if (TelecomUtil.isInManagedCall(context)) { - // Most devices are DSDS (dual SIM dual standby) which only one SIM can have active calls at - // a time. Telecom will ignore the phone account handle and use the current active SIM, thus - // there's no point of selecting SIMs - // TODO(a bug): let the user know selections are not available and preferred SIM is not - // used - // TODO(twyen): support other dual SIM modes when the API is exposed. - return false; - } - return true; } @@ -137,12 +129,7 @@ public class CallingAccountSelector implements PreCallAction { return; } if (result.getPhoneAccountHandle().isPresent()) { - Logger.get(coordinator.getActivity()) - .logImpression(DialerImpression.Type.DUAL_SIM_SELECTION_PREFERRED_USED); - coordinator - .getBuilder() - .setPhoneAccountHandle(result.getPhoneAccountHandle().get()); - pendingAction.finish(); + usePreferredAccount(coordinator, pendingAction, result); return; } PhoneAccountHandle defaultPhoneAccount = @@ -150,10 +137,7 @@ public class CallingAccountSelector implements PreCallAction { .getSystemService(TelecomManager.class) .getDefaultOutgoingPhoneAccount(builder.getUri().getScheme()); if (defaultPhoneAccount != null) { - Logger.get(coordinator.getActivity()) - .logImpression(DialerImpression.Type.DUAL_SIM_SELECTION_GLOBAL_USED); - builder.setPhoneAccountHandle(defaultPhoneAccount); - pendingAction.finish(); + useDefaultAccount(coordinator, pendingAction, result, defaultPhoneAccount); return; } if (result.getSuggestion().isPresent()) { @@ -161,18 +145,7 @@ public class CallingAccountSelector implements PreCallAction { "CallingAccountSelector.processPreferredAccount", "SIM suggested: " + result.getSuggestion().get().reason); if (result.getSuggestion().get().shouldAutoSelect) { - Logger.get(coordinator.getActivity()) - .logImpression( - DialerImpression.Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED); - LogUtil.i( - "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion"); - builder.setPhoneAccountHandle(result.getSuggestion().get().phoneAccountHandle); - builder - .getInCallUiIntentExtras() - .putString( - SuggestionProvider.EXTRA_SIM_SUGGESTION_REASON, - result.getSuggestion().get().reason.name()); - pendingAction.finish(); + useSuggestedAccount(coordinator, pendingAction, result); return; } } @@ -187,6 +160,120 @@ public class CallingAccountSelector implements PreCallAction { .executeParallel(activity); } + private void usePreferredAccount( + PreCallCoordinator coordinator, PendingAction pendingAction, Result result) { + String phoneNumber = coordinator.getBuilder().getUri().getSchemeSpecificPart(); + if (isSelectable(coordinator.getActivity(), result.getPhoneAccountHandle().get())) { + Logger.get(coordinator.getActivity()).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED); + coordinator.getBuilder().setPhoneAccountHandle(result.getPhoneAccountHandle().get()); + pendingAction.finish(); + } else { + Logger.get(coordinator.getActivity()) + .logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_NOT_SELECTABLE); + LogUtil.i("CallingAccountSelector.usePreferredAccount", "preferred account not selectable"); + showDialog( + coordinator, + pendingAction, + result.getDataId().orNull(), + phoneNumber, + result.getSuggestion().orNull()); + } + } + + private void useDefaultAccount( + PreCallCoordinator coordinator, + PendingAction pendingAction, + Result result, + PhoneAccountHandle defaultPhoneAccount) { + CallIntentBuilder builder = coordinator.getBuilder(); + String phoneNumber = builder.getUri().getSchemeSpecificPart(); + if (isSelectable(coordinator.getActivity(), defaultPhoneAccount)) { + Logger.get(coordinator.getActivity()).logImpression(Type.DUAL_SIM_SELECTION_GLOBAL_USED); + builder.setPhoneAccountHandle(defaultPhoneAccount); + pendingAction.finish(); + } else { + Logger.get(coordinator.getActivity()) + .logImpression(Type.DUAL_SIM_SELECTION_GLOBAL_NOT_SELECTABLE); + LogUtil.i("CallingAccountSelector.useDefaultAccount", "default account not selectable"); + showDialog( + coordinator, + pendingAction, + result.getDataId().orNull(), + phoneNumber, + result.getSuggestion().orNull()); + } + } + + private void useSuggestedAccount( + PreCallCoordinator coordinator, PendingAction pendingAction, Result result) { + CallIntentBuilder builder = coordinator.getBuilder(); + String phoneNumber = builder.getUri().getSchemeSpecificPart(); + if (isSelectable(coordinator.getActivity(), result.getSuggestion().get().phoneAccountHandle)) { + Logger.get(coordinator.getActivity()) + .logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED); + LogUtil.i("CallingAccountSelector.processPreferredAccount", "Auto selected suggestion"); + builder.setPhoneAccountHandle(result.getSuggestion().get().phoneAccountHandle); + builder + .getInCallUiIntentExtras() + .putString( + SuggestionProvider.EXTRA_SIM_SUGGESTION_REASON, + result.getSuggestion().get().reason.name()); + pendingAction.finish(); + } else { + LogUtil.i("CallingAccountSelector.useSuggestedAccount", "suggested account not selectable"); + Logger.get(coordinator.getActivity()) + .logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_NOT_SELECTABLE); + showDialog( + coordinator, + pendingAction, + result.getDataId().orNull(), + phoneNumber, + result.getSuggestion().orNull()); + } + } + + /** + * Most devices are DSDS (dual SIM dual standby) which only one SIM can have active calls at a + * time. TODO(twyen): support other dual SIM modes when the API is exposed. + */ + private static boolean isSelectable(Context context, PhoneAccountHandle phoneAccountHandle) { + ImmutableList activeCalls = + ActiveCallsComponent.get(context).activeCalls().getActiveCalls(); + if (activeCalls.isEmpty()) { + return true; + } + for (ActiveCallInfo activeCall : activeCalls) { + if (Objects.equals(phoneAccountHandle, activeCall.phoneAccountHandle().orNull())) { + return true; + } + } + return false; + } + + private static Optional getActiveCallLabel(Context context) { + ImmutableList activeCalls = + ActiveCallsComponent.get(context).activeCalls().getActiveCalls(); + + if (activeCalls.isEmpty()) { + LogUtil.e("CallingAccountSelector.getActiveCallLabel", "active calls no longer exist"); + return Optional.absent(); + } + ActiveCallInfo activeCall = activeCalls.get(0); + if (!activeCall.phoneAccountHandle().isPresent()) { + LogUtil.e("CallingAccountSelector.getActiveCallLabel", "active call has no phone account"); + return Optional.absent(); + } + PhoneAccount phoneAccount = + context + .getSystemService(TelecomManager.class) + .getPhoneAccount(activeCall.phoneAccountHandle().get()); + if (phoneAccount == null) { + LogUtil.e("CallingAccountSelector.getActiveCallLabel", "phone account not found"); + return Optional.absent(); + } + return Optional.of(phoneAccount.getLabel().toString()); + } + @MainThread private void showDialog( PreCallCoordinator coordinator, @@ -228,10 +315,23 @@ public class CallingAccountSelector implements PreCallAction { SelectPhoneAccountDialogOptions.Entry.Builder entryBuilder = SelectPhoneAccountDialogOptions.Entry.newBuilder(); SelectPhoneAccountDialogOptionsUtil.setPhoneAccountHandle(entryBuilder, phoneAccountHandle); - Optional hint = - SuggestionProvider.getHint(coordinator.getActivity(), phoneAccountHandle, suggestion); - if (hint.isPresent()) { - entryBuilder.setHint(hint.get()); + if (isSelectable(coordinator.getActivity(), phoneAccountHandle)) { + Optional hint = + SuggestionProvider.getHint(coordinator.getActivity(), phoneAccountHandle, suggestion); + if (hint.isPresent()) { + entryBuilder.setHint(hint.get()); + } + } else { + entryBuilder.setEnabled(false); + Optional activeCallLabel = getActiveCallLabel(coordinator.getActivity()); + if (activeCallLabel.isPresent()) { + entryBuilder.setHint( + coordinator + .getActivity() + .getString( + R.string.pre_call_select_phone_account_hint_other_sim_in_use, + activeCallLabel.get())); + } } optionsBuilder.addEntries(entryBuilder); } diff --git a/java/com/android/dialer/precall/impl/res/values/strings.xml b/java/com/android/dialer/precall/impl/res/values/strings.xml index 4bd5d36f2..3691271ce 100644 --- a/java/com/android/dialer/precall/impl/res/values/strings.xml +++ b/java/com/android/dialer/precall/impl/res/values/strings.xml @@ -14,7 +14,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> - + Cannot make call without phone permission @@ -26,4 +26,8 @@ same contact and never ask again [CHAR LIMIT=40]--> Remember this choice + + Not available while using %1$s \ No newline at end of file diff --git a/java/com/android/dialer/theme/res/color/dialer_primary_text_color.xml b/java/com/android/dialer/theme/res/color/dialer_primary_text_color.xml new file mode 100644 index 000000000..347db41bc --- /dev/null +++ b/java/com/android/dialer/theme/res/color/dialer_primary_text_color.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/java/com/android/dialer/theme/res/color/dialer_secondary_text_color.xml b/java/com/android/dialer/theme/res/color/dialer_secondary_text_color.xml new file mode 100644 index 000000000..920b46792 --- /dev/null +++ b/java/com/android/dialer/theme/res/color/dialer_secondary_text_color.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/java/com/android/dialer/theme/res/values/colors.xml b/java/com/android/dialer/theme/res/values/colors.xml index e80fc4b30..2185d861c 100644 --- a/java/com/android/dialer/theme/res/values/colors.xml +++ b/java/com/android/dialer/theme/res/values/colors.xml @@ -36,15 +36,11 @@ #F50057 - - #333333 #ffffff #DE78909C - - #636363 - #61000000 + #9E9E9E #2A56C6 diff --git a/java/com/android/incallui/ConferenceParticipantListAdapter.java b/java/com/android/incallui/ConferenceParticipantListAdapter.java index 4780974ef..dc793f7f8 100644 --- a/java/com/android/incallui/ConferenceParticipantListAdapter.java +++ b/java/com/android/incallui/ConferenceParticipantListAdapter.java @@ -356,7 +356,7 @@ public class ConferenceParticipantListAdapter extends BaseAdapter { statusTextView.setText(onHoldText); statusTextView.setVisibility(View.VISIBLE); - int onHoldColor = getContext().getColor(R.color.dialer_secondary_text_color_hiden); + int onHoldColor = getContext().getColor(R.color.dialer_disabled_text_color); nameTextView.setTextColor(onHoldColor); numberTextView.setTextColor(onHoldColor); diff --git a/java/com/android/incallui/res/layout/caller_in_conference.xml b/java/com/android/incallui/res/layout/caller_in_conference.xml index be4eca5f6..23bb28512 100644 --- a/java/com/android/incallui/res/layout/caller_in_conference.xml +++ b/java/com/android/incallui/res/layout/caller_in_conference.xml @@ -68,7 +68,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/SecondaryText" - android:textColor="@color/dialer_secondary_text_color_hiden" + android:textColor="@color/dialer_disabled_text_color" android:visibility="gone"/> -- cgit v1.2.3 From 3b9473d3807f21242432c586837ebfa094ce17e2 Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Tue, 24 Apr 2018 14:38:06 -0700 Subject: Newly starred SpeedDialUiItems now have SpeedDialEntry ids set. Bug: 78241895 Test: numerous PiperOrigin-RevId: 194147693 Change-Id: I9e9947ad689c5bf24dd52e37787f4138a92f5238 --- .../speeddial/database/SpeedDialEntryDao.java | 8 ++- .../database/SpeedDialEntryDatabaseHelper.java | 27 +++++++--- .../dialer/speeddial/loader/SpeedDialUiItem.java | 9 ++++ .../speeddial/loader/SpeedDialUiItemLoader.java | 63 +++++++++++++++------- 4 files changed, 79 insertions(+), 28 deletions(-) (limited to 'java') diff --git a/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java b/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java index ce771c3c8..4d6ac2d7f 100644 --- a/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java +++ b/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java @@ -17,6 +17,7 @@ package com.android.dialer.speeddial.database; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; /** * Interface that databases support speed dial entries should implement. @@ -32,8 +33,10 @@ public interface SpeedDialEntryDao { * Insert new entries. * *

{@link SpeedDialEntry#id() ids} must be null. + * + * @return a map of the inserted entries to their new ids. */ - void insert(ImmutableList entries); + ImmutableMap insert(ImmutableList entries); /** * Insert a new entry. @@ -59,11 +62,12 @@ public interface SpeedDialEntryDao { /** * Inserts, updates and deletes rows all in on transaction. * + * @return a map of the inserted entries to their new ids. * @see #insert(ImmutableList) * @see #update(ImmutableList) * @see #delete(ImmutableList) */ - void insertUpdateAndDelete( + ImmutableMap insertUpdateAndDelete( ImmutableList entriesToInsert, ImmutableList entriesToUpdate, ImmutableList entriesToDelete); diff --git a/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java b/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java index 137933fbe..544bb3613 100644 --- a/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java +++ b/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java @@ -26,6 +26,7 @@ import com.android.dialer.common.Assert; import com.android.dialer.common.database.Selection; import com.android.dialer.speeddial.database.SpeedDialEntry.Channel; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.List; @@ -132,30 +133,39 @@ public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper } @Override - public void insert(ImmutableList entries) { + public ImmutableMap insert(ImmutableList entries) { if (entries.isEmpty()) { - return; + return ImmutableMap.of(); } SQLiteDatabase db = getWritableDatabase(); db.beginTransaction(); try { - insert(db, entries); + ImmutableMap insertedEntriesToIdsMap = insert(db, entries); db.setTransactionSuccessful(); + return insertedEntriesToIdsMap; } finally { db.endTransaction(); db.close(); } } - private void insert(SQLiteDatabase writeableDatabase, ImmutableList entries) { + private ImmutableMap insert( + SQLiteDatabase writeableDatabase, ImmutableList entries) { + ImmutableMap.Builder insertedEntriesToIdsMap = ImmutableMap.builder(); for (SpeedDialEntry entry : entries) { Assert.checkArgument(entry.id() == null); - if (writeableDatabase.insert(TABLE_NAME, null, buildContentValuesWithoutId(entry)) == -1L) { + long id = writeableDatabase.insert(TABLE_NAME, null, buildContentValuesWithoutId(entry)); + if (id == -1L) { throw Assert.createUnsupportedOperationFailException( "Attempted to insert a row that already exists."); } + // It's impossible to insert two identical entries but this is an important assumption we need + // to verify because there's an assumption that each entry will correspond to exactly one id. + // ImmutableMap#put verifies this check for us. + insertedEntriesToIdsMap.put(entry, id); } + return insertedEntriesToIdsMap.build(); } @Override @@ -255,20 +265,21 @@ public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper } @Override - public void insertUpdateAndDelete( + public ImmutableMap insertUpdateAndDelete( ImmutableList entriesToInsert, ImmutableList entriesToUpdate, ImmutableList entriesToDelete) { if (entriesToInsert.isEmpty() && entriesToUpdate.isEmpty() && entriesToDelete.isEmpty()) { - return; + return ImmutableMap.of(); } SQLiteDatabase db = getWritableDatabase(); db.beginTransaction(); try { - insert(db, entriesToInsert); + ImmutableMap insertedEntriesToIdsMap = insert(db, entriesToInsert); update(db, entriesToUpdate); delete(db, entriesToDelete); db.setTransactionSuccessful(); + return insertedEntriesToIdsMap; } finally { db.endTransaction(); db.close(); diff --git a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java index 24bc776e7..9bda3fb31 100644 --- a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java +++ b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java @@ -136,6 +136,15 @@ public abstract class SpeedDialUiItem { return builder.build(); } + public SpeedDialEntry buildSpeedDialEntry() { + return SpeedDialEntry.builder() + .setId(speedDialEntryId()) + .setLookupKey(lookupKey()) + .setContactId(contactId()) + .setDefaultChannel(defaultChannel()) + .build(); + } + /** * Returns a video channel if there is exactly one video channel or the default channel is a video * channel. diff --git a/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java b/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java index 7107706fe..921468773 100644 --- a/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java +++ b/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java @@ -44,6 +44,7 @@ import com.android.dialer.speeddial.database.SpeedDialEntry.Channel; import com.android.dialer.speeddial.database.SpeedDialEntryDao; import com.android.dialer.speeddial.database.SpeedDialEntryDatabaseHelper; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import java.util.ArrayList; @@ -146,13 +147,7 @@ public final class SpeedDialUiItemLoader { } // Insert a new entry into the SpeedDialEntry database - getSpeedDialEntryDao() - .insert( - SpeedDialEntry.builder() - .setLookupKey(item.lookupKey()) - .setContactId(item.contactId()) - .setDefaultChannel(item.defaultChannel()) - .build()); + getSpeedDialEntryDao().insert(item.buildSpeedDialEntry()); } return loadSpeedDialUiItemsInternal(); } @@ -216,23 +211,55 @@ public final class SpeedDialUiItemLoader { contact.toBuilder().setDefaultChannel(contact.channels().get(0)).build()); } else if (speedDialUiItems.stream().noneMatch(c -> c.contactId() == contact.contactId())) { - entriesToInsert.add( - SpeedDialEntry.builder() - .setLookupKey(contact.lookupKey()) - .setContactId(contact.contactId()) - .setDefaultChannel(contact.defaultChannel()) - .build()); + entriesToInsert.add(contact.buildSpeedDialEntry()); // These are our newly starred contacts speedDialUiItems.add(contact); } } - db.insertUpdateAndDelete( - ImmutableList.copyOf(entriesToInsert), - ImmutableList.copyOf(entriesToUpdate), - ImmutableList.copyOf(entriesToDelete)); - return ImmutableList.copyOf(speedDialUiItems); + ImmutableMap insertedEntriesToIdsMap = + db.insertUpdateAndDelete( + ImmutableList.copyOf(entriesToInsert), + ImmutableList.copyOf(entriesToUpdate), + ImmutableList.copyOf(entriesToDelete)); + return speedDialUiItemsWithUpdatedIds(speedDialUiItems, insertedEntriesToIdsMap); + } + + /** + * Since newly starred contacts sometimes aren't in the SpeedDialEntry database, we couldn't set + * their ids when we created our initial list of {@link SpeedDialUiItem speedDialUiItems}. Now + * that we've inserted the entries into the database and we have their ids, build a new list of + * speedDialUiItems with the now known ids. + */ + private ImmutableList speedDialUiItemsWithUpdatedIds( + List speedDialUiItems, + ImmutableMap insertedEntriesToIdsMap) { + if (insertedEntriesToIdsMap.isEmpty()) { + // There were no newly inserted entries, so all entries ids are set already. + return ImmutableList.copyOf(speedDialUiItems); + } + + ImmutableList.Builder updatedItems = ImmutableList.builder(); + for (SpeedDialUiItem speedDialUiItem : speedDialUiItems) { + SpeedDialEntry entry = speedDialUiItem.buildSpeedDialEntry(); + if (insertedEntriesToIdsMap.containsKey(entry)) { + // Get the id for newly inserted entry, update our SpeedDialUiItem and add it to our list + Long id = Assert.isNotNull(insertedEntriesToIdsMap.get(entry)); + updatedItems.add(speedDialUiItem.toBuilder().setSpeedDialEntryId(id).build()); + continue; + } + + // Starred contacts that aren't in the map, should already have speed dial entry ids. + // Non-starred contacts (suggestions) aren't in the speed dial entry database, so they + // shouldn't have speed dial entry ids. + Assert.checkArgument( + speedDialUiItem.isStarred() == (speedDialUiItem.speedDialEntryId() != null), + "Contact must be starred with a speed dial entry id, or not starred with no id " + + "(suggested contacts)"); + updatedItems.add(speedDialUiItem); + } + return updatedItems.build(); } /** -- cgit v1.2.3 From 82953530c1db1ed497c1166e2e6c2b5b04282f8a Mon Sep 17 00:00:00 2001 From: linyuh Date: Tue, 24 Apr 2018 16:06:06 -0700 Subject: Convert CequintCallerIdContact into an @AutoValue Bug: 70989584 Test: None PiperOrigin-RevId: 194161852 Change-Id: I35e0748ab634a84f6b6a19b790bfc55090026a35 --- .../android/dialer/oem/CequintCallerIdManager.java | 56 +++++++++++++++------- .../dialer/phonenumbercache/ContactInfoHelper.java | 12 ++--- java/com/android/incallui/ContactInfoCache.java | 12 ++--- 3 files changed, 51 insertions(+), 29 deletions(-) (limited to 'java') diff --git a/java/com/android/dialer/oem/CequintCallerIdManager.java b/java/com/android/dialer/oem/CequintCallerIdManager.java index ee865bc14..55cafc15e 100644 --- a/java/com/android/dialer/oem/CequintCallerIdManager.java +++ b/java/com/android/dialer/oem/CequintCallerIdManager.java @@ -30,6 +30,7 @@ import android.text.TextUtils; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.configprovider.ConfigProviderBindings; +import com.google.auto.value.AutoValue; import java.util.concurrent.ConcurrentHashMap; /** @@ -70,20 +71,37 @@ public class CequintCallerIdManager { // TODO(wangqi): Revisit it and maybe remove it if it's not necessary. private final ConcurrentHashMap callLogCache; - /** Cequint caller id contact information. */ - public static class CequintCallerIdContact { - public final String name; - public final String geoDescription; - public final String imageUrl; + /** Cequint caller ID contact information. */ + @AutoValue + public abstract static class CequintCallerIdContact { - private CequintCallerIdContact(String name, String geoDescription, String imageUrl) { - this.name = name; - this.geoDescription = geoDescription; - this.imageUrl = imageUrl; + public abstract String name(); + + /** + * Description of the geolocation (e.g., "Mountain View, CA"), which is for display purpose + * only. + */ + public abstract String geolocation(); + + public abstract String photoUri(); + + static Builder builder() { + return new AutoValue_CequintCallerIdManager_CequintCallerIdContact.Builder(); + } + + @AutoValue.Builder + abstract static class Builder { + abstract Builder setName(String name); + + abstract Builder setGeolocation(String geolocation); + + abstract Builder setPhotoUri(String photoUri); + + abstract CequintCallerIdContact build(); } } - /** Check whether Cequint Caller Id provider package is available and enabled. */ + /** Check whether Cequint Caller ID provider package is available and enabled. */ @AnyThread public static synchronized boolean isCequintCallerIdEnabled(@NonNull Context context) { if (!ConfigProviderBindings.get(context).getBoolean(CONFIG_CALLER_ID_ENABLED, true)) { @@ -175,22 +193,26 @@ public class CequintCallerIdManager { String name = getString(cursor, cursor.getColumnIndex(NAME)); String firstName = getString(cursor, cursor.getColumnIndex(FIRST_NAME)); String lastName = getString(cursor, cursor.getColumnIndex(LAST_NAME)); - String imageUrl = getString(cursor, cursor.getColumnIndex(IMAGE)); + String photoUri = getString(cursor, cursor.getColumnIndex(IMAGE)); String displayName = getString(cursor, cursor.getColumnIndex(DISPLAY_NAME)); String contactName = TextUtils.isEmpty(displayName) ? generateDisplayName(firstName, lastName, company, name) : displayName; - String geoDescription = getGeoDescription(city, state, stateAbbr, country); + String geolocation = getGeolocation(city, state, stateAbbr, country); LogUtil.d( "CequintCallerIdManager.lookup", "number: %s, contact name: %s, geo: %s, photo url: %s", LogUtil.sanitizePhoneNumber(number), LogUtil.sanitizePii(contactName), - LogUtil.sanitizePii(geoDescription), - imageUrl); - return new CequintCallerIdContact(contactName, geoDescription, imageUrl); + LogUtil.sanitizePii(geolocation), + photoUri); + return CequintCallerIdContact.builder() + .setName(contactName) + .setGeolocation(geolocation) + .setPhotoUri(photoUri) + .build(); } else { LogUtil.d("CequintCallerIdManager.lookup", "No CequintCallerIdContact found"); return null; @@ -249,8 +271,8 @@ public class CequintCallerIdManager { return null; } - /** Returns geo location information. e.g. Mountain View, CA. */ - private static String getGeoDescription( + /** Returns geolocation information (e.g., "Mountain View, CA"). */ + private static String getGeolocation( String city, String state, String stateAbbr, String country) { String geoDescription = null; diff --git a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java index 777175e00..4302436a7 100644 --- a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java +++ b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java @@ -625,16 +625,16 @@ public class ContactInfoHelper { if (cequintCallerIdContact == null) { return; } - if (TextUtils.isEmpty(info.name) && !TextUtils.isEmpty(cequintCallerIdContact.name)) { - info.name = cequintCallerIdContact.name; + if (TextUtils.isEmpty(info.name) && !TextUtils.isEmpty(cequintCallerIdContact.name())) { + info.name = cequintCallerIdContact.name(); } - if (!TextUtils.isEmpty(cequintCallerIdContact.geoDescription)) { - info.geoDescription = cequintCallerIdContact.geoDescription; + if (!TextUtils.isEmpty(cequintCallerIdContact.geolocation())) { + info.geoDescription = cequintCallerIdContact.geolocation(); info.sourceType = ContactSource.Type.SOURCE_TYPE_CEQUINT_CALLER_ID; } // Only update photo if local lookup has no result. - if (!info.contactExists && info.photoUri == null && cequintCallerIdContact.imageUrl != null) { - info.photoUri = UriUtils.parseUriOrNull(cequintCallerIdContact.imageUrl); + if (!info.contactExists && info.photoUri == null && cequintCallerIdContact.photoUri() != null) { + info.photoUri = UriUtils.parseUriOrNull(cequintCallerIdContact.photoUri()); } } } diff --git a/java/com/android/incallui/ContactInfoCache.java b/java/com/android/incallui/ContactInfoCache.java index 165ec13bf..eefd4833c 100644 --- a/java/com/android/incallui/ContactInfoCache.java +++ b/java/com/android/incallui/ContactInfoCache.java @@ -522,20 +522,20 @@ public class ContactInfoCache implements OnImageLoadCompleteListener { } boolean hasUpdate = false; - if (TextUtils.isEmpty(callerInfo.name) && !TextUtils.isEmpty(cequintCallerIdContact.name)) { - callerInfo.name = cequintCallerIdContact.name; + if (TextUtils.isEmpty(callerInfo.name) && !TextUtils.isEmpty(cequintCallerIdContact.name())) { + callerInfo.name = cequintCallerIdContact.name(); hasUpdate = true; } - if (!TextUtils.isEmpty(cequintCallerIdContact.geoDescription)) { - callerInfo.geoDescription = cequintCallerIdContact.geoDescription; + if (!TextUtils.isEmpty(cequintCallerIdContact.geolocation())) { + callerInfo.geoDescription = cequintCallerIdContact.geolocation(); callerInfo.shouldShowGeoDescription = true; hasUpdate = true; } // Don't overwrite photo in local contacts. if (!callerInfo.contactExists && callerInfo.contactDisplayPhotoUri == null - && cequintCallerIdContact.imageUrl != null) { - callerInfo.contactDisplayPhotoUri = Uri.parse(cequintCallerIdContact.imageUrl); + && cequintCallerIdContact.photoUri() != null) { + callerInfo.contactDisplayPhotoUri = Uri.parse(cequintCallerIdContact.photoUri()); hasUpdate = true; } // Set contact to exist to avoid phone number service lookup. -- cgit v1.2.3 From 0ab7540db425179a2b45247ea7d950210fdedc8c Mon Sep 17 00:00:00 2001 From: twyen Date: Tue, 24 Apr 2018 16:19:02 -0700 Subject: Make SIM Selection hint multi-line SIM names can be really long and might be truncated if the template placed it at the end of the string. Also removed the char limit on the hint. TEST=TAP Bug: 69675796,72618783 Test: TAP PiperOrigin-RevId: 194163675 Change-Id: I8ee43ce87da80bc6438d2eaad480c63a0d89fbe2 --- .../com/android/contacts/common/res/layout/select_account_list_item.xml | 1 - java/com/android/dialer/precall/impl/res/values/strings.xml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'java') diff --git a/java/com/android/contacts/common/res/layout/select_account_list_item.xml b/java/com/android/contacts/common/res/layout/select_account_list_item.xml index bf52d6f09..98e7c5454 100644 --- a/java/com/android/contacts/common/res/layout/select_account_list_item.xml +++ b/java/com/android/contacts/common/res/layout/select_account_list_item.xml @@ -61,7 +61,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" - android:maxLines="1" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="@color/dialer_secondary_text_color" android:visibility="gone"/> diff --git a/java/com/android/dialer/precall/impl/res/values/strings.xml b/java/com/android/dialer/precall/impl/res/values/strings.xml index 3691271ce..5e7ddd36c 100644 --- a/java/com/android/dialer/precall/impl/res/values/strings.xml +++ b/java/com/android/dialer/precall/impl/res/values/strings.xml @@ -28,6 +28,6 @@ + [CHAR LIMIT=NONE]--> Not available while using %1$s \ No newline at end of file -- cgit v1.2.3 From a1723256b90fce7fad0a760bf8c889203b8d24df Mon Sep 17 00:00:00 2001 From: twyen Date: Tue, 24 Apr 2018 17:02:57 -0700 Subject: Use UI listener for preferred account worker in in call UI Before this CL it is ran on a non-UI task, where the callback might happen after the activity has already ended. TEST=manual Bug: 78517857 Test: manual PiperOrigin-RevId: 194169377 Change-Id: I0011019cb31b0b2c01c9d774776fb44dcac4d8c6 --- java/com/android/incallui/InCallActivity.java | 152 +++++++++++++++----------- 1 file changed, 86 insertions(+), 66 deletions(-) (limited to 'java') diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java index 68de8dcc3..2b6c2b49d 100644 --- a/java/com/android/incallui/InCallActivity.java +++ b/java/com/android/incallui/InCallActivity.java @@ -63,6 +63,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.ThreadUtil; +import com.android.dialer.common.concurrent.UiListener; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.logging.DialerImpression.Type; import com.android.dialer.logging.Logger; @@ -71,6 +72,7 @@ import com.android.dialer.metrics.Metrics; import com.android.dialer.metrics.MetricsComponent; import com.android.dialer.preferredsim.PreferredAccountRecorder; import com.android.dialer.preferredsim.PreferredAccountWorker; +import com.android.dialer.preferredsim.PreferredAccountWorker.Result; import com.android.dialer.preferredsim.suggestion.SuggestionProvider; import com.android.dialer.util.ViewUtil; import com.android.incallui.answer.bindings.AnswerBindings; @@ -103,6 +105,7 @@ import com.android.incallui.video.protocol.VideoCallScreen; import com.android.incallui.video.protocol.VideoCallScreenDelegate; import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory; import com.google.common.base.Optional; +import com.google.common.util.concurrent.ListenableFuture; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -132,6 +135,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity private static Optional audioRouteForTesting = Optional.absent(); private SelectPhoneAccountListener selectPhoneAccountListener; + private UiListener preferredAccountWorkerResultListener; private Animation dialpadSlideInAnimation; private Animation dialpadSlideOutAnimation; @@ -188,6 +192,10 @@ public class InCallActivity extends TransactionSafeFragmentActivity Trace.beginSection("InCallActivity.onCreate"); super.onCreate(bundle); + preferredAccountWorkerResultListener = + DialerExecutorComponent.get(this) + .createUiListener(getFragmentManager(), "preferredAccountWorkerResultListener"); + selectPhoneAccountListener = new SelectPhoneAccountListener(getApplicationContext()); if (bundle != null) { @@ -360,72 +368,84 @@ public class InCallActivity extends TransactionSafeFragmentActivity return false; } - DialerExecutorComponent.get(this) - .dialerExecutorFactory() - .createNonUiTaskBuilder(new PreferredAccountWorker(waitingForAccountCall.getNumber())) - .onSuccess( - (result -> { - if (result.getPhoneAccountHandle().isPresent()) { - Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED); - selectPhoneAccountListener.onPhoneAccountSelected( - result.getPhoneAccountHandle().get(), false, waitingForAccountCall.getId()); - return; - } - if (result.getSuggestion().isPresent()) { - LogUtil.i( - "CallingAccountSelector.processPreferredAccount", - "SIM suggested: " + result.getSuggestion().get().reason); - if (result.getSuggestion().get().shouldAutoSelect) { - Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED); - LogUtil.i( - "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion"); - selectPhoneAccountListener.onPhoneAccountSelected( - result.getSuggestion().get().phoneAccountHandle, - false, - waitingForAccountCall.getId()); - return; - } - } - Bundle extras = waitingForAccountCall.getIntentExtras(); - List phoneAccountHandles = - extras == null - ? new ArrayList<>() - : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS); - - waitingForAccountCall.setPreferredAccountRecorder( - new PreferredAccountRecorder( - waitingForAccountCall.getNumber(), - result.getSuggestion().orNull(), - result.getDataId().orNull())); - SelectPhoneAccountDialogOptions.Builder optionsBuilder = - SelectPhoneAccountDialogOptions.newBuilder() - .setTitle(R.string.select_phone_account_for_calls) - .setCanSetDefault(result.getDataId().isPresent()) - .setSetDefaultLabel(R.string.select_phone_account_for_calls_remember) - .setCallId(waitingForAccountCall.getId()); - - for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) { - SelectPhoneAccountDialogOptions.Entry.Builder entryBuilder = - SelectPhoneAccountDialogOptions.Entry.newBuilder(); - SelectPhoneAccountDialogOptionsUtil.setPhoneAccountHandle( - entryBuilder, phoneAccountHandle); - Optional hint = - SuggestionProvider.getHint( - this, phoneAccountHandle, result.getSuggestion().orNull()); - if (hint.isPresent()) { - entryBuilder.setHint(hint.get()); - } - optionsBuilder.addEntries(entryBuilder); - } - - selectPhoneAccountDialogFragment = - SelectPhoneAccountDialogFragment.newInstance( - optionsBuilder.build(), selectPhoneAccountListener); - selectPhoneAccountDialogFragment.show( - getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT); - })) - .build() - .executeParallel(this); + ListenableFuture preferredAccountFuture = + DialerExecutorComponent.get(this) + .backgroundExecutor() + .submit( + () -> { + try { + return new PreferredAccountWorker(waitingForAccountCall.getNumber()) + .doInBackground(getApplicationContext()); + } catch (Throwable throwable) { + throw new Exception(throwable); + } + }); + + preferredAccountWorkerResultListener.listen( + this, + preferredAccountFuture, + result -> { + if (result.getPhoneAccountHandle().isPresent()) { + Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED); + selectPhoneAccountListener.onPhoneAccountSelected( + result.getPhoneAccountHandle().get(), false, waitingForAccountCall.getId()); + return; + } + if (result.getSuggestion().isPresent()) { + LogUtil.i( + "CallingAccountSelector.processPreferredAccount", + "SIM suggested: " + result.getSuggestion().get().reason); + if (result.getSuggestion().get().shouldAutoSelect) { + Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED); + LogUtil.i( + "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion"); + selectPhoneAccountListener.onPhoneAccountSelected( + result.getSuggestion().get().phoneAccountHandle, + false, + waitingForAccountCall.getId()); + return; + } + } + Bundle extras = waitingForAccountCall.getIntentExtras(); + List phoneAccountHandles = + extras == null + ? new ArrayList<>() + : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS); + + waitingForAccountCall.setPreferredAccountRecorder( + new PreferredAccountRecorder( + waitingForAccountCall.getNumber(), + result.getSuggestion().orNull(), + result.getDataId().orNull())); + SelectPhoneAccountDialogOptions.Builder optionsBuilder = + SelectPhoneAccountDialogOptions.newBuilder() + .setTitle(R.string.select_phone_account_for_calls) + .setCanSetDefault(result.getDataId().isPresent()) + .setSetDefaultLabel(R.string.select_phone_account_for_calls_remember) + .setCallId(waitingForAccountCall.getId()); + + for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) { + SelectPhoneAccountDialogOptions.Entry.Builder entryBuilder = + SelectPhoneAccountDialogOptions.Entry.newBuilder(); + SelectPhoneAccountDialogOptionsUtil.setPhoneAccountHandle( + entryBuilder, phoneAccountHandle); + Optional hint = + SuggestionProvider.getHint( + this, phoneAccountHandle, result.getSuggestion().orNull()); + if (hint.isPresent()) { + entryBuilder.setHint(hint.get()); + } + optionsBuilder.addEntries(entryBuilder); + } + + selectPhoneAccountDialogFragment = + SelectPhoneAccountDialogFragment.newInstance( + optionsBuilder.build(), selectPhoneAccountListener); + selectPhoneAccountDialogFragment.show(getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT); + }, + throwable -> { + throw new RuntimeException(throwable); + }); return true; } -- cgit v1.2.3 From 79a407ee27e6c8f6447f3a8c71ae2c7f6b33f591 Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Wed, 25 Apr 2018 01:53:47 -0700 Subject: Show clear frequents option in the toolbar if there are suggested contacts. Bug: 36841782 Test: SpeedDialAdapterTest PiperOrigin-RevId: 194210091 Change-Id: I5b8ad5ca43ee6f519de09ad2a8b1b959637a825b --- java/com/android/dialer/common/FragmentUtils.java | 5 +++++ .../dialer/main/impl/NewMainActivityPeer.java | 23 +++++++++++----------- .../dialer/main/impl/OldMainActivityPeer.java | 23 ++++++++++++++++++++++ .../android/dialer/speeddial/SpeedDialAdapter.java | 5 +++++ .../dialer/speeddial/SpeedDialFragment.java | 17 +++++++++++----- 5 files changed, 57 insertions(+), 16 deletions(-) (limited to 'java') diff --git a/java/com/android/dialer/common/FragmentUtils.java b/java/com/android/dialer/common/FragmentUtils.java index c07d9a799..aa4441eeb 100644 --- a/java/com/android/dialer/common/FragmentUtils.java +++ b/java/com/android/dialer/common/FragmentUtils.java @@ -59,6 +59,11 @@ public class FragmentUtils { @SuppressWarnings("unchecked") // Casts are checked using runtime methods T parent = ((FragmentUtilListener) fragment.getActivity()).getImpl(callbackInterface); return parent; + } else if (fragment.getActivity() instanceof MainActivityPeer.PeerSupplier) { + MainActivityPeer peer = ((MainActivityPeer.PeerSupplier) fragment.getActivity()).getPeer(); + if (peer instanceof FragmentUtilListener) { + return ((FragmentUtilListener) peer).getImpl(callbackInterface); + } } return null; } diff --git a/java/com/android/dialer/main/impl/NewMainActivityPeer.java b/java/com/android/dialer/main/impl/NewMainActivityPeer.java index 0ab69a443..f2d6fa6d3 100644 --- a/java/com/android/dialer/main/impl/NewMainActivityPeer.java +++ b/java/com/android/dialer/main/impl/NewMainActivityPeer.java @@ -29,7 +29,6 @@ import com.android.dialer.main.MainActivityPeer; import com.android.dialer.main.impl.bottomnav.BottomNavBar; import com.android.dialer.main.impl.bottomnav.BottomNavBar.OnBottomNavTabSelectedListener; import com.android.dialer.main.impl.bottomnav.BottomNavBar.TabIndex; -import com.android.dialer.speeddial.SpeedDialFragment; import com.android.dialer.voicemail.listui.NewVoicemailFragment; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; @@ -106,16 +105,18 @@ public class NewMainActivityPeer implements MainActivityPeer { @Override public void onSpeedDialSelected() { hideAllFragments(); - SpeedDialFragment fragment = - (SpeedDialFragment) supportFragmentManager.findFragmentByTag(SPEED_DIAL_TAG); - if (fragment == null) { - supportFragmentManager - .beginTransaction() - .add(R.id.fragment_container, SpeedDialFragment.newInstance(), SPEED_DIAL_TAG) - .commit(); - } else { - supportFragmentManager.beginTransaction().show(fragment).commit(); - } + // TODO(calderwoodra): Since we aren't using fragment utils in this peer, let's disable + // speed dial until we figure out a solution. + // SpeedDialFragment fragment = + // (SpeedDialFragment) supportFragmentManager.findFragmentByTag(SPEED_DIAL_TAG); + // if (fragment == null) { + // supportFragmentManager + // .beginTransaction() + // .add(R.id.fragment_container, SpeedDialFragment.newInstance(), SPEED_DIAL_TAG) + // .commit(); + // } else { + // supportFragmentManager.beginTransaction().show(fragment).commit(); + // } } @Override diff --git a/java/com/android/dialer/main/impl/OldMainActivityPeer.java b/java/com/android/dialer/main/impl/OldMainActivityPeer.java index 1c0cad0b0..9ac351094 100644 --- a/java/com/android/dialer/main/impl/OldMainActivityPeer.java +++ b/java/com/android/dialer/main/impl/OldMainActivityPeer.java @@ -183,6 +183,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen // Speed Dial private MainOnPhoneNumberPickerActionListener onPhoneNumberPickerActionListener; private MainOldSpeedDialFragmentHost oldSpeedDialFragmentHost; + private MainSpeedDialFragmentHost speedDialFragmentHost; /** Language the device was in last time {@link #onSaveInstanceState(Bundle)} was called. */ private String savedLanguageCode; @@ -293,6 +294,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen activity.findViewById(R.id.remove_view), activity.findViewById(R.id.search_view_container), toolbar); + speedDialFragmentHost = new MainSpeedDialFragmentHost(toolbar); lastTabController = new LastTabController(activity, bottomNav, showVoicemailTab); @@ -639,6 +641,8 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen return (T) oldSpeedDialFragmentHost; } else if (callbackInterface.isInstance(searchController)) { return (T) searchController; + } else if (callbackInterface.isInstance(speedDialFragmentHost)) { + return (T) speedDialFragmentHost; } else { return null; } @@ -1190,6 +1194,25 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen } } + /** + * Handles the callbacks for {@link SpeedDialFragment}. + * + * @see SpeedDialFragment.HostInterface + */ + private static final class MainSpeedDialFragmentHost implements SpeedDialFragment.HostInterface { + + private final MainToolbar toolbar; + + MainSpeedDialFragmentHost(MainToolbar toolbar) { + this.toolbar = toolbar; + } + + @Override + public void setHasFrequents(boolean hasFrequents) { + toolbar.showClearFrequents(hasFrequents); + } + } + /** * Implementation of {@link OnBottomNavTabSelectedListener} that handles logic for showing each of * the main tabs and FAB. diff --git a/java/com/android/dialer/speeddial/SpeedDialAdapter.java b/java/com/android/dialer/speeddial/SpeedDialAdapter.java index 6f6ac5498..8a37e97dd 100644 --- a/java/com/android/dialer/speeddial/SpeedDialAdapter.java +++ b/java/com/android/dialer/speeddial/SpeedDialAdapter.java @@ -210,4 +210,9 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter speedDialUiItems) { + LogUtil.enterBlock("SpeedDialFragment.onSpeedDialUiItemListLoaded"); // TODO(calderwoodra): Use DiffUtil to properly update and animate the change adapter.setSpeedDialUiItems( UiItemLoaderComponent.get(getContext()) .speedDialUiItemLoader() .insertDuoChannels(getContext(), speedDialUiItems)); adapter.notifyDataSetChanged(); + if (getActivity() != null) { + FragmentUtils.getParentUnsafe(this, HostInterface.class) + .setHasFrequents(adapter.hasFrequents()); + } } @Override @@ -359,4 +360,10 @@ public class SpeedDialFragment extends Fragment { Contacts.CONTENT_URI, String.valueOf(speedDialUiItem.contactId())))); } } + + /** Interface for {@link SpeedDialFragment} to communicate with its host/parent. */ + public interface HostInterface { + + void setHasFrequents(boolean hasFrequents); + } } -- cgit v1.2.3