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