1 /* 2 * Copyright (C) 2023 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 com.android.wm.shell.common.split; 18 19 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; 20 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES; 21 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; 22 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; 23 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; 24 25 import android.app.ActivityManager; 26 import android.app.PendingIntent; 27 import android.content.Intent; 28 import android.content.res.Configuration; 29 import android.content.res.Resources; 30 import android.graphics.Color; 31 import android.graphics.Rect; 32 33 import androidx.annotation.Nullable; 34 35 import com.android.internal.util.ArrayUtils; 36 import com.android.wm.shell.Flags; 37 import com.android.wm.shell.ShellTaskOrganizer; 38 39 /** Helper utility class for split screen components to use. */ 40 public class SplitScreenUtils { 41 /** Reverse the split position. */ 42 @SplitScreenConstants.SplitPosition reverseSplitPosition(@plitScreenConstants.SplitPosition int position)43 public static int reverseSplitPosition(@SplitScreenConstants.SplitPosition int position) { 44 switch (position) { 45 case SPLIT_POSITION_TOP_OR_LEFT: 46 return SPLIT_POSITION_BOTTOM_OR_RIGHT; 47 case SPLIT_POSITION_BOTTOM_OR_RIGHT: 48 return SPLIT_POSITION_TOP_OR_LEFT; 49 case SPLIT_POSITION_UNDEFINED: 50 default: 51 return SPLIT_POSITION_UNDEFINED; 52 } 53 } 54 55 /** Returns true if the task is valid for split screen. */ isValidToSplit(ActivityManager.RunningTaskInfo taskInfo)56 public static boolean isValidToSplit(ActivityManager.RunningTaskInfo taskInfo) { 57 return taskInfo != null && taskInfo.supportsMultiWindow 58 && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType()) 59 && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode()); 60 } 61 62 /** Retrieve package name from an intent */ 63 @Nullable getPackageName(Intent intent)64 public static String getPackageName(Intent intent) { 65 if (intent == null || intent.getComponent() == null) { 66 return null; 67 } 68 return intent.getComponent().getPackageName(); 69 } 70 71 /** Retrieve package name from a PendingIntent */ 72 @Nullable getPackageName(PendingIntent pendingIntent)73 public static String getPackageName(PendingIntent pendingIntent) { 74 if (pendingIntent == null || pendingIntent.getIntent() == null) { 75 return null; 76 } 77 return getPackageName(pendingIntent.getIntent()); 78 } 79 80 /** Retrieve package name from a taskId */ 81 @Nullable getPackageName(int taskId, ShellTaskOrganizer taskOrganizer)82 public static String getPackageName(int taskId, ShellTaskOrganizer taskOrganizer) { 83 final ActivityManager.RunningTaskInfo taskInfo = taskOrganizer.getRunningTaskInfo(taskId); 84 return taskInfo != null ? getPackageName(taskInfo.baseIntent) : null; 85 } 86 87 /** Retrieve user id from a taskId */ getUserId(int taskId, ShellTaskOrganizer taskOrganizer)88 public static int getUserId(int taskId, ShellTaskOrganizer taskOrganizer) { 89 final ActivityManager.RunningTaskInfo taskInfo = taskOrganizer.getRunningTaskInfo(taskId); 90 return taskInfo != null ? taskInfo.userId : -1; 91 } 92 93 /** Generates a common log message for split screen failures */ splitFailureMessage(String caller, String reason)94 public static String splitFailureMessage(String caller, String reason) { 95 return "(" + caller + ") Splitscreen aborted: " + reason; 96 } 97 98 /** 99 * Returns whether left/right split is allowed in portrait. 100 */ allowLeftRightSplitInPortrait(Resources res)101 public static boolean allowLeftRightSplitInPortrait(Resources res) { 102 return Flags.enableLeftRightSplitInPortrait() && res.getBoolean( 103 com.android.internal.R.bool.config_leftRightSplitInPortrait); 104 } 105 106 /** 107 * Returns whether left/right split is supported in the given configuration. 108 */ isLeftRightSplit(boolean allowLeftRightSplitInPortrait, Configuration config)109 public static boolean isLeftRightSplit(boolean allowLeftRightSplitInPortrait, 110 Configuration config) { 111 // Compare the max bounds sizes as on near-square devices, the insets may result in a 112 // configuration in the other orientation 113 final boolean isLargeScreen = config.smallestScreenWidthDp >= 600; 114 final Rect maxBounds = config.windowConfiguration.getMaxBounds(); 115 final boolean isLandscape = maxBounds.width() >= maxBounds.height(); 116 return isLeftRightSplit(allowLeftRightSplitInPortrait, isLargeScreen, isLandscape); 117 } 118 119 /** 120 * Returns whether left/right split is supported in the given configuration state. This method 121 * is useful for cases where we need to calculate this given last saved state. 122 */ isLeftRightSplit(boolean allowLeftRightSplitInPortrait, boolean isLargeScreen, boolean isLandscape)123 public static boolean isLeftRightSplit(boolean allowLeftRightSplitInPortrait, 124 boolean isLargeScreen, boolean isLandscape) { 125 if (allowLeftRightSplitInPortrait && isLargeScreen) { 126 return !isLandscape; 127 } else { 128 return isLandscape; 129 } 130 } 131 132 /** Returns the specified background color that matches a RunningTaskInfo. */ getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo)133 public static Color getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) { 134 final int taskBgColor = taskInfo.taskDescription.getBackgroundColor(); 135 return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor); 136 } 137 } 138