Home | History | Annotate | Download | only in cts
      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