• 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         mAppsView.setOnIconLongClickListener(this::onIconLongClicked);
83         mActivity.getSecondaryDisplayPredictions()
84                 .setLongClickListener(mAppsView, this::onIconLongClicked);
85         // Setup workspace
86         mWorkspace = findViewById(R.id.workspace_grid);
87         mPinnedAppsAdapter = new PinnedAppsAdapter(mActivity, mAppsView.getAppsStore(),
88                 this::onIconLongClicked);
89         mWorkspace.setAdapter(mPinnedAppsAdapter);
90         mWorkspace.setNumColumns(mActivity.getDeviceProfile().inv.numColumns);
91     }
92 
93     /**
94      * {@inheritDoc}
95      */
96     @Override
onAttachedToWindow()97     protected void onAttachedToWindow() {
98         super.onAttachedToWindow();
99         mPinnedAppsAdapter.init();
100     }
101 
102     /**
103      * {@inheritDoc}
104      */
105     @Override
onDetachedFromWindow()106     protected void onDetachedFromWindow() {
107         super.onDetachedFromWindow();
108         mPinnedAppsAdapter.destroy();
109     }
110 
111     /**
112      * {@inheritDoc}
113      */
114     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)115     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
116         int width = MeasureSpec.getSize(widthMeasureSpec);
117         int height = MeasureSpec.getSize(heightMeasureSpec);
118         setMeasuredDimension(width, height);
119 
120         DeviceProfile grid = mActivity.getDeviceProfile();
121         int count = getChildCount();
122         for (int i = 0; i < count; i++) {
123             final View child = getChildAt(i);
124             if (child == mAppsView) {
125                 int horizontalPadding = (2 * grid.desiredWorkspaceHorizontalMarginPx)
126                         + grid.cellLayoutPaddingPx.left + grid.cellLayoutPaddingPx.right;
127                 int verticalPadding =
128                         grid.cellLayoutPaddingPx.top + grid.cellLayoutPaddingPx.bottom;
129 
130                 int maxWidth =
131                         grid.allAppsCellWidthPx * grid.numShownAllAppsColumns + horizontalPadding;
132                 int appsWidth = Math.min(width - getPaddingLeft() - getPaddingRight(), maxWidth);
133 
134                 int maxHeight =
135                         grid.allAppsCellHeightPx * grid.numShownAllAppsColumns + verticalPadding;
136                 int appsHeight = Math.min(height - getPaddingTop() - getPaddingBottom(), maxHeight);
137 
138                 mAppsView.measure(
139                         makeMeasureSpec(appsWidth, EXACTLY), makeMeasureSpec(appsHeight, EXACTLY));
140             } else if (child == mAllAppsButton) {
141                 int appsButtonSpec = makeMeasureSpec(grid.iconSizePx, EXACTLY);
142                 mAllAppsButton.measure(appsButtonSpec, appsButtonSpec);
143             } else if (child == mWorkspace) {
144                 measureChildWithMargins(mWorkspace, widthMeasureSpec, 0, heightMeasureSpec,
145                         grid.iconSizePx + grid.edgeMarginPx);
146             } else {
147                 measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
148             }
149         }
150     }
151 
152     private class CloseAllAppsTouchController implements TouchController {
153 
154         @Override
onControllerTouchEvent(MotionEvent ev)155         public boolean onControllerTouchEvent(MotionEvent ev) {
156             return false;
157         }
158 
159         @Override
onControllerInterceptTouchEvent(MotionEvent ev)160         public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
161             if (!mActivity.isAppDrawerShown()) {
162                 return false;
163             }
164 
165             if (AbstractFloatingView.getTopOpenView(mActivity) != null) {
166                 return false;
167             }
168 
169             if (ev.getAction() == MotionEvent.ACTION_DOWN
170                     && !isEventOverView(mActivity.getAppsView(), ev)) {
171                 mActivity.showAppDrawer(false);
172                 return true;
173             }
174             return false;
175         }
176     }
177 
getPinnedAppsAdapter()178     public PinnedAppsAdapter getPinnedAppsAdapter() {
179         return mPinnedAppsAdapter;
180     }
181 
onIconLongClicked(View v)182     private boolean onIconLongClicked(View v) {
183         if (!(v instanceof BubbleTextView)) {
184             return false;
185         }
186         if (PopupContainerWithArrow.getOpen(mActivity) != null) {
187             // There is already an items container open, so don't open this one.
188             v.clearFocus();
189             return false;
190         }
191         ItemInfo item = (ItemInfo) v.getTag();
192         if (!ShortcutUtil.supportsShortcuts(item)) {
193             return false;
194         }
195         PopupDataProvider popupDataProvider = mActivity.getPopupDataProvider();
196         if (popupDataProvider == null) {
197             return false;
198         }
199 
200         // order of this list will reflect in the popup
201         List<SystemShortcut> systemShortcuts = new ArrayList<>();
202         systemShortcuts.add(APP_INFO.getShortcut(mActivity, item, v));
203         // Hide redundant pin shortcut for app drawer icons if drag-n-drop is enabled.
204         if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
205             systemShortcuts.add(mPinnedAppsAdapter.getSystemShortcut(item, v));
206         }
207         int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
208         final PopupContainerWithArrow<SecondaryDisplayLauncher> container;
209         if (ENABLE_MATERIAL_U_POPUP.get()) {
210             container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
211                     R.layout.popup_container_material_u, mActivity.getDragLayer(), false);
212             container.populateAndShowRowsMaterialU((BubbleTextView) v, deepShortcutCount,
213                     systemShortcuts);
214         } else {
215             container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
216                     R.layout.popup_container, mActivity.getDragLayer(), false);
217             container.populateAndShow(
218                     (BubbleTextView) v,
219                     deepShortcutCount,
220                     Collections.emptyList(),
221                     systemShortcuts);
222         }
223         container.requestFocus();
224 
225         if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
226             return true;
227         }
228 
229         DragOptions options = new DragOptions();
230         DeviceProfile grid = mActivity.getDeviceProfile();
231         options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx;
232         options.preDragCondition = container.createPreDragCondition(false);
233         if (options.preDragCondition == null) {
234             options.preDragCondition = new DragOptions.PreDragCondition() {
235                 private DragView<SecondaryDisplayLauncher> mDragView;
236 
237                 @Override
238                 public boolean shouldStartDrag(double distanceDragged) {
239                     return mDragView != null && mDragView.isAnimationFinished();
240                 }
241 
242                 @Override
243                 public void onPreDragStart(DropTarget.DragObject dragObject) {
244                     mDragView = dragObject.dragView;
245                     if (!shouldStartDrag(0)) {
246                         mDragView.setOnAnimationEndCallback(() -> {
247                             mActivity.beginDragShared(v, mActivity.getAppsView(), options);
248                         });
249                     }
250                 }
251 
252                 @Override
253                 public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) {
254                     mDragView = null;
255                 }
256             };
257         }
258         mActivity.beginDragShared(v, mActivity.getAppsView(), options);
259         return true;
260     }
261 }
262