• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.view.WindowInsets.Type.navigationBars;
20 import static android.view.WindowInsets.Type.statusBars;
21 import static android.view.WindowInsets.Type.systemBars;
22 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
23 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
24 
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNotNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assume.assumeFalse;
29 
30 import android.app.Activity;
31 import android.content.res.Resources;
32 import android.content.pm.PackageManager;
33 import android.graphics.Insets;
34 import android.os.Bundle;
35 import android.view.View;
36 import android.view.Window;
37 import android.view.WindowInsets;
38 
39 import androidx.annotation.Nullable;
40 import androidx.test.platform.app.InstrumentationRegistry;
41 import androidx.test.rule.ActivityTestRule;
42 
43 import org.junit.Rule;
44 
45 import java.util.concurrent.CountDownLatch;
46 import java.util.concurrent.TimeUnit;
47 
48 public class ForceRelayoutTestBase {
49 
50     @Rule
51     public ActivityTestRule<TestActivity> mDecorActivity = new ActivityTestRule<>(
52             TestActivity.class);
53 
testRelayoutWhenInsetsChange(boolean expectRelayoutWhenInsetsChange, int softInputMode)54     void testRelayoutWhenInsetsChange(boolean expectRelayoutWhenInsetsChange, int softInputMode)
55             throws Throwable {
56         TestActivity activity = mDecorActivity.getActivity();
57         assertNotNull("test setup failed", activity.mLastContentInsets);
58         assumeFalse(Insets.NONE.equals(activity.mLastContentInsets.getInsetsIgnoringVisibility(
59                 statusBars() | navigationBars())));
60         assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
61 
62         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
63             activity.mLayoutHappened = false;
64             activity.mMeasureHappened = false;
65             activity.getWindow().setSoftInputMode(softInputMode);
66             activity.getWindow().getInsetsController().hide(systemBars());
67         });
68         activity.mZeroInsets.await(180, TimeUnit.SECONDS);
69         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
70             if (expectRelayoutWhenInsetsChange) {
71                 assertTrue(activity.mLayoutHappened);
72                 assertTrue(activity.mMeasureHappened);
73             } else {
74                 assertFalse(activity.mLayoutHappened);
75                 assertFalse(activity.mMeasureHappened);
76             }
77         });
78     }
79 
80     public static class TestActivity extends Activity {
81         WindowInsets mLastContentInsets;
82         final CountDownLatch mZeroInsets = new CountDownLatch(1);
83 
84         volatile boolean mLayoutHappened;
85         volatile boolean mMeasureHappened;
86 
87         @Override
onCreate(@ullable Bundle savedInstanceState)88         protected void onCreate(@Nullable Bundle savedInstanceState) {
89             super.onCreate(savedInstanceState);
90             getWindow().requestFeature(Window.FEATURE_NO_TITLE);
91             getWindow().setDecorFitsSystemWindows(false);
92             getWindow().getAttributes().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
93             View view = new View(this) {
94                 @Override
95                 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
96                     super.onLayout(changed, left, top, right, bottom);
97                     mLayoutHappened = true;
98                 }
99 
100                 @Override
101                 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
102                     super.onMeasure(widthMeasureSpec, heightMeasureSpec);
103                     mMeasureHappened = true;
104 
105                 }
106             };
107             view.setOnApplyWindowInsetsListener((v, wi) -> {
108                 mLastContentInsets = wi;
109                 if (wi.getInsets(systemBars()).equals(Insets.NONE)) {
110 
111                     // Make sure full traversal happens before counting down.
112                     v.post(mZeroInsets::countDown);
113                 }
114                 return WindowInsets.CONSUMED;
115             });
116             setContentView(view);
117         }
118     }
119 
remoteInsetsControllerControlsSystemBars()120     private static boolean remoteInsetsControllerControlsSystemBars() {
121         return InstrumentationRegistry.getInstrumentation().getTargetContext().getResources()
122                     .getBoolean(android.R.bool.config_remoteInsetsControllerControlsSystemBars);
123     }
124 
isCar()125     private boolean isCar() {
126         PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext()
127                               .getPackageManager();
128         return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
129     }
130 }
131