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