• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.launcher3.secondarydisplay;
17 
18 import static android.view.View.MeasureSpec.EXACTLY;
19 import static android.view.View.MeasureSpec.makeMeasureSpec;
20 
21 import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
22 import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
23 
24 import android.content.Context;
25 import android.util.AttributeSet;
26 import android.view.MotionEvent;
27 import android.view.View;
28 import android.widget.GridView;
29 
30 import com.android.launcher3.AbstractFloatingView;
31 import com.android.launcher3.BubbleTextView;
32 import com.android.launcher3.DeviceProfile;
33 import com.android.launcher3.DropTarget;
34 import com.android.launcher3.R;
35 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
36 import com.android.launcher3.config.FeatureFlags;
37 import com.android.launcher3.dragndrop.DragOptions;
38 import com.android.launcher3.dragndrop.DragView;
39 import com.android.launcher3.model.data.ItemInfo;
40 import com.android.launcher3.popup.PopupContainerWithArrow;
41 import com.android.launcher3.popup.PopupDataProvider;
42 import com.android.launcher3.popup.SystemShortcut;
43 import com.android.launcher3.util.ShortcutUtil;
44 import com.android.launcher3.util.TouchController;
45 import com.android.launcher3.views.BaseDragLayer;
46 
47 import java.util.ArrayList;
48 import java.util.Collections;
49 import java.util.List;
50 
51 /**
52  * DragLayer for Secondary launcher
53  */
54 public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> {
55 
56     private View mAllAppsButton;
57     private ActivityAllAppsContainerView<SecondaryDisplayLauncher> mAppsView;
58 
59     private GridView mWorkspace;
60     private PinnedAppsAdapter mPinnedAppsAdapter;
61 
SecondaryDragLayer(Context context, AttributeSet attrs)62     public SecondaryDragLayer(Context context, AttributeSet attrs) {
63         super(context, attrs, 1 /* alphaChannelCount */);
64         recreateControllers();
65     }
66 
67     @Override
recreateControllers()68     public void recreateControllers() {
69         mControllers = new TouchController[]{new CloseAllAppsTouchController(),
70                 mActivity.getDragController()};
71     }
72 
73     /**
74      * {@inheritDoc}
75      */
76     @Override
onFinishInflate()77     protected void onFinishInflate() {
78         super.onFinishInflate();
79         mAllAppsButton = findViewById(R.id.all_apps_button);
80 
81         mAppsView = findViewById(R.id.apps_view);
82         // Setup workspace
83         mWorkspace = findViewById(R.id.workspace_grid);
84         mPinnedAppsAdapter = new PinnedAppsAdapter(mActivity, mAppsView.getAppsStore(),
85                 this::onIconLongClicked);
86         mWorkspace.setAdapter(mPinnedAppsAdapter);
87         mWorkspace.setNumColumns(mActivity.getDeviceProfile().inv.numColumns);
88     }
89 
90     /**
91      * {@inheritDoc}
92      */
93     @Override
onAttachedToWindow()94     protected void onAttachedToWindow() {
95         super.onAttachedToWindow();
96         mPinnedAppsAdapter.init();
97     }
98 
99     /**
100      * {@inheritDoc}
101      */
102     @Override
onDetachedFromWindow()103     protected void onDetachedFromWindow() {
104         super.onDetachedFromWindow();
105         mPinnedAppsAdapter.destroy();
106     }
107 
108     /**
109      * {@inheritDoc}
110      */
111     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)112     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
113         int width = MeasureSpec.getSize(widthMeasureSpec);
114         int height = MeasureSpec.getSize(heightMeasureSpec);
115         setMeasuredDimension(width, height);
116 
117         DeviceProfile grid = mActivity.getDeviceProfile();
118         int count = getChildCount();
119         for (int i = 0; i < count; i++) {
120             final View child = getChildAt(i);
121             if (child == mAppsView) {
122                 int horizontalPadding = (2 * grid.desiredWorkspaceHorizontalMarginPx)
123                         + grid.cellLayoutPaddingPx.left + grid.cellLayoutPaddingPx.right;
124                 int verticalPadding =
125                         grid.cellLayoutPaddingPx.top + grid.cellLayoutPaddingPx.bottom;
126 
127                 int maxWidth =
128                         grid.allAppsCellWidthPx * grid.numShownAllAppsColumns + horizontalPadding;
129                 int appsWidth = Math.min(width - getPaddingLeft() - getPaddingRight(), maxWidth);
130 
131                 int maxHeight =
132                         grid.allAppsCellHeightPx * grid.numShownAllAppsColumns + verticalPadding;
133                 int appsHeight = Math.min(height - getPaddingTop() - getPaddingBottom(), maxHeight);
134 
135                 mAppsView.measure(
136                         makeMeasureSpec(appsWidth, EXACTLY), makeMeasureSpec(appsHeight, EXACTLY));
137             } else if (child == mAllAppsButton) {
138                 int appsButtonSpec = makeMeasureSpec(grid.iconSizePx, EXACTLY);
139                 mAllAppsButton.measure(appsButtonSpec, appsButtonSpec);
140             } else if (child == mWorkspace) {
141                 measureChildWithMargins(mWorkspace, widthMeasureSpec, 0, heightMeasureSpec,
142                         grid.iconSizePx + grid.edgeMarginPx);
143             } else {
144                 measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
145             }
146         }
147     }
148 
149     private class CloseAllAppsTouchController implements TouchController {
150 
151         @Override
onControllerTouchEvent(MotionEvent ev)152         public boolean onControllerTouchEvent(MotionEvent ev) {
153             return false;
154         }
155 
156         @Override
onControllerInterceptTouchEvent(MotionEvent ev)157         public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
158             if (!mActivity.isAppDrawerShown()) {
159                 return false;
160             }
161 
162             if (AbstractFloatingView.getTopOpenView(mActivity) != null) {
163                 return false;
164             }
165 
166             if (ev.getAction() == MotionEvent.ACTION_DOWN
167                     && !isEventOverView(mActivity.getAppsView(), ev)) {
168                 mActivity.showAppDrawer(false);
169                 return true;
170             }
171             return false;
172         }
173     }
174 
getPinnedAppsAdapter()175     public PinnedAppsAdapter getPinnedAppsAdapter() {
176         return mPinnedAppsAdapter;
177     }
178 
onIconLongClicked(View v)179     boolean onIconLongClicked(View v) {
180         if (!(v instanceof BubbleTextView)) {
181             return false;
182         }
183         if (PopupContainerWithArrow.getOpen(mActivity) != null) {
184             // There is already an items container open, so don't open this one.
185             v.clearFocus();
186             return false;
187         }
188         ItemInfo item = (ItemInfo) v.getTag();
189         if (!ShortcutUtil.supportsShortcuts(item)) {
190             return false;
191         }
192         PopupDataProvider popupDataProvider = mActivity.getPopupDataProvider();
193         if (popupDataProvider == null) {
194             return false;
195         }
196 
197         // order of this list will reflect in the popup
198         List<SystemShortcut> systemShortcuts = new ArrayList<>();
199         systemShortcuts.add(APP_INFO.getShortcut(mActivity, item, v));
200         // Hide redundant pin shortcut for app drawer icons if drag-n-drop is enabled.
201         if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
202             systemShortcuts.add(mPinnedAppsAdapter.getSystemShortcut(item, v));
203         }
204         int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
205         final PopupContainerWithArrow<SecondaryDisplayLauncher> container;
206         if (ENABLE_MATERIAL_U_POPUP.get()) {
207             container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
208                     R.layout.popup_container_material_u, mActivity.getDragLayer(), false);
209             container.populateAndShowRowsMaterialU((BubbleTextView) v, deepShortcutCount,
210                     systemShortcuts);
211         } else {
212             container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
213                     R.layout.popup_container, mActivity.getDragLayer(), false);
214             container.populateAndShow(
215                     (BubbleTextView) v,
216                     deepShortcutCount,
217                     Collections.emptyList(),
218                     systemShortcuts);
219         }
220         container.requestFocus();
221 
222         if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
223             return true;
224         }
225 
226         DragOptions options = new DragOptions();
227         DeviceProfile grid = mActivity.getDeviceProfile();
228         options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx;
229         options.preDragCondition = container.createPreDragCondition(false);
230         if (options.preDragCondition == null) {
231             options.preDragCondition = new DragOptions.PreDragCondition() {
232                 private DragView<SecondaryDisplayLauncher> mDragView;
233 
234                 @Override
235                 public boolean shouldStartDrag(double distanceDragged) {
236                     return mDragView != null && mDragView.isScaleAnimationFinished();
237                 }
238 
239                 @Override
240                 public void onPreDragStart(DropTarget.DragObject dragObject) {
241                     mDragView = dragObject.dragView;
242                     if (!shouldStartDrag(0)) {
243                         mDragView.setOnScaleAnimEndCallback(() ->
244                                 mActivity.beginDragShared(v, mActivity.getAppsView(), options));
245                     }
246                 }
247 
248                 @Override
249                 public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) {
250                     mDragView = null;
251                 }
252             };
253         }
254         mActivity.beginDragShared(v, mActivity.getAppsView(), options);
255         return true;
256     }
257 }
258