From 89e3d1bb7941993206861fe9115778f816262c07 Mon Sep 17 00:00:00 2001 From: erfanian Date: Wed, 2 May 2018 18:50:59 -0700 Subject: More refactoring Test: unit PiperOrigin-RevId: 195188099 Change-Id: Ie2273229c257a9a767715831c15d90a6985fdda8 --- .../HistoryItemActionBottomSheet.java | 6 +- java/com/android/incallui/InCallActivity.java | 3 +- java/com/android/incallui/call/DialerCall.java | 5 -- .../incallui/speakeasy/SpeakEasyCallManager.java | 12 ++++ .../speakeasy/SpeakEasyCallManagerStub.java | 15 +++++ .../incallui/speakeasy/runtime/Constraints.java | 74 ---------------------- 6 files changed, 32 insertions(+), 83 deletions(-) delete mode 100644 java/com/android/incallui/speakeasy/runtime/Constraints.java (limited to 'java') diff --git a/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java b/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java index e3e9e7a64..f90effc4c 100644 --- a/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java +++ b/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java @@ -20,9 +20,9 @@ import android.content.Context; import android.content.res.ColorStateList; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.design.widget.BottomSheetBehavior; -import android.support.design.widget.BottomSheetBehavior.BottomSheetCallback; -import android.support.design.widget.BottomSheetDialog; +import android.support.design.bottomsheet.BottomSheetBehavior; +import android.support.design.bottomsheet.BottomSheetBehavior.BottomSheetCallback; +import android.support.design.bottomsheet.BottomSheetDialog; import android.support.v4.content.ContextCompat; import android.text.TextUtils; import android.view.LayoutInflater; diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java index 5ac6b5029..98f001925 100644 --- a/java/com/android/incallui/InCallActivity.java +++ b/java/com/android/incallui/InCallActivity.java @@ -1504,7 +1504,8 @@ public class InCallActivity extends TransactionSafeFragmentActivity call.getVideoTech().isSelfManagedCamera(), shouldAllowAnswerAndRelease(call), CallList.getInstance().getBackgroundCall() != null, - call.isSpeakEasyEligible()); + getSpeakEasyCallManager().isAvailable(getApplicationContext()) + && call.isSpeakEasyEligible()); transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN); Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this); diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java index 1a0de1960..70678dbac 100644 --- a/java/com/android/incallui/call/DialerCall.java +++ b/java/com/android/incallui/call/DialerCall.java @@ -86,7 +86,6 @@ import com.android.incallui.audiomode.AudioModeProvider; import com.android.incallui.call.state.DialerCallState; import com.android.incallui.latencyreport.LatencyReport; import com.android.incallui.rtt.protocol.RttChatMessage; -import com.android.incallui.speakeasy.runtime.Constraints; import com.android.incallui.videotech.VideoTech; import com.android.incallui.videotech.VideoTech.VideoTechListener; import com.android.incallui.videotech.duo.DuoVideoTech; @@ -1697,10 +1696,6 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa /** Indicates the call is eligible for SpeakEasy */ public boolean isSpeakEasyEligible() { - if (!Constraints.isAvailable(context)) { - return false; - } - return !isPotentialEmergencyCallback() && !isEmergencyCall() && !isActiveRttCall() diff --git a/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java b/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java index f2721da7d..8a815d385 100644 --- a/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java +++ b/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java @@ -16,6 +16,7 @@ package com.android.incallui.speakeasy; +import android.content.Context; import android.support.annotation.NonNull; import android.support.v4.app.Fragment; import com.android.incallui.call.DialerCall; @@ -37,4 +38,15 @@ public interface SpeakEasyCallManager { * @param call The call which has been removed. */ void onCallRemoved(@NonNull DialerCall call); + + /** + * Indicates the feature is available. + * + * @param context The application context. + */ + boolean isAvailable(@NonNull Context context); + + /** Returns the config provider flag associated with the feature. */ + @NonNull + String getConfigProviderFlag(); } diff --git a/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java b/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java index 9e58ce18f..a0409737b 100644 --- a/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java +++ b/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java @@ -16,6 +16,8 @@ package com.android.incallui.speakeasy; +import android.content.Context; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import com.android.incallui.call.DialerCall; @@ -38,4 +40,17 @@ public class SpeakEasyCallManagerStub implements SpeakEasyCallManager { /** Always inert in the stub. */ @Override public void onCallRemoved(DialerCall call) {} + + /** Always returns false. */ + @Override + public boolean isAvailable(@NonNull Context unused) { + return false; + } + + /** Always returns a stub string. */ + @NonNull + @Override + public String getConfigProviderFlag() { + return "not_yet_implmented"; + } } diff --git a/java/com/android/incallui/speakeasy/runtime/Constraints.java b/java/com/android/incallui/speakeasy/runtime/Constraints.java deleted file mode 100644 index 1206d599c..000000000 --- a/java/com/android/incallui/speakeasy/runtime/Constraints.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.incallui.speakeasy.runtime; - -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build.VERSION_CODES; -import android.support.annotation.NonNull; -import android.support.annotation.VisibleForTesting; -import android.support.v4.os.BuildCompat; -import android.support.v4.os.UserManagerCompat; -import com.android.dialer.common.Assert; -import com.android.dialer.common.LogUtil; -import com.android.dialer.configprovider.ConfigProviderBindings; -import com.android.dialer.util.PermissionsUtil; - -/** Preconditions for the use of SpeakEasyModule */ -public final class Constraints { - - @VisibleForTesting public static final String SPEAK_EASY_ENABLED = "speak_easy_enabled"; - private static final String[] REQUIRED_PERMISSIONS = { - - }; - - // Non-instantiatable. - private Constraints() {} - - public static boolean isAvailable(@NonNull Context context) { - Assert.isNotNull(context); - - return isServerConfigEnabled(context) - && isUserUnlocked(context) - && meetsPlatformSdkFloor() - && hasNecessaryPermissions(context); - } - - private static boolean isServerConfigEnabled(@NonNull Context context) { - return ConfigProviderBindings.get(context).getBoolean(SPEAK_EASY_ENABLED, false); - } - - private static boolean isUserUnlocked(@NonNull Context context) { - return UserManagerCompat.isUserUnlocked(context); - } - - private static boolean meetsPlatformSdkFloor() { - return BuildCompat.isAtLeastP(); - } - - @SuppressWarnings("AndroidApiChecker") // Use of Java 8 APIs. - @TargetApi(VERSION_CODES.N) - private static boolean hasNecessaryPermissions(@NonNull Context context) { - for (String permission : REQUIRED_PERMISSIONS) { - if (!PermissionsUtil.hasPermission(context, permission)) { - LogUtil.i("Constraints.hasNecessaryPermissions", "missing permission: %s ", permission); - return false; - } - } - return true; - } -} -- cgit v1.2.3 From c1401221314601a479a7ad293cc382416f2304f3 Mon Sep 17 00:00:00 2001 From: maxwelb Date: Thu, 3 May 2018 11:51:02 -0700 Subject: Add spam status tests for CallList#onCallAdded There are some upcoming changes to CallList#onCallAdded, so this CL adds the tests needed to verify that behavior doesn't regress. This became something of a rabbit hole because: 1) CallListTest needed to use a FakeSpam so spam status could be changed 2) FakeSpam needed updates so it wouldn't crash when CallList calls it. This was implemented as a no-op for simplicity. It also needed to support the single number lookup method. 3) FakeCall needed updates to support setting the details' extras (needed tests) 4) ShadowCall needed updates to support setting the details' extras 5) DetailsProperty needed a new value 6) There was an old TODO to use a string that's now visible in the SDK 7) SharedPrefConfigProvider needed a new method to set the emergency call window long. Bug: 33779976,79171382 Test: Tap PiperOrigin-RevId: 195287258 Change-Id: Ib8b9fde35263183393e9bcbdcf73eeada24f28eb --- .../contacts/common/compat/telecom/TelecomManagerCompat.java | 5 ----- .../dialer/configprovider/SharedPrefConfigProvider.java | 4 ++++ java/com/android/incallui/call/DialerCall.java | 11 ++++++----- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'java') diff --git a/java/com/android/contacts/common/compat/telecom/TelecomManagerCompat.java b/java/com/android/contacts/common/compat/telecom/TelecomManagerCompat.java index bb0d3c625..ca8ed29ec 100644 --- a/java/com/android/contacts/common/compat/telecom/TelecomManagerCompat.java +++ b/java/com/android/contacts/common/compat/telecom/TelecomManagerCompat.java @@ -23,11 +23,6 @@ import java.lang.reflect.Field; /** Compatibility class for {@link android.telecom.TelecomManager}. */ public class TelecomManagerCompat { - // TODO(mdooley): remove once this is available in android.telecom.Call - // a bug - public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = - "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS"; - // Constants from http://cs/android/frameworks/base/telecomm/java/android/telecom/Call.java. public static final String EVENT_REQUEST_HANDOVER = "android.telecom.event.REQUEST_HANDOVER"; public static final String EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE = diff --git a/java/com/android/dialer/configprovider/SharedPrefConfigProvider.java b/java/com/android/dialer/configprovider/SharedPrefConfigProvider.java index ce95c5700..54e9c9aff 100644 --- a/java/com/android/dialer/configprovider/SharedPrefConfigProvider.java +++ b/java/com/android/dialer/configprovider/SharedPrefConfigProvider.java @@ -98,6 +98,10 @@ public class SharedPrefConfigProvider implements ConfigProvider { sharedPreferences.edit().putBoolean(PREF_PREFIX + key, value).apply(); } + public void putLong(String key, long value) { + sharedPreferences.edit().putLong(PREF_PREFIX + key, value).apply(); + } + @Override public String getString(String key, String defaultValue) { // Reading shared prefs on the main thread is generally safe since a single instance is cached. diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java index 70678dbac..9e1e17e2a 100644 --- a/java/com/android/incallui/call/DialerCall.java +++ b/java/com/android/incallui/call/DialerCall.java @@ -50,7 +50,6 @@ import android.telecom.VideoProfile; import android.text.TextUtils; import android.widget.Toast; import com.android.contacts.common.compat.CallCompat; -import com.android.contacts.common.compat.telecom.TelecomManagerCompat; import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.assisteddialing.TransformationInfo; import com.android.dialer.callintent.CallInitiationType; @@ -117,8 +116,11 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa public static final int PROPERTY_CODEC_KNOWN = 0x04000000; private static final String ID_PREFIX = "DialerCall_"; - private static final String CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS = + + @VisibleForTesting + public static final String CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS = "emergency_callback_window_millis"; + private static int idCounter = 0; /** @@ -821,10 +823,9 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa // We want to treat any incoming call that arrives a short time after an outgoing emergency call // as a potential emergency callback. if (getExtras() != null - && getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0) - > 0) { + && getExtras().getLong(Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0) > 0) { long lastEmergencyCallMillis = - getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0); + getExtras().getLong(Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0); if (isInEmergencyCallbackWindow(lastEmergencyCallMillis)) { return true; } -- cgit v1.2.3 From 49f90b332c6e716196276dab0f3d7e21b56b696e Mon Sep 17 00:00:00 2001 From: wangqi Date: Thu, 3 May 2018 12:34:08 -0700 Subject: Add test to verify no crash on multiple DialerCall#onRemovedFromCallList. This change also add a null check for RttCall when saving RTT transcript. Test: DialerCallTest PiperOrigin-RevId: 195293823 Change-Id: I67cf3410480ac106933486d9d31f0fbb3183b074 --- java/com/android/incallui/call/DialerCall.java | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'java') diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java index 9e1e17e2a..77e2ea30b 100644 --- a/java/com/android/incallui/call/DialerCall.java +++ b/java/com/android/incallui/call/DialerCall.java @@ -1058,6 +1058,7 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa } @TargetApi(28) + @Nullable public RttCall getRttCall() { if (!isActiveRttCall()) { return null; @@ -1111,16 +1112,18 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa if (!BuildCompat.isAtLeastP()) { return; } - // Save any remaining text in the buffer that's not shown by UI yet. - // This may happen when the call is switched to background before disconnect. - try { - String messageLeft = getRttCall().readImmediately(); - if (!TextUtils.isEmpty(messageLeft)) { - rttTranscript = - RttChatMessage.getRttTranscriptWithNewRemoteMessage(rttTranscript, messageLeft); + if (getRttCall() != null) { + // Save any remaining text in the buffer that's not shown by UI yet. + // This may happen when the call is switched to background before disconnect. + try { + String messageLeft = getRttCall().readImmediately(); + if (!TextUtils.isEmpty(messageLeft)) { + rttTranscript = + RttChatMessage.getRttTranscriptWithNewRemoteMessage(rttTranscript, messageLeft); + } + } catch (IOException e) { + LogUtil.e("DialerCall.saveRttTranscript", "error when reading remaining message", e); } - } catch (IOException e) { - LogUtil.e("DialerCall.saveRttTranscript", "error when reading remaining message", e); } // Don't save transcript if it's empty. if (rttTranscript.getMessagesCount() == 0) { @@ -1662,7 +1665,6 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa if (videoTechManager != null) { videoTechManager.dispatchRemovedFromCallList(); } - // TODO(a bug): Add tests for it to make sure no crash on subsequent call to this method. // TODO(wangqi): Consider moving this to a DialerCallListener. if (rttTranscript != null && !isCallRemoved) { saveRttTranscript(); -- cgit v1.2.3 From 253b4407c125acbb7add26592ba782144c4d0366 Mon Sep 17 00:00:00 2001 From: linyuh Date: Thu, 3 May 2018 12:42:04 -0700 Subject: Simplify how we build bottom sheet options (a.k.a. modules). Test: HistoryItemActionModulesBuilderTest, ModulesTest PiperOrigin-RevId: 195294876 Change-Id: Iac44f965a585975389da7dee758a94a8ad8311d3 --- .../android/dialer/calllog/ui/menu/Modules.java | 188 +++------- .../historyitemactions/BlockReportSpamModules.java | 120 +++++++ .../HistoryItemActionModulesBuilder.java | 400 +++++++++++++++++++++ .../dialer/historyitemactions/IntentModule.java | 9 + .../dialer/historyitemactions/SharedModules.java | 247 ------------- .../history_item_action_module_info.proto | 69 ++++ .../dialer/speeddial/SpeedDialFragment.java | 11 +- .../dialer/voicemail/listui/menu/Modules.java | 96 ++--- 8 files changed, 681 insertions(+), 459 deletions(-) create mode 100644 java/com/android/dialer/historyitemactions/BlockReportSpamModules.java create mode 100644 java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java delete mode 100644 java/com/android/dialer/historyitemactions/SharedModules.java create mode 100644 java/com/android/dialer/historyitemactions/history_item_action_module_info.proto (limited to 'java') diff --git a/java/com/android/dialer/calllog/ui/menu/Modules.java b/java/com/android/dialer/calllog/ui/menu/Modules.java index a56d6d5e2..b06e0fb1a 100644 --- a/java/com/android/dialer/calllog/ui/menu/Modules.java +++ b/java/com/android/dialer/calllog/ui/menu/Modules.java @@ -20,152 +20,53 @@ import android.content.Context; import android.provider.CallLog.Calls; import android.support.v4.os.BuildCompat; import android.text.TextUtils; -import com.android.dialer.blockreportspam.BlockReportSpamDialogInfo; import com.android.dialer.calldetails.CallDetailsActivity; import com.android.dialer.calldetails.CallDetailsHeaderInfo; -import com.android.dialer.callintent.CallInitiationType; -import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.calllog.model.CoalescedRow; import com.android.dialer.calllogutils.CallLogEntryText; import com.android.dialer.calllogutils.NumberAttributesConverter; -import com.android.dialer.duo.Duo; -import com.android.dialer.duo.DuoComponent; import com.android.dialer.glidephotomanager.PhotoInfo; -import com.android.dialer.historyitemactions.DividerModule; -import com.android.dialer.historyitemactions.DuoCallModule; import com.android.dialer.historyitemactions.HistoryItemActionModule; +import com.android.dialer.historyitemactions.HistoryItemActionModuleInfo; +import com.android.dialer.historyitemactions.HistoryItemActionModulesBuilder; import com.android.dialer.historyitemactions.IntentModule; -import com.android.dialer.historyitemactions.SharedModules; -import com.android.dialer.logging.ReportingLocation; import com.android.dialer.phonenumberutil.PhoneNumberHelper; -import com.android.dialer.util.CallUtil; -import com.google.common.base.Optional; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** - * Configures the modules for the bottom sheet; these are the rows below the top row (primary - * action) in the bottom sheet. + * Configures the modules for the bottom sheet; these are the rows below the top row (contact info) + * in the bottom sheet. */ -@SuppressWarnings("Guava") final class Modules { + /** + * Returns a list of {@link HistoryItemActionModule HistoryItemActionModules}, which are items in + * the bottom sheet. + */ static List fromRow(Context context, CoalescedRow row) { - // Conditionally add each module, which are items in the bottom sheet's menu. - List modules = new ArrayList<>(); - - String normalizedNumber = row.getNumber().getNormalizedNumber(); - boolean canPlaceCalls = - PhoneNumberHelper.canPlaceCallsTo(normalizedNumber, row.getNumberPresentation()); - - if (canPlaceCalls) { - modules.addAll(createModulesForCalls(context, row, normalizedNumber)); - Optional moduleForSendingTextMessage = - SharedModules.createModuleForSendingTextMessage( - context, normalizedNumber, row.getNumberAttributes().getIsBlocked()); - if (moduleForSendingTextMessage.isPresent()) { - modules.add(moduleForSendingTextMessage.get()); - } - } - - if (!modules.isEmpty()) { - modules.add(new DividerModule()); - } + HistoryItemActionModulesBuilder modulesBuilder = + new HistoryItemActionModulesBuilder(context, buildModuleInfo(row)); // TODO(zachh): Module for CallComposer. - if (canPlaceCalls) { - Optional moduleForAddingToContacts = - SharedModules.createModuleForAddingToContacts( - context, - row.getNumber(), - row.getNumberAttributes().getName(), - row.getNumberAttributes().getLookupUri(), - row.getNumberAttributes().getIsBlocked(), - row.getNumberAttributes().getIsSpam()); - if (moduleForAddingToContacts.isPresent()) { - modules.add(moduleForAddingToContacts.get()); - } - - BlockReportSpamDialogInfo blockReportSpamDialogInfo = - BlockReportSpamDialogInfo.newBuilder() - .setNormalizedNumber(row.getNumber().getNormalizedNumber()) - .setCountryIso(row.getNumber().getCountryIso()) - .setCallType(row.getCallType()) - .setReportingLocation(ReportingLocation.Type.CALL_LOG_HISTORY) - .setContactSource(row.getNumberAttributes().getContactSource()) - .build(); - modules.addAll( - SharedModules.createModulesHandlingBlockedOrSpamNumber( - context, - blockReportSpamDialogInfo, - row.getNumberAttributes().getIsBlocked(), - row.getNumberAttributes().getIsSpam())); - - Optional moduleForCopyingNumber = - SharedModules.createModuleForCopyingNumber(context, normalizedNumber); - if (moduleForCopyingNumber.isPresent()) { - modules.add(moduleForCopyingNumber.get()); - } + if (PhoneNumberHelper.canPlaceCallsTo( + row.getNumber().getNormalizedNumber(), row.getNumberPresentation())) { + modulesBuilder + .addModuleForVoiceCall() + .addModuleForVideoCall() + .addModuleForSendingTextMessage() + .addModuleForDivider() + .addModuleForAddingToContacts() + .addModuleForBlockedOrSpamNumber() + .addModuleForCopyingNumber(); } - modules.add(createModuleForAccessingCallDetails(context, row)); + List modules = modulesBuilder.build(); + // Add modules only available in the call log. + modules.add(createModuleForAccessingCallDetails(context, row)); modules.add(new DeleteCallLogItemModule(context, row.getCoalescedIds())); - - return modules; - } - - private static List createModulesForCalls( - Context context, CoalescedRow row, String normalizedNumber) { - // Don't add call options if a number is blocked. - if (row.getNumberAttributes().getIsBlocked()) { - return Collections.emptyList(); - } - - boolean isDuoCall = - DuoComponent.get(context).getDuo().isDuoAccount(row.getPhoneAccountComponentName()); - - List modules = new ArrayList<>(); - - // Add an audio call item - // TODO(zachh): Support post-dial digits; consider using DialerPhoneNumber. - CallIntentBuilder callIntentBuilder = - new CallIntentBuilder(normalizedNumber, CallInitiationType.Type.CALL_LOG) - .setAllowAssistedDial(canSupportAssistedDialing(row)); - // Leave PhoneAccountHandle blank so regular PreCall logic will be used. The account the call - // was made/received in should be ignored for audio and carrier video calls. - // TODO(a bug): figure out the correct video call behavior - modules.add(IntentModule.newCallModule(context, callIntentBuilder)); - - // If the call log entry is for a spam call, nothing more to be done. - if (row.getNumberAttributes().getIsSpam()) { - return modules; - } - - // If the call log entry is for a video call, add the corresponding video call options. - // Note that if the entry is for a Duo video call but Duo is not available, we will fall back to - // a carrier video call. - if ((row.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) { - modules.add( - isDuoCall && canPlaceDuoCall(context, normalizedNumber) - ? new DuoCallModule(context, normalizedNumber) - : IntentModule.newCallModule(context, callIntentBuilder.setIsVideoCall(true))); - return modules; - } - - // At this point, the call log entry is for an audio call. We will also show a video call option - // if the video capability is present. - // - // The carrier video call option takes precedence over Duo. - if (canPlaceCarrierVideoCall(context, row)) { - modules.add(IntentModule.newCallModule(context, callIntentBuilder.setIsVideoCall(true))); - } else if (canPlaceDuoCall(context, normalizedNumber)) { - modules.add(new DuoCallModule(context, normalizedNumber)); - } - return modules; } @@ -208,30 +109,27 @@ final class Modules { .build(); } - private static boolean canPlaceDuoCall(Context context, String phoneNumber) { - Duo duo = DuoComponent.get(context).getDuo(); - - return duo.isInstalled(context) - && duo.isEnabled(context) - && duo.isActivated(context) - && duo.isReachable(context, phoneNumber); - } - - private static boolean canPlaceCarrierVideoCall(Context context, CoalescedRow row) { - int carrierVideoAvailability = CallUtil.getVideoCallingAvailability(context); - boolean isCarrierVideoCallingEnabled = - ((carrierVideoAvailability & CallUtil.VIDEO_CALLING_ENABLED) - == CallUtil.VIDEO_CALLING_ENABLED); - boolean canRelyOnCarrierVideoPresence = - ((carrierVideoAvailability & CallUtil.VIDEO_CALLING_PRESENCE) - == CallUtil.VIDEO_CALLING_PRESENCE); - - return isCarrierVideoCallingEnabled - && canRelyOnCarrierVideoPresence - && row.getNumberAttributes().getCanSupportCarrierVideoCall(); - } - private static boolean canSupportAssistedDialing(CoalescedRow row) { return !TextUtils.isEmpty(row.getNumberAttributes().getLookupUri()); } + + private static HistoryItemActionModuleInfo buildModuleInfo(CoalescedRow row) { + return HistoryItemActionModuleInfo.newBuilder() + .setNormalizedNumber(row.getNumber().getNormalizedNumber()) + .setCountryIso(row.getNumber().getCountryIso()) + .setName(row.getNumberAttributes().getName()) + .setCallType(row.getCallType()) + .setFeatures(row.getFeatures()) + .setLookupUri(row.getNumberAttributes().getLookupUri()) + .setPhoneAccountComponentName(row.getPhoneAccountComponentName()) + .setCanReportAsInvalidNumber(row.getNumberAttributes().getCanReportAsInvalidNumber()) + .setCanSupportAssistedDialing(canSupportAssistedDialing(row)) + .setCanSupportCarrierVideoCall(row.getNumberAttributes().getCanSupportCarrierVideoCall()) + .setIsBlocked(row.getNumberAttributes().getIsBlocked()) + .setIsSpam(row.getNumberAttributes().getIsSpam()) + .setIsVoicemailCall(row.getIsVoicemailCall()) + .setContactSource(row.getNumberAttributes().getContactSource()) + .setHost(HistoryItemActionModuleInfo.Host.CALL_LOG) + .build(); + } } diff --git a/java/com/android/dialer/historyitemactions/BlockReportSpamModules.java b/java/com/android/dialer/historyitemactions/BlockReportSpamModules.java new file mode 100644 index 000000000..396c03376 --- /dev/null +++ b/java/com/android/dialer/historyitemactions/BlockReportSpamModules.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dialer.historyitemactions; + +import android.content.Context; +import com.android.dialer.blockreportspam.BlockReportSpamDialogInfo; +import com.android.dialer.blockreportspam.ShowBlockReportSpamDialogNotifier; + +/** Modules for blocking/unblocking a number and/or reporting it as spam/not spam. */ +final class BlockReportSpamModules { + + private BlockReportSpamModules() {} + + static HistoryItemActionModule moduleForMarkingNumberAsNotSpam( + Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo) { + + return new HistoryItemActionModule() { + @Override + public int getStringId() { + return R.string.not_spam; + } + + @Override + public int getDrawableId() { + return R.drawable.quantum_ic_report_off_vd_theme_24; + } + + @Override + public boolean onClick() { + ShowBlockReportSpamDialogNotifier.notifyShowDialogToReportNotSpam( + context, blockReportSpamDialogInfo); + return true; // Close the bottom sheet. + } + }; + } + + static HistoryItemActionModule moduleForBlockingNumber( + Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo) { + + return new HistoryItemActionModule() { + @Override + public int getStringId() { + return R.string.block_number; + } + + @Override + public int getDrawableId() { + return R.drawable.quantum_ic_block_vd_theme_24; + } + + @Override + public boolean onClick() { + ShowBlockReportSpamDialogNotifier.notifyShowDialogToBlockNumber( + context, blockReportSpamDialogInfo); + return true; // Close the bottom sheet. + } + }; + } + + static HistoryItemActionModule moduleForUnblockingNumber( + Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo) { + + return new HistoryItemActionModule() { + @Override + public int getStringId() { + return R.string.unblock_number; + } + + @Override + public int getDrawableId() { + return R.drawable.quantum_ic_unblock_vd_theme_24; + } + + @Override + public boolean onClick() { + ShowBlockReportSpamDialogNotifier.notifyShowDialogToUnblockNumber( + context, blockReportSpamDialogInfo); + + return true; // Close the bottom sheet. + } + }; + } + + static HistoryItemActionModule moduleForBlockingNumberAndOptionallyReportingSpam( + Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo) { + + return new HistoryItemActionModule() { + @Override + public int getStringId() { + return R.string.block_and_optionally_report_spam; + } + + @Override + public int getDrawableId() { + return R.drawable.quantum_ic_block_vd_theme_24; + } + + @Override + public boolean onClick() { + ShowBlockReportSpamDialogNotifier.notifyShowDialogToBlockNumberAndOptionallyReportSpam( + context, blockReportSpamDialogInfo); + return true; // Close the bottom sheet. + } + }; + } +} diff --git a/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java b/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java new file mode 100644 index 000000000..ca6d3f3e4 --- /dev/null +++ b/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dialer.historyitemactions; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.provider.CallLog.Calls; +import android.provider.ContactsContract; +import android.text.TextUtils; +import com.android.dialer.blockreportspam.BlockReportSpamDialogInfo; +import com.android.dialer.callintent.CallInitiationType; +import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.clipboard.ClipboardUtils; +import com.android.dialer.common.Assert; +import com.android.dialer.duo.Duo; +import com.android.dialer.duo.DuoComponent; +import com.android.dialer.logging.ReportingLocation; +import com.android.dialer.util.CallUtil; +import com.android.dialer.util.UriUtils; +import java.util.ArrayList; +import java.util.List; + +/** + * Builds a list of {@link HistoryItemActionModule HistoryItemActionModules}. + * + *

Example usage: + * + *


+ *    // Create a HistoryItemActionModuleInfo proto with the information you have.
+ *    // You can simply skip a field if there is no information for it.
+ *    HistoryItemActionModuleInfo moduleInfo =
+ *        HistoryItemActionModuleInfo.newBuilder()
+ *            .setNormalizedNumber("+16502530000")
+ *            .setCountryIso("US")
+ *            .setName("Google")
+ *            .build();
+ *
+ *    // Initialize the builder using the module info above.
+ *    // Note that some modules require an activity context to work so it is preferred to pass one
+ *    // instead of an application context to the builder.
+ *    HistoryItemActionModulesBuilder modulesBuilder =
+ *        new HistoryItemActionModulesBuilder(activityContext, moduleInfo);
+ *
+ *    // Add all modules you want in the order you like.
+ *    // If a module shouldn't be added according to the module info, it won't be.
+ *    // For example, if the module info is not for a video call and doesn't indicate the presence
+ *    // of video calling capabilities, calling addModuleForVideoCall() is a no-op.
+ *    modulesBuilder
+ *        .addModuleForVoiceCall()
+ *        .addModuleForVideoCall()
+ *        .addModuleForSendingTextMessage()
+ *        .addModuleForDivider()
+ *        .addModuleForAddingToContacts()
+ *        .addModuleForBlockedOrSpamNumber()
+ *        .addModuleForCopyingNumber();
+ *
+ *    List modules = modulesBuilder.build();
+ * 
+ */ +public final class HistoryItemActionModulesBuilder { + + private final Context context; + private final HistoryItemActionModuleInfo moduleInfo; + private final List modules; + + public HistoryItemActionModulesBuilder(Context context, HistoryItemActionModuleInfo moduleInfo) { + Assert.checkArgument( + moduleInfo.getHost() != HistoryItemActionModuleInfo.Host.UNKNOWN, + "A host must be specified."); + + this.context = context; + this.moduleInfo = moduleInfo; + this.modules = new ArrayList<>(); + } + + public List build() { + return new ArrayList<>(modules); + } + + /** + * Adds a module for placing a voice call. + * + *

The method is a no-op if the number is blocked. + */ + public HistoryItemActionModulesBuilder addModuleForVoiceCall() { + if (moduleInfo.getIsBlocked()) { + return this; + } + + // TODO(zachh): Support post-dial digits; consider using DialerPhoneNumber. + // Do not set PhoneAccountHandle so that regular PreCall logic will be used. The account used to + // place or receive the call should be ignored for voice calls. + CallIntentBuilder callIntentBuilder = + new CallIntentBuilder(moduleInfo.getNormalizedNumber(), getCallInitiationType()) + .setAllowAssistedDial(moduleInfo.getCanSupportAssistedDialing()); + modules.add(IntentModule.newCallModule(context, callIntentBuilder)); + return this; + } + + /** + * Adds a module for a carrier video call *or* a Duo video call. + * + *

If the number is blocked or marked as spam, this method is a no-op. + * + *

If the provided module info is for a Duo video call and Duo is available, add a Duo video + * call module. + * + *

If the provided module info is for a Duo video call but Duo is unavailable, add a carrier + * video call module. + * + *

If the provided module info is for a carrier video call, add a carrier video call module. + * + *

If the provided module info is for a voice call and the device has carrier video call + * capability, add a carrier video call module. + * + *

If the provided module info is for a voice call, the device doesn't have carrier video call + * capability, and Duo is available, add a Duo video call module. + */ + public HistoryItemActionModulesBuilder addModuleForVideoCall() { + if (moduleInfo.getIsBlocked() || moduleInfo.getIsSpam()) { + return this; + } + + // Do not set PhoneAccountHandle so that regular PreCall logic will be used. The account used to + // place or receive the call should be ignored for carrier video calls. + // TODO(a bug): figure out the correct video call behavior + HistoryItemActionModule carrierVideoCallModule = + IntentModule.newCallModule( + context, + new CallIntentBuilder(moduleInfo.getNormalizedNumber(), getCallInitiationType()) + .setAllowAssistedDial(moduleInfo.getCanSupportAssistedDialing()) + .setIsVideoCall(true)); + HistoryItemActionModule duoVideoCallModule = + new DuoCallModule(context, moduleInfo.getNormalizedNumber()); + + // If the module info is for a video call, add an appropriate video call module. + if ((moduleInfo.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) { + modules.add(isDuoCall() && canPlaceDuoCall() ? duoVideoCallModule : carrierVideoCallModule); + return this; + } + + // At this point, the module info is for an audio call. We will also add a video call module if + // the video capability is present. + // + // The carrier video call module takes precedence over the Duo module. + if (canPlaceCarrierVideoCall()) { + modules.add(carrierVideoCallModule); + } else if (canPlaceDuoCall()) { + modules.add(duoVideoCallModule); + } + return this; + } + + /** + * Adds a module for sending text messages. + * + *

The method is a no-op if the number is blocked or empty. + */ + public HistoryItemActionModulesBuilder addModuleForSendingTextMessage() { + // TODO(zachh): There are other conditions where this module should not be shown; consider + // voicemail, business numbers, etc. + if (moduleInfo.getIsBlocked() || TextUtils.isEmpty(moduleInfo.getNormalizedNumber())) { + return this; + } + + modules.add( + IntentModule.newModuleForSendingTextMessage(context, moduleInfo.getNormalizedNumber())); + return this; + } + + /** + * Adds a module for a divider. + * + *

The method is a no-op if the divider module will be the first module. + */ + public HistoryItemActionModulesBuilder addModuleForDivider() { + if (modules.isEmpty()) { + return this; + } + + modules.add(new DividerModule()); + return this; + } + + /** + * Adds a module for adding a number to Contacts. + * + *

The method is a no-op if + * + *

    + *
  • the number is blocked, + *
  • the number is marked as spam, + *
  • the number is empty, or + *
  • the number belongs to an existing contact. + *
+ */ + public HistoryItemActionModulesBuilder addModuleForAddingToContacts() { + if (moduleInfo.getIsBlocked() + || moduleInfo.getIsSpam() + || isExistingContact() + || TextUtils.isEmpty(moduleInfo.getNormalizedNumber())) { + return this; + } + + Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT); + intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE); + intent.putExtra(ContactsContract.Intents.Insert.PHONE, moduleInfo.getNormalizedNumber()); + + if (!TextUtils.isEmpty(moduleInfo.getName())) { + intent.putExtra(ContactsContract.Intents.Insert.NAME, moduleInfo.getName()); + } + + modules.add( + new IntentModule( + context, + intent, + R.string.add_to_contacts, + R.drawable.quantum_ic_person_add_vd_theme_24)); + return this; + } + + /** + * Add modules for blocking/unblocking a number and/or marking it as spam/not spam. + * + *

If a number is marked as spam, add two modules: + * + *

    + *
  • "Not spam" and "Block", or + *
  • "Not spam" and "Unblock". + *
+ * + *

If a number is blocked but not marked as spam, add the "Unblock" module. + * + *

If a number is not blocked or marked as spam, add the "Block/Report spam" module. + */ + public HistoryItemActionModulesBuilder addModuleForBlockedOrSpamNumber() { + BlockReportSpamDialogInfo blockReportSpamDialogInfo = + BlockReportSpamDialogInfo.newBuilder() + .setNormalizedNumber(moduleInfo.getNormalizedNumber()) + .setCountryIso(moduleInfo.getCountryIso()) + .setCallType(moduleInfo.getCallType()) + .setReportingLocation(getReportingLocation()) + .setContactSource(moduleInfo.getContactSource()) + .build(); + + // For a spam number, add two modules: + // (1) "Not spam" and "Block", or + // (2) "Not spam" and "Unblock". + if (moduleInfo.getIsSpam()) { + modules.add( + BlockReportSpamModules.moduleForMarkingNumberAsNotSpam( + context, blockReportSpamDialogInfo)); + modules.add( + moduleInfo.getIsBlocked() + ? BlockReportSpamModules.moduleForUnblockingNumber(context, blockReportSpamDialogInfo) + : BlockReportSpamModules.moduleForBlockingNumber(context, blockReportSpamDialogInfo)); + return this; + } + + // For a blocked non-spam number, add the "Unblock" module. + if (moduleInfo.getIsBlocked()) { + modules.add( + BlockReportSpamModules.moduleForUnblockingNumber(context, blockReportSpamDialogInfo)); + return this; + } + + // For a number that is neither a spam number nor blocked, add the "Block/Report spam" module. + modules.add( + BlockReportSpamModules.moduleForBlockingNumberAndOptionallyReportingSpam( + context, blockReportSpamDialogInfo)); + return this; + } + + /** + * Adds a module for copying a number. + * + *

The method is a no-op if the number is empty. + */ + public HistoryItemActionModulesBuilder addModuleForCopyingNumber() { + if (TextUtils.isEmpty(moduleInfo.getNormalizedNumber())) { + return this; + } + + modules.add( + new HistoryItemActionModule() { + @Override + public int getStringId() { + return R.string.copy_number; + } + + @Override + public int getDrawableId() { + return R.drawable.quantum_ic_content_copy_vd_theme_24; + } + + @Override + public boolean onClick() { + ClipboardUtils.copyText( + context, + /* label = */ null, + moduleInfo.getNormalizedNumber(), + /* showToast = */ true); + return false; + } + }); + return this; + } + + private boolean canPlaceCarrierVideoCall() { + int carrierVideoAvailability = CallUtil.getVideoCallingAvailability(context); + boolean isCarrierVideoCallingEnabled = + ((carrierVideoAvailability & CallUtil.VIDEO_CALLING_ENABLED) + == CallUtil.VIDEO_CALLING_ENABLED); + boolean canRelyOnCarrierVideoPresence = + ((carrierVideoAvailability & CallUtil.VIDEO_CALLING_PRESENCE) + == CallUtil.VIDEO_CALLING_PRESENCE); + + return isCarrierVideoCallingEnabled + && canRelyOnCarrierVideoPresence + && moduleInfo.getCanSupportCarrierVideoCall(); + } + + private boolean isDuoCall() { + return DuoComponent.get(context) + .getDuo() + .isDuoAccount(moduleInfo.getPhoneAccountComponentName()); + } + + private boolean canPlaceDuoCall() { + Duo duo = DuoComponent.get(context).getDuo(); + + return duo.isInstalled(context) + && duo.isEnabled(context) + && duo.isActivated(context) + && duo.isReachable(context, moduleInfo.getNormalizedNumber()); + } + + /** + * Lookup URIs are currently fetched from the cached column of the system call log. This URI + * contains encoded information for non-contacts for the purposes of populating contact cards. + * + *

We infer whether a contact is existing or not by checking if the lookup URI is "encoded" or + * not. + * + *

TODO(zachh): We should revisit this once the contact URI is no longer being read from the + * cached column in the system database, in case we decide not to overload the column. + */ + private boolean isExistingContact() { + return !TextUtils.isEmpty(moduleInfo.getLookupUri()) + && !UriUtils.isEncodedContactUri(Uri.parse(moduleInfo.getLookupUri())); + } + + /** + * Maps the value of {@link HistoryItemActionModuleInfo#getHost()} to {@link + * CallInitiationType.Type}, which is required by {@link CallIntentBuilder} to build a call + * intent. + */ + private CallInitiationType.Type getCallInitiationType() { + switch (moduleInfo.getHost()) { + case CALL_LOG: + return CallInitiationType.Type.CALL_LOG; + case VOICEMAIL: + return CallInitiationType.Type.VOICEMAIL_LOG; + default: + throw Assert.createUnsupportedOperationFailException( + String.format("Unsupported host: %s", moduleInfo.getHost())); + } + } + + /** + * Maps the value of {@link HistoryItemActionModuleInfo#getHost()} to {@link + * ReportingLocation.Type}, which is for logging where a spam number is reported. + */ + private ReportingLocation.Type getReportingLocation() { + switch (moduleInfo.getHost()) { + case CALL_LOG: + return ReportingLocation.Type.CALL_LOG_HISTORY; + case VOICEMAIL: + return ReportingLocation.Type.VOICEMAIL_HISTORY; + default: + throw Assert.createUnsupportedOperationFailException( + String.format("Unsupported host: %s", moduleInfo.getHost())); + } + } +} diff --git a/java/com/android/dialer/historyitemactions/IntentModule.java b/java/com/android/dialer/historyitemactions/IntentModule.java index f73d4c951..dc53064af 100644 --- a/java/com/android/dialer/historyitemactions/IntentModule.java +++ b/java/com/android/dialer/historyitemactions/IntentModule.java @@ -23,6 +23,7 @@ import android.support.annotation.StringRes; import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.precall.PreCall; import com.android.dialer.util.DialerUtils; +import com.android.dialer.util.IntentUtil; /** * {@link HistoryItemActionModule} useful for making easy to build modules based on starting an @@ -73,4 +74,12 @@ public class IntentModule implements HistoryItemActionModule { return new IntentModule(context, PreCall.getIntent(context, callIntentBuilder), text, image); } + + public static IntentModule newModuleForSendingTextMessage(Context context, String number) { + return new IntentModule( + context, + IntentUtil.getSendSmsIntent(number), + R.string.send_a_message, + R.drawable.quantum_ic_message_vd_theme_24); + } } diff --git a/java/com/android/dialer/historyitemactions/SharedModules.java b/java/com/android/dialer/historyitemactions/SharedModules.java deleted file mode 100644 index 8604bed1d..000000000 --- a/java/com/android/dialer/historyitemactions/SharedModules.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.dialer.historyitemactions; - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.provider.ContactsContract; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import com.android.dialer.DialerPhoneNumber; -import com.android.dialer.blockreportspam.BlockReportSpamDialogInfo; -import com.android.dialer.blockreportspam.ShowBlockReportSpamDialogNotifier; -import com.android.dialer.clipboard.ClipboardUtils; -import com.android.dialer.util.IntentUtil; -import com.android.dialer.util.UriUtils; -import com.google.common.base.Optional; -import java.util.ArrayList; -import java.util.List; - -/** - * Modules for the bottom sheet that are shared between NewVoicemailFragment and NewCallLogFragment - */ -@SuppressWarnings("Guava") -public class SharedModules { - - public static Optional createModuleForAddingToContacts( - Context context, - DialerPhoneNumber dialerPhoneNumber, - String name, - String lookupUri, - boolean isBlocked, - boolean isSpam) { - // Skip showing the menu item for a spam/blocked number. - if (isBlocked || isSpam) { - return Optional.absent(); - } - - // Skip showing the menu item for existing contacts. - if (isExistingContact(lookupUri)) { - return Optional.absent(); - } - - // Skip showing the menu item if there is no number. - String normalizedNumber = dialerPhoneNumber.getNormalizedNumber(); - if (TextUtils.isEmpty(normalizedNumber)) { - return Optional.absent(); - } - - Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT); - intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE); - intent.putExtra(ContactsContract.Intents.Insert.PHONE, normalizedNumber); - - if (!TextUtils.isEmpty(name)) { - intent.putExtra(ContactsContract.Intents.Insert.NAME, name); - } - - return Optional.of( - new IntentModule( - context, - intent, - R.string.add_to_contacts, - R.drawable.quantum_ic_person_add_vd_theme_24)); - } - - /** - * Lookup URIs are currently fetched from the cached column of the system call log. This URI - * contains encoded information for non-contacts for the purposes of populating contact cards. - * - *

We infer whether a contact is existing or not by checking if the lookup URI is "encoded" or - * not. - * - *

TODO(zachh): We should revisit this once the contact URI is no longer being read from the - * cached column in the system database, in case we decide not to overload the column. - */ - private static boolean isExistingContact(@Nullable String lookupUri) { - return !TextUtils.isEmpty(lookupUri) && !UriUtils.isEncodedContactUri(Uri.parse(lookupUri)); - } - - public static Optional createModuleForSendingTextMessage( - Context context, String normalizedNumber, boolean isBlocked) { - // Don't show the option to send a text message if the number is blocked. - if (isBlocked) { - return Optional.absent(); - } - - // TODO(zachh): There are some conditions where this module should not be shown; consider - // voicemail, business numbers, etc. - - return !TextUtils.isEmpty(normalizedNumber) - ? Optional.of( - new IntentModule( - context, - IntentUtil.getSendSmsIntent(normalizedNumber), - R.string.send_a_message, - R.drawable.quantum_ic_message_vd_theme_24)) - : Optional.absent(); - } - - /** - * Create modules related to blocking/unblocking a number and/or reporting it as spam/not spam. - */ - public static List createModulesHandlingBlockedOrSpamNumber( - Context context, - BlockReportSpamDialogInfo blockReportSpamDialogInfo, - boolean isBlocked, - boolean isSpam) { - List modules = new ArrayList<>(); - - // For a spam number, add two options: - // (1) "Not spam" and "Block", or - // (2) "Not spam" and "Unblock". - if (isSpam) { - modules.add(createModuleForMarkingNumberAsNonSpam(context, blockReportSpamDialogInfo)); - modules.add( - createModuleForBlockingOrUnblockingNumber(context, blockReportSpamDialogInfo, isBlocked)); - return modules; - } - - // For a blocked non-spam number, add "Unblock" option. - if (isBlocked) { - modules.add( - createModuleForBlockingOrUnblockingNumber(context, blockReportSpamDialogInfo, isBlocked)); - return modules; - } - - // For a number that is neither a spam number nor blocked, add "Block/Report spam" option. - modules.add( - createModuleForBlockingNumberAndOptionallyReportingSpam( - context, blockReportSpamDialogInfo)); - return modules; - } - - /** Create "Not spam" module. */ - private static HistoryItemActionModule createModuleForMarkingNumberAsNonSpam( - Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo) { - return new HistoryItemActionModule() { - @Override - public int getStringId() { - return R.string.not_spam; - } - - @Override - public int getDrawableId() { - return R.drawable.quantum_ic_report_off_vd_theme_24; - } - - @Override - public boolean onClick() { - ShowBlockReportSpamDialogNotifier.notifyShowDialogToReportNotSpam( - context, blockReportSpamDialogInfo); - return true; // Close the bottom sheet. - } - }; - } - - private static HistoryItemActionModule createModuleForBlockingOrUnblockingNumber( - Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo, boolean isBlocked) { - return new HistoryItemActionModule() { - @Override - public int getStringId() { - return isBlocked ? R.string.unblock_number : R.string.block_number; - } - - @Override - public int getDrawableId() { - return isBlocked - ? R.drawable.quantum_ic_unblock_vd_theme_24 - : R.drawable.quantum_ic_block_vd_theme_24; - } - - @Override - public boolean onClick() { - if (isBlocked) { - ShowBlockReportSpamDialogNotifier.notifyShowDialogToUnblockNumber( - context, blockReportSpamDialogInfo); - } else { - ShowBlockReportSpamDialogNotifier.notifyShowDialogToBlockNumber( - context, blockReportSpamDialogInfo); - } - return true; // Close the bottom sheet. - } - }; - } - - /** Create "Block/Report spam" module */ - private static HistoryItemActionModule createModuleForBlockingNumberAndOptionallyReportingSpam( - Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo) { - return new HistoryItemActionModule() { - @Override - public int getStringId() { - return R.string.block_and_optionally_report_spam; - } - - @Override - public int getDrawableId() { - return R.drawable.quantum_ic_block_vd_theme_24; - } - - @Override - public boolean onClick() { - ShowBlockReportSpamDialogNotifier.notifyShowDialogToBlockNumberAndOptionallyReportSpam( - context, blockReportSpamDialogInfo); - return true; // Close the bottom sheet. - } - }; - } - - public static Optional createModuleForCopyingNumber( - Context context, String normalizedNumber) { - if (TextUtils.isEmpty(normalizedNumber)) { - return Optional.absent(); - } - return Optional.of( - new HistoryItemActionModule() { - @Override - public int getStringId() { - return R.string.copy_number; - } - - @Override - public int getDrawableId() { - return R.drawable.quantum_ic_content_copy_vd_theme_24; - } - - @Override - public boolean onClick() { - ClipboardUtils.copyText(context, null, normalizedNumber, true); - return false; - } - }); - } -} diff --git a/java/com/android/dialer/historyitemactions/history_item_action_module_info.proto b/java/com/android/dialer/historyitemactions/history_item_action_module_info.proto new file mode 100644 index 000000000..99071a7cd --- /dev/null +++ b/java/com/android/dialer/historyitemactions/history_item_action_module_info.proto @@ -0,0 +1,69 @@ +syntax = "proto2"; + +option java_package = "com.android.dialer.historyitemactions"; +option java_multiple_files = true; +option optimize_for = LITE_RUNTIME; + + +package com.android.dialer.historyitemactions; + +import "java/com/android/dialer/logging/contact_source.proto"; + +// Contains information needed to construct items (modules) in a bottom sheet. +// Next ID: 16 +message HistoryItemActionModuleInfo { + // The dialer-normalized version of a phone number. + // See DialerPhoneNumber.normalized_number. + optional string normalized_number = 1; + + // The ISO 3166-1 two letters country code of the number. + optional string country_iso = 2; + + // The name associated with the number. + optional string name = 3; + + // The type of the call. + // See android.provider.CallLog.Calls.TYPE. + optional int32 call_type = 4; + + // Bit-mask describing features of the call. + // See android.provider.CallLog.Calls.FEATURES. + optional int32 features = 5; + + // The Contacts Provider lookup URI for the contact associated with the + // number. + optional string lookup_uri = 6; + + // The component name of the account used to place or receive the call. + // See android.provider.CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME. + optional string phone_account_component_name = 7; + + // Whether the number can be reported as invalid through People API + optional bool can_report_as_invalid_number = 8; + + // Whether assisted dialing is supported. + optional bool can_support_assisted_dialing = 9; + + // Whether carrier video call is supported. + optional bool can_support_carrier_video_call = 10; + + // Whether the number is blocked. + optional bool is_blocked = 11; + + // Whether the number is spam. + optional bool is_spam = 12; + + // Whether the call is to the voicemail inbox. + optional bool is_voicemail_call = 13; + + // The source of the contact if there is one associated with the number. + optional com.android.dialer.logging.ContactSource.Type contact_source = 14; + + // Places that can host items (modules) in a bottom sheet + enum Host { + UNKNOWN = 0; + CALL_LOG = 1; + VOICEMAIL = 2; + } + optional Host host = 15; +} diff --git a/java/com/android/dialer/speeddial/SpeedDialFragment.java b/java/com/android/dialer/speeddial/SpeedDialFragment.java index db4c0245e..aa306d214 100644 --- a/java/com/android/dialer/speeddial/SpeedDialFragment.java +++ b/java/com/android/dialer/speeddial/SpeedDialFragment.java @@ -29,6 +29,7 @@ import android.support.v4.app.FragmentManager; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -46,7 +47,6 @@ import com.android.dialer.historyitemactions.HistoryItemActionBottomSheet; import com.android.dialer.historyitemactions.HistoryItemActionModule; import com.android.dialer.historyitemactions.HistoryItemBottomSheetHeaderInfo; import com.android.dialer.historyitemactions.IntentModule; -import com.android.dialer.historyitemactions.SharedModules; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; import com.android.dialer.precall.PreCall; @@ -60,7 +60,6 @@ import com.android.dialer.speeddial.draghelper.SpeedDialLayoutManager; import com.android.dialer.speeddial.loader.SpeedDialUiItem; import com.android.dialer.speeddial.loader.UiItemLoaderComponent; import com.android.dialer.util.IntentUtil; -import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.Futures; import java.util.ArrayList; @@ -312,11 +311,9 @@ public class SpeedDialFragment extends Fragment { } // Add sms module - Optional smsModule = - SharedModules.createModuleForSendingTextMessage( - getContext(), defaultChannel.number(), false); - if (smsModule.isPresent()) { - modules.add(smsModule.get()); + if (!TextUtils.isEmpty(defaultChannel.number())) { + modules.add( + IntentModule.newModuleForSendingTextMessage(getContext(), defaultChannel.number())); } modules.add(new DividerModule()); diff --git a/java/com/android/dialer/voicemail/listui/menu/Modules.java b/java/com/android/dialer/voicemail/listui/menu/Modules.java index 226063c1b..dcd9116e9 100644 --- a/java/com/android/dialer/voicemail/listui/menu/Modules.java +++ b/java/com/android/dialer/voicemail/listui/menu/Modules.java @@ -17,77 +17,53 @@ package com.android.dialer.voicemail.listui.menu; import android.content.Context; -import com.android.dialer.blockreportspam.BlockReportSpamDialogInfo; -import com.android.dialer.historyitemactions.DividerModule; +import android.text.TextUtils; import com.android.dialer.historyitemactions.HistoryItemActionModule; -import com.android.dialer.historyitemactions.SharedModules; -import com.android.dialer.logging.ReportingLocation; +import com.android.dialer.historyitemactions.HistoryItemActionModuleInfo; +import com.android.dialer.historyitemactions.HistoryItemActionModulesBuilder; import com.android.dialer.voicemail.model.VoicemailEntry; -import com.google.common.base.Optional; -import java.util.ArrayList; import java.util.List; /** * Configures the modules for the voicemail bottom sheet; these are the rows below the top row - * (primary action) in the bottom sheet. + * (contact info) in the bottom sheet. */ -@SuppressWarnings("Guava") final class Modules { static List fromVoicemailEntry( Context context, VoicemailEntry voicemailEntry) { - // Conditionally add each module, which are items in the bottom sheet's menu. - List modules = new ArrayList<>(); - - // TODO(uabdullah): Handle maybeAddModuleForVideoOrAudioCall(context, modules, row); - Optional moduleForAddingContacts = - SharedModules.createModuleForAddingToContacts( - context, - voicemailEntry.getNumber(), - voicemailEntry.getNumberAttributes().getName(), - voicemailEntry.getNumberAttributes().getLookupUri(), - voicemailEntry.getNumberAttributes().getIsBlocked(), - voicemailEntry.getNumberAttributes().getIsSpam()); - if (moduleForAddingContacts.isPresent()) { - modules.add(moduleForAddingContacts.get()); - } - - Optional moduleForSendingTextMessage = - SharedModules.createModuleForSendingTextMessage( - context, - voicemailEntry.getNumber().getNormalizedNumber(), - voicemailEntry.getNumberAttributes().getIsBlocked()); - if (moduleForSendingTextMessage.isPresent()) { - modules.add(moduleForSendingTextMessage.get()); - } - - if (!modules.isEmpty()) { - modules.add(new DividerModule()); - } - - BlockReportSpamDialogInfo blockReportSpamDialogInfo = - BlockReportSpamDialogInfo.newBuilder() - .setNormalizedNumber(voicemailEntry.getNumber().getNormalizedNumber()) - .setCountryIso(voicemailEntry.getNumber().getCountryIso()) - .setCallType(voicemailEntry.getCallType()) - .setReportingLocation(ReportingLocation.Type.VOICEMAIL_HISTORY) - .setContactSource(voicemailEntry.getNumberAttributes().getContactSource()) - .build(); - modules.addAll( - SharedModules.createModulesHandlingBlockedOrSpamNumber( - context, - blockReportSpamDialogInfo, - voicemailEntry.getNumberAttributes().getIsBlocked(), - voicemailEntry.getNumberAttributes().getIsSpam())); - - // TODO(zachh): Module for CallComposer. - Optional moduleForCopyingNumber = - SharedModules.createModuleForCopyingNumber( - context, voicemailEntry.getNumber().getNormalizedNumber()); - if (moduleForCopyingNumber.isPresent()) { - modules.add(moduleForCopyingNumber.get()); - } + return new HistoryItemActionModulesBuilder(context, buildModuleInfo(voicemailEntry)) + // TODO(uabdullah): add module for calls. + .addModuleForAddingToContacts() + .addModuleForSendingTextMessage() + .addModuleForDivider() + .addModuleForBlockedOrSpamNumber() + .addModuleForCopyingNumber() + // TODO(zachh): Module for CallComposer. + .build(); + } - return modules; + private static HistoryItemActionModuleInfo buildModuleInfo(VoicemailEntry voicemailEntry) { + return HistoryItemActionModuleInfo.newBuilder() + .setNormalizedNumber(voicemailEntry.getNumber().getNormalizedNumber()) + .setCountryIso(voicemailEntry.getNumber().getCountryIso()) + .setName(voicemailEntry.getNumberAttributes().getName()) + .setCallType(voicemailEntry.getCallType()) + .setLookupUri(voicemailEntry.getNumberAttributes().getLookupUri()) + .setPhoneAccountComponentName(voicemailEntry.getPhoneAccountComponentName()) + .setCanReportAsInvalidNumber( + voicemailEntry.getNumberAttributes().getCanReportAsInvalidNumber()) + .setCanSupportAssistedDialing( + !TextUtils.isEmpty(voicemailEntry.getNumberAttributes().getLookupUri())) + .setCanSupportCarrierVideoCall( + voicemailEntry.getNumberAttributes().getCanSupportCarrierVideoCall()) + .setIsBlocked(voicemailEntry.getNumberAttributes().getIsBlocked()) + .setIsSpam(voicemailEntry.getNumberAttributes().getIsSpam()) + // A voicemail call is an outgoing call to the voicemail box. + // Voicemail entries are not voicemail calls. + .setIsVoicemailCall(false) + .setContactSource(voicemailEntry.getNumberAttributes().getContactSource()) + .setHost(HistoryItemActionModuleInfo.Host.VOICEMAIL) + .build(); } } -- cgit v1.2.3 From bc258a50efe33210ff698cefcfaeb5c4bb401183 Mon Sep 17 00:00:00 2001 From: twyen Date: Thu, 3 May 2018 15:04:54 -0700 Subject: Mark photo info as voicemails in bottom sheet TEST=TAP Bug: 79089209 Test: TAP PiperOrigin-RevId: 195317152 Change-Id: I2d456dc786f2ea6555b76d3ef6721140acee7413 --- java/com/android/dialer/calllog/ui/menu/BottomSheetHeader.java | 1 + 1 file changed, 1 insertion(+) (limited to 'java') diff --git a/java/com/android/dialer/calllog/ui/menu/BottomSheetHeader.java b/java/com/android/dialer/calllog/ui/menu/BottomSheetHeader.java index d87888d34..4e25cedf4 100644 --- a/java/com/android/dialer/calllog/ui/menu/BottomSheetHeader.java +++ b/java/com/android/dialer/calllog/ui/menu/BottomSheetHeader.java @@ -34,6 +34,7 @@ final class BottomSheetHeader { NumberAttributesConverter.toPhotoInfoBuilder(row.getNumberAttributes()) .setFormattedNumber(row.getFormattedNumber()) .setIsVideo((row.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) + .setIsVoicemail(row.getIsVoicemailCall()) .setIsRtt( BuildCompat.isAtLeastP() && (row.getFeatures() & Calls.FEATURES_RTT) == Calls.FEATURES_RTT) -- cgit v1.2.3 From 0f224557fa34a4b810fb1128cf35231668d6e583 Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Thu, 3 May 2018 15:15:36 -0700 Subject: Aosp fix for v28-support-prelease bottom sheet. The bottomsheet in v28-prelease support library is no longer available. So revert back to the deprecated bottom sheet. Test: manual PiperOrigin-RevId: 195319010 Change-Id: I580ef4d979d50864ea385b01245dfbeb68b8579d --- .../dialer/historyitemactions/HistoryItemActionBottomSheet.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'java') diff --git a/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java b/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java index f90effc4c..e3e9e7a64 100644 --- a/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java +++ b/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java @@ -20,9 +20,9 @@ import android.content.Context; import android.content.res.ColorStateList; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.design.bottomsheet.BottomSheetBehavior; -import android.support.design.bottomsheet.BottomSheetBehavior.BottomSheetCallback; -import android.support.design.bottomsheet.BottomSheetDialog; +import android.support.design.widget.BottomSheetBehavior; +import android.support.design.widget.BottomSheetBehavior.BottomSheetCallback; +import android.support.design.widget.BottomSheetDialog; import android.support.v4.content.ContextCompat; import android.text.TextUtils; import android.view.LayoutInflater; -- cgit v1.2.3 From e62700865987d7a46c8d51d7be1144282194c94f Mon Sep 17 00:00:00 2001 From: linyuh Date: Thu, 3 May 2018 15:18:04 -0700 Subject: Filter out unnecessary bottom sheet options for a call to a voicemail box. Bug: 78476115 Test: HistoryItemActionModulesBuilderTest PiperOrigin-RevId: 195319447 Change-Id: I7d431e74c2f4efe6ea3ce24b7d3ae42ebb4525b2 --- .../HistoryItemActionModulesBuilder.java | 36 +++++++++++++++++----- 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'java') diff --git a/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java b/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java index ca6d3f3e4..9af08be50 100644 --- a/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java +++ b/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java @@ -115,7 +115,13 @@ public final class HistoryItemActionModulesBuilder { /** * Adds a module for a carrier video call *or* a Duo video call. * - *

If the number is blocked or marked as spam, this method is a no-op. + *

This method is a no-op if + * + *

    + *
  • the call is one made to a voicemail box, + *
  • the number is blocked, or + *
  • the number is marked as spam. + *
* *

If the provided module info is for a Duo video call and Duo is available, add a Duo video * call module. @@ -132,7 +138,7 @@ public final class HistoryItemActionModulesBuilder { * capability, and Duo is available, add a Duo video call module. */ public HistoryItemActionModulesBuilder addModuleForVideoCall() { - if (moduleInfo.getIsBlocked() || moduleInfo.getIsSpam()) { + if (moduleInfo.getIsVoicemailCall() || moduleInfo.getIsBlocked() || moduleInfo.getIsSpam()) { return this; } @@ -169,12 +175,20 @@ public final class HistoryItemActionModulesBuilder { /** * Adds a module for sending text messages. * - *

The method is a no-op if the number is blocked or empty. + *

The method is a no-op if + * + *

    + *
  • the call is one made to a voicemail box, + *
  • the number is blocked, or + *
  • the number is empty. + *
*/ public HistoryItemActionModulesBuilder addModuleForSendingTextMessage() { - // TODO(zachh): There are other conditions where this module should not be shown; consider - // voicemail, business numbers, etc. - if (moduleInfo.getIsBlocked() || TextUtils.isEmpty(moduleInfo.getNormalizedNumber())) { + // TODO(zachh): There are other conditions where this module should not be shown + // (e.g., business numbers). + if (moduleInfo.getIsVoicemailCall() + || moduleInfo.getIsBlocked() + || TextUtils.isEmpty(moduleInfo.getNormalizedNumber())) { return this; } @@ -203,6 +217,7 @@ public final class HistoryItemActionModulesBuilder { *

The method is a no-op if * *

    + *
  • the call is one made to a voicemail box, *
  • the number is blocked, *
  • the number is marked as spam, *
  • the number is empty, or @@ -210,7 +225,8 @@ public final class HistoryItemActionModulesBuilder { *
*/ public HistoryItemActionModulesBuilder addModuleForAddingToContacts() { - if (moduleInfo.getIsBlocked() + if (moduleInfo.getIsVoicemailCall() + || moduleInfo.getIsBlocked() || moduleInfo.getIsSpam() || isExistingContact() || TextUtils.isEmpty(moduleInfo.getNormalizedNumber())) { @@ -237,6 +253,8 @@ public final class HistoryItemActionModulesBuilder { /** * Add modules for blocking/unblocking a number and/or marking it as spam/not spam. * + *

The method is a no-op if the call is one made to a voicemail box. + * *

If a number is marked as spam, add two modules: * *

    @@ -249,6 +267,10 @@ public final class HistoryItemActionModulesBuilder { *

    If a number is not blocked or marked as spam, add the "Block/Report spam" module. */ public HistoryItemActionModulesBuilder addModuleForBlockedOrSpamNumber() { + if (moduleInfo.getIsVoicemailCall()) { + return this; + } + BlockReportSpamDialogInfo blockReportSpamDialogInfo = BlockReportSpamDialogInfo.newBuilder() .setNormalizedNumber(moduleInfo.getNormalizedNumber()) -- cgit v1.2.3 From 8d4afb83b0c19bf886b282de21357c9fe3be1869 Mon Sep 17 00:00:00 2001 From: twyen Date: Thu, 3 May 2018 16:41:54 -0700 Subject: Clear NewCallLogViewHolder.onClickListener if row is not callable. Previously the listener is not cleared, and clicking on a private will call whatever the view was previously bound to. TEST=TAP Bug: 79219109 Test: TAP PiperOrigin-RevId: 195332291 Change-Id: I4806ab659099dc7986b90c68f2e52d8efd4f5f5b --- java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java | 1 + 1 file changed, 1 insertion(+) (limited to 'java') diff --git a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java index 44a08c75e..c02d80ede 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java @@ -268,6 +268,7 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { private void setOnClickListenerForRow(CoalescedRow row) { if (!PhoneNumberHelper.canPlaceCallsTo( row.getNumber().getNormalizedNumber(), row.getNumberPresentation())) { + itemView.setOnClickListener(null); return; } itemView.setOnClickListener(view -> CallLogRowActions.startCallForRow(activity, row)); -- cgit v1.2.3 From fb2154107b6e0c29d89dd530fe05e2f94b3ae27a Mon Sep 17 00:00:00 2001 From: wangqi Date: Thu, 3 May 2018 18:02:10 -0700 Subject: Update audio route after user select different audio route. Bug: 79195339 Test: manual PiperOrigin-RevId: 195344623 Change-Id: I64225b781c84d363848a15bcdaa351585dce6b04 --- .../android/incallui/rtt/impl/AudioSelectMenu.java | 36 ++++++++++++---------- .../android/incallui/rtt/impl/RttChatFragment.java | 6 +++- 2 files changed, 25 insertions(+), 17 deletions(-) (limited to 'java') diff --git a/java/com/android/incallui/rtt/impl/AudioSelectMenu.java b/java/com/android/incallui/rtt/impl/AudioSelectMenu.java index 01c3950e9..1c83637ea 100644 --- a/java/com/android/incallui/rtt/impl/AudioSelectMenu.java +++ b/java/com/android/incallui/rtt/impl/AudioSelectMenu.java @@ -17,8 +17,6 @@ package com.android.incallui.rtt.impl; import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.PorterDuff.Mode; import android.telecom.CallAudioState; import android.view.View; import android.widget.PopupWindow; @@ -28,8 +26,11 @@ import com.android.incallui.incall.protocol.InCallButtonUiDelegate; public class AudioSelectMenu extends PopupWindow { private final InCallButtonUiDelegate inCallButtonUiDelegate; - private final Context context; private final OnButtonClickListener onButtonClickListener; + private final RttCheckableButton bluetoothButton; + private final RttCheckableButton speakerButton; + private final RttCheckableButton headsetButton; + private final RttCheckableButton earpieceButton; interface OnButtonClickListener { void onBackPressed(); @@ -40,7 +41,6 @@ public class AudioSelectMenu extends PopupWindow { InCallButtonUiDelegate inCallButtonUiDelegate, OnButtonClickListener onButtonClickListener) { super(context, null, 0, R.style.OverflowMenu); - this.context = context; this.inCallButtonUiDelegate = inCallButtonUiDelegate; this.onButtonClickListener = onButtonClickListener; View view = View.inflate(context, R.layout.audio_route, null); @@ -55,28 +55,32 @@ public class AudioSelectMenu extends PopupWindow { this.onButtonClickListener.onBackPressed(); }); CallAudioState audioState = inCallButtonUiDelegate.getCurrentAudioState(); - initItem( - view.findViewById(R.id.audioroute_bluetooth), CallAudioState.ROUTE_BLUETOOTH, audioState); - initItem(view.findViewById(R.id.audioroute_speaker), CallAudioState.ROUTE_SPEAKER, audioState); - initItem( - view.findViewById(R.id.audioroute_headset), CallAudioState.ROUTE_WIRED_HEADSET, audioState); - initItem( - view.findViewById(R.id.audioroute_earpiece), CallAudioState.ROUTE_EARPIECE, audioState); + bluetoothButton = view.findViewById(R.id.audioroute_bluetooth); + speakerButton = view.findViewById(R.id.audioroute_speaker); + headsetButton = view.findViewById(R.id.audioroute_headset); + earpieceButton = view.findViewById(R.id.audioroute_earpiece); + initItem(bluetoothButton, CallAudioState.ROUTE_BLUETOOTH, audioState); + initItem(speakerButton, CallAudioState.ROUTE_SPEAKER, audioState); + initItem(headsetButton, CallAudioState.ROUTE_WIRED_HEADSET, audioState); + initItem(earpieceButton, CallAudioState.ROUTE_EARPIECE, audioState); } private void initItem(RttCheckableButton item, final int itemRoute, CallAudioState audioState) { - int selectedColor = - context.getColor(com.android.incallui.audioroute.R.color.dialer_theme_color); if ((audioState.getSupportedRouteMask() & itemRoute) == 0) { item.setVisibility(View.GONE); } else if (audioState.getRoute() == itemRoute) { - item.setTextColor(selectedColor); - item.setCompoundDrawableTintList(ColorStateList.valueOf(selectedColor)); - item.setCompoundDrawableTintMode(Mode.SRC_ATOP); + item.setChecked(true); } item.setOnClickListener( (v) -> { inCallButtonUiDelegate.setAudioRoute(itemRoute); }); } + + void setAudioState(CallAudioState audioState) { + bluetoothButton.setChecked(audioState.getRoute() == CallAudioState.ROUTE_BLUETOOTH); + speakerButton.setChecked(audioState.getRoute() == CallAudioState.ROUTE_SPEAKER); + headsetButton.setChecked(audioState.getRoute() == CallAudioState.ROUTE_WIRED_HEADSET); + earpieceButton.setChecked(audioState.getRoute() == CallAudioState.ROUTE_EARPIECE); + } } diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java index e56715981..c393393f8 100644 --- a/java/com/android/incallui/rtt/impl/RttChatFragment.java +++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java @@ -107,6 +107,7 @@ public class RttChatFragment extends Fragment private PrimaryCallState primaryCallState = PrimaryCallState.empty(); private boolean isUserScrolling; private boolean shouldAutoScrolling; + private AudioSelectMenu audioSelectMenu; /** * Create a new instance of RttChatFragment. @@ -558,6 +559,9 @@ public class RttChatFragment extends Fragment LogUtil.i("RttChatFragment.setAudioState", "audioState: " + audioState); overflowMenu.setMuteButtonChecked(audioState.isMuted()); overflowMenu.setAudioState(audioState); + if (audioSelectMenu != null) { + audioSelectMenu.setAudioState(audioState); + } } @Override @@ -573,7 +577,7 @@ public class RttChatFragment extends Fragment @Override public void showAudioRouteSelector() { - AudioSelectMenu audioSelectMenu = + audioSelectMenu = new AudioSelectMenu( getContext(), inCallButtonUiDelegate, -- cgit v1.2.3 From 4ef430e759b7e4f07bd1fbc273a7b6937b581b4a Mon Sep 17 00:00:00 2001 From: yueg Date: Fri, 4 May 2018 10:47:35 -0700 Subject: Use Telecom Bluetooth API instead of system Bluetooth API. Bug: 74238896 Test: manual PiperOrigin-RevId: 195437669 Change-Id: I1cb26187b8b90664b72de2a4451283a9fbdc0f10 --- .../basecomponent/BaseDialerRootComponent.java | 2 - java/com/android/incallui/InCallServiceImpl.java | 3 - .../audiomode/BluetoothDeviceProvider.java | 203 --------------------- .../BluetoothDeviceProviderComponent.java | 39 ---- .../AudioRouteSelectorDialogFragment.java | 43 +++-- java/com/android/incallui/call/TelecomAdapter.java | 11 ++ 6 files changed, 36 insertions(+), 265 deletions(-) delete mode 100644 java/com/android/incallui/audiomode/BluetoothDeviceProvider.java delete mode 100644 java/com/android/incallui/audiomode/BluetoothDeviceProviderComponent.java (limited to 'java') diff --git a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java index 5fed683f6..cad2eb7e0 100644 --- a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java +++ b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java @@ -41,7 +41,6 @@ import com.android.dialer.spam.SpamComponent; import com.android.dialer.speeddial.loader.UiItemLoaderComponent; import com.android.dialer.storage.StorageComponent; import com.android.dialer.strictmode.StrictModeComponent; -import com.android.incallui.audiomode.BluetoothDeviceProviderComponent; import com.android.incallui.calllocation.CallLocationComponent; import com.android.incallui.maps.MapsComponent; import com.android.incallui.speakeasy.SpeakEasyComponent; @@ -53,7 +52,6 @@ import com.android.voicemail.VoicemailComponent; */ public interface BaseDialerRootComponent extends ActiveCallsComponent.HasComponent, - BluetoothDeviceProviderComponent.HasComponent, BubbleComponent.HasComponent, CallLocationComponent.HasComponent, CallLogComponent.HasComponent, diff --git a/java/com/android/incallui/InCallServiceImpl.java b/java/com/android/incallui/InCallServiceImpl.java index d803956e6..b9d0eccba 100644 --- a/java/com/android/incallui/InCallServiceImpl.java +++ b/java/com/android/incallui/InCallServiceImpl.java @@ -26,7 +26,6 @@ import android.telecom.InCallService; import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler; import com.android.dialer.feedback.FeedbackComponent; import com.android.incallui.audiomode.AudioModeProvider; -import com.android.incallui.audiomode.BluetoothDeviceProviderComponent; import com.android.incallui.call.CallList; import com.android.incallui.call.ExternalCallList; import com.android.incallui.call.TelecomAdapter; @@ -98,7 +97,6 @@ public class InCallServiceImpl extends InCallService { final Context context = getApplicationContext(); final ContactInfoCache contactInfoCache = ContactInfoCache.getInstance(context); AudioModeProvider.getInstance().initializeAudioState(this); - BluetoothDeviceProviderComponent.get(context).bluetoothDeviceProvider().setUp(); InCallPresenter.getInstance() .setUp( context, @@ -142,7 +140,6 @@ public class InCallServiceImpl extends InCallService { // Tear down the InCall system InCallPresenter.getInstance().tearDown(); TelecomAdapter.getInstance().clearInCallService(); - BluetoothDeviceProviderComponent.get(this).bluetoothDeviceProvider().tearDown(); if (returnToCallController != null) { returnToCallController.tearDown(); returnToCallController = null; diff --git a/java/com/android/incallui/audiomode/BluetoothDeviceProvider.java b/java/com/android/incallui/audiomode/BluetoothDeviceProvider.java deleted file mode 100644 index 1aa1c20a8..000000000 --- a/java/com/android/incallui/audiomode/BluetoothDeviceProvider.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.incallui.audiomode; - -import android.annotation.SuppressLint; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadset; -import android.bluetooth.BluetoothProfile; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.util.ArraySet; -import com.android.dialer.common.LogUtil; -import com.android.dialer.inject.ApplicationContext; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Set; -import javax.inject.Inject; -import javax.inject.Singleton; - -/** Proxy class for getting and setting connected/active Bluetooth devices. */ -@Singleton -public final class BluetoothDeviceProvider extends BroadcastReceiver { - - // TODO(yueg): use BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED when possible - private static final String ACTION_ACTIVE_DEVICE_CHANGED = - "android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED"; - - private final Context appContext; - private final BluetoothProfileServiceListener bluetoothProfileServiceListener = - new BluetoothProfileServiceListener(); - - private final Set connectedBluetoothDeviceSet = new ArraySet<>(); - - private BluetoothDevice activeBluetoothDevice; - private BluetoothHeadset bluetoothHeadset; - private boolean isSetUp; - - @Inject - public BluetoothDeviceProvider(@ApplicationContext Context appContext) { - this.appContext = appContext; - } - - public void setUp() { - if (BluetoothAdapter.getDefaultAdapter() == null) { - // Bluetooth is not supported on this hardware platform - return; - } - // Get Bluetooth service including the initial connected device list (should only contain one - // device) - BluetoothAdapter.getDefaultAdapter() - .getProfileProxy(appContext, bluetoothProfileServiceListener, BluetoothProfile.HEADSET); - // Get notified of Bluetooth device update - IntentFilter filter = new IntentFilter(); - filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); - filter.addAction(ACTION_ACTIVE_DEVICE_CHANGED); - appContext.registerReceiver(this, filter); - - isSetUp = true; - } - - public void tearDown() { - if (!isSetUp) { - return; - } - appContext.unregisterReceiver(this); - if (bluetoothHeadset != null) { - BluetoothAdapter.getDefaultAdapter() - .closeProfileProxy(BluetoothProfile.HEADSET, bluetoothHeadset); - } - } - - public Set getConnectedBluetoothDeviceSet() { - return connectedBluetoothDeviceSet; - } - - public BluetoothDevice getActiveBluetoothDevice() { - return activeBluetoothDevice; - } - - @SuppressLint("PrivateApi") - public void setActiveBluetoothDevice(BluetoothDevice bluetoothDevice) { - if (!connectedBluetoothDeviceSet.contains(bluetoothDevice)) { - LogUtil.e("BluetoothProfileServiceListener.setActiveBluetoothDevice", "device is not in set"); - return; - } - // TODO(yueg): use BluetoothHeadset.setActiveDevice() when possible - try { - Method getActiveDeviceMethod = - bluetoothHeadset.getClass().getDeclaredMethod("setActiveDevice", BluetoothDevice.class); - getActiveDeviceMethod.setAccessible(true); - getActiveDeviceMethod.invoke(bluetoothHeadset, bluetoothDevice); - } catch (Exception e) { - LogUtil.e( - "BluetoothProfileServiceListener.setActiveBluetoothDevice", - "failed to call setActiveDevice", - e); - } - } - - @Override - public void onReceive(Context context, Intent intent) { - if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) { - handleActionConnectionStateChanged(intent); - } else if (ACTION_ACTIVE_DEVICE_CHANGED.equals(intent.getAction())) { - handleActionActiveDeviceChanged(intent); - } - } - - private void handleActionConnectionStateChanged(Intent intent) { - if (!intent.hasExtra(BluetoothDevice.EXTRA_DEVICE)) { - LogUtil.i( - "BluetoothDeviceProvider.handleActionConnectionStateChanged", - "extra BluetoothDevice.EXTRA_DEVICE not found"); - return; - } - BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - if (bluetoothDevice == null) { - return; - } - - int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); - if (state == BluetoothProfile.STATE_DISCONNECTED) { - connectedBluetoothDeviceSet.remove(bluetoothDevice); - LogUtil.i("BluetoothDeviceProvider.handleActionConnectionStateChanged", "device removed"); - } else if (state == BluetoothProfile.STATE_CONNECTED) { - connectedBluetoothDeviceSet.add(bluetoothDevice); - LogUtil.i("BluetoothDeviceProvider.handleActionConnectionStateChanged", "device added"); - } - } - - private void handleActionActiveDeviceChanged(Intent intent) { - if (!intent.hasExtra(BluetoothDevice.EXTRA_DEVICE)) { - LogUtil.i( - "BluetoothDeviceProvider.handleActionActiveDeviceChanged", - "extra BluetoothDevice.EXTRA_DEVICE not found"); - return; - } - activeBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - LogUtil.i( - "BluetoothDeviceProvider.handleActionActiveDeviceChanged", - (activeBluetoothDevice == null ? "null" : "")); - } - - private final class BluetoothProfileServiceListener implements BluetoothProfile.ServiceListener { - @Override - @SuppressLint("PrivateApi") - public void onServiceConnected(int profile, BluetoothProfile bluetoothProfile) { - if (profile != BluetoothProfile.HEADSET) { - return; - } - // Get initial connected device list - bluetoothHeadset = (BluetoothHeadset) bluetoothProfile; - List devices = bluetoothProfile.getConnectedDevices(); - for (BluetoothDevice device : devices) { - connectedBluetoothDeviceSet.add(device); - LogUtil.i( - "BluetoothProfileServiceListener.onServiceConnected", "get initial connected device"); - } - - // Get initial active device - // TODO(yueg): use BluetoothHeadset.getActiveDevice() when possible - try { - Method getActiveDeviceMethod = - bluetoothHeadset.getClass().getDeclaredMethod("getActiveDevice"); - getActiveDeviceMethod.setAccessible(true); - activeBluetoothDevice = (BluetoothDevice) getActiveDeviceMethod.invoke(bluetoothHeadset); - LogUtil.i( - "BluetoothProfileServiceListener.onServiceConnected", - "get initial active device" + ((activeBluetoothDevice == null) ? " null" : "")); - } catch (Exception e) { - LogUtil.e( - "BluetoothProfileServiceListener.onServiceConnected", - "failed to call getAcitveDevice", - e); - } - } - - @Override - public void onServiceDisconnected(int profile) { - LogUtil.enterBlock("BluetoothProfileServiceListener.onServiceDisconnected"); - if (profile == BluetoothProfile.HEADSET) { - bluetoothHeadset = null; - } - } - } -} diff --git a/java/com/android/incallui/audiomode/BluetoothDeviceProviderComponent.java b/java/com/android/incallui/audiomode/BluetoothDeviceProviderComponent.java deleted file mode 100644 index 9cd926835..000000000 --- a/java/com/android/incallui/audiomode/BluetoothDeviceProviderComponent.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.incallui.audiomode; - -import android.content.Context; -import com.android.dialer.inject.HasRootComponent; -import dagger.Subcomponent; - -/** Dagger component for the Bluetooth device provider. */ -@Subcomponent -public abstract class BluetoothDeviceProviderComponent { - - public abstract BluetoothDeviceProvider bluetoothDeviceProvider(); - - public static BluetoothDeviceProviderComponent get(Context context) { - return ((BluetoothDeviceProviderComponent.HasComponent) - ((HasRootComponent) context.getApplicationContext()).component()) - .bluetoothDeviceProviderComponent(); - } - - /** Used to refer to the root application component. */ - public interface HasComponent { - BluetoothDeviceProviderComponent bluetoothDeviceProviderComponent(); - } -} diff --git a/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java b/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java index d6946d8de..a561b5ee5 100644 --- a/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java +++ b/java/com/android/incallui/audioroute/AudioRouteSelectorDialogFragment.java @@ -39,12 +39,12 @@ import com.android.dialer.common.FragmentUtils; import com.android.dialer.common.LogUtil; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; -import com.android.incallui.audiomode.BluetoothDeviceProviderComponent; import com.android.incallui.call.CallList; import com.android.incallui.call.DialerCall; +import com.android.incallui.call.TelecomAdapter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Set; +import java.util.Collection; /** Shows picker for audio routes */ public class AudioRouteSelectorDialogFragment extends BottomSheetDialogFragment { @@ -91,24 +91,33 @@ public class AudioRouteSelectorDialogFragment extends BottomSheetDialogFragment @Nullable @Override + @SuppressLint("NewApi") public View onCreateView( LayoutInflater layoutInflater, @Nullable ViewGroup viewGroup, @Nullable Bundle bundle) { View view = layoutInflater.inflate(R.layout.audioroute_selector, viewGroup, false); CallAudioState audioState = getArguments().getParcelable(ARG_AUDIO_STATE); - Set bluetoothDeviceSet = - BluetoothDeviceProviderComponent.get(getContext()) - .bluetoothDeviceProvider() - .getConnectedBluetoothDeviceSet(); - for (BluetoothDevice device : bluetoothDeviceSet) { - boolean selected = - (audioState.getRoute() == CallAudioState.ROUTE_BLUETOOTH) - && (bluetoothDeviceSet.size() == 1 - || device.equals( - BluetoothDeviceProviderComponent.get(getContext()) - .bluetoothDeviceProvider() - .getActiveBluetoothDevice())); - TextView textView = createBluetoothItem(device, selected); + if (BuildCompat.isAtLeastP()) { + // Create items for all connected Bluetooth devices + Collection bluetoothDeviceSet = audioState.getSupportedBluetoothDevices(); + for (BluetoothDevice device : bluetoothDeviceSet) { + boolean selected = + (audioState.getRoute() == CallAudioState.ROUTE_BLUETOOTH) + && (bluetoothDeviceSet.size() == 1 + || device.equals(audioState.getActiveBluetoothDevice())); + TextView textView = createBluetoothItem(device, selected); + ((LinearLayout) view).addView(textView, 0); + } + } else { + // Only create Bluetooth audio route + TextView textView = + (TextView) getLayoutInflater().inflate(R.layout.audioroute_item, null, false); + textView.setText(getString(R.string.audioroute_bluetooth)); + initItem( + textView, + CallAudioState.ROUTE_BLUETOOTH, + audioState, + DialerImpression.Type.IN_CALL_SWITCH_AUDIO_ROUTE_BLUETOOTH); ((LinearLayout) view).addView(textView, 0); } @@ -183,9 +192,7 @@ public class AudioRouteSelectorDialogFragment extends BottomSheetDialogFragment AudioRouteSelectorDialogFragment.this, AudioRouteSelectorPresenter.class) .onAudioRouteSelected(CallAudioState.ROUTE_BLUETOOTH); // Set active Bluetooth device - BluetoothDeviceProviderComponent.get(getContext()) - .bluetoothDeviceProvider() - .setActiveBluetoothDevice(bluetoothDevice); + TelecomAdapter.getInstance().requestBluetoothAudio(bluetoothDevice); dismiss(); }); diff --git a/java/com/android/incallui/call/TelecomAdapter.java b/java/com/android/incallui/call/TelecomAdapter.java index a7e10d37c..4ae1bc1db 100644 --- a/java/com/android/incallui/call/TelecomAdapter.java +++ b/java/com/android/incallui/call/TelecomAdapter.java @@ -16,7 +16,9 @@ package com.android.incallui.call; +import android.annotation.TargetApi; import android.app.Notification; +import android.bluetooth.BluetoothDevice; import android.content.ActivityNotFoundException; import android.content.Intent; import android.os.Looper; @@ -193,4 +195,13 @@ public class TelecomAdapter implements InCallServiceListener { "no inCallService available for stopping foreground notification"); } } + + @TargetApi(28) + public void requestBluetoothAudio(BluetoothDevice bluetoothDevice) { + if (inCallService != null) { + inCallService.requestBluetoothAudio(bluetoothDevice); + } else { + LogUtil.e("TelecomAdapter.requestBluetoothAudio", "inCallService is null"); + } + } } -- cgit v1.2.3 From 763ce4404ae8e4199da719359a1b01389884cec4 Mon Sep 17 00:00:00 2001 From: linyuh Date: Fri, 4 May 2018 10:54:12 -0700 Subject: Remove TODOs for showing SIM info in the bottom sheet & call details. Bug: 74522027 Test: None PiperOrigin-RevId: 195439124 Change-Id: Ibab0bc7e58bd1b23255d9af476c5b98ed89f13fa --- java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java | 2 -- .../com/android/dialer/calldetails/proto/call_details_header_info.proto | 2 -- .../historyitemactions/history_item_bottom_sheet_header_info.proto | 2 -- 3 files changed, 6 deletions(-) (limited to 'java') diff --git a/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java b/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java index cb84a28c2..cd1752d74 100644 --- a/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java +++ b/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java @@ -192,8 +192,6 @@ public class CallDetailsHeaderViewHolder extends RecyclerView.ViewHolder nameView.setText(headerInfo.getPrimaryText()); numberView.setText(headerInfo.getSecondaryText()); - // TODO(a bug): show SIM info in the TextView returned by getNetworkView(). - setCallbackAction(callbackAction); } diff --git a/java/com/android/dialer/calldetails/proto/call_details_header_info.proto b/java/com/android/dialer/calldetails/proto/call_details_header_info.proto index ea7ba1e72..e2532d504 100644 --- a/java/com/android/dialer/calldetails/proto/call_details_header_info.proto +++ b/java/com/android/dialer/calldetails/proto/call_details_header_info.proto @@ -31,6 +31,4 @@ message CallDetailsHeaderInfo { // "Blocked • Mobile • 555-1234", and // "Spam • Mobile • 555-1234". optional string secondary_text = 4; - - // TODO(a bug): Add SIM info. } \ No newline at end of file diff --git a/java/com/android/dialer/historyitemactions/history_item_bottom_sheet_header_info.proto b/java/com/android/dialer/historyitemactions/history_item_bottom_sheet_header_info.proto index ef71ecd7e..04d9f2259 100644 --- a/java/com/android/dialer/historyitemactions/history_item_bottom_sheet_header_info.proto +++ b/java/com/android/dialer/historyitemactions/history_item_bottom_sheet_header_info.proto @@ -36,6 +36,4 @@ message HistoryItemBottomSheetHeaderInfo { // "Blocked • Mobile • 555-1234", and // "Spam • Mobile • 555-1234". optional string secondary_text = 4; - - // TODO(a bug): Add SIM info. } -- cgit v1.2.3