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.jetpack.utils;
18 
19 import android.app.Activity;
20 import android.content.res.Configuration;
21 import android.os.Bundle;
22 import android.view.View;
23 
24 import androidx.annotation.NonNull;
25 import androidx.annotation.Nullable;
26 
27 import java.util.concurrent.CountDownLatch;
28 import java.util.concurrent.TimeUnit;
29 
30 /**
31  * Test activity that can verify whether the layout changes. Copied from
32  * androidx.window.TestActivity.
33  */
34 public class TestActivity extends Activity implements View.OnLayoutChangeListener {
35     private CountDownLatch mLayoutLatch;
36     private CountDownLatch mOnConfigurationChangeLatch = new CountDownLatch(1);
37     private CountDownLatch mFocusLatch = new CountDownLatch(1);
38     private static CountDownLatch sResumeLatch = new CountDownLatch(1);
39 
40     @Override
onCreate(@ullable Bundle savedInstanceState)41     public void onCreate(@Nullable Bundle savedInstanceState) {
42         super.onCreate(savedInstanceState);
43 
44         resetLayoutCounter();
45         getWindow().getDecorView().addOnLayoutChangeListener(this);
46     }
47 
48     @Override
onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)49     public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
50             int oldTop, int oldRight, int oldBottom) {
51         mLayoutLatch.countDown();
52     }
53 
54     @Override
onConfigurationChanged(@onNull Configuration newConfig)55     public void onConfigurationChanged(@NonNull Configuration newConfig) {
56         super.onConfigurationChanged(newConfig);
57         mOnConfigurationChangeLatch.countDown();
58     }
59 
60     @Override
onWindowFocusChanged(boolean hasWindowFocus)61     public void onWindowFocusChanged(boolean hasWindowFocus) {
62         if (hasWindowFocus) {
63             mFocusLatch.countDown();
64         }
65     }
66 
67     @Override
onResume()68     protected void onResume() {
69         super.onResume();
70         sResumeLatch.countDown();
71     }
72 
73     /**
74      * Resets layout counter when waiting for a layout to happen before calling
75      * {@link #waitForLayout()}.
76      */
resetLayoutCounter()77     public void resetLayoutCounter() {
78         mLayoutLatch = new CountDownLatch(1);
79     }
80 
81     /**
82      * Blocks and waits for the next layout to happen. {@link #resetLayoutCounter()} must be called
83      * before calling this method.
84      * @return {@code true} if the layout happened before the timeout count reached zero and
85      *         {@code false} if the waiting time elapsed before the layout happened.
86      */
waitForLayout()87     public boolean waitForLayout() {
88         try {
89             return mLayoutLatch.await(3, TimeUnit.SECONDS);
90         } catch (InterruptedException e) {
91             return false;
92         }
93     }
94 
95     /**
96      * Resets the focus counter.
97      */
resetFocusCounter()98     public void resetFocusCounter() {
99         mFocusLatch = new CountDownLatch(1);
100     }
101 
102     /**
103      * Waits for receiving the first window focus.
104      *
105      * @return {@code true} if the window ever becomes the focused window.
106      */
waitForFocus()107     public boolean waitForFocus() {
108         try {
109             return mFocusLatch.await(3, TimeUnit.SECONDS);
110         } catch (InterruptedException e) {
111             return false;
112         }
113     }
114 
115     /**
116      * Resets the configuration change counter.
117      */
resetOnConfigurationChangeCounter()118     public void resetOnConfigurationChangeCounter() {
119         mOnConfigurationChangeLatch = new CountDownLatch(1);
120     }
121 
122     /**
123      * Waits for a configuration change callback.
124      *
125      * @return {@code true} if the configuration change callback is triggered, {@code false}
126      * otherwise.
127      */
waitForConfigurationChange()128     public boolean waitForConfigurationChange() {
129         try {
130             return mOnConfigurationChangeLatch.await(3, TimeUnit.SECONDS);
131         } catch (InterruptedException e) {
132             return false;
133         }
134     }
135 
136     /**
137      * Resets layout counter when waiting for a layout to happen before calling
138      * {@link #waitForOnResume()}.
139      */
resetResumeCounter()140     public static void resetResumeCounter() {
141         sResumeLatch = new CountDownLatch(1);
142     }
143 
144     /**
145      * Same as {@link #waitForLayout()}, but waits for onResume() to be called for any activity of
146      * this class. This can be used to track activity re-creation.
147      * @return {@code true} if the onResume() happened before the timeout count reached zero and
148      *         {@code false} if the waiting time elapsed before the onResume() happened.
149      */
waitForOnResume()150     public static boolean waitForOnResume() {
151         try {
152             return sResumeLatch.await(3, TimeUnit.SECONDS);
153         } catch (InterruptedException e) {
154             return false;
155         }
156     }
157 }
158