1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.display; 18 19 import android.app.ActivityThread; 20 import android.content.Context; 21 import android.content.res.Resources; 22 import android.hardware.sidekick.SidekickInternal; 23 import android.os.Build; 24 import android.os.Handler; 25 import android.os.IBinder; 26 import android.os.Looper; 27 import android.os.PowerManager; 28 import android.os.SystemProperties; 29 import android.os.Trace; 30 import android.util.LongSparseArray; 31 import android.util.Slog; 32 import android.util.SparseArray; 33 import android.view.Display; 34 import android.view.DisplayAddress; 35 import android.view.DisplayCutout; 36 import android.view.DisplayEventReceiver; 37 import android.view.RoundedCorners; 38 import android.view.SurfaceControl; 39 40 import com.android.internal.annotations.VisibleForTesting; 41 import com.android.internal.display.BrightnessSynchronizer; 42 import com.android.internal.util.function.pooled.PooledLambda; 43 import com.android.server.LocalServices; 44 import com.android.server.lights.LightsManager; 45 import com.android.server.lights.LogicalLight; 46 47 import java.io.PrintWriter; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.Collections; 51 import java.util.List; 52 import java.util.Objects; 53 54 /** 55 * A display adapter for the local displays managed by SurfaceFlinger. 56 * <p> 57 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock. 58 * </p> 59 */ 60 final class LocalDisplayAdapter extends DisplayAdapter { 61 private static final String TAG = "LocalDisplayAdapter"; 62 private static final boolean DEBUG = false; 63 64 private static final String UNIQUE_ID_PREFIX = "local:"; 65 66 private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular"; 67 68 private static final int NO_DISPLAY_MODE_ID = 0; 69 70 private final LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>(); 71 72 private final Injector mInjector; 73 74 private final SurfaceControlProxy mSurfaceControlProxy; 75 76 // Called with SyncRoot lock held. LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener)77 public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, 78 Context context, Handler handler, Listener listener) { 79 this(syncRoot, context, handler, listener, new Injector()); 80 } 81 82 @VisibleForTesting LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, Injector injector)83 LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, 84 Context context, Handler handler, Listener listener, Injector injector) { 85 super(syncRoot, context, handler, listener, TAG); 86 mInjector = injector; 87 mSurfaceControlProxy = mInjector.getSurfaceControlProxy(); 88 } 89 90 @Override registerLocked()91 public void registerLocked() { 92 super.registerLocked(); 93 94 mInjector.setDisplayEventListenerLocked(getHandler().getLooper(), 95 new LocalDisplayEventListener()); 96 97 for (long physicalDisplayId : mSurfaceControlProxy.getPhysicalDisplayIds()) { 98 tryConnectDisplayLocked(physicalDisplayId); 99 } 100 } 101 tryConnectDisplayLocked(long physicalDisplayId)102 private void tryConnectDisplayLocked(long physicalDisplayId) { 103 final IBinder displayToken = 104 mSurfaceControlProxy.getPhysicalDisplayToken(physicalDisplayId); 105 if (displayToken != null) { 106 SurfaceControl.StaticDisplayInfo staticInfo = 107 mSurfaceControlProxy.getStaticDisplayInfo(displayToken); 108 if (staticInfo == null) { 109 Slog.w(TAG, "No valid static info found for display device " + physicalDisplayId); 110 return; 111 } 112 SurfaceControl.DynamicDisplayInfo dynamicInfo = 113 mSurfaceControlProxy.getDynamicDisplayInfo(displayToken); 114 if (dynamicInfo == null) { 115 Slog.w(TAG, "No valid dynamic info found for display device " + physicalDisplayId); 116 return; 117 } 118 if (dynamicInfo.supportedDisplayModes == null) { 119 // There are no valid modes for this device, so we can't use it 120 Slog.w(TAG, "No valid modes found for display device " + physicalDisplayId); 121 return; 122 } 123 if (dynamicInfo.activeDisplayModeId < 0) { 124 // There is no active mode, and for now we don't have the 125 // policy to set one. 126 Slog.w(TAG, "No valid active mode found for display device " + physicalDisplayId); 127 return; 128 } 129 if (dynamicInfo.activeColorMode < 0) { 130 // We failed to get the active color mode. We don't bail out here since on the next 131 // configuration pass we'll go ahead and set it to whatever it was set to last (or 132 // COLOR_MODE_NATIVE if this is the first configuration). 133 Slog.w(TAG, "No valid active color mode for display device " + physicalDisplayId); 134 dynamicInfo.activeColorMode = Display.COLOR_MODE_INVALID; 135 } 136 SurfaceControl.DesiredDisplayModeSpecs modeSpecs = 137 mSurfaceControlProxy.getDesiredDisplayModeSpecs(displayToken); 138 LocalDisplayDevice device = mDevices.get(physicalDisplayId); 139 if (device == null) { 140 // Display was added. 141 final boolean isDefaultDisplay = mDevices.size() == 0; 142 device = new LocalDisplayDevice(displayToken, physicalDisplayId, staticInfo, 143 dynamicInfo, modeSpecs, isDefaultDisplay); 144 mDevices.put(physicalDisplayId, device); 145 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); 146 } else if (device.updateDisplayPropertiesLocked(staticInfo, dynamicInfo, 147 modeSpecs)) { 148 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED); 149 } 150 } else { 151 // The display is no longer available. Ignore the attempt to add it. 152 // If it was connected but has already been disconnected, we'll get a 153 // disconnect event that will remove it from mDevices. 154 } 155 } 156 tryDisconnectDisplayLocked(long physicalDisplayId)157 private void tryDisconnectDisplayLocked(long physicalDisplayId) { 158 LocalDisplayDevice device = mDevices.get(physicalDisplayId); 159 if (device != null) { 160 // Display was removed. 161 mDevices.remove(physicalDisplayId); 162 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED); 163 } 164 } 165 getPowerModeForState(int state)166 static int getPowerModeForState(int state) { 167 switch (state) { 168 case Display.STATE_OFF: 169 return SurfaceControl.POWER_MODE_OFF; 170 case Display.STATE_DOZE: 171 return SurfaceControl.POWER_MODE_DOZE; 172 case Display.STATE_DOZE_SUSPEND: 173 return SurfaceControl.POWER_MODE_DOZE_SUSPEND; 174 case Display.STATE_ON_SUSPEND: 175 return SurfaceControl.POWER_MODE_ON_SUSPEND; 176 default: 177 return SurfaceControl.POWER_MODE_NORMAL; 178 } 179 } 180 181 private final class LocalDisplayDevice extends DisplayDevice { 182 private final long mPhysicalDisplayId; 183 private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>(); 184 private final ArrayList<Integer> mSupportedColorModes = new ArrayList<>(); 185 private final boolean mIsDefaultDisplay; 186 private final BacklightAdapter mBacklightAdapter; 187 188 private DisplayDeviceInfo mInfo; 189 private boolean mHavePendingChanges; 190 private int mState = Display.STATE_UNKNOWN; 191 // This is only set in the runnable returned from requestDisplayStateLocked. 192 private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT; 193 private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT; 194 private int mDefaultModeId; 195 private int mDefaultModeGroup; 196 private int mActiveModeId; 197 private DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs = 198 new DisplayModeDirector.DesiredDisplayModeSpecs(); 199 private boolean mDisplayModeSpecsInvalid; 200 private int mActiveColorMode; 201 private Display.HdrCapabilities mHdrCapabilities; 202 private boolean mAllmSupported; 203 private boolean mGameContentTypeSupported; 204 private boolean mAllmRequested; 205 private boolean mGameContentTypeRequested; 206 private boolean mSidekickActive; 207 private SidekickInternal mSidekickInternal; 208 private SurfaceControl.StaticDisplayInfo mStaticDisplayInfo; 209 // The supported display modes according in SurfaceFlinger 210 private SurfaceControl.DisplayMode[] mSfDisplayModes; 211 // The active display mode in SurfaceFlinger 212 private SurfaceControl.DisplayMode mActiveSfDisplayMode; 213 private DisplayDeviceConfig mDisplayDeviceConfig; 214 215 private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides = 216 new DisplayEventReceiver.FrameRateOverride[0]; 217 LocalDisplayDevice(IBinder displayToken, long physicalDisplayId, SurfaceControl.StaticDisplayInfo staticDisplayInfo, SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isDefaultDisplay)218 LocalDisplayDevice(IBinder displayToken, long physicalDisplayId, 219 SurfaceControl.StaticDisplayInfo staticDisplayInfo, 220 SurfaceControl.DynamicDisplayInfo dynamicInfo, 221 SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isDefaultDisplay) { 222 super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId, 223 getContext()); 224 mPhysicalDisplayId = physicalDisplayId; 225 mIsDefaultDisplay = isDefaultDisplay; 226 updateDisplayPropertiesLocked(staticDisplayInfo, dynamicInfo, modeSpecs); 227 mSidekickInternal = LocalServices.getService(SidekickInternal.class); 228 mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay, 229 mSurfaceControlProxy); 230 mDisplayDeviceConfig = null; 231 } 232 233 @Override hasStableUniqueId()234 public boolean hasStableUniqueId() { 235 return true; 236 } 237 238 /** 239 * Returns true if there is a change. 240 **/ updateDisplayPropertiesLocked(SurfaceControl.StaticDisplayInfo staticInfo, SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs)241 public boolean updateDisplayPropertiesLocked(SurfaceControl.StaticDisplayInfo staticInfo, 242 SurfaceControl.DynamicDisplayInfo dynamicInfo, 243 SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { 244 boolean changed = updateDisplayModesLocked( 245 dynamicInfo.supportedDisplayModes, dynamicInfo.activeDisplayModeId, modeSpecs); 246 changed |= updateStaticInfo(staticInfo); 247 changed |= updateColorModesLocked(dynamicInfo.supportedColorModes, 248 dynamicInfo.activeColorMode); 249 changed |= updateHdrCapabilitiesLocked(dynamicInfo.hdrCapabilities); 250 changed |= updateAllmSupport(dynamicInfo.autoLowLatencyModeSupported); 251 changed |= updateGameContentTypeSupport(dynamicInfo.gameContentTypeSupported); 252 253 if (changed) { 254 mHavePendingChanges = true; 255 } 256 return changed; 257 } 258 updateDisplayModesLocked( SurfaceControl.DisplayMode[] displayModes, int activeDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs)259 public boolean updateDisplayModesLocked( 260 SurfaceControl.DisplayMode[] displayModes, int activeDisplayModeId, 261 SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { 262 mSfDisplayModes = Arrays.copyOf(displayModes, displayModes.length); 263 mActiveSfDisplayMode = getModeById(displayModes, activeDisplayModeId); 264 265 // Build an updated list of all existing modes. 266 ArrayList<DisplayModeRecord> records = new ArrayList<>(); 267 boolean modesAdded = false; 268 for (int i = 0; i < displayModes.length; i++) { 269 SurfaceControl.DisplayMode mode = displayModes[i]; 270 List<Float> alternativeRefreshRates = new ArrayList<>(); 271 for (int j = 0; j < displayModes.length; j++) { 272 SurfaceControl.DisplayMode other = displayModes[j]; 273 boolean isAlternative = j != i && other.width == mode.width 274 && other.height == mode.height 275 && other.refreshRate != mode.refreshRate 276 && other.group == mode.group; 277 if (isAlternative) { 278 alternativeRefreshRates.add(displayModes[j].refreshRate); 279 } 280 } 281 Collections.sort(alternativeRefreshRates); 282 283 // First, check to see if we've already added a matching mode. Since not all 284 // configuration options are exposed via Display.Mode, it's possible that we have 285 // multiple DisplayModes that would generate the same Display.Mode. 286 boolean existingMode = false; 287 for (DisplayModeRecord record : records) { 288 if (record.hasMatchingMode(mode) 289 && refreshRatesEquals(alternativeRefreshRates, 290 record.mMode.getAlternativeRefreshRates())) { 291 existingMode = true; 292 break; 293 } 294 } 295 if (existingMode) { 296 continue; 297 } 298 // If we haven't already added a mode for this configuration to the new set of 299 // supported modes then check to see if we have one in the prior set of supported 300 // modes to reuse. 301 DisplayModeRecord record = findDisplayModeRecord(mode, alternativeRefreshRates); 302 if (record == null) { 303 float[] alternativeRates = new float[alternativeRefreshRates.size()]; 304 for (int j = 0; j < alternativeRates.length; j++) { 305 alternativeRates[j] = alternativeRefreshRates.get(j); 306 } 307 record = new DisplayModeRecord(mode, alternativeRates); 308 modesAdded = true; 309 } 310 records.add(record); 311 } 312 313 // Get the currently active mode 314 DisplayModeRecord activeRecord = null; 315 for (DisplayModeRecord record : records) { 316 if (record.hasMatchingMode(mActiveSfDisplayMode)) { 317 activeRecord = record; 318 break; 319 } 320 } 321 322 boolean activeModeChanged = false; 323 324 // Check whether SurfaceFlinger or the display device changed the active mode out from 325 // under us. 326 if (mActiveModeId != NO_DISPLAY_MODE_ID 327 && mActiveModeId != activeRecord.mMode.getModeId()) { 328 Slog.d(TAG, "The active mode was changed from SurfaceFlinger or the display" 329 + "device."); 330 mActiveModeId = activeRecord.mMode.getModeId(); 331 activeModeChanged = true; 332 sendTraversalRequestLocked(); 333 } 334 335 // Check whether surface flinger spontaneously changed display config specs out from 336 // under us. If so, schedule a traversal to reapply our display config specs. 337 if (mDisplayModeSpecs.baseModeId != NO_DISPLAY_MODE_ID) { 338 int activeBaseMode = findMatchingModeIdLocked(modeSpecs.defaultMode); 339 // If we can't map the defaultMode index to a mode, then the physical display 340 // modes must have changed, and the code below for handling changes to the 341 // list of available modes will take care of updating display mode specs. 342 if (activeBaseMode == NO_DISPLAY_MODE_ID 343 || mDisplayModeSpecs.baseModeId != activeBaseMode 344 || mDisplayModeSpecs.primaryRefreshRateRange.min 345 != modeSpecs.primaryRefreshRateMin 346 || mDisplayModeSpecs.primaryRefreshRateRange.max 347 != modeSpecs.primaryRefreshRateMax 348 || mDisplayModeSpecs.appRequestRefreshRateRange.min 349 != modeSpecs.appRequestRefreshRateMin 350 || mDisplayModeSpecs.appRequestRefreshRateRange.max 351 != modeSpecs.appRequestRefreshRateMax) { 352 mDisplayModeSpecsInvalid = true; 353 sendTraversalRequestLocked(); 354 } 355 } 356 357 boolean recordsChanged = records.size() != mSupportedModes.size() || modesAdded; 358 // If the records haven't changed then we're done here. 359 if (!recordsChanged) { 360 return activeModeChanged; 361 } 362 363 mSupportedModes.clear(); 364 for (DisplayModeRecord record : records) { 365 mSupportedModes.put(record.mMode.getModeId(), record); 366 } 367 368 // For a new display, we need to initialize the default mode ID. 369 if (mDefaultModeId == NO_DISPLAY_MODE_ID) { 370 mDefaultModeId = activeRecord.mMode.getModeId(); 371 mDefaultModeGroup = mActiveSfDisplayMode.group; 372 } else if (modesAdded && activeModeChanged) { 373 Slog.d(TAG, "New display modes are added and the active mode has changed, " 374 + "use active mode as default mode."); 375 mDefaultModeId = activeRecord.mMode.getModeId(); 376 mDefaultModeGroup = mActiveSfDisplayMode.group; 377 } else if (findDisplayModeIdLocked(mDefaultModeId, mDefaultModeGroup) < 0) { 378 Slog.w(TAG, "Default display mode no longer available, using currently" 379 + " active mode as default."); 380 mDefaultModeId = activeRecord.mMode.getModeId(); 381 mDefaultModeGroup = mActiveSfDisplayMode.group; 382 } 383 384 // Determine whether the display mode specs' base mode is still there. 385 if (mSupportedModes.indexOfKey(mDisplayModeSpecs.baseModeId) < 0) { 386 if (mDisplayModeSpecs.baseModeId != NO_DISPLAY_MODE_ID) { 387 Slog.w(TAG, 388 "DisplayModeSpecs base mode no longer available, using currently" 389 + " active mode."); 390 } 391 mDisplayModeSpecs.baseModeId = activeRecord.mMode.getModeId(); 392 mDisplayModeSpecsInvalid = true; 393 } 394 395 // Determine whether the active mode is still there. 396 if (mSupportedModes.indexOfKey(mActiveModeId) < 0) { 397 if (mActiveModeId != NO_DISPLAY_MODE_ID) { 398 Slog.w(TAG, "Active display mode no longer available, reverting to default" 399 + " mode."); 400 } 401 mActiveModeId = mDefaultModeId; 402 } 403 404 // Schedule traversals so that we apply pending changes. 405 sendTraversalRequestLocked(); 406 return true; 407 } 408 409 @Override getDisplayDeviceConfig()410 public DisplayDeviceConfig getDisplayDeviceConfig() { 411 if (mDisplayDeviceConfig == null) { 412 loadDisplayDeviceConfig(); 413 } 414 return mDisplayDeviceConfig; 415 } 416 loadDisplayDeviceConfig()417 private void loadDisplayDeviceConfig() { 418 // Load display device config 419 final Context context = getOverlayContext(); 420 mDisplayDeviceConfig = DisplayDeviceConfig.create(context, mPhysicalDisplayId, 421 mIsDefaultDisplay); 422 if (mDisplayDeviceConfig == null) { 423 return; 424 } 425 426 // Load brightness HWC quirk 427 mBacklightAdapter.setForceSurfaceControl(mDisplayDeviceConfig.hasQuirk( 428 DisplayDeviceConfig.QUIRK_CAN_SET_BRIGHTNESS_VIA_HWC)); 429 } 430 updateStaticInfo(SurfaceControl.StaticDisplayInfo info)431 private boolean updateStaticInfo(SurfaceControl.StaticDisplayInfo info) { 432 if (Objects.equals(mStaticDisplayInfo, info)) { 433 return false; 434 } 435 mStaticDisplayInfo = info; 436 return true; 437 } 438 updateColorModesLocked(int[] colorModes, int activeColorMode)439 private boolean updateColorModesLocked(int[] colorModes, int activeColorMode) { 440 if (colorModes == null) { 441 return false; 442 } 443 444 List<Integer> pendingColorModes = new ArrayList<>(); 445 // Build an updated list of all existing color modes. 446 boolean colorModesAdded = false; 447 for (int colorMode : colorModes) { 448 if (!mSupportedColorModes.contains(colorMode)) { 449 colorModesAdded = true; 450 } 451 pendingColorModes.add(colorMode); 452 } 453 454 boolean colorModesChanged = 455 pendingColorModes.size() != mSupportedColorModes.size() 456 || colorModesAdded; 457 458 // If the supported color modes haven't changed then we're done here. 459 if (!colorModesChanged) { 460 return false; 461 } 462 463 mSupportedColorModes.clear(); 464 mSupportedColorModes.addAll(pendingColorModes); 465 Collections.sort(mSupportedColorModes); 466 467 // Determine whether the active color mode is still there. 468 if (!mSupportedColorModes.contains(mActiveColorMode)) { 469 if (mActiveColorMode != Display.COLOR_MODE_DEFAULT) { 470 Slog.w(TAG, "Active color mode no longer available, reverting" 471 + " to default mode."); 472 mActiveColorMode = Display.COLOR_MODE_DEFAULT; 473 } else { 474 if (!mSupportedColorModes.isEmpty()) { 475 // This should never happen. 476 Slog.e(TAG, "Default and active color mode is no longer available!" 477 + " Reverting to first available mode."); 478 mActiveColorMode = mSupportedColorModes.get(0); 479 } else { 480 // This should really never happen. 481 Slog.e(TAG, "No color modes available!"); 482 } 483 } 484 } 485 return true; 486 } 487 updateHdrCapabilitiesLocked(Display.HdrCapabilities newHdrCapabilities)488 private boolean updateHdrCapabilitiesLocked(Display.HdrCapabilities newHdrCapabilities) { 489 // If the HDR capabilities haven't changed, then we're done here. 490 if (Objects.equals(mHdrCapabilities, newHdrCapabilities)) { 491 return false; 492 } 493 mHdrCapabilities = newHdrCapabilities; 494 return true; 495 } 496 updateAllmSupport(boolean supported)497 private boolean updateAllmSupport(boolean supported) { 498 if (mAllmSupported == supported) { 499 return false; 500 } 501 mAllmSupported = supported; 502 return true; 503 } 504 updateGameContentTypeSupport(boolean supported)505 private boolean updateGameContentTypeSupport(boolean supported) { 506 if (mGameContentTypeSupported == supported) { 507 return false; 508 } 509 mGameContentTypeSupported = supported; 510 return true; 511 } 512 getModeById(SurfaceControl.DisplayMode[] supportedModes, int modeId)513 private SurfaceControl.DisplayMode getModeById(SurfaceControl.DisplayMode[] supportedModes, 514 int modeId) { 515 for (SurfaceControl.DisplayMode mode : supportedModes) { 516 if (mode.id == modeId) { 517 return mode; 518 } 519 } 520 Slog.e(TAG, "Can't find display mode with id " + modeId); 521 return null; 522 } 523 findDisplayModeRecord(SurfaceControl.DisplayMode mode, List<Float> alternativeRefreshRates)524 private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayMode mode, 525 List<Float> alternativeRefreshRates) { 526 for (int i = 0; i < mSupportedModes.size(); i++) { 527 DisplayModeRecord record = mSupportedModes.valueAt(i); 528 if (record.hasMatchingMode(mode) 529 && refreshRatesEquals(alternativeRefreshRates, 530 record.mMode.getAlternativeRefreshRates())) { 531 return record; 532 } 533 } 534 return null; 535 } 536 refreshRatesEquals(List<Float> list, float[] array)537 private boolean refreshRatesEquals(List<Float> list, float[] array) { 538 if (list.size() != array.length) { 539 return false; 540 } 541 for (int i = 0; i < list.size(); i++) { 542 if (Float.floatToIntBits(list.get(i)) != Float.floatToIntBits(array[i])) { 543 return false; 544 } 545 } 546 return true; 547 } 548 549 @Override applyPendingDisplayDeviceInfoChangesLocked()550 public void applyPendingDisplayDeviceInfoChangesLocked() { 551 if (mHavePendingChanges) { 552 mInfo = null; 553 mHavePendingChanges = false; 554 } 555 } 556 557 @Override getDisplayDeviceInfoLocked()558 public DisplayDeviceInfo getDisplayDeviceInfoLocked() { 559 if (mInfo == null) { 560 mInfo = new DisplayDeviceInfo(); 561 mInfo.width = mActiveSfDisplayMode.width; 562 mInfo.height = mActiveSfDisplayMode.height; 563 mInfo.modeId = mActiveModeId; 564 mInfo.defaultModeId = mDefaultModeId; 565 mInfo.supportedModes = getDisplayModes(mSupportedModes); 566 mInfo.colorMode = mActiveColorMode; 567 mInfo.allmSupported = mAllmSupported; 568 mInfo.gameContentTypeSupported = mGameContentTypeSupported; 569 mInfo.supportedColorModes = 570 new int[mSupportedColorModes.size()]; 571 for (int i = 0; i < mSupportedColorModes.size(); i++) { 572 mInfo.supportedColorModes[i] = mSupportedColorModes.get(i); 573 } 574 mInfo.hdrCapabilities = mHdrCapabilities; 575 mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos; 576 mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos; 577 mInfo.state = mState; 578 mInfo.uniqueId = getUniqueId(); 579 final DisplayAddress.Physical physicalAddress = 580 DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId); 581 mInfo.address = physicalAddress; 582 mInfo.densityDpi = (int) (mStaticDisplayInfo.density * 160 + 0.5f); 583 mInfo.xDpi = mActiveSfDisplayMode.xDpi; 584 mInfo.yDpi = mActiveSfDisplayMode.yDpi; 585 mInfo.deviceProductInfo = mStaticDisplayInfo.deviceProductInfo; 586 587 // Assume that all built-in displays that have secure output (eg. HDCP) also 588 // support compositing from gralloc protected buffers. 589 if (mStaticDisplayInfo.secure) { 590 mInfo.flags = DisplayDeviceInfo.FLAG_SECURE 591 | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; 592 } 593 594 final Resources res = getOverlayContext().getResources(); 595 596 if (mIsDefaultDisplay) { 597 mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY; 598 599 if (res.getBoolean(com.android.internal.R.bool.config_mainBuiltInDisplayIsRound) 600 || (Build.IS_EMULATOR 601 && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) { 602 mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND; 603 } 604 } else { 605 if (!res.getBoolean( 606 com.android.internal.R.bool.config_localDisplaysMirrorContent)) { 607 mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; 608 } 609 610 if (isDisplayPrivate(physicalAddress)) { 611 mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE; 612 } 613 } 614 615 if (DisplayCutout.getMaskBuiltInDisplayCutout(res, mInfo.uniqueId)) { 616 mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT; 617 } 618 mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res, 619 mInfo.uniqueId, mInfo.width, mInfo.height); 620 621 mInfo.roundedCorners = RoundedCorners.fromResources( 622 res, mInfo.uniqueId, mInfo.width, mInfo.height); 623 624 if (mStaticDisplayInfo.isInternal) { 625 mInfo.type = Display.TYPE_INTERNAL; 626 mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; 627 mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; 628 mInfo.name = res.getString( 629 com.android.internal.R.string.display_manager_built_in_display_name); 630 } else { 631 mInfo.type = Display.TYPE_EXTERNAL; 632 mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; 633 mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION; 634 mInfo.name = getContext().getResources().getString( 635 com.android.internal.R.string.display_manager_hdmi_display_name); 636 } 637 mInfo.frameRateOverrides = mFrameRateOverrides; 638 639 // The display is trusted since it is created by system. 640 mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED; 641 mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN; 642 mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX; 643 mInfo.brightnessDefault = getDisplayDeviceConfig().getBrightnessDefault(); 644 } 645 return mInfo; 646 } 647 648 @Override requestDisplayStateLocked(final int state, final float brightnessState, final float sdrBrightnessState)649 public Runnable requestDisplayStateLocked(final int state, final float brightnessState, 650 final float sdrBrightnessState) { 651 // Assume that the brightness is off if the display is being turned off. 652 assert state != Display.STATE_OFF 653 || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT; 654 final boolean stateChanged = (mState != state); 655 final boolean brightnessChanged = mBrightnessState != brightnessState 656 || mSdrBrightnessState != sdrBrightnessState; 657 if (stateChanged || brightnessChanged) { 658 final long physicalDisplayId = mPhysicalDisplayId; 659 final IBinder token = getDisplayTokenLocked(); 660 final int oldState = mState; 661 662 if (stateChanged) { 663 mState = state; 664 updateDeviceInfoLocked(); 665 } 666 667 // Defer actually setting the display state until after we have exited 668 // the critical section since it can take hundreds of milliseconds 669 // to complete. 670 return new Runnable() { 671 @Override 672 public void run() { 673 // Exit a suspended state before making any changes. 674 int currentState = oldState; 675 if (Display.isSuspendedState(oldState) 676 || oldState == Display.STATE_UNKNOWN) { 677 if (!Display.isSuspendedState(state)) { 678 setDisplayState(state); 679 currentState = state; 680 } else if (state == Display.STATE_DOZE_SUSPEND 681 || oldState == Display.STATE_DOZE_SUSPEND) { 682 setDisplayState(Display.STATE_DOZE); 683 currentState = Display.STATE_DOZE; 684 } else if (state == Display.STATE_ON_SUSPEND 685 || oldState == Display.STATE_ON_SUSPEND) { 686 setDisplayState(Display.STATE_ON); 687 currentState = Display.STATE_ON; 688 689 // If UNKNOWN, we still want to set the initial display state, 690 // otherwise, return early. 691 } else if (oldState != Display.STATE_UNKNOWN) { 692 return; // old state and new state is off 693 } 694 } 695 696 // If the state change was from or to VR, then we need to tell the light 697 // so that it can apply appropriate VR brightness settings. Also, update the 698 // brightness so the state is propogated to light. 699 boolean vrModeChange = false; 700 if ((state == Display.STATE_VR || currentState == Display.STATE_VR) && 701 currentState != state) { 702 setVrMode(state == Display.STATE_VR); 703 vrModeChange = true; 704 } 705 706 // Apply brightness changes given that we are in a non-suspended state. 707 if (brightnessChanged || vrModeChange) { 708 setDisplayBrightness(brightnessState, sdrBrightnessState); 709 mBrightnessState = brightnessState; 710 mSdrBrightnessState = sdrBrightnessState; 711 } 712 713 // Enter the final desired state, possibly suspended. 714 if (state != currentState) { 715 setDisplayState(state); 716 } 717 } 718 719 private void setVrMode(boolean isVrEnabled) { 720 if (DEBUG) { 721 Slog.d(TAG, "setVrMode(" 722 + "id=" + physicalDisplayId 723 + ", state=" + Display.stateToString(state) + ")"); 724 } 725 mBacklightAdapter.setVrMode(isVrEnabled); 726 } 727 728 private void setDisplayState(int state) { 729 if (DEBUG) { 730 Slog.d(TAG, "setDisplayState(" 731 + "id=" + physicalDisplayId 732 + ", state=" + Display.stateToString(state) + ")"); 733 } 734 735 // We must tell sidekick to stop controlling the display before we 736 // can change its power mode, so do that first. 737 if (mSidekickActive) { 738 Trace.traceBegin(Trace.TRACE_TAG_POWER, 739 "SidekickInternal#endDisplayControl"); 740 try { 741 mSidekickInternal.endDisplayControl(); 742 } finally { 743 Trace.traceEnd(Trace.TRACE_TAG_POWER); 744 } 745 mSidekickActive = false; 746 } 747 final int mode = getPowerModeForState(state); 748 Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayState(" 749 + "id=" + physicalDisplayId 750 + ", state=" + Display.stateToString(state) + ")"); 751 try { 752 mSurfaceControlProxy.setDisplayPowerMode(token, mode); 753 Trace.traceCounter(Trace.TRACE_TAG_POWER, "DisplayPowerMode", mode); 754 } finally { 755 Trace.traceEnd(Trace.TRACE_TAG_POWER); 756 } 757 // If we're entering a suspended (but not OFF) power state and we 758 // have a sidekick available, tell it now that it can take control. 759 if (Display.isSuspendedState(state) && state != Display.STATE_OFF 760 && mSidekickInternal != null && !mSidekickActive) { 761 Trace.traceBegin(Trace.TRACE_TAG_POWER, 762 "SidekickInternal#startDisplayControl"); 763 try { 764 mSidekickActive = mSidekickInternal.startDisplayControl(state); 765 } finally { 766 Trace.traceEnd(Trace.TRACE_TAG_POWER); 767 } 768 } 769 } 770 771 private void setDisplayBrightness(float brightnessState, 772 float sdrBrightnessState) { 773 // brightnessState includes invalid, off and full range. 774 if (Float.isNaN(brightnessState) || Float.isNaN(sdrBrightnessState)) { 775 return; 776 } 777 778 if (DEBUG) { 779 Slog.d(TAG, "setDisplayBrightness(" 780 + "id=" + physicalDisplayId 781 + ", brightnessState=" + brightnessState 782 + ", sdrBrightnessState=" + sdrBrightnessState + ")"); 783 } 784 785 Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness(" 786 + "id=" + physicalDisplayId + ", brightnessState=" 787 + brightnessState + ", sdrBrightnessState=" + sdrBrightnessState 788 + ")"); 789 try { 790 final float backlight = brightnessToBacklight(brightnessState); 791 final float sdrBacklight = brightnessToBacklight(sdrBrightnessState); 792 793 final float nits = backlightToNits(backlight); 794 final float sdrNits = backlightToNits(sdrBacklight); 795 796 mBacklightAdapter.setBacklight(sdrBacklight, sdrNits, backlight, nits); 797 Trace.traceCounter(Trace.TRACE_TAG_POWER, 798 "ScreenBrightness", 799 BrightnessSynchronizer.brightnessFloatToInt(brightnessState)); 800 Trace.traceCounter(Trace.TRACE_TAG_POWER, 801 "SdrScreenBrightness", 802 BrightnessSynchronizer.brightnessFloatToInt( 803 sdrBrightnessState)); 804 } finally { 805 Trace.traceEnd(Trace.TRACE_TAG_POWER); 806 } 807 } 808 809 private float brightnessToBacklight(float brightness) { 810 if (brightness == PowerManager.BRIGHTNESS_OFF_FLOAT) { 811 return PowerManager.BRIGHTNESS_OFF_FLOAT; 812 } else { 813 return getDisplayDeviceConfig().getBacklightFromBrightness(brightness); 814 } 815 } 816 817 private float backlightToNits(float backlight) { 818 return getDisplayDeviceConfig().getNitsFromBacklight(backlight); 819 } 820 }; 821 } 822 return null; 823 } 824 825 @Override setRequestedColorModeLocked(int colorMode)826 public void setRequestedColorModeLocked(int colorMode) { 827 requestColorModeLocked(colorMode); 828 } 829 830 @Override setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs)831 public void setDesiredDisplayModeSpecsLocked( 832 DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) { 833 if (displayModeSpecs.baseModeId == 0) { 834 // Bail if the caller is requesting a null mode. We'll get called again shortly with 835 // a valid mode. 836 return; 837 } 838 839 // Find the mode Id based on the desired mode specs. In case there is more than one 840 // mode matching the mode spec, prefer the one that is in the default mode group. 841 // For now the default config mode is taken from the active mode when we got the 842 // hotplug event for the display. In the future we might want to change the default 843 // mode based on vendor requirements. 844 // Note: We prefer the default mode group over the current one as this is the mode 845 // group the vendor prefers. 846 int baseModeId = findDisplayModeIdLocked(displayModeSpecs.baseModeId, 847 mDefaultModeGroup); 848 if (baseModeId < 0) { 849 // When a display is hotplugged, it's possible for a mode to be removed that was 850 // previously valid. Because of the way display changes are propagated through the 851 // framework, and the caching of the display mode specs in LogicalDisplay, it's 852 // possible we'll get called with a stale mode id that no longer represents a valid 853 // mode. This should only happen in extremely rare cases. A followup call will 854 // contain a valid mode id. 855 Slog.w(TAG, 856 "Ignoring request for invalid base mode id " + displayModeSpecs.baseModeId); 857 updateDeviceInfoLocked(); 858 return; 859 } 860 if (mDisplayModeSpecsInvalid || !displayModeSpecs.equals(mDisplayModeSpecs)) { 861 mDisplayModeSpecsInvalid = false; 862 mDisplayModeSpecs.copyFrom(displayModeSpecs); 863 getHandler().sendMessage(PooledLambda.obtainMessage( 864 LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this, 865 getDisplayTokenLocked(), 866 new SurfaceControl.DesiredDisplayModeSpecs(baseModeId, 867 mDisplayModeSpecs.allowGroupSwitching, 868 mDisplayModeSpecs.primaryRefreshRateRange.min, 869 mDisplayModeSpecs.primaryRefreshRateRange.max, 870 mDisplayModeSpecs.appRequestRefreshRateRange.min, 871 mDisplayModeSpecs.appRequestRefreshRateRange.max))); 872 } 873 } 874 setDesiredDisplayModeSpecsAsync(IBinder displayToken, SurfaceControl.DesiredDisplayModeSpecs modeSpecs)875 private void setDesiredDisplayModeSpecsAsync(IBinder displayToken, 876 SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { 877 // Do not lock when calling these SurfaceControl methods because they are sync 878 // operations that may block for a while when setting display power mode. 879 mSurfaceControlProxy.setDesiredDisplayModeSpecs(displayToken, modeSpecs); 880 } 881 882 @Override onOverlayChangedLocked()883 public void onOverlayChangedLocked() { 884 updateDeviceInfoLocked(); 885 } 886 onActiveDisplayModeChangedLocked(int sfModeId)887 public void onActiveDisplayModeChangedLocked(int sfModeId) { 888 if (updateActiveModeLocked(sfModeId)) { 889 updateDeviceInfoLocked(); 890 } 891 } 892 onFrameRateOverridesChanged( DisplayEventReceiver.FrameRateOverride[] overrides)893 public void onFrameRateOverridesChanged( 894 DisplayEventReceiver.FrameRateOverride[] overrides) { 895 if (updateFrameRateOverridesLocked(overrides)) { 896 updateDeviceInfoLocked(); 897 } 898 } 899 updateActiveModeLocked(int activeSfModeId)900 public boolean updateActiveModeLocked(int activeSfModeId) { 901 if (mActiveSfDisplayMode.id == activeSfModeId) { 902 return false; 903 } 904 mActiveSfDisplayMode = getModeById(mSfDisplayModes, activeSfModeId); 905 mActiveModeId = findMatchingModeIdLocked(activeSfModeId); 906 if (mActiveModeId == NO_DISPLAY_MODE_ID) { 907 Slog.w(TAG, "In unknown mode after setting allowed modes" 908 + ", activeModeId=" + activeSfModeId); 909 } 910 return true; 911 } 912 updateFrameRateOverridesLocked( DisplayEventReceiver.FrameRateOverride[] overrides)913 public boolean updateFrameRateOverridesLocked( 914 DisplayEventReceiver.FrameRateOverride[] overrides) { 915 if (overrides.equals(mFrameRateOverrides)) { 916 return false; 917 } 918 919 mFrameRateOverrides = overrides; 920 return true; 921 } 922 requestColorModeLocked(int colorMode)923 public void requestColorModeLocked(int colorMode) { 924 if (mActiveColorMode == colorMode) { 925 return; 926 } 927 if (!mSupportedColorModes.contains(colorMode)) { 928 Slog.w(TAG, "Unable to find color mode " + colorMode 929 + ", ignoring request."); 930 return; 931 } 932 933 mActiveColorMode = colorMode; 934 getHandler().sendMessage(PooledLambda.obtainMessage( 935 LocalDisplayDevice::requestColorModeAsync, this, 936 getDisplayTokenLocked(), colorMode)); 937 } 938 requestColorModeAsync(IBinder displayToken, int colorMode)939 private void requestColorModeAsync(IBinder displayToken, int colorMode) { 940 // Do not lock when calling this SurfaceControl method because it is a sync operation 941 // that may block for a while when setting display power mode. 942 mSurfaceControlProxy.setActiveColorMode(displayToken, colorMode); 943 synchronized (getSyncRoot()) { 944 updateDeviceInfoLocked(); 945 } 946 } 947 948 @Override setAutoLowLatencyModeLocked(boolean on)949 public void setAutoLowLatencyModeLocked(boolean on) { 950 if (mAllmRequested == on) { 951 return; 952 } 953 954 mAllmRequested = on; 955 956 if (!mAllmSupported) { 957 Slog.d(TAG, "Unable to set ALLM because the connected display " 958 + "does not support ALLM."); 959 return; 960 } 961 962 mSurfaceControlProxy.setAutoLowLatencyMode(getDisplayTokenLocked(), on); 963 } 964 965 @Override setGameContentTypeLocked(boolean on)966 public void setGameContentTypeLocked(boolean on) { 967 if (mGameContentTypeRequested == on) { 968 return; 969 } 970 971 mGameContentTypeRequested = on; 972 973 if (!mGameContentTypeSupported) { 974 Slog.d(TAG, "Unable to set game content type because the connected " 975 + "display does not support game content type."); 976 return; 977 } 978 979 mSurfaceControlProxy.setGameContentType(getDisplayTokenLocked(), on); 980 } 981 982 @Override dumpLocked(PrintWriter pw)983 public void dumpLocked(PrintWriter pw) { 984 super.dumpLocked(pw); 985 pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId); 986 pw.println("mDisplayModeSpecs={" + mDisplayModeSpecs + "}"); 987 pw.println("mDisplayModeSpecsInvalid=" + mDisplayModeSpecsInvalid); 988 pw.println("mActiveModeId=" + mActiveModeId); 989 pw.println("mActiveColorMode=" + mActiveColorMode); 990 pw.println("mDefaultModeId=" + mDefaultModeId); 991 pw.println("mState=" + Display.stateToString(mState)); 992 pw.println("mBrightnessState=" + mBrightnessState); 993 pw.println("mBacklightAdapter=" + mBacklightAdapter); 994 pw.println("mAllmSupported=" + mAllmSupported); 995 pw.println("mAllmRequested=" + mAllmRequested); 996 pw.println("mGameContentTypeSupported=" + mGameContentTypeSupported); 997 pw.println("mGameContentTypeRequested=" + mGameContentTypeRequested); 998 pw.println("mStaticDisplayInfo=" + mStaticDisplayInfo); 999 pw.println("mSfDisplayModes="); 1000 for (int i = 0; i < mSfDisplayModes.length; i++) { 1001 pw.println(" " + mSfDisplayModes[i]); 1002 } 1003 pw.println("mActiveSfDisplayMode=" + mActiveSfDisplayMode); 1004 pw.println("mSupportedModes="); 1005 for (int i = 0; i < mSupportedModes.size(); i++) { 1006 pw.println(" " + mSupportedModes.valueAt(i)); 1007 } 1008 pw.println("mSupportedColorModes=" + mSupportedColorModes.toString()); 1009 pw.println("mDisplayDeviceConfig=" + mDisplayDeviceConfig); 1010 } 1011 findDisplayModeIdLocked(int modeId, int modeGroup)1012 private int findDisplayModeIdLocked(int modeId, int modeGroup) { 1013 int matchingModeId = SurfaceControl.DisplayMode.INVALID_DISPLAY_MODE_ID; 1014 DisplayModeRecord record = mSupportedModes.get(modeId); 1015 if (record != null) { 1016 for (SurfaceControl.DisplayMode mode : mSfDisplayModes) { 1017 if (record.hasMatchingMode(mode)) { 1018 if (matchingModeId 1019 == SurfaceControl.DisplayMode.INVALID_DISPLAY_MODE_ID) { 1020 matchingModeId = mode.id; 1021 } 1022 1023 // Prefer to return a mode that matches the modeGroup 1024 if (mode.group == modeGroup) { 1025 return mode.id; 1026 } 1027 } 1028 } 1029 } 1030 return matchingModeId; 1031 } 1032 findMatchingModeIdLocked(int sfModeId)1033 private int findMatchingModeIdLocked(int sfModeId) { 1034 SurfaceControl.DisplayMode mode = getModeById(mSfDisplayModes, sfModeId); 1035 if (mode == null) { 1036 Slog.e(TAG, "Invalid display mode ID " + sfModeId); 1037 return NO_DISPLAY_MODE_ID; 1038 } 1039 for (int i = 0; i < mSupportedModes.size(); i++) { 1040 DisplayModeRecord record = mSupportedModes.valueAt(i); 1041 if (record.hasMatchingMode(mode)) { 1042 return record.mMode.getModeId(); 1043 } 1044 } 1045 return NO_DISPLAY_MODE_ID; 1046 } 1047 updateDeviceInfoLocked()1048 private void updateDeviceInfoLocked() { 1049 mInfo = null; 1050 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 1051 } 1052 getDisplayModes(SparseArray<DisplayModeRecord> records)1053 private Display.Mode[] getDisplayModes(SparseArray<DisplayModeRecord> records) { 1054 final int size = records.size(); 1055 Display.Mode[] modes = new Display.Mode[size]; 1056 for (int i = 0; i < size; i++) { 1057 DisplayModeRecord record = records.valueAt(i); 1058 modes[i] = record.mMode; 1059 } 1060 return modes; 1061 } 1062 isDisplayPrivate(DisplayAddress.Physical physicalAddress)1063 private boolean isDisplayPrivate(DisplayAddress.Physical physicalAddress) { 1064 if (physicalAddress == null) { 1065 return false; 1066 } 1067 final Resources res = getOverlayContext().getResources(); 1068 int[] ports = res.getIntArray( 1069 com.android.internal.R.array.config_localPrivateDisplayPorts); 1070 if (ports != null) { 1071 int port = physicalAddress.getPort(); 1072 for (int p : ports) { 1073 if (p == port) { 1074 return true; 1075 } 1076 } 1077 } 1078 return false; 1079 } 1080 } 1081 1082 /** Supplies a context whose Resources apply runtime-overlays */ 1083 Context getOverlayContext() { 1084 return ActivityThread.currentActivityThread().getSystemUiContext(); 1085 } 1086 1087 /** 1088 * Keeps track of a display mode. 1089 */ 1090 private static final class DisplayModeRecord { 1091 public final Display.Mode mMode; 1092 1093 DisplayModeRecord(SurfaceControl.DisplayMode mode, 1094 float[] alternativeRefreshRates) { 1095 mMode = createMode(mode.width, mode.height, mode.refreshRate, 1096 alternativeRefreshRates); 1097 } 1098 1099 /** 1100 * Returns whether the mode generated by the given DisplayModes matches the mode 1101 * contained by the record modulo mode ID. 1102 * 1103 * Note that this doesn't necessarily mean that the DisplayModes are identical, just 1104 * that they generate identical modes. 1105 */ 1106 public boolean hasMatchingMode(SurfaceControl.DisplayMode mode) { 1107 return mMode.getPhysicalWidth() == mode.width 1108 && mMode.getPhysicalHeight() == mode.height 1109 && Float.floatToIntBits(mMode.getRefreshRate()) 1110 == Float.floatToIntBits(mode.refreshRate); 1111 } 1112 1113 public String toString() { 1114 return "DisplayModeRecord{mMode=" + mMode + "}"; 1115 } 1116 } 1117 1118 public static class Injector { 1119 private ProxyDisplayEventReceiver mReceiver; 1120 public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) { 1121 mReceiver = new ProxyDisplayEventReceiver(looper, listener); 1122 } 1123 public SurfaceControlProxy getSurfaceControlProxy() { 1124 return new SurfaceControlProxy(); 1125 } 1126 } 1127 1128 public interface DisplayEventListener { 1129 void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected); 1130 void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId); 1131 void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, 1132 DisplayEventReceiver.FrameRateOverride[] overrides); 1133 1134 } 1135 1136 public static final class ProxyDisplayEventReceiver extends DisplayEventReceiver { 1137 private final DisplayEventListener mListener; 1138 ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) { 1139 super(looper, VSYNC_SOURCE_APP, 1140 EVENT_REGISTRATION_MODE_CHANGED_FLAG 1141 | EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG); 1142 mListener = listener; 1143 } 1144 1145 @Override 1146 public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 1147 mListener.onHotplug(timestampNanos, physicalDisplayId, connected); 1148 } 1149 1150 @Override 1151 public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) { 1152 mListener.onModeChanged(timestampNanos, physicalDisplayId, modeId); 1153 } 1154 1155 @Override 1156 public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, 1157 DisplayEventReceiver.FrameRateOverride[] overrides) { 1158 mListener.onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides); 1159 } 1160 } 1161 1162 private final class LocalDisplayEventListener implements DisplayEventListener { 1163 @Override 1164 public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 1165 synchronized (getSyncRoot()) { 1166 if (connected) { 1167 tryConnectDisplayLocked(physicalDisplayId); 1168 } else { 1169 tryDisconnectDisplayLocked(physicalDisplayId); 1170 } 1171 } 1172 } 1173 1174 @Override 1175 public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) { 1176 if (DEBUG) { 1177 Slog.d(TAG, "onModeChanged(" 1178 + "timestampNanos=" + timestampNanos 1179 + ", physicalDisplayId=" + physicalDisplayId 1180 + ", modeId=" + modeId + ")"); 1181 } 1182 synchronized (getSyncRoot()) { 1183 LocalDisplayDevice device = mDevices.get(physicalDisplayId); 1184 if (device == null) { 1185 if (DEBUG) { 1186 Slog.d(TAG, "Received mode change for unhandled physical display: " 1187 + "physicalDisplayId=" + physicalDisplayId); 1188 } 1189 return; 1190 } 1191 device.onActiveDisplayModeChangedLocked(modeId); 1192 } 1193 } 1194 1195 @Override 1196 public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, 1197 DisplayEventReceiver.FrameRateOverride[] overrides) { 1198 if (DEBUG) { 1199 Slog.d(TAG, "onFrameRateOverrideChanged(timestampNanos=" + timestampNanos 1200 + ", physicalDisplayId=" + physicalDisplayId + " overrides=" 1201 + Arrays.toString(overrides) + ")"); 1202 } 1203 synchronized (getSyncRoot()) { 1204 LocalDisplayDevice device = mDevices.get(physicalDisplayId); 1205 if (device == null) { 1206 if (DEBUG) { 1207 Slog.d(TAG, "Received frame rate override event for unhandled physical" 1208 + " display: physicalDisplayId=" + physicalDisplayId); 1209 } 1210 return; 1211 } 1212 device.onFrameRateOverridesChanged(overrides); 1213 } 1214 } 1215 } 1216 1217 @VisibleForTesting 1218 static class SurfaceControlProxy { 1219 public SurfaceControl.DynamicDisplayInfo getDynamicDisplayInfo(IBinder token) { 1220 return SurfaceControl.getDynamicDisplayInfo(token); 1221 } 1222 1223 public long[] getPhysicalDisplayIds() { 1224 return SurfaceControl.getPhysicalDisplayIds(); 1225 } 1226 1227 public IBinder getPhysicalDisplayToken(long physicalDisplayId) { 1228 return SurfaceControl.getPhysicalDisplayToken(physicalDisplayId); 1229 } 1230 1231 public SurfaceControl.StaticDisplayInfo getStaticDisplayInfo(IBinder displayToken) { 1232 return SurfaceControl.getStaticDisplayInfo(displayToken); 1233 } 1234 1235 public SurfaceControl.DesiredDisplayModeSpecs getDesiredDisplayModeSpecs( 1236 IBinder displayToken) { 1237 return SurfaceControl.getDesiredDisplayModeSpecs(displayToken); 1238 } 1239 1240 public boolean setDesiredDisplayModeSpecs(IBinder token, 1241 SurfaceControl.DesiredDisplayModeSpecs specs) { 1242 return SurfaceControl.setDesiredDisplayModeSpecs(token, specs); 1243 } 1244 1245 public void setDisplayPowerMode(IBinder displayToken, int mode) { 1246 SurfaceControl.setDisplayPowerMode(displayToken, mode); 1247 } 1248 1249 public boolean setActiveColorMode(IBinder displayToken, int colorMode) { 1250 return SurfaceControl.setActiveColorMode(displayToken, colorMode); 1251 } 1252 1253 public void setAutoLowLatencyMode(IBinder displayToken, boolean on) { 1254 SurfaceControl.setAutoLowLatencyMode(displayToken, on); 1255 1256 } 1257 1258 public void setGameContentType(IBinder displayToken, boolean on) { 1259 SurfaceControl.setGameContentType(displayToken, on); 1260 } 1261 1262 public boolean getDisplayBrightnessSupport(IBinder displayToken) { 1263 return SurfaceControl.getDisplayBrightnessSupport(displayToken); 1264 } 1265 1266 public boolean setDisplayBrightness(IBinder displayToken, float brightness) { 1267 return SurfaceControl.setDisplayBrightness(displayToken, brightness); 1268 } 1269 1270 public boolean setDisplayBrightness(IBinder displayToken, float sdrBacklight, 1271 float sdrNits, float displayBacklight, float displayNits) { 1272 return SurfaceControl.setDisplayBrightness(displayToken, sdrBacklight, sdrNits, 1273 displayBacklight, displayNits); 1274 } 1275 1276 } 1277 1278 static class BacklightAdapter { 1279 private final IBinder mDisplayToken; 1280 private final LogicalLight mBacklight; 1281 private final boolean mUseSurfaceControlBrightness; 1282 private final SurfaceControlProxy mSurfaceControlProxy; 1283 1284 private boolean mForceSurfaceControl = false; 1285 1286 /** 1287 * @param displayToken Token for display associated with this backlight. 1288 * @param isDefaultDisplay {@code true} if it is the default display. 1289 */ 1290 BacklightAdapter(IBinder displayToken, boolean isDefaultDisplay, 1291 SurfaceControlProxy surfaceControlProxy) { 1292 mDisplayToken = displayToken; 1293 mSurfaceControlProxy = surfaceControlProxy; 1294 1295 mUseSurfaceControlBrightness = mSurfaceControlProxy 1296 .getDisplayBrightnessSupport(mDisplayToken); 1297 1298 if (!mUseSurfaceControlBrightness && isDefaultDisplay) { 1299 LightsManager lights = LocalServices.getService(LightsManager.class); 1300 mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT); 1301 } else { 1302 mBacklight = null; 1303 } 1304 } 1305 1306 // Set backlight within min and max backlight values 1307 void setBacklight(float sdrBacklight, float sdrNits, float backlight, float nits) { 1308 if (mUseSurfaceControlBrightness || mForceSurfaceControl) { 1309 if (BrightnessSynchronizer.floatEquals( 1310 sdrBacklight, PowerManager.BRIGHTNESS_INVALID_FLOAT)) { 1311 mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, backlight); 1312 } else { 1313 mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, sdrBacklight, sdrNits, 1314 backlight, nits); 1315 } 1316 } else if (mBacklight != null) { 1317 mBacklight.setBrightness(backlight); 1318 } 1319 } 1320 1321 void setVrMode(boolean isVrModeEnabled) { 1322 if (mBacklight != null) { 1323 mBacklight.setVrMode(isVrModeEnabled); 1324 } 1325 } 1326 1327 void setForceSurfaceControl(boolean forceSurfaceControl) { 1328 mForceSurfaceControl = forceSurfaceControl; 1329 } 1330 1331 @Override 1332 public String toString() { 1333 return "BacklightAdapter [useSurfaceControl=" + mUseSurfaceControlBrightness 1334 + " (force_anyway? " + mForceSurfaceControl + ")" 1335 + ", backlight=" + mBacklight + "]"; 1336 } 1337 } 1338 } 1339