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

Commit d6208202 authored by Yanting Yang's avatar Yanting Yang
Browse files

Introduce InteractionJankMonitor into Settings

Detects the jank of page scrolling which is implemented by
InstrumentedPreferenceFragment.

Bug: 187306869
Test: verify with Perfetto

Change-Id: Icaa557d1b47a12374298f044e2f9568281589f64
parent 8c1c7b63
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.settings.core;

import static com.android.internal.jank.InteractionJankMonitor.CUJ_SETTINGS_PAGE_SCROLL;

import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
@@ -24,7 +26,9 @@ import android.util.Log;
import androidx.annotation.XmlRes;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView;

import com.android.internal.jank.InteractionJankMonitor;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.survey.SurveyMixin;
import com.android.settingslib.core.instrumentation.Instrumentable;
@@ -47,6 +51,7 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc
    protected final int PLACEHOLDER_METRIC = 10000;

    private VisibilityLoggerMixin mVisibilityLoggerMixin;
    private RecyclerView.OnScrollListener mOnScrollListener;

    @Override
    public void onAttach(Context context) {
@@ -62,9 +67,25 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc
    @Override
    public void onResume() {
        mVisibilityLoggerMixin.setSourceMetricsCategory(getActivity());
        // Add scroll listener to trace interaction jank.
        final RecyclerView recyclerView = getListView();
        if (recyclerView != null) {
            mOnScrollListener = new OnScrollListener(getClass().getName());
            recyclerView.addOnScrollListener(mOnScrollListener);
        }
        super.onResume();
    }

    @Override
    public void onPause() {
        final RecyclerView recyclerView = getListView();
        if (mOnScrollListener != null) {
            recyclerView.removeOnScrollListener(mOnScrollListener);
            mOnScrollListener = null;
        }
        super.onPause();
    }

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        final int resId = getPreferenceScreenResId();
@@ -123,4 +144,26 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc
        }
    }

    private static final class OnScrollListener extends RecyclerView.OnScrollListener {
        private final InteractionJankMonitor mMonitor = InteractionJankMonitor.getInstance();
        private final String mClassName;

        private OnScrollListener(String className) {
            mClassName = className;
        }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            switch (newState) {
                case RecyclerView.SCROLL_STATE_DRAGGING:
                    // TODO: Update API with tag parameter (class name).
                    mMonitor.begin(recyclerView, CUJ_SETTINGS_PAGE_SCROLL);
                    break;
                case RecyclerView.SCROLL_STATE_IDLE:
                    mMonitor.end(CUJ_SETTINGS_PAGE_SCROLL);
                    break;
                default:
            }
        }
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.core.FeatureFlags;
import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowStorageManager;
import com.android.settings.testutils.shadow.ShadowUserManager;
@@ -81,7 +82,8 @@ import org.robolectric.shadows.ShadowPersistentDataBlockManager;
                ShadowPersistentDataBlockManager.class,
                ShadowStorageManager.class,
                ShadowUserManager.class,
                ShadowUtils.class
                ShadowUtils.class,
                ShadowInteractionJankMonitor.class
        })
public class ChooseLockGenericTest {

+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.settings.testutils.shadow;

import static org.mockito.Mockito.mock;

import com.android.internal.jank.InteractionJankMonitor;

import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;

@Implements(InteractionJankMonitor.class)
public class ShadowInteractionJankMonitor {

    @Implementation
    public static InteractionJankMonitor getInstance() {
        return mock(InteractionJankMonitor.class);
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import com.android.settings.testutils.XmlTestUtils;
import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
import com.android.settingslib.core.AbstractPreferenceController;

import org.junit.Before;
@@ -55,11 +56,13 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

import java.util.ArrayList;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowInteractionJankMonitor.class)
public class WifiP2pSettingsTest {

    private Context mContext;
+3 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import androidx.fragment.app.FragmentTransaction;

import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
import com.android.settingslib.core.AbstractPreferenceController;

import org.junit.Before;
@@ -43,8 +44,10 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowInteractionJankMonitor.class)
public class SavedAccessPointsWifiSettings2Test {

    @Mock