1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.window; 18 19 import android.annotation.Nullable; 20 import android.os.SystemProperties; 21 import android.util.Log; 22 23 import com.android.window.flags.Flags; 24 25 import java.util.function.BooleanSupplier; 26 27 /** 28 * Checks Desktop Experience flag state. 29 * 30 * <p>This enum provides a centralized way to control the behavior of flags related to desktop 31 * experience features which are aiming for developer preview before their release. It allows 32 * developer option to override the default behavior of these flags. 33 * 34 * <p>The flags here will be controlled by the {@code 35 * persist.wm.debug.desktop_experience_devopts} system property. 36 * 37 * <p>NOTE: Flags should only be added to this enum when they have received Product and UX alignment 38 * that the feature is ready for developer preview, otherwise just do a flag check. 39 * 40 * @hide 41 */ 42 public enum DesktopExperienceFlags { 43 // go/keep-sorted start 44 ACTIVITY_EMBEDDING_SUPPORT_FOR_CONNECTED_DISPLAYS( 45 Flags::activityEmbeddingSupportForConnectedDisplays, false), 46 BASE_DENSITY_FOR_EXTERNAL_DISPLAYS( 47 com.android.server.display.feature.flags.Flags::baseDensityForExternalDisplays, true), 48 CONNECTED_DISPLAYS_CURSOR(com.android.input.flags.Flags::connectedDisplaysCursor, true), 49 DISPLAY_TOPOLOGY(com.android.server.display.feature.flags.Flags::displayTopology, true), 50 ENABLE_BUG_FIXES_FOR_SECONDARY_DISPLAY(Flags::enableBugFixesForSecondaryDisplay, true), 51 ENABLE_CONNECTED_DISPLAYS_DND(Flags::enableConnectedDisplaysDnd, false), 52 ENABLE_CONNECTED_DISPLAYS_PIP(Flags::enableConnectedDisplaysPip, false), 53 ENABLE_CONNECTED_DISPLAYS_WALLPAPER( 54 android.app.Flags::enableConnectedDisplaysWallpaper, false), 55 ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG(Flags::enableConnectedDisplaysWindowDrag, true), 56 ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT( 57 com.android.server.display.feature.flags.Flags::enableDisplayContentModeManagement, 58 true), 59 ENABLE_DISPLAY_DISCONNECT_INTERACTION(Flags::enableDisplayDisconnectInteraction, false), 60 ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS(Flags::enableDisplayFocusInShellTransitions, true), 61 ENABLE_DISPLAY_RECONNECT_INTERACTION(Flags::enableDisplayReconnectInteraction, false), 62 ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING(Flags::enableDisplayWindowingModeSwitching, true), 63 ENABLE_DRAG_TO_MAXIMIZE(Flags::enableDragToMaximize, true), 64 ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX(Flags::enableDynamicRadiusComputationBugfix, false), 65 ENABLE_KEYBOARD_SHORTCUTS_TO_SWITCH_DESKS(Flags::keyboardShortcutsToSwitchDesks, false), 66 ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT(Flags::enableMoveToNextDisplayShortcut, true), 67 ENABLE_MULTIDISPLAY_TRACKPAD_BACK_GESTURE(Flags::enableMultidisplayTrackpadBackGesture, false), 68 ENABLE_MULTIPLE_DESKTOPS_BACKEND(Flags::enableMultipleDesktopsBackend, false), 69 ENABLE_MULTIPLE_DESKTOPS_FRONTEND(Flags::enableMultipleDesktopsFrontend, false), 70 ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS( 71 Flags::enablePersistingDisplaySizeForConnectedDisplays, false), 72 ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY(Flags::enablePerDisplayDesktopWallpaperActivity, 73 false), 74 ENABLE_PER_DISPLAY_PACKAGE_CONTEXT_CACHE_IN_STATUSBAR_NOTIF( 75 Flags::enablePerDisplayPackageContextCacheInStatusbarNotif, false), 76 ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE(Flags::enableProjectedDisplayDesktopMode, false), 77 ENABLE_TASKBAR_CONNECTED_DISPLAYS(Flags::enableTaskbarConnectedDisplays, true), 78 ENTER_DESKTOP_BY_DEFAULT_ON_FREEFORM_DISPLAYS(Flags::enterDesktopByDefaultOnFreeformDisplays, 79 true), 80 FORM_FACTOR_BASED_DESKTOP_FIRST_SWITCH(Flags::formFactorBasedDesktopFirstSwitch, false), 81 REPARENT_WINDOW_TOKEN_API(Flags::reparentWindowTokenApi, true) 82 // go/keep-sorted end 83 ; 84 85 /** 86 * Flag class, to be used in case the enum cannot be used because the flag is not accessible. 87 * 88 * <p>This class will still use the process-wide cache. 89 */ 90 public static class DesktopExperienceFlag { 91 // Function called to obtain aconfig flag value. 92 private final BooleanSupplier mFlagFunction; 93 // Whether the flag state should be affected by developer option. 94 private final boolean mShouldOverrideByDevOption; 95 DesktopExperienceFlag(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption)96 public DesktopExperienceFlag(BooleanSupplier flagFunction, 97 boolean shouldOverrideByDevOption) { 98 this.mFlagFunction = flagFunction; 99 this.mShouldOverrideByDevOption = shouldOverrideByDevOption; 100 } 101 102 /** 103 * Determines state of flag based on the actual flag and desktop experience developer option 104 * overrides. 105 */ isTrue()106 public boolean isTrue() { 107 return isFlagTrue(mFlagFunction, mShouldOverrideByDevOption); 108 } 109 } 110 111 private static final String TAG = "DesktopExperienceFlags"; 112 // Function called to obtain aconfig flag value. 113 private final BooleanSupplier mFlagFunction; 114 // Whether the flag state should be affected by developer option. 115 private final boolean mShouldOverrideByDevOption; 116 117 // Local cache for toggle override, which is initialized once on its first access. It needs to 118 // be refreshed only on reboots as overridden state is expected to take effect on reboots. 119 @Nullable 120 private static Boolean sCachedToggleOverride; 121 122 public static final String SYSTEM_PROPERTY_NAME = "persist.wm.debug.desktop_experience_devopts"; 123 DesktopExperienceFlags(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption)124 DesktopExperienceFlags(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption) { 125 this.mFlagFunction = flagFunction; 126 this.mShouldOverrideByDevOption = shouldOverrideByDevOption; 127 } 128 129 /** 130 * Determines state of flag based on the actual flag and desktop experience developer option 131 * overrides. 132 */ isTrue()133 public boolean isTrue() { 134 return isFlagTrue(mFlagFunction, mShouldOverrideByDevOption); 135 } 136 isFlagTrue( BooleanSupplier flagFunction, boolean shouldOverrideByDevOption)137 private static boolean isFlagTrue( 138 BooleanSupplier flagFunction, boolean shouldOverrideByDevOption) { 139 if (shouldOverrideByDevOption 140 && Flags.showDesktopExperienceDevOption() 141 && getToggleOverride()) { 142 return true; 143 } 144 return flagFunction.getAsBoolean(); 145 } 146 getToggleOverride()147 private static boolean getToggleOverride() { 148 // If cached, return it 149 if (sCachedToggleOverride != null) { 150 return sCachedToggleOverride; 151 } 152 153 // Otherwise, fetch and cache it 154 boolean override = getToggleOverrideFromSystem(); 155 sCachedToggleOverride = override; 156 Log.d(TAG, "Toggle override initialized to: " + override); 157 return override; 158 } 159 160 /** Returns the {@link ToggleOverride} from the system property.. */ getToggleOverrideFromSystem()161 private static boolean getToggleOverrideFromSystem() { 162 return SystemProperties.getBoolean(SYSTEM_PROPERTY_NAME, false); 163 } 164 } 165