Loading core/java/android/view/WindowManager.java +37 −0 Original line number Diff line number Diff line Loading @@ -852,6 +852,43 @@ public interface WindowManager extends ViewManager { String PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION = "android.window.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION"; /** * Application level {@link android.content.pm.PackageManager.Property PackageManager * .Property} for an app to inform the system that the application can be opted-in or opted-out * from the compatibility treatment that enables sending a fake focus event for unfocused * resumed split screen activities. This is needed because some game engines wait to get * focus before drawing the content of the app which isn't guaranteed by default in multi-window * modes. * * <p>Device manufacturers can enable this treatment using their discretion on a per-device * basis to improve display compatibility. The treatment also needs to be specifically enabled * on a per-app basis afterwards. This can either be done by device manufacturers or developers. * * <p>With this property set to {@code true}, the system will apply the treatment only if the * device manufacturer had previously enabled it on the device. A fake focus event will be sent * to the app after it is resumed only if the app is in split-screen. * * <p>Setting this property to {@code false} informs the system that the activity must be * opted-out from the compatibility treatment even if the device manufacturer has opted the app * into the treatment. * * <p>If the property remains unset the system will apply the treatment only if it had * previously been enabled both at the device and app level by the device manufacturer. * * <p><b>Syntax:</b> * <pre> * <application> * <property * android:name="android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS" * android:value="true|false"/> * </application> * </pre> * * @hide */ // TODO(b/263984287): Make this public API. String PROPERTY_COMPAT_ENABLE_FAKE_FOCUS = "android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS"; /** * Application level {@link android.content.pm.PackageManager.Property PackageManager * .Property} for an app to inform the system that the app should be excluded from the Loading services/core/java/com/android/server/wm/ActivityRecord.java +2 −2 Original line number Diff line number Diff line Loading @@ -10214,8 +10214,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // TODO(b/263592337): Explore enabling compat fake focus for fullscreen, e.g. for when // covered with bubbles. boolean shouldSendCompatFakeFocus() { return mWmService.mLetterboxConfiguration.isCompatFakeFocusEnabled(info) && inMultiWindowMode() && !inPinnedWindowingMode() && !inFreeformWindowingMode(); return mLetterboxUiController.shouldSendFakeFocus() && inMultiWindowMode() && !inPinnedWindowingMode() && !inFreeformWindowingMode(); } static class Builder { Loading services/core/java/com/android/server/wm/LetterboxConfiguration.java +1 −33 Original line number Diff line number Diff line Loading @@ -25,8 +25,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.graphics.Color; import android.provider.DeviceConfig; import android.util.Slog; Loading Loading @@ -1062,38 +1060,8 @@ final class LetterboxConfiguration { "enable_translucent_activity_letterbox", false); } @VisibleForTesting boolean getPackageManagerProperty(PackageManager pm, String property) { boolean enabled = false; try { final PackageManager.Property p = pm.getProperty(property, mContext.getPackageName()); enabled = p.getBoolean(); } catch (PackageManager.NameNotFoundException e) { // Property not found } return enabled; } @VisibleForTesting boolean isCompatFakeFocusEnabled(ActivityInfo info) { if (!isCompatFakeFocusEnabledOnDevice()) { return false; } // See if the developer has chosen to opt in / out of treatment PackageManager pm = mContext.getPackageManager(); if (getPackageManagerProperty(pm, PROPERTY_COMPAT_FAKE_FOCUS_OPT_OUT)) { return false; } else if (getPackageManagerProperty(pm, PROPERTY_COMPAT_FAKE_FOCUS_OPT_IN)) { return true; } if (info.isChangeEnabled(ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS)) { return true; } return false; } /** Whether fake sending focus is enabled for unfocused apps in splitscreen */ boolean isCompatFakeFocusEnabledOnDevice() { boolean isCompatFakeFocusEnabled() { return mIsCompatFakeFocusEnabled && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER, DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, true); Loading services/core/java/com/android/server/wm/LetterboxUiController.java +34 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE; import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS; import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION; import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR; Loading @@ -41,6 +42,7 @@ import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS; import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM; Loading Loading @@ -149,6 +151,9 @@ final class LetterboxUiController { // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled; // Corresponds to OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS private final boolean mIsOverrideEnableCompatFakeFocusEnabled; @Nullable private final Boolean mBooleanPropertyAllowOrientationOverride; @Nullable Loading Loading @@ -204,6 +209,9 @@ final class LetterboxUiController { @Nullable private final Boolean mBooleanPropertyIgnoreRequestedOrientation; @Nullable private final Boolean mBooleanPropertyFakeFocus; private boolean mIsRelauchingAfterRequestedOrientationChanged; LetterboxUiController(WindowManagerService wmService, ActivityRecord activityRecord) { Loading @@ -218,6 +226,10 @@ final class LetterboxUiController { readComponentProperty(packageManager, mActivityRecord.packageName, mLetterboxConfiguration::isPolicyForIgnoringRequestedOrientationEnabled, PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION); mBooleanPropertyFakeFocus = readComponentProperty(packageManager, mActivityRecord.packageName, mLetterboxConfiguration::isCompatFakeFocusEnabled, PROPERTY_COMPAT_ENABLE_FAKE_FOCUS); mBooleanPropertyCameraCompatAllowForceRotation = readComponentProperty(packageManager, mActivityRecord.packageName, () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled( Loading Loading @@ -265,6 +277,9 @@ final class LetterboxUiController { mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION); mIsOverrideEnableCompatFakeFocusEnabled = isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS); } /** Loading Loading @@ -359,6 +374,25 @@ final class LetterboxUiController { return false; } /** * Whether sending compat fake focus for split screen resumed activities is enabled. Needed * because some game engines wait to get focus before drawing the content of the app which isn't * guaranteed by default in multi-window modes. * * <p>This treatment is enabled when the following conditions are met: * <ul> * <li>Flag gating the treatment is enabled * <li>Component property is NOT set to false * <li>Component property is set to true or per-app override is enabled * </ul> */ boolean shouldSendFakeFocus() { return shouldEnableWithOverrideAndProperty( /* gatingCondition */ mLetterboxConfiguration::isCompatFakeFocusEnabled, mIsOverrideEnableCompatFakeFocusEnabled, mBooleanPropertyFakeFocus); } /** * Sets whether an activity is relaunching after the app has called {@link * android.app.Activity#setRequestedOrientation}. Loading services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java +4 −4 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ import java.util.function.BiConsumer; * Tests for the {@link LetterboxConfiguration} class. * * Build/Install/Run: * atest WmTests:LetterboxConfigurationTests * atest WmTests:LetterboxConfigurationTest */ @SmallTest @Presubmit Loading Loading @@ -243,18 +243,18 @@ public class LetterboxConfigurationTest { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, "true", false); mLetterboxConfiguration.setIsCompatFakeFocusEnabled(false); assertFalse(mLetterboxConfiguration.isCompatFakeFocusEnabledOnDevice()); assertFalse(mLetterboxConfiguration.isCompatFakeFocusEnabled()); // Set runtime flag to false and build time flag to true DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, "false", false); mLetterboxConfiguration.setIsCompatFakeFocusEnabled(true); assertFalse(mLetterboxConfiguration.isCompatFakeFocusEnabledOnDevice()); assertFalse(mLetterboxConfiguration.isCompatFakeFocusEnabled()); // Set runtime flag to true so that both are enabled DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, "true", false); assertTrue(mLetterboxConfiguration.isCompatFakeFocusEnabledOnDevice()); assertTrue(mLetterboxConfiguration.isCompatFakeFocusEnabled()); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, Boolean.toString(wasFakeFocusEnabled), Loading Loading
core/java/android/view/WindowManager.java +37 −0 Original line number Diff line number Diff line Loading @@ -852,6 +852,43 @@ public interface WindowManager extends ViewManager { String PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION = "android.window.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION"; /** * Application level {@link android.content.pm.PackageManager.Property PackageManager * .Property} for an app to inform the system that the application can be opted-in or opted-out * from the compatibility treatment that enables sending a fake focus event for unfocused * resumed split screen activities. This is needed because some game engines wait to get * focus before drawing the content of the app which isn't guaranteed by default in multi-window * modes. * * <p>Device manufacturers can enable this treatment using their discretion on a per-device * basis to improve display compatibility. The treatment also needs to be specifically enabled * on a per-app basis afterwards. This can either be done by device manufacturers or developers. * * <p>With this property set to {@code true}, the system will apply the treatment only if the * device manufacturer had previously enabled it on the device. A fake focus event will be sent * to the app after it is resumed only if the app is in split-screen. * * <p>Setting this property to {@code false} informs the system that the activity must be * opted-out from the compatibility treatment even if the device manufacturer has opted the app * into the treatment. * * <p>If the property remains unset the system will apply the treatment only if it had * previously been enabled both at the device and app level by the device manufacturer. * * <p><b>Syntax:</b> * <pre> * <application> * <property * android:name="android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS" * android:value="true|false"/> * </application> * </pre> * * @hide */ // TODO(b/263984287): Make this public API. String PROPERTY_COMPAT_ENABLE_FAKE_FOCUS = "android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS"; /** * Application level {@link android.content.pm.PackageManager.Property PackageManager * .Property} for an app to inform the system that the app should be excluded from the Loading
services/core/java/com/android/server/wm/ActivityRecord.java +2 −2 Original line number Diff line number Diff line Loading @@ -10214,8 +10214,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // TODO(b/263592337): Explore enabling compat fake focus for fullscreen, e.g. for when // covered with bubbles. boolean shouldSendCompatFakeFocus() { return mWmService.mLetterboxConfiguration.isCompatFakeFocusEnabled(info) && inMultiWindowMode() && !inPinnedWindowingMode() && !inFreeformWindowingMode(); return mLetterboxUiController.shouldSendFakeFocus() && inMultiWindowMode() && !inPinnedWindowingMode() && !inFreeformWindowingMode(); } static class Builder { Loading
services/core/java/com/android/server/wm/LetterboxConfiguration.java +1 −33 Original line number Diff line number Diff line Loading @@ -25,8 +25,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.graphics.Color; import android.provider.DeviceConfig; import android.util.Slog; Loading Loading @@ -1062,38 +1060,8 @@ final class LetterboxConfiguration { "enable_translucent_activity_letterbox", false); } @VisibleForTesting boolean getPackageManagerProperty(PackageManager pm, String property) { boolean enabled = false; try { final PackageManager.Property p = pm.getProperty(property, mContext.getPackageName()); enabled = p.getBoolean(); } catch (PackageManager.NameNotFoundException e) { // Property not found } return enabled; } @VisibleForTesting boolean isCompatFakeFocusEnabled(ActivityInfo info) { if (!isCompatFakeFocusEnabledOnDevice()) { return false; } // See if the developer has chosen to opt in / out of treatment PackageManager pm = mContext.getPackageManager(); if (getPackageManagerProperty(pm, PROPERTY_COMPAT_FAKE_FOCUS_OPT_OUT)) { return false; } else if (getPackageManagerProperty(pm, PROPERTY_COMPAT_FAKE_FOCUS_OPT_IN)) { return true; } if (info.isChangeEnabled(ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS)) { return true; } return false; } /** Whether fake sending focus is enabled for unfocused apps in splitscreen */ boolean isCompatFakeFocusEnabledOnDevice() { boolean isCompatFakeFocusEnabled() { return mIsCompatFakeFocusEnabled && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER, DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, true); Loading
services/core/java/com/android/server/wm/LetterboxUiController.java +34 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE; import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS; import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION; import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR; Loading @@ -41,6 +42,7 @@ import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS; import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM; Loading Loading @@ -149,6 +151,9 @@ final class LetterboxUiController { // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled; // Corresponds to OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS private final boolean mIsOverrideEnableCompatFakeFocusEnabled; @Nullable private final Boolean mBooleanPropertyAllowOrientationOverride; @Nullable Loading Loading @@ -204,6 +209,9 @@ final class LetterboxUiController { @Nullable private final Boolean mBooleanPropertyIgnoreRequestedOrientation; @Nullable private final Boolean mBooleanPropertyFakeFocus; private boolean mIsRelauchingAfterRequestedOrientationChanged; LetterboxUiController(WindowManagerService wmService, ActivityRecord activityRecord) { Loading @@ -218,6 +226,10 @@ final class LetterboxUiController { readComponentProperty(packageManager, mActivityRecord.packageName, mLetterboxConfiguration::isPolicyForIgnoringRequestedOrientationEnabled, PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION); mBooleanPropertyFakeFocus = readComponentProperty(packageManager, mActivityRecord.packageName, mLetterboxConfiguration::isCompatFakeFocusEnabled, PROPERTY_COMPAT_ENABLE_FAKE_FOCUS); mBooleanPropertyCameraCompatAllowForceRotation = readComponentProperty(packageManager, mActivityRecord.packageName, () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled( Loading Loading @@ -265,6 +277,9 @@ final class LetterboxUiController { mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION); mIsOverrideEnableCompatFakeFocusEnabled = isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS); } /** Loading Loading @@ -359,6 +374,25 @@ final class LetterboxUiController { return false; } /** * Whether sending compat fake focus for split screen resumed activities is enabled. Needed * because some game engines wait to get focus before drawing the content of the app which isn't * guaranteed by default in multi-window modes. * * <p>This treatment is enabled when the following conditions are met: * <ul> * <li>Flag gating the treatment is enabled * <li>Component property is NOT set to false * <li>Component property is set to true or per-app override is enabled * </ul> */ boolean shouldSendFakeFocus() { return shouldEnableWithOverrideAndProperty( /* gatingCondition */ mLetterboxConfiguration::isCompatFakeFocusEnabled, mIsOverrideEnableCompatFakeFocusEnabled, mBooleanPropertyFakeFocus); } /** * Sets whether an activity is relaunching after the app has called {@link * android.app.Activity#setRequestedOrientation}. Loading
services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java +4 −4 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ import java.util.function.BiConsumer; * Tests for the {@link LetterboxConfiguration} class. * * Build/Install/Run: * atest WmTests:LetterboxConfigurationTests * atest WmTests:LetterboxConfigurationTest */ @SmallTest @Presubmit Loading Loading @@ -243,18 +243,18 @@ public class LetterboxConfigurationTest { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, "true", false); mLetterboxConfiguration.setIsCompatFakeFocusEnabled(false); assertFalse(mLetterboxConfiguration.isCompatFakeFocusEnabledOnDevice()); assertFalse(mLetterboxConfiguration.isCompatFakeFocusEnabled()); // Set runtime flag to false and build time flag to true DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, "false", false); mLetterboxConfiguration.setIsCompatFakeFocusEnabled(true); assertFalse(mLetterboxConfiguration.isCompatFakeFocusEnabledOnDevice()); assertFalse(mLetterboxConfiguration.isCompatFakeFocusEnabled()); // Set runtime flag to true so that both are enabled DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, "true", false); assertTrue(mLetterboxConfiguration.isCompatFakeFocusEnabledOnDevice()); assertTrue(mLetterboxConfiguration.isCompatFakeFocusEnabled()); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, DEVICE_CONFIG_KEY_ENABLE_COMPAT_FAKE_FOCUS, Boolean.toString(wasFakeFocusEnabled), Loading