1 /* 2 * Copyright (C) 2017 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.app.cts; 18 19 import com.android.appSdk25.Sdk25MaxAspectRatioActivity; 20 21 import org.junit.After; 22 import org.junit.Before; 23 import org.junit.Ignore; 24 import org.junit.Rule; 25 import org.junit.Test; 26 import org.junit.runner.RunWith; 27 28 import android.app.Activity; 29 import android.app.stubs.MaxAspectRatioActivity; 30 import android.app.stubs.MaxAspectRatioResizeableActivity; 31 import android.app.stubs.MaxAspectRatioUnsetActivity; 32 import android.content.Context; 33 import android.content.res.Configuration; 34 import android.graphics.Point; 35 import android.platform.test.annotations.Presubmit; 36 import android.support.test.InstrumentationRegistry; 37 import android.support.test.rule.ActivityTestRule; 38 import android.support.test.runner.AndroidJUnit4; 39 import android.util.DisplayMetrics; 40 import android.view.Display; 41 import android.view.WindowManager; 42 43 import static android.content.Context.WINDOW_SERVICE; 44 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 45 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 46 import static android.content.pm.PackageManager.FEATURE_WATCH; 47 import static org.junit.Assert.fail; 48 49 /** 50 * Build: mmma -j32 cts/tests/app 51 * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsAppTestCases android.app.cts.AspectRatioTests 52 */ 53 @RunWith(AndroidJUnit4.class) 54 public class AspectRatioTests { 55 private static final String TAG = "AspectRatioTests"; 56 57 // The max. aspect ratio the test activities are using. 58 private static final float MAX_ASPECT_RATIO = 1.0f; 59 60 // Max supported aspect ratio for pre-O apps. 61 private static final float MAX_PRE_O_ASPECT_RATIO = 1.86f; 62 63 // The minimum supported device aspect ratio. 64 private static final float MIN_DEVICE_ASPECT_RATIO = 1.333f; 65 66 // The minimum supported device aspect ratio for watches. 67 private static final float MIN_WATCH_DEVICE_ASPECT_RATIO = 1.0f; 68 69 @Rule 70 public ActivityTestRule<MaxAspectRatioActivity> mMaxAspectRatioActivity = 71 new ActivityTestRule<>(MaxAspectRatioActivity.class, 72 false /* initialTouchMode */, false /* launchActivity */); 73 74 @Rule 75 public ActivityTestRule<MaxAspectRatioResizeableActivity> mMaxAspectRatioResizeableActivity = 76 new ActivityTestRule<>(MaxAspectRatioResizeableActivity.class, 77 false /* initialTouchMode */, false /* launchActivity */); 78 79 @Rule 80 public ActivityTestRule<MaxAspectRatioUnsetActivity> mMaxAspectRatioUnsetActivity = 81 new ActivityTestRule<>(MaxAspectRatioUnsetActivity.class, 82 false /* initialTouchMode */, false /* launchActivity */); 83 84 // TODO: Can't use this to start an activity in a different process...sigh. 85 @Rule 86 public ActivityTestRule<Sdk25MaxAspectRatioActivity> mSdk25MaxAspectRatioActivity = 87 new ActivityTestRule<>(Sdk25MaxAspectRatioActivity.class, "com.android.appSdk25", 88 268435456, false /* initialTouchMode */, false /* launchActivity */); 89 90 private interface AssertAspectRatioCallback { 91 void assertAspectRatio(float actual); 92 } 93 94 @Before 95 public void setUp() throws Exception { 96 97 } 98 99 @After 100 public void tearDown() throws Exception { 101 finishActivity(mMaxAspectRatioActivity); 102 finishActivity(mMaxAspectRatioResizeableActivity); 103 finishActivity(mSdk25MaxAspectRatioActivity); 104 finishActivity(mMaxAspectRatioUnsetActivity); 105 } 106 107 @Test 108 @Presubmit 109 public void testDeviceAspectRatio() throws Exception { 110 final Context context = InstrumentationRegistry.getInstrumentation().getContext(); 111 final WindowManager wm = (WindowManager) context.getSystemService(WINDOW_SERVICE); 112 final Display display = wm.getDefaultDisplay(); 113 final DisplayMetrics metrics = new DisplayMetrics(); 114 display.getRealMetrics(metrics); 115 116 float longSide = Math.max(metrics.widthPixels, metrics.heightPixels); 117 float shortSide = Math.min(metrics.widthPixels, metrics.heightPixels); 118 float deviceAspectRatio = longSide / shortSide; 119 float expectedMinAspectRatio = context.getPackageManager().hasSystemFeature(FEATURE_WATCH) 120 ? MIN_WATCH_DEVICE_ASPECT_RATIO : MIN_DEVICE_ASPECT_RATIO; 121 122 if (deviceAspectRatio < expectedMinAspectRatio) { 123 fail("deviceAspectRatio=" + deviceAspectRatio 124 + " is less than expectedMinAspectRatio=" + expectedMinAspectRatio); 125 } 126 } 127 128 @Test 129 @Presubmit 130 public void testMaxAspectRatio() throws Exception { 131 runTest(launchActivity(mMaxAspectRatioActivity), 132 actual -> { 133 if (MAX_ASPECT_RATIO >= actual) return; 134 fail("actual=" + actual + " is greater than expected=" + MAX_ASPECT_RATIO); 135 }); 136 } 137 138 @Test 139 // TODO: Currently 10% flaky so not part of pre-submit for now 140 public void testMaxAspectRatioResizeableActivity() throws Exception { 141 final Context context = InstrumentationRegistry.getInstrumentation().getContext(); 142 final float expected = getAspectRatio(context); 143 144 // Since this activity is resizeable, its aspect ratio shouldn't be less than the device's 145 runTest(launchActivity(mMaxAspectRatioResizeableActivity), 146 actual -> { 147 if (aspectRatioEqual(expected, actual) || expected < actual) return; 148 fail("actual=" + actual + " is less than expected=" + expected); 149 }); 150 } 151 152 @Test 153 @Presubmit 154 public void testMaxAspectRatioUnsetActivity() throws Exception { 155 final Context context = InstrumentationRegistry.getInstrumentation().getContext(); 156 final float expected = getAspectRatio(context); 157 158 // Since this activity didn't set an aspect ratio, its aspect ratio shouldn't be less than 159 // the device's 160 runTest(launchActivity(mMaxAspectRatioUnsetActivity), 161 actual -> { 162 if (aspectRatioEqual(expected, actual) || expected < actual) return; 163 fail("actual=" + actual + " is less than expected=" + expected); 164 }); 165 } 166 167 @Test 168 // TODO(b/35810513): Can't use rule to start an activity in a different process. Need a 169 // different way to make this test happen...host side? Sigh... 170 @Ignore 171 public void testMaxAspectRatioPreOActivity() throws Exception { 172 runTest(launchActivity(mSdk25MaxAspectRatioActivity), 173 actual -> { 174 if (MAX_PRE_O_ASPECT_RATIO >= actual) return; 175 fail("actual=" + actual + " is greater than expected=" + MAX_PRE_O_ASPECT_RATIO); 176 }); 177 } 178 179 private void runTest(Activity activity, AssertAspectRatioCallback callback) { 180 callback.assertAspectRatio(getAspectRatio(activity)); 181 182 // TODO(b/35810513): All this rotation stuff doesn't really work yet. Need to make sure 183 // context is updated correctly here. Also, what does it mean to be holding a reference to 184 // this activity if changing the orientation will cause a relaunch? 185 // activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); 186 // waitForIdle(); 187 // callback.assertAspectRatio(getAspectRatio(activity)); 188 // 189 // activity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); 190 // waitForIdle(); 191 // callback.assertAspectRatio(getAspectRatio(activity)); 192 } 193 194 private float getAspectRatio(Context context) { 195 final Display display = 196 ((WindowManager) context.getSystemService(WINDOW_SERVICE)).getDefaultDisplay(); 197 final Point size = new Point(); 198 display.getSize(size); 199 final float longSide = Math.max(size.x, size.y); 200 final float shortSide = Math.min(size.x, size.y); 201 return longSide / shortSide; 202 } 203 204 private Activity launchActivity(ActivityTestRule activityRule) { 205 final Activity activity = activityRule.launchActivity(null); 206 waitForIdle(); 207 return activity; 208 } 209 210 private void finishActivity(ActivityTestRule activityRule) { 211 final Activity activity = activityRule.getActivity(); 212 if (activity != null) { 213 activity.finish(); 214 } 215 } 216 217 private void waitForIdle() { 218 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 219 } 220 221 private static boolean aspectRatioEqual(float a, float b) { 222 // Aspect ratios are considered equal if they ware within to significant digits. 223 float diff = Math.abs(a - b); 224 return diff < 0.01f; 225 } 226 } 227