/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.contentcaptureservice.cts; import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE; import static android.contentcaptureservice.cts.Helper.MY_PACKAGE; import static android.contentcaptureservice.cts.Helper.resetService; import static android.contentcaptureservice.cts.Helper.sContext; import static android.contentcaptureservice.cts.Helper.sUserSettings; import static android.contentcaptureservice.cts.Helper.setService; import static android.contentcaptureservice.cts.Helper.toSet; import static android.provider.Settings.Secure.CONTENT_CAPTURE_ENABLED; import static com.android.compatibility.common.util.ShellUtils.runShellCommand; import android.content.ComponentName; import android.content.ContentCaptureOptions; import android.contentcaptureservice.cts.CtsContentCaptureService.ServiceWatcher; import android.provider.DeviceConfig; import android.util.Log; import android.util.Pair; import android.view.contentcapture.ContentCaptureManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.compatibility.common.util.DeviceConfigStateChangerRule; import com.android.compatibility.common.util.DeviceConfigStateManager; import com.android.compatibility.common.util.RequiredServiceRule; import com.android.compatibility.common.util.SafeCleanerRule; import com.android.compatibility.common.util.SettingsStateChangerRule; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.junit.runners.model.Statement; import java.util.Set; /** * Base class for all (or most :-) integration tests in this CTS suite. */ @RunWith(AndroidJUnit4.class) public abstract class AbstractContentCaptureIntegrationTest { private static final String TAG = AbstractContentCaptureIntegrationTest.class.getSimpleName(); protected static final DeviceConfigStateManager sKillSwitchManager = new DeviceConfigStateManager(sContext, DeviceConfig.NAMESPACE_CONTENT_CAPTURE, ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED); protected final String mTag = getClass().getSimpleName(); private final RequiredServiceRule mRequiredServiceRule = new RequiredServiceRule(CONTENT_CAPTURE_MANAGER_SERVICE); private final DeviceConfigStateChangerRule mVerboseLoggingRule = new DeviceConfigStateChangerRule( sContext, DeviceConfig.NAMESPACE_CONTENT_CAPTURE, ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL, Integer.toString(ContentCaptureManager.LOGGING_LEVEL_VERBOSE)); private final ContentCaptureLoggingTestRule mLoggingRule = new ContentCaptureLoggingTestRule(); /** * Watcher set on {@link #enableService()} and used to wait until it's gone after the test * finishes. */ private ServiceWatcher mServiceWatcher; protected final SafeCleanerRule mSafeCleanerRule = new SafeCleanerRule() .setDumper(mLoggingRule) .add(() -> { return CtsContentCaptureService.getExceptions(); }); private final TestRule mServiceDisablerRule = (base, description) -> { return new Statement() { @Override public void evaluate() throws Throwable { try { base.evaluate(); } finally { Log.v(mTag, "@mServiceDisablerRule: safelyDisableService()"); safelyDisableService(); } } }; }; private void safelyDisableService() { try { resetService(); if (mServiceWatcher != null) { mServiceWatcher.waitOnDestroy(); } } catch (Throwable t) { Log.e(TAG, "error disabling service", t); } } private final DeviceConfigStateChangerRule mKillSwitchKillerRule = new DeviceConfigStateChangerRule(sKillSwitchManager, "true"); private final SettingsStateChangerRule mFeatureEnablerRule = new SettingsStateChangerRule( sContext, CONTENT_CAPTURE_ENABLED, "1"); @Rule public final RuleChain mLookAllTheseRules = RuleChain // mRequiredServiceRule should be first so the test can be skipped right away .outerRule(mRequiredServiceRule) // service must be disable at the last step, otherwise it's contents are not dump in // case of error .around(mServiceDisablerRule) // log everything .around(mVerboseLoggingRule) // enable it as soon as possible, as it have to wait for the listener .around(mKillSwitchKillerRule) .around(mFeatureEnablerRule) // mLoggingRule wraps the test but doesn't interfere with it .around(mLoggingRule) // mSafeCleanerRule will catch errors .around(mSafeCleanerRule) // Finally, let subclasses set their own rule .around(getMainTestRule()); /** * Hack to make sure ContentCapture is available for the CTS test package. * *

It must be set here because when the application starts it queries the server, at which * point our service is not set yet. */ // TODO: remove this hack if we ever split the CTS module in multiple APKs @BeforeClass public static void whitelistSelf() { final ContentCaptureOptions options = ContentCaptureOptions.forWhitelistingItself(); Log.v(TAG, "@BeforeClass: whitelistSelf(): options=" + options); sContext.getApplicationContext().setContentCaptureOptions(options); } @AfterClass public static void unWhitelistSelf() { Log.v(TAG, "@afterClass: unWhitelistSelf()"); sContext.getApplicationContext().setContentCaptureOptions(null); } @BeforeClass public static void disableDefaultService() { Log.v(TAG, "@BeforeClass: disableDefaultService()"); Helper.setDefaultServiceEnabled(false); } @AfterClass public static void enableDefaultService() { Log.v(TAG, "@AfterClass: enableDefaultService()"); Helper.setDefaultServiceEnabled(true); } @Before public void prepareDevice() throws Exception { Log.v(mTag, "@Before: prepareDevice()"); // Unlock screen. runShellCommand("input keyevent KEYCODE_WAKEUP"); // Dismiss keyguard, in case it's set as "Swipe to unlock". runShellCommand("wm dismiss-keyguard"); // Collapse notifications. runShellCommand("cmd statusbar collapse"); } @Before public void clearState() { Log.v(mTag, "@Before: clearState()"); CtsContentCaptureService.resetStaticState(); } @After public void clearServiceWatcher() { Log.v(mTag, "@After: clearServiceWatcher()"); CtsContentCaptureService.clearServiceWatcher(); } @Nullable public static void setFeatureEnabledBySettings(@Nullable boolean enabled) { sUserSettings.syncSet(CONTENT_CAPTURE_ENABLED, enabled ? "1" : "0"); } /** * Sets {@link CtsContentCaptureService} as the service for the current user and waits until * its created, then allowlist the CTS test package. */ public CtsContentCaptureService enableService() throws InterruptedException { return enableService(toSet(MY_PACKAGE), /* whitelistedComponents= */ null); } public CtsContentCaptureService enableService(@Nullable Set whitelistedPackages, @Nullable Set whitelistedComponents) throws InterruptedException { return enableService(new Pair<>(whitelistedPackages, whitelistedComponents)); } public CtsContentCaptureService enableService( @Nullable Pair, Set> whitelist) throws InterruptedException { if (mServiceWatcher != null) { throw new IllegalStateException("There Can Be Only One!"); } mServiceWatcher = CtsContentCaptureService.setServiceWatcher(); setService(CtsContentCaptureService.SERVICE_NAME); mServiceWatcher.whitelist(whitelist); return mServiceWatcher.waitOnCreate(); } /** * Gets the test-specific {@link Rule}. */ @NonNull protected abstract TestRule getMainTestRule(); }