add uievent logs for nav buttons
Bug: 147508017 Test: atest KeyButtonViewTest Change-Id: Ia237154b5a9ab10335f266c8974eabdf06d7997a
This commit is contained in:
@@ -52,6 +52,9 @@ import android.widget.ImageView;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.UiEvent;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.logging.UiEventLoggerImpl;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
@@ -64,6 +67,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
|
||||
private static final String TAG = KeyButtonView.class.getSimpleName();
|
||||
|
||||
private final boolean mPlaySounds;
|
||||
private final UiEventLogger mUiEventLogger;
|
||||
private int mContentDescriptionRes;
|
||||
private long mDownTime;
|
||||
private int mCode;
|
||||
@@ -72,7 +76,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
|
||||
private boolean mIsVertical;
|
||||
private AudioManager mAudioManager;
|
||||
private boolean mGestureAborted;
|
||||
private boolean mLongClicked;
|
||||
@VisibleForTesting boolean mLongClicked;
|
||||
private OnClickListener mOnClickListener;
|
||||
private final KeyButtonRipple mRipple;
|
||||
private final OverviewProxyService mOverviewProxyService;
|
||||
@@ -82,6 +86,40 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
|
||||
private float mDarkIntensity;
|
||||
private boolean mHasOvalBg = false;
|
||||
|
||||
@VisibleForTesting
|
||||
public enum NavBarActionsEvent implements UiEventLogger.UiEventEnum {
|
||||
|
||||
@UiEvent(doc = "The home button was pressed in the navigation bar.")
|
||||
NAVBAR_HOME_BUTTON_TAP(533),
|
||||
|
||||
@UiEvent(doc = "The back button was pressed in the navigation bar.")
|
||||
NAVBAR_BACK_BUTTON_TAP(534),
|
||||
|
||||
@UiEvent(doc = "The overview button was pressed in the navigation bar.")
|
||||
NAVBAR_OVERVIEW_BUTTON_TAP(535),
|
||||
|
||||
@UiEvent(doc = "The home button was long-pressed in the navigation bar.")
|
||||
NAVBAR_HOME_BUTTON_LONGPRESS(536),
|
||||
|
||||
@UiEvent(doc = "The back button was long-pressed in the navigation bar.")
|
||||
NAVBAR_BACK_BUTTON_LONGPRESS(537),
|
||||
|
||||
@UiEvent(doc = "The overview button was long-pressed in the navigation bar.")
|
||||
NAVBAR_OVERVIEW_BUTTON_LONGPRESS(538),
|
||||
|
||||
NONE(0); // an event we should not log
|
||||
|
||||
private final int mId;
|
||||
|
||||
NavBarActionsEvent(int id) {
|
||||
mId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
}
|
||||
private final Runnable mCheckLongPress = new Runnable() {
|
||||
public void run() {
|
||||
if (isPressed()) {
|
||||
@@ -104,12 +142,14 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
|
||||
}
|
||||
|
||||
public KeyButtonView(Context context, AttributeSet attrs, int defStyle) {
|
||||
this(context, attrs, defStyle, InputManager.getInstance());
|
||||
this(context, attrs, defStyle, InputManager.getInstance(), new UiEventLoggerImpl());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public KeyButtonView(Context context, AttributeSet attrs, int defStyle, InputManager manager) {
|
||||
public KeyButtonView(Context context, AttributeSet attrs, int defStyle, InputManager manager,
|
||||
UiEventLogger uiEventLogger) {
|
||||
super(context, attrs);
|
||||
mUiEventLogger = uiEventLogger;
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
|
||||
defStyle, 0);
|
||||
@@ -326,13 +366,48 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
|
||||
sendEvent(action, flags, SystemClock.uptimeMillis());
|
||||
}
|
||||
|
||||
private void logSomePresses(int action, int flags) {
|
||||
boolean longPressSet = (flags & KeyEvent.FLAG_LONG_PRESS) != 0;
|
||||
NavBarActionsEvent uiEvent = NavBarActionsEvent.NONE;
|
||||
if (action == MotionEvent.ACTION_UP && mLongClicked) {
|
||||
return; // don't log the up after a long press
|
||||
}
|
||||
if (action == MotionEvent.ACTION_DOWN && !longPressSet) {
|
||||
return; // don't log a down unless it is also the long press marker
|
||||
}
|
||||
if ((flags & KeyEvent.FLAG_CANCELED) != 0
|
||||
|| (flags & KeyEvent.FLAG_CANCELED_LONG_PRESS) != 0) {
|
||||
return; // don't log various cancels
|
||||
}
|
||||
switch(mCode) {
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
uiEvent = longPressSet
|
||||
? NavBarActionsEvent.NAVBAR_BACK_BUTTON_LONGPRESS
|
||||
: NavBarActionsEvent.NAVBAR_BACK_BUTTON_TAP;
|
||||
break;
|
||||
case KeyEvent.KEYCODE_HOME:
|
||||
uiEvent = longPressSet
|
||||
? NavBarActionsEvent.NAVBAR_HOME_BUTTON_LONGPRESS
|
||||
: NavBarActionsEvent.NAVBAR_HOME_BUTTON_TAP;
|
||||
break;
|
||||
case KeyEvent.KEYCODE_APP_SWITCH:
|
||||
uiEvent = longPressSet
|
||||
? NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS
|
||||
: NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_TAP;
|
||||
break;
|
||||
}
|
||||
if (uiEvent != NavBarActionsEvent.NONE) {
|
||||
mUiEventLogger.log(uiEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendEvent(int action, int flags, long when) {
|
||||
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
|
||||
.setType(MetricsEvent.TYPE_ACTION)
|
||||
.setSubtype(mCode)
|
||||
.addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
|
||||
.addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
|
||||
// TODO(b/122195391): Added logs to make sure sysui is sending back button events
|
||||
logSomePresses(action, flags);
|
||||
if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
|
||||
Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
|
||||
if (action == MotionEvent.ACTION_UP) {
|
||||
|
||||
@@ -14,21 +14,33 @@
|
||||
|
||||
package com.android.systemui.statusbar.policy;
|
||||
|
||||
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_NAV_BUTTON_EVENT;
|
||||
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_FLAGS;
|
||||
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NAV_ACTION;
|
||||
import static android.view.KeyEvent.ACTION_DOWN;
|
||||
import static android.view.KeyEvent.ACTION_UP;
|
||||
import static android.view.KeyEvent.FLAG_CANCELED;
|
||||
import static android.view.KeyEvent.FLAG_LONG_PRESS;
|
||||
import static android.view.KeyEvent.KEYCODE_0;
|
||||
import static android.view.KeyEvent.KEYCODE_APP_SWITCH;
|
||||
import static android.view.KeyEvent.KEYCODE_BACK;
|
||||
import static android.view.KeyEvent.KEYCODE_HOME;
|
||||
|
||||
import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_BACK_BUTTON_LONGPRESS;
|
||||
import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_BACK_BUTTON_TAP;
|
||||
import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_HOME_BUTTON_LONGPRESS;
|
||||
import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_HOME_BUTTON_TAP;
|
||||
import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS;
|
||||
import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_TAP;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.hardware.input.InputManager;
|
||||
import android.metrics.LogMaker;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
@@ -37,7 +49,7 @@ import android.view.KeyEvent;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.bubbles.BubbleController;
|
||||
import com.android.systemui.recents.OverviewProxyService;
|
||||
@@ -46,12 +58,9 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper
|
||||
@SmallTest
|
||||
@@ -60,6 +69,7 @@ public class KeyButtonViewTest extends SysuiTestCase {
|
||||
private KeyButtonView mKeyButtonView;
|
||||
private MetricsLogger mMetricsLogger;
|
||||
private BubbleController mBubbleController;
|
||||
private UiEventLogger mUiEventLogger;
|
||||
private InputManager mInputManager = mock(InputManager.class);
|
||||
@Captor
|
||||
private ArgumentCaptor<KeyEvent> mInputEventCaptor;
|
||||
@@ -70,45 +80,74 @@ public class KeyButtonViewTest extends SysuiTestCase {
|
||||
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
|
||||
mBubbleController = mDependency.injectMockDependency(BubbleController.class);
|
||||
mDependency.injectMockDependency(OverviewProxyService.class);
|
||||
mUiEventLogger = mDependency.injectMockDependency(UiEventLogger.class);
|
||||
|
||||
TestableLooper.get(this).runWithLooper(() -> {
|
||||
mKeyButtonView = new KeyButtonView(mContext, null, 0, mInputManager);
|
||||
mKeyButtonView = new KeyButtonView(mContext, null, 0, mInputManager, mUiEventLogger);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetrics() {
|
||||
int action = 42;
|
||||
int flags = 0x141;
|
||||
int code = KeyEvent.KEYCODE_ENTER;
|
||||
public void testLogBackPress() {
|
||||
checkmetrics(KEYCODE_BACK, ACTION_UP, 0, NAVBAR_BACK_BUTTON_TAP);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogOverviewPress() {
|
||||
checkmetrics(KEYCODE_APP_SWITCH, ACTION_UP, 0, NAVBAR_OVERVIEW_BUTTON_TAP);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogHomePress() {
|
||||
checkmetrics(KEYCODE_HOME, ACTION_UP, 0, NAVBAR_HOME_BUTTON_TAP);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogBackLongPressLog() {
|
||||
checkmetrics(KEYCODE_BACK, ACTION_DOWN, FLAG_LONG_PRESS, NAVBAR_BACK_BUTTON_LONGPRESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogOverviewLongPress() {
|
||||
checkmetrics(KEYCODE_APP_SWITCH, ACTION_DOWN, FLAG_LONG_PRESS,
|
||||
NAVBAR_OVERVIEW_BUTTON_LONGPRESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogHomeLongPress() {
|
||||
checkmetrics(KEYCODE_HOME, ACTION_DOWN, FLAG_LONG_PRESS, NAVBAR_HOME_BUTTON_LONGPRESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoLogKeyDown() {
|
||||
checkmetrics(KEYCODE_BACK, ACTION_DOWN, 0, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoLogTapAfterLong() {
|
||||
mKeyButtonView.mLongClicked = true;
|
||||
checkmetrics(KEYCODE_BACK, ACTION_UP, 0, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoLogCanceled() {
|
||||
checkmetrics(KEYCODE_HOME, ACTION_UP, FLAG_CANCELED, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoLogArbitraryKeys() {
|
||||
checkmetrics(KEYCODE_0, ACTION_UP, 0, null);
|
||||
}
|
||||
|
||||
private void checkmetrics(int code, int action, int flag,
|
||||
KeyButtonView.NavBarActionsEvent expected) {
|
||||
mKeyButtonView.setCode(code);
|
||||
mKeyButtonView.sendEvent(action, flags);
|
||||
|
||||
verify(mMetricsLogger).write(argThat(new ArgumentMatcher<LogMaker>() {
|
||||
public String mReason;
|
||||
|
||||
@Override
|
||||
public boolean matches(LogMaker argument) {
|
||||
return checkField("category", argument.getCategory(), ACTION_NAV_BUTTON_EVENT)
|
||||
&& checkField("type", argument.getType(), MetricsEvent.TYPE_ACTION)
|
||||
&& checkField("subtype", argument.getSubtype(), code)
|
||||
&& checkField("FIELD_FLAGS", argument.getTaggedData(FIELD_FLAGS), flags)
|
||||
&& checkField("FIELD_NAV_ACTION", argument.getTaggedData(FIELD_NAV_ACTION),
|
||||
action);
|
||||
}
|
||||
|
||||
private boolean checkField(String field, Object val, Object val2) {
|
||||
if (!Objects.equals(val, val2)) {
|
||||
mReason = "Expected " + field + " " + val2 + " but was " + val;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mReason;
|
||||
}
|
||||
}));
|
||||
mKeyButtonView.sendEvent(action, flag);
|
||||
if (expected == null) {
|
||||
verify(mUiEventLogger, never()).log(any(KeyButtonView.NavBarActionsEvent.class));
|
||||
} else {
|
||||
verify(mUiEventLogger, times(1)).log(expected);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user