Merge "add uievent logs for nav buttons" into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-06-06 05:01:39 +00:00
committed by Android (Google) Code Review
2 changed files with 160 additions and 46 deletions

View File

@@ -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) {

View File

@@ -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