1 /*
2  * Copyright (C) 2020 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.touch;
18 
19 import android.content.res.Resources;
20 import android.graphics.Canvas;
21 import android.graphics.Matrix;
22 import android.graphics.PointF;
23 import android.graphics.Rect;
24 import android.graphics.RectF;
25 import android.graphics.drawable.ShapeDrawable;
26 import android.util.FloatProperty;
27 import android.util.Pair;
28 import android.view.MotionEvent;
29 import android.view.VelocityTracker;
30 import android.view.View;
31 import android.view.accessibility.AccessibilityEvent;
32 import android.widget.FrameLayout;
33 import android.widget.LinearLayout;
34 
35 import com.android.launcher3.DeviceProfile;
36 import com.android.launcher3.util.SplitConfigurationOptions;
37 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
38 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
39 import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
40 
41 import java.util.List;
42 
43 /**
44  * Abstraction layer to separate horizontal and vertical specific implementations
45  * for {@link com.android.launcher3.PagedView}. Majority of these implementations are (should be) as
46  * simple as choosing the correct X and Y analogous methods.
47  */
48 public interface PagedOrientationHandler {
49 
50     int SPLIT_TRANSLATE_PRIMARY_POSITIVE = 0;
51     int SPLIT_TRANSLATE_PRIMARY_NEGATIVE = 1;
52     int SPLIT_TRANSLATE_SECONDARY_NEGATIVE = 2;
53 
54     PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
55     PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
56     PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
57 
58     interface Int2DAction<T> {
call(T target, int x, int y)59         void call(T target, int x, int y);
60     }
61     interface Float2DAction<T> {
call(T target, float x, float y)62         void call(T target, float x, float y);
63     }
64     Int2DAction<View> VIEW_SCROLL_BY = View::scrollBy;
65     Int2DAction<View> VIEW_SCROLL_TO = View::scrollTo;
66     Float2DAction<Canvas> CANVAS_TRANSLATE = Canvas::translate;
67     Float2DAction<Matrix> MATRIX_POST_TRANSLATE = Matrix::postTranslate;
68 
setPrimary(T target, Int2DAction<T> action, int param)69     <T> void setPrimary(T target, Int2DAction<T> action, int param);
setPrimary(T target, Float2DAction<T> action, float param)70     <T> void setPrimary(T target, Float2DAction<T> action, float param);
setSecondary(T target, Float2DAction<T> action, float param)71     <T> void setSecondary(T target, Float2DAction<T> action, float param);
set(T target, Int2DAction<T> action, int primaryParam, int secondaryParam)72     <T> void set(T target, Int2DAction<T> action, int primaryParam, int secondaryParam);
getPrimaryDirection(MotionEvent event, int pointerIndex)73     float getPrimaryDirection(MotionEvent event, int pointerIndex);
getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId)74     float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
getMeasuredSize(View view)75     int getMeasuredSize(View view);
getPrimarySize(View view)76     int getPrimarySize(View view);
getPrimarySize(RectF rect)77     float getPrimarySize(RectF rect);
getStart(RectF rect)78     float getStart(RectF rect);
getEnd(RectF rect)79     float getEnd(RectF rect);
getClearAllSidePadding(View view, boolean isRtl)80     int getClearAllSidePadding(View view, boolean isRtl);
getSecondaryDimension(View view)81     int getSecondaryDimension(View view);
getPrimaryViewTranslate()82     FloatProperty<View> getPrimaryViewTranslate();
getSecondaryViewTranslate()83     FloatProperty<View> getSecondaryViewTranslate();
84 
85     /**
86      * @param stagePosition The position where the view to be split will go
87      * @return {@link #SPLIT_TRANSLATE_*} constants to indicate which direction the
88      * dismissal should happen
89      */
getSplitTaskViewDismissDirection(@tagePosition int stagePosition, DeviceProfile dp)90     int getSplitTaskViewDismissDirection(@StagePosition int stagePosition, DeviceProfile dp);
getPrimaryScroll(View view)91     int getPrimaryScroll(View view);
getPrimaryScale(View view)92     float getPrimaryScale(View view);
getChildStart(View view)93     int getChildStart(View view);
getCenterForPage(View view, Rect insets)94     int getCenterForPage(View view, Rect insets);
getScrollOffsetStart(View view, Rect insets)95     int getScrollOffsetStart(View view, Rect insets);
getScrollOffsetEnd(View view, Rect insets)96     int getScrollOffsetEnd(View view, Rect insets);
getSecondaryTranslationDirectionFactor()97     int getSecondaryTranslationDirectionFactor();
getSplitTranslationDirectionFactor(@tagePosition int stagePosition, DeviceProfile deviceProfile)98     int getSplitTranslationDirectionFactor(@StagePosition int stagePosition,
99             DeviceProfile deviceProfile);
getChildBounds(View child, int childStart, int pageCenter, boolean layoutChild)100     ChildBounds getChildBounds(View child, int childStart, int pageCenter, boolean layoutChild);
setMaxScroll(AccessibilityEvent event, int maxScroll)101     void setMaxScroll(AccessibilityEvent event, int maxScroll);
getRecentsRtlSetting(Resources resources)102     boolean getRecentsRtlSetting(Resources resources);
getDegreesRotated()103     float getDegreesRotated();
getRotation()104     int getRotation();
setPrimaryScale(View view, float scale)105     void setPrimaryScale(View view, float scale);
setSecondaryScale(View view, float scale)106     void setSecondaryScale(View view, float scale);
107 
getPrimaryValue(T x, T y)108     <T> T getPrimaryValue(T x, T y);
getSecondaryValue(T x, T y)109     <T> T getSecondaryValue(T x, T y);
110 
getPrimaryValue(int x, int y)111     int getPrimaryValue(int x, int y);
getSecondaryValue(int x, int y)112     int getSecondaryValue(int x, int y);
113 
getPrimaryValue(float x, float y)114     float getPrimaryValue(float x, float y);
getSecondaryValue(float x, float y)115     float getSecondaryValue(float x, float y);
116 
isLayoutNaturalToLauncher()117     boolean isLayoutNaturalToLauncher();
getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary, DeviceProfile deviceProfile)118     Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
119             FloatProperty secondary, DeviceProfile deviceProfile);
getDistanceToBottomOfRect(DeviceProfile dp, Rect rect)120     int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
getSplitPositionOptions(DeviceProfile dp)121     List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp);
122     /**
123      * @param splitholderSize height of placeholder view in portrait, width in landscape
124      */
getInitialSplitPlaceholderBounds(int splitholderSize, DeviceProfile dp, @StagePosition int stagePosition, Rect out)125     void getInitialSplitPlaceholderBounds(int splitholderSize, DeviceProfile dp,
126             @StagePosition int stagePosition, Rect out);
127 
128     /**
129      * @param splitDividerSize height of split screen drag handle in portrait, width in landscape
130      * @param stagePosition the split position option (top/left, bottom/right) of the first
131      *                           task selected for entering split
132      * @param out1 the bounds for where the first selected app will be
133      * @param out2 the bounds for where the second selected app will be, complimentary to
134      *             {@param out1} based on {@param initialSplitOption}
135      */
getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp, @StagePosition int stagePosition, Rect out1, Rect out2)136     void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp,
137             @StagePosition int stagePosition, Rect out1, Rect out2);
138 
getDefaultSplitPosition(DeviceProfile deviceProfile)139     int getDefaultSplitPosition(DeviceProfile deviceProfile);
140 
141     /**
142      * @param outRect This is expected to be the rect that has the dimensions for a non-split,
143      *                fullscreen task in overview. This will directly be modified.
144      * @param desiredStagePosition Which stage position (topLeft/rightBottom) we want to resize
145      *                           outRect for
146      */
setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, StagedSplitBounds splitInfo, @SplitConfigurationOptions.StagePosition int desiredStagePosition)147     void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, StagedSplitBounds splitInfo,
148             @SplitConfigurationOptions.StagePosition int desiredStagePosition);
149 
measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot, int parentWidth, int parentHeight, StagedSplitBounds splitBoundsConfig, DeviceProfile dp)150     void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
151             int parentWidth, int parentHeight,
152             StagedSplitBounds splitBoundsConfig, DeviceProfile dp);
153 
154     // Overview TaskMenuView methods
setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight, FrameLayout.LayoutParams snapshotParams, boolean isRtl)155     void setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight,
156             FrameLayout.LayoutParams snapshotParams, boolean isRtl);
setSplitIconParams(View primaryIconView, View secondaryIconView, int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight, boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig)157     void setSplitIconParams(View primaryIconView, View secondaryIconView,
158             int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
159             boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig);
160 
161     /*
162      * The following two methods try to center the TaskMenuView in landscape by finding the center
163      * of the thumbnail view and then subtracting half of the taskMenu width. In this case, the
164      * taskMenu width is the same size as the thumbnail width (what got set below in
165      * getTaskMenuWidth()), so we directly use that in the calculations.
166      */
getTaskMenuX(float x, View thumbnailView, int overScroll, DeviceProfile deviceProfile)167     float getTaskMenuX(float x, View thumbnailView, int overScroll, DeviceProfile deviceProfile);
getTaskMenuY(float y, View thumbnailView, int overScroll)168     float getTaskMenuY(float y, View thumbnailView, int overScroll);
getTaskMenuWidth(View view, DeviceProfile deviceProfile)169     int getTaskMenuWidth(View view, DeviceProfile deviceProfile);
170     /**
171      * Sets linear layout orientation for {@link com.android.launcher3.popup.SystemShortcut} items
172      * inside task menu view.
173      */
setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile, LinearLayout taskMenuLayout, int dividerSpacing, ShapeDrawable dividerDrawable)174     void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
175             LinearLayout taskMenuLayout, int dividerSpacing,
176             ShapeDrawable dividerDrawable);
177     /**
178      * Sets layout param attributes for {@link com.android.launcher3.popup.SystemShortcut} child
179      * views inside task menu view.
180      */
setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp, LinearLayout viewGroup, DeviceProfile deviceProfile)181     void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
182             LinearLayout viewGroup, DeviceProfile deviceProfile);
183     /**
184      * Adjusts margins for the entire task menu view itself, which comprises of both app title and
185      * shortcut options.
186      */
setTaskMenuAroundTaskView(LinearLayout taskView, float margin)187     void setTaskMenuAroundTaskView(LinearLayout taskView, float margin);
188     /**
189      * Since the task menu layout is manually positioned on top of recents view, this method returns
190      * additional adjustments to the positioning based on fake land/seascape
191      */
getAdditionalInsetForTaskMenu(float margin)192     PointF getAdditionalInsetForTaskMenu(float margin);
193 
setDwbLayoutParamsAndGetTranslations(int taskViewWidth, int taskViewHeight, StagedSplitBounds splitBounds, DeviceProfile deviceProfile, View[] thumbnailViews, int desiredTaskId, View banner)194     Pair<Float, Float> setDwbLayoutParamsAndGetTranslations(int taskViewWidth,
195             int taskViewHeight, StagedSplitBounds splitBounds, DeviceProfile deviceProfile,
196             View[] thumbnailViews, int desiredTaskId, View banner);
197 
198     // The following are only used by TaskViewTouchHandler.
199     /** @return Either VERTICAL or HORIZONTAL. */
getUpDownSwipeDirection()200     SingleAxisSwipeDetector.Direction getUpDownSwipeDirection();
201     /** @return Given {@link #getUpDownSwipeDirection()}, whether POSITIVE or NEGATIVE is up. */
getUpDirection(boolean isRtl)202     int getUpDirection(boolean isRtl);
203     /** @return Whether the displacement is going towards the top of the screen. */
isGoingUp(float displacement, boolean isRtl)204     boolean isGoingUp(float displacement, boolean isRtl);
205     /** @return Either 1 or -1, a factor to multiply by so the animation goes the correct way. */
getTaskDragDisplacementFactor(boolean isRtl)206     int getTaskDragDisplacementFactor(boolean isRtl);
207 
208     /**
209      * Maps the velocity from the coordinate plane of the foreground app to that
210      * of Launcher's (which now will always be portrait)
211      */
adjustFloatingIconStartVelocity(PointF velocity)212     void adjustFloatingIconStartVelocity(PointF velocity);
213 
214     class ChildBounds {
215 
216         public final int primaryDimension;
217         public final int secondaryDimension;
218         public final int childPrimaryEnd;
219         public final int childSecondaryEnd;
220 
ChildBounds(int primaryDimension, int secondaryDimension, int childPrimaryEnd, int childSecondaryEnd)221         ChildBounds(int primaryDimension, int secondaryDimension, int childPrimaryEnd,
222             int childSecondaryEnd) {
223             this.primaryDimension = primaryDimension;
224             this.secondaryDimension = secondaryDimension;
225             this.childPrimaryEnd = childPrimaryEnd;
226             this.childSecondaryEnd = childSecondaryEnd;
227         }
228     }
229 }
230