ShortcutsItemView.java revision ee82b035dbaf0cba73ffd856ddc97d092728dc34
1/* 2 * Copyright (C) 2017 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 17package com.android.launcher3.shortcuts; 18 19import android.animation.Animator; 20import android.animation.AnimatorSet; 21import android.content.Context; 22import android.graphics.Point; 23import android.util.AttributeSet; 24import android.view.MotionEvent; 25import android.view.View; 26import android.widget.LinearLayout; 27 28import com.android.launcher3.AbstractFloatingView; 29import com.android.launcher3.ItemInfo; 30import com.android.launcher3.Launcher; 31import com.android.launcher3.LauncherAnimUtils; 32import com.android.launcher3.R; 33import com.android.launcher3.anim.PropertyListBuilder; 34import com.android.launcher3.dragndrop.DragOptions; 35import com.android.launcher3.dragndrop.DragView; 36import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider; 37import com.android.launcher3.popup.PopupContainerWithArrow; 38import com.android.launcher3.popup.PopupItemView; 39import com.android.launcher3.popup.PopupPopulator; 40import com.android.launcher3.popup.SystemShortcut; 41import com.android.launcher3.userevent.nano.LauncherLogProto; 42 43import java.util.ArrayList; 44import java.util.Collections; 45import java.util.List; 46 47/** 48 * A {@link PopupItemView} that contains all of the {@link DeepShortcutView}s for an app, 49 * as well as the system shortcuts such as Widgets and App Info. 50 */ 51public class ShortcutsItemView extends PopupItemView implements View.OnLongClickListener, 52 View.OnTouchListener, LogContainerProvider { 53 54 private Launcher mLauncher; 55 private LinearLayout mShortcutsLayout; 56 private LinearLayout mSystemShortcutIcons; 57 private final Point mIconShift = new Point(); 58 private final Point mIconLastTouchPos = new Point(); 59 private final List<DeepShortcutView> mDeepShortcutViews = new ArrayList<>(); 60 private final List<View> mSystemShortcutViews = new ArrayList<>(); 61 62 public ShortcutsItemView(Context context) { 63 this(context, null, 0); 64 } 65 66 public ShortcutsItemView(Context context, AttributeSet attrs) { 67 this(context, attrs, 0); 68 } 69 70 public ShortcutsItemView(Context context, AttributeSet attrs, int defStyle) { 71 super(context, attrs, defStyle); 72 73 mLauncher = Launcher.getLauncher(context); 74 } 75 76 @Override 77 protected void onFinishInflate() { 78 super.onFinishInflate(); 79 mShortcutsLayout = findViewById(R.id.deep_shortcuts); 80 } 81 82 @Override 83 public boolean onTouch(View v, MotionEvent ev) { 84 // Touched a shortcut, update where it was touched so we can drag from there on long click. 85 switch (ev.getAction()) { 86 case MotionEvent.ACTION_DOWN: 87 case MotionEvent.ACTION_MOVE: 88 mIconLastTouchPos.set((int) ev.getX(), (int) ev.getY()); 89 break; 90 } 91 return false; 92 } 93 94 @Override 95 public boolean onLongClick(View v) { 96 // Return early if this is not initiated from a touch or not the correct view 97 if (!v.isInTouchMode() || !(v.getParent() instanceof DeepShortcutView)) return false; 98 // Return early if global dragging is not enabled 99 if (!mLauncher.isDraggingEnabled()) return false; 100 // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts) 101 if (mLauncher.getDragController().isDragging()) return false; 102 103 // Long clicked on a shortcut. 104 DeepShortcutView sv = (DeepShortcutView) v.getParent(); 105 sv.setWillDrawIcon(false); 106 107 // Move the icon to align with the center-top of the touch point 108 mIconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x; 109 mIconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx; 110 111 DragView dv = mLauncher.getWorkspace().beginDragShared(sv.getBubbleText(), 112 (PopupContainerWithArrow) getParent(), sv.getFinalInfo(), 113 new ShortcutDragPreviewProvider(sv.getIconView(), mIconShift), new DragOptions()); 114 dv.animateShift(-mIconShift.x, -mIconShift.y); 115 116 // TODO: support dragging from within folder without having to close it 117 AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_FOLDER); 118 return false; 119 } 120 121 public void addShortcutView(View shortcutView, PopupPopulator.Item shortcutType) { 122 if (shortcutType == PopupPopulator.Item.SHORTCUT) { 123 mDeepShortcutViews.add((DeepShortcutView) shortcutView); 124 } else { 125 mSystemShortcutViews.add(shortcutView); 126 } 127 if (shortcutType == PopupPopulator.Item.SYSTEM_SHORTCUT_ICON) { 128 // System shortcut icons are added to a header that is separate from the full shortcuts. 129 if (mSystemShortcutIcons == null) { 130 mSystemShortcutIcons = (LinearLayout) mLauncher.getLayoutInflater().inflate( 131 R.layout.system_shortcut_icons, mShortcutsLayout, false); 132 mShortcutsLayout.addView(mSystemShortcutIcons, 0); 133 } 134 mSystemShortcutIcons.addView(shortcutView); 135 } else { 136 if (mShortcutsLayout.getChildCount() > 0) { 137 View prevChild = mShortcutsLayout.getChildAt(mShortcutsLayout.getChildCount() - 1); 138 if (prevChild instanceof DeepShortcutView) { 139 prevChild.findViewById(R.id.divider).setVisibility(VISIBLE); 140 } 141 } 142 mShortcutsLayout.addView(shortcutView); 143 } 144 } 145 146 public List<DeepShortcutView> getDeepShortcutViews(boolean reverseOrder) { 147 if (reverseOrder) { 148 Collections.reverse(mDeepShortcutViews); 149 } 150 return mDeepShortcutViews; 151 } 152 153 public List<View> getSystemShortcutViews(boolean reverseOrder) { 154 // Always reverse system shortcut icons (in the header) 155 // so they are in priority order from right to left. 156 if (reverseOrder || mSystemShortcutIcons != null) { 157 Collections.reverse(mSystemShortcutViews); 158 } 159 return mSystemShortcutViews; 160 } 161 162 /** 163 * Sets the onClickListener on widgets system shortcut child, and updates alpha to 1. 164 * @return whether widgets is enabled, i.e. the onClickListener is not null. 165 */ 166 public boolean enableWidgets(ItemInfo itemInfo) { 167 for (View systemShortcut : mSystemShortcutViews) { 168 if (systemShortcut.getTag() instanceof SystemShortcut.Widgets) { 169 View.OnClickListener onClickListener = 170 ((SystemShortcut.Widgets) systemShortcut.getTag()).getOnClickListener( 171 mLauncher, itemInfo); 172 if (onClickListener != null) { 173 systemShortcut.setAlpha(1f); 174 systemShortcut.setOnClickListener(onClickListener); 175 return true; 176 } 177 return false; 178 } 179 } 180 return false; 181 } 182 183 @Override 184 public Animator createOpenAnimation(boolean isContainerAboveIcon, boolean pivotLeft) { 185 AnimatorSet openAnimation = LauncherAnimUtils.createAnimatorSet(); 186 openAnimation.play(super.createOpenAnimation(isContainerAboveIcon, pivotLeft)); 187 for (int i = 0; i < mShortcutsLayout.getChildCount(); i++) { 188 if (!(mShortcutsLayout.getChildAt(i) instanceof DeepShortcutView)) { 189 continue; 190 } 191 DeepShortcutView shortcutView = ((DeepShortcutView) mShortcutsLayout.getChildAt(i)); 192 View deepShortcutIcon = shortcutView.getIconView(); 193 deepShortcutIcon.setScaleX(0); 194 deepShortcutIcon.setScaleY(0); 195 openAnimation.play(LauncherAnimUtils.ofPropertyValuesHolder( 196 deepShortcutIcon, new PropertyListBuilder().scale(1).build())); 197 } 198 return openAnimation; 199 } 200 201 @Override 202 public Animator createCloseAnimation(boolean isContainerAboveIcon, boolean pivotLeft, 203 long duration) { 204 AnimatorSet closeAnimation = LauncherAnimUtils.createAnimatorSet(); 205 closeAnimation.play(super.createCloseAnimation(isContainerAboveIcon, pivotLeft, duration)); 206 for (int i = 0; i < mShortcutsLayout.getChildCount(); i++) { 207 if (!(mShortcutsLayout.getChildAt(i) instanceof DeepShortcutView)) { 208 continue; 209 } 210 DeepShortcutView shortcutView = ((DeepShortcutView) mShortcutsLayout.getChildAt(i)); 211 View deepShortcutIcon = shortcutView.getIconView(); 212 deepShortcutIcon.setScaleX(1); 213 deepShortcutIcon.setScaleY(1); 214 closeAnimation.play(LauncherAnimUtils.ofPropertyValuesHolder( 215 deepShortcutIcon, new PropertyListBuilder().scale(0).build())); 216 } 217 return closeAnimation; 218 } 219 220 @Override 221 public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target, 222 LauncherLogProto.Target targetParent) { 223 target.itemType = LauncherLogProto.ItemType.DEEPSHORTCUT; 224 target.rank = info.rank; 225 targetParent.containerType = LauncherLogProto.ContainerType.DEEPSHORTCUTS; 226 } 227} 228