blob: 1667c1658a0704adca47d236ec86b1d2b4b11a05 [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 Hsub078bc12020-05-04 21:58:50 +080049import org.junit.Before;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060050import org.junit.BeforeClass;
51import org.junit.Rule;
52import org.junit.Test;
53import org.junit.runner.RunWith;
54import org.junit.runners.Parameterized;
55
56import java.util.ArrayList;
57import java.util.Arrays;
58import java.util.Collection;
59import java.util.concurrent.Semaphore;
60import java.util.concurrent.TimeUnit;
61
62@RunWith(Parameterized.class)
63@LargeTest
64public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
65 private static Intent sRecentsIntent;
66
67 @Rule
68 public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
69
70 @Rule
Riddle Hsuf5622d22019-09-24 17:56:05 -060071 public final PerfTestActivityRule mActivityRule =
72 new PerfTestActivityRule(true /* launchActivity */);
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060073
74 private long mMeasuredTimeNs;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060075
Riddle Hsub078bc12020-05-04 21:58:50 +080076 /**
77 * Used to skip each test method if there is error. It cannot be raised in static setup because
78 * that will break the amount of target method count.
79 */
80 private static Exception sSetUpClassException;
81
Riddle Hsu5ef56dd62019-07-26 21:28:51 -060082 @Parameterized.Parameter(0)
83 public int intervalBetweenOperations;
84
85 @Parameterized.Parameters(name = "interval{0}ms")
86 public static Collection<Object[]> getParameters() {
87 return Arrays.asList(new Object[][] {
88 { 0 },
89 { 100 },
90 { 300 },
91 });
92 }
93
94 @BeforeClass
95 public static void setUpClass() {
96 // Get the permission to invoke startRecentsActivity.
97 sUiAutomation.adoptShellPermissionIdentity();
98
99 final Context context = getInstrumentation().getContext();
100 final PackageManager pm = context.getPackageManager();
101 final ComponentName defaultHome = pm.getHomeActivities(new ArrayList<>());
102
103 try {
104 final ComponentName recentsComponent =
105 ComponentName.unflattenFromString(context.getResources().getString(
106 com.android.internal.R.string.config_recentsComponentName));
107 final int enabledState = pm.getComponentEnabledSetting(recentsComponent);
108 Assume.assumeThat(enabledState, anyOf(
109 is(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
110 is(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)));
111
112 final boolean homeIsRecents =
113 recentsComponent.getPackageName().equals(defaultHome.getPackageName());
114 sRecentsIntent =
115 new Intent().setComponent(homeIsRecents ? defaultHome : recentsComponent);
116 } catch (Exception e) {
Riddle Hsub078bc12020-05-04 21:58:50 +0800117 sSetUpClassException = e;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600118 }
119 }
120
121 @AfterClass
122 public static void tearDownClass() {
Riddle Hsub078bc12020-05-04 21:58:50 +0800123 sSetUpClassException = null;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600124 sUiAutomation.dropShellPermissionIdentity();
125 }
126
Riddle Hsub078bc12020-05-04 21:58:50 +0800127 @Before
128 public void setUp() {
129 Assume.assumeNoException(sSetUpClassException);
130 }
131
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600132 /** Simulate the timing of touch. */
133 private void makeInterval() {
134 SystemClock.sleep(intervalBetweenOperations);
135 }
136
137 /**
138 * <pre>
139 * Steps:
140 * (1) Start recents activity (only make it visible).
141 * (2) Finish animation, take turns to execute (a), (b).
142 * (a) Move recents activity to top.
143 * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_TOP})
144 * Move test app to top by startActivityFromRecents.
145 * (b) Cancel (it is similar to swipe a little distance and give up to enter recents).
146 * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_ORIGINAL_POSITION})
147 * (3) Loop (1).
148 * </pre>
149 */
150 @Test
151 @ManualBenchmarkTest(
152 warmupDurationNs = TIME_1_S_IN_NS,
153 targetTestDurationNs = TIME_5_S_IN_NS,
Riddle Hsuf5622d22019-09-24 17:56:05 -0600154 statsReport = @StatsReport(flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
155 | StatsReport.FLAG_COEFFICIENT_VAR))
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600156 public void testRecentsAnimation() throws Throwable {
157 final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
158 final IActivityTaskManager atm = ActivityTaskManager.getService();
159
160 final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>();
161 // Real launch the recents activity.
162 finishCases.add(new Pair<>("finishMoveToTop", true));
163 // Return to the original top.
164 finishCases.add(new Pair<>("finishCancel", false));
165
166 // Ensure startRecentsActivity won't be called before finishing the animation.
167 final Semaphore recentsSemaphore = new Semaphore(1);
168
169 final int testActivityTaskId = mActivityRule.getActivity().getTaskId();
170 final IRecentsAnimationRunner.Stub anim = new IRecentsAnimationRunner.Stub() {
171 int mIteration;
172
173 @Override
174 public void onAnimationStart(IRecentsAnimationController controller,
Winson Chungd5852192019-09-06 17:20:28 -0700175 RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
176 Rect homeContentInsets, Rect minimizedHomeBounds) throws RemoteException {
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600177 final Pair<String, Boolean> finishCase = finishCases.get(mIteration++ % 2);
178 final boolean moveRecentsToTop = finishCase.second;
179 makeInterval();
180
181 long startTime = SystemClock.elapsedRealtimeNanos();
182 controller.finish(moveRecentsToTop, false /* sendUserLeaveHint */);
183 final long elapsedTimeNsOfFinish = SystemClock.elapsedRealtimeNanos() - startTime;
184 mMeasuredTimeNs += elapsedTimeNsOfFinish;
185 state.addExtraResult(finishCase.first, elapsedTimeNsOfFinish);
186
187 if (moveRecentsToTop) {
Riddle Hsuf5622d22019-09-24 17:56:05 -0600188 mActivityRule.waitForIdleSync(Stage.STOPPED);
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600189
190 startTime = SystemClock.elapsedRealtimeNanos();
191 atm.startActivityFromRecents(testActivityTaskId, null /* options */);
192 final long elapsedTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
193 mMeasuredTimeNs += elapsedTimeNs;
194 state.addExtraResult("startFromRecents", elapsedTimeNs);
195
Riddle Hsuf5622d22019-09-24 17:56:05 -0600196 mActivityRule.waitForIdleSync(Stage.RESUMED);
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600197 }
198
199 makeInterval();
200 recentsSemaphore.release();
201 }
202
203 @Override
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700204 public void onAnimationCanceled(TaskSnapshot taskSnapshot) throws RemoteException {
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600205 Assume.assumeNoException(
206 new AssertionError("onAnimationCanceled should not be called"));
207 }
lumark04bceb92020-03-07 00:03:33 +0800208
209 @Override
210 public void onTaskAppeared(RemoteAnimationTarget app) throws RemoteException {
211 /* no-op */
212 }
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600213 };
214
Riddle Hsuf5622d22019-09-24 17:56:05 -0600215 recentsSemaphore.tryAcquire();
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600216 while (state.keepRunning(mMeasuredTimeNs)) {
Riddle Hsuf5622d22019-09-24 17:56:05 -0600217 mMeasuredTimeNs = 0;
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600218
219 final long startTime = SystemClock.elapsedRealtimeNanos();
220 atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim);
221 final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime;
222 mMeasuredTimeNs += elapsedTimeNsOfStart;
223 state.addExtraResult("start", elapsedTimeNsOfStart);
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600224
Riddle Hsuf5622d22019-09-24 17:56:05 -0600225 // Ensure the animation callback is done.
226 Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS));
Riddle Hsu5ef56dd62019-07-26 21:28:51 -0600227 }
228 }
229}