From 056b3ee745303f6f934e0f0018deea4208a5ea7c Mon Sep 17 00:00:00 2001 From: Galia Peycheva Date: Wed, 26 Jun 2019 14:05:12 +0200 Subject: [PATCH] Add minimal post processing API to framework This API allows applications to instruct the connected display to do minimal post processing on the produced image or video frames. This will switch the display to a low latency mode (ALLM, Game mode or some other custom implementation thereof), reducing lag in the final images. Thus, minimal post processing would greatly enhance performance for gaming and video conferencing applications. It would not, however, suit applications that prioritise image quality over performance. This CL adds 2 public method: - Window.setPreferMinimalPostProcessing() (this can also be set in WindowManager.LayoutParams.preferMinimalPostProcessing) If minimal post processing is preferred, the connected display will be requested to go into low latency mode, which reduces image processing, resulting in better performance for gaming applications. If the Display sink is connected via HDMI, the device will begin to send infoframes with Auto Low Latency Mode enabled and Game Content Type. This will switch the connected display to a lower latency mode (if available). For more information, see HDMI 2.1 specification. If the Display sink has an internal connection or uses some other protocol than HDMI, effects may be similar but implementation-defined. - Display.isMinimalPostProcessingPreferred() Returns true if the connected display supports either Low Latency Mode (ALLM or some other custom low latency implementation) or Game content type. Bug: 135116095 Test: make -> flash on ATV OTT device -> open an activity which requests minimal post processing -> check SurfaceControl logs -> verify correct signals are passed to native Change-Id: I5508bb9e5c138b0f2b42d8f8fab10e1915ba3cb6 --- api/current.txt | 5 ++ core/java/android/app/Activity.java | 1 + .../java/android/content/pm/ActivityInfo.java | 31 ++++++++++++ .../display/DisplayManagerInternal.java | 7 ++- core/java/android/view/Display.java | 26 ++++++++++ core/java/android/view/DisplayInfo.java | 12 +++++ core/java/android/view/SurfaceControl.java | 49 +++++++++++++++++++ core/java/android/view/Window.java | 38 ++++++++++++++ core/java/android/view/WindowManager.java | 40 +++++++++++++++ core/jni/android_view_SurfaceControl.cpp | 36 ++++++++++++++ core/res/res/values/attrs_manifest.xml | 24 +++++++++ core/res/res/values/public.xml | 4 ++ .../android/server/display/DisplayDevice.java | 18 +++++++ .../server/display/DisplayDeviceInfo.java | 16 ++++++ .../server/display/DisplayManagerService.java | 28 +++++++++-- .../server/display/LocalDisplayAdapter.java | 46 +++++++++++++++++ .../server/display/LogicalDisplay.java | 24 +++++++++ .../com/android/server/wm/DisplayContent.java | 8 +++ 18 files changed, 407 insertions(+), 6 deletions(-) diff --git a/api/current.txt b/api/current.txt index 5d12f81eebcf7..8572c8347dac2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1062,6 +1062,7 @@ package android { field public static final int popupWindowStyle = 16842870; // 0x1010076 field public static final int port = 16842793; // 0x1010029 field public static final int positiveButtonText = 16843253; // 0x10101f5 + field public static final int preferMinimalPostProcessing = 16844300; // 0x101060c field public static final int preferenceCategoryStyle = 16842892; // 0x101008c field public static final int preferenceFragmentStyle = 16844038; // 0x1010506 field public static final int preferenceInformationStyle = 16842893; // 0x101008d @@ -11189,6 +11190,7 @@ package android.content.pm { field public String parentActivityName; field public String permission; field public int persistableMode; + field public boolean preferMinimalPostProcessing; field public int screenOrientation; field public int softInputMode; field public String targetActivity; @@ -49895,6 +49897,7 @@ package android.view { method @Deprecated public float[] getSupportedRefreshRates(); method @Deprecated public int getWidth(); method public boolean isHdr(); + method public boolean isMinimalPostProcessingSupported(); method public boolean isValid(); method public boolean isWideColorGamut(); field public static final int DEFAULT_DISPLAY = 0; // 0x0 @@ -52927,6 +52930,7 @@ package android.view { method public abstract void setNavigationBarColor(@ColorInt int); method public void setNavigationBarContrastEnforced(boolean); method public void setNavigationBarDividerColor(@ColorInt int); + method public void setPreferMinimalPostProcessing(boolean); method public void setReenterTransition(android.transition.Transition); method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable); method public final void setRestrictedCaptionAreaListener(android.view.Window.OnRestrictedCaptionAreaChangedListener); @@ -53314,6 +53318,7 @@ package android.view { field public int layoutInDisplayCutoutMode; field @Deprecated public int memoryType; field public String packageName; + field public boolean preferMinimalPostProcessing; field public int preferredDisplayModeId; field @Deprecated public float preferredRefreshRate; field public int rotationAnimation; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 9e0c2fc18fd9a..00b704d4f5b35 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -7871,6 +7871,7 @@ public class Activity extends ContextThemeWrapper mCurrentConfig = config; mWindow.setColorMode(info.colorMode); + mWindow.setPreferMinimalPostProcessing(info.preferMinimalPostProcessing); setAutofillOptions(application.getAutofillOptions()); setContentCaptureOptions(application.getContentCaptureOptions()); diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 5b1f92642ee2b..e5daaca4aa528 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -289,6 +289,34 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @ColorMode public int colorMode = COLOR_MODE_DEFAULT; + /** + * Indicates whether the activity wants the connected display to do minimal post processing on + * the produced image or video frames. This will only be requested if this activity's main + * window is visible on the screen. + * + *

This setting should be used when low latency has a higher priority than image enhancement + * processing (e.g. for games or video conferencing). + * + *

If the Display sink is connected via HDMI, the device will begin to send infoframes with + * Auto Low Latency Mode enabled and Game Content Type. This will switch the connected display + * to a minimal image processing mode (if available), which reduces latency, improving the user + * experience for gaming or video conferencing applications. For more information, see HDMI 2.1 + * specification. + * + *

If the Display sink has an internal connection or uses some other protocol than HDMI, + * effects may be similar but implementation-defined. + * + *

The ability to switch to a mode with minimal post proessing may be disabled by a user + * setting in the system settings menu. In that case, this field is ignored and the display will + * remain in its current mode. + * + *

Set from attribute {@link android.R.attr#preferMinimalPostProcessing}. + * + * @see android.view.WindowManager.LayoutParams#preferMinimalPostProcessing + * @see android.view.Display#isMinimalPostProcessingSupported + */ + public boolean preferMinimalPostProcessing = false; + /** * Bit in {@link #flags} indicating whether this activity is able to * run in multiple processes. If @@ -1004,6 +1032,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { requestedVrComponent = orig.requestedVrComponent; rotationAnimation = orig.rotationAnimation; colorMode = orig.colorMode; + preferMinimalPostProcessing = orig.preferMinimalPostProcessing; maxAspectRatio = orig.maxAspectRatio; minAspectRatio = orig.minAspectRatio; } @@ -1231,6 +1260,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { dest.writeInt(colorMode); dest.writeFloat(maxAspectRatio); dest.writeFloat(minAspectRatio); + dest.writeBoolean(preferMinimalPostProcessing); } /** @@ -1349,6 +1379,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { colorMode = source.readInt(); maxAspectRatio = source.readFloat(); minAspectRatio = source.readFloat(); + preferMinimalPostProcessing = source.readBoolean(); } /** diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index c9551378c1908..79a339fa27aab 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -24,7 +24,6 @@ import android.util.IntArray; import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; -import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; @@ -151,11 +150,15 @@ public abstract class DisplayManagerInternal { * has a preference. * @param requestedModeId The preferred mode id for the top-most visible window that has a * preference. + * @param requestedMinimalPostProcessing The preferred minimal post processing setting for the + * display. This is true when there is at least one visible window that wants minimal post + * processng on. * @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, int requestedModeId, boolean inTraversal); + float requestedRefreshRate, int requestedModeId, boolean requestedMinimalPostProcessing, + boolean inTraversal); /** * Applies an offset to the contents of a display, for example to avoid burn-in. diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index b555d20bc08a4..4368115917e54 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.TestApi; import android.app.KeyguardManager; import android.compat.annotation.UnsupportedAppUsage; @@ -875,6 +876,31 @@ public final class Display { } } + /** + *

Returns true if the connected display can be switched into a mode with minimal + * post processing.

+ * + *

If the Display sink is connected via HDMI, this method will return true if the + * display supports either Auto Low Latency Mode or Game Content Type. + * + *

If the Display sink has an internal connection or uses some other protocol than + * HDMI, this method will return true if the sink can be switched into an + * implementation-defined low latency image processing mode.

+ * + *

The ability to switch to a mode with minimal post processing may be disabled + * by a user setting in the system settings menu. In that case, this method returns + * false.

+ * + * @see android.view.Window#setPreferMinimalPostProcessing + */ + @SuppressLint("VisiblySynchronized") + public boolean isMinimalPostProcessingSupported() { + synchronized (this) { + updateDisplayInfoLocked(); + return mDisplayInfo.minimalPostProcessingSupported; + } + } + /** * Request the display applies a color mode. * @hide diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 8a5385d6e2b2d..7d455c93729cc 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -183,6 +183,14 @@ public final class DisplayInfo implements Parcelable { /** The display's HDR capabilities */ public Display.HdrCapabilities hdrCapabilities; + /** + * Indicates whether the display can be switched into a mode with minimal post + * processing. + * + * @see android.view.Display#isMinimalPostProcessingSupported + */ + public boolean minimalPostProcessingSupported; + /** * The logical display density which is the basis for density-independent * pixels. @@ -305,6 +313,7 @@ public final class DisplayInfo implements Parcelable { && colorMode == other.colorMode && Arrays.equals(supportedColorModes, other.supportedColorModes) && Objects.equals(hdrCapabilities, other.hdrCapabilities) + && minimalPostProcessingSupported == other.minimalPostProcessingSupported && logicalDensityDpi == other.logicalDensityDpi && physicalXDpi == other.physicalXDpi && physicalYDpi == other.physicalYDpi @@ -346,6 +355,7 @@ public final class DisplayInfo implements Parcelable { supportedColorModes = Arrays.copyOf( other.supportedColorModes, other.supportedColorModes.length); hdrCapabilities = other.hdrCapabilities; + minimalPostProcessingSupported = other.minimalPostProcessingSupported; logicalDensityDpi = other.logicalDensityDpi; physicalXDpi = other.physicalXDpi; physicalYDpi = other.physicalYDpi; @@ -388,6 +398,7 @@ public final class DisplayInfo implements Parcelable { supportedColorModes[i] = source.readInt(); } hdrCapabilities = source.readParcelable(null); + minimalPostProcessingSupported = source.readBoolean(); logicalDensityDpi = source.readInt(); physicalXDpi = source.readFloat(); physicalYDpi = source.readFloat(); @@ -430,6 +441,7 @@ public final class DisplayInfo implements Parcelable { dest.writeInt(supportedColorModes[i]); } dest.writeParcelable(hdrCapabilities, flags); + dest.writeBoolean(minimalPostProcessingSupported); dest.writeInt(logicalDensityDpi); dest.writeFloat(physicalXDpi); dest.writeFloat(physicalYDpi); diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index c566eaefa0aa7..661322dec8ad0 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -169,6 +169,8 @@ public final class SurfaceControl implements Parcelable { private static native int nativeGetActiveColorMode(IBinder displayToken); private static native boolean nativeSetActiveColorMode(IBinder displayToken, int colorMode); + private static native void nativeSetAutoLowLatencyMode(IBinder displayToken, boolean on); + private static native void nativeSetGameContentType(IBinder displayToken, boolean on); private static native void nativeSetDisplayPowerMode( IBinder displayToken, int mode); private static native void nativeDeferTransactionUntil(long transactionObj, long nativeObject, @@ -186,6 +188,9 @@ public final class SurfaceControl implements Parcelable { private static native Display.HdrCapabilities nativeGetHdrCapabilities(IBinder displayToken); + private static native boolean nativeGetAutoLowLatencyModeSupport(IBinder displayToken); + private static native boolean nativeGetGameContentTypeSupport(IBinder displayToken); + private static native void nativeSetInputWindowInfo(long transactionObj, long nativeObject, InputWindowHandle handle); @@ -1680,6 +1685,28 @@ public final class SurfaceControl implements Parcelable { return colorSpaces; } + /** + * @hide + */ + public static void setAutoLowLatencyMode(IBinder displayToken, boolean on) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + + nativeSetAutoLowLatencyMode(displayToken, on); + } + + /** + * @hide + */ + public static void setGameContentType(IBinder displayToken, boolean on) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + + nativeSetGameContentType(displayToken, on); + } + /** * @hide */ @@ -1731,6 +1758,28 @@ public final class SurfaceControl implements Parcelable { return nativeGetHdrCapabilities(displayToken); } + /** + * @hide + */ + public static boolean getAutoLowLatencyModeSupport(IBinder displayToken) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + + return nativeGetAutoLowLatencyModeSupport(displayToken); + } + + /** + * @hide + */ + public static boolean getGameContentTypeSupport(IBinder displayToken) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + + return nativeGetGameContentTypeSupport(displayToken); + } + /** * @hide */ diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 07764694a40b0..a1894f30d6f69 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1198,6 +1198,44 @@ public abstract class Window { dispatchWindowAttributesChanged(attrs); } + /** + * If {@code isPreferred} is true, this method requests that the connected display does minimal + * post processing when this window is visible on the screen. Otherwise, it requests that the + * display switches back to standard image processing. + * + *

By default, the display does not do minimal post processing and if this is desired, this + * method should not be used. It should be used with {@code isPreferred=true} when low + * latency has a higher priority than image enhancement processing (e.g. for games or video + * conferencing). The display will automatically go back into standard image processing mode + * when no window requesting minimal posst processing is visible on screen anymore. + * {@code setPreferMinimalPostProcessing(false)} can be used if + * {@code setPreferMinimalPostProcessing(true)} was previously called for this window and + * minimal post processing is no longer required. + * + *

If the Display sink is connected via HDMI, the device will begin to send infoframes with + * Auto Low Latency Mode enabled and Game Content Type. This will switch the connected display + * to a minimal image processing mode (if available), which reduces latency, improving the user + * experience for gaming or video conferencing applications. For more information, see HDMI 2.1 + * specification. + * + *

If the Display sink has an internal connection or uses some other protocol than HDMI, + * effects may be similar but implementation-defined. + * + *

The ability to switch to a mode with minimal post proessing may be disabled by a user + * setting in the system settings menu. In that case, this method does nothing. + * + * @see android.content.pm.ActivityInfo#preferMinimalPostProcessing + * @see android.view.Display#isMinimalPostProcessingSupported + * @see android.view.WindowManager.LayoutParams#preferMinimalPostProcessing + * + * @param isPreferred Indicates whether minimal post processing is preferred for this window + * ({@code isPreferred=true}) or not ({@code isPreferred=false}). + */ + public void setPreferMinimalPostProcessing(boolean isPreferred) { + mWindowAttributes.preferMinimalPostProcessing = isPreferred; + dispatchWindowAttributesChanged(mWindowAttributes); + } + /** * Returns the requested color mode of the window, one of * {@link ActivityInfo#COLOR_MODE_DEFAULT}, {@link ActivityInfo#COLOR_MODE_WIDE_COLOR_GAMUT} diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index fc126396edc68..f7d9706a9fcee 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -2606,6 +2606,33 @@ public interface WindowManager extends ViewManager { @UnsupportedAppUsage public long hideTimeoutMilliseconds = -1; + /** + * Indicates whether this window wants the connected display to do minimal post processing + * on the produced image or video frames. This will only be requested if the window is + * visible on the screen. + * + *

This setting should be used when low latency has a higher priority than image + * enhancement processing (e.g. for games or video conferencing). + * + *

If the Display sink is connected via HDMI, the device will begin to send infoframes + * with Auto Low Latency Mode enabled and Game Content Type. This will switch the connected + * display to a minimal image processing mode (if available), which reduces latency, + * improving the user experience for gaming or video conferencing applications. For more + * information, see HDMI 2.1 specification. + * + *

If the Display sink has an internal connection or uses some other protocol than HDMI, + * effects may be similar but implementation-defined. + * + *

The ability to switch to a mode with minimal post proessing may be disabled by a user + * setting in the system settings menu. In that case, this field is ignored and the display + * will remain in its current mode. + * + * @see android.content.pm.ActivityInfo#preferMinimalPostProcessing + * @see android.view.Display#isMinimalPostProcessingSupported + * @see android.view.Window#setPreferMinimalPostProcessing + */ + public boolean preferMinimalPostProcessing = false; + /** * The color mode requested by this window. The target display may * not be able to honor the request. When the color mode is not set @@ -2909,6 +2936,7 @@ public interface WindowManager extends ViewManager { out.writeInt(mFitWindowInsetsTypes); out.writeInt(mFitWindowInsetsSides); out.writeBoolean(mFitIgnoreVisibility); + out.writeBoolean(preferMinimalPostProcessing); } public static final @android.annotation.NonNull Parcelable.Creator CREATOR @@ -2969,6 +2997,7 @@ public interface WindowManager extends ViewManager { mFitWindowInsetsTypes = in.readInt(); mFitWindowInsetsSides = in.readInt(); mFitIgnoreVisibility = in.readBoolean(); + preferMinimalPostProcessing = in.readBoolean(); } @SuppressWarnings({"PointlessBitwiseExpression"}) @@ -3014,6 +3043,8 @@ public interface WindowManager extends ViewManager { public static final int COLOR_MODE_CHANGED = 1 << 26; /** {@hide} */ public static final int INSET_FLAGS_CHANGED = 1 << 27; + /** {@hide} */ + public static final int MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED = 1 << 28; // internal buffer to backup/restore parameters under compatibility mode. private int[] mCompatibilityParamsBackup = null; @@ -3194,6 +3225,11 @@ public interface WindowManager extends ViewManager { changes |= COLOR_MODE_CHANGED; } + if (preferMinimalPostProcessing != o.preferMinimalPostProcessing) { + preferMinimalPostProcessing = o.preferMinimalPostProcessing; + changes |= MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED; + } + // This can't change, it's only set at window creation time. hideTimeoutMilliseconds = o.hideTimeoutMilliseconds; @@ -3348,6 +3384,10 @@ public interface WindowManager extends ViewManager { if (mColorMode != COLOR_MODE_DEFAULT) { sb.append(" colorMode=").append(ActivityInfo.colorModeToString(mColorMode)); } + if (preferMinimalPostProcessing) { + sb.append(" preferMinimalPostProcessing="); + sb.append(preferMinimalPostProcessing); + } sb.append(System.lineSeparator()); sb.append(prefix).append(" fl=").append( ViewDebug.flagsToString(LayoutParams.class, "flags", flags)); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 33da34d809eb8..4a7276c4f94e3 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -1174,6 +1174,34 @@ static jobject nativeGetHdrCapabilities(JNIEnv* env, jclass clazz, jobject token capabilities.getDesiredMaxAverageLuminance(), capabilities.getDesiredMinLuminance()); } +static jboolean nativeGetAutoLowLatencyModeSupport(JNIEnv* env, jclass clazz, jobject tokenObject) { + sp token(ibinderForJavaObject(env, tokenObject)); + if (token == NULL) return NULL; + + return SurfaceComposerClient::getAutoLowLatencyModeSupport(token); +} + +static jboolean nativeGetGameContentTypeSupport(JNIEnv* env, jclass clazz, jobject tokenObject) { + sp token(ibinderForJavaObject(env, tokenObject)); + if (token == NULL) return NULL; + + return SurfaceComposerClient::getGameContentTypeSupport(token); +} + +static void nativeSetAutoLowLatencyMode(JNIEnv* env, jclass clazz, jobject tokenObject, jboolean on) { + sp token(ibinderForJavaObject(env, tokenObject)); + if (token == NULL) return; + + SurfaceComposerClient::setAutoLowLatencyMode(token, on); +} + +static void nativeSetGameContentType(JNIEnv* env, jclass clazz, jobject tokenObject, jboolean on) { + sp token(ibinderForJavaObject(env, tokenObject)); + if (token == NULL) return; + + SurfaceComposerClient::setGameContentType(token, on); +} + static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); if (parcel == NULL) { @@ -1376,6 +1404,14 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeGetActiveColorMode}, {"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z", (void*)nativeSetActiveColorMode}, + {"nativeGetAutoLowLatencyModeSupport", "(Landroid/os/IBinder;)Z", + (void*)nativeGetAutoLowLatencyModeSupport }, + {"nativeSetAutoLowLatencyMode", "(Landroid/os/IBinder;Z)V", + (void*)nativeSetAutoLowLatencyMode }, + {"nativeGetGameContentTypeSupport", "(Landroid/os/IBinder;)Z", + (void*)nativeGetGameContentTypeSupport }, + {"nativeSetGameContentType", "(Landroid/os/IBinder;Z)V", + (void*)nativeSetGameContentType }, {"nativeGetCompositionDataspaces", "()[I", (void*)nativeGetCompositionDataspaces}, {"nativeGetHdrCapabilities", "(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;", diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index b17d473409ac5..6350bf6e5352f 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2497,6 +2497,30 @@ + +