• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.views;
17 
18 import static com.android.launcher3.BaseDraggingActivity.INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION;
19 import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET;
20 
21 import android.content.Context;
22 import android.content.Intent;
23 import android.graphics.Rect;
24 import android.graphics.RectF;
25 import android.text.TextUtils;
26 import android.util.ArrayMap;
27 import android.util.AttributeSet;
28 import android.view.MotionEvent;
29 import android.view.View;
30 import android.view.View.OnClickListener;
31 import android.view.View.OnLongClickListener;
32 import android.widget.Toast;
33 
34 import com.android.launcher3.Launcher;
35 import com.android.launcher3.R;
36 import com.android.launcher3.Utilities;
37 import com.android.launcher3.popup.ArrowPopup;
38 import com.android.launcher3.shortcuts.DeepShortcutView;
39 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
40 import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
41 import com.android.launcher3.widget.WidgetsFullSheet;
42 
43 import java.util.ArrayList;
44 import java.util.List;
45 
46 /**
47  * Popup shown on long pressing an empty space in launcher
48  */
49 public class OptionsPopupView extends ArrowPopup
50         implements OnClickListener, OnLongClickListener {
51 
52     private final ArrayMap<View, OptionItem> mItemMap = new ArrayMap<>();
53     private RectF mTargetRect;
54 
OptionsPopupView(Context context, AttributeSet attrs)55     public OptionsPopupView(Context context, AttributeSet attrs) {
56         this(context, attrs, 0);
57     }
58 
OptionsPopupView(Context context, AttributeSet attrs, int defStyleAttr)59     public OptionsPopupView(Context context, AttributeSet attrs, int defStyleAttr) {
60         super(context, attrs, defStyleAttr);
61     }
62 
63     @Override
onClick(View view)64     public void onClick(View view) {
65         handleViewClick(view, Action.Touch.TAP);
66     }
67 
68     @Override
onLongClick(View view)69     public boolean onLongClick(View view) {
70         return handleViewClick(view, Action.Touch.LONGPRESS);
71     }
72 
handleViewClick(View view, int action)73     private boolean handleViewClick(View view, int action) {
74         OptionItem item = mItemMap.get(view);
75         if (item == null) {
76             return false;
77         }
78         if (item.mControlTypeForLog > 0) {
79             logTap(action, item.mControlTypeForLog);
80         }
81         if (item.mClickListener.onLongClick(view)) {
82             close(true);
83             return true;
84         }
85         return false;
86     }
87 
logTap(int action, int controlType)88     private void logTap(int action, int controlType) {
89         mLauncher.getUserEventDispatcher().logActionOnControl(action, controlType);
90     }
91 
92     @Override
onControllerInterceptTouchEvent(MotionEvent ev)93     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
94         if (ev.getAction() != MotionEvent.ACTION_DOWN) {
95             return false;
96         }
97         if (mLauncher.getDragLayer().isEventOverView(this, ev)) {
98             return false;
99         }
100         close(true);
101         return true;
102     }
103 
104     @Override
logActionCommand(int command)105     public void logActionCommand(int command) {
106         // TODO:
107     }
108 
109     @Override
isOfType(int type)110     protected boolean isOfType(int type) {
111         return (type & TYPE_OPTIONS_POPUP) != 0;
112     }
113 
114     @Override
getTargetObjectLocation(Rect outPos)115     protected void getTargetObjectLocation(Rect outPos) {
116         mTargetRect.roundOut(outPos);
117     }
118 
show(Launcher launcher, RectF targetRect, List<OptionItem> items)119     public static void show(Launcher launcher, RectF targetRect, List<OptionItem> items) {
120         OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater()
121                 .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false);
122         popup.mTargetRect = targetRect;
123 
124         for (OptionItem item : items) {
125             DeepShortcutView view = popup.inflateAndAdd(R.layout.system_shortcut, popup);
126             view.getIconView().setBackgroundResource(item.mIconRes);
127             view.getBubbleText().setText(item.mLabelRes);
128             view.setDividerVisibility(View.INVISIBLE);
129             view.setOnClickListener(popup);
130             view.setOnLongClickListener(popup);
131             popup.mItemMap.put(view, item);
132         }
133         popup.reorderAndShow(popup.getChildCount());
134     }
135 
showDefaultOptions(Launcher launcher, float x, float y)136     public static void showDefaultOptions(Launcher launcher, float x, float y) {
137         float halfSize = launcher.getResources().getDimension(R.dimen.options_menu_thumb_size) / 2;
138         if (x < 0 || y < 0) {
139             x = launcher.getDragLayer().getWidth() / 2;
140             y = launcher.getDragLayer().getHeight() / 2;
141         }
142         RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
143 
144         ArrayList<OptionItem> options = new ArrayList<>();
145         options.add(new OptionItem(R.string.wallpaper_button_text, R.drawable.ic_wallpaper,
146                 ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker));
147         options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
148                 ControlType.WIDGETS_BUTTON, OptionsPopupView::onWidgetsClicked));
149         options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting,
150                 ControlType.SETTINGS_BUTTON, OptionsPopupView::startSettings));
151 
152         show(launcher, target, options);
153     }
154 
onWidgetsClicked(View view)155     public static boolean onWidgetsClicked(View view) {
156         Launcher launcher = Launcher.getLauncher(view.getContext());
157         if (launcher.getPackageManager().isSafeMode()) {
158             Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
159             return false;
160         } else {
161             WidgetsFullSheet.show(launcher, true /* animated */);
162             return true;
163         }
164     }
165 
startSettings(View view)166     public static boolean startSettings(View view) {
167         Launcher launcher = Launcher.getLauncher(view.getContext());
168         launcher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
169                 .setPackage(launcher.getPackageName())
170                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
171         return true;
172     }
173 
174     /**
175      * Event handler for the wallpaper picker button that appears after a long press
176      * on the home screen.
177      */
startWallpaperPicker(View v)178     public static boolean startWallpaperPicker(View v) {
179         Launcher launcher = Launcher.getLauncher(v.getContext());
180         if (!Utilities.isWallpaperAllowed(launcher)) {
181             Toast.makeText(launcher, R.string.msg_disabled_by_admin, Toast.LENGTH_SHORT).show();
182             return false;
183         }
184         Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
185                 .putExtra(EXTRA_WALLPAPER_OFFSET,
186                         launcher.getWorkspace().getWallpaperOffsetForCenterPage());
187         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
188 
189         String pickerPackage = launcher.getString(R.string.wallpaper_picker_package);
190         if (!TextUtils.isEmpty(pickerPackage)) {
191             intent.setPackage(pickerPackage);
192         } else {
193             // If there is no target package, use the default intent chooser animation
194             intent.putExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true);
195         }
196         return launcher.startActivitySafely(v, intent, null);
197     }
198 
199     public static class OptionItem {
200 
201         private final int mLabelRes;
202         private final int mIconRes;
203         private final int mControlTypeForLog;
204         private final OnLongClickListener mClickListener;
205 
OptionItem(int labelRes, int iconRes, int controlTypeForLog, OnLongClickListener clickListener)206         public OptionItem(int labelRes, int iconRes, int controlTypeForLog,
207                 OnLongClickListener clickListener) {
208             mLabelRes = labelRes;
209             mIconRes = iconRes;
210             mControlTypeForLog = controlTypeForLog;
211             mClickListener = clickListener;
212         }
213     }
214 }
215