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 package com.android.wm.shell.shared.split; 17 18 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 19 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 23 24 import android.annotation.IntDef; 25 26 import com.android.wm.shell.shared.TransitionUtil; 27 28 /** Helper utility class of methods and constants that are available to be imported in Launcher. */ 29 public class SplitScreenConstants { 30 /** Duration used for every split fade-in or fade-out. */ 31 public static final int FADE_DURATION = 133; 32 /** Duration where we keep an app veiled to allow it to redraw itself behind the scenes. */ 33 public static final int VEIL_DELAY_DURATION = 300; 34 35 /** Key for passing in widget intents when invoking split from launcher workspace. */ 36 public static final String KEY_EXTRA_WIDGET_INTENT = "key_extra_widget_intent"; 37 38 /////////////// 39 // IMPORTANT for the following SPLIT_POSITION and SNAP_TO constants: 40 // These int values must not be changed -- they are persisted to user-defined app pairs, and 41 // will break things if changed. 42 // 43 44 /** 45 * Split position isn't specified normally meaning to use what ever it is currently set to. 46 */ 47 public static final int SPLIT_POSITION_UNDEFINED = -1; 48 49 /** 50 * Specifies that a split is positioned at the top half of the screen if 51 * in portrait mode or at the left half of the screen if in landscape mode. 52 */ 53 public static final int SPLIT_POSITION_TOP_OR_LEFT = 0; 54 55 /** 56 * Specifies that a split is positioned at the bottom half of the screen if 57 * in portrait mode or at the right half of the screen if in landscape mode. 58 */ 59 public static final int SPLIT_POSITION_BOTTOM_OR_RIGHT = 1; 60 61 /** 62 * Deprecated and will be replaced fully by @SplitIndex. With support for 3+ apps in split, 63 * existing references to top/left and bottom/right will be replaced by INDEX_0 and INDEX_1 64 * respectively. For now they can be used interchangeably, the underlying ints are the same. 65 */ 66 @IntDef(prefix = {"SPLIT_POSITION_"}, value = { 67 SPLIT_POSITION_UNDEFINED, 68 SPLIT_POSITION_TOP_OR_LEFT, 69 SPLIT_POSITION_BOTTOM_OR_RIGHT, 70 }) 71 public @interface SplitPosition { 72 } 73 74 // These SPLIT_INDEX constants will be used in the same way as the above SPLIT_POSITION ints, 75 // but scalable to n apps. Eventually, SPLIT_POSITION can be deprecated and only the below 76 // will be used. 77 public static final int SPLIT_INDEX_UNDEFINED = -1; 78 public static final int SPLIT_INDEX_0 = 0; 79 public static final int SPLIT_INDEX_1 = 1; 80 public static final int SPLIT_INDEX_2 = 2; 81 public static final int SPLIT_INDEX_3 = 3; 82 83 @IntDef(prefix = {"SPLIT_INDEX_"}, value = { 84 SPLIT_INDEX_UNDEFINED, 85 SPLIT_INDEX_0, 86 SPLIT_INDEX_1, 87 SPLIT_INDEX_2, 88 SPLIT_INDEX_3 89 }) 90 public @interface SplitIndex { 91 } 92 93 /** 94 * Return the @SplitIndex constant for a given integer index. @SplitIndex is the replacement 95 * for @SplitPosition, and will be used interchangeably with @SplitPosition to support 3+ apps 96 * in split. 97 */ getIndex(int i)98 public static int getIndex(int i) { 99 return switch (i) { 100 case 0 -> SPLIT_INDEX_0; 101 case 1 -> SPLIT_INDEX_1; 102 case 2 -> SPLIT_INDEX_2; 103 case 3 -> SPLIT_INDEX_3; 104 default -> SPLIT_INDEX_UNDEFINED; 105 }; 106 } 107 108 /** Signifies that user is currently not in split screen. */ 109 public static final int NOT_IN_SPLIT = -1; 110 111 /** 112 * A snap target for two apps, where the split is 33-66. With FLAG_ENABLE_FLEXIBLE_SPLIT, 113 * only used on tablets. 114 */ 115 public static final int SNAP_TO_2_33_66 = 0; 116 117 /** A snap target for two apps, where the split is 50-50. */ 118 public static final int SNAP_TO_2_50_50 = 1; 119 120 /** 121 * A snap target for two apps, where the split is 66-33. With FLAG_ENABLE_FLEXIBLE_SPLIT, 122 * only used on tablets. 123 */ 124 public static final int SNAP_TO_2_66_33 = 2; 125 126 /** 127 * A snap target for two apps, where the split is 90-10. The "10" app extends off the screen, 128 * and is actually the same size as the onscreen app, but the visible portion takes up 10% of 129 * the screen. With FLAG_ENABLE_FLEXIBLE_SPLIT, used on phones and foldables. 130 */ 131 public static final int SNAP_TO_2_90_10 = 3; 132 133 /** 134 * A snap target for two apps, where the split is 10-90. The "10" app extends off the screen, 135 * and is actually the same size as the onscreen app, but the visible portion takes up 10% of 136 * the screen. With FLAG_ENABLE_FLEXIBLE_SPLIT, used on phones and foldables. 137 */ 138 public static final int SNAP_TO_2_10_90 = 4; 139 140 /** 141 * A snap target for three apps, where the split is 33-33-33. With FLAG_ENABLE_FLEXIBLE_SPLIT, 142 * only used on tablets. 143 */ 144 public static final int SNAP_TO_3_33_33_33 = 5; 145 146 /** 147 * A snap target for three apps, where the split is 45-45-10. The "10" app extends off the 148 * screen, and is actually the same size as the onscreen apps, but the visible portion takes 149 * up 10% of the screen. With FLAG_ENABLE_FLEXIBLE_SPLIT, only used on unfolded foldables. 150 */ 151 public static final int SNAP_TO_3_45_45_10 = 6; 152 153 /** 154 * A snap target for three apps, where the split is 10-45-45. The "10" app extends off the 155 * screen, and is actually the same size as the onscreen apps, but the visible portion takes 156 * up 10% of the screen. With FLAG_ENABLE_FLEXIBLE_SPLIT, only used on unfolded foldables. 157 */ 158 public static final int SNAP_TO_3_10_45_45 = 7; 159 160 /** 161 * These snap targets are used for split pairs in a stable, non-transient state. They may be 162 * persisted in Launcher when the user saves an app pair. They are a subset of 163 * {@link SnapPosition}. 164 */ 165 @IntDef(prefix = { "SNAP_TO_" }, value = { 166 SNAP_TO_2_33_66, 167 SNAP_TO_2_50_50, 168 SNAP_TO_2_66_33, 169 SNAP_TO_2_90_10, 170 SNAP_TO_2_10_90, 171 SNAP_TO_3_33_33_33, 172 SNAP_TO_3_45_45_10, 173 SNAP_TO_3_10_45_45, 174 }) 175 public @interface PersistentSnapPosition {} 176 177 /** 178 * These are all the valid "states" that split screen can be in. It's the set of 179 * {@link PersistentSnapPosition} + {@link #NOT_IN_SPLIT}. 180 */ 181 @IntDef(value = { 182 NOT_IN_SPLIT, // user is not in split screen 183 SNAP_TO_NONE, // in "free snap mode," where apps are fully resizable 184 SNAP_TO_2_33_66, 185 SNAP_TO_2_50_50, 186 SNAP_TO_2_66_33, 187 SNAP_TO_2_90_10, 188 SNAP_TO_2_10_90, 189 SNAP_TO_3_33_33_33, 190 SNAP_TO_3_45_45_10, 191 SNAP_TO_3_10_45_45, 192 }) 193 public @interface SplitScreenState {} 194 195 /** Converts a {@link SplitScreenState} to a human-readable string. */ stateToString(@plitScreenState int state)196 public static String stateToString(@SplitScreenState int state) { 197 return switch (state) { 198 case NOT_IN_SPLIT -> "NOT_IN_SPLIT"; 199 case SNAP_TO_NONE -> "SNAP_TO_NONE"; 200 case SNAP_TO_2_33_66 -> "SNAP_TO_2_33_66"; 201 case SNAP_TO_2_50_50 -> "SNAP_TO_2_50_50"; 202 case SNAP_TO_2_66_33 -> "SNAP_TO_2_66_33"; 203 case SNAP_TO_2_90_10 -> "SNAP_TO_2_90_10"; 204 case SNAP_TO_2_10_90 -> "SNAP_TO_2_10_90"; 205 case SNAP_TO_3_33_33_33 -> "SNAP_TO_3_33_33_33"; 206 case SNAP_TO_3_45_45_10 -> "SNAP_TO_3_45_45_10"; 207 case SNAP_TO_3_10_45_45 -> "SNAP_TO_3_10_45_45"; 208 default -> "UNKNOWN"; 209 }; 210 } 211 212 /** 213 * Checks if the snapPosition in question is a {@link PersistentSnapPosition}. 214 */ 215 public static boolean isPersistentSnapPosition(@SnapPosition int snapPosition) { 216 return snapPosition == SNAP_TO_2_33_66 217 || snapPosition == SNAP_TO_2_50_50 218 || snapPosition == SNAP_TO_2_66_33 219 || snapPosition == SNAP_TO_2_90_10 220 || snapPosition == SNAP_TO_2_10_90 221 || snapPosition == SNAP_TO_3_33_33_33 222 || snapPosition == SNAP_TO_3_45_45_10 223 || snapPosition == SNAP_TO_3_10_45_45; 224 } 225 226 /** The divider doesn't snap to any target and is freely placeable. */ 227 public static final int SNAP_TO_NONE = 10; 228 229 /** If the divider reaches this value, the left/top task should be dismissed. */ 230 public static final int SNAP_TO_START_AND_DISMISS = 11; 231 232 /** If the divider reaches this value, the right/bottom task should be dismissed. */ 233 public static final int SNAP_TO_END_AND_DISMISS = 12; 234 235 /** A snap target positioned near the screen edge for a minimized task */ 236 public static final int SNAP_TO_MINIMIZE = 13; 237 238 @IntDef(prefix = { "SNAP_TO_" }, value = { 239 SNAP_TO_2_33_66, 240 SNAP_TO_2_50_50, 241 SNAP_TO_2_66_33, 242 SNAP_TO_2_90_10, 243 SNAP_TO_2_10_90, 244 SNAP_TO_3_33_33_33, 245 SNAP_TO_3_45_45_10, 246 SNAP_TO_3_10_45_45, 247 SNAP_TO_NONE, 248 SNAP_TO_START_AND_DISMISS, 249 SNAP_TO_END_AND_DISMISS, 250 SNAP_TO_MINIMIZE, 251 }) 252 public @interface SnapPosition {} 253 254 /////////////// 255 256 public static final int[] CONTROLLED_ACTIVITY_TYPES = {ACTIVITY_TYPE_STANDARD}; 257 public static final int[] CONTROLLED_WINDOWING_MODES = 258 {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED}; 259 public static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE = 260 {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW, 261 WINDOWING_MODE_FREEFORM}; 262 263 /** Flag applied to a transition change to identify it as a divider bar for animation. */ 264 public static final int FLAG_IS_DIVIDER_BAR = TransitionUtil.FLAG_IS_DIVIDER_BAR; 265 public static final int FLAG_IS_DIM_LAYER = TransitionUtil.FLAG_IS_DIM_LAYER; 266 267 public static final String splitPositionToString(@SplitPosition int pos) { 268 switch (pos) { 269 case SPLIT_POSITION_UNDEFINED: 270 return "SPLIT_POSITION_UNDEFINED"; 271 case SPLIT_POSITION_TOP_OR_LEFT: 272 return "SPLIT_POSITION_TOP_OR_LEFT"; 273 case SPLIT_POSITION_BOTTOM_OR_RIGHT: 274 return "SPLIT_POSITION_BOTTOM_OR_RIGHT"; 275 default: 276 return "UNKNOWN"; 277 } 278 } 279 } 280