blob: 6d514b20e831a3002f648c1de44a290674c38931 [file] [log] [blame]
/*
* Copyright (C) 2019 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 com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
import static android.view.Display.DEFAULT_DISPLAY;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.withSettings;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.IApplicationThread;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.StrictMode;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.Log;
import android.view.InputChannel;
import android.view.SurfaceControl;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.server.AnimationThread;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.input.InputManagerService;
import com.android.server.pm.UserManagerService;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.mockito.MockSettings;
import org.mockito.Mockito;
import org.mockito.quality.Strictness;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* JUnit test rule to correctly setting up system services like {@link WindowManagerService}
* and {@link ActivityTaskManagerService} for tests.
*/
public class SystemServicesTestRule implements TestRule {
private static final String TAG = SystemServicesTestRule.class.getSimpleName();
static int sNextDisplayId = DEFAULT_DISPLAY + 100;
private static final int[] TEST_USER_PROFILE_IDS = {};
/** Use a real static object so there won't be NPE in finalize() after clearInlineMocks(). */
private static final PowerManager.WakeLock sWakeLock = getInstrumentation().getContext()
.getSystemService(PowerManager.class).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
private PowerManager.WakeLock mStubbedWakeLock;
/**
* The captured listeners will be unregistered in {@link #tearDown()} to avoid keeping static
* references of test instances from DeviceConfig.
*/
private final ArrayList<DeviceConfig.OnPropertiesChangedListener> mDeviceConfigListeners =
new ArrayList<>();
private Description mDescription;
private Context mContext;
private StaticMockitoSession mMockitoSession;
private ActivityTaskManagerService mAtmService;
private WindowManagerService mWmService;
private WindowState.PowerManagerWrapper mPowerManagerWrapper;
private InputManagerService mImService;
private InputChannel mInputChannel;
/**
* Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
*/
SurfaceControl.Transaction mTransaction;
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
mDescription = description;
Throwable throwable = null;
try {
runWithDexmakerShareClassLoader(SystemServicesTestRule.this::setUp);
base.evaluate();
} catch (Throwable t) {
throwable = t;
} finally {
try {
tearDown();
} catch (Throwable t) {
if (throwable != null) {
Log.e("SystemServicesTestRule", "Suppressed: ", throwable);
t.addSuppressed(throwable);
}
throwable = t;
}
}
if (throwable != null) throw throwable;
}
};
}
private void setUp() {
// Use stubOnly() to reduce memory usage if it doesn't need verification.
final MockSettings spyStubOnly = withSettings().stubOnly()
.defaultAnswer(CALLS_REAL_METHODS);
final MockSettings mockStubOnly = withSettings().stubOnly();
// Return mocked services: LocalServices.getService
// Avoid real operation: SurfaceControl.mirrorSurface
// Avoid leakage: DeviceConfig.addOnPropertiesChangedListener, LockGuard.installLock
// Watchdog.getInstance/addMonitor
mMockitoSession = mockitoSession()
.mockStatic(LocalServices.class, spyStubOnly)
.mockStatic(DeviceConfig.class, spyStubOnly)
.mockStatic(SurfaceControl.class, mockStubOnly)
.mockStatic(LockGuard.class, mockStubOnly)
.mockStatic(Watchdog.class, mockStubOnly)
.strictness(Strictness.LENIENT)
.startMocking();
setUpSystemCore();
setUpLocalServices();
setUpActivityTaskManagerService();
setUpWindowManagerService();
}
private void setUpSystemCore() {
doReturn(mock(Watchdog.class)).when(Watchdog::getInstance);
doAnswer(invocation -> {
// Exclude CONSTRAIN_DISPLAY_APIS because ActivityRecord#sConstrainDisplayApisConfig
// only registers once and it doesn't reference to outside.
if (!NAMESPACE_CONSTRAIN_DISPLAY_APIS.equals(invocation.getArgument(0))) {
mDeviceConfigListeners.add(invocation.getArgument(2));
}
// SizeCompatTests uses setNeverConstrainDisplayApisFlag, and ActivityRecordTests
// uses splash_screen_exception_list. So still execute real registration.
return invocation.callRealMethod();
}).when(() -> DeviceConfig.addOnPropertiesChangedListener(anyString(), any(), any()));
mContext = getInstrumentation().getTargetContext();
spyOn(mContext);
doReturn(null).when(mContext)
.registerReceiver(nullable(BroadcastReceiver.class), any(IntentFilter.class));
doReturn(null).when(mContext)
.registerReceiverAsUser(any(BroadcastReceiver.class), any(UserHandle.class),
any(IntentFilter.class), nullable(String.class), nullable(Handler.class));
final ContentResolver contentResolver = mContext.getContentResolver();
spyOn(contentResolver);
doNothing().when(contentResolver)
.registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class),
anyInt());
}
private void setUpLocalServices() {
// Tear down any local services just in case.
tearDownLocalServices();
// UriGrantsManagerInternal
final UriGrantsManagerInternal ugmi = mock(UriGrantsManagerInternal.class);
LocalServices.addService(UriGrantsManagerInternal.class, ugmi);
// AppOpsManager
final AppOpsManager aom = mock(AppOpsManager.class);
doReturn(aom).when(mContext).getSystemService(eq(Context.APP_OPS_SERVICE));
// DeviceStateManager
final DeviceStateManager dsm = mock(DeviceStateManager.class);
doReturn(dsm).when(mContext).getSystemService(eq(Context.DEVICE_STATE_SERVICE));
// Prevent "WakeLock finalized while still held: SCREEN_FROZEN".
final PowerManager pm = mock(PowerManager.class);
doReturn(pm).when(mContext).getSystemService(eq(Context.POWER_SERVICE));
mStubbedWakeLock = createStubbedWakeLock(false /* needVerification */);
doReturn(mStubbedWakeLock).when(pm).newWakeLock(anyInt(), anyString());
doReturn(mStubbedWakeLock).when(pm).newWakeLock(anyInt(), anyString(), anyInt());
// DisplayManagerInternal
final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class);
doReturn(dmi).when(() -> LocalServices.getService(eq(DisplayManagerInternal.class)));
// ColorDisplayServiceInternal
final ColorDisplayService.ColorDisplayServiceInternal cds =
mock(ColorDisplayService.ColorDisplayServiceInternal.class);
doReturn(cds).when(() -> LocalServices.getService(
eq(ColorDisplayService.ColorDisplayServiceInternal.class)));
final UsageStatsManagerInternal usmi = mock(UsageStatsManagerInternal.class);
LocalServices.addService(UsageStatsManagerInternal.class, usmi);
// PackageManagerInternal
final PackageManagerInternal packageManagerInternal = mock(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, packageManagerInternal);
doReturn(false).when(packageManagerInternal).isPermissionsReviewRequired(
anyString(), anyInt());
doReturn(null).when(packageManagerInternal).getDefaultHomeActivity(anyInt());
ComponentName systemServiceComponent = new ComponentName("android.test.system.service", "");
doReturn(systemServiceComponent).when(packageManagerInternal).getSystemUiServiceComponent();
// PowerManagerInternal
final PowerManagerInternal pmi = mock(PowerManagerInternal.class);
final PowerSaveState state = new PowerSaveState.Builder().build();
doReturn(state).when(pmi).getLowPowerState(anyInt());
doReturn(pmi).when(() -> LocalServices.getService(eq(PowerManagerInternal.class)));
// PermissionPolicyInternal
final PermissionPolicyInternal ppi = mock(PermissionPolicyInternal.class);
LocalServices.addService(PermissionPolicyInternal.class, ppi);
doReturn(true).when(ppi).checkStartActivity(any(), anyInt(), any());
// InputManagerService
mImService = mock(InputManagerService.class);
// InputChannel cannot be mocked because it may pass to InputEventReceiver.
final InputChannel[] inputChannels = InputChannel.openInputChannelPair(TAG);
inputChannels[0].dispose();
mInputChannel = inputChannels[1];
doReturn(mInputChannel).when(mImService).monitorInput(anyString(), anyInt());
doReturn(mInputChannel).when(mImService).createInputChannel(anyString());
// StatusBarManagerInternal
final StatusBarManagerInternal sbmi = mock(StatusBarManagerInternal.class);
doReturn(sbmi).when(() -> LocalServices.getService(eq(StatusBarManagerInternal.class)));
}
private void setUpActivityTaskManagerService() {
// ActivityManagerInternal
final ActivityManagerInternal amInternal =
mock(ActivityManagerInternal.class, withSettings().stubOnly());
doReturn(UserHandle.USER_SYSTEM).when(amInternal).getCurrentUserId();
doReturn(TEST_USER_PROFILE_IDS).when(amInternal).getCurrentProfileIds();
doReturn(true).when(amInternal).isUserRunning(anyInt(), anyInt());
doReturn(true).when(amInternal).hasStartedUserState(anyInt());
doReturn(false).when(amInternal).shouldConfirmCredentials(anyInt());
doReturn(false).when(amInternal).isActivityStartsLoggingEnabled();
LocalServices.addService(ActivityManagerInternal.class, amInternal);
final ActivityManagerService amService =
mock(ActivityManagerService.class, withSettings().stubOnly());
mAtmService = new TestActivityTaskManagerService(mContext, amService);
LocalServices.addService(ActivityTaskManagerInternal.class, mAtmService.getAtmInternal());
}
private void setUpWindowManagerService() {
mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
TestWindowManagerPolicy wmPolicy = new TestWindowManagerPolicy();
TestDisplayWindowSettingsProvider testDisplayWindowSettingsProvider =
new TestDisplayWindowSettingsProvider();
// Suppress StrictMode violation (DisplayWindowSettings) to avoid log flood.
DisplayThread.getHandler().post(StrictMode::allowThreadDiskWritesMask);
mWmService = WindowManagerService.main(
mContext, mImService, false, false, wmPolicy, mAtmService,
testDisplayWindowSettingsProvider, StubTransaction::new,
(unused) -> new MockSurfaceControlBuilder());
spyOn(mWmService);
spyOn(mWmService.mRoot);
// Invoked during {@link ActivityStack} creation.
doNothing().when(mWmService.mRoot).updateUIDsPresentOnDisplay();
// Always keep things awake.
doReturn(true).when(mWmService.mRoot).hasAwakeDisplay();
// Called when moving activity to pinned stack.
doNothing().when(mWmService.mRoot).ensureActivitiesVisible(any(),
anyInt(), anyBoolean(), anyBoolean());
spyOn(mWmService.mDisplayWindowSettings);
spyOn(mWmService.mDisplayWindowSettingsProvider);
// Setup factory classes to prevent calls to native code.
mTransaction = spy(StubTransaction.class);
// Return a spied Transaction class than can be used to verify calls.
mWmService.mTransactionFactory = () -> mTransaction;
mWmService.mSurfaceAnimationRunner = new SurfaceAnimationRunner(
null, null, mTransaction, mWmService.mPowerManagerInternal);
mWmService.onInitReady();
mAtmService.setWindowManager(mWmService);
mWmService.mDisplayEnabled = true;
mWmService.mDisplayReady = true;
// Set configuration for default display
mWmService.getDefaultDisplayContentLocked().reconfigureDisplayLocked();
// Mock default display, and home stack.
final DisplayContent display = mAtmService.mRootWindowContainer.getDefaultDisplay();
// Set default display to be in fullscreen mode. Devices with PC feature may start their
// default display in freeform mode but some of tests in WmTests have implicit assumption on
// that the default display is in fullscreen mode.
display.setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN);
spyOn(display);
final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
// Set the default focused TDA.
display.onLastFocusedTaskDisplayAreaChanged(taskDisplayArea);
spyOn(taskDisplayArea);
final Task homeStack = taskDisplayArea.getRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
spyOn(homeStack);
}
private void tearDown() {
mWmService.mRoot.forAllDisplayPolicies(DisplayPolicy::release);
// Unregister display listener from root to avoid issues with subsequent tests.
mContext.getSystemService(DisplayManager.class)
.unregisterDisplayListener(mAtmService.mRootWindowContainer);
for (int i = mDeviceConfigListeners.size() - 1; i >= 0; i--) {
DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigListeners.get(i));
}
// This makes sure the posted messages without delay are processed, e.g.
// DisplayPolicy#release, WindowManagerService#setAnimationScale.
waitUntilWindowManagerHandlersIdle();
// Clear all posted messages with delay, so they don't be executed at unexpected times.
cleanupWindowManagerHandlers();
// Needs to explicitly dispose current static threads because there could be messages
// scheduled at a later time, and all mocks are invalid when it's executed.
DisplayThread.dispose();
// Dispose SurfaceAnimationThread before AnimationThread does, so it won't create a new
// AnimationThread after AnimationThread disposed, see {@link
// AnimatorListenerAdapter#onAnimationEnd()}
SurfaceAnimationThread.dispose();
AnimationThread.dispose();
UiThread.dispose();
mInputChannel.dispose();
tearDownLocalServices();
// Reset priority booster because animation thread has been changed.
WindowManagerService.sThreadPriorityBooster = new WindowManagerThreadPriorityBooster();
mMockitoSession.finishMocking();
Mockito.framework().clearInlineMocks();
}
private static void tearDownLocalServices() {
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
LocalServices.removeServiceForTest(PowerManagerInternal.class);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.removeServiceForTest(WindowManagerPolicy.class);
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.removeServiceForTest(PermissionPolicyInternal.class);
LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
}
Description getDescription() {
return mDescription;
}
WindowManagerService getWindowManagerService() {
return mWmService;
}
ActivityTaskManagerService getActivityTaskManagerService() {
return mAtmService;
}
WindowState.PowerManagerWrapper getPowerManagerWrapper() {
return mPowerManagerWrapper;
}
/** Creates a no-op wakelock object. */
PowerManager.WakeLock createStubbedWakeLock(boolean needVerification) {
if (needVerification) {
return mock(PowerManager.WakeLock.class, Mockito.withSettings()
.spiedInstance(sWakeLock).defaultAnswer(Mockito.RETURNS_DEFAULTS));
}
return mock(PowerManager.WakeLock.class, Mockito.withSettings()
.spiedInstance(sWakeLock).stubOnly());
}
WindowProcessController addProcess(String pkgName, String procName, int pid, int uid) {
return addProcess(mAtmService, pkgName, procName, pid, uid);
}
static WindowProcessController addProcess(ActivityTaskManagerService atmService, String pkgName,
String procName, int pid, int uid) {
final ApplicationInfo info = new ApplicationInfo();
info.uid = uid;
info.packageName = pkgName;
return addProcess(atmService, info, procName, pid);
}
static WindowProcessController addProcess(ActivityTaskManagerService atmService,
ApplicationInfo info, String procName, int pid) {
final WindowProcessListener mockListener = mock(WindowProcessListener.class,
withSettings().stubOnly());
final int uid = info.uid;
final WindowProcessController proc = new WindowProcessController(atmService,
info, procName, uid, UserHandle.getUserId(uid), mockListener, mockListener);
proc.setThread(mock(IApplicationThread.class, withSettings().stubOnly()));
atmService.mProcessNames.put(procName, uid, proc);
if (pid > 0) {
proc.setPid(pid);
atmService.mProcessMap.put(pid, proc);
}
return proc;
}
void cleanupWindowManagerHandlers() {
final WindowManagerService wm = getWindowManagerService();
if (wm == null) {
return;
}
wm.mH.removeCallbacksAndMessages(null);
wm.mAnimationHandler.removeCallbacksAndMessages(null);
// This is a different handler object than the wm.mAnimationHandler above.
AnimationThread.getHandler().removeCallbacksAndMessages(null);
SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null);
}
void waitUntilWindowManagerHandlersIdle() {
final WindowManagerService wm = getWindowManagerService();
if (wm == null) {
return;
}
waitHandlerIdle(wm.mH);
waitHandlerIdle(wm.mAnimationHandler);
// This is a different handler object than the wm.mAnimationHandler above.
waitHandlerIdle(AnimationThread.getHandler());
waitHandlerIdle(SurfaceAnimationThread.getHandler());
}
static void waitHandlerIdle(Handler handler) {
handler.runWithScissors(() -> { }, 0 /* timeout */);
}
void waitUntilWindowAnimatorIdle() {
final WindowManagerService wm = getWindowManagerService();
if (wm == null) {
return;
}
// Add a message to the handler queue and make sure it is fully processed before we move on.
// This makes sure all previous messages in the handler are fully processed vs. just popping
// them from the message queue.
final AtomicBoolean currentMessagesProcessed = new AtomicBoolean(false);
wm.mAnimator.getChoreographer().postFrameCallback(time -> {
synchronized (currentMessagesProcessed) {
currentMessagesProcessed.set(true);
currentMessagesProcessed.notifyAll();
}
});
while (!currentMessagesProcessed.get()) {
synchronized (currentMessagesProcessed) {
try {
currentMessagesProcessed.wait();
} catch (InterruptedException e) {
}
}
}
}
/**
* Throws if caller doesn't hold the given lock.
* @param lock the lock
*/
static void checkHoldsLock(Object lock) {
if (!Thread.holdsLock(lock)) {
throw new IllegalStateException("Caller doesn't hold global lock.");
}
}
protected class TestActivityTaskManagerService extends ActivityTaskManagerService {
// ActivityTaskSupervisor may be created more than once while setting up AMS and ATMS.
// We keep the reference in order to prevent creating it twice.
ActivityTaskSupervisor mTestTaskSupervisor;
TestActivityTaskManagerService(Context context, ActivityManagerService ams) {
super(context);
spyOn(this);
mSupportsMultiWindow = true;
mSupportsMultiDisplay = true;
mSupportsSplitScreenMultiWindow = true;
mSupportsFreeformWindowManagement = true;
mSupportsPictureInPicture = true;
mDevEnableNonResizableMultiWindow = false;
mMinPercentageMultiWindowSupportHeight = 0.3f;
mMinPercentageMultiWindowSupportWidth = 0.5f;
mLargeScreenSmallestScreenWidthDp = 600;
mSupportsNonResizableMultiWindow = 0;
mRespectsActivityMinWidthHeightMultiWindow = 0;
mForceResizableActivities = false;
doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
// allow background activity starts by default
doReturn(true).when(this).isBackgroundActivityStartsEnabled();
doNothing().when(this).updateCpuStats();
// AppOpsService
final AppOpsManager aos = mock(AppOpsManager.class);
doReturn(aos).when(this).getAppOpsManager();
// Make sure permission checks aren't overridden.
doReturn(AppOpsManager.MODE_DEFAULT).when(aos).noteOpNoThrow(anyInt(), anyInt(),
anyString(), nullable(String.class), nullable(String.class));
// UserManagerService
final UserManagerService ums = mock(UserManagerService.class);
doReturn(ums).when(this).getUserManager();
doReturn(TEST_USER_PROFILE_IDS).when(ums).getProfileIds(anyInt(), eq(true));
setUsageStatsManager(LocalServices.getService(UsageStatsManagerInternal.class));
ams.mActivityTaskManager = this;
ams.mAtmInternal = mInternal;
onActivityManagerInternalAdded();
final IntentFirewall intentFirewall = mock(IntentFirewall.class);
doReturn(true).when(intentFirewall).checkStartActivity(
any(), anyInt(), anyInt(), nullable(String.class), any());
initialize(intentFirewall, null /* intentController */,
DisplayThread.getHandler().getLooper());
spyOn(getLifecycleManager());
spyOn(getLockTaskController());
spyOn(getTaskChangeNotificationController());
AppWarnings appWarnings = getAppWarningsLocked();
spyOn(appWarnings);
doNothing().when(appWarnings).onStartActivity(any());
}
@Override
int handleIncomingUser(int callingPid, int callingUid, int userId, String name) {
return userId;
}
@Override
protected ActivityTaskSupervisor createTaskSupervisor() {
if (mTestTaskSupervisor == null) {
mTestTaskSupervisor = new TestActivityTaskSupervisor(this, mH.getLooper());
}
return mTestTaskSupervisor;
}
}
/**
* An {@link ActivityTaskSupervisor} which stubs out certain methods that depend on
* setup not available in the test environment. Also specifies an injector for
*/
protected class TestActivityTaskSupervisor extends ActivityTaskSupervisor {
TestActivityTaskSupervisor(ActivityTaskManagerService service, Looper looper) {
super(service, looper);
spyOn(this);
// Do not schedule idle that may touch methods outside the scope of the test.
doNothing().when(this).scheduleIdle();
doNothing().when(this).scheduleIdleTimeout(any());
// unit test version does not handle launch wake lock
doNothing().when(this).acquireLaunchWakelock();
mLaunchingActivityWakeLock = mStubbedWakeLock;
initialize();
final KeyguardController controller = getKeyguardController();
spyOn(controller);
doReturn(true).when(controller).checkKeyguardVisibility(any());
}
}
}