• 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 package android.view.cts;
17 
18 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
19 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
20 
21 import android.annotation.SuppressLint;
22 import android.app.Activity;
23 import android.content.pm.ActivityInfo;
24 import android.content.pm.PackageManager;
25 import android.server.wm.IgnoreOrientationRequestSession;
26 import android.util.Log;
27 import android.view.AttachedSurfaceControl;
28 
29 import androidx.lifecycle.Lifecycle;
30 import androidx.test.core.app.ActivityScenario;
31 import androidx.test.filters.LargeTest;
32 import androidx.test.filters.RequiresDevice;
33 import androidx.test.platform.app.InstrumentationRegistry;
34 import androidx.test.runner.AndroidJUnit4;
35 
36 import com.android.compatibility.common.util.SystemUtil;
37 
38 import org.junit.After;
39 import org.junit.Assert;
40 import org.junit.Assume;
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 
45 import java.util.concurrent.CountDownLatch;
46 import java.util.concurrent.TimeUnit;
47 import java.util.function.IntConsumer;
48 
49 @RunWith(AndroidJUnit4.class)
50 @LargeTest
51 @SuppressLint("RtlHardcoded")
52 @RequiresDevice
53 public class AttachedSurfaceControlTest {
54     private static final String TAG = "AttachedSurfaceControlTest";
55     private static final String FIXED_TO_USER_ROTATION_COMMAND =
56             "cmd window fixed-to-user-rotation";
57     private IgnoreOrientationRequestSession mOrientationSession;
58 
59     private static class TransformHintListener implements
60             AttachedSurfaceControl.OnBufferTransformHintChangedListener {
61         Activity activity;
62         int expectedOrientation;
63         CountDownLatch latch = new CountDownLatch(1);
64         IntConsumer hintConsumer;
65 
TransformHintListener(Activity activity, int expectedOrientation, IntConsumer hintConsumer)66         TransformHintListener(Activity activity, int expectedOrientation,
67                 IntConsumer hintConsumer) {
68             this.activity = activity;
69             this.expectedOrientation = expectedOrientation;
70             this.hintConsumer = hintConsumer;
71         }
72 
73         @Override
onBufferTransformHintChanged(int hint)74         public void onBufferTransformHintChanged(int hint) {
75             int orientation = activity.getResources().getConfiguration().orientation;
76             Log.d(TAG, "onBufferTransformHintChanged: orientation actual=" + orientation
77                     + " expected=" + expectedOrientation + " transformHint=" + hint);
78             Assert.assertEquals("Failed to switch orientation hint=" + hint, orientation,
79                     expectedOrientation);
80             hintConsumer.accept(hint);
81             latch.countDown();
82             activity.getWindow().getRootSurfaceControl()
83                     .removeOnBufferTransformHintChangedListener(this);
84         }
85     }
86 
87     @Before
setup()88     public void setup() {
89         PackageManager pm =
90                 InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
91         boolean supportsRotation = pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT)
92                 && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE);
93         final boolean isFixedToUserRotation =
94                 "enabled".equals(SystemUtil.runShellCommand(FIXED_TO_USER_ROTATION_COMMAND).trim());
95         Assume.assumeTrue(supportsRotation && !isFixedToUserRotation);
96         mOrientationSession = new IgnoreOrientationRequestSession(false /* enable */);
97     }
98 
99     @After
teardown()100     public void teardown() {
101         if (mOrientationSession != null) {
102             mOrientationSession.close();
103         }
104     }
105 
106     @Test
testOnBufferTransformHintChangedListener()107     public void testOnBufferTransformHintChangedListener() throws InterruptedException {
108         final int[] transformHintResult = new int[2];
109         final CountDownLatch[] firstCallback = new CountDownLatch[1];
110         final CountDownLatch[] secondCallback = new CountDownLatch[1];
111         try (ActivityScenario<HandleConfigurationActivity> scenario =
112                      ActivityScenario.launch(HandleConfigurationActivity.class)) {
113             scenario.moveToState(Lifecycle.State.RESUMED);
114             scenario.onActivity(activity -> {
115                 int requestedOrientation = getRequestedOrientation(activity);
116                 TransformHintListener listener = new TransformHintListener(activity,
117                         requestedOrientation, hint -> transformHintResult[0] = hint);
118                 firstCallback[0] = listener.latch;
119                 activity.getWindow().getRootSurfaceControl()
120                         .addOnBufferTransformHintChangedListener(listener);
121                 setRequestedOrientation(activity, requestedOrientation);
122             });
123             // Check we get a callback since the orientation has changed and we expect transform
124             // hint to change.
125             Assert.assertTrue(firstCallback[0].await(3, TimeUnit.SECONDS));
126 
127             // Check the callback value matches the call to get the transform hint.
128             scenario.onActivity(activity -> Assert.assertEquals(transformHintResult[0],
129                     activity.getWindow().getRootSurfaceControl().getBufferTransformHint()));
130 
131             scenario.onActivity(activity -> {
132                 int requestedOrientation = getRequestedOrientation(activity);
133                 TransformHintListener listener = new TransformHintListener(activity,
134                         requestedOrientation, hint -> transformHintResult[1] = hint);
135                 secondCallback[0] = listener.latch;
136                 activity.getWindow().getRootSurfaceControl()
137                         .addOnBufferTransformHintChangedListener(listener);
138                 setRequestedOrientation(activity, requestedOrientation);
139             });
140             // Check we get a callback since the orientation has changed and we expect transform
141             // hint to change.
142             Assert.assertTrue(secondCallback[0].await(3, TimeUnit.SECONDS));
143 
144             // Check the callback value matches the call to get the transform hint.
145             scenario.onActivity(activity -> Assert.assertEquals(transformHintResult[1],
146                     activity.getWindow().getRootSurfaceControl().getBufferTransformHint()));
147         }
148 
149         // If the app orientation was changed, we should get a different transform hint
150         Assert.assertNotEquals(transformHintResult[0], transformHintResult[1]);
151     }
152 
getRequestedOrientation(Activity activity)153     private int getRequestedOrientation(Activity activity) {
154         int currentOrientation = activity.getResources().getConfiguration().orientation;
155         return currentOrientation == ORIENTATION_LANDSCAPE ? ORIENTATION_PORTRAIT
156                 : ORIENTATION_LANDSCAPE;
157     }
158 
setRequestedOrientation(Activity activity, int requestedOrientation)159     private void setRequestedOrientation(Activity activity,
160             /* @Configuration.Orientation */ int requestedOrientation) {
161         /* @ActivityInfo.ScreenOrientation */
162         Log.d(TAG, "setRequestedOrientation: requestedOrientation=" + requestedOrientation);
163         int screenOrientation =
164                 requestedOrientation == ORIENTATION_LANDSCAPE
165                         ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
166                         : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
167         activity.setRequestedOrientation(screenOrientation);
168     }
169 
170     @Test
testOnBufferTransformHintChangesFromLandToSea()171     public void testOnBufferTransformHintChangesFromLandToSea() throws InterruptedException {
172         final int[] transformHintResult = new int[2];
173         final CountDownLatch[] firstCallback = new CountDownLatch[1];
174         final CountDownLatch[] secondCallback = new CountDownLatch[1];
175         try (ActivityScenario<HandleConfigurationActivity> scenario =
176                      ActivityScenario.launch(HandleConfigurationActivity.class)) {
177             scenario.moveToState(Lifecycle.State.RESUMED);
178             scenario.onActivity(activity -> {
179                 if (activity.getResources().getConfiguration().orientation
180                         == ORIENTATION_LANDSCAPE) {
181                     return;
182                 }
183                 TransformHintListener listener = new TransformHintListener(activity,
184                         ORIENTATION_LANDSCAPE, hint -> transformHintResult[0] = hint);
185                 firstCallback[0] = listener.latch;
186                 activity.getWindow().getRootSurfaceControl()
187                         .addOnBufferTransformHintChangedListener(listener);
188                 setRequestedOrientation(activity, ORIENTATION_LANDSCAPE);
189             });
190 
191             // If the device is already in landscape, do nothing.
192             if (firstCallback[0] != null) {
193                 Assert.assertTrue(firstCallback[0].await(3, TimeUnit.SECONDS));
194                 scenario.onActivity(activity -> Assert.assertEquals(transformHintResult[0],
195                     activity.getWindow().getRootSurfaceControl().getBufferTransformHint()));
196             }
197 
198             scenario.onActivity(activity -> {
199                 TransformHintListener listener = new TransformHintListener(activity,
200                         ORIENTATION_LANDSCAPE, hint -> transformHintResult[1] = hint);
201                 secondCallback[0] = listener.latch;
202                 activity.getWindow().getRootSurfaceControl()
203                         .addOnBufferTransformHintChangedListener(listener);
204                 activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
205             });
206             // Check we get a callback since the orientation has changed and we expect transform
207             // hint to change.
208             Assert.assertTrue(secondCallback[0].await(3, TimeUnit.SECONDS));
209 
210             // Check the callback value matches the call to get the transform hint.
211             scenario.onActivity(activity -> Assert.assertEquals(transformHintResult[1],
212                     activity.getWindow().getRootSurfaceControl().getBufferTransformHint()));
213         }
214 
215         // If the app orientation was changed, we should get a different transform hint
216         Assert.assertNotEquals(transformHintResult[0], transformHintResult[1]);
217     }
218 
219 }
220