diff --git a/src/com/android/settings/core/InstrumentedPreferenceFragment.java b/src/com/android/settings/core/InstrumentedPreferenceFragment.java index 48e5176c891..bff405b8e6d 100644 --- a/src/com/android/settings/core/InstrumentedPreferenceFragment.java +++ b/src/com/android/settings/core/InstrumentedPreferenceFragment.java @@ -27,6 +27,7 @@ import android.util.Log; import androidx.annotation.XmlRes; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; import androidx.recyclerview.widget.RecyclerView; import com.android.internal.jank.InteractionJankMonitor; @@ -34,6 +35,7 @@ import com.android.settings.overlay.FeatureFactory; import com.android.settings.survey.SurveyMixin; import com.android.settingslib.core.instrumentation.Instrumentable; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.settingslib.core.instrumentation.SettingsJankMonitor; import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment; @@ -45,7 +47,6 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc private static final String TAG = "InstrumentedPrefFrag"; - protected MetricsFeatureProvider mMetricsFeatureProvider; // metrics placeholder value. Only use this for development. @@ -65,6 +66,19 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc super.onAttach(context); } + @Override + public void onStart() { + super.onStart(); + // Override the OnPreferenceTreeClickListener in super.onStart() to inject jank detection. + getPreferenceManager().setOnPreferenceTreeClickListener((preference) -> { + if (preference instanceof SwitchPreference) { + SettingsJankMonitor.detectSwitchPreferenceClickJank( + getListView(), (SwitchPreference) preference); + } + return onPreferenceTreeClick(preference); + }); + } + @Override public void onResume() { mVisibilityLoggerMixin.setSourceMetricsCategory(getActivity()); diff --git a/src/com/android/settings/core/TogglePreferenceController.java b/src/com/android/settings/core/TogglePreferenceController.java index fa83aeacdf1..f14e0b23b87 100644 --- a/src/com/android/settings/core/TogglePreferenceController.java +++ b/src/com/android/settings/core/TogglePreferenceController.java @@ -16,12 +16,15 @@ package com.android.settings.core; import android.content.Context; import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; import androidx.preference.TwoStatePreference; import com.android.settings.overlay.FeatureFactory; import com.android.settings.slices.SliceData; import com.android.settings.widget.TwoStateButtonPreference; import com.android.settingslib.PrimarySwitchPreference; +import com.android.settingslib.core.instrumentation.SettingsJankMonitor; +import com.android.settingslib.widget.MainSwitchPreference; /** * Abstract class that consolidates logic for updating toggle controllers. @@ -50,6 +53,16 @@ public abstract class TogglePreferenceController extends BasePreferenceControlle */ public abstract boolean setChecked(boolean isChecked); + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + Preference preference = screen.findPreference(getPreferenceKey()); + if (preference instanceof MainSwitchPreference) { + ((MainSwitchPreference) preference).addOnSwitchChangeListener((switchView, isChecked) -> + SettingsJankMonitor.detectToggleJank(getPreferenceKey(), switchView)); + } + } + @Override public void updateState(Preference preference) { if (preference instanceof TwoStatePreference) { diff --git a/src/com/android/settings/widget/SettingsMainSwitchPreference.java b/src/com/android/settings/widget/SettingsMainSwitchPreference.java index 92649113d82..ce91c9e693c 100644 --- a/src/com/android/settings/widget/SettingsMainSwitchPreference.java +++ b/src/com/android/settings/widget/SettingsMainSwitchPreference.java @@ -32,6 +32,7 @@ import androidx.preference.TwoStatePreference; import com.android.settings.R; import com.android.settings.widget.SettingsMainSwitchBar.OnBeforeCheckedChangeListener; import com.android.settingslib.RestrictedPreferenceHelper; +import com.android.settingslib.core.instrumentation.SettingsJankMonitor; import com.android.settingslib.widget.OnMainSwitchChangeListener; import com.google.android.setupdesign.util.LayoutStyler; @@ -153,6 +154,7 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements @Override public void onSwitchChanged(Switch switchView, boolean isChecked) { super.setChecked(isChecked); + SettingsJankMonitor.detectToggleJank(getKey(), switchView); } /** diff --git a/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java index 8d643ad4613..3cb3abfc4a0 100644 --- a/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java @@ -31,9 +31,11 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.content.Context; import android.provider.Settings; +import android.widget.Switch; import androidx.preference.PreferenceScreen; +import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor; import com.android.settingslib.widget.MainSwitchPreference; import org.junit.Before; @@ -44,16 +46,21 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowActivityManager; @RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowInteractionJankMonitor.class}) public class BubbleNotificationPreferenceControllerTest { private Context mContext; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private PreferenceScreen mScreen; + @Mock + private Switch mSwitch; + private BubbleNotificationPreferenceController mController; private MainSwitchPreference mPreference; @@ -102,7 +109,7 @@ public class BubbleNotificationPreferenceControllerTest { public void onSwitchChanged_true_settingIsOff_flagShouldOn() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, OFF); - mController.onSwitchChanged(null, true); + mController.onSwitchChanged(mSwitch, true); assertThat(Settings.Global.getInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, OFF)).isEqualTo(ON); @@ -112,7 +119,7 @@ public class BubbleNotificationPreferenceControllerTest { public void onSwitchChanged_false_settingIsOn_flagShouldOff() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, ON); - mController.onSwitchChanged(null, false); + mController.onSwitchChanged(mSwitch, false); assertThat(Settings.Global.getInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, ON)).isEqualTo(OFF); diff --git a/tests/robotests/src/com/android/settings/notification/app/BlockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BlockPreferenceControllerTest.java index 0c2eebe8070..9e9e655e3af 100644 --- a/tests/robotests/src/com/android/settings/notification/app/BlockPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/app/BlockPreferenceControllerTest.java @@ -17,7 +17,6 @@ package com.android.settings.notification.app; import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID; -import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_NONE; @@ -49,6 +48,7 @@ import androidx.preference.PreferenceViewHolder; import com.android.settings.notification.NotificationBackend; import com.android.settings.widget.SettingsMainSwitchPreference; +import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor; import org.junit.Before; import org.junit.Test; @@ -57,11 +57,13 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowApplication; import java.util.ArrayList; @RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowInteractionJankMonitor.class}) public class BlockPreferenceControllerTest { private Context mContext; diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java index 3ec07c515ce..9eb08d79246 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java @@ -23,6 +23,10 @@ import com.android.internal.jank.InteractionJankMonitor; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +/** + * @deprecated use {@link com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor} + */ +@Deprecated @Implements(InteractionJankMonitor.class) public class ShadowInteractionJankMonitor {