1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package android.app.cts; 17 18 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 19 20 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 21 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertNotEquals; 24 import static org.junit.Assert.assertNotNull; 25 26 import android.app.ActivityOptions; 27 import android.app.UiAutomation; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.pm.PackageManager; 31 import android.content.res.Configuration; 32 33 import androidx.test.ext.junit.rules.ActivityScenarioRule; 34 import androidx.test.filters.SmallTest; 35 36 import org.junit.Rule; 37 import org.junit.Test; 38 import org.junit.rules.ExternalResource; 39 import org.junit.rules.RuleChain; 40 import org.junit.rules.TestRule; 41 42 import java.util.concurrent.Future; 43 import java.util.function.Function; 44 45 /** 46 * Tests the {@link android.view.ContextThemeWrapper#applyOverrideConfiguration(Configuration)} 47 * method and how it affects the Activity's resources and lifecycle callbacks. 48 */ 49 public class ApplyOverrideConfigurationTest { 50 private static ActivityScenarioRule<ApplyOverrideConfigurationActivity> getActivityScenarioRule()51 getActivityScenarioRule() { 52 final ActivityOptions options = ActivityOptions.makeBasic(); 53 options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); 54 55 final Intent intent = new Intent( 56 getInstrumentation().getTargetContext(), ApplyOverrideConfigurationActivity.class); 57 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 58 return new ActivityScenarioRule<>(intent, options.toBundle()); 59 } 60 61 private final ActivityScenarioRule<ApplyOverrideConfigurationActivity> mActivityScenarioRule = 62 getActivityScenarioRule(); 63 64 @Rule 65 public TestRule mRule = RuleChain.outerRule(new ExternalResource() { 66 @Override 67 protected void before() { 68 getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0); 69 } 70 71 @Override 72 protected void after() { 73 getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE); 74 } 75 }).around(mActivityScenarioRule); 76 onActivity(Function<ApplyOverrideConfigurationActivity, R> func)77 private <R> R onActivity(Function<ApplyOverrideConfigurationActivity, R> func) { 78 Object[] result = new Object[1]; 79 mActivityScenarioRule.getScenario().onActivity(activity -> { 80 result[0] = func.apply(activity); 81 }); 82 return (R) result[0]; 83 } 84 85 @SmallTest 86 @Test testOverriddenConfigurationIsPassedIntoCallback()87 public void testOverriddenConfigurationIsPassedIntoCallback() throws Exception { 88 // This test instruments display rotation; disable it on devices that do not 89 // support auto-rotation. 90 91 if (!onActivity(ApplyOverrideConfigurationTest::isRotationSupported)) { 92 return; 93 } 94 95 final Configuration originalConfig = 96 onActivity(activity -> activity.getResources().getConfiguration()); 97 assertEquals(ApplyOverrideConfigurationActivity.OVERRIDE_SMALLEST_WIDTH, 98 originalConfig.smallestScreenWidthDp); 99 100 final Future<Configuration> callbackConfigurationFuture = onActivity( 101 ApplyOverrideConfigurationActivity::watchForSingleOnConfigurationChangedCallback); 102 getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_90); 103 final Configuration callbackConfig = callbackConfigurationFuture.get(); 104 assertNotNull(callbackConfig); 105 106 final Configuration newConfig = onActivity( 107 activity -> activity.getResources().getConfiguration()); 108 assertNotEquals(originalConfig.orientation, newConfig.orientation); 109 assertEquals(ApplyOverrideConfigurationActivity.OVERRIDE_SMALLEST_WIDTH, 110 newConfig.smallestScreenWidthDp); 111 assertEquals(newConfig, callbackConfig); 112 } 113 114 /** 115 * Gets whether the device supports rotation. In general such a 116 * device has both portrait and landscape features. 117 * 118 * @param context Context for accessing system resources. 119 * @return Whether the device supports rotation. 120 */ isRotationSupported(Context context)121 public static boolean isRotationSupported(Context context) { 122 PackageManager pm = context.getPackageManager(); 123 return pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT) 124 && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE) 125 && !isVrHeadset(context); 126 } 127 128 /** 129 * Gets whether the DUT is a vr headset. 130 * 131 * @param context Context for accessing system resources. 132 * @return Whether the device is a vr headset. 133 */ isVrHeadset(Context context)134 public static boolean isVrHeadset(Context context) { 135 return (context.getResources().getConfiguration().uiMode 136 & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_VR_HEADSET; 137 } 138 } 139