Add the jank detection to Settings toggles
Add jank detection when click the following preferences, - SwitchPreference Single target, detect click in InstrumentedPreferenceFragment - PrimarySwitchPreference Two target, only detect click switch in switch's onClick() - MainSwitchPreference Single target, detect click in TogglePreferenceController - SettingsMainSwitchPreference Single target, detect click in its onSwitchChanged() Bug: 230285829 Test: manual & robo tests Change-Id: I97a13e05a601237b16cd2d903ba2fb6ec4a69a74
This commit is contained in:
@@ -27,6 +27,7 @@ import android.util.Log;
|
|||||||
import androidx.annotation.XmlRes;
|
import androidx.annotation.XmlRes;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
import androidx.preference.SwitchPreference;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.android.internal.jank.InteractionJankMonitor;
|
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.settings.survey.SurveyMixin;
|
||||||
import com.android.settingslib.core.instrumentation.Instrumentable;
|
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
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.instrumentation.VisibilityLoggerMixin;
|
||||||
import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
|
import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
|
||||||
|
|
||||||
@@ -45,7 +47,6 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc
|
|||||||
|
|
||||||
private static final String TAG = "InstrumentedPrefFrag";
|
private static final String TAG = "InstrumentedPrefFrag";
|
||||||
|
|
||||||
|
|
||||||
protected MetricsFeatureProvider mMetricsFeatureProvider;
|
protected MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
|
|
||||||
// metrics placeholder value. Only use this for development.
|
// metrics placeholder value. Only use this for development.
|
||||||
@@ -65,6 +66,19 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc
|
|||||||
super.onAttach(context);
|
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
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
mVisibilityLoggerMixin.setSourceMetricsCategory(getActivity());
|
mVisibilityLoggerMixin.setSourceMetricsCategory(getActivity());
|
||||||
|
@@ -16,12 +16,15 @@ package com.android.settings.core;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
import androidx.preference.TwoStatePreference;
|
import androidx.preference.TwoStatePreference;
|
||||||
|
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.slices.SliceData;
|
import com.android.settings.slices.SliceData;
|
||||||
import com.android.settings.widget.TwoStateButtonPreference;
|
import com.android.settings.widget.TwoStateButtonPreference;
|
||||||
import com.android.settingslib.PrimarySwitchPreference;
|
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.
|
* 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);
|
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
|
@Override
|
||||||
public void updateState(Preference preference) {
|
public void updateState(Preference preference) {
|
||||||
if (preference instanceof TwoStatePreference) {
|
if (preference instanceof TwoStatePreference) {
|
||||||
|
@@ -32,6 +32,7 @@ import androidx.preference.TwoStatePreference;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.widget.SettingsMainSwitchBar.OnBeforeCheckedChangeListener;
|
import com.android.settings.widget.SettingsMainSwitchBar.OnBeforeCheckedChangeListener;
|
||||||
import com.android.settingslib.RestrictedPreferenceHelper;
|
import com.android.settingslib.RestrictedPreferenceHelper;
|
||||||
|
import com.android.settingslib.core.instrumentation.SettingsJankMonitor;
|
||||||
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
||||||
|
|
||||||
import com.google.android.setupdesign.util.LayoutStyler;
|
import com.google.android.setupdesign.util.LayoutStyler;
|
||||||
@@ -153,6 +154,7 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements
|
|||||||
@Override
|
@Override
|
||||||
public void onSwitchChanged(Switch switchView, boolean isChecked) {
|
public void onSwitchChanged(Switch switchView, boolean isChecked) {
|
||||||
super.setChecked(isChecked);
|
super.setChecked(isChecked);
|
||||||
|
SettingsJankMonitor.detectToggleJank(getKey(), switchView);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -31,9 +31,11 @@ import static org.mockito.Mockito.when;
|
|||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.widget.Switch;
|
||||||
|
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
|
||||||
import com.android.settingslib.widget.MainSwitchPreference;
|
import com.android.settingslib.widget.MainSwitchPreference;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -44,16 +46,21 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadow.api.Shadow;
|
import org.robolectric.shadow.api.Shadow;
|
||||||
import org.robolectric.shadows.ShadowActivityManager;
|
import org.robolectric.shadows.ShadowActivityManager;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(shadows = {ShadowInteractionJankMonitor.class})
|
||||||
public class BubbleNotificationPreferenceControllerTest {
|
public class BubbleNotificationPreferenceControllerTest {
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
private PreferenceScreen mScreen;
|
private PreferenceScreen mScreen;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Switch mSwitch;
|
||||||
|
|
||||||
private BubbleNotificationPreferenceController mController;
|
private BubbleNotificationPreferenceController mController;
|
||||||
private MainSwitchPreference mPreference;
|
private MainSwitchPreference mPreference;
|
||||||
|
|
||||||
@@ -102,7 +109,7 @@ public class BubbleNotificationPreferenceControllerTest {
|
|||||||
public void onSwitchChanged_true_settingIsOff_flagShouldOn() {
|
public void onSwitchChanged_true_settingIsOff_flagShouldOn() {
|
||||||
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, OFF);
|
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, OFF);
|
||||||
|
|
||||||
mController.onSwitchChanged(null, true);
|
mController.onSwitchChanged(mSwitch, true);
|
||||||
|
|
||||||
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
|
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
NOTIFICATION_BUBBLES, OFF)).isEqualTo(ON);
|
NOTIFICATION_BUBBLES, OFF)).isEqualTo(ON);
|
||||||
@@ -112,7 +119,7 @@ public class BubbleNotificationPreferenceControllerTest {
|
|||||||
public void onSwitchChanged_false_settingIsOn_flagShouldOff() {
|
public void onSwitchChanged_false_settingIsOn_flagShouldOff() {
|
||||||
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, ON);
|
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, ON);
|
||||||
|
|
||||||
mController.onSwitchChanged(null, false);
|
mController.onSwitchChanged(mSwitch, false);
|
||||||
|
|
||||||
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
|
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
NOTIFICATION_BUBBLES, ON)).isEqualTo(OFF);
|
NOTIFICATION_BUBBLES, ON)).isEqualTo(OFF);
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
package com.android.settings.notification.app;
|
package com.android.settings.notification.app;
|
||||||
|
|
||||||
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
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_HIGH;
|
||||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
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.notification.NotificationBackend;
|
||||||
import com.android.settings.widget.SettingsMainSwitchPreference;
|
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||||
|
import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -57,11 +57,13 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadows.ShadowApplication;
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(shadows = {ShadowInteractionJankMonitor.class})
|
||||||
public class BlockPreferenceControllerTest {
|
public class BlockPreferenceControllerTest {
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
@@ -23,6 +23,10 @@ import com.android.internal.jank.InteractionJankMonitor;
|
|||||||
import org.robolectric.annotation.Implementation;
|
import org.robolectric.annotation.Implementation;
|
||||||
import org.robolectric.annotation.Implements;
|
import org.robolectric.annotation.Implements;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
@Implements(InteractionJankMonitor.class)
|
@Implements(InteractionJankMonitor.class)
|
||||||
public class ShadowInteractionJankMonitor {
|
public class ShadowInteractionJankMonitor {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user