Merge "Fix footer preference may flash one time when entering" into sc-dev
diff --git a/src/com/android/settings/core/InstrumentedPreferenceFragment.java b/src/com/android/settings/core/InstrumentedPreferenceFragment.java
index 06e6584..183c6f7 100644
--- a/src/com/android/settings/core/InstrumentedPreferenceFragment.java
+++ b/src/com/android/settings/core/InstrumentedPreferenceFragment.java
@@ -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 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 @@
     protected final int PLACEHOLDER_METRIC = 10000;
 
     private VisibilityLoggerMixin mVisibilityLoggerMixin;
+    private RecyclerView.OnScrollListener mOnScrollListener;
 
     @Override
     public void onAttach(Context context) {
@@ -62,10 +67,26 @@
     @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();
         if (resId > 0) {
@@ -123,4 +144,26 @@
         }
     }
 
+    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:
+            }
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
index 6b92e57..fd711f8 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
@@ -57,6 +57,7 @@
 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 @@
                 ShadowPersistentDataBlockManager.class,
                 ShadowStorageManager.class,
                 ShadowUserManager.class,
-                ShadowUtils.class
+                ShadowUtils.class,
+                ShadowInteractionJankMonitor.class
         })
 public class ChooseLockGenericTest {
 
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java
new file mode 100644
index 0000000..3ec07c5
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java
@@ -0,0 +1,33 @@
+/*
+ * 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);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
index c9d2119..ab306d9 100644
--- a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
@@ -45,6 +45,7 @@
 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.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;
diff --git a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2Test.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2Test.java
index 657d3a7..8c07ac3 100644
--- a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2Test.java
@@ -33,6 +33,7 @@
 
 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.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