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