Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a15a870d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents 0fcf6ff4 fad16787
Loading
Loading
Loading
Loading
+79 −4
Original line number Diff line number Diff line
@@ -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) {
+81 −42
Original line number Diff line number Diff line
@@ -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;
        mKeyButtonView.setCode(code);
        mKeyButtonView.sendEvent(action, flags);
    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);
    }

        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);
    @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);
    }

            private boolean checkField(String field, Object val, Object val2) {
                if (!Objects.equals(val, val2)) {
                    mReason = "Expected " + field + " " + val2 + " but was " + val;
                    return false;
    @Test
    public void testNoLogTapAfterLong() {
        mKeyButtonView.mLongClicked = true;
        checkmetrics(KEYCODE_BACK, ACTION_UP, 0, null);
    }
                return true;

    @Test
    public void testNoLogCanceled() {
        checkmetrics(KEYCODE_HOME, ACTION_UP, FLAG_CANCELED, null);
    }

            @Override
            public String toString() {
                return mReason;
    @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, flag);
        if (expected == null) {
            verify(mUiEventLogger, never()).log(any(KeyButtonView.NavBarActionsEvent.class));
        } else {
            verify(mUiEventLogger, times(1)).log(expected);
        }
        }));
    }

    @Test