Merge "Add side loaded listener and controller" into rvc-dev am: bf3079a2ba am: 43e7ffa9b9 am: 6f8511b82f
Change-Id: Id8900b0347954b0062c8db99b8d6cf845bc464af
This commit is contained in:
@@ -111,5 +111,6 @@
|
||||
<item>com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier</item>
|
||||
<item>com.android.systemui.car.window.SystemUIOverlayWindowManager</item>
|
||||
<item>com.android.systemui.car.volume.VolumeUI</item>
|
||||
<item>com.android.systemui.car.sideloaded.SideLoadedAppController</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.android.systemui.biometrics.AuthController;
|
||||
import com.android.systemui.bubbles.dagger.BubbleModule;
|
||||
import com.android.systemui.car.navigationbar.CarNavigationBar;
|
||||
import com.android.systemui.car.notification.CarNotificationModule;
|
||||
import com.android.systemui.car.sideloaded.SideLoadedAppController;
|
||||
import com.android.systemui.car.statusbar.CarStatusBar;
|
||||
import com.android.systemui.car.statusbar.CarStatusBarModule;
|
||||
import com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier;
|
||||
@@ -192,4 +193,10 @@ public abstract class CarSystemUIBinder {
|
||||
@IntoMap
|
||||
@ClassKey(SystemUIOverlayWindowManager.class)
|
||||
public abstract SystemUI bindSystemUIPrimaryWindowManager(SystemUIOverlayWindowManager sysui);
|
||||
|
||||
/** Inject into SideLoadedAppController. */
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(SideLoadedAppController.class)
|
||||
public abstract SystemUI bindSideLoadedAppController(SideLoadedAppController sysui);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.systemui.car.sideloaded;
|
||||
|
||||
import android.app.IActivityTaskManager;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.SystemUI;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Controller responsible for detecting unsafe apps.
|
||||
*/
|
||||
@Singleton
|
||||
public class SideLoadedAppController extends SystemUI {
|
||||
private static final String TAG = SideLoadedAppController.class.getSimpleName();
|
||||
|
||||
private IActivityTaskManager mActivityTaskManager;
|
||||
private SideLoadedAppListener mSideLoadedAppListener;
|
||||
private SideLoadedAppDetector mSideLoadedAppDetector;
|
||||
private SideLoadedAppStateController mSideLoadedAppStateController;
|
||||
|
||||
@Inject
|
||||
public SideLoadedAppController(Context context,
|
||||
IActivityTaskManager activityTaskManager,
|
||||
SideLoadedAppDetector sideLoadedAppDetector,
|
||||
SideLoadedAppListener sideLoadedAppListener,
|
||||
SideLoadedAppStateController sideLoadedAppStateController) {
|
||||
super(context);
|
||||
|
||||
mSideLoadedAppDetector = sideLoadedAppDetector;
|
||||
mActivityTaskManager = activityTaskManager;
|
||||
mSideLoadedAppListener = sideLoadedAppListener;
|
||||
mSideLoadedAppStateController = sideLoadedAppStateController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBootCompleted() {
|
||||
Log.i(TAG, "OnBootCompleted");
|
||||
|
||||
try {
|
||||
mActivityTaskManager.registerTaskStackListener(mSideLoadedAppListener);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not register car side loaded app listener.", e);
|
||||
}
|
||||
|
||||
if (mSideLoadedAppDetector.hasUnsafeInstalledApps()) {
|
||||
mSideLoadedAppStateController.onUnsafeInstalledAppsDetected();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,15 +42,15 @@ import javax.inject.Singleton;
|
||||
* An app is considered safe if is a system app or installed through whitelisted sources.
|
||||
*/
|
||||
@Singleton
|
||||
public class CarSideLoadedAppDetector {
|
||||
private static final String TAG = "CarSideLoadedDetector";
|
||||
public class SideLoadedAppDetector {
|
||||
private static final String TAG = SideLoadedAppDetector.class.getSimpleName();
|
||||
|
||||
private final PackageManager mPackageManager;
|
||||
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
|
||||
private final List<String> mAllowedAppInstallSources;
|
||||
|
||||
@Inject
|
||||
public CarSideLoadedAppDetector(@Main Resources resources, PackageManager packageManager,
|
||||
public SideLoadedAppDetector(@Main Resources resources, PackageManager packageManager,
|
||||
CarDeviceProvisionedController deviceProvisionedController) {
|
||||
mAllowedAppInstallSources = Arrays.asList(
|
||||
resources.getStringArray(R.array.config_allowedAppInstallSources));
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.systemui.car.sideloaded;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.StackInfo;
|
||||
import android.app.IActivityTaskManager;
|
||||
import android.app.TaskStackListener;
|
||||
import android.content.ComponentName;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* A TaskStackListener to detect when an unsafe app is launched/foregrounded.
|
||||
*/
|
||||
public class SideLoadedAppListener extends TaskStackListener {
|
||||
private static final String TAG = SideLoadedAppListener.class.getSimpleName();
|
||||
|
||||
private IActivityTaskManager mActivityTaskManager;
|
||||
private DisplayManager mDisplayManager;
|
||||
private SideLoadedAppDetector mSideLoadedAppDetector;
|
||||
private SideLoadedAppStateController mSideLoadedAppStateController;
|
||||
|
||||
@Inject
|
||||
SideLoadedAppListener(SideLoadedAppDetector sideLoadedAppDetector,
|
||||
IActivityTaskManager activityTaskManager,
|
||||
DisplayManager displayManager,
|
||||
SideLoadedAppStateController sideLoadedAppStateController) {
|
||||
mSideLoadedAppDetector = sideLoadedAppDetector;
|
||||
mActivityTaskManager = activityTaskManager;
|
||||
mDisplayManager = displayManager;
|
||||
mSideLoadedAppStateController = sideLoadedAppStateController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
|
||||
super.onTaskCreated(taskId, componentName);
|
||||
|
||||
List<StackInfo> stackInfoList = mActivityTaskManager.getAllStackInfos();
|
||||
ActivityManager.StackInfo stackInfo = getStackInfo(stackInfoList, taskId);
|
||||
if (stackInfo == null) {
|
||||
Log.e(TAG, "Stack info was not available for taskId: " + taskId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mSideLoadedAppDetector.isSafe(stackInfo)) {
|
||||
Display display = mDisplayManager.getDisplay(stackInfo.displayId);
|
||||
mSideLoadedAppStateController.onUnsafeTaskCreatedOnDisplay(display);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskStackChanged() throws RemoteException {
|
||||
super.onTaskStackChanged();
|
||||
|
||||
Display[] displays = mDisplayManager.getDisplays();
|
||||
for (Display display : displays) {
|
||||
// Note that the stackInfoList is ordered by recency.
|
||||
List<StackInfo> stackInfoList =
|
||||
mActivityTaskManager.getAllStackInfosOnDisplay(display.getDisplayId());
|
||||
|
||||
if (stackInfoList == null) {
|
||||
continue;
|
||||
}
|
||||
StackInfo stackInfo = getTopVisibleStackInfo(stackInfoList);
|
||||
if (stackInfo == null) {
|
||||
continue;
|
||||
}
|
||||
if (mSideLoadedAppDetector.isSafe(stackInfo)) {
|
||||
mSideLoadedAppStateController.onSafeTaskDisplayedOnDisplay(display);
|
||||
} else {
|
||||
mSideLoadedAppStateController.onUnsafeTaskDisplayedOnDisplay(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns stack info for a given taskId.
|
||||
*/
|
||||
private ActivityManager.StackInfo getStackInfo(
|
||||
List<ActivityManager.StackInfo> stackInfoList, int taskId) {
|
||||
if (stackInfoList == null) {
|
||||
return null;
|
||||
}
|
||||
for (ActivityManager.StackInfo stackInfo : stackInfoList) {
|
||||
if (stackInfo.taskIds == null) {
|
||||
continue;
|
||||
}
|
||||
for (int stackTaskId : stackInfo.taskIds) {
|
||||
if (taskId == stackTaskId) {
|
||||
return stackInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first visible stackInfo.
|
||||
*/
|
||||
private ActivityManager.StackInfo getTopVisibleStackInfo(
|
||||
List<ActivityManager.StackInfo> stackInfoList) {
|
||||
for (ActivityManager.StackInfo stackInfo : stackInfoList) {
|
||||
if (stackInfo.visible) {
|
||||
return stackInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.systemui.car.sideloaded;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Manager responsible for displaying proper UI when an unsafe app is detected.
|
||||
*/
|
||||
@Singleton
|
||||
public class SideLoadedAppStateController {
|
||||
private static final String TAG = SideLoadedAppStateController.class.getSimpleName();
|
||||
|
||||
@Inject
|
||||
SideLoadedAppStateController() {
|
||||
}
|
||||
|
||||
void onUnsafeInstalledAppsDetected() {
|
||||
Log.d(TAG, "Unsafe installed apps detected.");
|
||||
}
|
||||
|
||||
void onUnsafeTaskCreatedOnDisplay(Display display) {
|
||||
Log.d(TAG, "Unsafe task created on display " + display.getDisplayId() + ".");
|
||||
}
|
||||
|
||||
void onSafeTaskDisplayedOnDisplay(Display display) {
|
||||
Log.d(TAG, "Safe task displayed on display " + display.getDisplayId() + ".");
|
||||
}
|
||||
|
||||
void onUnsafeTaskDisplayedOnDisplay(Display display) {
|
||||
Log.d(TAG, "Unsafe task displayed on display " + display.getDisplayId() + ".");
|
||||
}
|
||||
}
|
||||
@@ -47,14 +47,14 @@ import org.mockito.MockitoAnnotations;
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
@SmallTest
|
||||
public class CarSideLoadedAppDetectorTest extends SysuiTestCase {
|
||||
public class SideLoadedAppDetectorTest extends SysuiTestCase {
|
||||
|
||||
private static final String SAFE_VENDOR = "com.safe.vendor";
|
||||
private static final String UNSAFE_VENDOR = "com.unsafe.vendor";
|
||||
private static final String APP_PACKAGE_NAME = "com.test";
|
||||
private static final String APP_CLASS_NAME = ".TestClass";
|
||||
|
||||
private CarSideLoadedAppDetector mSideLoadedAppDetector;
|
||||
private SideLoadedAppDetector mSideLoadedAppDetector;
|
||||
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@@ -70,7 +70,7 @@ public class CarSideLoadedAppDetectorTest extends SysuiTestCase {
|
||||
testableResources.addOverride(R.array.config_allowedAppInstallSources,
|
||||
allowedAppInstallSources);
|
||||
|
||||
mSideLoadedAppDetector = new CarSideLoadedAppDetector(testableResources.getResources(),
|
||||
mSideLoadedAppDetector = new SideLoadedAppDetector(testableResources.getResources(),
|
||||
mPackageManager,
|
||||
mCarDeviceProvisionedController);
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.systemui.car.sideloaded;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager.StackInfo;
|
||||
import android.app.IActivityTaskManager;
|
||||
import android.content.ComponentName;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManagerGlobal;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayAdjustments;
|
||||
import android.view.DisplayInfo;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
@SmallTest
|
||||
public class SideLoadedAppListenerTest extends SysuiTestCase {
|
||||
|
||||
private static final String APP_PACKAGE_NAME = "com.test";
|
||||
private static final String APP_CLASS_NAME = ".TestClass";
|
||||
|
||||
private SideLoadedAppListener mSideLoadedAppListener;
|
||||
|
||||
@Mock
|
||||
private SideLoadedAppDetector mSideLoadedAppDetector;
|
||||
@Mock
|
||||
private DisplayManager mDisplayManager;
|
||||
@Mock
|
||||
private IActivityTaskManager mActivityTaskManager;
|
||||
@Mock
|
||||
private SideLoadedAppStateController mSideLoadedAppStateController;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mSideLoadedAppListener = new SideLoadedAppListener(mSideLoadedAppDetector,
|
||||
mActivityTaskManager, mDisplayManager, mSideLoadedAppStateController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTaskCreated_safeTask_callsNoMethods() throws Exception {
|
||||
int taskId = 999;
|
||||
int displayId = 123;
|
||||
ComponentName componentName = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
|
||||
|
||||
StackInfo stackInfo1 = createTask(1, /* isVisible= */ true);
|
||||
stackInfo1.taskIds = new int[] { 11, 22, 33 };
|
||||
|
||||
StackInfo stackInfo2 = createTask(2, /* isVisible= */ true);
|
||||
stackInfo2.taskIds = new int[] { 111, 222, 333, taskId };
|
||||
stackInfo2.displayId = displayId;
|
||||
|
||||
List<StackInfo> stackInfoList = Arrays.asList(stackInfo1, stackInfo2);
|
||||
|
||||
when(mActivityTaskManager.getAllStackInfos()).thenReturn(stackInfoList);
|
||||
when(mSideLoadedAppDetector.isSafe(stackInfo2)).thenReturn(true);
|
||||
|
||||
mSideLoadedAppListener.onTaskCreated(taskId, componentName);
|
||||
|
||||
verify(mSideLoadedAppDetector, never()).isSafe(stackInfo1);
|
||||
verify(mSideLoadedAppDetector).isSafe(stackInfo2);
|
||||
|
||||
verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
|
||||
verify(mSideLoadedAppStateController, never()).onSafeTaskDisplayedOnDisplay(any());
|
||||
verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTaskCreated_unsafeTask_callsUnsafeTaskCreated() throws Exception {
|
||||
int taskId = 999;
|
||||
int displayId = 123;
|
||||
ComponentName componentName = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
|
||||
|
||||
StackInfo stackInfo1 = createTask(1, /* isVisible= */ true);
|
||||
stackInfo1.taskIds = new int[] { 11, 22, 33 };
|
||||
StackInfo stackInfo2 = createTask(2, /* isVisible= */ true);
|
||||
stackInfo2.taskIds = new int[] { 111, 222, 333, taskId };
|
||||
stackInfo2.displayId = displayId;
|
||||
List<StackInfo> stackInfoList = Arrays.asList(stackInfo1, stackInfo2);
|
||||
|
||||
Display display = createDisplay(displayId);
|
||||
|
||||
when(mActivityTaskManager.getAllStackInfos()).thenReturn(stackInfoList);
|
||||
when(mSideLoadedAppDetector.isSafe(stackInfo2)).thenReturn(false);
|
||||
when(mDisplayManager.getDisplay(displayId)).thenReturn(display);
|
||||
|
||||
mSideLoadedAppListener.onTaskCreated(taskId, componentName);
|
||||
|
||||
verify(mSideLoadedAppDetector, never()).isSafe(stackInfo1);
|
||||
verify(mSideLoadedAppDetector).isSafe(stackInfo2);
|
||||
|
||||
verify(mSideLoadedAppStateController).onUnsafeTaskCreatedOnDisplay(display);
|
||||
verify(mSideLoadedAppStateController, never()).onSafeTaskDisplayedOnDisplay(any());
|
||||
verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTaskStackChanged_safeTask_callsSafeTaskDisplayed() throws Exception {
|
||||
Display display = createDisplay(123);
|
||||
StackInfo stackInfo1 = createTask(1, /* isVisible= */ false);
|
||||
StackInfo stackInfo2 = createTask(2, /* isVisible= */ true);
|
||||
StackInfo stackInfo3 = createTask(3, /* isVisible= */ true);
|
||||
List<StackInfo> stackInfoList = Arrays.asList(stackInfo1, stackInfo2, stackInfo3);
|
||||
|
||||
when(mActivityTaskManager.getAllStackInfosOnDisplay(display.getDisplayId()))
|
||||
.thenReturn(stackInfoList);
|
||||
when(mSideLoadedAppDetector.isSafe(stackInfo2)).thenReturn(true);
|
||||
when(mDisplayManager.getDisplays()).thenReturn(new Display[] { display });
|
||||
|
||||
mSideLoadedAppListener.onTaskStackChanged();
|
||||
|
||||
verify(mSideLoadedAppDetector, never()).isSafe(stackInfo1);
|
||||
verify(mSideLoadedAppDetector).isSafe(stackInfo2);
|
||||
verify(mSideLoadedAppDetector, never()).isSafe(stackInfo3);
|
||||
|
||||
verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
|
||||
verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display);
|
||||
verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTaskStackChanged_unsafeTask_callsUnsafeTaskDisplayed() throws Exception {
|
||||
Display display = createDisplay(123);
|
||||
StackInfo stackInfo1 = createTask(1, /* isVisible= */ false);
|
||||
StackInfo stackInfo2 = createTask(2, /* isVisible= */ true);
|
||||
StackInfo stackInfo3 = createTask(3, /* isVisible= */ true);
|
||||
List<StackInfo> stackInfoList = Arrays.asList(stackInfo1, stackInfo2, stackInfo3);
|
||||
|
||||
when(mActivityTaskManager.getAllStackInfosOnDisplay(display.getDisplayId()))
|
||||
.thenReturn(stackInfoList);
|
||||
when(mSideLoadedAppDetector.isSafe(stackInfo2)).thenReturn(false);
|
||||
when(mDisplayManager.getDisplays()).thenReturn(new Display[] { display });
|
||||
|
||||
mSideLoadedAppListener.onTaskStackChanged();
|
||||
|
||||
verify(mSideLoadedAppDetector, never()).isSafe(stackInfo1);
|
||||
verify(mSideLoadedAppDetector).isSafe(stackInfo2);
|
||||
verify(mSideLoadedAppDetector, never()).isSafe(stackInfo3);
|
||||
|
||||
verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
|
||||
verify(mSideLoadedAppStateController, never()).onSafeTaskDisplayedOnDisplay(any());
|
||||
verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTaskStackChanged_multiDisplay_callsTasksDisplayed() throws Exception {
|
||||
Display display1 = createDisplay(1);
|
||||
StackInfo stackInfo1 = createTask(1, /* isVisible= */ false);
|
||||
StackInfo stackInfo2 = createTask(2, /* isVisible= */ true);
|
||||
StackInfo stackInfo3 = createTask(3, /* isVisible= */ true);
|
||||
List<StackInfo> display1Stack = Arrays.asList(stackInfo1, stackInfo2, stackInfo3);
|
||||
|
||||
Display display2 = createDisplay(2);
|
||||
StackInfo stackInfo4 = createTask(4, /* isVisible= */ true);
|
||||
List<StackInfo> display2Stack = Collections.singletonList(stackInfo4);
|
||||
|
||||
Display display3 = createDisplay(3);
|
||||
StackInfo stackInfo5 = createTask(5, /* isVisible= */ true);
|
||||
List<StackInfo> display3Stack = Collections.singletonList(stackInfo5);
|
||||
|
||||
when(mActivityTaskManager.getAllStackInfosOnDisplay(display1.getDisplayId()))
|
||||
.thenReturn(display1Stack);
|
||||
when(mActivityTaskManager.getAllStackInfosOnDisplay(display2.getDisplayId()))
|
||||
.thenReturn(display2Stack);
|
||||
when(mActivityTaskManager.getAllStackInfosOnDisplay(display3.getDisplayId()))
|
||||
.thenReturn(display3Stack);
|
||||
|
||||
when(mSideLoadedAppDetector.isSafe(stackInfo2)).thenReturn(true);
|
||||
when(mSideLoadedAppDetector.isSafe(stackInfo4)).thenReturn(false);
|
||||
when(mSideLoadedAppDetector.isSafe(stackInfo5)).thenReturn(true);
|
||||
|
||||
when(mDisplayManager.getDisplays())
|
||||
.thenReturn(new Display[] { display1, display2, display3});
|
||||
|
||||
mSideLoadedAppListener.onTaskStackChanged();
|
||||
|
||||
verify(mSideLoadedAppDetector, never()).isSafe(stackInfo1);
|
||||
verify(mSideLoadedAppDetector).isSafe(stackInfo2);
|
||||
verify(mSideLoadedAppDetector, never()).isSafe(stackInfo3);
|
||||
verify(mSideLoadedAppDetector).isSafe(stackInfo4);
|
||||
verify(mSideLoadedAppDetector).isSafe(stackInfo5);
|
||||
|
||||
verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
|
||||
verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display1);
|
||||
verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display2);
|
||||
verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display3);
|
||||
verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display1);
|
||||
verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display2);
|
||||
verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display3);
|
||||
}
|
||||
|
||||
private Display createDisplay(int id) {
|
||||
return new Display(DisplayManagerGlobal.getInstance(),
|
||||
id,
|
||||
new DisplayInfo(),
|
||||
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
|
||||
}
|
||||
|
||||
private StackInfo createTask(int id, boolean isVisible) {
|
||||
StackInfo stackInfo = new StackInfo();
|
||||
stackInfo.stackId = id;
|
||||
stackInfo.visible = isVisible;
|
||||
return stackInfo;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user