blob: 836e6b617395417d66a31eb434e0f8c4e3b64579 [file] [log] [blame]
Riddle Hsu5ef56dd62019-07-26 21:28:51 -06001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.wm;
18
Riddle Hsuf5622d22019-09-24 17:56:05 -060019import static android.perftests.utils.ManualBenchmarkState.StatsReport;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060020
21import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
22
23import static org.hamcrest.core.AnyOf.anyOf;
24import static org.hamcrest.core.Is.is;
25
Tracy Zhou8089ffa2019-07-30 17:30:43 -070026import android.app.ActivityManager.TaskSnapshot;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060027import android.app.ActivityTaskManager;
28import android.app.IActivityTaskManager;
29import android.content.ComponentName;
30import android.content.Context;
31import android.content.Intent;
32import android.content.pm.PackageManager;
33import android.graphics.Rect;
34import android.os.RemoteException;
35import android.os.SystemClock;
36import android.perftests.utils.ManualBenchmarkState;
37import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest;
38import android.perftests.utils.PerfManualStatusReporter;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060039import android.util.Pair;
40import android.view.IRecentsAnimationController;
41import android.view.IRecentsAnimationRunner;
42import android.view.RemoteAnimationTarget;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060043
44import androidx.test.filters.LargeTest;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060045import androidx.test.runner.lifecycle.Stage;
46
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060047import org.junit.AfterClass;
48import org.junit.Assume;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060049import org.junit.BeforeClass;
50import org.junit.Rule;
51import org.junit.Test;
52import org.junit.runner.RunWith;
53import org.junit.runners.Parameterized;
54
55import java.util.ArrayList;
56import java.util.Arrays;
57import java.util.Collection;
58import java.util.concurrent.Semaphore;
59import java.util.concurrent.TimeUnit;
60
61@RunWith(Parameterized.class)
62@LargeTest
63public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
64 private static Intent sRecentsIntent;
65
66 @Rule
67 public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
68
69 @Rule
Riddle Hsuf5622d22019-09-24 17:56:05 -060070 public final PerfTestActivityRule mActivityRule =
71 new PerfTestActivityRule(true /* launchActivity */);
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060072
73 private long mMeasuredTimeNs;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060074
75 @Parameterized.Parameter(0)
76 public int intervalBetweenOperations;
77
78 @Parameterized.Parameters(name = "interval{0}ms")
79 public static Collection<Object[]> getParameters() {
80 return Arrays.asList(new Object[][] {
81 { 0 },
82 { 100 },
83 { 300 },
84 });
85 }
86
87 @BeforeClass
88 public static void setUpClass() {
89 // Get the permission to invoke startRecentsActivity.
90 sUiAutomation.adoptShellPermissionIdentity();
91
92 final Context context = getInstrumentation().getContext();
93 final PackageManager pm = context.getPackageManager();
94 final ComponentName defaultHome = pm.getHomeActivities(new ArrayList<>());
95
96 try {
97 final ComponentName recentsComponent =
98 ComponentName.unflattenFromString(context.getResources().getString(
99 com.android.internal.R.string.config_recentsComponentName));
100 final int enabledState = pm.getComponentEnabledSetting(recentsComponent);
101 Assume.assumeThat(enabledState, anyOf(
102 is(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
103 is(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)));
104
105 final boolean homeIsRecents =
106 recentsComponent.getPackageName().equals(defaultHome.getPackageName());
107 sRecentsIntent =
108 new Intent().setComponent(homeIsRecents ? defaultHome : recentsComponent);
109 } catch (Exception e) {
110 Assume.assumeNoException(e);
111 }
112 }
113
114 @AfterClass
115 public static void tearDownClass() {
116 sUiAutomation.dropShellPermissionIdentity();
117 }
118
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600119 /** Simulate the timing of touch. */
120 private void makeInterval() {
121 SystemClock.sleep(intervalBetweenOperations);
122 }
123
124 /**
125 * <pre>
126 * Steps:
127 * (1) Start recents activity (only make it visible).
128 * (2) Finish animation, take turns to execute (a), (b).
129 * (a) Move recents activity to top.
130 * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_TOP})
131 * Move test app to top by startActivityFromRecents.
132 * (b) Cancel (it is similar to swipe a little distance and give up to enter recents).
133 * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_ORIGINAL_POSITION})
134 * (3) Loop (1).
135 * </pre>
136 */
137 @Test
138 @ManualBenchmarkTest(
139 warmupDurationNs = TIME_1_S_IN_NS,
140 targetTestDurationNs = TIME_5_S_IN_NS,
Riddle Hsuf5622d22019-09-24 17:56:05 -0600141 statsReport = @StatsReport(flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
142 | StatsReport.FLAG_COEFFICIENT_VAR))
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600143 public void testRecentsAnimation() throws Throwable {
144 final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
145 final IActivityTaskManager atm = ActivityTaskManager.getService();
146
147 final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>();
148 // Real launch the recents activity.
149 finishCases.add(new Pair<>("finishMoveToTop", true));
150 // Return to the original top.
151 finishCases.add(new Pair<>("finishCancel", false));
152
153 // Ensure startRecentsActivity won't be called before finishing the animation.
154 final Semaphore recentsSemaphore = new Semaphore(1);
155
156 final int testActivityTaskId = mActivityRule.getActivity().getTaskId();
157 final IRecentsAnimationRunner.Stub anim = new IRecentsAnimationRunner.Stub() {
158 int mIteration;
159
160 @Override
161 public void onAnimationStart(IRecentsAnimationController controller,
Winson Chungd5852192019-09-06 17:20:28 -0700162 RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
163 Rect homeContentInsets, Rect minimizedHomeBounds) throws RemoteException {
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600164 final Pair<String, Boolean> finishCase = finishCases.get(mIteration++ % 2);
165 final boolean moveRecentsToTop = finishCase.second;
166 makeInterval();
167
168 long startTime = SystemClock.elapsedRealtimeNanos();
169 controller.finish(moveRecentsToTop, false /* sendUserLeaveHint */);
170 final long elapsedTimeNsOfFinish = SystemClock.elapsedRealtimeNanos() - startTime;
171 mMeasuredTimeNs += elapsedTimeNsOfFinish;
172 state.addExtraResult(finishCase.first, elapsedTimeNsOfFinish);
173
174 if (moveRecentsToTop) {
Riddle Hsuf5622d22019-09-24 17:56:05 -0600175 mActivityRule.waitForIdleSync(Stage.STOPPED);
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600176
177 startTime = SystemClock.elapsedRealtimeNanos();
178 atm.startActivityFromRecents(testActivityTaskId, null /* options */);
179 final long elapsedTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
180 mMeasuredTimeNs += elapsedTimeNs;
181 state.addExtraResult("startFromRecents", elapsedTimeNs);
182
Riddle Hsuf5622d22019-09-24 17:56:05 -0600183 mActivityRule.waitForIdleSync(Stage.RESUMED);
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600184 }
185
186 makeInterval();
187 recentsSemaphore.release();
188 }
189
190 @Override
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700191 public void onAnimationCanceled(TaskSnapshot taskSnapshot) throws RemoteException {
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600192 Assume.assumeNoException(
193 new AssertionError("onAnimationCanceled should not be called"));
194 }
lumark04bceb92020-03-07 00:03:33 +0800195
196 @Override
197 public void onTaskAppeared(RemoteAnimationTarget app) throws RemoteException {
198 /* no-op */
199 }
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600200 };
201
Riddle Hsuf5622d22019-09-24 17:56:05 -0600202 recentsSemaphore.tryAcquire();
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600203 while (state.keepRunning(mMeasuredTimeNs)) {
Riddle Hsuf5622d22019-09-24 17:56:05 -0600204 mMeasuredTimeNs = 0;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600205
206 final long startTime = SystemClock.elapsedRealtimeNanos();
207 atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim);
208 final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime;
209 mMeasuredTimeNs += elapsedTimeNsOfStart;
210 state.addExtraResult("start", elapsedTimeNsOfStart);
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600211
Riddle Hsuf5622d22019-09-24 17:56:05 -0600212 // Ensure the animation callback is done.
213 Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS));
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600214 }
215 }
216}