Merge "Added UserVisibilityListener logic to UserVisibilityMediator."
This commit is contained in:
@@ -634,7 +634,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
@GuardedBy("mUserStates")
|
||||
private final WatchedUserStates mUserStates = new WatchedUserStates();
|
||||
|
||||
private final UserVisibilityMediator mUserVisibilityMediator = new UserVisibilityMediator();
|
||||
private final UserVisibilityMediator mUserVisibilityMediator;
|
||||
|
||||
private static UserManagerService sInstance;
|
||||
|
||||
@@ -733,6 +733,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
mPackagesLock = packagesLock;
|
||||
mUsers = users != null ? users : new SparseArray<>();
|
||||
mHandler = new MainHandler();
|
||||
mUserVisibilityMediator = new UserVisibilityMediator(mHandler);
|
||||
mUserDataPreparer = userDataPreparer;
|
||||
mUserTypes = UserTypeFactory.getUserTypes();
|
||||
invalidateOwnerNameIfNecessary(context.getResources(), true /* forceUpdate */);
|
||||
|
||||
@@ -28,6 +28,7 @@ import static com.android.server.pm.UserManagerInternal.userAssignmentResultToSt
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Dumpable;
|
||||
@@ -40,9 +41,11 @@ import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.pm.UserManagerInternal.UserAssignmentResult;
|
||||
import com.android.server.pm.UserManagerInternal.UserVisibilityListener;
|
||||
import com.android.server.utils.Slogf;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* Class responsible for deciding whether a user is visible (or visible for a given display).
|
||||
@@ -110,15 +113,24 @@ public final class UserVisibilityMediator implements Dumpable {
|
||||
@GuardedBy("mLock")
|
||||
private final SparseIntArray mStartedProfileGroupIds = new SparseIntArray();
|
||||
|
||||
UserVisibilityMediator() {
|
||||
this(UserManager.isUsersOnSecondaryDisplaysEnabled());
|
||||
/**
|
||||
* Handler user to call listeners
|
||||
*/
|
||||
private final Handler mHandler;
|
||||
|
||||
// @GuardedBy("mLock") - hold lock for writes, no lock necessary for simple reads
|
||||
final CopyOnWriteArrayList<UserVisibilityListener> mListeners =
|
||||
new CopyOnWriteArrayList<>();
|
||||
|
||||
UserVisibilityMediator(Handler handler) {
|
||||
this(UserManager.isUsersOnSecondaryDisplaysEnabled(), handler);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
UserVisibilityMediator(boolean usersOnSecondaryDisplaysEnabled) {
|
||||
UserVisibilityMediator(boolean usersOnSecondaryDisplaysEnabled, Handler handler) {
|
||||
mUsersOnSecondaryDisplaysEnabled = usersOnSecondaryDisplaysEnabled;
|
||||
mUsersOnSecondaryDisplays = mUsersOnSecondaryDisplaysEnabled ? new SparseIntArray() : null;
|
||||
|
||||
mHandler = handler;
|
||||
// TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
|
||||
mStartedProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
|
||||
}
|
||||
@@ -151,6 +163,7 @@ public final class UserVisibilityMediator implements Dumpable {
|
||||
}
|
||||
|
||||
int result;
|
||||
IntArray visibleUsersBefore, visibleUsersAfter;
|
||||
synchronized (mLock) {
|
||||
result = getUserVisibilityOnStartLocked(userId, profileGroupId, foreground, displayId);
|
||||
if (DBG) {
|
||||
@@ -166,6 +179,8 @@ public final class UserVisibilityMediator implements Dumpable {
|
||||
return USER_ASSIGNMENT_RESULT_FAILURE;
|
||||
}
|
||||
|
||||
visibleUsersBefore = getVisibleUsers();
|
||||
|
||||
// Set current user / profiles state
|
||||
if (foreground) {
|
||||
mCurrentUserId = userId;
|
||||
@@ -195,8 +210,12 @@ public final class UserVisibilityMediator implements Dumpable {
|
||||
Slogf.wtf(TAG, "invalid resut from canAssignUserToDisplayLocked: %d",
|
||||
mappingResult);
|
||||
}
|
||||
|
||||
visibleUsersAfter = getVisibleUsers();
|
||||
}
|
||||
|
||||
dispatchVisibilityChanged(visibleUsersBefore, visibleUsersAfter);
|
||||
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "returning %s", userAssignmentResultToString(result));
|
||||
}
|
||||
@@ -320,29 +339,40 @@ public final class UserVisibilityMediator implements Dumpable {
|
||||
/**
|
||||
* See {@link UserManagerInternal#unassignUserFromDisplayOnStop(int)}.
|
||||
*/
|
||||
public void unassignUserFromDisplayOnStop(int userId) {
|
||||
public void unassignUserFromDisplayOnStop(@UserIdInt int userId) {
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "unassignUserFromDisplayOnStop(%d)", userId);
|
||||
}
|
||||
IntArray visibleUsersBefore, visibleUsersAfter;
|
||||
synchronized (mLock) {
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId,
|
||||
mStartedProfileGroupIds);
|
||||
}
|
||||
mStartedProfileGroupIds.delete(userId);
|
||||
visibleUsersBefore = getVisibleUsers();
|
||||
|
||||
if (!mUsersOnSecondaryDisplaysEnabled) {
|
||||
// Don't need to do update mUsersOnSecondaryDisplays because methods (such as
|
||||
// isUserVisible()) already know that the current user (and their profiles) is
|
||||
// assigned to the default display.
|
||||
return;
|
||||
}
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "Removing %d from mUsersOnSecondaryDisplays (%s)", userId,
|
||||
mUsersOnSecondaryDisplays);
|
||||
}
|
||||
mUsersOnSecondaryDisplays.delete(userId);
|
||||
unassignUserFromDisplayOnStopLocked(userId);
|
||||
|
||||
visibleUsersAfter = getVisibleUsers();
|
||||
}
|
||||
dispatchVisibilityChanged(visibleUsersBefore, visibleUsersAfter);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void unassignUserFromDisplayOnStopLocked(@UserIdInt int userId) {
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId,
|
||||
mStartedProfileGroupIds);
|
||||
}
|
||||
mStartedProfileGroupIds.delete(userId);
|
||||
|
||||
if (!mUsersOnSecondaryDisplaysEnabled) {
|
||||
// Don't need to do update mUsersOnSecondaryDisplays because methods (such as
|
||||
// isUserVisible()) already know that the current user (and their profiles) is
|
||||
// assigned to the default display.
|
||||
return;
|
||||
}
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "Removing %d from mUsersOnSecondaryDisplays (%s)", userId,
|
||||
mUsersOnSecondaryDisplays);
|
||||
}
|
||||
mUsersOnSecondaryDisplays.delete(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -351,18 +381,29 @@ public final class UserVisibilityMediator implements Dumpable {
|
||||
public boolean isUserVisible(@UserIdInt int userId) {
|
||||
// First check current foreground user and their profiles (on main display)
|
||||
if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "isUserVisible(%d): true to current user or profile", userId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Device doesn't support multiple users on multiple displays, so only users checked above
|
||||
// can be visible
|
||||
if (!mUsersOnSecondaryDisplaysEnabled) {
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "isUserVisible(%d): false for non-current user on MUMD", userId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean visible;
|
||||
synchronized (mLock) {
|
||||
return mUsersOnSecondaryDisplays.indexOfKey(userId) >= 0;
|
||||
visible = mUsersOnSecondaryDisplays.indexOfKey(userId) >= 0;
|
||||
}
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible);
|
||||
}
|
||||
return visible;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,6 +522,79 @@ public final class UserVisibilityMediator implements Dumpable {
|
||||
return visibleUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link UserVisibilityListener listener}.
|
||||
*/
|
||||
public void addListener(UserVisibilityListener listener) {
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "adding listener %s", listener);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a {@link UserVisibilityListener listener}.
|
||||
*/
|
||||
public void removeListener(UserVisibilityListener listener) {
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "removing listener %s", listener);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nofify all listeners about the visibility changes from before / after a change of state.
|
||||
*/
|
||||
private void dispatchVisibilityChanged(IntArray visibleUsersBefore,
|
||||
IntArray visibleUsersAfter) {
|
||||
if (visibleUsersBefore == null) {
|
||||
// Optimization - it's only null when listeners is empty
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "dispatchVisibilityChanged(): ignoring, no listeners");
|
||||
}
|
||||
return;
|
||||
}
|
||||
CopyOnWriteArrayList<UserVisibilityListener> listeners = mListeners;
|
||||
if (DBG) {
|
||||
Slogf.d(TAG,
|
||||
"dispatchVisibilityChanged(): visibleUsersBefore=%s, visibleUsersAfter=%s, "
|
||||
+ "%d listeners (%s)", visibleUsersBefore, visibleUsersAfter, listeners.size(),
|
||||
mListeners);
|
||||
}
|
||||
for (int i = 0; i < visibleUsersBefore.size(); i++) {
|
||||
int userId = visibleUsersBefore.get(i);
|
||||
if (visibleUsersAfter.indexOf(userId) == -1) {
|
||||
dispatchVisibilityChanged(listeners, userId, /* visible= */ false);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < visibleUsersAfter.size(); i++) {
|
||||
int userId = visibleUsersAfter.get(i);
|
||||
if (visibleUsersBefore.indexOf(userId) == -1) {
|
||||
dispatchVisibilityChanged(listeners, userId, /* visible= */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchVisibilityChanged(CopyOnWriteArrayList<UserVisibilityListener> listeners,
|
||||
@UserIdInt int userId, boolean visible) {
|
||||
if (DBG) {
|
||||
Slogf.d(TAG, "dispatchVisibilityChanged(%d -> %b): sending to %d listeners",
|
||||
userId, visible, listeners.size());
|
||||
}
|
||||
for (int i = 0; i < mListeners.size(); i++) {
|
||||
UserVisibilityListener listener = mListeners.get(i);
|
||||
if (DBG) {
|
||||
Slogf.v(TAG, "dispatchVisibilityChanged(%d -> %b): sending to %s",
|
||||
userId, visible, listener);
|
||||
}
|
||||
mHandler.post(() -> listener.onUserVisibilityChanged(userId, visible));
|
||||
}
|
||||
}
|
||||
|
||||
private void dump(IndentingPrintWriter ipw) {
|
||||
ipw.println("UserVisibilityMediator");
|
||||
ipw.increaseIndent();
|
||||
@@ -504,6 +618,18 @@ public final class UserVisibilityMediator implements Dumpable {
|
||||
dumpSparseIntArray(ipw, mUsersOnSecondaryDisplays,
|
||||
"background user / secondary display", "u", "d");
|
||||
}
|
||||
int numberListeners = mListeners.size();
|
||||
ipw.print("Number of listeners: ");
|
||||
ipw.println(numberListeners);
|
||||
if (numberListeners > 0) {
|
||||
ipw.increaseIndent();
|
||||
for (int i = 0; i < numberListeners; i++) {
|
||||
ipw.print(i);
|
||||
ipw.print(": ");
|
||||
ipw.println(mListeners.get(i));
|
||||
}
|
||||
ipw.decreaseIndent();
|
||||
}
|
||||
}
|
||||
|
||||
ipw.decreaseIndent();
|
||||
|
||||
@@ -43,7 +43,7 @@ public abstract class ExtendedMockitoTestCase {
|
||||
|
||||
private MockitoSession mSession;
|
||||
|
||||
private final Expect mExpect = Expect.create();
|
||||
protected final Expect mExpect = Expect.create();
|
||||
protected final DumpableDumperRule mDumpableDumperRule = new DumpableDumperRule();
|
||||
|
||||
@Rule
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.pm;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.pm.UserManagerInternal.UserVisibilityListener;
|
||||
|
||||
import com.google.common.truth.Expect;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* {@link UserVisibilityListener} implementation that expects callback events to be asynchronously
|
||||
* received.
|
||||
*/
|
||||
public final class AsyncUserVisibilityListener implements UserVisibilityListener {
|
||||
|
||||
private static final String TAG = AsyncUserVisibilityListener.class.getSimpleName();
|
||||
|
||||
private static final long WAIT_TIMEOUT_MS = 2_000;
|
||||
private static final long WAIT_NO_EVENTS_TIMEOUT_MS = 1_000;
|
||||
|
||||
private static int sNextId;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final Expect mExpect;
|
||||
private final int mId = ++sNextId;
|
||||
private final Thread mExpectedReceiverThread;
|
||||
private final CountDownLatch mLatch;
|
||||
private final List<UserVisibilityChangedEvent> mExpectedEvents;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final List<UserVisibilityChangedEvent> mReceivedEvents = new ArrayList<>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final List<String> mErrors = new ArrayList<>();
|
||||
|
||||
private AsyncUserVisibilityListener(Expect expect, Thread expectedReceiverThread,
|
||||
List<UserVisibilityChangedEvent> expectedEvents) {
|
||||
mExpect = expect;
|
||||
mExpectedReceiverThread = expectedReceiverThread;
|
||||
mExpectedEvents = expectedEvents;
|
||||
mLatch = new CountDownLatch(expectedEvents.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserVisibilityChanged(int userId, boolean visible) {
|
||||
UserVisibilityChangedEvent event = new UserVisibilityChangedEvent(userId, visible);
|
||||
Thread callingThread = Thread.currentThread();
|
||||
Log.d(TAG, "Received event (" + event + ") on thread " + callingThread);
|
||||
|
||||
if (callingThread != mExpectedReceiverThread) {
|
||||
addError("event %s received in on thread %s but was expected on thread %s",
|
||||
event, callingThread, mExpectedReceiverThread);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mReceivedEvents.add(event);
|
||||
mLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the expected events were called.
|
||||
*/
|
||||
public void verify() throws InterruptedException {
|
||||
waitForEventsAndCheckErrors();
|
||||
|
||||
List<UserVisibilityChangedEvent> receivedEvents = getReceivedEvents();
|
||||
|
||||
if (receivedEvents.isEmpty()) {
|
||||
mExpect.withMessage("received events").that(receivedEvents).isEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: check "inOrder" might be too harsh in some cases (for example, if the fg user
|
||||
// has 2 profiles, the order of the events on the profiles wouldn't matter), but we
|
||||
// still need some dependency (like "user A became invisible before user B became
|
||||
// visible", so this is fine for now (but eventually we might need to add more
|
||||
// sophisticated assertions)
|
||||
mExpect.withMessage("received events").that(receivedEvents)
|
||||
.containsExactlyElementsIn(mExpectedEvents).inOrder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
List<UserVisibilityChangedEvent> receivedEvents = getReceivedEvents();
|
||||
return "[" + getClass().getSimpleName() + ": id=" + mId
|
||||
+ ", creationThread=" + mExpectedReceiverThread
|
||||
+ ", received=" + receivedEvents.size()
|
||||
+ ", events=" + receivedEvents + "]";
|
||||
}
|
||||
|
||||
private List<UserVisibilityChangedEvent> getReceivedEvents() {
|
||||
synchronized (mLock) {
|
||||
return Collections.unmodifiableList(mReceivedEvents);
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForEventsAndCheckErrors() throws InterruptedException {
|
||||
waitForEvents();
|
||||
synchronized (mLock) {
|
||||
if (!mErrors.isEmpty()) {
|
||||
fail(mErrors.size() + " errors on received events: " + mErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForEvents() throws InterruptedException {
|
||||
if (mExpectedEvents.isEmpty()) {
|
||||
Log.v(TAG, "Sleeping " + WAIT_NO_EVENTS_TIMEOUT_MS + "ms to make sure no event is "
|
||||
+ "received");
|
||||
Thread.sleep(WAIT_NO_EVENTS_TIMEOUT_MS);
|
||||
return;
|
||||
}
|
||||
|
||||
int expectedNumberEvents = mExpectedEvents.size();
|
||||
Log.v(TAG, "Waiting up to " + WAIT_TIMEOUT_MS + "ms until " + expectedNumberEvents
|
||||
+ " events are received");
|
||||
if (!mLatch.await(WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
|
||||
List<UserVisibilityChangedEvent> receivedEvents = getReceivedEvents();
|
||||
addError("Timed out (%d ms) waiting for %d events; received %d so far (%s), "
|
||||
+ "but expecting %d (%s)", WAIT_NO_EVENTS_TIMEOUT_MS, expectedNumberEvents,
|
||||
receivedEvents.size(), receivedEvents, expectedNumberEvents, mExpectedEvents);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("AnnotateFormatMethod")
|
||||
private void addError(String format, Object...args) {
|
||||
synchronized (mLock) {
|
||||
mErrors.add(String.format(format, args));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for {@link AsyncUserVisibilityListener} objects.
|
||||
*/
|
||||
public static final class Factory {
|
||||
private final Expect mExpect;
|
||||
private final Thread mExpectedReceiverThread;
|
||||
|
||||
public Factory(Expect expect, Thread expectedReceiverThread) {
|
||||
mExpect = expect;
|
||||
mExpectedReceiverThread = expectedReceiverThread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link AsyncUserVisibilityListener} that is expecting the given events.
|
||||
*/
|
||||
public AsyncUserVisibilityListener forEvents(UserVisibilityChangedEvent...expectedEvents) {
|
||||
return new AsyncUserVisibilityListener(mExpect, mExpectedReceiverThread,
|
||||
Arrays.asList(expectedEvents));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link AsyncUserVisibilityListener} that is expecting no events.
|
||||
*/
|
||||
public AsyncUserVisibilityListener forNoEvents() {
|
||||
return new AsyncUserVisibilityListener(mExpect, mExpectedReceiverThread,
|
||||
Collections.emptyList());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.pm;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
|
||||
/**
|
||||
* Representation of a {@link UserManagerInternal.UserVisibilityListener} event.
|
||||
*/
|
||||
public final class UserVisibilityChangedEvent {
|
||||
|
||||
public @UserIdInt int userId;
|
||||
public boolean visible;
|
||||
|
||||
UserVisibilityChangedEvent(@UserIdInt int userId, boolean visible) {
|
||||
this.userId = userId;
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + userId;
|
||||
result = prime * result + (visible ? 1231 : 1237);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
UserVisibilityChangedEvent other = (UserVisibilityChangedEvent) obj;
|
||||
if (userId != other.userId) return false;
|
||||
if (visible != other.visible) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return userId + ":" + (visible ? "visible" : "invisible");
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method.
|
||||
*/
|
||||
public static UserVisibilityChangedEvent onVisible(@UserIdInt int userId) {
|
||||
return new UserVisibilityChangedEvent(userId, /* visible= */ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method.
|
||||
*/
|
||||
public static UserVisibilityChangedEvent onInvisible(@UserIdInt int userId) {
|
||||
return new UserVisibilityChangedEvent(userId, /* visible= */ false);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import static android.view.Display.INVALID_DISPLAY;
|
||||
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
|
||||
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
|
||||
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
|
||||
import static com.android.server.pm.UserVisibilityChangedEvent.onVisible;
|
||||
import static com.android.server.pm.UserVisibilityMediator.INITIAL_CURRENT_USER_ID;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -34,28 +35,38 @@ import org.junit.Test;
|
||||
*/
|
||||
public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediatorTestCase {
|
||||
|
||||
public UserVisibilityMediatorMUMDTest() {
|
||||
public UserVisibilityMediatorMUMDTest() throws Exception {
|
||||
super(/* usersOnSecondaryDisplaysEnabled= */ true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartFgUser_onInvalidDisplay() {
|
||||
public void testStartFgUser_onInvalidDisplay() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG, INVALID_DISPLAY);
|
||||
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartBgUser_onInvalidDisplay() {
|
||||
public void testStartBgUser_onInvalidDisplay() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG, INVALID_DISPLAY);
|
||||
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
|
||||
|
||||
expectUserIsNotVisibleAtAll(USER_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartBgUser_onSecondaryDisplay_displayAvailable() {
|
||||
public void testStartBgUser_onSecondaryDisplay_displayAvailable() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(USER_ID));
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG,
|
||||
SECONDARY_DISPLAY_ID);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
|
||||
@@ -68,10 +79,13 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
|
||||
|
||||
expectDisplayAssignedToUser(USER_ID, SECONDARY_DISPLAY_ID);
|
||||
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVisibilityOfCurrentUserAndProfilesOnDisplayAssignedToAnotherUser() {
|
||||
public void testVisibilityOfCurrentUserAndProfilesOnDisplayAssignedToAnotherUser()
|
||||
throws Exception {
|
||||
startDefaultProfile();
|
||||
|
||||
// Make sure they were visible before
|
||||
@@ -87,7 +101,8 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartBgUser_onSecondaryDisplay_displayAlreadyAssigned() {
|
||||
public void testStartBgUser_onSecondaryDisplay_displayAlreadyAssigned() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(OTHER_USER_ID));
|
||||
startUserInSecondaryDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID);
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG,
|
||||
@@ -97,10 +112,13 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
|
||||
expectUserIsNotVisibleAtAll(USER_ID);
|
||||
expectNoDisplayAssignedToUser(USER_ID);
|
||||
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, OTHER_USER_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartBgUser_onSecondaryDisplay_userAlreadyAssigned() {
|
||||
public void testStartBgUser_onSecondaryDisplay_userAlreadyAssigned() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(USER_ID));
|
||||
startUserInSecondaryDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG,
|
||||
@@ -116,10 +134,14 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
|
||||
|
||||
expectDisplayAssignedToUser(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
|
||||
expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, USER_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartBgProfile_onDefaultDisplay_whenParentVisibleOnSecondaryDisplay() {
|
||||
public void testStartBgProfile_onDefaultDisplay_whenParentVisibleOnSecondaryDisplay()
|
||||
throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
|
||||
startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
|
||||
@@ -129,5 +151,7 @@ public final class UserVisibilityMediatorMUMDTest extends UserVisibilityMediator
|
||||
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
|
||||
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
|
||||
expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@ package com.android.server.pm;
|
||||
|
||||
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
@@ -35,26 +33,18 @@ public final class UserVisibilityMediatorSUSDTest extends UserVisibilityMediator
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartBgUser_onSecondaryDisplay() {
|
||||
startUserInBackgroundOnSecondaryDisplayAndAssertFailure(USER_ID, USER_ID);
|
||||
public void testStartBgUser_onSecondaryDisplay() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
|
||||
expectNoUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartBgProfileUser_onSecondaryDisplay() {
|
||||
startForegroundUser(PARENT_USER_ID);
|
||||
|
||||
startUserInBackgroundOnSecondaryDisplayAndAssertFailure(PROFILE_USER_ID, PARENT_USER_ID);
|
||||
}
|
||||
|
||||
private void startUserInBackgroundOnSecondaryDisplayAndAssertFailure(@UserIdInt int userId,
|
||||
@UserIdInt int profileGroupId) {
|
||||
int result = mMediator.assignUserToDisplayOnStart(userId, profileGroupId, BG,
|
||||
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG,
|
||||
SECONDARY_DISPLAY_ID);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
|
||||
|
||||
expectUserIsNotVisibleAtAll(userId);
|
||||
expectNoDisplayAssignedToUser(userId);
|
||||
expectUserIsNotVisibleAtAll(USER_ID);
|
||||
expectNoDisplayAssignedToUser(USER_ID);
|
||||
|
||||
expectNoUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_F
|
||||
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
|
||||
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
|
||||
import static com.android.server.pm.UserManagerInternal.userAssignmentResultToString;
|
||||
import static com.android.server.pm.UserVisibilityChangedEvent.onInvisible;
|
||||
import static com.android.server.pm.UserVisibilityChangedEvent.onVisible;
|
||||
import static com.android.server.pm.UserVisibilityMediator.INITIAL_CURRENT_USER_ID;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
@@ -34,13 +36,16 @@ import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.IntArray;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.ExtendedMockitoTestCase;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -98,6 +103,11 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
protected static final boolean FG = true;
|
||||
protected static final boolean BG = false;
|
||||
|
||||
private static final HandlerThread sHandlerThread = new HandlerThread(TAG);
|
||||
|
||||
protected final AsyncUserVisibilityListener.Factory mListenerFactory =
|
||||
new AsyncUserVisibilityListener.Factory(mExpect, sHandlerThread);
|
||||
|
||||
private final boolean mUsersOnSecondaryDisplaysEnabled;
|
||||
|
||||
protected UserVisibilityMediator mMediator;
|
||||
@@ -106,9 +116,24 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
mUsersOnSecondaryDisplaysEnabled = usersOnSecondaryDisplaysEnabled;
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static final void startHandlerThread() {
|
||||
Log.d(TAG, "Starting handler thread " + sHandlerThread);
|
||||
sHandlerThread.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static final void quitHandlerThread() {
|
||||
Log.d(TAG, "Quitting handler thread " + sHandlerThread);
|
||||
if (!sHandlerThread.quit()) {
|
||||
Log.w(TAG, "sHandlerThread(" + sHandlerThread + ").quit() returned false");
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public final void setMediator() {
|
||||
mMediator = new UserVisibilityMediator(mUsersOnSecondaryDisplaysEnabled);
|
||||
public final void setFixtures() {
|
||||
mMediator = new UserVisibilityMediator(mUsersOnSecondaryDisplaysEnabled,
|
||||
sHandlerThread.getThreadHandler());
|
||||
mDumpableDumperRule.addDumpable(mMediator);
|
||||
}
|
||||
|
||||
@@ -125,7 +150,11 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testStartFgUser_onDefaultDisplay() {
|
||||
public final void testStartFgUser_onDefaultDisplay() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(
|
||||
onInvisible(INITIAL_CURRENT_USER_ID),
|
||||
onVisible(USER_ID));
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
|
||||
DEFAULT_DISPLAY);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
|
||||
@@ -144,12 +173,19 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
|
||||
|
||||
expectDisplayAssignedToUser(USER_NULL, INVALID_DISPLAY);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testSwitchFgUser_onDefaultDisplay() {
|
||||
public final void testSwitchFgUser_onDefaultDisplay() throws Exception {
|
||||
int previousCurrentUserId = OTHER_USER_ID;
|
||||
int currentUserId = USER_ID;
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(
|
||||
onInvisible(INITIAL_CURRENT_USER_ID),
|
||||
onVisible(previousCurrentUserId),
|
||||
onInvisible(previousCurrentUserId),
|
||||
onVisible(currentUserId));
|
||||
startForegroundUser(previousCurrentUserId);
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(currentUserId, currentUserId, FG,
|
||||
@@ -169,22 +205,29 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
|
||||
expectUserIsNotVisibleAtAll(previousCurrentUserId);
|
||||
expectNoDisplayAssignedToUser(previousCurrentUserId);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testStartFgUser_onSecondaryDisplay() {
|
||||
int userId = USER_ID;
|
||||
public final void testStartFgUser_onSecondaryDisplay() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(userId, userId, FG, SECONDARY_DISPLAY_ID);
|
||||
int result =
|
||||
mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG, SECONDARY_DISPLAY_ID);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
|
||||
|
||||
expectUserIsNotVisibleAtAll(userId);
|
||||
expectUserIsNotVisibleAtAll(USER_ID);
|
||||
expectNoDisplayAssignedToUser(USER_ID);
|
||||
expectNoUserAssignedToDisplay(DEFAULT_DISPLAY);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testStartBgUser_onDefaultDisplay() {
|
||||
public final void testStartBgUser_onDefaultDisplay() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG,
|
||||
DEFAULT_DISPLAY);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
|
||||
@@ -192,10 +235,15 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
expectUserIsNotVisibleAtAll(USER_ID);
|
||||
expectNoDisplayAssignedToUser(USER_ID);
|
||||
expectNoUserAssignedToDisplay(DEFAULT_DISPLAY);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testStartBgSystemUser_onSecondaryDisplay() {
|
||||
public final void testStartBgSystemUser_onSecondaryDisplay() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(
|
||||
onInvisible(INITIAL_CURRENT_USER_ID),
|
||||
onVisible(USER_ID));
|
||||
// Must explicitly set current user, as USER_SYSTEM is the default current user
|
||||
startForegroundUser(USER_ID);
|
||||
|
||||
@@ -207,10 +255,17 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
|
||||
expectNoDisplayAssignedToUser(USER_SYSTEM);
|
||||
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testStartBgProfile_onDefaultDisplay_whenParentIsCurrentUser() {
|
||||
public final void testStartBgProfile_onDefaultDisplay_whenParentIsCurrentUser()
|
||||
throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(
|
||||
onInvisible(INITIAL_CURRENT_USER_ID),
|
||||
onVisible(PARENT_USER_ID),
|
||||
onVisible(PROFILE_USER_ID));
|
||||
startForegroundUser(PARENT_USER_ID);
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
|
||||
@@ -226,10 +281,16 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
|
||||
expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testStopVisibleProfile() {
|
||||
public final void testStopVisibleProfile() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(
|
||||
onInvisible(INITIAL_CURRENT_USER_ID),
|
||||
onVisible(PARENT_USER_ID),
|
||||
onVisible(PROFILE_USER_ID),
|
||||
onInvisible(PROFILE_USER_ID));
|
||||
startDefaultProfile();
|
||||
|
||||
mMediator.unassignUserFromDisplayOnStop(PROFILE_USER_ID);
|
||||
@@ -237,10 +298,19 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
|
||||
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
|
||||
expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testVisibleProfileBecomesInvisibleWhenParentIsSwitchedOut() {
|
||||
public final void testVisibleProfileBecomesInvisibleWhenParentIsSwitchedOut() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForEvents(
|
||||
onInvisible(INITIAL_CURRENT_USER_ID),
|
||||
onVisible(PARENT_USER_ID),
|
||||
onVisible(PROFILE_USER_ID),
|
||||
onInvisible(PARENT_USER_ID),
|
||||
onInvisible(PROFILE_USER_ID),
|
||||
onVisible(OTHER_USER_ID));
|
||||
startDefaultProfile();
|
||||
|
||||
startForegroundUser(OTHER_USER_ID);
|
||||
@@ -248,20 +318,29 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
|
||||
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
|
||||
expectUserAssignedToDisplay(DEFAULT_DISPLAY, OTHER_USER_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testStartBgProfile_onDefaultDisplay_whenParentIsNotStarted() {
|
||||
public final void testStartBgProfile_onDefaultDisplay_whenParentIsNotStarted()
|
||||
throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
|
||||
DEFAULT_DISPLAY);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
|
||||
|
||||
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
|
||||
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testStartBgProfile_onDefaultDisplay_whenParentIsStartedOnBg() {
|
||||
public final void testStartBgProfile_onDefaultDisplay_whenParentIsStartedOnBg()
|
||||
throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
startBackgroundUser(PARENT_USER_ID);
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
|
||||
@@ -272,11 +351,15 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
|
||||
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
|
||||
expectNoUserAssignedToDisplay(DEFAULT_DISPLAY);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
// Not supported - profiles can only be started on default display
|
||||
@Test
|
||||
public final void testStartBgProfile_onSecondaryDisplay() {
|
||||
public final void testStartBgProfile_onSecondaryDisplay() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
|
||||
SECONDARY_DISPLAY_ID);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
|
||||
@@ -284,10 +367,14 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
|
||||
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
|
||||
expectNoUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testStartFgProfile_onDefaultDisplay() {
|
||||
public final void testStartFgProfile_onDefaultDisplay() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, FG,
|
||||
DEFAULT_DISPLAY);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
|
||||
@@ -296,10 +383,14 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
|
||||
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
|
||||
expectNoUserAssignedToDisplay(DEFAULT_DISPLAY);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testStartFgProfile_onSecondaryDisplay() {
|
||||
public final void testStartFgProfile_onSecondaryDisplay() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
|
||||
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, FG,
|
||||
SECONDARY_DISPLAY_ID);
|
||||
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
|
||||
@@ -307,10 +398,12 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
|
||||
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
|
||||
expectNoUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
|
||||
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testIsUserVisible_invalidUsers() {
|
||||
public final void testIsUserVisible_invalidUsers() throws Exception {
|
||||
expectWithMessage("isUserVisible(%s)", USER_NULL)
|
||||
.that(mMediator.isUserVisible(USER_NULL))
|
||||
.isFalse();
|
||||
@@ -325,6 +418,16 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testRemoveListener() throws Exception {
|
||||
AsyncUserVisibilityListener listener = addListenerForNoEvents();
|
||||
|
||||
mMediator.removeListener(listener);
|
||||
|
||||
startForegroundUser(USER_ID);
|
||||
listener.verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a user in foreground on the default display, asserting it was properly started.
|
||||
*
|
||||
@@ -397,6 +500,19 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
protected AsyncUserVisibilityListener addListenerForNoEvents() {
|
||||
AsyncUserVisibilityListener listener = mListenerFactory.forNoEvents();
|
||||
mMediator.addListener(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
protected AsyncUserVisibilityListener addListenerForEvents(
|
||||
UserVisibilityChangedEvent... events) {
|
||||
AsyncUserVisibilityListener listener = mListenerFactory.forEvents(events);
|
||||
mMediator.addListener(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
protected void assertStartUserResult(int actualResult, int expectedResult) {
|
||||
assertWithMessage("startUser() result (where %s=%s and %s=%s)",
|
||||
expectedResult, userAssignmentResultToString(expectedResult),
|
||||
|
||||
Reference in New Issue
Block a user