• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
22 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
25 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
26 import static android.server.wm.RoundedCornerTests.TestActivity.EXTRA_ORIENTATION;
27 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
28 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
29 
30 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
31 
32 import static org.junit.Assert.assertEquals;
33 import static org.junit.Assert.assertNotNull;
34 import static org.junit.Assert.assertTrue;
35 import static org.junit.Assume.assumeFalse;
36 
37 import android.app.Activity;
38 import android.content.Intent;
39 import android.graphics.Rect;
40 import android.os.Bundle;
41 import android.platform.test.annotations.Presubmit;
42 import android.view.Gravity;
43 import android.view.View;
44 import android.view.Window;
45 import android.view.WindowInsets;
46 import android.view.WindowManager;
47 import android.view.WindowMetrics;
48 
49 import androidx.test.rule.ActivityTestRule;
50 
51 import com.android.compatibility.common.util.PollingCheck;
52 
53 import org.junit.Rule;
54 import org.junit.Test;
55 import org.junit.runner.RunWith;
56 import org.junit.runners.Parameterized;
57 
58 @Presubmit
59 @RunWith(Parameterized.class)
60 public class PrivacyIndicatorBoundsTests extends ActivityManagerTestBase {
61 
62     private static final String TAG = PrivacyIndicatorBoundsTests.class.getSimpleName();
63     private static final long TIMEOUT_MS = 1000;
64 
65     @Parameterized.Parameters(name= "{1}({0})")
data()66     public static Object[][] data() {
67         return new Object[][]{
68                 {SCREEN_ORIENTATION_PORTRAIT, "SCREEN_ORIENTATION_PORTRAIT"},
69                 {SCREEN_ORIENTATION_LANDSCAPE, "SCREEN_ORIENTATION_LANDSCAPE"},
70                 {SCREEN_ORIENTATION_REVERSE_LANDSCAPE, "SCREEN_ORIENTATION_REVERSE_LANDSCAPE"},
71                 {SCREEN_ORIENTATION_REVERSE_PORTRAIT, "SCREEN_ORIENTATION_REVERSE_PORTRAIT"},
72         };
73     }
74 
75     @Parameterized.Parameter(0)
76     public int orientation;
77 
78     @Parameterized.Parameter(1)
79     public String orientationName;
80 
81     @Rule
82     public final ActivityTestRule<TestActivity> mTestActivity =
83             new ActivityTestRule<>(TestActivity.class, false /* initialTouchMode */,
84                     false /* launchActivity */);
85 
86 
87     @Test
testStaticBoundsAreNotNull()88     public void testStaticBoundsAreNotNull() {
89         // TODO(b/187757919): Allow Automotive to skip this test until privacy chip is implemented
90         // in immersive mode
91         assumeFalse(isCar());
92         assumeFalse(isWatch());
93 
94         final PrivacyIndicatorBoundsTests.TestActivity activity = mTestActivity.launchActivity(
95                 new Intent().putExtra(EXTRA_ORIENTATION, orientation));
96         getInstrumentation().runOnMainSync(() -> {
97             activity.addChildWindow();
98         });
99 
100         final View childWindowRoot = activity.getChildWindowRoot();
101         PollingCheck.waitFor(TIMEOUT_MS, () -> childWindowRoot.getWidth() > 0);
102         PollingCheck.waitFor(TIMEOUT_MS, () -> activity.getDispatchedInsets() != null);
103         mWmState.waitForValidState(mTestActivity.getActivity().getComponentName());
104         WindowInsets insets = activity.getDispatchedInsets();
105         assertNotNull(insets);
106         Rect screenBounds = activity.getScreenBounds();
107         assertNotNull(screenBounds);
108         Rect bounds = insets.getPrivacyIndicatorBounds();
109         assertNotNull(bounds);
110         final int windowingMode = mWmState
111                 .getTaskDisplayArea(mTestActivity.getActivity().getComponentName())
112                 .getWindowingMode();
113         final boolean inMultiWindowMode = windowingMode != WINDOWING_MODE_FULLSCREEN
114                 && windowingMode != WINDOWING_MODE_UNDEFINED;
115         if (!inMultiWindowMode) {
116             // Multi-window environments may place the indicator bounds somewhere other than the
117             // top (e.g. desktops may decide that the bottom-right corner has the highest visual
118             // priority). Other windowing modes
119             assertEquals(bounds.top, 0);
120         }
121         // TODO 188788786: Figure out why the screen bounds are different in cuttlefish,
122         // causing failures
123         // assertTrue(bounds + " not contained in " + screenBounds, screenBounds.contains(bounds));
124         assertTrue(bounds.left >= 0);
125         assertTrue(bounds.right >= 0);
126     }
127 
128     public static class TestActivity extends Activity {
129         static final String EXTRA_ORIENTATION = "extra.orientation";
130 
131         private View mChildWindowRoot;
132         private WindowInsets mDispatchedInsets;
133         private Rect mScreenBounds = null;
134 
135         @Override
onCreate(Bundle savedInstanceState)136         protected void onCreate(Bundle savedInstanceState) {
137             super.onCreate(savedInstanceState);
138             getWindow().requestFeature(Window.FEATURE_NO_TITLE);
139             getWindow().getDecorView().getWindowInsetsController().hide(
140                     android.view.WindowInsets.Type.statusBars());
141             getWindow().getAttributes().layoutInDisplayCutoutMode =
142                     LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
143             if (getIntent() != null) {
144                 setRequestedOrientation(getIntent().getIntExtra(
145                         EXTRA_ORIENTATION, SCREEN_ORIENTATION_UNSPECIFIED));
146             }
147 
148         }
149 
addChildWindow()150         void addChildWindow() {
151             final WindowMetrics windowMetrics = getWindowManager().getMaximumWindowMetrics();
152             mScreenBounds = windowMetrics.getBounds();
153             final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams();
154             attrs.x = mScreenBounds.left;
155             attrs.y = mScreenBounds.top;
156             attrs.width = mScreenBounds.width();
157             attrs.height = mScreenBounds.height();
158             attrs.gravity = Gravity.LEFT | Gravity.TOP;
159             attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
160             attrs.flags = FLAG_NOT_FOCUSABLE;
161             attrs.setFitInsetsTypes(0);
162             mChildWindowRoot = new View(this);
163             mChildWindowRoot.setOnApplyWindowInsetsListener(
164                     (v, insets) -> {
165                         mDispatchedInsets = insets;
166                         return insets;
167                     });
168             getWindowManager().addView(mChildWindowRoot, attrs);
169         }
170 
getChildWindowRoot()171         View getChildWindowRoot() {
172             return mChildWindowRoot;
173         }
174 
getDispatchedInsets()175         WindowInsets getDispatchedInsets() {
176             return mDispatchedInsets;
177         }
178 
getScreenBounds()179         Rect getScreenBounds() {
180             return mScreenBounds;
181         }
182     }
183 }
184