1 /*
2  * Copyright 2021 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.launcher3.util;
18 
19 import static java.lang.annotation.RetentionPolicy.SOURCE;
20 
21 import android.graphics.Rect;
22 
23 import androidx.annotation.IntDef;
24 
25 import java.lang.annotation.Retention;
26 
27 public final class SplitConfigurationOptions {
28 
29     ///////////////////////////////////
30     // Taken from
31     // frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
32     /**
33      * Stage position isn't specified normally meaning to use what ever it is currently set to.
34      */
35     public static final int STAGE_POSITION_UNDEFINED = -1;
36     /**
37      * Specifies that a stage is positioned at the top half of the screen if
38      * in portrait mode or at the left half of the screen if in landscape mode.
39      */
40     public static final int STAGE_POSITION_TOP_OR_LEFT = 0;
41 
42     /**
43      * Specifies that a stage is positioned at the bottom half of the screen if
44      * in portrait mode or at the right half of the screen if in landscape mode.
45      */
46     public static final int STAGE_POSITION_BOTTOM_OR_RIGHT = 1;
47 
48     @Retention(SOURCE)
49     @IntDef({STAGE_POSITION_UNDEFINED, STAGE_POSITION_TOP_OR_LEFT, STAGE_POSITION_BOTTOM_OR_RIGHT})
50     public @interface StagePosition {}
51 
52     /**
53      * Stage type isn't specified normally meaning to use what ever the default is.
54      * E.g. exit split-screen and launch the app in fullscreen.
55      */
56     public static final int STAGE_TYPE_UNDEFINED = -1;
57     /**
58      * The main stage type.
59      */
60     public static final int STAGE_TYPE_MAIN = 0;
61 
62     /**
63      * The side stage type.
64      */
65     public static final int STAGE_TYPE_SIDE = 1;
66 
67     @IntDef({STAGE_TYPE_UNDEFINED, STAGE_TYPE_MAIN, STAGE_TYPE_SIDE})
68     public @interface StageType {}
69     ///////////////////////////////////
70 
71     /**
72      * Default split ratio for launching app pair from overview.
73      */
74     public static final float DEFAULT_SPLIT_RATIO = 0.5f;
75 
76     public static class SplitPositionOption {
77         public final int iconResId;
78         public final int textResId;
79         @StagePosition
80         public final int stagePosition;
81 
82         @StageType
83         public final int mStageType;
84 
SplitPositionOption(int iconResId, int textResId, int stagePosition, int stageType)85         public SplitPositionOption(int iconResId, int textResId, int stagePosition, int stageType) {
86             this.iconResId = iconResId;
87             this.textResId = textResId;
88             this.stagePosition = stagePosition;
89             mStageType = stageType;
90         }
91     }
92 
93     /**
94      * NOTE: Engineers complained about too little ambiguity in the last survey, so there is a class
95      * with the same name/functionality in wm.shell.util (which launcher3 cannot be built against)
96      *
97      * If you make changes here, consider making the same changes there
98      */
99     public static class StagedSplitBounds {
100         public final Rect leftTopBounds;
101         public final Rect rightBottomBounds;
102         /** This rect represents the actual gap between the two apps */
103         public final Rect visualDividerBounds;
104         // This class is orientation-agnostic, so we compute both for later use
105         public final float topTaskPercent;
106         public final float leftTaskPercent;
107         public final float dividerWidthPercent;
108         public final float dividerHeightPercent;
109         /**
110          * If {@code true}, that means at the time of creation of this object, the
111          * split-screened apps were vertically stacked. This is useful in scenarios like
112          * rotation where the bounds won't change, but this variable can indicate what orientation
113          * the bounds were originally in
114          */
115         public final boolean appsStackedVertically;
116         public final int leftTopTaskId;
117         public final int rightBottomTaskId;
118 
StagedSplitBounds(Rect leftTopBounds, Rect rightBottomBounds, int leftTopTaskId, int rightBottomTaskId)119         public StagedSplitBounds(Rect leftTopBounds, Rect rightBottomBounds, int leftTopTaskId,
120                 int rightBottomTaskId) {
121             this.leftTopBounds = leftTopBounds;
122             this.rightBottomBounds = rightBottomBounds;
123             this.leftTopTaskId = leftTopTaskId;
124             this.rightBottomTaskId = rightBottomTaskId;
125 
126             if (rightBottomBounds.top > leftTopBounds.top) {
127                 // vertical apps, horizontal divider
128                 this.visualDividerBounds = new Rect(leftTopBounds.left, leftTopBounds.bottom,
129                         leftTopBounds.right, rightBottomBounds.top);
130                 appsStackedVertically = true;
131             } else {
132                 // horizontal apps, vertical divider
133                 this.visualDividerBounds = new Rect(leftTopBounds.right, leftTopBounds.top,
134                         rightBottomBounds.left, leftTopBounds.bottom);
135                 appsStackedVertically = false;
136             }
137 
138             leftTaskPercent = this.leftTopBounds.width() / (float) rightBottomBounds.right;
139             topTaskPercent = this.leftTopBounds.height() / (float) rightBottomBounds.bottom;
140             dividerWidthPercent = visualDividerBounds.width() / (float) rightBottomBounds.right;
141             dividerHeightPercent = visualDividerBounds.height() / (float) rightBottomBounds.bottom;
142         }
143     }
144 
145     public static class StagedSplitTaskPosition {
146         public int taskId = -1;
147         @StagePosition
148         public int stagePosition = STAGE_POSITION_UNDEFINED;
149         @StageType
150         public int stageType = STAGE_TYPE_UNDEFINED;
151     }
152 }
153