diff options
author | P.Y. Laligand <pylaligand@google.com> | 2015-05-12 17:39:55 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-05-12 17:39:57 +0000 |
commit | e6c47686f62643d3399218eef4728c22358cbcfb (patch) | |
tree | 7fc2b26868c6a5767d3c87e1a8e3f1cc2f309e22 | |
parent | 4b403557bca7b622c187c3b06814e2118ec7d985 (diff) | |
parent | b3b9eb3cfc5b3b3609a5d01258315798b38a5cf9 (diff) | |
download | frameworks_base-e6c47686f62643d3399218eef4728c22358cbcfb.zip frameworks_base-e6c47686f62643d3399218eef4728c22358cbcfb.tar.gz frameworks_base-e6c47686f62643d3399218eef4728c22358cbcfb.tar.bz2 |
Merge "DO NOT MERGE - Display mode switches." into mnc-dev
20 files changed, 658 insertions, 239 deletions
@@ -519,10 +519,11 @@ aidl_files := \ frameworks/base/core/java/android/net/Uri.aidl \ frameworks/base/core/java/android/net/NetworkRequest.aidl \ frameworks/base/core/java/android/net/LinkAddress.aidl \ - frameworks/base/core/java/android/view/Surface.aidl \ - frameworks/base/core/java/android/view/WindowContentFrameStats.aidl \ + frameworks/base/core/java/android/view/Display.aidl \ frameworks/base/core/java/android/view/InputDevice.aidl \ frameworks/base/core/java/android/view/InputEvent.aidl \ + frameworks/base/core/java/android/view/Surface.aidl \ + frameworks/base/core/java/android/view/WindowContentFrameStats.aidl \ frameworks/base/core/java/android/view/inputmethod/InputMethodSubtype.aidl \ frameworks/base/core/java/android/view/inputmethod/CursorAnchorInfo.aidl \ frameworks/base/core/java/android/view/inputmethod/CompletionInfo.aidl \ diff --git a/api/current.txt b/api/current.txt index 45e3c8a..46f38ca 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34549,6 +34549,7 @@ package android.view { method public int getFlags(); method public deprecated int getHeight(); method public void getMetrics(android.util.DisplayMetrics); + method public android.view.Display.Mode getMode(); method public java.lang.String getName(); method public deprecated int getOrientation(); method public deprecated int getPixelFormat(); @@ -34560,7 +34561,8 @@ package android.view { method public int getRotation(); method public void getSize(android.graphics.Point); method public int getState(); - method public float[] getSupportedRefreshRates(); + method public android.view.Display.Mode[] getSupportedModes(); + method public deprecated float[] getSupportedRefreshRates(); method public deprecated int getWidth(); method public boolean isValid(); field public static final int DEFAULT_DISPLAY = 0; // 0x0 @@ -34575,6 +34577,16 @@ package android.view { field public static final int STATE_UNKNOWN = 0; // 0x0 } + public static final class Display.Mode implements android.os.Parcelable { + method public int describeContents(); + method public int getModeId(); + method public int getPhysicalHeight(); + method public int getPhysicalWidth(); + method public float getRefreshRate(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.view.Display.Mode> CREATOR; + } + public class DragEvent implements android.os.Parcelable { method public int describeContents(); method public int getAction(); @@ -37365,7 +37377,8 @@ package android.view { field public float horizontalWeight; field public deprecated int memoryType; field public java.lang.String packageName; - field public float preferredRefreshRate; + field public int preferredDisplayModeId; + field public deprecated float preferredRefreshRate; field public int rotationAnimation; field public float screenBrightness; field public int screenOrientation; diff --git a/api/system-current.txt b/api/system-current.txt index 32eaeed..b2a6f65 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -36771,6 +36771,7 @@ package android.view { method public int getFlags(); method public deprecated int getHeight(); method public void getMetrics(android.util.DisplayMetrics); + method public android.view.Display.Mode getMode(); method public java.lang.String getName(); method public deprecated int getOrientation(); method public deprecated int getPixelFormat(); @@ -36782,7 +36783,8 @@ package android.view { method public int getRotation(); method public void getSize(android.graphics.Point); method public int getState(); - method public float[] getSupportedRefreshRates(); + method public android.view.Display.Mode[] getSupportedModes(); + method public deprecated float[] getSupportedRefreshRates(); method public deprecated int getWidth(); method public boolean isValid(); field public static final int DEFAULT_DISPLAY = 0; // 0x0 @@ -36797,6 +36799,16 @@ package android.view { field public static final int STATE_UNKNOWN = 0; // 0x0 } + public static final class Display.Mode implements android.os.Parcelable { + method public int describeContents(); + method public int getModeId(); + method public int getPhysicalHeight(); + method public int getPhysicalWidth(); + method public float getRefreshRate(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.view.Display.Mode> CREATOR; + } + public class DragEvent implements android.os.Parcelable { method public int describeContents(); method public int getAction(); @@ -39590,7 +39602,8 @@ package android.view { field public float horizontalWeight; field public deprecated int memoryType; field public java.lang.String packageName; - field public float preferredRefreshRate; + field public int preferredDisplayModeId; + field public deprecated float preferredRefreshRate; field public int rotationAnimation; field public float screenBrightness; field public int screenOrientation; diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index 02793f1..aa697ea 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -125,11 +125,13 @@ public abstract class DisplayManagerInternal { * mirroring. * @param requestedRefreshRate The preferred refresh rate for the top-most visible window that * has a preference. + * @param requestedModeId The preferred mode id for the top-most visible window that has a + * preference. * @param inTraversal True if called from WindowManagerService during a window traversal * prior to call to performTraversalInTransactionFromWindowManager. */ public abstract void setDisplayProperties(int displayId, boolean hasContent, - float requestedRefreshRate, boolean inTraversal); + float requestedRefreshRate, int requestedModeId, boolean inTraversal); /** * Applies an offset to the contents of a display, for example to avoid burn-in. diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 79a8489..d2b6533 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -209,7 +209,7 @@ public final class Choreographer { private static float getRefreshRate() { DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo( Display.DEFAULT_DISPLAY); - return di.refreshRate; + return di.getMode().getRefreshRate(); } /** diff --git a/core/java/android/view/Display.aidl b/core/java/android/view/Display.aidl new file mode 100644 index 0000000..42bba44 --- /dev/null +++ b/core/java/android/view/Display.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +parcelable Display.Mode; diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 71e2251..d4b971a 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -21,6 +21,8 @@ import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; +import android.os.Parcel; +import android.os.Parcelable; import android.os.Process; import android.os.SystemClock; import android.util.DisplayMetrics; @@ -619,18 +621,44 @@ public final class Display { public float getRefreshRate() { synchronized (this) { updateDisplayInfoLocked(); - return mDisplayInfo.refreshRate; + return mDisplayInfo.getMode().getRefreshRate(); } } /** * Get the supported refresh rates of this display in frames per second. + * <p> + * This method only returns refresh rates for the display's default modes. For more options, use + * {@link #getSupportedModes()}. + * + * @deprecated use {@link #getSupportedModes()} instead */ + @Deprecated public float[] getSupportedRefreshRates() { synchronized (this) { updateDisplayInfoLocked(); - final float[] refreshRates = mDisplayInfo.supportedRefreshRates; - return Arrays.copyOf(refreshRates, refreshRates.length); + return mDisplayInfo.getDefaultRefreshRates(); + } + } + + /** + * Returns the active mode of the display. + */ + public Mode getMode() { + synchronized (this) { + updateDisplayInfoLocked(); + return mDisplayInfo.getMode(); + } + } + + /** + * Gets the supported modes of this display. + */ + public Mode[] getSupportedModes() { + synchronized (this) { + updateDisplayInfoLocked(); + final Display.Mode[] modes = mDisplayInfo.supportedModes; + return Arrays.copyOf(modes, modes.length); } } @@ -862,4 +890,152 @@ public final class Display { public static boolean isSuspendedState(int state) { return state == STATE_OFF || state == STATE_DOZE_SUSPEND; } + + /** + * A mode supported by a given display. + * + * @see Display#getSupportedModes() + */ + public static final class Mode implements Parcelable { + /** + * @hide + */ + public static final Mode[] EMPTY_ARRAY = new Mode[0]; + + private final int mModeId; + private final int mWidth; + private final int mHeight; + private final float mRefreshRate; + + /** + * @hide + */ + public Mode(int modeId, int width, int height, float refreshRate) { + mModeId = modeId; + mWidth = width; + mHeight = height; + mRefreshRate = refreshRate; + } + + /** + * Returns this mode's id. + */ + public int getModeId() { + return mModeId; + } + + /** + * Returns the physical width of the display in pixels when configured in this mode's + * resolution. + * <p> + * Note that due to application UI scaling, the number of pixels made available to + * applications when the mode is active (as reported by {@link Display#getWidth()} may + * differ from the mode's actual resolution (as reported by this function). + * <p> + * For example, applications running on a 4K display may have their UI laid out and rendered + * in 1080p and then scaled up. Applications can take advantage of the extra resolution by + * rendering content through a {@link android.view.SurfaceView} using full size buffers. + */ + public int getPhysicalWidth() { + return mWidth; + } + + /** + * Returns the physical height of the display in pixels when configured in this mode's + * resolution. + * <p> + * Note that due to application UI scaling, the number of pixels made available to + * applications when the mode is active (as reported by {@link Display#getHeight()} may + * differ from the mode's actual resolution (as reported by this function). + * <p> + * For example, applications running on a 4K display may have their UI laid out and rendered + * in 1080p and then scaled up. Applications can take advantage of the extra resolution by + * rendering content through a {@link android.view.SurfaceView} using full size buffers. + */ + public int getPhysicalHeight() { + return mHeight; + } + + /** + * Returns the refresh rate in frames per second. + */ + public float getRefreshRate() { + return mRefreshRate; + } + + /** + * Returns {@code true} if this mode matches the given parameters. + * + * @hide + */ + public boolean matches(int width, int height, float refreshRate) { + return mWidth == width && + mHeight == height && + Float.floatToIntBits(mRefreshRate) == Float.floatToIntBits(refreshRate); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof Mode)) { + return false; + } + Mode that = (Mode) other; + return mModeId == that.mModeId && matches(that.mWidth, that.mHeight, that.mRefreshRate); + } + + @Override + public int hashCode() { + int hash = 1; + hash = hash * 17 + mModeId; + hash = hash * 17 + mWidth; + hash = hash * 17 + mHeight; + hash = hash * 17 + Float.floatToIntBits(mRefreshRate); + return hash; + } + + @Override + public String toString() { + return new StringBuilder("{") + .append("id=").append(mModeId) + .append(", width=").append(mWidth) + .append(", height=").append(mHeight) + .append(", fps=").append(mRefreshRate) + .append("}") + .toString(); + } + + @Override + public int describeContents() { + return 0; + } + + private Mode(Parcel in) { + this(in.readInt(), in.readInt(), in.readInt(), in.readFloat()); + } + + @Override + public void writeToParcel(Parcel out, int parcelableFlags) { + out.writeInt(mModeId); + out.writeInt(mWidth); + out.writeInt(mHeight); + out.writeFloat(mRefreshRate); + } + + @SuppressWarnings("hiding") + public static final Parcelable.Creator<Mode> CREATOR + = new Parcelable.Creator<Mode>() { + @Override + public Mode createFromParcel(Parcel in) { + return new Mode(in); + } + + @Override + public Mode[] newArray(int size) { + return new Mode[size]; + } + }; + } } diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 243961c..b9fde8a 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -20,11 +20,11 @@ import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.os.Parcel; import android.os.Parcelable; +import android.util.ArraySet; import android.util.DisplayMetrics; import java.util.Arrays; -import libcore.util.EmptyArray; import libcore.util.Objects; /** @@ -155,18 +155,19 @@ public final class DisplayInfo implements Parcelable { public int rotation; /** - * The refresh rate of this display in frames per second. - * <p> - * The value of this field is indeterminate if the logical display is presented on - * more than one physical display. - * </p> + * The active display mode. + */ + public int modeId; + + /** + * The default display mode. */ - public float refreshRate; + public int defaultModeId; /** - * The supported refresh rates of this display at the current resolution in frames per second. + * The supported modes of this display. */ - public float[] supportedRefreshRates = EmptyArray.FLOAT; + public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY; /** * The logical display density which is the basis for density-independent @@ -276,7 +277,8 @@ public final class DisplayInfo implements Parcelable { && overscanRight == other.overscanRight && overscanBottom == other.overscanBottom && rotation == other.rotation - && refreshRate == other.refreshRate + && modeId == other.modeId + && defaultModeId == other.defaultModeId && logicalDensityDpi == other.logicalDensityDpi && physicalXDpi == other.physicalXDpi && physicalYDpi == other.physicalYDpi @@ -312,9 +314,9 @@ public final class DisplayInfo implements Parcelable { overscanRight = other.overscanRight; overscanBottom = other.overscanBottom; rotation = other.rotation; - refreshRate = other.refreshRate; - supportedRefreshRates = Arrays.copyOf( - other.supportedRefreshRates, other.supportedRefreshRates.length); + modeId = other.modeId; + defaultModeId = other.defaultModeId; + supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length); logicalDensityDpi = other.logicalDensityDpi; physicalXDpi = other.physicalXDpi; physicalYDpi = other.physicalYDpi; @@ -344,8 +346,13 @@ public final class DisplayInfo implements Parcelable { overscanRight = source.readInt(); overscanBottom = source.readInt(); rotation = source.readInt(); - refreshRate = source.readFloat(); - supportedRefreshRates = source.createFloatArray(); + modeId = source.readInt(); + defaultModeId = source.readInt(); + int nModes = source.readInt(); + supportedModes = new Display.Mode[nModes]; + for (int i = 0; i < nModes; i++) { + supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source); + } logicalDensityDpi = source.readInt(); physicalXDpi = source.readFloat(); physicalYDpi = source.readFloat(); @@ -377,8 +384,12 @@ public final class DisplayInfo implements Parcelable { dest.writeInt(overscanRight); dest.writeInt(overscanBottom); dest.writeInt(rotation); - dest.writeFloat(refreshRate); - dest.writeFloatArray(supportedRefreshRates); + dest.writeInt(modeId); + dest.writeInt(defaultModeId); + dest.writeInt(supportedModes.length); + for (int i = 0; i < supportedModes.length; i++) { + supportedModes[i].writeToParcel(dest, flags); + } dest.writeInt(logicalDensityDpi); dest.writeFloat(physicalXDpi); dest.writeFloat(physicalYDpi); @@ -395,6 +406,61 @@ public final class DisplayInfo implements Parcelable { return 0; } + public Display.Mode getMode() { + return findMode(modeId); + } + + public Display.Mode getDefaultMode() { + return findMode(defaultModeId); + } + + private Display.Mode findMode(int id) { + for (int i = 0; i < supportedModes.length; i++) { + if (supportedModes[i].getModeId() == id) { + return supportedModes[i]; + } + } + throw new IllegalStateException("Unable to locate mode " + id); + } + + /** + * Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable + * mode could be found. + */ + public int findDefaultModeByRefreshRate(float refreshRate) { + Display.Mode[] modes = supportedModes; + Display.Mode defaultMode = getDefaultMode(); + for (int i = 0; i < modes.length; i++) { + if (modes[i].matches( + defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) { + return modes[i].getModeId(); + } + } + return 0; + } + + /** + * Returns the list of supported refresh rates in the default mode. + */ + public float[] getDefaultRefreshRates() { + Display.Mode[] modes = supportedModes; + ArraySet<Float> rates = new ArraySet<>(); + Display.Mode defaultMode = getDefaultMode(); + for (int i = 0; i < modes.length; i++) { + Display.Mode mode = modes[i]; + if (mode.getPhysicalWidth() == defaultMode.getPhysicalWidth() + && mode.getPhysicalHeight() == defaultMode.getPhysicalHeight()) { + rates.add(mode.getRefreshRate()); + } + } + float[] result = new float[rates.size()]; + int i = 0; + for (Float rate : rates) { + result[i++] = rate; + } + return result; + } + public void getAppMetrics(DisplayMetrics outMetrics) { getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); } @@ -490,10 +556,12 @@ public final class DisplayInfo implements Parcelable { sb.append(smallestNominalAppWidth); sb.append(" x "); sb.append(smallestNominalAppHeight); - sb.append(", "); - sb.append(refreshRate); - sb.append(" fps, supportedRefreshRates "); - sb.append(Arrays.toString(supportedRefreshRates)); + sb.append(", mode "); + sb.append(modeId); + sb.append(", defaultMode "); + sb.append(defaultModeId); + sb.append(", modes "); + sb.append(Arrays.toString(supportedModes)); sb.append(", rotation "); sb.append(rotation); sb.append(", density "); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 2797b6e..7976ca4 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -101,7 +101,7 @@ public interface WindowManager extends ViewManager { * the given view hierarchy's {@link View#onDetachedFromWindow() * View.onDetachedFromWindow()} methods before returning. This is not * for normal applications; using it correctly requires great care. - * + * * @param view The view to be removed. */ public void removeViewImmediate(View view); @@ -115,7 +115,7 @@ public interface WindowManager extends ViewManager { */ @ViewDebug.ExportedProperty public int x; - + /** * Y position for this window. With the default gravity it is ignored. * When using {@link Gravity#TOP} or {@link Gravity#BOTTOM} it provides @@ -228,12 +228,12 @@ public interface WindowManager extends ViewManager { @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"), }) public int type; - + /** * Start of window types that represent normal application windows. */ public static final int FIRST_APPLICATION_WINDOW = 1; - + /** * Window type: an application window that serves as the "base" window * of the overall application; all other application windows will @@ -241,14 +241,14 @@ public interface WindowManager extends ViewManager { * In multiuser systems shows only on the owning user's window. */ public static final int TYPE_BASE_APPLICATION = 1; - + /** * Window type: a normal application window. The {@link #token} must be * an Activity token identifying who the window belongs to. * In multiuser systems shows only on the owning user's window. */ public static final int TYPE_APPLICATION = 2; - + /** * Window type: special application window that is displayed while the * application is starting. Not for use by applications themselves; @@ -257,7 +257,7 @@ public interface WindowManager extends ViewManager { * In multiuser systems shows on all users' windows. */ public static final int TYPE_APPLICATION_STARTING = 3; - + /** * End of types of application windows. */ @@ -330,14 +330,14 @@ public interface WindowManager extends ViewManager { * In multiuser systems shows on all users' windows. */ public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW; - + /** * Window type: the search bar. There can be only one search bar * window; it is placed at the top of the screen. * In multiuser systems shows on all users' windows. */ public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1; - + /** * Window type: phone. These are non-application windows providing * user interaction with the phone (in particular incoming calls). @@ -346,7 +346,7 @@ public interface WindowManager extends ViewManager { * In multiuser systems shows on all users' windows. */ public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2; - + /** * Window type: system window, such as low power alert. These windows * are always on top of application windows. @@ -366,7 +366,7 @@ public interface WindowManager extends ViewManager { * In multiuser systems shows only on the owning user's window. */ public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5; - + /** * Window type: system overlay windows, which need to be displayed * on top of everything else. These windows must not take input @@ -374,7 +374,7 @@ public interface WindowManager extends ViewManager { * In multiuser systems shows only on the owning user's window. */ public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6; - + /** * Window type: priority phone UI, which needs to be displayed even if * the keyguard is active. These windows must not take input @@ -382,26 +382,26 @@ public interface WindowManager extends ViewManager { * In multiuser systems shows on all users' windows. */ public static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7; - + /** * Window type: panel that slides out from the status bar * In multiuser systems shows on all users' windows. */ public static final int TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8; - + /** * Window type: dialogs that the keyguard shows * In multiuser systems shows on all users' windows. */ public static final int TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9; - + /** * Window type: internal system error windows, appear on top of * everything they can. * In multiuser systems shows only on the owning user's window. */ public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10; - + /** * Window type: internal input methods windows, which appear above * the normal UI. Application windows may be resized or panned to keep @@ -581,16 +581,16 @@ public interface WindowManager extends ViewManager { /** @deprecated this is ignored, this value is set automatically when needed. */ @Deprecated public static final int MEMORY_TYPE_PUSH_BUFFERS = 3; - + /** * @deprecated this is ignored */ @Deprecated public int memoryType; - + /** Window flag: as long as this window is visible to the user, allow - * the lock screen to activate while the screen is on. - * This can be used independently, or in combination with + * the lock screen to activate while the screen is on. + * This can be used independently, or in combination with * {@link #FLAG_KEEP_SCREEN_ON} and/or {@link #FLAG_SHOW_WHEN_LOCKED} */ public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001; @@ -608,26 +608,26 @@ public interface WindowManager extends ViewManager { * instead go to whatever focusable window is behind it. This flag * will also enable {@link #FLAG_NOT_TOUCH_MODAL} whether or not that * is explicitly set. - * + * * <p>Setting this flag also implies that the window will not need to * interact with - * a soft input method, so it will be Z-ordered and positioned + * a soft input method, so it will be Z-ordered and positioned * independently of any active input method (typically this means it * gets Z-ordered on top of the input method, so it can use the full * screen for its content and cover the input method if needed. You * can use {@link #FLAG_ALT_FOCUSABLE_IM} to modify this behavior. */ public static final int FLAG_NOT_FOCUSABLE = 0x00000008; - + /** Window flag: this window can never receive touch events. */ public static final int FLAG_NOT_TOUCHABLE = 0x00000010; - + /** Window flag: even when this window is focusable (its * {@link #FLAG_NOT_FOCUSABLE} is not set), allow any pointer events * outside of the window to be sent to the windows behind it. Otherwise * it will consume all pointer events itself, regardless of whether they * are inside of the window. */ public static final int FLAG_NOT_TOUCH_MODAL = 0x00000020; - + /** Window flag: when set, if the device is asleep when the touch * screen is pressed, you will receive this first touch event. Usually * the first touch event is consumed by the system since the user can @@ -637,21 +637,21 @@ public interface WindowManager extends ViewManager { */ @Deprecated public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040; - + /** Window flag: as long as this window is visible to the user, keep * the device's screen turned on and bright. */ public static final int FLAG_KEEP_SCREEN_ON = 0x00000080; - + /** Window flag: place the window within the entire screen, ignoring * decorations around the border (such as the status bar). The * window must correctly position its contents to take the screen * decoration into account. This flag is normally set for you * by Window as described in {@link Window#setFlags}. */ public static final int FLAG_LAYOUT_IN_SCREEN = 0x00000100; - + /** Window flag: allow window to extend outside of the screen. */ public static final int FLAG_LAYOUT_NO_LIMITS = 0x00000200; - + /** * Window flag: hide all screen decorations (such as the status bar) while * this window is displayed. This allows the window to use the entire @@ -673,17 +673,17 @@ public interface WindowManager extends ViewManager { * {@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_Fullscreen}.</p> */ public static final int FLAG_FULLSCREEN = 0x00000400; - + /** Window flag: override {@link #FLAG_FULLSCREEN} and force the * screen decorations (such as the status bar) to be shown. */ public static final int FLAG_FORCE_NOT_FULLSCREEN = 0x00000800; - + /** Window flag: turn on dithering when compositing this window to * the screen. * @deprecated This flag is no longer used. */ @Deprecated public static final int FLAG_DITHER = 0x00001000; - + /** Window flag: treat the content of the window as secure, preventing * it from appearing in screenshots or from being viewed on non-secure * displays. @@ -692,21 +692,21 @@ public interface WindowManager extends ViewManager { * secure surfaces and secure displays. */ public static final int FLAG_SECURE = 0x00002000; - + /** Window flag: a special mode where the layout parameters are used * to perform scaling of the surface when it is composited to the * screen. */ public static final int FLAG_SCALED = 0x00004000; - + /** Window flag: intended for windows that will often be used when the user is * holding the screen against their face, it will aggressively filter the event * stream to prevent unintended presses in this situation that may not be - * desired for a particular window, when such an event stream is detected, the + * desired for a particular window, when such an event stream is detected, the * application will receive a CANCEL motion event to indicate this so applications - * can handle this accordingly by taking no action on the event + * can handle this accordingly by taking no action on the event * until the finger is released. */ public static final int FLAG_IGNORE_CHEEK_PRESSES = 0x00008000; - + /** Window flag: a special option only for use in combination with * {@link #FLAG_LAYOUT_IN_SCREEN}. When requesting layout in the * screen your window may appear on top of or behind screen decorations @@ -715,7 +715,7 @@ public interface WindowManager extends ViewManager { * content is not covered by screen decorations. This flag is normally * set for you by Window as described in {@link Window#setFlags}.*/ public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000; - + /** Window flag: invert the state of {@link #FLAG_NOT_FOCUSABLE} with * respect to how this window interacts with the current method. That * is, if FLAG_NOT_FOCUSABLE is set and this flag is set, then the @@ -726,7 +726,7 @@ public interface WindowManager extends ViewManager { * to use more space and cover the input method. */ public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000; - + /** Window flag: if you have set {@link #FLAG_NOT_TOUCH_MODAL}, you * can set this flag to receive a single special MotionEvent with * the action @@ -736,7 +736,7 @@ public interface WindowManager extends ViewManager { * first down as an ACTION_OUTSIDE. */ public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000; - + /** Window flag: special flag to let windows be shown when the screen * is locked. This will let application windows take precedence over * key guard or any other lock screens. Can be used with @@ -766,13 +766,13 @@ public interface WindowManager extends ViewManager { * {@link android.R.style#Theme_DeviceDefault_Wallpaper_NoTitleBar}.</p> */ public static final int FLAG_SHOW_WALLPAPER = 0x00100000; - + /** Window flag: when set as a window is being added or made * visible, once the window has been shown then the system will * poke the power manager's user activity (as if the user had woken * up the device) to turn the screen on. */ public static final int FLAG_TURN_SCREEN_ON = 0x00200000; - + /** Window flag: when set the window will cause the keyguard to * be dismissed, only if it is not a secure lock keyguard. Because such * a keyguard is not needed for security, it will never re-appear if @@ -786,7 +786,7 @@ public interface WindowManager extends ViewManager { * also been set. */ public static final int FLAG_DISMISS_KEYGUARD = 0x00400000; - + /** Window flag: when set the window will accept for touch events * outside of its bounds to be sent to other windows that also * support split touch. When this flag is not set, the first pointer @@ -798,7 +798,7 @@ public interface WindowManager extends ViewManager { * to be split across multiple windows. */ public static final int FLAG_SPLIT_TOUCH = 0x00800000; - + /** * <p>Indicates whether this window should be hardware accelerated. * Requesting hardware acceleration does not guarantee it will happen.</p> @@ -940,7 +940,7 @@ public interface WindowManager extends ViewManager { /** * Various behavioral options/flags. Default is none. - * + * * @see #FLAG_ALLOW_LOCK_WHILE_SCREEN_ON * @see #FLAG_DIM_BEHIND * @see #FLAG_NOT_FOCUSABLE @@ -1041,10 +1041,10 @@ public interface WindowManager extends ViewManager { * as if it was. * Like {@link #FLAG_HARDWARE_ACCELERATED} except for trusted system windows * that need hardware acceleration (e.g. LockScreen), where hardware acceleration - * is generally disabled. This flag must be specified in addition to + * is generally disabled. This flag must be specified in addition to * {@link #FLAG_HARDWARE_ACCELERATED} to enable hardware acceleration for system * windows. - * + * * @hide */ public static final int PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED = 0x00000001; @@ -1055,7 +1055,7 @@ public interface WindowManager extends ViewManager { * If certain parts of the UI that really do want to use hardware * acceleration, this flag can be set to force it. This is basically * for the lock screen. Anyone else using it, you are probably wrong. - * + * * @hide */ public static final int PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED = 0x00000002; @@ -1194,63 +1194,63 @@ public interface WindowManager extends ViewManager { } return false; } - + /** * Mask for {@link #softInputMode} of the bits that determine the * desired visibility state of the soft input area for this window. */ public static final int SOFT_INPUT_MASK_STATE = 0x0f; - + /** * Visibility state for {@link #softInputMode}: no state has been specified. */ public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0; - + /** * Visibility state for {@link #softInputMode}: please don't change the state of * the soft input area. */ public static final int SOFT_INPUT_STATE_UNCHANGED = 1; - + /** * Visibility state for {@link #softInputMode}: please hide any soft input * area when normally appropriate (when the user is navigating * forward to your window). */ public static final int SOFT_INPUT_STATE_HIDDEN = 2; - + /** * Visibility state for {@link #softInputMode}: please always hide any * soft input area when this window receives focus. */ public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3; - + /** * Visibility state for {@link #softInputMode}: please show the soft * input area when normally appropriate (when the user is navigating * forward to your window). */ public static final int SOFT_INPUT_STATE_VISIBLE = 4; - + /** * Visibility state for {@link #softInputMode}: please always make the * soft input area visible when this window receives input focus. */ public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5; - + /** * Mask for {@link #softInputMode} of the bits that determine the * way that the window should be adjusted to accommodate the soft * input window. */ public static final int SOFT_INPUT_MASK_ADJUST = 0xf0; - + /** Adjustment option for {@link #softInputMode}: nothing specified. * The system will try to pick one or * the other depending on the contents of the window. */ public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00; - + /** Adjustment option for {@link #softInputMode}: set to allow the * window to be resized when an input * method is shown, so that its contents are not covered by the input @@ -1263,7 +1263,7 @@ public interface WindowManager extends ViewManager { * not resize, but will stay fullscreen. */ public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10; - + /** Adjustment option for {@link #softInputMode}: set to have a window * pan when an input method is * shown, so it doesn't need to deal with resizing but just panned @@ -1273,7 +1273,7 @@ public interface WindowManager extends ViewManager { * the other depending on the contents of the window. */ public static final int SOFT_INPUT_ADJUST_PAN = 0x20; - + /** Adjustment option for {@link #softInputMode}: set to have a window * not adjust for a shown input method. The window will not be resized, * and it will not be panned to make its focus visible. @@ -1292,7 +1292,7 @@ public interface WindowManager extends ViewManager { /** * Desired operating mode for any soft input area. May be any combination * of: - * + * * <ul> * <li> One of the visibility states * {@link #SOFT_INPUT_STATE_UNSPECIFIED}, {@link #SOFT_INPUT_STATE_UNCHANGED}, @@ -1309,7 +1309,7 @@ public interface WindowManager extends ViewManager { * {@link android.R.attr#windowSoftInputMode} attribute.</p> */ public int softInputMode; - + /** * Placement of window within the screen as per {@link Gravity}. Both * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int, @@ -1326,7 +1326,7 @@ public interface WindowManager extends ViewManager { * @see Gravity */ public int gravity; - + /** * The horizontal margin, as a percentage of the container's width, * between the container and the widget. See @@ -1335,7 +1335,7 @@ public interface WindowManager extends ViewManager { * field is added with {@link #x} to supply the <var>xAdj</var> parameter. */ public float horizontalMargin; - + /** * The vertical margin, as a percentage of the container's height, * between the container and the widget. See @@ -1361,26 +1361,26 @@ public interface WindowManager extends ViewManager { * @hide */ public boolean hasManualSurfaceInsets; - + /** * The desired bitmap format. May be one of the constants in * {@link android.graphics.PixelFormat}. Default is OPAQUE. */ public int format; - + /** * A style resource defining the animations to use for this window. * This must be a system resource; it can not be an application resource * because the window manager does not have access to applications. */ public int windowAnimations; - + /** * An alpha value to apply to this entire window. * An alpha of 1.0 means fully opaque and 0.0 means fully transparent */ public float alpha = 1.0f; - + /** * When {@link #FLAG_DIM_BEHIND} is set, this is the amount of dimming * to apply. Range is from 1.0 for completely opaque to 0.0 for no @@ -1408,7 +1408,7 @@ public interface WindowManager extends ViewManager { * to the hightest value when this window is in front. */ public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f; - + /** * This can be used to override the user's preferred brightness of * the screen. A value of less than 0, the default, means to use the @@ -1416,7 +1416,7 @@ public interface WindowManager extends ViewManager { * dark to full bright. */ public float screenBrightness = BRIGHTNESS_OVERRIDE_NONE; - + /** * This can be used to override the standard behavior of the button and * keyboard backlights. A value of less than 0, the default, means to @@ -1450,7 +1450,7 @@ public interface WindowManager extends ViewManager { * opaque windows have the #FLAG_FULLSCREEN bit set and are not covered * by other windows. All other situations default to the * {@link #ROTATION_ANIMATION_ROTATE} behavior. - * + * * @see #ROTATION_ANIMATION_ROTATE * @see #ROTATION_ANIMATION_CROSSFADE * @see #ROTATION_ANIMATION_JUMPCUT @@ -1462,18 +1462,18 @@ public interface WindowManager extends ViewManager { * you. */ public IBinder token = null; - + /** * Name of the package owning this window. */ public String packageName = null; - + /** * Specific orientation value for a window. * May be any of the same values allowed - * for {@link android.content.pm.ActivityInfo#screenOrientation}. - * If not set, a default value of - * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} + * for {@link android.content.pm.ActivityInfo#screenOrientation}. + * If not set, a default value of + * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} * will be used. */ public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -1482,13 +1482,28 @@ public interface WindowManager extends ViewManager { * The preferred refresh rate for the window. * * This must be one of the supported refresh rates obtained for the display(s) the window - * is on. + * is on. The selected refresh rate will be applied to the display's default mode. + * + * This value is ignored if {@link #preferredDisplayModeId} is set. * * @see Display#getSupportedRefreshRates() + * @deprecated use {@link #preferredDisplayModeId} instead */ + @Deprecated public float preferredRefreshRate; /** + * Id of the preferred display mode for the window. + * <p> + * This must be one of the supported modes obtained for the display(s) the window is on. + * A value of {@code 0} means no preference. + * + * @see Display#getSupportedModes() + * @see Display.Mode#getModeId() + */ + public int preferredDisplayModeId; + + /** * Control the visibility of the status bar. * * @see View#STATUS_BAR_VISIBLE @@ -1505,7 +1520,7 @@ public interface WindowManager extends ViewManager { /** * Get callbacks about the system ui visibility changing. - * + * * TODO: Maybe there should be a bitfield of optional callbacks that we need. * * @hide @@ -1571,34 +1586,34 @@ public interface WindowManager extends ViewManager { type = TYPE_APPLICATION; format = PixelFormat.OPAQUE; } - + public LayoutParams(int _type) { super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); type = _type; format = PixelFormat.OPAQUE; } - + public LayoutParams(int _type, int _flags) { super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); type = _type; flags = _flags; format = PixelFormat.OPAQUE; } - + public LayoutParams(int _type, int _flags, int _format) { super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); type = _type; flags = _flags; format = _format; } - + public LayoutParams(int w, int h, int _type, int _flags, int _format) { super(w, h); type = _type; flags = _flags; format = _format; } - + public LayoutParams(int w, int h, int xpos, int ypos, int _type, int _flags, int _format) { super(w, h); @@ -1608,14 +1623,14 @@ public interface WindowManager extends ViewManager { flags = _flags; format = _format; } - + public final void setTitle(CharSequence title) { if (null == title) title = ""; - + mTitle = TextUtils.stringOrSpannedString(title); } - + public final CharSequence getTitle() { return mTitle; } @@ -1660,6 +1675,7 @@ public interface WindowManager extends ViewManager { TextUtils.writeToParcel(mTitle, out, parcelableFlags); out.writeInt(screenOrientation); out.writeFloat(preferredRefreshRate); + out.writeInt(preferredDisplayModeId); out.writeInt(systemUiVisibility); out.writeInt(subtreeSystemUiVisibility); out.writeInt(hasSystemUiListeners ? 1 : 0); @@ -1683,8 +1699,8 @@ public interface WindowManager extends ViewManager { return new LayoutParams[size]; } }; - - + + public LayoutParams(Parcel in) { width = in.readInt(); height = in.readInt(); @@ -1709,6 +1725,7 @@ public interface WindowManager extends ViewManager { mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); screenOrientation = in.readInt(); preferredRefreshRate = in.readFloat(); + preferredDisplayModeId = in.readInt(); systemUiVisibility = in.readInt(); subtreeSystemUiVisibility = in.readInt(); hasSystemUiListeners = in.readInt() != 0; @@ -1757,6 +1774,8 @@ public interface WindowManager extends ViewManager { /** {@hide} */ public static final int NEEDS_MENU_KEY_CHANGED = 1 << 22; /** {@hide} */ + public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23; + /** {@hide} */ public static final int EVERYTHING_CHANGED = 0xffffffff; // internal buffer to backup/restore parameters under compatibility mode. @@ -1863,7 +1882,7 @@ public interface WindowManager extends ViewManager { rotationAnimation = o.rotationAnimation; changes |= ROTATION_ANIMATION_CHANGED; } - + if (screenOrientation != o.screenOrientation) { screenOrientation = o.screenOrientation; changes |= SCREEN_ORIENTATION_CHANGED; @@ -1874,6 +1893,11 @@ public interface WindowManager extends ViewManager { changes |= PREFERRED_REFRESH_RATE_CHANGED; } + if (preferredDisplayModeId != o.preferredDisplayModeId) { + preferredDisplayModeId = o.preferredDisplayModeId; + changes |= PREFERRED_DISPLAY_MODE_ID; + } + if (systemUiVisibility != o.systemUiVisibility || subtreeSystemUiVisibility != o.subtreeSystemUiVisibility) { systemUiVisibility = o.systemUiVisibility; @@ -1924,7 +1948,7 @@ public interface WindowManager extends ViewManager { Log.d("Debug", "WindowManager.LayoutParams={title=" + mTitle + "}"); return ""; } - + @Override public String toString() { StringBuilder sb = new StringBuilder(256); @@ -1996,6 +2020,10 @@ public interface WindowManager extends ViewManager { sb.append(" preferredRefreshRate="); sb.append(preferredRefreshRate); } + if (preferredDisplayModeId != 0) { + sb.append(" preferredDisplayMode="); + sb.append(preferredDisplayModeId); + } if (systemUiVisibility != 0) { sb.append(" sysui=0x"); sb.append(Integer.toHexString(systemUiVisibility)); diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java index b411a0d..6ba25a5 100644 --- a/services/core/java/com/android/server/display/DisplayAdapter.java +++ b/services/core/java/com/android/server/display/DisplayAdapter.java @@ -18,8 +18,10 @@ package com.android.server.display; import android.content.Context; import android.os.Handler; +import android.view.Display; import java.io.PrintWriter; +import java.util.concurrent.atomic.AtomicInteger; /** * A display adapter makes zero or more display devices available to the system @@ -42,6 +44,11 @@ abstract class DisplayAdapter { public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2; public static final int DISPLAY_DEVICE_EVENT_REMOVED = 3; + /** + * Used to generate globally unique display mode ids. + */ + private static final AtomicInteger NEXT_DISPLAY_MODE_ID = new AtomicInteger(1); // 0 = no mode. + // Called with SyncRoot lock held. public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, String name) { @@ -122,6 +129,11 @@ abstract class DisplayAdapter { }); } + public static Display.Mode createMode(int width, int height, float refreshRate) { + return new Display.Mode( + NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate); + } + public interface Listener { public void onDisplayDeviceEvent(DisplayDevice device, int event); public void onTraversalRequested(); diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index ee36972..93bda46 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -19,6 +19,7 @@ package com.android.server.display; import android.graphics.Rect; import android.hardware.display.DisplayViewport; import android.os.IBinder; +import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; @@ -132,9 +133,9 @@ abstract class DisplayDevice { } /** - * Sets the refresh rate, if supported. + * Sets the mode, if supported. */ - public void requestRefreshRateLocked(float refreshRate) { + public void requestModeInTransactionLocked(int id) { } /** diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index ebf6e4e..0db3e3f 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -23,7 +23,6 @@ import android.view.Surface; import java.util.Arrays; -import libcore.util.EmptyArray; import libcore.util.Objects; /** @@ -137,14 +136,19 @@ final class DisplayDeviceInfo { public int height; /** - * The refresh rate of the display, in frames per second. + * The active mode of the display. */ - public float refreshRate; + public int modeId; /** - * The supported refresh rates of the display at the current resolution in frames per second. + * The default mode of the display. */ - public float[] supportedRefreshRates = EmptyArray.FLOAT; + public int defaultModeId; + + /** + * The supported modes of the display. + */ + public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY; /** * The nominal apparent density of the display in DPI used for layout calculations. @@ -264,8 +268,9 @@ final class DisplayDeviceInfo { || !Objects.equal(uniqueId, other.uniqueId) || width != other.width || height != other.height - || refreshRate != other.refreshRate - || !Arrays.equals(supportedRefreshRates, other.supportedRefreshRates) + || modeId != other.modeId + || defaultModeId != other.defaultModeId + || !Arrays.equals(supportedModes, other.supportedModes) || densityDpi != other.densityDpi || xDpi != other.xDpi || yDpi != other.yDpi @@ -293,8 +298,9 @@ final class DisplayDeviceInfo { uniqueId = other.uniqueId; width = other.width; height = other.height; - refreshRate = other.refreshRate; - supportedRefreshRates = other.supportedRefreshRates; + modeId = other.modeId; + defaultModeId = other.defaultModeId; + supportedModes = other.supportedModes; densityDpi = other.densityDpi; xDpi = other.xDpi; yDpi = other.yDpi; @@ -317,8 +323,9 @@ final class DisplayDeviceInfo { sb.append("DisplayDeviceInfo{\""); sb.append(name).append("\": uniqueId=\"").append(uniqueId).append("\", "); sb.append(width).append(" x ").append(height); - sb.append(", ").append(refreshRate).append(" fps"); - sb.append(", supportedRefreshRates ").append(Arrays.toString(supportedRefreshRates)); + sb.append(", modeId ").append(modeId); + sb.append(", defaultModeId ").append(defaultModeId); + sb.append(", supportedModes ").append(Arrays.toString(supportedModes)); sb.append(", density ").append(densityDpi); sb.append(", ").append(xDpi).append(" x ").append(yDpi).append(" dpi"); sb.append(", appVsyncOff ").append(appVsyncOffsetNanos); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 1e87433..7440b8c 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -842,7 +842,7 @@ public final class DisplayManagerService extends SystemService { } private void setDisplayPropertiesInternal(int displayId, boolean hasContent, - float requestedRefreshRate, boolean inTraversal) { + float requestedRefreshRate, int requestedModeId, boolean inTraversal) { synchronized (mSyncRoot) { LogicalDisplay display = mLogicalDisplays.get(displayId); if (display == null) { @@ -857,12 +857,17 @@ public final class DisplayManagerService extends SystemService { display.setHasContentLocked(hasContent); scheduleTraversalLocked(inTraversal); } - if (display.getRequestedRefreshRateLocked() != requestedRefreshRate) { + if (requestedModeId == 0 && requestedRefreshRate != 0) { + // Scan supported modes returned by display.getInfo() to find a mode with the same + // size as the default display mode but with the specified refresh rate instead. + requestedModeId = display.getDisplayInfoLocked().findDefaultModeByRefreshRate( + requestedRefreshRate); + } + if (display.getRequestedModeIdLocked() != requestedModeId) { if (DEBUG) { - Slog.d(TAG, "Display " + displayId + " has requested a new refresh rate: " - + requestedRefreshRate + "fps"); + Slog.d(TAG, "Display " + displayId + " switching to mode " + requestedModeId); } - display.setRequestedRefreshRateLocked(requestedRefreshRate); + display.setRequestedModeIdLocked(requestedModeId); scheduleTraversalLocked(inTraversal); } } @@ -1564,8 +1569,9 @@ public final class DisplayManagerService extends SystemService { @Override public void setDisplayProperties(int displayId, boolean hasContent, - float requestedRefreshRate, boolean inTraversal) { - setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate, inTraversal); + float requestedRefreshRate, int requestedMode, boolean inTraversal) { + setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate, + requestedMode, inTraversal); } @Override diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index e87f265..cc7d848 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -35,7 +35,7 @@ import android.view.Surface; import android.view.SurfaceControl; import java.io.PrintWriter; -import java.util.Arrays; +import java.util.ArrayList; /** * A display adapter for the local displays managed by Surface Flinger. @@ -56,6 +56,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final SparseArray<LocalDisplayDevice> mDevices = new SparseArray<LocalDisplayDevice>(); + @SuppressWarnings("unused") // Becomes active at instantiation time. private HotplugDisplayEventReceiver mHotplugReceiver; // Called with SyncRoot lock held. @@ -136,28 +137,22 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final class LocalDisplayDevice extends DisplayDevice { private final int mBuiltInDisplayId; - private final SurfaceControl.PhysicalDisplayInfo mPhys; - private final int mDefaultPhysicalDisplayInfo; private final Light mBacklight; + private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>(); private DisplayDeviceInfo mInfo; private boolean mHavePendingChanges; private int mState = Display.STATE_UNKNOWN; private int mBrightness = PowerManager.BRIGHTNESS_DEFAULT; - private float[] mSupportedRefreshRates; - private int[] mRefreshRateConfigIndices; - private float mLastRequestedRefreshRate; - + private int mDefaultModeId; + private int mActiveModeId; + private boolean mActiveModeInvalid; public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId, SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) { super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + builtInDisplayId); mBuiltInDisplayId = builtInDisplayId; - mPhys = new SurfaceControl.PhysicalDisplayInfo( - physicalDisplayInfos[activeDisplayInfo]); - mDefaultPhysicalDisplayInfo = activeDisplayInfo; - updateSupportedRefreshRatesLocked(physicalDisplayInfos, mPhys); - + updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo); if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) { LightsManager lights = LocalServices.getService(LightsManager.class); mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT); @@ -168,14 +163,73 @@ final class LocalDisplayAdapter extends DisplayAdapter { public boolean updatePhysicalDisplayInfoLocked( SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) { - SurfaceControl.PhysicalDisplayInfo newPhys = physicalDisplayInfos[activeDisplayInfo]; - if (!mPhys.equals(newPhys)) { - mPhys.copyFrom(newPhys); - updateSupportedRefreshRatesLocked(physicalDisplayInfos, mPhys); - mHavePendingChanges = true; - return true; + // Build an updated list of all existing modes. + boolean modesAdded = false; + DisplayModeRecord activeRecord = null; + ArrayList<DisplayModeRecord> records = new ArrayList<DisplayModeRecord>(); + for (int i = 0; i < physicalDisplayInfos.length; i++) { + SurfaceControl.PhysicalDisplayInfo info = physicalDisplayInfos[i]; + DisplayModeRecord record = findDisplayModeRecord(info); + if (record != null) { + record.mPhysIndex = i; + } else { + record = new DisplayModeRecord(info, i); + modesAdded = true; + } + records.add(record); + if (i == activeDisplayInfo) { + activeRecord = record; + } + } + // Check whether surface flinger spontaneously changed modes out from under us. Schedule + // traversals to ensure that the correct state is reapplied if necessary. + if (mActiveModeId != 0 + && mActiveModeId != activeRecord.mMode.getModeId()) { + mActiveModeInvalid = true; + sendTraversalRequestLocked(); + } + // If no modes were added and we have the same number of modes as before, then nothing + // actually changed except possibly the physical index (which we only care about when + // setting the mode) so we're done. + if (records.size() == mSupportedModes.size() && !modesAdded) { + return false; + } + // Update the index of modes. + mHavePendingChanges = true; + mSupportedModes.clear(); + for (DisplayModeRecord record : records) { + mSupportedModes.put(record.mMode.getModeId(), record); + } + // Update the default mode if needed. + if (mSupportedModes.indexOfKey(mDefaultModeId) < 0) { + if (mDefaultModeId != 0) { + Slog.w(TAG, "Default display mode no longer available, using currently active" + + " mode as default."); + } + mDefaultModeId = activeRecord.mMode.getModeId(); + } + // Determine whether the active mode is still there. + if (mSupportedModes.indexOfKey(mActiveModeId) < 0) { + if (mActiveModeId != 0) { + Slog.w(TAG, "Active display mode no longer available, reverting to default" + + " mode."); + } + mActiveModeId = mDefaultModeId; + mActiveModeInvalid = true; + } + // Schedule traversals so that we apply pending changes. + sendTraversalRequestLocked(); + return true; + } + + private DisplayModeRecord findDisplayModeRecord(SurfaceControl.PhysicalDisplayInfo info) { + for (int i = 0; i < mSupportedModes.size(); i++) { + DisplayModeRecord record = mSupportedModes.valueAt(i); + if (record.mPhys.equals(info)) { + return record; + } } - return false; + return null; } @Override @@ -189,19 +243,25 @@ final class LocalDisplayAdapter extends DisplayAdapter { @Override public DisplayDeviceInfo getDisplayDeviceInfoLocked() { if (mInfo == null) { + SurfaceControl.PhysicalDisplayInfo phys = mSupportedModes.get(mActiveModeId).mPhys; mInfo = new DisplayDeviceInfo(); - mInfo.width = mPhys.width; - mInfo.height = mPhys.height; - mInfo.refreshRate = mPhys.refreshRate; - mInfo.supportedRefreshRates = mSupportedRefreshRates; - mInfo.appVsyncOffsetNanos = mPhys.appVsyncOffsetNanos; - mInfo.presentationDeadlineNanos = mPhys.presentationDeadlineNanos; + mInfo.width = phys.width; + mInfo.height = phys.height; + mInfo.modeId = mActiveModeId; + mInfo.defaultModeId = mDefaultModeId; + mInfo.supportedModes = new Display.Mode[mSupportedModes.size()]; + for (int i = 0; i < mSupportedModes.size(); i++) { + DisplayModeRecord record = mSupportedModes.valueAt(i); + mInfo.supportedModes[i] = record.mMode; + } + mInfo.appVsyncOffsetNanos = phys.appVsyncOffsetNanos; + mInfo.presentationDeadlineNanos = phys.presentationDeadlineNanos; mInfo.state = mState; mInfo.uniqueId = getUniqueId(); // Assume that all built-in displays that have secure output (eg. HDCP) also // support compositing from gralloc protected buffers. - if (mPhys.secure) { + if (phys.secure) { mInfo.flags = DisplayDeviceInfo.FLAG_SECURE | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; } @@ -212,9 +272,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; mInfo.type = Display.TYPE_BUILT_IN; - mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f); - mInfo.xDpi = mPhys.xDpi; - mInfo.yDpi = mPhys.yDpi; + mInfo.densityDpi = (int)(phys.density * 160 + 0.5f); + mInfo.xDpi = phys.xDpi; + mInfo.yDpi = phys.yDpi; mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; } else { mInfo.type = Display.TYPE_HDMI; @@ -222,7 +282,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.name = getContext().getResources().getString( com.android.internal.R.string.display_manager_hdmi_display_name); mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; - mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height); + mInfo.setAssumedDensityForExternalDisplay(phys.width, phys.height); // For demonstration purposes, allow rotation of the external display. // In the future we might allow the user to configure this directly. @@ -332,30 +392,29 @@ final class LocalDisplayAdapter extends DisplayAdapter { } @Override - public void requestRefreshRateLocked(float refreshRate) { - if (mLastRequestedRefreshRate == refreshRate) { - return; + public void requestModeInTransactionLocked(int modeId) { + if (modeId == 0) { + modeId = mDefaultModeId; + } else if (mSupportedModes.indexOfKey(modeId) < 0) { + Slog.w(TAG, "Requested mode " + modeId + " is not supported by this display," + + " reverting to default display mode."); + modeId = mDefaultModeId; } - mLastRequestedRefreshRate = refreshRate; - if (refreshRate != 0) { - final int N = mSupportedRefreshRates.length; - for (int i = 0; i < N; i++) { - if (refreshRate == mSupportedRefreshRates[i]) { - final int configIndex = mRefreshRateConfigIndices[i]; - SurfaceControl.setActiveConfig(getDisplayTokenLocked(), configIndex); - return; - } - } - Slog.w(TAG, "Requested refresh rate " + refreshRate + " is unsupported."); + if (mActiveModeId == modeId && !mActiveModeInvalid) { + return; } - SurfaceControl.setActiveConfig(getDisplayTokenLocked(), mDefaultPhysicalDisplayInfo); + DisplayModeRecord record = mSupportedModes.get(modeId); + SurfaceControl.setActiveConfig(getDisplayTokenLocked(), record.mPhysIndex); + mActiveModeId = modeId; + mActiveModeInvalid = false; + updateDeviceInfoLocked(); } @Override public void dumpLocked(PrintWriter pw) { super.dumpLocked(pw); pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId); - pw.println("mPhys=" + mPhys); + pw.println("mActiveModeId=" + mActiveModeId); pw.println("mState=" + Display.stateToString(mState)); pw.println("mBrightness=" + mBrightness); pw.println("mBacklight=" + mBacklight); @@ -365,29 +424,20 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo = null; sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); } + } - private void updateSupportedRefreshRatesLocked( - SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, - SurfaceControl.PhysicalDisplayInfo activePhys) { - final int N = physicalDisplayInfos.length; - int idx = 0; - mSupportedRefreshRates = new float[N]; - mRefreshRateConfigIndices = new int[N]; - for (int i = 0; i < N; i++) { - final SurfaceControl.PhysicalDisplayInfo phys = physicalDisplayInfos[i]; - if (activePhys.width == phys.width - && activePhys.height == phys.height - && activePhys.density == phys.density - && activePhys.xDpi == phys.xDpi - && activePhys.yDpi == phys.yDpi) { - mSupportedRefreshRates[idx] = phys.refreshRate; - mRefreshRateConfigIndices[idx++] = i; - } - } - if (idx != N) { - mSupportedRefreshRates = Arrays.copyOfRange(mSupportedRefreshRates, 0, idx); - mRefreshRateConfigIndices = Arrays.copyOfRange(mRefreshRateConfigIndices, 0, idx); - } + /** + * Keeps track of a display configuration. + */ + private static final class DisplayModeRecord { + public final Display.Mode mMode; + public final SurfaceControl.PhysicalDisplayInfo mPhys; + public int mPhysIndex; + + public DisplayModeRecord(SurfaceControl.PhysicalDisplayInfo phys, int physIndex) { + mMode = createMode(phys.width, phys.height, phys.refreshRate); + mPhys = phys; + mPhysIndex = physIndex; } } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 65dc72f..7accbf2 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -73,8 +73,7 @@ final class LogicalDisplay { // True if the logical display has unique content. private boolean mHasContent; - // The pending requested refresh rate. 0 if no request is pending. - private float mRequestedRefreshRate; + private int mRequestedModeId; // The display offsets to apply to the display projection. private int mDisplayOffsetX; @@ -219,9 +218,10 @@ final class LogicalDisplay { mBaseDisplayInfo.logicalWidth = deviceInfo.width; mBaseDisplayInfo.logicalHeight = deviceInfo.height; mBaseDisplayInfo.rotation = Surface.ROTATION_0; - mBaseDisplayInfo.refreshRate = deviceInfo.refreshRate; - mBaseDisplayInfo.supportedRefreshRates = Arrays.copyOf( - deviceInfo.supportedRefreshRates, deviceInfo.supportedRefreshRates.length); + mBaseDisplayInfo.modeId = deviceInfo.modeId; + mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId; + mBaseDisplayInfo.supportedModes = Arrays.copyOf( + deviceInfo.supportedModes, deviceInfo.supportedModes.length); mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi; mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi; mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi; @@ -259,14 +259,19 @@ final class LogicalDisplay { */ public void configureDisplayInTransactionLocked(DisplayDevice device, boolean isBlanked) { - final DisplayInfo displayInfo = getDisplayInfoLocked(); - final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked(); - // Set the layer stack. device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack); - // Set the refresh rate - device.requestRefreshRateLocked(mRequestedRefreshRate); + // Set the mode. + if (device == mPrimaryDisplayDevice) { + device.requestModeInTransactionLocked(mRequestedModeId); + } else { + device.requestModeInTransactionLocked(0); // Revert to default. + } + + // Only grab the display info now as it may have been changed based on the requests above. + final DisplayInfo displayInfo = getDisplayInfoLocked(); + final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked(); // Set the viewport. // This is the area of the logical display that we intend to show on the @@ -351,20 +356,17 @@ final class LogicalDisplay { } /** - * Requests the given refresh rate. - * @param requestedRefreshRate The desired refresh rate. + * Requests the given mode. */ - public void setRequestedRefreshRateLocked(float requestedRefreshRate) { - mRequestedRefreshRate = requestedRefreshRate; + public void setRequestedModeIdLocked(int modeId) { + mRequestedModeId = modeId; } /** - * Gets the pending requested refresh rate. - * - * @return The pending refresh rate requested + * Returns the pending requested mode. */ - public float getRequestedRefreshRateLocked() { - return mRequestedRefreshRate; + public int getRequestedModeIdLocked() { + return mRequestedModeId; } /** @@ -393,7 +395,7 @@ final class LogicalDisplay { pw.println("mDisplayId=" + mDisplayId); pw.println("mLayerStack=" + mLayerStack); pw.println("mHasContent=" + mHasContent); - pw.println("mRequestedRefreshRate=" + mRequestedRefreshRate); + pw.println("mRequestedMode=" + mRequestedModeId); pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")"); pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ? mPrimaryDisplayDevice.getNameLocked() : "null")); diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java index af9f456..080665a 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java @@ -197,6 +197,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { private final long mDisplayPresentationDeadlineNanos; private final int mDensityDpi; private final boolean mSecure; + private final Display.Mode mMode; private int mState; private SurfaceTexture mSurfaceTexture; @@ -217,6 +218,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { mSecure = secure; mState = state; mSurfaceTexture = surfaceTexture; + mMode = createMode(width, height, refreshRate); } public void destroyLocked() { @@ -251,8 +253,9 @@ final class OverlayDisplayAdapter extends DisplayAdapter { mInfo.uniqueId = getUniqueId(); mInfo.width = mWidth; mInfo.height = mHeight; - mInfo.refreshRate = mRefreshRate; - mInfo.supportedRefreshRates = new float[] { mRefreshRate }; + mInfo.modeId = mMode.getModeId(); + mInfo.defaultModeId = mMode.getModeId(); + mInfo.supportedModes = new Display.Mode[] { mMode }; mInfo.densityDpi = mDensityDpi; mInfo.xDpi = mDensityDpi; mInfo.yDpi = mDensityDpi; diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java index 3f4eab9..786889a 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java +++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java @@ -302,7 +302,8 @@ final class OverlayDisplayWindow implements DumpUtils.Dump { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { - mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate, + mListener.onWindowCreated(surfaceTexture, + mDefaultDisplayInfo.getMode().getRefreshRate(), mDefaultDisplayInfo.presentationDeadlineNanos, mDefaultDisplayInfo.state); } @@ -377,4 +378,4 @@ final class OverlayDisplayWindow implements DumpUtils.Dump { public void onWindowDestroyed(); public void onStateChanged(int state); } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 7f961ae..986efd6 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -165,6 +165,8 @@ final class VirtualDisplayAdapter extends DisplayAdapter { private static final int PENDING_SURFACE_CHANGE = 0x01; private static final int PENDING_RESIZE = 0x02; + private static final float REFRESH_RATE = 60.0f; + private final IBinder mAppToken; private final int mOwnerUid; final String mOwnerPackageName; @@ -181,6 +183,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { private boolean mStopped; private int mPendingChanges; private int mUniqueIndex; + private Display.Mode mMode; public VirtualDisplayDevice(IBinder displayToken, IBinder appToken, int ownerUid, String ownerPackageName, @@ -193,6 +196,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { mName = name; mWidth = width; mHeight = height; + mMode = createMode(width, height, REFRESH_RATE); mDensityDpi = densityDpi; mSurface = surface; mFlags = flags; @@ -262,6 +266,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { sendTraversalRequestLocked(); mWidth = width; mHeight = height; + mMode = createMode(width, height, REFRESH_RATE); mDensityDpi = densityDpi; mInfo = null; mPendingChanges |= PENDING_RESIZE; @@ -290,12 +295,13 @@ final class VirtualDisplayAdapter extends DisplayAdapter { mInfo.uniqueId = getUniqueId(); mInfo.width = mWidth; mInfo.height = mHeight; - mInfo.refreshRate = 60; - mInfo.supportedRefreshRates = new float[] { 60.0f }; + mInfo.modeId = mMode.getModeId(); + mInfo.defaultModeId = mMode.getModeId(); + mInfo.supportedModes = new Display.Mode[] { mMode }; mInfo.densityDpi = mDensityDpi; mInfo.xDpi = mDensityDpi; mInfo.yDpi = mDensityDpi; - mInfo.presentationDeadlineNanos = 1000000000L / (int) mInfo.refreshRate; // 1 frame + mInfo.presentationDeadlineNanos = 1000000000L / (int) REFRESH_RATE; // 1 frame mInfo.flags = 0; if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java index f163555..64bc729 100644 --- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java @@ -583,6 +583,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { private final float mRefreshRate; private final int mFlags; private final String mAddress; + private final Display.Mode mMode; private Surface mSurface; private DisplayDeviceInfo mInfo; @@ -598,6 +599,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { mFlags = flags; mAddress = address; mSurface = surface; + mMode = createMode(width, height, refreshRate); } public void destroyLocked() { @@ -628,8 +630,9 @@ final class WifiDisplayAdapter extends DisplayAdapter { mInfo.uniqueId = getUniqueId(); mInfo.width = mWidth; mInfo.height = mHeight; - mInfo.refreshRate = mRefreshRate; - mInfo.supportedRefreshRates = new float[] { mRefreshRate }; + mInfo.modeId = mMode.getModeId(); + mInfo.defaultModeId = mMode.getModeId(); + mInfo.supportedModes = new Display.Mode[] { mMode }; mInfo.presentationDeadlineNanos = 1000000000L / (int) mRefreshRate; // 1 frame mInfo.flags = mFlags; mInfo.type = Display.TYPE_WIFI; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 6bf68e8..06d3b22 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -691,6 +691,8 @@ public class WindowManagerService extends IWindowManager.Stub boolean mObscureApplicationContentOnSecondaryDisplays = false; float mPreferredRefreshRate = 0; + + int mPreferredModeId = 0; } final LayoutFields mInnerFields = new LayoutFields(); @@ -9713,6 +9715,10 @@ public class WindowManagerService extends IWindowManager.Stub && w.mAttrs.preferredRefreshRate != 0) { mInnerFields.mPreferredRefreshRate = w.mAttrs.preferredRefreshRate; } + if (mInnerFields.mPreferredModeId == 0 + && w.mAttrs.preferredDisplayModeId != 0) { + mInnerFields.mPreferredModeId = w.mAttrs.preferredDisplayModeId; + } } } } @@ -9846,6 +9852,7 @@ public class WindowManagerService extends IWindowManager.Stub // Reset for each display. mInnerFields.mDisplayHasContent = false; mInnerFields.mPreferredRefreshRate = 0; + mInnerFields.mPreferredModeId = 0; int repeats = 0; do { @@ -10066,6 +10073,7 @@ public class WindowManagerService extends IWindowManager.Stub mDisplayManagerInternal.setDisplayProperties(displayId, mInnerFields.mDisplayHasContent, mInnerFields.mPreferredRefreshRate, + mInnerFields.mPreferredModeId, true /* inTraversal, must call performTraversalInTrans... below */); getDisplayContentLocked(displayId).stopDimmingIfNeeded(); |