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 55 public OptionsPopupView(Context context, AttributeSet attrs) { 56 this(context, attrs, 0); 57 } 58 59 public OptionsPopupView(Context context, AttributeSet attrs, int defStyleAttr) { 60 super(context, attrs, defStyleAttr); 61 } 62 63 @Override 64 public void onClick(View view) { 65 handleViewClick(view, Action.Touch.TAP); 66 } 67 68 @Override 69 public boolean onLongClick(View view) { 70 return handleViewClick(view, Action.Touch.LONGPRESS); 71 } 72 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 88 private void logTap(int action, int controlType) { 89 mLauncher.getUserEventDispatcher().logActionOnControl(action, controlType); 90 } 91 92 @Override 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 105 public void logActionCommand(int command) { 106 // TODO: 107 } 108 109 @Override 110 protected boolean isOfType(int type) { 111 return (type & TYPE_OPTIONS_POPUP) != 0; 112 } 113 114 @Override 115 protected void getTargetObjectLocation(Rect outPos) { 116 mTargetRect.roundOut(outPos); 117 } 118 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 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 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 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 */ 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 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