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