Merge changes from topic "jank-toggle" into tm-dev
* changes: Add SettingsJankMonitor Add SETTINGS_TOGGLE CUJ to InteractionJankMonitor
This commit is contained in:
@@ -20,6 +20,7 @@ import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL;
|
|||||||
import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT;
|
import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT;
|
||||||
import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
|
import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
|
||||||
import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN;
|
import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION;
|
||||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
|
||||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
|
||||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
|
||||||
@@ -46,6 +47,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
|
|||||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD;
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD;
|
||||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL;
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL;
|
||||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER;
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_TOGGLE;
|
||||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH;
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH;
|
||||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON;
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON;
|
||||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER;
|
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER;
|
||||||
@@ -198,6 +200,7 @@ public class InteractionJankMonitor {
|
|||||||
public static final int CUJ_SETTINGS_SLIDER = 53;
|
public static final int CUJ_SETTINGS_SLIDER = 53;
|
||||||
public static final int CUJ_TAKE_SCREENSHOT = 54;
|
public static final int CUJ_TAKE_SCREENSHOT = 54;
|
||||||
public static final int CUJ_VOLUME_CONTROL = 55;
|
public static final int CUJ_VOLUME_CONTROL = 55;
|
||||||
|
public static final int CUJ_SETTINGS_TOGGLE = 57;
|
||||||
|
|
||||||
private static final int NO_STATSD_LOGGING = -1;
|
private static final int NO_STATSD_LOGGING = -1;
|
||||||
|
|
||||||
@@ -262,6 +265,8 @@ public class InteractionJankMonitor {
|
|||||||
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER,
|
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER,
|
||||||
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TAKE_SCREENSHOT,
|
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TAKE_SCREENSHOT,
|
||||||
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL,
|
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL,
|
||||||
|
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION,
|
||||||
|
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_TOGGLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static volatile InteractionJankMonitor sInstance;
|
private static volatile InteractionJankMonitor sInstance;
|
||||||
@@ -338,6 +343,7 @@ public class InteractionJankMonitor {
|
|||||||
CUJ_SETTINGS_SLIDER,
|
CUJ_SETTINGS_SLIDER,
|
||||||
CUJ_TAKE_SCREENSHOT,
|
CUJ_TAKE_SCREENSHOT,
|
||||||
CUJ_VOLUME_CONTROL,
|
CUJ_VOLUME_CONTROL,
|
||||||
|
CUJ_SETTINGS_TOGGLE,
|
||||||
})
|
})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface CujType {
|
public @interface CujType {
|
||||||
@@ -768,6 +774,8 @@ public class InteractionJankMonitor {
|
|||||||
return "TAKE_SCREENSHOT";
|
return "TAKE_SCREENSHOT";
|
||||||
case CUJ_VOLUME_CONTROL:
|
case CUJ_VOLUME_CONTROL:
|
||||||
return "VOLUME_CONTROL";
|
return "VOLUME_CONTROL";
|
||||||
|
case CUJ_SETTINGS_TOGGLE:
|
||||||
|
return "SETTINGS_TOGGLE";
|
||||||
}
|
}
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ package com.android.settingslib;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.widget.Switch;
|
import android.widget.Switch;
|
||||||
|
|
||||||
import androidx.annotation.Keep;
|
import androidx.annotation.Keep;
|
||||||
@@ -28,6 +26,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.preference.PreferenceViewHolder;
|
import androidx.preference.PreferenceViewHolder;
|
||||||
|
|
||||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||||
|
import com.android.settingslib.core.instrumentation.SettingsJankMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom preference that provides inline switch toggle. It has a mandatory field for title, and
|
* A custom preference that provides inline switch toggle. It has a mandatory field for title, and
|
||||||
@@ -65,31 +64,25 @@ public class PrimarySwitchPreference extends RestrictedPreference {
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||||
super.onBindViewHolder(holder);
|
super.onBindViewHolder(holder);
|
||||||
final View switchWidget = holder.findViewById(R.id.switchWidget);
|
mSwitch = (Switch) holder.findViewById(R.id.switchWidget);
|
||||||
if (switchWidget != null) {
|
if (mSwitch != null) {
|
||||||
switchWidget.setOnClickListener(new OnClickListener() {
|
mSwitch.setOnClickListener(v -> {
|
||||||
@Override
|
if (mSwitch != null && !mSwitch.isEnabled()) {
|
||||||
public void onClick(View v) {
|
return;
|
||||||
if (mSwitch != null && !mSwitch.isEnabled()) {
|
}
|
||||||
return;
|
final boolean newChecked = !mChecked;
|
||||||
}
|
if (callChangeListener(newChecked)) {
|
||||||
setChecked(!mChecked);
|
SettingsJankMonitor.detectToggleJank(getKey(), mSwitch);
|
||||||
if (!callChangeListener(mChecked)) {
|
setChecked(newChecked);
|
||||||
setChecked(!mChecked);
|
persistBoolean(newChecked);
|
||||||
} else {
|
|
||||||
persistBoolean(mChecked);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Consumes move events to ignore drag actions.
|
// Consumes move events to ignore drag actions.
|
||||||
switchWidget.setOnTouchListener((v, event) -> {
|
mSwitch.setOnTouchListener((v, event) -> {
|
||||||
return event.getActionMasked() == MotionEvent.ACTION_MOVE;
|
return event.getActionMasked() == MotionEvent.ACTION_MOVE;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
mSwitch = (Switch) holder.findViewById(R.id.switchWidget);
|
|
||||||
if (mSwitch != null) {
|
|
||||||
mSwitch.setContentDescription(getTitle());
|
mSwitch.setContentDescription(getTitle());
|
||||||
mSwitch.setChecked(mChecked);
|
mSwitch.setChecked(mChecked);
|
||||||
mSwitch.setEnabled(mEnableSwitch);
|
mSwitch.setEnabled(mEnableSwitch);
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.settingslib.core.instrumentation
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import androidx.preference.PreferenceGroupAdapter
|
||||||
|
import androidx.preference.SwitchPreference
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.android.internal.jank.InteractionJankMonitor
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for Settings library to trace jank.
|
||||||
|
*/
|
||||||
|
object SettingsJankMonitor {
|
||||||
|
private val jankMonitor = InteractionJankMonitor.getInstance()
|
||||||
|
private val scheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
|
||||||
|
|
||||||
|
// Switch toggle animation duration is 250ms, and there is also a ripple effect animation when
|
||||||
|
// clicks, which duration is variable. Use 300ms here to cover.
|
||||||
|
@VisibleForTesting
|
||||||
|
const val MONITORED_ANIMATION_DURATION_MS = 300L
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects the jank when click on a SwitchPreference.
|
||||||
|
*
|
||||||
|
* @param recyclerView the recyclerView contains the preference
|
||||||
|
* @param preference the clicked preference
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun detectSwitchPreferenceClickJank(recyclerView: RecyclerView, preference: SwitchPreference) {
|
||||||
|
val adapter = recyclerView.adapter as? PreferenceGroupAdapter ?: return
|
||||||
|
val adapterPosition = adapter.getPreferenceAdapterPosition(preference)
|
||||||
|
val viewHolder = recyclerView.findViewHolderForAdapterPosition(adapterPosition) ?: return
|
||||||
|
detectToggleJank(preference.key, viewHolder.itemView)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects the animation jank on the given view.
|
||||||
|
*
|
||||||
|
* @param tag the tag for jank monitor
|
||||||
|
* @param view the instrumented view
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun detectToggleJank(tag: String?, view: View) {
|
||||||
|
val builder = InteractionJankMonitor.Configuration.Builder.withView(
|
||||||
|
InteractionJankMonitor.CUJ_SETTINGS_TOGGLE,
|
||||||
|
view
|
||||||
|
)
|
||||||
|
if (tag != null) {
|
||||||
|
builder.setTag(tag)
|
||||||
|
}
|
||||||
|
if (jankMonitor.begin(builder)) {
|
||||||
|
scheduledExecutorService.schedule({
|
||||||
|
jankMonitor.end(InteractionJankMonitor.CUJ_SETTINGS_TOGGLE)
|
||||||
|
}, MONITORED_ANIMATION_DURATION_MS, TimeUnit.MILLISECONDS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,6 +63,7 @@ java_library {
|
|||||||
|
|
||||||
libs: [
|
libs: [
|
||||||
"Robolectric_all-target",
|
"Robolectric_all-target",
|
||||||
|
"mockito-robolectric-prebuilt",
|
||||||
"truth-prebuilt",
|
"truth-prebuilt",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,14 +30,17 @@ import androidx.preference.Preference.OnPreferenceChangeListener;
|
|||||||
import androidx.preference.PreferenceViewHolder;
|
import androidx.preference.PreferenceViewHolder;
|
||||||
|
|
||||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||||
|
import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(shadows = {ShadowInteractionJankMonitor.class})
|
||||||
public class PrimarySwitchPreferenceTest {
|
public class PrimarySwitchPreferenceTest {
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.settingslib.core.instrumentation;
|
||||||
|
|
||||||
|
import static com.android.internal.jank.InteractionJankMonitor.CUJ_SETTINGS_TOGGLE;
|
||||||
|
import static com.android.settingslib.core.instrumentation.SettingsJankMonitor.MONITORED_ANIMATION_DURATION_MS;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceGroupAdapter;
|
||||||
|
import androidx.preference.SwitchPreference;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.internal.jank.InteractionJankMonitor;
|
||||||
|
import com.android.internal.jank.InteractionJankMonitor.CujType;
|
||||||
|
import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.annotation.Implementation;
|
||||||
|
import org.robolectric.annotation.Implements;
|
||||||
|
import org.robolectric.annotation.Resetter;
|
||||||
|
import org.robolectric.util.ReflectionHelpers;
|
||||||
|
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(shadows = {ShadowInteractionJankMonitor.class, SettingsJankMonitorTest.ShadowBuilder.class})
|
||||||
|
public class SettingsJankMonitorTest {
|
||||||
|
private static final String TEST_KEY = "key";
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public MockitoRule mocks = MockitoJUnit.rule();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private View mView;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RecyclerView mRecyclerView;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PreferenceGroupAdapter mPreferenceGroupAdapter;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private SwitchPreference mSwitchPreference;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ScheduledExecutorService mScheduledExecutorService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
ShadowInteractionJankMonitor.reset();
|
||||||
|
when(ShadowInteractionJankMonitor.MOCK_INSTANCE.begin(any())).thenReturn(true);
|
||||||
|
ReflectionHelpers.setStaticField(SettingsJankMonitor.class, "scheduledExecutorService",
|
||||||
|
mScheduledExecutorService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void detectToggleJank() {
|
||||||
|
SettingsJankMonitor.detectToggleJank(TEST_KEY, mView);
|
||||||
|
|
||||||
|
verifyToggleJankMonitored();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void detectSwitchPreferenceClickJank() {
|
||||||
|
int adapterPosition = 7;
|
||||||
|
when(mRecyclerView.getAdapter()).thenReturn(mPreferenceGroupAdapter);
|
||||||
|
when(mPreferenceGroupAdapter.getPreferenceAdapterPosition(mSwitchPreference))
|
||||||
|
.thenReturn(adapterPosition);
|
||||||
|
when(mRecyclerView.findViewHolderForAdapterPosition(adapterPosition))
|
||||||
|
.thenReturn(new RecyclerView.ViewHolder(mView) {
|
||||||
|
});
|
||||||
|
when(mSwitchPreference.getKey()).thenReturn(TEST_KEY);
|
||||||
|
|
||||||
|
SettingsJankMonitor.detectSwitchPreferenceClickJank(mRecyclerView, mSwitchPreference);
|
||||||
|
|
||||||
|
verifyToggleJankMonitored();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyToggleJankMonitored() {
|
||||||
|
verify(ShadowInteractionJankMonitor.MOCK_INSTANCE).begin(ShadowBuilder.sBuilder);
|
||||||
|
assertThat(ShadowBuilder.sView).isSameInstanceAs(mView);
|
||||||
|
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||||
|
verify(mScheduledExecutorService).schedule(runnableCaptor.capture(),
|
||||||
|
eq(MONITORED_ANIMATION_DURATION_MS), eq(TimeUnit.MILLISECONDS));
|
||||||
|
runnableCaptor.getValue().run();
|
||||||
|
verify(ShadowInteractionJankMonitor.MOCK_INSTANCE).end(CUJ_SETTINGS_TOGGLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implements(InteractionJankMonitor.Configuration.Builder.class)
|
||||||
|
static class ShadowBuilder {
|
||||||
|
private static InteractionJankMonitor.Configuration.Builder sBuilder;
|
||||||
|
private static View sView;
|
||||||
|
|
||||||
|
@Resetter
|
||||||
|
public static void reset() {
|
||||||
|
sBuilder = null;
|
||||||
|
sView = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public static InteractionJankMonitor.Configuration.Builder withView(
|
||||||
|
@CujType int cuj, @NonNull View view) {
|
||||||
|
assertThat(cuj).isEqualTo(CUJ_SETTINGS_TOGGLE);
|
||||||
|
sView = view;
|
||||||
|
sBuilder = mock(InteractionJankMonitor.Configuration.Builder.class);
|
||||||
|
when(sBuilder.setTag(TEST_KEY)).thenReturn(sBuilder);
|
||||||
|
return sBuilder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.settingslib.testutils.shadow;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import com.android.internal.jank.InteractionJankMonitor;
|
||||||
|
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.robolectric.annotation.Implementation;
|
||||||
|
import org.robolectric.annotation.Implements;
|
||||||
|
import org.robolectric.annotation.Resetter;
|
||||||
|
|
||||||
|
@Implements(InteractionJankMonitor.class)
|
||||||
|
public class ShadowInteractionJankMonitor {
|
||||||
|
public static final InteractionJankMonitor MOCK_INSTANCE = mock(InteractionJankMonitor.class);
|
||||||
|
|
||||||
|
@Resetter
|
||||||
|
public static void reset() {
|
||||||
|
Mockito.reset(MOCK_INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public static InteractionJankMonitor getInstance() {
|
||||||
|
return MOCK_INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user