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 \
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();
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
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();
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;
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();
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
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();
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;
* 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.
private static float getRefreshRate() {
DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
Display.DEFAULT_DISPLAY);
- return di.refreshRate;
+ return di.getMode().getRefreshRate();
}
/**
--- /dev/null
+/**
+ * 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;
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;
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);
}
}
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];
+ }
+ };
+ }
}
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;
/**
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
&& 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
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;
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();
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);
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);
}
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 ");
* 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);
*/
@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
@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
* 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;
* In multiuser systems shows on all users' windows.
*/
public static final int TYPE_APPLICATION_STARTING = 3;
-
+
/**
* End of types of application windows.
*/
* 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).
* 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.
* 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
* 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
* 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
/** @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;
* 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
*/
@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
* {@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.
* 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
* 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
* 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
* 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
* {@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
* 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
* 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>
/**
* Various behavioral options/flags. Default is none.
- *
+ *
* @see #FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
* @see #FLAG_DIM_BEHIND
* @see #FLAG_NOT_FOCUSABLE
* 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;
* 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;
}
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
* 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
* 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.
/**
* 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},
* {@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,
* @see Gravity
*/
public int gravity;
-
+
/**
* The horizontal margin, as a percentage of the container's width,
* between the container and the widget. See
* 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
* @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
* 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
* 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
* 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
* 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;
* 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
/**
* Get callbacks about the system ui visibility changing.
- *
+ *
* TODO: Maybe there should be a bitfield of optional callbacks that we need.
*
* @hide
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);
flags = _flags;
format = _format;
}
-
+
public final void setTitle(CharSequence title) {
if (null == title)
title = "";
-
+
mTitle = TextUtils.stringOrSpannedString(title);
}
-
+
public final CharSequence getTitle() {
return mTitle;
}
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);
return new LayoutParams[size];
}
};
-
-
+
+
public LayoutParams(Parcel in) {
width = in.readInt();
height = in.readInt();
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;
/** {@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.
rotationAnimation = o.rotationAnimation;
changes |= ROTATION_ANIMATION_CHANGED;
}
-
+
if (screenOrientation != o.screenOrientation) {
screenOrientation = o.screenOrientation;
changes |= SCREEN_ORIENTATION_CHANGED;
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;
Log.d("Debug", "WindowManager.LayoutParams={title=" + mTitle + "}");
return "";
}
-
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(256);
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));
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
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) {
});
}
+ 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();
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;
}
/**
- * Sets the refresh rate, if supported.
+ * Sets the mode, if supported.
*/
- public void requestRefreshRateLocked(float refreshRate) {
+ public void requestModeInTransactionLocked(int id) {
}
/**
import java.util.Arrays;
-import libcore.util.EmptyArray;
import libcore.util.Objects;
/**
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.
|| !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
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;
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);
}
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) {
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);
}
}
@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
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.
private final SparseArray<LocalDisplayDevice> mDevices =
new SparseArray<LocalDisplayDevice>();
+ @SuppressWarnings("unused") // Becomes active at instantiation time.
private HotplugDisplayEventReceiver mHotplugReceiver;
// Called with SyncRoot lock held.
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);
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
@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;
}
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;
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.
}
@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);
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;
}
}
// 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;
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;
*/
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
}
/**
- * 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;
}
/**
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"));
private final long mDisplayPresentationDeadlineNanos;
private final int mDensityDpi;
private final boolean mSecure;
+ private final Display.Mode mMode;
private int mState;
private SurfaceTexture mSurfaceTexture;
mSecure = secure;
mState = state;
mSurfaceTexture = surfaceTexture;
+ mMode = createMode(width, height, refreshRate);
}
public void destroyLocked() {
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;
@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);
}
public void onWindowDestroyed();
public void onStateChanged(int state);
}
-}
\ No newline at end of file
+}
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;
private boolean mStopped;
private int mPendingChanges;
private int mUniqueIndex;
+ private Display.Mode mMode;
public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
int ownerUid, String ownerPackageName,
mName = name;
mWidth = width;
mHeight = height;
+ mMode = createMode(width, height, REFRESH_RATE);
mDensityDpi = densityDpi;
mSurface = surface;
mFlags = flags;
sendTraversalRequestLocked();
mWidth = width;
mHeight = height;
+ mMode = createMode(width, height, REFRESH_RATE);
mDensityDpi = densityDpi;
mInfo = null;
mPendingChanges |= PENDING_RESIZE;
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
private final float mRefreshRate;
private final int mFlags;
private final String mAddress;
+ private final Display.Mode mMode;
private Surface mSurface;
private DisplayDeviceInfo mInfo;
mFlags = flags;
mAddress = address;
mSurface = surface;
+ mMode = createMode(width, height, refreshRate);
}
public void destroyLocked() {
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;
boolean mObscureApplicationContentOnSecondaryDisplays = false;
float mPreferredRefreshRate = 0;
+
+ int mPreferredModeId = 0;
}
final LayoutFields mInnerFields = new LayoutFields();
&& w.mAttrs.preferredRefreshRate != 0) {
mInnerFields.mPreferredRefreshRate = w.mAttrs.preferredRefreshRate;
}
+ if (mInnerFields.mPreferredModeId == 0
+ && w.mAttrs.preferredDisplayModeId != 0) {
+ mInnerFields.mPreferredModeId = w.mAttrs.preferredDisplayModeId;
+ }
}
}
}
// Reset for each display.
mInnerFields.mDisplayHasContent = false;
mInnerFields.mPreferredRefreshRate = 0;
+ mInnerFields.mPreferredModeId = 0;
int repeats = 0;
do {
mDisplayManagerInternal.setDisplayProperties(displayId,
mInnerFields.mDisplayHasContent, mInnerFields.mPreferredRefreshRate,
+ mInnerFields.mPreferredModeId,
true /* inTraversal, must call performTraversalInTrans... below */);
getDisplayContentLocked(displayId).stopDimmingIfNeeded();