• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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;
18 
19 import android.annotation.SuppressLint;
20 import android.content.Context;
21 import android.content.res.TypedArray;
22 import android.graphics.PointF;
23 import android.graphics.Rect;
24 import android.graphics.drawable.ColorDrawable;
25 import android.graphics.drawable.Drawable;
26 import android.graphics.drawable.InsetDrawable;
27 import android.util.AttributeSet;
28 import android.view.MotionEvent;
29 import android.view.View;
30 import android.view.ViewConfiguration;
31 import android.widget.FrameLayout;
32 
33 import com.android.launcher3.allapps.AllAppsContainerView;
34 import com.android.launcher3.config.FeatureFlags;
35 import com.android.launcher3.util.TransformingTouchDelegate;
36 
37 /**
38  * A base container view, which supports resizing.
39  */
40 public abstract class BaseContainerView extends FrameLayout
41         implements DeviceProfile.LauncherLayoutChangeListener {
42 
43     private static final Rect sBgPaddingRect = new Rect();
44 
45     protected final Drawable mBaseDrawable;
46 
47     private View mRevealView;
48     private View mContent;
49 
50     private TransformingTouchDelegate mTouchDelegate;
51 
52     private final PointF mLastTouchDownPosPx = new PointF(-1.0f, -1.0f);
53 
BaseContainerView(Context context)54     public BaseContainerView(Context context) {
55         this(context, null);
56     }
57 
BaseContainerView(Context context, AttributeSet attrs)58     public BaseContainerView(Context context, AttributeSet attrs) {
59         this(context, attrs, 0);
60     }
61 
BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr)62     public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
63         super(context, attrs, defStyleAttr);
64 
65         if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
66             mBaseDrawable = new ColorDrawable();
67         } else {
68             TypedArray a = context.obtainStyledAttributes(attrs,
69                     R.styleable.BaseContainerView, defStyleAttr, 0);
70             mBaseDrawable = a.getDrawable(R.styleable.BaseContainerView_revealBackground);
71             a.recycle();
72         }
73     }
74 
75     @Override
onAttachedToWindow()76     protected void onAttachedToWindow() {
77         super.onAttachedToWindow();
78 
79         DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
80         grid.addLauncherLayoutChangedListener(this);
81 
82         View touchDelegateTargetView = getTouchDelegateTargetView();
83         if (touchDelegateTargetView != null) {
84             mTouchDelegate = new TransformingTouchDelegate(touchDelegateTargetView);
85             ((View) touchDelegateTargetView.getParent()).setTouchDelegate(mTouchDelegate);
86         }
87     }
88 
89     @Override
onDetachedFromWindow()90     protected void onDetachedFromWindow() {
91         super.onDetachedFromWindow();
92 
93         DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
94         grid.removeLauncherLayoutChangedListener(this);
95     }
96 
97     @Override
onFinishInflate()98     protected void onFinishInflate() {
99         super.onFinishInflate();
100 
101         mContent = findViewById(R.id.main_content);
102         mRevealView = findViewById(R.id.reveal_view);
103 
104         updatePaddings();
105     }
106 
107     @Override
onLauncherLayoutChanged()108     public void onLauncherLayoutChanged() {
109         updatePaddings();
110     }
111 
112     /**
113      * Calculate the background padding as it can change due to insets/content padding change.
114      */
updatePaddings()115     private void updatePaddings() {
116         Context context = getContext();
117         int paddingLeft;
118         int paddingRight;
119         int paddingTop;
120         int paddingBottom;
121 
122         DeviceProfile grid = Launcher.getLauncher(context).getDeviceProfile();
123         int[] padding = grid.getContainerPadding();
124         paddingLeft = padding[0] + grid.edgeMarginPx;
125         paddingRight = padding[1] + grid.edgeMarginPx;
126         if (!grid.isVerticalBarLayout()) {
127             paddingTop = paddingBottom = grid.edgeMarginPx;
128         } else {
129             paddingTop = paddingBottom = 0;
130         }
131         updateBackground(paddingLeft, paddingTop, paddingRight, paddingBottom);
132     }
133 
134     /**
135      * Update the background for the reveal view and content view based on the background padding.
136      */
updateBackground(int paddingLeft, int paddingTop, int paddingRight, int paddingBottom)137     protected void updateBackground(int paddingLeft, int paddingTop,
138             int paddingRight, int paddingBottom) {
139         mRevealView.setBackground(new InsetDrawable(mBaseDrawable,
140                 paddingLeft, paddingTop, paddingRight, paddingBottom));
141         mContent.setBackground(new InsetDrawable(mBaseDrawable,
142                 paddingLeft, paddingTop, paddingRight, paddingBottom));
143     }
144 
145     @Override
onLayout(boolean changed, int left, int top, int right, int bottom)146     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
147         super.onLayout(changed, left, top, right, bottom);
148 
149         View touchDelegateTargetView = getTouchDelegateTargetView();
150         if (touchDelegateTargetView != null) {
151             getRevealView().getBackground().getPadding(sBgPaddingRect);
152             mTouchDelegate.setBounds(
153                     touchDelegateTargetView.getLeft() - sBgPaddingRect.left,
154                     touchDelegateTargetView.getTop() - sBgPaddingRect.top,
155                     touchDelegateTargetView.getRight() + sBgPaddingRect.right,
156                     touchDelegateTargetView.getBottom() + sBgPaddingRect.bottom);
157         }
158     }
159 
160     @Override
onInterceptTouchEvent(MotionEvent ev)161     public boolean onInterceptTouchEvent(MotionEvent ev) {
162         return handleTouchEvent(ev);
163     }
164 
165     @SuppressLint("ClickableViewAccessibility")
166     @Override
onTouchEvent(MotionEvent ev)167     public boolean onTouchEvent(MotionEvent ev) {
168         return handleTouchEvent(ev);
169     }
170 
setRevealDrawableColor(int color)171     public void setRevealDrawableColor(int color) {
172         ((ColorDrawable) mBaseDrawable).setColor(color);
173     }
174 
getContentView()175     public final View getContentView() {
176         return mContent;
177     }
178 
getRevealView()179     public final View getRevealView() {
180         return mRevealView;
181     }
182 
183 
184     /**
185      * Handles the touch events that shows the workspace when clicking outside the bounds of the
186      * touch delegate target view.
187      */
handleTouchEvent(MotionEvent ev)188     private boolean handleTouchEvent(MotionEvent ev) {
189         switch (ev.getAction()) {
190             case MotionEvent.ACTION_DOWN:
191                 // Check if the touch is outside touch delegate target view
192                 View touchDelegateTargetView = getTouchDelegateTargetView();
193                 float leftBoundPx = touchDelegateTargetView.getLeft();
194                 if (ev.getX() < leftBoundPx ||
195                         ev.getX() > (touchDelegateTargetView.getWidth() + leftBoundPx)) {
196                     mLastTouchDownPosPx.set((int) ev.getX(), (int) ev.getY());
197                 }
198                 break;
199             case MotionEvent.ACTION_UP:
200                 if (mLastTouchDownPosPx.x > -1) {
201                     ViewConfiguration viewConfig = ViewConfiguration.get(getContext());
202                     float dx = ev.getX() - mLastTouchDownPosPx.x;
203                     float dy = ev.getY() - mLastTouchDownPosPx.y;
204                     float distance = PointF.length(dx, dy);
205                     if (distance < viewConfig.getScaledTouchSlop()) {
206                         // The background was clicked, so just go home
207                         Launcher.getLauncher(getContext()).showWorkspace(true);
208                         return true;
209                     }
210                 }
211                 // Fall through
212             case MotionEvent.ACTION_CANCEL:
213                 mLastTouchDownPosPx.set(-1, -1);
214                 break;
215         }
216         return false;
217     }
218 
getTouchDelegateTargetView()219     public abstract View getTouchDelegateTargetView();
220 }
221