1 /*
2  * Copyright (C) 2022 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 
17 package com.android.quickstep;
18 
19 import static androidx.test.InstrumentationRegistry.getInstrumentation;
20 
21 import static com.android.quickstep.TaskbarModeSwitchRule.Mode.ALL;
22 import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
23 import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
24 
25 import android.content.Context;
26 import android.util.Log;
27 
28 import com.android.launcher3.tapl.LauncherInstrumentation;
29 import com.android.launcher3.tapl.TestHelpers;
30 import com.android.launcher3.ui.AbstractLauncherUiTest;
31 import com.android.launcher3.util.DisplayController;
32 import com.android.launcher3.util.rule.FailureWatcher;
33 
34 import org.junit.rules.TestRule;
35 import org.junit.runner.Description;
36 import org.junit.runners.model.Statement;
37 
38 import java.lang.annotation.ElementType;
39 import java.lang.annotation.Retention;
40 import java.lang.annotation.RetentionPolicy;
41 import java.lang.annotation.Target;
42 
43 /**
44  * Test rule that allows executing a test multiple times with different conditions
45  * ie. with transient taskbar enabled and disabled.
46  * The test should be annotated with @TaskbarModeSwitch.
47  */
48 public class TaskbarModeSwitchRule implements TestRule {
49 
50     static final String TAG = "TaskbarModeSwitchRule";
51 
52     public static final int WAIT_TIME_MS = 10000;
53 
54     public enum Mode {
55         TRANSIENT, PERSISTENT, ALL
56     }
57 
58     // Annotation for tests that need to be run with quickstep enabled and disabled.
59     @Retention(RetentionPolicy.RUNTIME)
60     @Target(ElementType.METHOD)
61     public @interface TaskbarModeSwitch {
mode()62         Mode mode() default ALL;
63     }
64 
65     private final LauncherInstrumentation mLauncher;
66 
TaskbarModeSwitchRule(LauncherInstrumentation launcher)67     public TaskbarModeSwitchRule(LauncherInstrumentation launcher) {
68         mLauncher = launcher;
69     }
70 
71     @Override
apply(Statement base, Description description)72     public Statement apply(Statement base, Description description) {
73         if (TestHelpers.isInLauncherProcess()
74                 && description.getAnnotation(TaskbarModeSwitch.class) != null) {
75             Mode mode = description.getAnnotation(TaskbarModeSwitch.class).mode();
76             return new Statement() {
77                 @Override
78                 public void evaluate() throws Throwable {
79                     mLauncher.enableDebugTracing();
80                     final boolean wasTransientTaskbarMode =
81                             isTaskbarTransientMode(getInstrumentation().getTargetContext());
82                     try {
83                         if (mode == TRANSIENT || mode == ALL) {
84                             evaluateWithTransientTaskbar();
85                         }
86                         if (mode == PERSISTENT || mode == ALL) {
87                             evaluateWithPersistentTaskbar();
88                         }
89                     } catch (Throwable e) {
90                         Log.e(TAG, "Error", e);
91                         throw e;
92                     } finally {
93                         Log.d(TAG, "In Finally block");
94                         setTaskbarMode(mLauncher, wasTransientTaskbarMode, description);
95                     }
96                 }
97 
98                 private void evaluateWithPersistentTaskbar() throws Throwable {
99                     setTaskbarMode(mLauncher, false, description);
100                     base.evaluate();
101                 }
102 
103                 private void evaluateWithTransientTaskbar() throws Throwable {
104                     setTaskbarMode(mLauncher, true, description);
105                     base.evaluate();
106                 }
107             };
108         } else {
109             return base;
110         }
111     }
112 
113     private static boolean isTaskbarTransientMode(Context context) {
114         return DisplayController.isTransientTaskbar(context);
115     }
116 
117     public static void setTaskbarMode(LauncherInstrumentation launcher,
118             boolean expectTransientTaskbar, Description description) throws Exception {
119         launcher.enableTransientTaskbar(expectTransientTaskbar);
120         launcher.recreateTaskbar();
121 
122         Context context = getInstrumentation().getTargetContext();
123         assertTrue(launcher, "Couldn't set taskbar=" + expectTransientTaskbar,
124                 isTaskbarTransientMode(context) == expectTransientTaskbar, description);
125 
126         AbstractLauncherUiTest.checkDetectedLeaks(launcher, true);
127     }
128 
129     private static void assertTrue(LauncherInstrumentation launcher, String message,
130             boolean condition, Description description) {
131         launcher.checkForAnomaly(true, true);
132         if (!condition) {
133             if (description != null) {
134                 FailureWatcher.onError(launcher, description);
135             }
136             throw new AssertionError(message);
137         }
138     }
139 }
140