From f539f7885be23d3aff470e573c70d52db3b2a878 Mon Sep 17 00:00:00 2001 From: yueg Date: Mon, 18 Dec 2017 16:20:58 -0800 Subject: Bubble v2 logging. Log the following actions: - expand/collapse bubble - return to call - mute/unmute - switch audio route to speaker/bluetooth/wired or earpiece - end call Bug: 67605985 Test: AudioRouteSelectorActivityTest, NewReturnToCallControllerTest PiperOrigin-RevId: 179484647 Change-Id: I4e2ee34f5550382b2e51bab16ce33e9e16caa3b2 --- .../android/dialer/logging/dialer_impression.proto | 21 ++- java/com/android/incallui/AndroidManifest.xml | 3 + .../incallui/AudioRouteSelectorActivity.java | 39 ++++++ .../incallui/NewReturnToCallActionReceiver.java | 156 +++++++++++++++++++++ .../incallui/NewReturnToCallController.java | 24 ++-- java/com/android/newbubble/NewBubble.java | 38 +++-- 6 files changed, 243 insertions(+), 38 deletions(-) create mode 100644 java/com/android/incallui/NewReturnToCallActionReceiver.java (limited to 'java/com') diff --git a/java/com/android/dialer/logging/dialer_impression.proto b/java/com/android/dialer/logging/dialer_impression.proto index aed66251a..2d2eebf67 100644 --- a/java/com/android/dialer/logging/dialer_impression.proto +++ b/java/com/android/dialer/logging/dialer_impression.proto @@ -12,7 +12,7 @@ message DialerImpression { // Event enums to be used for Impression Logging in Dialer. // It's perfectly acceptable for this enum to be large // Values should be from 1000 to 100000. - // Next Tag: 1311 + // Next Tag: 1320 enum Type { UNKNOWN_AOSP_EVENT_TYPE = 1000; @@ -625,5 +625,24 @@ message DialerImpression { DUO_CALL_LOG_SET_UP_INSTALL = 1308; DUO_CALL_LOG_SET_UP_ACTIVATE = 1309; DUO_CALL_LOG_INVITE = 1310; + + // Bubble primary button first click to expand bubble + BUBBLE_V2_CLICK_TO_EXPAND = 1311; + // Bubble primary button second click to collapse bubble + BUBBLE_V2_CLICK_TO_COLLAPSE = 1312; + // User return to call from bubble call action menu + BUBBLE_V2_RETURN_TO_CALL = 1313; + // User muted call from bubble call action menu + BUBBLE_V2_MUTE_CALL = 1314; + // User unmuted call from bubble call action menu + BUBBLE_V2_UNMUTE_CALL = 1315; + // User choose audio route speakerphone from bubble call action menu + BUBBLE_V2_SPEAKERPHONE = 1316; + // User choose audio route wired or earpiece from bubble call action menu + BUBBLE_V2_WIRED_OR_EARPIECE = 1317; + // User choose audio route bluetooth from bubble call action menu + BUBBLE_V2_BLUETOOTH = 1318; + // User ended call from bubble call action menu + BUBBLE_V2_END_CALL = 1319; } } diff --git a/java/com/android/incallui/AndroidManifest.xml b/java/com/android/incallui/AndroidManifest.xml index af9970056..b9d481b31 100644 --- a/java/com/android/incallui/AndroidManifest.xml +++ b/java/com/android/incallui/AndroidManifest.xml @@ -109,6 +109,9 @@ + diff --git a/java/com/android/incallui/AudioRouteSelectorActivity.java b/java/com/android/incallui/AudioRouteSelectorActivity.java index 8d166649c..a6fcc9c7d 100644 --- a/java/com/android/incallui/AudioRouteSelectorActivity.java +++ b/java/com/android/incallui/AudioRouteSelectorActivity.java @@ -19,18 +19,29 @@ package com.android.incallui; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; +import android.telecom.CallAudioState; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.logging.Logger; import com.android.incallui.audiomode.AudioModeProvider; import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment; import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment.AudioRouteSelectorPresenter; +import com.android.incallui.call.CallList; +import com.android.incallui.call.DialerCall; import com.android.incallui.call.TelecomAdapter; /** Simple activity that just shows the audio route selector fragment */ public class AudioRouteSelectorActivity extends FragmentActivity implements AudioRouteSelectorPresenter { + public static final String SHOULD_LOG_BUBBLE_V2_IMPRESSION_EXTRA = "shouldLogBubbleV2Impression"; + + private boolean shouldLogBubbleV2Impression; + @Override protected void onCreate(@Nullable Bundle bundle) { super.onCreate(bundle); + shouldLogBubbleV2Impression = + getIntent().getBooleanExtra(SHOULD_LOG_BUBBLE_V2_IMPRESSION_EXTRA, false); AudioRouteSelectorDialogFragment.newInstance(AudioModeProvider.getInstance().getAudioState()) .show(getSupportFragmentManager(), AudioRouteSelectorDialogFragment.TAG); } @@ -39,6 +50,34 @@ public class AudioRouteSelectorActivity extends FragmentActivity public void onAudioRouteSelected(int audioRoute) { TelecomAdapter.getInstance().setAudioRoute(audioRoute); finish(); + + if (!shouldLogBubbleV2Impression) { + return; + } + + // Log the select action with audio route and call + DialerImpression.Type impressionType = null; + if ((audioRoute & CallAudioState.ROUTE_WIRED_OR_EARPIECE) != 0) { + impressionType = DialerImpression.Type.BUBBLE_V2_WIRED_OR_EARPIECE; + } else if (audioRoute == CallAudioState.ROUTE_SPEAKER) { + impressionType = DialerImpression.Type.BUBBLE_V2_SPEAKERPHONE; + } else if (audioRoute == CallAudioState.ROUTE_BLUETOOTH) { + impressionType = DialerImpression.Type.BUBBLE_V2_BLUETOOTH; + } + if (impressionType == null) { + return; + } + + DialerCall call = CallList.getInstance().getOutgoingCall(); + if (call == null) { + call = CallList.getInstance().getActiveOrBackgroundCall(); + } + if (call != null) { + Logger.get(this) + .logCallImpression(impressionType, call.getUniqueCallId(), call.getTimeAddedMs()); + } else { + Logger.get(this).logImpression(impressionType); + } } @Override diff --git a/java/com/android/incallui/NewReturnToCallActionReceiver.java b/java/com/android/incallui/NewReturnToCallActionReceiver.java new file mode 100644 index 000000000..23debe204 --- /dev/null +++ b/java/com/android/incallui/NewReturnToCallActionReceiver.java @@ -0,0 +1,156 @@ +/* + * 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; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.telecom.CallAudioState; +import com.android.dialer.common.Assert; +import com.android.dialer.common.LogUtil; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.logging.Logger; +import com.android.incallui.audiomode.AudioModeProvider; +import com.android.incallui.call.CallList; +import com.android.incallui.call.DialerCall; +import com.android.incallui.call.TelecomAdapter; + +/** Handles clicks on the return-to-call bubble */ +public class NewReturnToCallActionReceiver extends BroadcastReceiver { + + public static final String ACTION_RETURN_TO_CALL = "returnToCallV2"; + public static final String ACTION_TOGGLE_SPEAKER = "toggleSpeakerV2"; + public static final String ACTION_SHOW_AUDIO_ROUTE_SELECTOR = "showAudioRouteSelectorV2"; + public static final String ACTION_TOGGLE_MUTE = "toggleMuteV2"; + public static final String ACTION_END_CALL = "endCallV2"; + + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case ACTION_RETURN_TO_CALL: + returnToCall(context); + break; + case ACTION_TOGGLE_SPEAKER: + toggleSpeaker(context); + break; + case ACTION_SHOW_AUDIO_ROUTE_SELECTOR: + showAudioRouteSelector(context); + break; + case ACTION_TOGGLE_MUTE: + toggleMute(context); + break; + case ACTION_END_CALL: + endCall(context); + break; + default: + throw Assert.createIllegalStateFailException( + "Invalid intent action: " + intent.getAction()); + } + } + + private void returnToCall(Context context) { + DialerCall call = getCall(); + Logger.get(context) + .logCallImpression( + DialerImpression.Type.BUBBLE_V2_RETURN_TO_CALL, + call != null ? call.getUniqueCallId() : "", + call != null ? call.getTimeAddedMs() : 0); + + Intent activityIntent = InCallActivity.getIntent(context, false, false, false); + activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(activityIntent); + } + + private void toggleSpeaker(Context context) { + CallAudioState audioState = AudioModeProvider.getInstance().getAudioState(); + + if ((audioState.getSupportedRouteMask() & CallAudioState.ROUTE_BLUETOOTH) + == CallAudioState.ROUTE_BLUETOOTH) { + LogUtil.w( + "ReturnToCallActionReceiver.toggleSpeaker", + "toggleSpeaker() called when bluetooth available." + + " Probably should have shown audio route selector"); + } + + DialerCall call = getCall(); + + int newRoute; + if (audioState.getRoute() == CallAudioState.ROUTE_SPEAKER) { + newRoute = CallAudioState.ROUTE_WIRED_OR_EARPIECE; + Logger.get(context) + .logCallImpression( + DialerImpression.Type.BUBBLE_V2_WIRED_OR_EARPIECE, + call != null ? call.getUniqueCallId() : "", + call != null ? call.getTimeAddedMs() : 0); + } else { + newRoute = CallAudioState.ROUTE_SPEAKER; + Logger.get(context) + .logCallImpression( + DialerImpression.Type.BUBBLE_V2_SPEAKERPHONE, + call != null ? call.getUniqueCallId() : "", + call != null ? call.getTimeAddedMs() : 0); + } + TelecomAdapter.getInstance().setAudioRoute(newRoute); + } + + public void showAudioRouteSelector(Context context) { + Intent intent = new Intent(context, AudioRouteSelectorActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + intent.putExtra(AudioRouteSelectorActivity.SHOULD_LOG_BUBBLE_V2_IMPRESSION_EXTRA, true); + context.startActivity(intent); + } + + private void toggleMute(Context context) { + DialerCall call = getCall(); + boolean shouldMute = !AudioModeProvider.getInstance().getAudioState().isMuted(); + Logger.get(context) + .logCallImpression( + shouldMute + ? DialerImpression.Type.BUBBLE_V2_MUTE_CALL + : DialerImpression.Type.BUBBLE_V2_UNMUTE_CALL, + call != null ? call.getUniqueCallId() : "", + call != null ? call.getTimeAddedMs() : 0); + TelecomAdapter.getInstance().mute(shouldMute); + } + + private void endCall(Context context) { + DialerCall call = getCall(); + + Logger.get(context) + .logCallImpression( + DialerImpression.Type.BUBBLE_V2_END_CALL, + call != null ? call.getUniqueCallId() : "", + call != null ? call.getTimeAddedMs() : 0); + if (call != null) { + call.disconnect(); + } + } + + private DialerCall getCall() { + CallList callList = InCallPresenter.getInstance().getCallList(); + if (callList != null) { + DialerCall call = callList.getOutgoingCall(); + if (call == null) { + call = callList.getActiveOrBackgroundCall(); + } + if (call != null) { + return call; + } + } + return null; + } +} diff --git a/java/com/android/incallui/NewReturnToCallController.java b/java/com/android/incallui/NewReturnToCallController.java index d3d993027..ad49d6828 100644 --- a/java/com/android/incallui/NewReturnToCallController.java +++ b/java/com/android/incallui/NewReturnToCallController.java @@ -53,8 +53,6 @@ import java.util.List; */ public class NewReturnToCallController implements InCallUiListener, Listener, AudioModeListener { - public static final String RETURN_TO_CALL_EXTRA_KEY = "RETURN_TO_CALL_BUBBLE"; - private final Context context; @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @@ -78,18 +76,12 @@ public class NewReturnToCallController implements InCallUiListener, Listener, Au this.context = context; this.contactInfoCache = contactInfoCache; - toggleSpeaker = createActionIntent(ReturnToCallActionReceiver.ACTION_TOGGLE_SPEAKER); + toggleSpeaker = createActionIntent(NewReturnToCallActionReceiver.ACTION_TOGGLE_SPEAKER); showSpeakerSelect = - createActionIntent(ReturnToCallActionReceiver.ACTION_SHOW_AUDIO_ROUTE_SELECTOR); - toggleMute = createActionIntent(ReturnToCallActionReceiver.ACTION_TOGGLE_MUTE); - endCall = createActionIntent(ReturnToCallActionReceiver.ACTION_END_CALL); - - Intent activityIntent = InCallActivity.getIntent(context, false, false, false); - activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - activityIntent.putExtra(RETURN_TO_CALL_EXTRA_KEY, true); - fullScreen = - PendingIntent.getActivity( - context, InCallActivity.PendingIntentRequestCodes.BUBBLE, activityIntent, 0); + createActionIntent(NewReturnToCallActionReceiver.ACTION_SHOW_AUDIO_ROUTE_SELECTOR); + toggleMute = createActionIntent(NewReturnToCallActionReceiver.ACTION_TOGGLE_MUTE); + endCall = createActionIntent(NewReturnToCallActionReceiver.ACTION_END_CALL); + fullScreen = createActionIntent(NewReturnToCallActionReceiver.ACTION_RETURN_TO_CALL); InCallPresenter.getInstance().addInCallUiListener(this); CallList.getInstance().addListener(this); @@ -280,9 +272,9 @@ public class NewReturnToCallController implements InCallUiListener, Listener, Au @NonNull private PendingIntent createActionIntent(String action) { - Intent toggleSpeaker = new Intent(context, ReturnToCallActionReceiver.class); - toggleSpeaker.setAction(action); - return PendingIntent.getBroadcast(context, 0, toggleSpeaker, 0); + Intent intent = new Intent(context, NewReturnToCallActionReceiver.class); + intent.setAction(action); + return PendingIntent.getBroadcast(context, 0, intent, 0); } @NonNull diff --git a/java/com/android/newbubble/NewBubble.java b/java/com/android/newbubble/NewBubble.java index d13952ba5..3378ad81a 100644 --- a/java/com/android/newbubble/NewBubble.java +++ b/java/com/android/newbubble/NewBubble.java @@ -232,10 +232,7 @@ public class NewBubble { } /** Expands the main bubble menu. */ - public void expand(boolean isUserAction) { - if (isUserAction) { - logBasicOrCallImpression(DialerImpression.Type.BUBBLE_PRIMARY_BUTTON_EXPAND); - } + public void expand() { setPrimaryButtonAccessibilityAction( context.getString(R.string.a11y_bubble_primary_button_collapse_action)); @@ -307,8 +304,7 @@ public class NewBubble { } @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - public void startCollapse( - @CollapseEnd int endAction, boolean isUserAction, boolean shouldRecoverYPosition) { + public void startCollapse(@CollapseEnd int endAction, boolean shouldRecoverYPosition) { View expandedView = viewHolder.getExpandedView(); if (expandedView.getVisibility() != View.VISIBLE || collapseAnimation != null) { // Drawer is already collapsed or animation is running. @@ -321,10 +317,6 @@ public class NewBubble { if (collapseEndAction == CollapseEnd.NOTHING) { collapseEndAction = endAction; } - if (isUserAction && collapseEndAction == CollapseEnd.NOTHING) { - logBasicOrCallImpression(DialerImpression.Type.BUBBLE_COLLAPSE_BY_USER); - } - setPrimaryButtonAccessibilityAction( context.getString(R.string.a11y_bubble_primary_button_expand_action)); @@ -572,8 +564,7 @@ public class NewBubble { public void showText(@NonNull CharSequence text) { textShowing = true; if (expanded) { - startCollapse( - CollapseEnd.NOTHING, false /* isUserAction */, false /* shouldRecoverYPosition */); + startCollapse(CollapseEnd.NOTHING, false /* shouldRecoverYPosition */); doShowText(text); } else { // Need to transition from old bounds to new bounds manually @@ -667,10 +658,11 @@ public class NewBubble { return; } if (expanded) { - startCollapse( - CollapseEnd.NOTHING, true /* isUserAction */, true /* shouldRecoverYPosition */); + logBasicOrCallImpression(DialerImpression.Type.BUBBLE_V2_CLICK_TO_COLLAPSE); + startCollapse(CollapseEnd.NOTHING, true /* shouldRecoverYPosition */); } else { - expand(true); + logBasicOrCallImpression(DialerImpression.Type.BUBBLE_V2_CLICK_TO_EXPAND); + expand(); } } @@ -713,7 +705,7 @@ public class NewBubble { } if (expanded) { - startCollapse(CollapseEnd.HIDE, false /* isUserAction */, false /* shouldRecoverYPosition */); + startCollapse(CollapseEnd.HIDE, false /* shouldRecoverYPosition */); return; } @@ -891,7 +883,11 @@ public class NewBubble { } private void logBasicOrCallImpression(DialerImpression.Type impressionType) { - DialerCall call = CallList.getInstance().getActiveOrBackgroundCall(); + // Bubble is shown for outgoing, active or background call + DialerCall call = CallList.getInstance().getOutgoingCall(); + if (call == null) { + call = CallList.getInstance().getActiveOrBackgroundCall(); + } if (call != null) { Logger.get(context) .logCallImpression(impressionType, call.getUniqueCallId(), call.getTimeAddedMs()); @@ -982,8 +978,8 @@ public class NewBubble { root.setOnBackPressedListener( () -> { if (visibility == Visibility.SHOWING && expanded) { - startCollapse( - CollapseEnd.NOTHING, true /* isUserAction */, true /* shouldRecoverYPosition */); + logBasicOrCallImpression(DialerImpression.Type.BUBBLE_V2_CLICK_TO_COLLAPSE); + startCollapse(CollapseEnd.NOTHING, true /* shouldRecoverYPosition */); return true; } return false; @@ -998,8 +994,8 @@ public class NewBubble { root.setOnTouchListener( (v, event) -> { if (expanded && event.getActionMasked() == MotionEvent.ACTION_OUTSIDE) { - startCollapse( - CollapseEnd.NOTHING, true /* isUserAction */, true /* shouldRecoverYPosition */); + logBasicOrCallImpression(DialerImpression.Type.BUBBLE_V2_CLICK_TO_COLLAPSE); + startCollapse(CollapseEnd.NOTHING, true /* shouldRecoverYPosition */); return true; } return false; -- cgit v1.2.3