• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
20 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
21 import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
22 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
23 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
24 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
25 
26 import android.content.res.Resources;
27 import android.graphics.PointF;
28 import android.graphics.Rect;
29 import android.graphics.RectF;
30 import android.graphics.drawable.ShapeDrawable;
31 import android.util.FloatProperty;
32 import android.view.MotionEvent;
33 import android.view.Surface;
34 import android.view.VelocityTracker;
35 import android.view.View;
36 import android.view.accessibility.AccessibilityEvent;
37 import android.widget.LinearLayout;
38 
39 import com.android.launcher3.DeviceProfile;
40 import com.android.launcher3.R;
41 import com.android.launcher3.Utilities;
42 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
43 import com.android.launcher3.views.BaseDragLayer;
44 
45 import java.util.ArrayList;
46 import java.util.List;
47 
48 public class PortraitPagedViewHandler implements PagedOrientationHandler {
49 
50     @Override
getPrimaryValue(T x, T y)51     public <T> T getPrimaryValue(T x, T y) {
52         return x;
53     }
54 
55     @Override
getSecondaryValue(T x, T y)56     public <T> T getSecondaryValue(T x, T y) {
57         return y;
58     }
59 
60     @Override
getPrimaryValue(int x, int y)61     public int getPrimaryValue(int x, int y) {
62         return x;
63     }
64 
65     @Override
getSecondaryValue(int x, int y)66     public int getSecondaryValue(int x, int y) {
67         return y;
68     }
69 
70     @Override
getPrimaryValue(float x, float y)71     public float getPrimaryValue(float x, float y) {
72         return x;
73     }
74 
75     @Override
getSecondaryValue(float x, float y)76     public float getSecondaryValue(float x, float y) {
77         return y;
78     }
79 
80     @Override
isLayoutNaturalToLauncher()81     public boolean isLayoutNaturalToLauncher() {
82         return true;
83     }
84 
85     @Override
adjustFloatingIconStartVelocity(PointF velocity)86     public void adjustFloatingIconStartVelocity(PointF velocity) {
87         //no-op
88     }
89 
90     @Override
set(T target, Int2DAction<T> action, int param)91     public <T> void set(T target, Int2DAction<T> action, int param) {
92         action.call(target, param, 0);
93     }
94 
95     @Override
set(T target, Float2DAction<T> action, float param)96     public <T> void set(T target, Float2DAction<T> action, float param) {
97         action.call(target, param, 0);
98     }
99 
100     @Override
setSecondary(T target, Float2DAction<T> action, float param)101     public <T> void setSecondary(T target, Float2DAction<T> action, float param) {
102         action.call(target, 0, param);
103     }
104 
105     @Override
getPrimaryDirection(MotionEvent event, int pointerIndex)106     public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
107         return event.getX(pointerIndex);
108     }
109 
110     @Override
getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId)111     public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
112         return velocityTracker.getXVelocity(pointerId);
113     }
114 
115     @Override
getMeasuredSize(View view)116     public int getMeasuredSize(View view) {
117         return view.getMeasuredWidth();
118     }
119 
120     @Override
getPrimarySize(View view)121     public int getPrimarySize(View view) {
122         return view.getWidth();
123     }
124 
125     @Override
getPrimarySize(RectF rect)126     public float getPrimarySize(RectF rect) {
127         return rect.width();
128     }
129 
130     @Override
getStart(RectF rect)131     public float getStart(RectF rect) {
132         return rect.left;
133     }
134 
135     @Override
getEnd(RectF rect)136     public float getEnd(RectF rect) {
137         return rect.right;
138     }
139 
140     @Override
getClearAllSidePadding(View view, boolean isRtl)141     public int getClearAllSidePadding(View view, boolean isRtl) {
142         return (isRtl ? view.getPaddingRight() : - view.getPaddingLeft()) / 2;
143     }
144 
145     @Override
getSecondaryDimension(View view)146     public int getSecondaryDimension(View view) {
147         return view.getHeight();
148     }
149 
150     @Override
getPrimaryViewTranslate()151     public FloatProperty<View> getPrimaryViewTranslate() {
152         return VIEW_TRANSLATE_X;
153     }
154 
155     @Override
getSecondaryViewTranslate()156     public FloatProperty<View> getSecondaryViewTranslate() {
157         return VIEW_TRANSLATE_Y;
158     }
159 
160     @Override
getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, DeviceProfile dp)161     public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition,
162             DeviceProfile dp) {
163         if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
164             if (dp.isLandscape) {
165                 // Left side
166                 return SPLIT_TRANSLATE_PRIMARY_NEGATIVE;
167             } else {
168                 // Top side
169                 return SPLIT_TRANSLATE_SECONDARY_NEGATIVE;
170             }
171         } else if (splitPosition.mStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
172             // We don't have a bottom option, so should be right
173             return SPLIT_TRANSLATE_PRIMARY_POSITIVE;
174         }
175         throw new IllegalStateException("Invalid split stage position: " +
176                 splitPosition.mStagePosition);
177     }
178 
179     @Override
getPrimaryScroll(View view)180     public int getPrimaryScroll(View view) {
181         return view.getScrollX();
182     }
183 
184     @Override
getPrimaryScale(View view)185     public float getPrimaryScale(View view) {
186         return view.getScaleX();
187     }
188 
189     @Override
setMaxScroll(AccessibilityEvent event, int maxScroll)190     public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
191         event.setMaxScrollX(maxScroll);
192     }
193 
194     @Override
getRecentsRtlSetting(Resources resources)195     public boolean getRecentsRtlSetting(Resources resources) {
196         return !Utilities.isRtl(resources);
197     }
198 
199     @Override
getDegreesRotated()200     public float getDegreesRotated() {
201         return 0;
202     }
203 
204     @Override
getRotation()205     public int getRotation() {
206         return Surface.ROTATION_0;
207     }
208 
209     @Override
getChildStart(View view)210     public int getChildStart(View view) {
211         return view.getLeft();
212     }
213 
214     @Override
getChildStartWithTranslation(View view)215     public float getChildStartWithTranslation(View view) {
216         return view.getLeft() + view.getTranslationX();
217     }
218 
219     @Override
getCenterForPage(View view, Rect insets)220     public int getCenterForPage(View view, Rect insets) {
221         return (view.getPaddingTop() + view.getMeasuredHeight() + insets.top
222             - insets.bottom - view.getPaddingBottom()) / 2;
223     }
224 
225     @Override
getScrollOffsetStart(View view, Rect insets)226     public int getScrollOffsetStart(View view, Rect insets) {
227         return insets.left + view.getPaddingLeft();
228     }
229 
230     @Override
getScrollOffsetEnd(View view, Rect insets)231     public int getScrollOffsetEnd(View view, Rect insets) {
232         return view.getWidth() - view.getPaddingRight() - insets.right;
233     }
234 
235     @Override
getPrimaryTranslationDirectionFactor()236     public int getPrimaryTranslationDirectionFactor() {
237         return 1;
238     }
239 
getSecondaryTranslationDirectionFactor()240     public int getSecondaryTranslationDirectionFactor() {
241         return -1;
242     }
243 
244     @Override
getSplitTranslationDirectionFactor(int stagePosition)245     public int getSplitTranslationDirectionFactor(int stagePosition) {
246         if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
247             return -1;
248         } else {
249             return 1;
250         }
251     }
252 
253     @Override
getSplitAnimationTranslation(int translationOffset, DeviceProfile dp)254     public int getSplitAnimationTranslation(int translationOffset, DeviceProfile dp) {
255         if (dp.isLandscape) {
256             return translationOffset;
257         }
258         return 0;
259     }
260 
261     @Override
getTaskMenuX(float x, View thumbnailView, int overScroll)262     public float getTaskMenuX(float x, View thumbnailView, int overScroll) {
263         return x + overScroll;
264     }
265 
266     @Override
getTaskMenuY(float y, View thumbnailView, int overScroll)267     public float getTaskMenuY(float y, View thumbnailView, int overScroll) {
268         return y;
269     }
270 
271     @Override
getTaskMenuWidth(View view)272     public int getTaskMenuWidth(View view) {
273         return view.getMeasuredWidth();
274     }
275 
276     @Override
setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile, LinearLayout taskMenuLayout, int dividerSpacing, ShapeDrawable dividerDrawable)277     public void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
278             LinearLayout taskMenuLayout, int dividerSpacing,
279             ShapeDrawable dividerDrawable) {
280         if (deviceProfile.isLandscape && !deviceProfile.isTablet) {
281             // Phone landscape
282             taskMenuLayout.setOrientation(LinearLayout.HORIZONTAL);
283             dividerDrawable.setIntrinsicWidth(dividerSpacing);
284         } else {
285             // Phone Portrait, LargeScreen Landscape/Portrait
286             taskMenuLayout.setOrientation(LinearLayout.VERTICAL);
287             dividerDrawable.setIntrinsicHeight(dividerSpacing);
288         }
289         taskMenuLayout.setDividerDrawable(dividerDrawable);
290     }
291 
292     @Override
setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp, LinearLayout viewGroup, DeviceProfile deviceProfile)293     public void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
294             LinearLayout viewGroup, DeviceProfile deviceProfile) {
295         if (deviceProfile.isLandscape && !deviceProfile.isTablet) {
296             // Phone landscape
297             viewGroup.setOrientation(LinearLayout.VERTICAL);
298             lp.width = 0;
299             lp.weight = 1;
300             Utilities.setStartMarginForView(viewGroup.findViewById(R.id.text), 0);
301             Utilities.setStartMarginForView(viewGroup.findViewById(R.id.icon), 0);
302         } else {
303             // Phone Portrait, LargeScreen Landscape/Portrait
304             viewGroup.setOrientation(LinearLayout.HORIZONTAL);
305             lp.width = LinearLayout.LayoutParams.MATCH_PARENT;
306         }
307 
308         lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
309     }
310 
311     @Override
setTaskMenuAroundTaskView(LinearLayout taskView, float margin)312     public void setTaskMenuAroundTaskView(LinearLayout taskView, float margin) {
313         BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskView.getLayoutParams();
314         lp.topMargin += margin;
315         lp.leftMargin += margin;
316     }
317 
318     @Override
getAdditionalInsetForTaskMenu(float margin)319     public PointF getAdditionalInsetForTaskMenu(float margin) {
320         return new PointF(0, 0);
321     }
322 
323     /* ---------- The following are only used by TaskViewTouchHandler. ---------- */
324 
325     @Override
getUpDownSwipeDirection()326     public SingleAxisSwipeDetector.Direction getUpDownSwipeDirection() {
327         return VERTICAL;
328     }
329 
330     @Override
getUpDirection(boolean isRtl)331     public int getUpDirection(boolean isRtl) {
332         // Ignore rtl since it only affects X value displacement, Y displacement doesn't change
333         return SingleAxisSwipeDetector.DIRECTION_POSITIVE;
334     }
335 
336     @Override
isGoingUp(float displacement, boolean isRtl)337     public boolean isGoingUp(float displacement, boolean isRtl) {
338         // Ignore rtl since it only affects X value displacement, Y displacement doesn't change
339         return displacement < 0;
340     }
341 
342     @Override
getTaskDragDisplacementFactor(boolean isRtl)343     public int getTaskDragDisplacementFactor(boolean isRtl) {
344         // Ignore rtl since it only affects X value displacement, Y displacement doesn't change
345         return 1;
346     }
347 
348     /* -------------------- */
349 
350     @Override
getChildBounds(View child, int childStart, int pageCenter, boolean layoutChild)351     public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
352         boolean layoutChild) {
353         final int childWidth = child.getMeasuredWidth();
354         final int childRight = childStart + childWidth;
355         final int childHeight = child.getMeasuredHeight();
356         final int childTop = pageCenter - childHeight / 2;
357         if (layoutChild) {
358             child.layout(childStart, childTop, childRight, childTop + childHeight);
359         }
360         return new ChildBounds(childWidth, childHeight, childRight, childTop);
361     }
362 
363     @Override
getDistanceToBottomOfRect(DeviceProfile dp, Rect rect)364     public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
365         return dp.heightPx - rect.bottom;
366     }
367 
368     @Override
getSplitPositionOptions(DeviceProfile dp)369     public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
370         List<SplitPositionOption> options = new ArrayList<>(1);
371         // Add both left and right options if we're in tablet mode
372         // TODO: Add in correct icons
373         if (dp.isTablet && dp.isLandscape) {
374             options.add(new SplitPositionOption(
375                     R.drawable.ic_split_screen, R.string.split_screen_position_right,
376                     STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
377             options.add(new SplitPositionOption(
378                     R.drawable.ic_split_screen, R.string.split_screen_position_left,
379                     STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
380         } else {
381             if (dp.isSeascape()) {
382                 // Add left/right options
383                 options.add(new SplitPositionOption(
384                         R.drawable.ic_split_screen, R.string.split_screen_position_right,
385                         STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
386             } else if (dp.isLandscape) {
387                 options.add(new SplitPositionOption(
388                         R.drawable.ic_split_screen, R.string.split_screen_position_left,
389                         STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
390             } else {
391                 // Only add top option
392                 options.add(new SplitPositionOption(
393                         R.drawable.ic_split_screen, R.string.split_screen_position_top,
394                         STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
395             }
396         }
397         return options;
398     }
399 
400     @Override
getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary, DeviceProfile dp)401     public FloatProperty getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary,
402             DeviceProfile dp) {
403         if (dp.isLandscape) { // or seascape
404             return primary;
405         } else {
406             return secondary;
407         }
408     }
409 }
410