Log AppCompatStateChanged atom.
Metric Design doc: eldar/122311064 Bug: 190487401 Test: Ran $ statsd_testdrive 386 Test: atest CtsWindowManagerDeviceTestCases:ActivityMetricsLoggerTests Change-Id: I224b431fb76d49f109db3a44f9655269cbacf547
This commit is contained in:
@@ -59,6 +59,8 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_T
|
||||
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
|
||||
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
|
||||
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
|
||||
import static com.android.server.am.MemoryStatUtil.MemoryStat;
|
||||
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
|
||||
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
|
||||
@@ -89,6 +91,7 @@ import android.util.ArrayMap;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TimeUtils;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
@@ -157,6 +160,9 @@ class ActivityMetricsLogger {
|
||||
private final ArrayList<TransitionInfo> mTransitionInfoList = new ArrayList<>();
|
||||
/** Map : Last launched activity => {@link TransitionInfo} */
|
||||
private final ArrayMap<ActivityRecord, TransitionInfo> mLastTransitionInfo = new ArrayMap<>();
|
||||
/** SparseArray : Package UID => {@link PackageCompatStateInfo} */
|
||||
private final SparseArray<PackageCompatStateInfo> mPackageUidToCompatStateInfo =
|
||||
new SparseArray<>(0);
|
||||
|
||||
private ArtManagerInternal mArtManagerInternal;
|
||||
private final StringBuilder mStringBuilder = new StringBuilder();
|
||||
@@ -447,6 +453,15 @@ class ActivityMetricsLogger {
|
||||
}
|
||||
}
|
||||
|
||||
/** Information about the App Compat state logging associated with a package UID . */
|
||||
private static final class PackageCompatStateInfo {
|
||||
/** All activities that have a visible state. */
|
||||
final ArrayList<ActivityRecord> mVisibleActivities = new ArrayList<>();
|
||||
/** The last logged state. */
|
||||
int mLastLoggedState = APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
|
||||
@Nullable ActivityRecord mLastLoggedActivity;
|
||||
}
|
||||
|
||||
ActivityMetricsLogger(ActivityTaskSupervisor supervisor, Looper looper) {
|
||||
mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
|
||||
mSupervisor = supervisor;
|
||||
@@ -767,6 +782,21 @@ class ActivityMetricsLogger {
|
||||
/** Makes sure that the reference to the removed activity is cleared. */
|
||||
void notifyActivityRemoved(@NonNull ActivityRecord r) {
|
||||
mLastTransitionInfo.remove(r);
|
||||
|
||||
final int packageUid = r.info.applicationInfo.uid;
|
||||
final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
|
||||
if (compatStateInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
compatStateInfo.mVisibleActivities.remove(r);
|
||||
if (compatStateInfo.mLastLoggedActivity == r) {
|
||||
compatStateInfo.mLastLoggedActivity = null;
|
||||
}
|
||||
if (compatStateInfo.mVisibleActivities.isEmpty()) {
|
||||
// No need to keep the entry if there are no visible activities.
|
||||
mPackageUidToCompatStateInfo.remove(packageUid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1263,6 +1293,115 @@ class ActivityMetricsLogger {
|
||||
memoryStat.swapInBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the current App Compat state of the given {@link ActivityRecord} with its package
|
||||
* UID, if all of the following hold:
|
||||
* <ul>
|
||||
* <li>The current state is different than the last logged state for the package UID of the
|
||||
* activity.
|
||||
* <li>If the current state is NOT_VISIBLE, there is a previously logged state for the
|
||||
* package UID and there are no other visible activities with the same package UID.
|
||||
* <li>The last logged activity with the same package UID is either {@code activity} or the
|
||||
* last logged state is NOT_VISIBLE or NOT_LETTERBOXED.
|
||||
* </ul>
|
||||
*
|
||||
* <p>If the current state is NOT_VISIBLE and the previous state which was logged by {@code
|
||||
* activity} wasn't, looks for the first visible activity with the same package UID that has
|
||||
* a letterboxed state, or a non-letterboxed state if there isn't one, and logs that state.
|
||||
*
|
||||
* <p>This method assumes that the caller is wrapping the call with a synchronized block so
|
||||
* that there won't be a race condition between two activities with the same package.
|
||||
*/
|
||||
void logAppCompatState(@NonNull ActivityRecord activity) {
|
||||
final int packageUid = activity.info.applicationInfo.uid;
|
||||
final int state = activity.getAppCompatState();
|
||||
|
||||
if (!mPackageUidToCompatStateInfo.contains(packageUid)) {
|
||||
mPackageUidToCompatStateInfo.put(packageUid, new PackageCompatStateInfo());
|
||||
}
|
||||
final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
|
||||
final int lastLoggedState = compatStateInfo.mLastLoggedState;
|
||||
final ActivityRecord lastLoggedActivity = compatStateInfo.mLastLoggedActivity;
|
||||
|
||||
final boolean isVisible = state != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
|
||||
final ArrayList<ActivityRecord> visibleActivities = compatStateInfo.mVisibleActivities;
|
||||
if (isVisible && !visibleActivities.contains(activity)) {
|
||||
visibleActivities.add(activity);
|
||||
} else if (!isVisible) {
|
||||
visibleActivities.remove(activity);
|
||||
if (visibleActivities.isEmpty()) {
|
||||
// No need to keep the entry if there are no visible activities.
|
||||
mPackageUidToCompatStateInfo.remove(packageUid);
|
||||
}
|
||||
}
|
||||
|
||||
if (state == lastLoggedState) {
|
||||
// We don’t want to log the same state twice or log DEFAULT_NOT_VISIBLE before any
|
||||
// visible state was logged.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isVisible && !visibleActivities.isEmpty()) {
|
||||
// There is another visible activity for this package UID.
|
||||
if (activity == lastLoggedActivity) {
|
||||
// Make sure a new visible state is logged if needed.
|
||||
findAppCompatStateToLog(compatStateInfo, packageUid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (activity != lastLoggedActivity
|
||||
&& lastLoggedState != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE
|
||||
&& lastLoggedState != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED) {
|
||||
// Another visible activity for this package UID has logged a letterboxed state.
|
||||
return;
|
||||
}
|
||||
|
||||
logAppCompatStateInternal(activity, state, packageUid, compatStateInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for the first visible activity in {@code compatStateInfo} that has a letterboxed
|
||||
* state, or a non-letterboxed state if there isn't one, and logs that state for the given
|
||||
* {@code packageUid}.
|
||||
*/
|
||||
private void findAppCompatStateToLog(PackageCompatStateInfo compatStateInfo, int packageUid) {
|
||||
final ArrayList<ActivityRecord> visibleActivities = compatStateInfo.mVisibleActivities;
|
||||
|
||||
ActivityRecord activityToLog = null;
|
||||
int stateToLog = APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
|
||||
for (int i = 0; i < visibleActivities.size(); i++) {
|
||||
ActivityRecord activity = visibleActivities.get(i);
|
||||
int state = activity.getAppCompatState();
|
||||
if (state == APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE) {
|
||||
// This shouldn't happen.
|
||||
Slog.w(TAG, "Visible activity with NOT_VISIBLE App Compat state for package UID: "
|
||||
+ packageUid);
|
||||
continue;
|
||||
}
|
||||
if (stateToLog == APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE || (
|
||||
stateToLog == APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED
|
||||
&& state != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED)) {
|
||||
activityToLog = activity;
|
||||
stateToLog = state;
|
||||
}
|
||||
}
|
||||
if (activityToLog != null && stateToLog != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE) {
|
||||
logAppCompatStateInternal(activityToLog, stateToLog, packageUid, compatStateInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private void logAppCompatStateInternal(@NonNull ActivityRecord activity, int state,
|
||||
int packageUid, PackageCompatStateInfo compatStateInfo) {
|
||||
compatStateInfo.mLastLoggedState = state;
|
||||
compatStateInfo.mLastLoggedActivity = activity;
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPAT_STATE_CHANGED, packageUid, state);
|
||||
|
||||
if (DEBUG_METRICS) {
|
||||
Slog.i(TAG, String.format("APP_COMPAT_STATE_CHANGED(%s, %s)", packageUid, state));
|
||||
}
|
||||
}
|
||||
|
||||
private ArtManagerInternal getArtManagerInternal() {
|
||||
if (mArtManagerInternal == null) {
|
||||
// Note that this may be null.
|
||||
|
||||
@@ -127,6 +127,11 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
|
||||
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
|
||||
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
|
||||
import static com.android.server.wm.ActivityRecord.State.DESTROYED;
|
||||
@@ -4659,6 +4664,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED);
|
||||
mTaskSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
|
||||
mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
|
||||
logAppCompatState();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -7396,6 +7402,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
}
|
||||
resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
|
||||
}
|
||||
|
||||
logAppCompatState();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7405,18 +7413,55 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
* LetterboxUiController#shouldShowLetterboxUi} for more context.
|
||||
*/
|
||||
boolean areBoundsLetterboxed() {
|
||||
return getAppCompatState(/* ignoreVisibility= */ true)
|
||||
!= APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the current App Compat state via {@link ActivityMetricsLogger#logAppCompatState}.
|
||||
*/
|
||||
private void logAppCompatState() {
|
||||
mTaskSupervisor.getActivityMetricsLogger().logAppCompatState(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current App Compat state of this activity.
|
||||
*
|
||||
* <p>The App Compat state indicates whether the activity is visible and letterboxed, and if so
|
||||
* what is the reason for letterboxing. The state is used for logging the time spent in
|
||||
* letterbox (sliced by the reason) vs non-letterbox per app.
|
||||
*/
|
||||
int getAppCompatState() {
|
||||
return getAppCompatState(/* ignoreVisibility= */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #getAppCompatState()} except when {@code ignoreVisibility} the visibility
|
||||
* of the activity is ignored.
|
||||
*
|
||||
* @param ignoreVisibility whether to ignore the visibility of the activity and not return
|
||||
* NOT_VISIBLE if {@code mVisibleRequested} is false.
|
||||
*/
|
||||
private int getAppCompatState(boolean ignoreVisibility) {
|
||||
if (!ignoreVisibility && !mVisibleRequested) {
|
||||
return APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
|
||||
}
|
||||
if (mInSizeCompatModeForBounds) {
|
||||
return true;
|
||||
return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
|
||||
}
|
||||
// Letterbox for fixed orientation. This check returns true only when an activity is
|
||||
// letterboxed for fixed orientation. Aspect ratio restrictions are also applied if
|
||||
// present. But this doesn't return true when the activity is letterboxed only because
|
||||
// of aspect ratio restrictions.
|
||||
if (isLetterboxedForFixedOrientationAndAspectRatio()) {
|
||||
return true;
|
||||
return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
|
||||
}
|
||||
// Letterbox for limited aspect ratio.
|
||||
return mIsAspectRatioApplied;
|
||||
if (mIsAspectRatioApplied) {
|
||||
return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
|
||||
}
|
||||
|
||||
return APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,11 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
|
||||
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
|
||||
import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
|
||||
import static com.android.server.wm.ActivityRecord.State.RESUMED;
|
||||
import static com.android.server.wm.ActivityRecord.State.STOPPED;
|
||||
@@ -55,7 +60,9 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.same;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.doCallRealMethod;
|
||||
|
||||
@@ -101,10 +108,14 @@ public class SizeCompatTests extends WindowTestsBase {
|
||||
|
||||
private Task mTask;
|
||||
private ActivityRecord mActivity;
|
||||
private ActivityMetricsLogger mActivityMetricsLogger;
|
||||
private Properties mInitialConstrainDisplayApisFlags;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
|
||||
clearInvocations(mActivityMetricsLogger);
|
||||
doReturn(mActivityMetricsLogger).when(mAtm.mTaskSupervisor).getActivityMetricsLogger();
|
||||
mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties(
|
||||
NAMESPACE_CONSTRAIN_DISPLAY_APIS);
|
||||
DeviceConfig.setProperties(
|
||||
@@ -1939,13 +1950,19 @@ public class SizeCompatTests extends WindowTestsBase {
|
||||
setUpDisplaySizeWithApp(1000, 2500);
|
||||
|
||||
assertFalse(mActivity.areBoundsLetterboxed());
|
||||
verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
|
||||
|
||||
prepareUnresizable(mActivity, /* maxAspect= */ 2, SCREEN_ORIENTATION_PORTRAIT);
|
||||
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
|
||||
assertFalse(mActivity.inSizeCompatMode());
|
||||
assertTrue(mActivity.areBoundsLetterboxed());
|
||||
|
||||
verifyLogAppCompatState(mActivity,
|
||||
APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO);
|
||||
|
||||
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
|
||||
verifyLogAppCompatState(mActivity,
|
||||
APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE);
|
||||
rotateDisplay(mActivity.mDisplayContent, ROTATION_0);
|
||||
|
||||
// After returning to the original rotation, bounds are computed in
|
||||
@@ -1955,6 +1972,18 @@ public class SizeCompatTests extends WindowTestsBase {
|
||||
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
|
||||
assertFalse(mActivity.inSizeCompatMode());
|
||||
assertTrue(mActivity.areBoundsLetterboxed());
|
||||
verifyLogAppCompatState(mActivity,
|
||||
APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO);
|
||||
|
||||
// After setting the visibility of the activity to false, areBoundsLetterboxed() still
|
||||
// returns true but the NOT_VISIBLE App Compat state is logged.
|
||||
mActivity.setVisibility(false);
|
||||
assertTrue(mActivity.areBoundsLetterboxed());
|
||||
verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE);
|
||||
mActivity.setVisibility(true);
|
||||
assertTrue(mActivity.areBoundsLetterboxed());
|
||||
verifyLogAppCompatState(mActivity,
|
||||
APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1963,12 +1992,15 @@ public class SizeCompatTests extends WindowTestsBase {
|
||||
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
|
||||
|
||||
assertFalse(mActivity.areBoundsLetterboxed());
|
||||
verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
|
||||
|
||||
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
|
||||
|
||||
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
|
||||
assertFalse(mActivity.inSizeCompatMode());
|
||||
assertTrue(mActivity.areBoundsLetterboxed());
|
||||
verifyLogAppCompatState(mActivity,
|
||||
APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1978,12 +2010,15 @@ public class SizeCompatTests extends WindowTestsBase {
|
||||
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
|
||||
|
||||
assertFalse(mActivity.areBoundsLetterboxed());
|
||||
verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
|
||||
|
||||
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
|
||||
|
||||
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
|
||||
assertTrue(mActivity.inSizeCompatMode());
|
||||
assertTrue(mActivity.areBoundsLetterboxed());
|
||||
verifyLogAppCompatState(mActivity,
|
||||
APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2197,6 +2232,11 @@ public class SizeCompatTests extends WindowTestsBase {
|
||||
.isEqualTo(activity.getWindowConfiguration().getBounds());
|
||||
}
|
||||
|
||||
private void verifyLogAppCompatState(ActivityRecord activity, int state) {
|
||||
verify(mActivityMetricsLogger, atLeastOnce()).logAppCompatState(
|
||||
argThat(r -> activity == r && r.getAppCompatState() == state));
|
||||
}
|
||||
|
||||
static Configuration rotateDisplay(DisplayContent display, int rotation) {
|
||||
final Configuration c = new Configuration();
|
||||
display.getDisplayRotation().setRotation(rotation);
|
||||
|
||||
Reference in New Issue
Block a user