1 /*
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 
17 package android.server.wm;
18 
19 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
21 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
22 import static android.view.Display.DEFAULT_DISPLAY;
23 
24 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
25 
26 import static org.junit.Assert.assertEquals;
27 
28 import android.app.Activity;
29 import android.app.ActivityOptions;
30 import android.content.Intent;
31 import android.os.Bundle;
32 
33 import com.android.compatibility.common.util.SystemUtil;
34 
35 import java.lang.reflect.Array;
36 
37 import javax.annotation.concurrent.GuardedBy;
38 
39 public class WindowManagerTestBase extends MultiDisplayTestBase {
40     static final long TIMEOUT_WINDOW_FOCUS_CHANGED = 1000; // milliseconds
41 
startActivity(Class<T> cls)42     static <T extends FocusableActivity> T startActivity(Class<T> cls) {
43         return startActivity(cls, DEFAULT_DISPLAY);
44     }
45 
startActivity(Class<T> cls, int displayId)46     static <T extends FocusableActivity> T startActivity(Class<T> cls, int displayId) {
47         return startActivity(cls, displayId, true /* hasFocus */);
48     }
49 
startActivity( Class<T> cls, int displayId, boolean hasFocus)50     static <T extends FocusableActivity> T startActivity(
51             Class<T> cls, int displayId, boolean hasFocus) {
52         return startActivity(cls, displayId, hasFocus, WINDOWING_MODE_UNDEFINED);
53     }
54 
startActivityInWindowingMode( Class<T> cls, int windowingMode)55     static <T extends FocusableActivity> T startActivityInWindowingMode(
56             Class<T> cls, int windowingMode) {
57         return startActivity(cls, DEFAULT_DISPLAY, true /* hasFocus */, windowingMode);
58     }
59 
startActivityInWindowingModeFullScreen( Class<T> cls)60     static <T extends FocusableActivity> T startActivityInWindowingModeFullScreen(
61             Class<T> cls) {
62         return startActivity(cls, DEFAULT_DISPLAY, true /* hasFocus */, WINDOWING_MODE_FULLSCREEN);
63     }
64 
startActivity(Class<T> cls, int displayId, boolean hasFocus, int windowingMode)65     static <T extends FocusableActivity> T startActivity(Class<T> cls, int displayId,
66             boolean hasFocus, int windowingMode) {
67         final Bundle options;
68         if (displayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_UNDEFINED) {
69             options = null;
70         } else {
71             final ActivityOptions ap= ActivityOptions.makeBasic();
72             if (displayId != DEFAULT_DISPLAY) ap.setLaunchDisplayId(displayId);
73             if (windowingMode != WINDOWING_MODE_UNDEFINED) ap.setLaunchWindowingMode(windowingMode);
74             options = ap.toBundle();
75         }
76         final T[] activity = (T[]) Array.newInstance(FocusableActivity.class, 1);
77         SystemUtil.runWithShellPermissionIdentity(() -> {
78             activity[0] = (T) getInstrumentation().startActivitySync(
79                     new Intent(getInstrumentation().getTargetContext(), cls)
80                             .addFlags(FLAG_ACTIVITY_NEW_TASK), options);
81             activity[0].waitAndAssertWindowFocusState(hasFocus);
82         });
83         return activity[0];
84     }
85 
86     static class FocusableActivity extends Activity {
87         private final Object mLockWindowFocus = new Object();
88 
89         @GuardedBy("mLockWindowFocus")
90         private boolean mHasWindowFocus;
91 
getLogTag()92         final String getLogTag() {
93             return ComponentNameUtils.getLogTag(getComponentName());
94         }
95 
96         @Override
onWindowFocusChanged(boolean hasFocus)97         public void onWindowFocusChanged(boolean hasFocus) {
98             synchronized (mLockWindowFocus) {
99                 mHasWindowFocus = hasFocus;
100                 mLockWindowFocus.notify();
101             }
102         }
103 
assertWindowFocusState(boolean hasFocus)104         void assertWindowFocusState(boolean hasFocus) {
105             synchronized (mLockWindowFocus) {
106                 assertEquals(getLogTag() + " must" + (hasFocus ? "" : " not")
107                         + " have window focus.", hasFocus, mHasWindowFocus);
108             }
109         }
110 
waitAndAssertWindowFocusState(boolean hasFocus)111         void waitAndAssertWindowFocusState(boolean hasFocus) {
112             synchronized (mLockWindowFocus) {
113                 if (mHasWindowFocus != hasFocus) {
114                     try {
115                         mLockWindowFocus.wait(TIMEOUT_WINDOW_FOCUS_CHANGED);
116                     } catch (InterruptedException e) {
117                     }
118                 }
119             }
120             assertWindowFocusState(hasFocus);
121         }
122     }
123 }
124