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 17 package com.android.cts.overlay.target; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 22 import static org.junit.Assert.fail; 23 24 import android.app.Instrumentation; 25 import android.content.Intent; 26 import android.os.Bundle; 27 import android.os.UserHandle; 28 29 import androidx.test.InstrumentationRegistry; 30 import androidx.test.rule.ActivityTestRule; 31 import androidx.test.runner.AndroidJUnit4; 32 33 import com.android.compatibility.common.util.PollingCheck; 34 import com.android.compatibility.common.util.SystemUtil; 35 36 import org.junit.Before; 37 import org.junit.Rule; 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 44 @RunWith(AndroidJUnit4.class) 45 public class OverlayTargetTest { 46 // overlay package 47 private static final String OVERLAY_ALL_PACKAGE_NAME = "com.android.cts.overlay.all"; 48 49 // Overlay states 50 private static final String STATE_DISABLED = "STATE_DISABLED"; 51 private static final String STATE_ENABLED = "STATE_ENABLED"; 52 53 // Default timeout value 54 private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5); 55 56 // Keys for test arguments 57 private static final String PARAM_START_SERVICE = "start_service"; 58 59 private Instrumentation mInstrumentation; 60 61 @Rule 62 public ActivityTestRule<OverlayTargetActivity> mActivityTestRule = new ActivityTestRule<>( 63 OverlayTargetActivity.class, false /* initialTouchMode */, false /* launchActivity */); 64 65 @Before setup()66 public void setup() { 67 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 68 launchOverlayTargetActivity(InstrumentationRegistry.getArguments()); 69 assertThat(mActivityTestRule.getActivity()).isNotNull(); 70 } 71 72 @Test overlayEnabled_activityInForeground()73 public void overlayEnabled_activityInForeground() throws Exception { 74 final OverlayTargetActivity targetActivity = mActivityTestRule.getActivity(); 75 final CountDownLatch latch = new CountDownLatch(1); 76 targetActivity.setConfigurationChangedCallback((activity, config) -> { 77 latch.countDown(); 78 activity.setConfigurationChangedCallback(null); 79 }); 80 81 setOverlayEnabled(OVERLAY_ALL_PACKAGE_NAME, true /* enabled */); 82 83 if (!latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 84 fail("Fail to wait configuration changes for the overlay target activity."); 85 } 86 } 87 88 @Test overlayEnabled_activityInBackground_toForeground()89 public void overlayEnabled_activityInBackground_toForeground() throws Exception { 90 final OverlayTargetActivity targetActivity = mActivityTestRule.getActivity(); 91 // Activity goes into background 92 launchHome(); 93 mInstrumentation.waitForIdleSync(); 94 final CountDownLatch latch = new CountDownLatch(1); 95 targetActivity.setConfigurationChangedCallback((activity, config) -> { 96 latch.countDown(); 97 activity.setConfigurationChangedCallback(null); 98 }); 99 setOverlayEnabled(OVERLAY_ALL_PACKAGE_NAME, true /* enabled */); 100 101 if (latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 102 fail("Activity in background should not receive configuration changes"); 103 } 104 105 // Bring activity to foreground 106 final Intent intent = new Intent(mInstrumentation.getTargetContext(), 107 OverlayTargetActivity.class); 108 intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 109 targetActivity.startActivity(intent); 110 111 if (!latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 112 fail("Fail to wait configuration changes for the overlay target activity."); 113 } 114 } 115 launchOverlayTargetActivity(Bundle testArgs)116 private void launchOverlayTargetActivity(Bundle testArgs) { 117 final Intent intent = new Intent(mInstrumentation.getTargetContext(), 118 OverlayTargetActivity.class); 119 final boolean startService = (testArgs != null 120 && "true".equalsIgnoreCase(testArgs.getString(PARAM_START_SERVICE))); 121 intent.putExtra(OverlayTargetActivity.EXTRA_START_SERVICE, startService); 122 mActivityTestRule.launchActivity(intent); 123 mInstrumentation.waitForIdleSync(); 124 } 125 setOverlayEnabled(String overlayPackage, boolean enabled)126 private static void setOverlayEnabled(String overlayPackage, boolean enabled) 127 throws Exception { 128 final String current = getStateForOverlay(overlayPackage); 129 final String expected = enabled ? STATE_ENABLED : STATE_DISABLED; 130 assertThat(current).isNotEqualTo(expected); 131 SystemUtil.runShellCommand("cmd overlay " 132 + (enabled ? "enable" : "disable") 133 + " --user current " 134 + overlayPackage); 135 PollingCheck.check("Fail to wait overlay enabled state " + expected 136 + " for " + overlayPackage, TIMEOUT_MS, 137 () -> expected.equals(getStateForOverlay(overlayPackage))); 138 } 139 launchHome()140 private static void launchHome() { 141 SystemUtil.runShellCommand("am start -W -a android.intent.action.MAIN" 142 + " -c android.intent.category.HOME"); 143 } 144 getStateForOverlay(String overlayPackage)145 private static String getStateForOverlay(String overlayPackage) { 146 final String errorMsg = "Fail to parse the state of overlay package " + overlayPackage; 147 final String result = SystemUtil.runShellCommand("cmd overlay dump"); 148 final String overlayPackageForCurrentUser = overlayPackage + ":" + UserHandle.myUserId(); 149 final int startIndex = result.indexOf(overlayPackageForCurrentUser); 150 assertWithMessage(errorMsg).that(startIndex).isAtLeast(0); 151 152 final int endIndex = result.indexOf('}', startIndex); 153 assertWithMessage(errorMsg).that(endIndex).isGreaterThan(startIndex); 154 155 final int stateIndex = result.indexOf("mState", startIndex); 156 assertWithMessage(errorMsg).that(startIndex).isLessThan(stateIndex); 157 assertWithMessage(errorMsg).that(stateIndex).isLessThan(endIndex); 158 159 final int colonIndex = result.indexOf(':', stateIndex); 160 assertWithMessage(errorMsg).that(stateIndex).isLessThan(colonIndex); 161 assertWithMessage(errorMsg).that(colonIndex).isLessThan(endIndex); 162 163 final int endLineIndex = result.indexOf('\n', colonIndex); 164 assertWithMessage(errorMsg).that(colonIndex).isLessThan(endLineIndex); 165 assertWithMessage(errorMsg).that(endLineIndex).isLessThan(endIndex); 166 167 return result.substring(colonIndex + 2, endLineIndex); 168 } 169 } 170