Do not send updates for disabled displays.
If a display is disabled, do not share it outside of
DisplayManagerService.
This will help by not creating any unnecessary updates for displays that
are disabled, and also not informing Applications of displays that they
are unable to use.
Also fixing a concurrency issue with DMS.handleLogicalDisplaySwapped
which became apparent with this CL. Deferring the runnable with a
Handler.post() caused the display-state-OFF update to happen after a newer
change to turn the display ON. This caused the device to startup into a
black screen. Removed the unnecessary call (since the displays are now
made to both go into the "transition" state) to update the state and
removed a lot of the redundant code with handleLogicalDisplayChange()
which was called at the end of the method anyway.
Bug: 221071695
Test: atest com.server.android.display
Test: Manually verify display layouts still successfully change, and
also confirm logs no longer hand excessive add/remove
display notifications.
Change-Id: I003fd91567630a447cf030b6fb83e5cb1041bcb5
Merged-In: I003fd91567630a447cf030b6fb83e5cb1041bcb5
This commit is contained in:
@@ -559,18 +559,20 @@ public final class DisplayManager {
|
||||
* @see #DISPLAY_CATEGORY_PRESENTATION
|
||||
*/
|
||||
public Display[] getDisplays(String category) {
|
||||
final int[] displayIds = mGlobal.getDisplayIds();
|
||||
boolean includeDisabled = (category != null
|
||||
&& category.equals(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED));
|
||||
final int[] displayIds = mGlobal.getDisplayIds(includeDisabled);
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
if (category == null
|
||||
|| DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED.equals(category)) {
|
||||
addAllDisplaysLocked(mTempDisplays, displayIds);
|
||||
} else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
|
||||
if (DISPLAY_CATEGORY_PRESENTATION.equals(category)) {
|
||||
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
|
||||
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_EXTERNAL);
|
||||
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
|
||||
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
|
||||
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_INTERNAL);
|
||||
} else if (category == null
|
||||
|| DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED.equals(category)) {
|
||||
addAllDisplaysLocked(mTempDisplays, displayIds);
|
||||
}
|
||||
return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
|
||||
} finally {
|
||||
|
||||
@@ -206,6 +206,16 @@ public final class DisplayManagerGlobal {
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public int[] getDisplayIds() {
|
||||
return getDisplayIds(/* includeDisabled= */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all currently valid logical display ids.
|
||||
*
|
||||
* @param includeDisabled True if the returned list of displays includes disabled displays.
|
||||
* @return An array containing all display ids.
|
||||
*/
|
||||
public int[] getDisplayIds(boolean includeDisabled) {
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
if (USE_CACHE) {
|
||||
@@ -214,7 +224,7 @@ public final class DisplayManagerGlobal {
|
||||
}
|
||||
}
|
||||
|
||||
int[] displayIds = mDm.getDisplayIds();
|
||||
int[] displayIds = mDm.getDisplayIds(includeDisabled);
|
||||
if (USE_CACHE) {
|
||||
mDisplayIdCache = displayIds;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import android.view.Surface;
|
||||
interface IDisplayManager {
|
||||
@UnsupportedAppUsage
|
||||
DisplayInfo getDisplayInfo(int displayId);
|
||||
int[] getDisplayIds();
|
||||
int[] getDisplayIds(boolean includeDisabled);
|
||||
|
||||
boolean isUidPresentOnDisplay(int uid, int displayId);
|
||||
|
||||
|
||||
@@ -1545,7 +1545,7 @@ public final class DisplayManagerService extends SystemService {
|
||||
mSyncRoot.notifyAll();
|
||||
}
|
||||
|
||||
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
|
||||
sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
|
||||
|
||||
Runnable work = updateDisplayStateLocked(device);
|
||||
if (work != null) {
|
||||
@@ -1564,7 +1564,7 @@ public final class DisplayManagerService extends SystemService {
|
||||
// We don't bother invalidating the display info caches here because any changes to the
|
||||
// display info will trigger a cache invalidation inside of LogicalDisplay before we hit
|
||||
// this point.
|
||||
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
|
||||
sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
|
||||
scheduleTraversalLocked(false);
|
||||
mPersistentDataStore.saveIfNeeded();
|
||||
|
||||
@@ -1593,7 +1593,7 @@ public final class DisplayManagerService extends SystemService {
|
||||
mDisplayStates.delete(displayId);
|
||||
mDisplayBrightnesses.delete(displayId);
|
||||
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
|
||||
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
|
||||
sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
|
||||
scheduleTraversalLocked(false);
|
||||
|
||||
if (mDisplayWindowPolicyControllers.contains(displayId)) {
|
||||
@@ -1609,24 +1609,13 @@ public final class DisplayManagerService extends SystemService {
|
||||
}
|
||||
|
||||
private void handleLogicalDisplaySwappedLocked(@NonNull LogicalDisplay display) {
|
||||
final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
|
||||
final Runnable work = updateDisplayStateLocked(device);
|
||||
if (work != null) {
|
||||
mHandler.post(work);
|
||||
}
|
||||
final int displayId = display.getDisplayIdLocked();
|
||||
handleLogicalDisplayChangedLocked(display);
|
||||
|
||||
final int displayId = display.getDisplayIdLocked();
|
||||
if (displayId == Display.DEFAULT_DISPLAY) {
|
||||
notifyDefaultDisplayDeviceUpdated(display);
|
||||
}
|
||||
|
||||
DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
|
||||
if (dpc != null) {
|
||||
dpc.onDisplayChanged();
|
||||
}
|
||||
mPersistentDataStore.saveIfNeeded();
|
||||
mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS);
|
||||
handleLogicalDisplayChangedLocked(display);
|
||||
}
|
||||
|
||||
private void notifyDefaultDisplayDeviceUpdated(LogicalDisplay display) {
|
||||
@@ -1638,7 +1627,7 @@ public final class DisplayManagerService extends SystemService {
|
||||
final int displayId = display.getDisplayIdLocked();
|
||||
final DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
|
||||
if (dpc != null) {
|
||||
dpc.onDeviceStateTransition();
|
||||
dpc.onDisplayChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2348,9 +2337,13 @@ public final class DisplayManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private void sendDisplayEventLocked(int displayId, @DisplayEvent int event) {
|
||||
Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
|
||||
mHandler.sendMessage(msg);
|
||||
private void sendDisplayEventLocked(@NonNull LogicalDisplay display, @DisplayEvent int event) {
|
||||
// Only send updates outside of DisplayManagerService for enabled displays
|
||||
if (display.isEnabledLocked()) {
|
||||
int displayId = display.getDisplayIdLocked();
|
||||
Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendDisplayGroupEvent(int groupId, int event) {
|
||||
@@ -2636,8 +2629,7 @@ public final class DisplayManagerService extends SystemService {
|
||||
}
|
||||
|
||||
private void handleBrightnessChange(LogicalDisplay display) {
|
||||
sendDisplayEventLocked(display.getDisplayIdLocked(),
|
||||
DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED);
|
||||
sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED);
|
||||
}
|
||||
|
||||
private DisplayDevice getDeviceForDisplayLocked(int displayId) {
|
||||
@@ -2854,12 +2846,12 @@ public final class DisplayManagerService extends SystemService {
|
||||
* Returns the list of all display ids.
|
||||
*/
|
||||
@Override // Binder call
|
||||
public int[] getDisplayIds() {
|
||||
public int[] getDisplayIds(boolean includeDisabled) {
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mSyncRoot) {
|
||||
return mLogicalDisplayMapper.getDisplayIdsLocked(callingUid);
|
||||
return mLogicalDisplayMapper.getDisplayIdsLocked(callingUid, includeDisabled);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
@@ -3337,6 +3329,11 @@ public final class DisplayManagerService extends SystemService {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mSyncRoot) {
|
||||
LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(
|
||||
displayId, /* includeDisabled= */ false);
|
||||
if (display == null || !display.isEnabledLocked()) {
|
||||
return null;
|
||||
}
|
||||
DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
|
||||
if (dpc != null) {
|
||||
return dpc.getBrightnessInfo();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.display;
|
||||
|
||||
import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
|
||||
import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE;
|
||||
import static android.os.PowerManager.BRIGHTNESS_INVALID;
|
||||
|
||||
@@ -1457,7 +1458,7 @@ public class DisplayModeDirector {
|
||||
SparseArray<Display.Mode[]> modes = new SparseArray<>();
|
||||
SparseArray<Display.Mode> defaultModes = new SparseArray<>();
|
||||
DisplayInfo info = new DisplayInfo();
|
||||
Display[] displays = dm.getDisplays();
|
||||
Display[] displays = dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
|
||||
for (Display d : displays) {
|
||||
final int displayId = d.getDisplayId();
|
||||
d.getDisplayInfo(info);
|
||||
@@ -2332,7 +2333,8 @@ public class DisplayModeDirector {
|
||||
sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
|
||||
|
||||
synchronized (mSensorObserverLock) {
|
||||
for (Display d : mDisplayManager.getDisplays()) {
|
||||
for (Display d : mDisplayManager.getDisplays(
|
||||
DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
|
||||
mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
|
||||
}
|
||||
}
|
||||
@@ -2343,7 +2345,8 @@ public class DisplayModeDirector {
|
||||
}
|
||||
|
||||
private void recalculateVotesLocked() {
|
||||
final Display[] displays = mDisplayManager.getDisplays();
|
||||
final Display[] displays = mDisplayManager.getDisplays(
|
||||
DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
|
||||
for (Display d : displays) {
|
||||
int displayId = d.getDisplayId();
|
||||
Vote vote = null;
|
||||
|
||||
@@ -491,6 +491,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
private final String mSuspendBlockerIdProxNegative;
|
||||
private final String mSuspendBlockerIdProxDebounce;
|
||||
|
||||
private boolean mIsEnabled;
|
||||
private boolean mIsInTransition;
|
||||
|
||||
/**
|
||||
* Creates the display power controller.
|
||||
*/
|
||||
@@ -512,6 +515,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
|
||||
mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
|
||||
mDisplayStatsId = mUniqueDisplayId.hashCode();
|
||||
mIsEnabled = logicalDisplay.isEnabledLocked();
|
||||
mIsInTransition = logicalDisplay.isInTransitionLocked();
|
||||
mHandler = new DisplayControllerHandler(handler.getLooper());
|
||||
mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
|
||||
mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
|
||||
@@ -789,13 +794,30 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
final DisplayDeviceConfig config = device.getDisplayDeviceConfig();
|
||||
final IBinder token = device.getDisplayTokenLocked();
|
||||
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
|
||||
final boolean isEnabled = mLogicalDisplay.isEnabledLocked();
|
||||
final boolean isInTransition = mLogicalDisplay.isInTransitionLocked();
|
||||
mHandler.post(() -> {
|
||||
boolean changed = false;
|
||||
if (mDisplayDevice != device) {
|
||||
changed = true;
|
||||
mDisplayDevice = device;
|
||||
mUniqueDisplayId = uniqueId;
|
||||
mDisplayStatsId = mUniqueDisplayId.hashCode();
|
||||
mDisplayDeviceConfig = config;
|
||||
loadFromDisplayDeviceConfig(token, info);
|
||||
|
||||
// Since the underlying display-device changed, we really don't know the
|
||||
// last command that was sent to change it's state. Lets assume it is unknown so
|
||||
// that we trigger a change immediately.
|
||||
mPowerState.resetScreenState();
|
||||
}
|
||||
if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) {
|
||||
changed = true;
|
||||
mIsEnabled = isEnabled;
|
||||
mIsInTransition = isInTransition;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (DEBUG) {
|
||||
Trace.beginAsyncSection("DisplayPowerController#updatePowerState", 0);
|
||||
}
|
||||
@@ -807,15 +829,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the displays are preparing to transition from one device state to another.
|
||||
* This process involves turning off some displays so we need updatePowerState() to run and
|
||||
* calculate the new state.
|
||||
*/
|
||||
public void onDeviceStateTransition() {
|
||||
sendUpdatePowerState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters all listeners and interrupts all running threads; halting future work.
|
||||
*
|
||||
@@ -1291,8 +1304,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
mIgnoreProximityUntilChanged = false;
|
||||
}
|
||||
|
||||
if (!mLogicalDisplay.isEnabled()
|
||||
|| mLogicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION
|
||||
if (!mIsEnabled
|
||||
|| mIsInTransition
|
||||
|| mScreenOffBecauseOfProximity) {
|
||||
state = Display.STATE_OFF;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ final class DisplayPowerState {
|
||||
public void setScreenState(int state) {
|
||||
if (mScreenState != state) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "setScreenState: state=" + state);
|
||||
Slog.w(TAG, "setScreenState: state=" + Display.stateToString(state));
|
||||
}
|
||||
|
||||
mScreenState = state;
|
||||
@@ -339,6 +339,15 @@ final class DisplayPowerState {
|
||||
if (mColorFade != null) mColorFade.dump(pw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the screen state to unknown. Useful when the underlying display-device changes for the
|
||||
* LogicalDisplay and we do not know the last state that was sent to it.
|
||||
*/
|
||||
void resetScreenState() {
|
||||
mScreenState = Display.STATE_UNKNOWN;
|
||||
mScreenReady = false;
|
||||
}
|
||||
|
||||
private void scheduleScreenUpdate() {
|
||||
if (!mScreenUpdatePending) {
|
||||
mScreenUpdatePending = true;
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.server.display;
|
||||
|
||||
import static com.android.server.display.DisplayDeviceInfo.TOUCH_NONE;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.Point;
|
||||
@@ -68,33 +67,6 @@ import java.util.Objects;
|
||||
final class LogicalDisplay {
|
||||
private static final String TAG = "LogicalDisplay";
|
||||
|
||||
/**
|
||||
* Phase indicating the logical display's existence is hidden from the rest of the framework.
|
||||
* This can happen if the current layout has specifically requested to keep this display
|
||||
* disabled.
|
||||
*/
|
||||
static final int DISPLAY_PHASE_DISABLED = -1;
|
||||
|
||||
/**
|
||||
* Phase indicating that the logical display is going through a layout transition.
|
||||
* When in this phase, other systems can choose to special case power-state handling of a
|
||||
* display that might be in a transition.
|
||||
*/
|
||||
static final int DISPLAY_PHASE_LAYOUT_TRANSITION = 0;
|
||||
|
||||
/**
|
||||
* The display is exposed to the rest of the system and its power state is determined by a
|
||||
* power-request from PowerManager.
|
||||
*/
|
||||
static final int DISPLAY_PHASE_ENABLED = 1;
|
||||
|
||||
@IntDef(prefix = {"DISPLAY_PHASE" }, value = {
|
||||
DISPLAY_PHASE_DISABLED,
|
||||
DISPLAY_PHASE_LAYOUT_TRANSITION,
|
||||
DISPLAY_PHASE_ENABLED
|
||||
})
|
||||
@interface DisplayPhase {}
|
||||
|
||||
// The layer stack we use when the display has been blanked to prevent any
|
||||
// of its content from appearing.
|
||||
private static final int BLANK_LAYER_STACK = -1;
|
||||
@@ -158,14 +130,6 @@ final class LogicalDisplay {
|
||||
private final Rect mTempLayerStackRect = new Rect();
|
||||
private final Rect mTempDisplayRect = new Rect();
|
||||
|
||||
/**
|
||||
* Indicates the current phase of the display. Generally, phases supersede any
|
||||
* requests from PowerManager in DPC's calculation for the display state. Only when the
|
||||
* phase is ENABLED does PowerManager's request for the display take effect.
|
||||
*/
|
||||
@DisplayPhase
|
||||
private int mPhase = DISPLAY_PHASE_ENABLED;
|
||||
|
||||
/**
|
||||
* The UID mappings for refresh rate override
|
||||
*/
|
||||
@@ -181,12 +145,22 @@ final class LogicalDisplay {
|
||||
*/
|
||||
private final SparseArray<Float> mTempFrameRateOverride;
|
||||
|
||||
// Indicates the display is enabled (allowed to be ON).
|
||||
private boolean mIsEnabled;
|
||||
|
||||
// Indicates the display is part of a transition from one device-state ({@link
|
||||
// DeviceStateManager}) to another. Being a "part" of a transition means that either
|
||||
// the {@link mIsEnabled} is changing, or the underlying mPrimiaryDisplayDevice is changing.
|
||||
private boolean mIsInTransition;
|
||||
|
||||
public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
|
||||
mDisplayId = displayId;
|
||||
mLayerStack = layerStack;
|
||||
mPrimaryDisplayDevice = primaryDisplayDevice;
|
||||
mPendingFrameRateOverrideUids = new ArraySet<>();
|
||||
mTempFrameRateOverride = new SparseArray<>();
|
||||
mIsEnabled = true;
|
||||
mIsInTransition = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -525,7 +499,7 @@ final class LogicalDisplay {
|
||||
// Prevent displays that are disabled from receiving input.
|
||||
// TODO(b/188914255): Remove once input can dispatch against device vs layerstack.
|
||||
device.setDisplayFlagsLocked(t,
|
||||
(isEnabled() && device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE)
|
||||
(isEnabledLocked() && device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE)
|
||||
? SurfaceControl.DISPLAY_RECEIVES_INPUT
|
||||
: 0);
|
||||
|
||||
@@ -767,32 +741,45 @@ final class LogicalDisplay {
|
||||
return old;
|
||||
}
|
||||
|
||||
public void setPhase(@DisplayPhase int phase) {
|
||||
mPhase = phase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently set phase for this LogicalDisplay. Phases are used when transitioning
|
||||
* from one device state to another. {@see LogicalDisplayMapper}.
|
||||
*/
|
||||
@DisplayPhase
|
||||
public int getPhase() {
|
||||
return mPhase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the LogicalDisplay is enabled or {@code false}
|
||||
* if disabled indicating that the display should be hidden from the rest of the apps and
|
||||
* framework.
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
// DISPLAY_PHASE_LAYOUT_TRANSITION is still considered an 'enabled' phase.
|
||||
return mPhase == DISPLAY_PHASE_ENABLED || mPhase == DISPLAY_PHASE_LAYOUT_TRANSITION;
|
||||
public boolean isEnabledLocked() {
|
||||
return mIsEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display as enabled.
|
||||
*
|
||||
* @param enable True if enabled, false otherwise.
|
||||
*/
|
||||
public void setEnabledLocked(boolean enabled) {
|
||||
mIsEnabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the LogicalDisplay is in a transition phase. This is used to indicate
|
||||
* that we are getting ready to swap the underlying display-device and the display should be
|
||||
* rendered appropriately to reduce jank.
|
||||
*/
|
||||
public boolean isInTransitionLocked() {
|
||||
return mIsInTransition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transition phase.
|
||||
* @param isInTransition True if it display is in transition.
|
||||
*/
|
||||
public void setIsInTransitionLocked(boolean isInTransition) {
|
||||
mIsInTransition = isInTransition;
|
||||
}
|
||||
|
||||
public void dumpLocked(PrintWriter pw) {
|
||||
pw.println("mDisplayId=" + mDisplayId);
|
||||
pw.println("mPhase=" + mPhase);
|
||||
pw.println("mIsEnabled=" + mIsEnabled);
|
||||
pw.println("mIsInTransition=" + mIsInTransition);
|
||||
pw.println("mLayerStack=" + mLayerStack);
|
||||
pw.println("mHasContent=" + mHasContent);
|
||||
pw.println("mDesiredDisplayModeSpecs={" + mDesiredDisplayModeSpecs + "}");
|
||||
|
||||
@@ -39,7 +39,6 @@ import android.view.DisplayAddress;
|
||||
import android.view.DisplayInfo;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.display.LogicalDisplay.DisplayPhase;
|
||||
import com.android.server.display.layout.Layout;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -167,6 +166,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
|
||||
@NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
|
||||
@NonNull Handler handler) {
|
||||
this(context, repo, listener, syncRoot, handler, new DeviceStateToLayoutMap());
|
||||
}
|
||||
|
||||
LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
|
||||
@NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
|
||||
@NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap) {
|
||||
mSyncRoot = syncRoot;
|
||||
mPowerManager = context.getSystemService(PowerManager.class);
|
||||
mInteractive = mPowerManager.isInteractive();
|
||||
@@ -181,7 +186,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
mDeviceStatesOnWhichToSleep = toSparseBooleanArray(context.getResources().getIntArray(
|
||||
com.android.internal.R.array.config_deviceStatesOnWhichToSleep));
|
||||
mDisplayDeviceRepo.addListener(this);
|
||||
mDeviceStateToLayoutMap = new DeviceStateToLayoutMap();
|
||||
mDeviceStateToLayoutMap = deviceStateToLayoutMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -218,10 +223,22 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
}
|
||||
|
||||
public LogicalDisplay getDisplayLocked(int displayId) {
|
||||
return mLogicalDisplays.get(displayId);
|
||||
return getDisplayLocked(displayId, /* includeDisabled= */ true);
|
||||
}
|
||||
|
||||
public LogicalDisplay getDisplayLocked(int displayId, boolean includeDisabled) {
|
||||
LogicalDisplay display = mLogicalDisplays.get(displayId);
|
||||
if (display == null || display.isEnabledLocked() || includeDisabled) {
|
||||
return display;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public LogicalDisplay getDisplayLocked(DisplayDevice device) {
|
||||
return getDisplayLocked(device, /* includeDisabled= */ true);
|
||||
}
|
||||
|
||||
public LogicalDisplay getDisplayLocked(DisplayDevice device, boolean includeDisabled) {
|
||||
if (device == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -229,21 +246,26 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
for (int i = 0; i < count; i++) {
|
||||
final LogicalDisplay display = mLogicalDisplays.valueAt(i);
|
||||
if (display.getPrimaryDisplayDeviceLocked() == device) {
|
||||
return display;
|
||||
if (display.isEnabledLocked() || includeDisabled) {
|
||||
return display;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int[] getDisplayIdsLocked(int callingUid) {
|
||||
public int[] getDisplayIdsLocked(int callingUid, boolean includeDisabled) {
|
||||
final int count = mLogicalDisplays.size();
|
||||
int[] displayIds = new int[count];
|
||||
int n = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
LogicalDisplay display = mLogicalDisplays.valueAt(i);
|
||||
DisplayInfo info = display.getDisplayInfoLocked();
|
||||
if (info.hasAccess(callingUid)) {
|
||||
displayIds[n++] = mLogicalDisplays.keyAt(i);
|
||||
if (display.isEnabledLocked() || includeDisabled) {
|
||||
DisplayInfo info = display.getDisplayInfoLocked();
|
||||
if (info.hasAccess(callingUid)) {
|
||||
displayIds[n++] = mLogicalDisplays.keyAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n != count) {
|
||||
@@ -364,14 +386,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
|
||||
void setDeviceStateLocked(int state, boolean isOverrideActive) {
|
||||
Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState
|
||||
+ ", interactive=" + mInteractive);
|
||||
+ ", interactive=" + mInteractive + ", mBootCompleted=" + mBootCompleted);
|
||||
// As part of a state transition, we may need to turn off some displays temporarily so that
|
||||
// the transition is smooth. Plus, on some devices, only one internal displays can be
|
||||
// on at a time. We use DISPLAY_PHASE_LAYOUT_TRANSITION to mark a display that needs to be
|
||||
// on at a time. We use LogicalDisplay.setIsInTransition to mark a display that needs to be
|
||||
// temporarily turned off.
|
||||
if (mDeviceState != DeviceStateManager.INVALID_DEVICE_STATE) {
|
||||
resetLayoutLocked(mDeviceState, state, LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION);
|
||||
}
|
||||
resetLayoutLocked(mDeviceState, state, /* isStateChangeStarting= */ true);
|
||||
mPendingDeviceState = state;
|
||||
final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState,
|
||||
mInteractive, mBootCompleted);
|
||||
@@ -481,7 +501,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
final int count = mLogicalDisplays.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final LogicalDisplay display = mLogicalDisplays.valueAt(i);
|
||||
if (display.getPhase() != LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) {
|
||||
if (!display.isInTransitionLocked()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -497,7 +517,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
}
|
||||
|
||||
private void transitionToPendingStateLocked() {
|
||||
resetLayoutLocked(mDeviceState, mPendingDeviceState, LogicalDisplay.DISPLAY_PHASE_ENABLED);
|
||||
resetLayoutLocked(mDeviceState, mPendingDeviceState, /* isStateChangeStarting= */ false);
|
||||
mDeviceState = mPendingDeviceState;
|
||||
mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
|
||||
applyLayoutLocked();
|
||||
@@ -789,17 +809,17 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
|
||||
/**
|
||||
* Goes through all the displays used in the layouts for the specified {@code fromState} and
|
||||
* {@code toState} and applies the specified {@code phase}. When a new layout is requested, we
|
||||
* put the displays that will change into a transitional phase so that they can all be turned
|
||||
* OFF. Once all are confirmed OFF, then this method gets called again to reset the phase to
|
||||
* normal operation. This helps to ensure that all display-OFF requests are made before
|
||||
* {@code toState} and un/marks them for transition. When a new layout is requested, we
|
||||
* mark the displays that will change into a transitional phase so that they can all be turned
|
||||
* OFF. Once all are confirmed OFF, then this method gets called again to reset transition
|
||||
* marker. This helps to ensure that all display-OFF requests are made before
|
||||
* display-ON which in turn hides any resizing-jank windows might incur when switching displays.
|
||||
*
|
||||
* @param fromState The state we are switching from.
|
||||
* @param toState The state we are switching to.
|
||||
* @param phase The new phase to apply to the displays.
|
||||
* @param isStateChangeStarting Indicates whether to start or end Transition phase.
|
||||
*/
|
||||
private void resetLayoutLocked(int fromState, int toState, @DisplayPhase int phase) {
|
||||
private void resetLayoutLocked(int fromState, int toState, boolean isStateChangeStarting) {
|
||||
final Layout fromLayout = mDeviceStateToLayoutMap.get(fromState);
|
||||
final Layout toLayout = mDeviceStateToLayoutMap.get(toState);
|
||||
|
||||
@@ -817,12 +837,16 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
// new layout.
|
||||
final DisplayAddress address = device.getDisplayDeviceInfoLocked().address;
|
||||
|
||||
// Virtual displays do not have addresses.
|
||||
// Virtual displays do not have addresses, so account for nulls.
|
||||
final Layout.Display fromDisplay =
|
||||
address != null ? fromLayout.getByAddress(address) : null;
|
||||
final Layout.Display toDisplay =
|
||||
address != null ? toLayout.getByAddress(address) : null;
|
||||
|
||||
// If the display is in one of the layouts but not the other, then the content will
|
||||
// change, so in this case we also want to blank the displays to avoid jank.
|
||||
final boolean displayNotInBothLayouts = (fromDisplay == null) != (toDisplay == null);
|
||||
|
||||
// If a layout doesn't mention a display-device at all, then the display-device defaults
|
||||
// to enabled. This is why we treat null as "enabled" in the code below.
|
||||
final boolean wasEnabled = fromDisplay == null || fromDisplay.isEnabled();
|
||||
@@ -837,16 +861,23 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
// 3) It's enabled, but it's mapped to a new logical display ID. To the user this
|
||||
// would look like apps moving from one screen to another since task-stacks stay
|
||||
// with the logical display [ID].
|
||||
// 4) It's in one layout but not the other, so the content will change.
|
||||
final boolean isTransitioning =
|
||||
(logicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION)
|
||||
logicalDisplay.isInTransitionLocked()
|
||||
|| (wasEnabled != willBeEnabled)
|
||||
|| deviceHasNewLogicalDisplayId;
|
||||
|| deviceHasNewLogicalDisplayId
|
||||
|| displayNotInBothLayouts;
|
||||
|
||||
if (isTransitioning) {
|
||||
setDisplayPhase(logicalDisplay, phase);
|
||||
if (phase == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) {
|
||||
mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_TRANSITION);
|
||||
if (isStateChangeStarting != logicalDisplay.isInTransitionLocked()) {
|
||||
Slog.i(TAG, "Set isInTransition on display " + displayId + ": "
|
||||
+ isStateChangeStarting);
|
||||
}
|
||||
// This will either mark the display as "transitioning" if we are starting to change
|
||||
// the device state, or remove the transitioning marker if the state change is
|
||||
// ending.
|
||||
logicalDisplay.setIsInTransitionLocked(isStateChangeStarting);
|
||||
mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_TRANSITION);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -891,9 +922,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
newDisplay.swapDisplaysLocked(oldDisplay);
|
||||
}
|
||||
|
||||
if (!displayLayout.isEnabled()) {
|
||||
setDisplayPhase(newDisplay, LogicalDisplay.DISPLAY_PHASE_DISABLED);
|
||||
}
|
||||
setEnabledLocked(newDisplay, displayLayout.isEnabled());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -912,23 +941,25 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
|
||||
final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
|
||||
display.updateLocked(mDisplayDeviceRepo);
|
||||
mLogicalDisplays.put(displayId, display);
|
||||
setDisplayPhase(display, LogicalDisplay.DISPLAY_PHASE_ENABLED);
|
||||
return display;
|
||||
}
|
||||
|
||||
private void setDisplayPhase(LogicalDisplay display, @DisplayPhase int phase) {
|
||||
private void setEnabledLocked(LogicalDisplay display, boolean isEnabled) {
|
||||
final int displayId = display.getDisplayIdLocked();
|
||||
final DisplayInfo info = display.getDisplayInfoLocked();
|
||||
|
||||
final boolean disallowSecondaryDisplay = mSingleDisplayDemoMode
|
||||
&& (info.type != Display.TYPE_INTERNAL);
|
||||
if (phase != LogicalDisplay.DISPLAY_PHASE_DISABLED && disallowSecondaryDisplay) {
|
||||
if (isEnabled && disallowSecondaryDisplay) {
|
||||
Slog.i(TAG, "Not creating a logical display for a secondary display because single"
|
||||
+ " display demo mode is enabled: " + display.getDisplayInfoLocked());
|
||||
phase = LogicalDisplay.DISPLAY_PHASE_DISABLED;
|
||||
isEnabled = false;
|
||||
}
|
||||
|
||||
display.setPhase(phase);
|
||||
if (display.isEnabledLocked() != isEnabled) {
|
||||
Slog.i(TAG, "SetEnabled on display " + displayId + ": " + isEnabled);
|
||||
display.setEnabledLocked(isEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
private int assignDisplayGroupIdLocked(boolean isOwnDisplayGroup) {
|
||||
|
||||
@@ -287,7 +287,7 @@ public class DisplayManagerServiceTest {
|
||||
|
||||
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
|
||||
|
||||
final int displayIds[] = bs.getDisplayIds();
|
||||
final int[] displayIds = bs.getDisplayIds(/* includeDisabled= */ true);
|
||||
final int size = displayIds.length;
|
||||
assertTrue(size > 0);
|
||||
|
||||
@@ -1174,7 +1174,8 @@ public class DisplayManagerServiceTest {
|
||||
DisplayManagerService.BinderService displayManagerBinderService,
|
||||
FakeDisplayDevice displayDevice) {
|
||||
|
||||
final int[] displayIds = displayManagerBinderService.getDisplayIds();
|
||||
final int[] displayIds = displayManagerBinderService.getDisplayIds(
|
||||
/* includeDisabled= */ true);
|
||||
assertTrue(displayIds.length > 0);
|
||||
int displayId = Display.INVALID_DISPLAY;
|
||||
for (int i = 0; i < displayIds.length; i++) {
|
||||
|
||||
@@ -30,6 +30,8 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
@@ -53,6 +55,8 @@ import android.view.DisplayInfo;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.display.layout.Layout;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -60,6 +64,7 @@ import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -85,6 +90,7 @@ public class LogicalDisplayMapperTest {
|
||||
@Mock Resources mResourcesMock;
|
||||
@Mock IPowerManager mIPowerManagerMock;
|
||||
@Mock IThermalService mIThermalServiceMock;
|
||||
@Spy DeviceStateToLayoutMap mDeviceStateToLayoutMapSpy = new DeviceStateToLayoutMap();
|
||||
|
||||
@Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor;
|
||||
|
||||
@@ -134,7 +140,8 @@ public class LogicalDisplayMapperTest {
|
||||
mLooper = new TestLooper();
|
||||
mHandler = new Handler(mLooper.getLooper());
|
||||
mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo,
|
||||
mListenerMock, new DisplayManagerService.SyncRoot(), mHandler);
|
||||
mListenerMock, new DisplayManagerService.SyncRoot(), mHandler,
|
||||
mDeviceStateToLayoutMapSpy);
|
||||
}
|
||||
|
||||
|
||||
@@ -261,7 +268,8 @@ public class LogicalDisplayMapperTest {
|
||||
add(createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800, 0));
|
||||
add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0));
|
||||
|
||||
int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID);
|
||||
int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID,
|
||||
/* includeDisabled= */ true);
|
||||
assertEquals(3, ids.length);
|
||||
Arrays.sort(ids);
|
||||
assertEquals(DEFAULT_DISPLAY, ids[0]);
|
||||
@@ -413,6 +421,178 @@ public class LogicalDisplayMapperTest {
|
||||
/* isBootCompleted= */true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeviceStateLocked() {
|
||||
DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
|
||||
DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
|
||||
DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
|
||||
DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
|
||||
|
||||
Layout layout = new Layout();
|
||||
layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address, true, true);
|
||||
layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address, false, false);
|
||||
when(mDeviceStateToLayoutMapSpy.get(0)).thenReturn(layout);
|
||||
|
||||
layout = new Layout();
|
||||
layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address, false, false);
|
||||
layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address, true, true);
|
||||
when(mDeviceStateToLayoutMapSpy.get(1)).thenReturn(layout);
|
||||
when(mDeviceStateToLayoutMapSpy.get(2)).thenReturn(layout);
|
||||
|
||||
LogicalDisplay display1 = add(device1);
|
||||
assertEquals(info(display1).address, info(device1).address);
|
||||
assertEquals(DEFAULT_DISPLAY, id(display1));
|
||||
|
||||
LogicalDisplay display2 = add(device2);
|
||||
assertEquals(info(display2).address, info(device2).address);
|
||||
// We can only have one default display
|
||||
assertEquals(DEFAULT_DISPLAY, id(display1));
|
||||
|
||||
mLogicalDisplayMapper.setDeviceStateLocked(0, false);
|
||||
mLooper.moveTimeForward(1000);
|
||||
mLooper.dispatchAll();
|
||||
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
|
||||
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
|
||||
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked());
|
||||
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
|
||||
|
||||
mLogicalDisplayMapper.setDeviceStateLocked(1, false);
|
||||
mLooper.moveTimeForward(1000);
|
||||
mLooper.dispatchAll();
|
||||
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
|
||||
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
|
||||
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked());
|
||||
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
|
||||
|
||||
mLogicalDisplayMapper.setDeviceStateLocked(2, false);
|
||||
mLooper.moveTimeForward(1000);
|
||||
mLooper.dispatchAll();
|
||||
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
|
||||
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
|
||||
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked());
|
||||
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnabledAndDisabledDisplays() {
|
||||
DisplayAddress displayAddressOne = new TestUtils.TestDisplayAddress();
|
||||
DisplayAddress displayAddressTwo = new TestUtils.TestDisplayAddress();
|
||||
DisplayAddress displayAddressThree = new TestUtils.TestDisplayAddress();
|
||||
|
||||
TestDisplayDevice device1 = createDisplayDevice(displayAddressOne, Display.TYPE_INTERNAL,
|
||||
600, 800,
|
||||
DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
|
||||
TestDisplayDevice device2 = createDisplayDevice(displayAddressTwo, Display.TYPE_INTERNAL,
|
||||
200, 800,
|
||||
DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
|
||||
TestDisplayDevice device3 = createDisplayDevice(displayAddressThree, Display.TYPE_INTERNAL,
|
||||
600, 900, DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
|
||||
|
||||
Layout threeDevicesEnabledLayout = new Layout();
|
||||
threeDevicesEnabledLayout.createDisplayLocked(
|
||||
displayAddressOne,
|
||||
/* isDefault= */ true,
|
||||
/* isEnabled= */ true);
|
||||
threeDevicesEnabledLayout.createDisplayLocked(
|
||||
displayAddressTwo,
|
||||
/* isDefault= */ false,
|
||||
/* isEnabled= */ true);
|
||||
threeDevicesEnabledLayout.createDisplayLocked(
|
||||
displayAddressThree,
|
||||
/* isDefault= */ false,
|
||||
/* isEnabled= */ true);
|
||||
|
||||
when(mDeviceStateToLayoutMapSpy.get(DeviceStateToLayoutMap.STATE_DEFAULT))
|
||||
.thenReturn(threeDevicesEnabledLayout);
|
||||
|
||||
LogicalDisplay display1 = add(device1);
|
||||
LogicalDisplay display2 = add(device2);
|
||||
LogicalDisplay display3 = add(device3);
|
||||
|
||||
// ensure 3 displays are returned
|
||||
int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID, false);
|
||||
assertEquals(3, ids.length);
|
||||
Arrays.sort(ids);
|
||||
assertEquals(DEFAULT_DISPLAY, ids[0]);
|
||||
assertNotNull(mLogicalDisplayMapper.getDisplayLocked(device1,
|
||||
/* includeDisabled= */ false));
|
||||
assertNotNull(mLogicalDisplayMapper.getDisplayLocked(device2,
|
||||
/* includeDisabled= */ false));
|
||||
assertNotNull(mLogicalDisplayMapper.getDisplayLocked(device3,
|
||||
/* includeDisabled= */ false));
|
||||
assertNotNull(mLogicalDisplayMapper.getDisplayLocked(
|
||||
threeDevicesEnabledLayout.getByAddress(displayAddressOne).getLogicalDisplayId(),
|
||||
/* includeDisabled= */ false));
|
||||
assertNotNull(mLogicalDisplayMapper.getDisplayLocked(
|
||||
threeDevicesEnabledLayout.getByAddress(displayAddressTwo).getLogicalDisplayId(),
|
||||
/* includeDisabled= */ false));
|
||||
assertNotNull(mLogicalDisplayMapper.getDisplayLocked(
|
||||
threeDevicesEnabledLayout.getByAddress(displayAddressThree).getLogicalDisplayId(),
|
||||
/* includeDisabled= */ false));
|
||||
|
||||
Layout oneDeviceEnabledLayout = new Layout();
|
||||
oneDeviceEnabledLayout.createDisplayLocked(
|
||||
displayAddressOne,
|
||||
/* isDefault= */ true,
|
||||
/* isEnabled= */ true);
|
||||
oneDeviceEnabledLayout.createDisplayLocked(
|
||||
displayAddressTwo,
|
||||
/* isDefault= */ false,
|
||||
/* isEnabled= */ false);
|
||||
oneDeviceEnabledLayout.createDisplayLocked(
|
||||
displayAddressThree,
|
||||
/* isDefault= */ false,
|
||||
/* isEnabled= */ false);
|
||||
|
||||
when(mDeviceStateToLayoutMapSpy.get(0)).thenReturn(oneDeviceEnabledLayout);
|
||||
when(mDeviceStateToLayoutMapSpy.get(1)).thenReturn(threeDevicesEnabledLayout);
|
||||
|
||||
// 1) Set the new state
|
||||
// 2) Mark the displays as STATE_OFF so that it can continue with transition
|
||||
// 3) Send DISPLAY_DEVICE_EVENT_CHANGE to inform the mapper of the new display state
|
||||
// 4) Dispatch handler events.
|
||||
mLogicalDisplayMapper.setDeviceStateLocked(0, false);
|
||||
mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
|
||||
mLooper.moveTimeForward(1000);
|
||||
mLooper.dispatchAll();
|
||||
final int[] allDisplayIds = mLogicalDisplayMapper.getDisplayIdsLocked(
|
||||
Process.SYSTEM_UID, false);
|
||||
if (allDisplayIds.length != 1) {
|
||||
throw new RuntimeException("Displays: \n"
|
||||
+ mLogicalDisplayMapper.getDisplayLocked(device1).toString()
|
||||
+ "\n" + mLogicalDisplayMapper.getDisplayLocked(device2).toString()
|
||||
+ "\n" + mLogicalDisplayMapper.getDisplayLocked(device3).toString());
|
||||
}
|
||||
// ensure only one display is returned
|
||||
assertEquals(1, allDisplayIds.length);
|
||||
assertNotNull(mLogicalDisplayMapper.getDisplayLocked(device1,
|
||||
/* includeDisabled= */ false));
|
||||
assertNull(mLogicalDisplayMapper.getDisplayLocked(device2,
|
||||
/* includeDisabled= */ false));
|
||||
assertNull(mLogicalDisplayMapper.getDisplayLocked(device3,
|
||||
/* includeDisabled= */ false));
|
||||
assertNotNull(mLogicalDisplayMapper.getDisplayLocked(
|
||||
oneDeviceEnabledLayout.getByAddress(displayAddressOne).getLogicalDisplayId(),
|
||||
/* includeDisabled= */ false));
|
||||
assertNull(mLogicalDisplayMapper.getDisplayLocked(
|
||||
oneDeviceEnabledLayout.getByAddress(displayAddressTwo).getLogicalDisplayId(),
|
||||
/* includeDisabled= */ false));
|
||||
assertNull(mLogicalDisplayMapper.getDisplayLocked(
|
||||
oneDeviceEnabledLayout.getByAddress(displayAddressThree).getLogicalDisplayId(),
|
||||
/* includeDisabled= */ false));
|
||||
|
||||
// Now do it again to go back to state 1
|
||||
mLogicalDisplayMapper.setDeviceStateLocked(1, false);
|
||||
mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
|
||||
mLooper.moveTimeForward(1000);
|
||||
mLooper.dispatchAll();
|
||||
final int[] threeDisplaysEnabled = mLogicalDisplayMapper.getDisplayIdsLocked(
|
||||
Process.SYSTEM_UID, false);
|
||||
|
||||
// ensure all three displays are returned
|
||||
assertEquals(3, threeDisplaysEnabled.length);
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// Helper Methods
|
||||
/////////////////
|
||||
@@ -477,6 +657,7 @@ public class LogicalDisplayMapperTest {
|
||||
class TestDisplayDevice extends DisplayDevice {
|
||||
private DisplayDeviceInfo mInfo;
|
||||
private DisplayDeviceInfo mSentInfo;
|
||||
private int mState;
|
||||
|
||||
TestDisplayDevice() {
|
||||
super(null, null, "test_display_" + sUniqueTestDisplayId++, mContextMock);
|
||||
|
||||
@@ -128,12 +128,12 @@ public class LogicalDisplayTest {
|
||||
verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT));
|
||||
reset(t);
|
||||
|
||||
mLogicalDisplay.setPhase(LogicalDisplay.DISPLAY_PHASE_DISABLED);
|
||||
mLogicalDisplay.setEnabledLocked(false);
|
||||
mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
|
||||
verify(t).setDisplayFlags(any(), eq(0));
|
||||
reset(t);
|
||||
|
||||
mLogicalDisplay.setPhase(LogicalDisplay.DISPLAY_PHASE_ENABLED);
|
||||
mLogicalDisplay.setEnabledLocked(true);
|
||||
mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
|
||||
mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
|
||||
verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT));
|
||||
|
||||
Reference in New Issue
Block a user