Merge "Do not send updates for disabled displays." into tm-qpr-dev

This commit is contained in:
Santos Cordon
2022-12-05 13:31:40 +00:00
committed by Android (Google) Code Review
12 changed files with 375 additions and 141 deletions

View File

@@ -559,18 +559,20 @@ public final class DisplayManager {
* @see #DISPLAY_CATEGORY_PRESENTATION * @see #DISPLAY_CATEGORY_PRESENTATION
*/ */
public Display[] getDisplays(String category) { 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) { synchronized (mLock) {
try { try {
if (category == null if (DISPLAY_CATEGORY_PRESENTATION.equals(category)) {
|| DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED.equals(category)) {
addAllDisplaysLocked(mTempDisplays, displayIds);
} else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI); addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_EXTERNAL); addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_EXTERNAL);
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY); addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL); addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_INTERNAL); 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()]); return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
} finally { } finally {

View File

@@ -206,6 +206,16 @@ public final class DisplayManagerGlobal {
*/ */
@UnsupportedAppUsage @UnsupportedAppUsage
public int[] getDisplayIds() { 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 { try {
synchronized (mLock) { synchronized (mLock) {
if (USE_CACHE) { if (USE_CACHE) {
@@ -214,7 +224,7 @@ public final class DisplayManagerGlobal {
} }
} }
int[] displayIds = mDm.getDisplayIds(); int[] displayIds = mDm.getDisplayIds(includeDisabled);
if (USE_CACHE) { if (USE_CACHE) {
mDisplayIdCache = displayIds; mDisplayIdCache = displayIds;
} }

View File

@@ -36,7 +36,7 @@ import android.view.Surface;
interface IDisplayManager { interface IDisplayManager {
@UnsupportedAppUsage @UnsupportedAppUsage
DisplayInfo getDisplayInfo(int displayId); DisplayInfo getDisplayInfo(int displayId);
int[] getDisplayIds(); int[] getDisplayIds(boolean includeDisabled);
boolean isUidPresentOnDisplay(int uid, int displayId); boolean isUidPresentOnDisplay(int uid, int displayId);

View File

@@ -1545,7 +1545,7 @@ public final class DisplayManagerService extends SystemService {
mSyncRoot.notifyAll(); mSyncRoot.notifyAll();
} }
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED); sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
Runnable work = updateDisplayStateLocked(device); Runnable work = updateDisplayStateLocked(device);
if (work != null) { 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 // 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 // display info will trigger a cache invalidation inside of LogicalDisplay before we hit
// this point. // this point.
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
scheduleTraversalLocked(false); scheduleTraversalLocked(false);
mPersistentDataStore.saveIfNeeded(); mPersistentDataStore.saveIfNeeded();
@@ -1593,7 +1593,7 @@ public final class DisplayManagerService extends SystemService {
mDisplayStates.delete(displayId); mDisplayStates.delete(displayId);
mDisplayBrightnesses.delete(displayId); mDisplayBrightnesses.delete(displayId);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches(); DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
scheduleTraversalLocked(false); scheduleTraversalLocked(false);
if (mDisplayWindowPolicyControllers.contains(displayId)) { if (mDisplayWindowPolicyControllers.contains(displayId)) {
@@ -1609,24 +1609,13 @@ public final class DisplayManagerService extends SystemService {
} }
private void handleLogicalDisplaySwappedLocked(@NonNull LogicalDisplay display) { private void handleLogicalDisplaySwappedLocked(@NonNull LogicalDisplay display) {
final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); handleLogicalDisplayChangedLocked(display);
final Runnable work = updateDisplayStateLocked(device);
if (work != null) {
mHandler.post(work);
}
final int displayId = display.getDisplayIdLocked();
final int displayId = display.getDisplayIdLocked();
if (displayId == Display.DEFAULT_DISPLAY) { if (displayId == Display.DEFAULT_DISPLAY) {
notifyDefaultDisplayDeviceUpdated(display); notifyDefaultDisplayDeviceUpdated(display);
} }
DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
dpc.onDisplayChanged();
}
mPersistentDataStore.saveIfNeeded();
mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS); mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS);
handleLogicalDisplayChangedLocked(display);
} }
private void notifyDefaultDisplayDeviceUpdated(LogicalDisplay display) { private void notifyDefaultDisplayDeviceUpdated(LogicalDisplay display) {
@@ -1638,7 +1627,7 @@ public final class DisplayManagerService extends SystemService {
final int displayId = display.getDisplayIdLocked(); final int displayId = display.getDisplayIdLocked();
final DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); final DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) { if (dpc != null) {
dpc.onDeviceStateTransition(); dpc.onDisplayChanged();
} }
} }
@@ -2348,10 +2337,14 @@ public final class DisplayManagerService extends SystemService {
} }
} }
private void sendDisplayEventLocked(int displayId, @DisplayEvent int event) { 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); Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
mHandler.sendMessage(msg); mHandler.sendMessage(msg);
} }
}
private void sendDisplayGroupEvent(int groupId, int event) { private void sendDisplayGroupEvent(int groupId, int event) {
Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_GROUP_EVENT, groupId, event); Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_GROUP_EVENT, groupId, event);
@@ -2636,8 +2629,7 @@ public final class DisplayManagerService extends SystemService {
} }
private void handleBrightnessChange(LogicalDisplay display) { private void handleBrightnessChange(LogicalDisplay display) {
sendDisplayEventLocked(display.getDisplayIdLocked(), sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED);
DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED);
} }
private DisplayDevice getDeviceForDisplayLocked(int displayId) { private DisplayDevice getDeviceForDisplayLocked(int displayId) {
@@ -2854,12 +2846,12 @@ public final class DisplayManagerService extends SystemService {
* Returns the list of all display ids. * Returns the list of all display ids.
*/ */
@Override // Binder call @Override // Binder call
public int[] getDisplayIds() { public int[] getDisplayIds(boolean includeDisabled) {
final int callingUid = Binder.getCallingUid(); final int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity(); final long token = Binder.clearCallingIdentity();
try { try {
synchronized (mSyncRoot) { synchronized (mSyncRoot) {
return mLogicalDisplayMapper.getDisplayIdsLocked(callingUid); return mLogicalDisplayMapper.getDisplayIdsLocked(callingUid, includeDisabled);
} }
} finally { } finally {
Binder.restoreCallingIdentity(token); Binder.restoreCallingIdentity(token);
@@ -3337,6 +3329,11 @@ public final class DisplayManagerService extends SystemService {
final long token = Binder.clearCallingIdentity(); final long token = Binder.clearCallingIdentity();
try { try {
synchronized (mSyncRoot) { synchronized (mSyncRoot) {
LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(
displayId, /* includeDisabled= */ false);
if (display == null || !display.isEnabledLocked()) {
return null;
}
DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) { if (dpc != null) {
return dpc.getBrightnessInfo(); return dpc.getBrightnessInfo();

View File

@@ -16,6 +16,7 @@
package com.android.server.display; 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.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE;
import static android.os.PowerManager.BRIGHTNESS_INVALID; import static android.os.PowerManager.BRIGHTNESS_INVALID;
@@ -1457,7 +1458,7 @@ public class DisplayModeDirector {
SparseArray<Display.Mode[]> modes = new SparseArray<>(); SparseArray<Display.Mode[]> modes = new SparseArray<>();
SparseArray<Display.Mode> defaultModes = new SparseArray<>(); SparseArray<Display.Mode> defaultModes = new SparseArray<>();
DisplayInfo info = new DisplayInfo(); DisplayInfo info = new DisplayInfo();
Display[] displays = dm.getDisplays(); Display[] displays = dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
for (Display d : displays) { for (Display d : displays) {
final int displayId = d.getDisplayId(); final int displayId = d.getDisplayId();
d.getDisplayInfo(info); d.getDisplayInfo(info);
@@ -2332,7 +2333,8 @@ public class DisplayModeDirector {
sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this); sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
synchronized (mSensorObserverLock) { synchronized (mSensorObserverLock) {
for (Display d : mDisplayManager.getDisplays()) { for (Display d : mDisplayManager.getDisplays(
DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d)); mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
} }
} }
@@ -2343,7 +2345,8 @@ public class DisplayModeDirector {
} }
private void recalculateVotesLocked() { private void recalculateVotesLocked() {
final Display[] displays = mDisplayManager.getDisplays(); final Display[] displays = mDisplayManager.getDisplays(
DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
for (Display d : displays) { for (Display d : displays) {
int displayId = d.getDisplayId(); int displayId = d.getDisplayId();
Vote vote = null; Vote vote = null;

View File

@@ -491,6 +491,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private final String mSuspendBlockerIdProxNegative; private final String mSuspendBlockerIdProxNegative;
private final String mSuspendBlockerIdProxDebounce; private final String mSuspendBlockerIdProxDebounce;
private boolean mIsEnabled;
private boolean mIsInTransition;
/** /**
* Creates the display power controller. * Creates the display power controller.
*/ */
@@ -512,6 +515,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
mDisplayStatsId = mUniqueDisplayId.hashCode(); mDisplayStatsId = mUniqueDisplayId.hashCode();
mIsEnabled = logicalDisplay.isEnabledLocked();
mIsInTransition = logicalDisplay.isInTransitionLocked();
mHandler = new DisplayControllerHandler(handler.getLooper()); mHandler = new DisplayControllerHandler(handler.getLooper());
mLastBrightnessEvent = new BrightnessEvent(mDisplayId); mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
mTempBrightnessEvent = new BrightnessEvent(mDisplayId); mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
@@ -789,13 +794,30 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
final DisplayDeviceConfig config = device.getDisplayDeviceConfig(); final DisplayDeviceConfig config = device.getDisplayDeviceConfig();
final IBinder token = device.getDisplayTokenLocked(); final IBinder token = device.getDisplayTokenLocked();
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean isEnabled = mLogicalDisplay.isEnabledLocked();
final boolean isInTransition = mLogicalDisplay.isInTransitionLocked();
mHandler.post(() -> { mHandler.post(() -> {
boolean changed = false;
if (mDisplayDevice != device) { if (mDisplayDevice != device) {
changed = true;
mDisplayDevice = device; mDisplayDevice = device;
mUniqueDisplayId = uniqueId; mUniqueDisplayId = uniqueId;
mDisplayStatsId = mUniqueDisplayId.hashCode(); mDisplayStatsId = mUniqueDisplayId.hashCode();
mDisplayDeviceConfig = config; mDisplayDeviceConfig = config;
loadFromDisplayDeviceConfig(token, info); 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) { if (DEBUG) {
Trace.beginAsyncSection("DisplayPowerController#updatePowerState", 0); 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. * Unregisters all listeners and interrupts all running threads; halting future work.
* *
@@ -1291,8 +1304,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mIgnoreProximityUntilChanged = false; mIgnoreProximityUntilChanged = false;
} }
if (!mLogicalDisplay.isEnabled() if (!mIsEnabled
|| mLogicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION || mIsInTransition
|| mScreenOffBecauseOfProximity) { || mScreenOffBecauseOfProximity) {
state = Display.STATE_OFF; state = Display.STATE_OFF;
} }

View File

@@ -145,7 +145,7 @@ final class DisplayPowerState {
public void setScreenState(int state) { public void setScreenState(int state) {
if (mScreenState != state) { if (mScreenState != state) {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "setScreenState: state=" + state); Slog.w(TAG, "setScreenState: state=" + Display.stateToString(state));
} }
mScreenState = state; mScreenState = state;
@@ -339,6 +339,15 @@ final class DisplayPowerState {
if (mColorFade != null) mColorFade.dump(pw); 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() { private void scheduleScreenUpdate() {
if (!mScreenUpdatePending) { if (!mScreenUpdatePending) {
mScreenUpdatePending = true; mScreenUpdatePending = true;

View File

@@ -18,7 +18,6 @@ package com.android.server.display;
import static com.android.server.display.DisplayDeviceInfo.TOUCH_NONE; import static com.android.server.display.DisplayDeviceInfo.TOUCH_NONE;
import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.graphics.Point; import android.graphics.Point;
@@ -68,33 +67,6 @@ import java.util.Objects;
final class LogicalDisplay { final class LogicalDisplay {
private static final String TAG = "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 // The layer stack we use when the display has been blanked to prevent any
// of its content from appearing. // of its content from appearing.
private static final int BLANK_LAYER_STACK = -1; private static final int BLANK_LAYER_STACK = -1;
@@ -158,14 +130,6 @@ final class LogicalDisplay {
private final Rect mTempLayerStackRect = new Rect(); private final Rect mTempLayerStackRect = new Rect();
private final Rect mTempDisplayRect = 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 * The UID mappings for refresh rate override
*/ */
@@ -181,12 +145,22 @@ final class LogicalDisplay {
*/ */
private final SparseArray<Float> mTempFrameRateOverride; 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) { public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
mDisplayId = displayId; mDisplayId = displayId;
mLayerStack = layerStack; mLayerStack = layerStack;
mPrimaryDisplayDevice = primaryDisplayDevice; mPrimaryDisplayDevice = primaryDisplayDevice;
mPendingFrameRateOverrideUids = new ArraySet<>(); mPendingFrameRateOverrideUids = new ArraySet<>();
mTempFrameRateOverride = new SparseArray<>(); mTempFrameRateOverride = new SparseArray<>();
mIsEnabled = true;
mIsInTransition = false;
} }
/** /**
@@ -525,7 +499,7 @@ final class LogicalDisplay {
// Prevent displays that are disabled from receiving input. // Prevent displays that are disabled from receiving input.
// TODO(b/188914255): Remove once input can dispatch against device vs layerstack. // TODO(b/188914255): Remove once input can dispatch against device vs layerstack.
device.setDisplayFlagsLocked(t, device.setDisplayFlagsLocked(t,
(isEnabled() && device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE) (isEnabledLocked() && device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE)
? SurfaceControl.DISPLAY_RECEIVES_INPUT ? SurfaceControl.DISPLAY_RECEIVES_INPUT
: 0); : 0);
@@ -767,32 +741,45 @@ final class LogicalDisplay {
return old; 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} * @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 * if disabled indicating that the display should be hidden from the rest of the apps and
* framework. * framework.
*/ */
public boolean isEnabled() { public boolean isEnabledLocked() {
// DISPLAY_PHASE_LAYOUT_TRANSITION is still considered an 'enabled' phase. return mIsEnabled;
return mPhase == DISPLAY_PHASE_ENABLED || mPhase == DISPLAY_PHASE_LAYOUT_TRANSITION; }
/**
* 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) { public void dumpLocked(PrintWriter pw) {
pw.println("mDisplayId=" + mDisplayId); pw.println("mDisplayId=" + mDisplayId);
pw.println("mPhase=" + mPhase); pw.println("mIsEnabled=" + mIsEnabled);
pw.println("mIsInTransition=" + mIsInTransition);
pw.println("mLayerStack=" + mLayerStack); pw.println("mLayerStack=" + mLayerStack);
pw.println("mHasContent=" + mHasContent); pw.println("mHasContent=" + mHasContent);
pw.println("mDesiredDisplayModeSpecs={" + mDesiredDisplayModeSpecs + "}"); pw.println("mDesiredDisplayModeSpecs={" + mDesiredDisplayModeSpecs + "}");

View File

@@ -39,7 +39,6 @@ import android.view.DisplayAddress;
import android.view.DisplayInfo; import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.LogicalDisplay.DisplayPhase;
import com.android.server.display.layout.Layout; import com.android.server.display.layout.Layout;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -167,6 +166,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo, LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
@NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
@NonNull Handler handler) { @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; mSyncRoot = syncRoot;
mPowerManager = context.getSystemService(PowerManager.class); mPowerManager = context.getSystemService(PowerManager.class);
mInteractive = mPowerManager.isInteractive(); mInteractive = mPowerManager.isInteractive();
@@ -181,7 +186,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
mDeviceStatesOnWhichToSleep = toSparseBooleanArray(context.getResources().getIntArray( mDeviceStatesOnWhichToSleep = toSparseBooleanArray(context.getResources().getIntArray(
com.android.internal.R.array.config_deviceStatesOnWhichToSleep)); com.android.internal.R.array.config_deviceStatesOnWhichToSleep));
mDisplayDeviceRepo.addListener(this); mDisplayDeviceRepo.addListener(this);
mDeviceStateToLayoutMap = new DeviceStateToLayoutMap(); mDeviceStateToLayoutMap = deviceStateToLayoutMap;
} }
@Override @Override
@@ -218,10 +223,22 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
} }
public LogicalDisplay getDisplayLocked(int displayId) { 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) { public LogicalDisplay getDisplayLocked(DisplayDevice device) {
return getDisplayLocked(device, /* includeDisabled= */ true);
}
public LogicalDisplay getDisplayLocked(DisplayDevice device, boolean includeDisabled) {
if (device == null) { if (device == null) {
return null; return null;
} }
@@ -229,23 +246,28 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
final LogicalDisplay display = mLogicalDisplays.valueAt(i); final LogicalDisplay display = mLogicalDisplays.valueAt(i);
if (display.getPrimaryDisplayDeviceLocked() == device) { if (display.getPrimaryDisplayDeviceLocked() == device) {
if (display.isEnabledLocked() || includeDisabled) {
return display; return display;
} }
return null;
}
} }
return null; return null;
} }
public int[] getDisplayIdsLocked(int callingUid) { public int[] getDisplayIdsLocked(int callingUid, boolean includeDisabled) {
final int count = mLogicalDisplays.size(); final int count = mLogicalDisplays.size();
int[] displayIds = new int[count]; int[] displayIds = new int[count];
int n = 0; int n = 0;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
LogicalDisplay display = mLogicalDisplays.valueAt(i); LogicalDisplay display = mLogicalDisplays.valueAt(i);
if (display.isEnabledLocked() || includeDisabled) {
DisplayInfo info = display.getDisplayInfoLocked(); DisplayInfo info = display.getDisplayInfoLocked();
if (info.hasAccess(callingUid)) { if (info.hasAccess(callingUid)) {
displayIds[n++] = mLogicalDisplays.keyAt(i); displayIds[n++] = mLogicalDisplays.keyAt(i);
} }
} }
}
if (n != count) { if (n != count) {
displayIds = Arrays.copyOfRange(displayIds, 0, n); displayIds = Arrays.copyOfRange(displayIds, 0, n);
} }
@@ -364,14 +386,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
void setDeviceStateLocked(int state, boolean isOverrideActive) { void setDeviceStateLocked(int state, boolean isOverrideActive) {
Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState 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 // 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 // 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. // temporarily turned off.
if (mDeviceState != DeviceStateManager.INVALID_DEVICE_STATE) { resetLayoutLocked(mDeviceState, state, /* isStateChangeStarting= */ true);
resetLayoutLocked(mDeviceState, state, LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION);
}
mPendingDeviceState = state; mPendingDeviceState = state;
final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState, final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState,
mInteractive, mBootCompleted); mInteractive, mBootCompleted);
@@ -481,7 +501,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
final int count = mLogicalDisplays.size(); final int count = mLogicalDisplays.size();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
final LogicalDisplay display = mLogicalDisplays.valueAt(i); final LogicalDisplay display = mLogicalDisplays.valueAt(i);
if (display.getPhase() != LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) { if (!display.isInTransitionLocked()) {
continue; continue;
} }
@@ -497,7 +517,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
} }
private void transitionToPendingStateLocked() { private void transitionToPendingStateLocked() {
resetLayoutLocked(mDeviceState, mPendingDeviceState, LogicalDisplay.DISPLAY_PHASE_ENABLED); resetLayoutLocked(mDeviceState, mPendingDeviceState, /* isStateChangeStarting= */ false);
mDeviceState = mPendingDeviceState; mDeviceState = mPendingDeviceState;
mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE; mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
applyLayoutLocked(); 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 * 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 * {@code toState} and un/marks them for transition. When a new layout is requested, we
* put the displays that will change into a transitional phase so that they can all be turned * 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 the phase to * OFF. Once all are confirmed OFF, then this method gets called again to reset transition
* normal operation. This helps to ensure that all display-OFF requests are made before * 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. * display-ON which in turn hides any resizing-jank windows might incur when switching displays.
* *
* @param fromState The state we are switching from. * @param fromState The state we are switching from.
* @param toState The state we are switching to. * @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 fromLayout = mDeviceStateToLayoutMap.get(fromState);
final Layout toLayout = mDeviceStateToLayoutMap.get(toState); final Layout toLayout = mDeviceStateToLayoutMap.get(toState);
@@ -817,12 +837,16 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
// new layout. // new layout.
final DisplayAddress address = device.getDisplayDeviceInfoLocked().address; 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 = final Layout.Display fromDisplay =
address != null ? fromLayout.getByAddress(address) : null; address != null ? fromLayout.getByAddress(address) : null;
final Layout.Display toDisplay = final Layout.Display toDisplay =
address != null ? toLayout.getByAddress(address) : null; 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 // 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. // to enabled. This is why we treat null as "enabled" in the code below.
final boolean wasEnabled = fromDisplay == null || fromDisplay.isEnabled(); 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 // 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 // would look like apps moving from one screen to another since task-stacks stay
// with the logical display [ID]. // with the logical display [ID].
// 4) It's in one layout but not the other, so the content will change.
final boolean isTransitioning = final boolean isTransitioning =
(logicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) logicalDisplay.isInTransitionLocked()
|| (wasEnabled != willBeEnabled) || (wasEnabled != willBeEnabled)
|| deviceHasNewLogicalDisplayId; || deviceHasNewLogicalDisplayId
|| displayNotInBothLayouts;
if (isTransitioning) { if (isTransitioning) {
setDisplayPhase(logicalDisplay, phase); if (isStateChangeStarting != logicalDisplay.isInTransitionLocked()) {
if (phase == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) { Slog.i(TAG, "Set isInTransition on display " + displayId + ": "
mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_TRANSITION); + 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); newDisplay.swapDisplaysLocked(oldDisplay);
} }
if (!displayLayout.isEnabled()) { setEnabledLocked(newDisplay, displayLayout.isEnabled());
setDisplayPhase(newDisplay, LogicalDisplay.DISPLAY_PHASE_DISABLED);
}
} }
} }
@@ -912,23 +941,25 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device); final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
display.updateLocked(mDisplayDeviceRepo); display.updateLocked(mDisplayDeviceRepo);
mLogicalDisplays.put(displayId, display); mLogicalDisplays.put(displayId, display);
setDisplayPhase(display, LogicalDisplay.DISPLAY_PHASE_ENABLED);
return display; return display;
} }
private void setDisplayPhase(LogicalDisplay display, @DisplayPhase int phase) { private void setEnabledLocked(LogicalDisplay display, boolean isEnabled) {
final int displayId = display.getDisplayIdLocked(); final int displayId = display.getDisplayIdLocked();
final DisplayInfo info = display.getDisplayInfoLocked(); final DisplayInfo info = display.getDisplayInfoLocked();
final boolean disallowSecondaryDisplay = mSingleDisplayDemoMode final boolean disallowSecondaryDisplay = mSingleDisplayDemoMode
&& (info.type != Display.TYPE_INTERNAL); && (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" Slog.i(TAG, "Not creating a logical display for a secondary display because single"
+ " display demo mode is enabled: " + display.getDisplayInfoLocked()); + " 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) { private int assignDisplayGroupIdLocked(boolean isOwnDisplayGroup) {

View File

@@ -287,7 +287,7 @@ public class DisplayManagerServiceTest {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final int displayIds[] = bs.getDisplayIds(); final int[] displayIds = bs.getDisplayIds(/* includeDisabled= */ true);
final int size = displayIds.length; final int size = displayIds.length;
assertTrue(size > 0); assertTrue(size > 0);
@@ -1174,7 +1174,8 @@ public class DisplayManagerServiceTest {
DisplayManagerService.BinderService displayManagerBinderService, DisplayManagerService.BinderService displayManagerBinderService,
FakeDisplayDevice displayDevice) { FakeDisplayDevice displayDevice) {
final int[] displayIds = displayManagerBinderService.getDisplayIds(); final int[] displayIds = displayManagerBinderService.getDisplayIds(
/* includeDisabled= */ true);
assertTrue(displayIds.length > 0); assertTrue(displayIds.length > 0);
int displayId = Display.INVALID_DISPLAY; int displayId = Display.INVALID_DISPLAY;
for (int i = 0; i < displayIds.length; i++) { for (int i = 0; i < displayIds.length; i++) {

View File

@@ -30,6 +30,8 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals; 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.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.clearInvocations;
@@ -53,6 +55,8 @@ import android.view.DisplayInfo;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
import com.android.server.display.layout.Layout;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -60,6 +64,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Captor; import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@@ -85,6 +90,7 @@ public class LogicalDisplayMapperTest {
@Mock Resources mResourcesMock; @Mock Resources mResourcesMock;
@Mock IPowerManager mIPowerManagerMock; @Mock IPowerManager mIPowerManagerMock;
@Mock IThermalService mIThermalServiceMock; @Mock IThermalService mIThermalServiceMock;
@Spy DeviceStateToLayoutMap mDeviceStateToLayoutMapSpy = new DeviceStateToLayoutMap();
@Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor; @Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor;
@@ -134,7 +140,8 @@ public class LogicalDisplayMapperTest {
mLooper = new TestLooper(); mLooper = new TestLooper();
mHandler = new Handler(mLooper.getLooper()); mHandler = new Handler(mLooper.getLooper());
mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo, 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_EXTERNAL, 600, 800, 0));
add(createDisplayDevice(Display.TYPE_VIRTUAL, 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); assertEquals(3, ids.length);
Arrays.sort(ids); Arrays.sort(ids);
assertEquals(DEFAULT_DISPLAY, ids[0]); assertEquals(DEFAULT_DISPLAY, ids[0]);
@@ -413,6 +421,178 @@ public class LogicalDisplayMapperTest {
/* isBootCompleted= */true)); /* 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 // Helper Methods
///////////////// /////////////////
@@ -477,6 +657,7 @@ public class LogicalDisplayMapperTest {
class TestDisplayDevice extends DisplayDevice { class TestDisplayDevice extends DisplayDevice {
private DisplayDeviceInfo mInfo; private DisplayDeviceInfo mInfo;
private DisplayDeviceInfo mSentInfo; private DisplayDeviceInfo mSentInfo;
private int mState;
TestDisplayDevice() { TestDisplayDevice() {
super(null, null, "test_display_" + sUniqueTestDisplayId++, mContextMock); super(null, null, "test_display_" + sUniqueTestDisplayId++, mContextMock);

View File

@@ -128,12 +128,12 @@ public class LogicalDisplayTest {
verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT)); verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT));
reset(t); reset(t);
mLogicalDisplay.setPhase(LogicalDisplay.DISPLAY_PHASE_DISABLED); mLogicalDisplay.setEnabledLocked(false);
mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
verify(t).setDisplayFlags(any(), eq(0)); verify(t).setDisplayFlags(any(), eq(0));
reset(t); reset(t);
mLogicalDisplay.setPhase(LogicalDisplay.DISPLAY_PHASE_ENABLED); mLogicalDisplay.setEnabledLocked(true);
mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT)); verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT));