The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 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 | |
Sunny Goyal | 2611943 | 2016-02-18 22:09:23 +0000 | [diff] [blame] | 17 | package com.android.launcher3.folder; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 18 | |
Adam Cohen | 2801caf | 2011-05-13 20:57:39 -0700 | [diff] [blame] | 19 | import android.animation.Animator; |
| 20 | import android.animation.AnimatorListenerAdapter; |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 21 | import android.animation.ObjectAnimator; |
Adam Cohen | 2801caf | 2011-05-13 20:57:39 -0700 | [diff] [blame] | 22 | import android.animation.ValueAnimator; |
| 23 | import android.animation.ValueAnimator.AnimatorUpdateListener; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 24 | import android.content.Context; |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 25 | import android.graphics.Canvas; |
Adam Cohen | f4b0891 | 2011-05-17 18:45:47 -0700 | [diff] [blame] | 26 | import android.graphics.Color; |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 27 | import android.graphics.Matrix; |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 28 | import android.graphics.Paint; |
Adam Cohen | 119e898 | 2016-02-05 14:47:50 -0800 | [diff] [blame] | 29 | import android.graphics.Path; |
Tony Wickham | 1237df0 | 2017-02-24 08:59:36 -0800 | [diff] [blame] | 30 | import android.graphics.Point; |
Adam Cohen | badf71e | 2011-05-26 19:08:29 -0700 | [diff] [blame] | 31 | import android.graphics.PorterDuff; |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 32 | import android.graphics.PorterDuffXfermode; |
| 33 | import android.graphics.RadialGradient; |
Adam Cohen | 3e8f811 | 2011-07-02 18:03:00 -0700 | [diff] [blame] | 34 | import android.graphics.Rect; |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 35 | import android.graphics.Region; |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 36 | import android.graphics.Shader; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 37 | import android.graphics.drawable.Drawable; |
Adam Cohen | 099f60d | 2011-08-23 21:07:26 -0700 | [diff] [blame] | 38 | import android.os.Parcelable; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 39 | import android.util.AttributeSet; |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 40 | import android.util.DisplayMetrics; |
Tony Wickham | 1e61849 | 2017-02-02 12:57:18 -0800 | [diff] [blame] | 41 | import android.util.Property; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 42 | import android.view.LayoutInflater; |
Winson Chung | 88f3345 | 2012-02-23 15:23:44 -0800 | [diff] [blame] | 43 | import android.view.MotionEvent; |
Adam Cohen | 7c69321 | 2011-05-18 15:26:57 -0700 | [diff] [blame] | 44 | import android.view.View; |
Jason Monk | 02dd7ae | 2014-04-15 15:23:31 -0400 | [diff] [blame] | 45 | import android.view.ViewConfiguration; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 46 | import android.view.ViewGroup; |
Adam Cohen | 3e8f811 | 2011-07-02 18:03:00 -0700 | [diff] [blame] | 47 | import android.view.animation.AccelerateInterpolator; |
| 48 | import android.view.animation.DecelerateInterpolator; |
Winson Chung | 6e1c0d3 | 2013-10-25 15:24:24 -0700 | [diff] [blame] | 49 | import android.widget.FrameLayout; |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 50 | import android.widget.TextView; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 51 | |
Sunny Goyal | 2611943 | 2016-02-18 22:09:23 +0000 | [diff] [blame] | 52 | import com.android.launcher3.Alarm; |
| 53 | import com.android.launcher3.AppInfo; |
| 54 | import com.android.launcher3.BubbleTextView; |
| 55 | import com.android.launcher3.CellLayout; |
| 56 | import com.android.launcher3.CheckLongPressHelper; |
| 57 | import com.android.launcher3.DeviceProfile; |
Daniel Sandler | 325dc23 | 2013-06-05 22:57:57 -0400 | [diff] [blame] | 58 | import com.android.launcher3.DropTarget.DragObject; |
Sunny Goyal | 2611943 | 2016-02-18 22:09:23 +0000 | [diff] [blame] | 59 | import com.android.launcher3.FastBitmapDrawable; |
| 60 | import com.android.launcher3.FolderInfo; |
Daniel Sandler | 325dc23 | 2013-06-05 22:57:57 -0400 | [diff] [blame] | 61 | import com.android.launcher3.FolderInfo.FolderListener; |
Sunny Goyal | 2611943 | 2016-02-18 22:09:23 +0000 | [diff] [blame] | 62 | import com.android.launcher3.ItemInfo; |
| 63 | import com.android.launcher3.Launcher; |
| 64 | import com.android.launcher3.LauncherAnimUtils; |
Sunny Goyal | 2611943 | 2016-02-18 22:09:23 +0000 | [diff] [blame] | 65 | import com.android.launcher3.LauncherSettings; |
| 66 | import com.android.launcher3.OnAlarmListener; |
Sunny Goyal | 2611943 | 2016-02-18 22:09:23 +0000 | [diff] [blame] | 67 | import com.android.launcher3.R; |
| 68 | import com.android.launcher3.ShortcutInfo; |
| 69 | import com.android.launcher3.SimpleOnStylusPressListener; |
| 70 | import com.android.launcher3.StylusEventHelper; |
| 71 | import com.android.launcher3.Utilities; |
| 72 | import com.android.launcher3.Workspace; |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 73 | import com.android.launcher3.badge.BadgeRenderer; |
| 74 | import com.android.launcher3.badge.FolderBadgeInfo; |
Adam Cohen | 119e898 | 2016-02-05 14:47:50 -0800 | [diff] [blame] | 75 | import com.android.launcher3.config.FeatureFlags; |
Vadim Tryshev | fedca43 | 2015-08-19 17:55:02 -0700 | [diff] [blame] | 76 | import com.android.launcher3.dragndrop.DragLayer; |
| 77 | import com.android.launcher3.dragndrop.DragView; |
Adam Cohen | 091440a | 2015-03-18 14:16:05 -0700 | [diff] [blame] | 78 | import com.android.launcher3.util.Thunk; |
Jon Miranda | c476d6e | 2017-05-04 16:30:01 -0700 | [diff] [blame^] | 79 | import com.android.launcher3.widget.PendingAddShortcutInfo; |
Romain Guy | edcce09 | 2010-03-04 13:03:17 -0800 | [diff] [blame] | 80 | |
Adam Cohen | c0dcf59 | 2011-06-01 15:30:43 -0700 | [diff] [blame] | 81 | import java.util.ArrayList; |
Jon Miranda | 12b616c | 2017-02-06 15:45:53 -0800 | [diff] [blame] | 82 | import java.util.List; |
Adam Cohen | c0dcf59 | 2011-06-01 15:30:43 -0700 | [diff] [blame] | 83 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 84 | /** |
Adam Cohen | f9c184a | 2016-01-15 16:47:43 -0800 | [diff] [blame] | 85 | * An icon that can appear on in the workspace representing an {@link Folder}. |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 86 | */ |
Winson Chung | 6e1c0d3 | 2013-10-25 15:24:24 -0700 | [diff] [blame] | 87 | public class FolderIcon extends FrameLayout implements FolderListener { |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 88 | @Thunk Launcher mLauncher; |
Adam Cohen | 091440a | 2015-03-18 14:16:05 -0700 | [diff] [blame] | 89 | @Thunk Folder mFolder; |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 90 | private FolderInfo mInfo; |
Adam Cohen | 091440a | 2015-03-18 14:16:05 -0700 | [diff] [blame] | 91 | @Thunk static boolean sStaticValuesDirty = true; |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 92 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 93 | public static final int NUM_ITEMS_IN_PREVIEW = FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON ? |
| 94 | StackFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW : |
| 95 | ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW; |
Adam Cohen | f9c184a | 2016-01-15 16:47:43 -0800 | [diff] [blame] | 96 | |
Winson Chung | 88f3345 | 2012-02-23 15:23:44 -0800 | [diff] [blame] | 97 | private CheckLongPressHelper mLongPressHelper; |
Mady Mellor | ef044dd | 2015-06-02 15:35:07 -0700 | [diff] [blame] | 98 | private StylusEventHelper mStylusEventHelper; |
Winson Chung | 88f3345 | 2012-02-23 15:23:44 -0800 | [diff] [blame] | 99 | |
Adam Cohen | badf71e | 2011-05-26 19:08:29 -0700 | [diff] [blame] | 100 | // The number of icons to display in the |
Adam Cohen | f4b0891 | 2011-05-17 18:45:47 -0700 | [diff] [blame] | 101 | private static final int CONSUMPTION_ANIMATION_DURATION = 100; |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 102 | private static final int DROP_IN_ANIMATION_DURATION = 400; |
Adam Cohen | 8dfcba4 | 2011-07-07 16:38:18 -0700 | [diff] [blame] | 103 | private static final int INITIAL_ITEM_ANIMATION_DURATION = 350; |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 104 | private static final int FINAL_ITEM_ANIMATION_DURATION = 200; |
Adam Cohen | badf71e | 2011-05-26 19:08:29 -0700 | [diff] [blame] | 105 | |
Jorim Jaggi | 55bd972 | 2014-01-16 15:30:42 -0800 | [diff] [blame] | 106 | // Flag whether the folder should open itself when an item is dragged over is enabled. |
| 107 | public static final boolean SPRING_LOADING_ENABLED = true; |
| 108 | |
Jorim Jaggi | 55bd972 | 2014-01-16 15:30:42 -0800 | [diff] [blame] | 109 | // Delay when drag enters until the folder opens, in miliseconds. |
| 110 | private static final int ON_OPEN_DELAY = 800; |
| 111 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 112 | @Thunk BubbleTextView mFolderName; |
Adam Cohen | 2801caf | 2011-05-13 20:57:39 -0700 | [diff] [blame] | 113 | |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 114 | // These variables are all associated with the drawing of the preview; they are stored |
| 115 | // as member variables for shared usage and to avoid computation on each frame |
Adam Cohen | aa2542a | 2016-03-21 13:40:02 -0700 | [diff] [blame] | 116 | private int mIntrinsicIconSize = -1; |
| 117 | private int mTotalWidth = -1; |
| 118 | private int mPrevTopPadding = -1; |
| 119 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 120 | PreviewBackground mBackground = new PreviewBackground(); |
Adam Cohen | f9c184a | 2016-01-15 16:47:43 -0800 | [diff] [blame] | 121 | |
| 122 | private PreviewLayoutRule mPreviewLayoutRule; |
| 123 | |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 124 | boolean mAnimating = false; |
Tony Wickham | 1237df0 | 2017-02-24 08:59:36 -0800 | [diff] [blame] | 125 | private Rect mTempBounds = new Rect(); |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 126 | |
Jason Monk | 02dd7ae | 2014-04-15 15:23:31 -0400 | [diff] [blame] | 127 | private float mSlop; |
| 128 | |
Jon Miranda | 655ec42 | 2017-02-07 11:40:22 -0800 | [diff] [blame] | 129 | FolderIconPreviewVerifier mPreviewVerifier; |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 130 | private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0); |
| 131 | private ArrayList<PreviewItemDrawingParams> mDrawingParams = new ArrayList<PreviewItemDrawingParams>(); |
| 132 | private Drawable mReferenceDrawable = null; |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 133 | |
Jorim Jaggi | 55bd972 | 2014-01-16 15:30:42 -0800 | [diff] [blame] | 134 | private Alarm mOpenAlarm = new Alarm(); |
Jorim Jaggi | 55bd972 | 2014-01-16 15:30:42 -0800 | [diff] [blame] | 135 | |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 136 | private FolderBadgeInfo mBadgeInfo = new FolderBadgeInfo(); |
| 137 | private BadgeRenderer mBadgeRenderer; |
Tony Wickham | 1e61849 | 2017-02-02 12:57:18 -0800 | [diff] [blame] | 138 | private float mBadgeScale; |
Tony Wickham | 1237df0 | 2017-02-24 08:59:36 -0800 | [diff] [blame] | 139 | private Point mTempSpaceForBadgeOffset = new Point(); |
Tony Wickham | 1e61849 | 2017-02-02 12:57:18 -0800 | [diff] [blame] | 140 | |
| 141 | private static final Property<FolderIcon, Float> BADGE_SCALE_PROPERTY |
| 142 | = new Property<FolderIcon, Float>(Float.TYPE, "badgeScale") { |
| 143 | @Override |
| 144 | public Float get(FolderIcon folderIcon) { |
| 145 | return folderIcon.mBadgeScale; |
| 146 | } |
| 147 | |
| 148 | @Override |
| 149 | public void set(FolderIcon folderIcon, Float value) { |
| 150 | folderIcon.mBadgeScale = value; |
| 151 | folderIcon.invalidate(); |
| 152 | } |
| 153 | }; |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 154 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 155 | public FolderIcon(Context context, AttributeSet attrs) { |
| 156 | super(context, attrs); |
Winson Chung | 88f3345 | 2012-02-23 15:23:44 -0800 | [diff] [blame] | 157 | init(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | public FolderIcon(Context context) { |
| 161 | super(context); |
Winson Chung | 88f3345 | 2012-02-23 15:23:44 -0800 | [diff] [blame] | 162 | init(); |
| 163 | } |
| 164 | |
| 165 | private void init() { |
| 166 | mLongPressHelper = new CheckLongPressHelper(this); |
Mady Mellor | bb83520 | 2015-07-15 16:34:34 -0700 | [diff] [blame] | 167 | mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 168 | mPreviewLayoutRule = FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON ? |
| 169 | new StackFolderIconLayoutRule() : |
| 170 | new ClippedFolderIconLayoutRule(); |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 171 | mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 172 | } |
| 173 | |
Adam Cohen | f9c184a | 2016-01-15 16:47:43 -0800 | [diff] [blame] | 174 | public static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group, |
Sunny Goyal | 1cd01b0 | 2016-11-09 10:43:58 -0800 | [diff] [blame] | 175 | FolderInfo folderInfo) { |
Michael Jurka | 3a9fced | 2012-04-13 14:44:29 -0700 | [diff] [blame] | 176 | @SuppressWarnings("all") // suppress dead code warning |
| 177 | final boolean error = INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION; |
| 178 | if (error) { |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 179 | throw new IllegalStateException("DROP_IN_ANIMATION_DURATION must be greater than " + |
| 180 | "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " + |
| 181 | "is dependent on this"); |
| 182 | } |
Adam Cohen | 2e6da15 | 2015-05-06 11:42:25 -0700 | [diff] [blame] | 183 | |
| 184 | DeviceProfile grid = launcher.getDeviceProfile(); |
Sunny Goyal | 9b29ca5 | 2017-02-17 10:39:44 -0800 | [diff] [blame] | 185 | FolderIcon icon = (FolderIcon) LayoutInflater.from(group.getContext()) |
| 186 | .inflate(resId, group, false); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 187 | |
Winson Chung | 5f8afe6 | 2013-08-12 16:19:28 -0700 | [diff] [blame] | 188 | icon.setClipToPadding(false); |
Adam Cohen | d2eca6b | 2011-07-26 22:49:13 -0700 | [diff] [blame] | 189 | icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name); |
Adam Cohen | 76fc085 | 2011-06-17 13:26:23 -0700 | [diff] [blame] | 190 | icon.mFolderName.setText(folderInfo.title); |
Winson Chung | 6e1c0d3 | 2013-10-25 15:24:24 -0700 | [diff] [blame] | 191 | icon.mFolderName.setCompoundDrawablePadding(0); |
| 192 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mFolderName.getLayoutParams(); |
| 193 | lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx; |
| 194 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 195 | icon.setTag(folderInfo); |
| 196 | icon.setOnClickListener(launcher); |
| 197 | icon.mInfo = folderInfo; |
| 198 | icon.mLauncher = launcher; |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 199 | icon.mBadgeRenderer = launcher.getDeviceProfile().mBadgeRenderer; |
Sunny Goyal | f4f89ef | 2015-09-02 15:06:12 -0700 | [diff] [blame] | 200 | icon.setContentDescription(launcher.getString(R.string.folder_name_format, folderInfo.title)); |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 201 | Folder folder = Folder.fromXml(launcher); |
| 202 | folder.setDragController(launcher.getDragController()); |
Adam Cohen | 2801caf | 2011-05-13 20:57:39 -0700 | [diff] [blame] | 203 | folder.setFolderIcon(icon); |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 204 | folder.bind(folderInfo); |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 205 | icon.setFolder(folder); |
Sunny Goyal | ae50284 | 2016-06-17 08:43:56 -0700 | [diff] [blame] | 206 | icon.setAccessibilityDelegate(launcher.getAccessibilityDelegate()); |
Sunny Goyal | e48644a | 2016-05-16 16:16:14 -0700 | [diff] [blame] | 207 | |
Sunny Goyal | 90cb3e5 | 2016-05-17 21:25:48 +0000 | [diff] [blame] | 208 | folderInfo.addListener(icon); |
| 209 | |
| 210 | icon.setOnFocusChangeListener(launcher.mFocusHandler); |
Adam Cohen | 19072da | 2011-05-31 14:30:45 -0700 | [diff] [blame] | 211 | return icon; |
| 212 | } |
| 213 | |
Adam Cohen | 099f60d | 2011-08-23 21:07:26 -0700 | [diff] [blame] | 214 | @Override |
| 215 | protected Parcelable onSaveInstanceState() { |
| 216 | sStaticValuesDirty = true; |
| 217 | return super.onSaveInstanceState(); |
| 218 | } |
| 219 | |
Anjali Koppal | f05545f | 2014-03-10 19:18:43 -0700 | [diff] [blame] | 220 | public Folder getFolder() { |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 221 | return mFolder; |
| 222 | } |
| 223 | |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 224 | private void setFolder(Folder folder) { |
| 225 | mFolder = folder; |
Jon Miranda | 655ec42 | 2017-02-07 11:40:22 -0800 | [diff] [blame] | 226 | mPreviewVerifier = new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv); |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 227 | updateItemDrawingParams(false); |
| 228 | } |
| 229 | |
Adam Cohen | 073a46f | 2011-05-17 16:28:09 -0700 | [diff] [blame] | 230 | private boolean willAcceptItem(ItemInfo item) { |
| 231 | final int itemType = item.itemType; |
| 232 | return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || |
Tony Wickham | bfbf7f9 | 2016-05-19 11:19:39 -0700 | [diff] [blame] | 233 | itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT || |
| 234 | itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) && |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 235 | !mFolder.isFull() && item != mInfo && !mFolder.isOpen()); |
Adam Cohen | 073a46f | 2011-05-17 16:28:09 -0700 | [diff] [blame] | 236 | } |
| 237 | |
Sunny Goyal | aa8ef11 | 2015-06-12 20:04:41 -0700 | [diff] [blame] | 238 | public boolean acceptDrop(ItemInfo dragInfo) { |
| 239 | final ItemInfo item = dragInfo; |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 240 | return !mFolder.isDestroyed() && willAcceptItem(item); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 241 | } |
| 242 | |
Adam Cohen | df03538 | 2011-04-11 17:22:04 -0700 | [diff] [blame] | 243 | public void addItem(ShortcutInfo item) { |
Sunny Goyal | c52ba71 | 2016-04-05 15:59:05 -0700 | [diff] [blame] | 244 | mInfo.add(item, true); |
Adam Cohen | df03538 | 2011-04-11 17:22:04 -0700 | [diff] [blame] | 245 | } |
| 246 | |
Sunny Goyal | aa8ef11 | 2015-06-12 20:04:41 -0700 | [diff] [blame] | 247 | public void onDragEnter(ItemInfo dragInfo) { |
| 248 | if (mFolder.isDestroyed() || !willAcceptItem(dragInfo)) return; |
Adam Cohen | 69ce2e5 | 2011-07-03 19:25:21 -0700 | [diff] [blame] | 249 | CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 250 | CellLayout cl = (CellLayout) getParent().getParent(); |
| 251 | |
| 252 | mBackground.animateToAccept(cl, lp.cellX, lp.cellY); |
Jorim Jaggi | 55bd972 | 2014-01-16 15:30:42 -0800 | [diff] [blame] | 253 | mOpenAlarm.setOnAlarmListener(mOnOpenListener); |
Adam Cohen | dedfca2 | 2014-05-19 15:10:39 -0700 | [diff] [blame] | 254 | if (SPRING_LOADING_ENABLED && |
Jon Miranda | c476d6e | 2017-05-04 16:30:01 -0700 | [diff] [blame^] | 255 | ((dragInfo instanceof AppInfo) |
| 256 | || (dragInfo instanceof ShortcutInfo) |
| 257 | || (dragInfo instanceof PendingAddShortcutInfo))) { |
Jorim Jaggi | 55bd972 | 2014-01-16 15:30:42 -0800 | [diff] [blame] | 258 | mOpenAlarm.setAlarm(ON_OPEN_DELAY); |
| 259 | } |
Adam Cohen | 073a46f | 2011-05-17 16:28:09 -0700 | [diff] [blame] | 260 | } |
| 261 | |
Jorim Jaggi | 55bd972 | 2014-01-16 15:30:42 -0800 | [diff] [blame] | 262 | OnAlarmListener mOnOpenListener = new OnAlarmListener() { |
| 263 | public void onAlarm(Alarm alarm) { |
Sunny Goyal | e393d3a | 2016-09-09 12:42:10 -0700 | [diff] [blame] | 264 | mFolder.beginExternalDrag(); |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 265 | mFolder.animateOpen(); |
Jorim Jaggi | 55bd972 | 2014-01-16 15:30:42 -0800 | [diff] [blame] | 266 | } |
| 267 | }; |
| 268 | |
Winson | 8f288aa | 2016-07-25 16:49:15 -0700 | [diff] [blame] | 269 | public Drawable prepareCreate(final View destView) { |
Sunny Goyal | 96ac68a | 2017-02-02 16:37:21 -0800 | [diff] [blame] | 270 | Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1]; |
Winson | 8f288aa | 2016-07-25 16:49:15 -0700 | [diff] [blame] | 271 | computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), |
| 272 | destView.getMeasuredWidth()); |
| 273 | return animateDrawable; |
| 274 | } |
| 275 | |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 276 | public void performCreateAnimation(final ShortcutInfo destInfo, final View destView, |
Winson Chung | 7bd1bbb | 2012-02-13 18:29:29 -0800 | [diff] [blame] | 277 | final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect, |
Adam Cohen | ac8c876 | 2011-07-13 11:15:27 -0700 | [diff] [blame] | 278 | float scaleRelativeToDragLayer, Runnable postAnimationRunnable) { |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 279 | |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 280 | // These correspond two the drawable and view that the icon was dropped _onto_ |
Winson | 8f288aa | 2016-07-25 16:49:15 -0700 | [diff] [blame] | 281 | Drawable animateDrawable = prepareCreate(destView); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 282 | |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 283 | mReferenceDrawable = animateDrawable; |
| 284 | |
| 285 | addItem(destInfo); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 286 | // This will animate the first item from it's position as an icon into its |
| 287 | // position as the first item in the preview |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 288 | animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION, false, null); |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 289 | |
| 290 | // This will animate the dragView (srcView) into the new folder |
Sunny Goyal | e393d3a | 2016-09-09 12:42:10 -0700 | [diff] [blame] | 291 | onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable); |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 292 | } |
| 293 | |
| 294 | public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) { |
Sunny Goyal | 96ac68a | 2017-02-02 16:37:21 -0800 | [diff] [blame] | 295 | Drawable animateDrawable = ((TextView) finalView).getCompoundDrawables()[1]; |
Jason Monk | 02dd7ae | 2014-04-15 15:23:31 -0400 | [diff] [blame] | 296 | computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 297 | finalView.getMeasuredWidth()); |
| 298 | |
| 299 | // This will animate the first item from it's position as an icon into its |
| 300 | // position as the first item in the preview |
| 301 | animateFirstItem(animateDrawable, FINAL_ITEM_ANIMATION_DURATION, true, |
| 302 | onCompleteRunnable); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 303 | } |
| 304 | |
Adam Cohen | c6cc61d | 2012-04-04 12:47:08 -0700 | [diff] [blame] | 305 | public void onDragExit() { |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 306 | mBackground.animateToRest(); |
Jorim Jaggi | 55bd972 | 2014-01-16 15:30:42 -0800 | [diff] [blame] | 307 | mOpenAlarm.cancelAlarm(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 308 | } |
Patrick Dubroy | 440c360 | 2010-07-13 17:50:32 -0700 | [diff] [blame] | 309 | |
Winson Chung | 7bd1bbb | 2012-02-13 18:29:29 -0800 | [diff] [blame] | 310 | private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect, |
Sunny Goyal | e393d3a | 2016-09-09 12:42:10 -0700 | [diff] [blame] | 311 | float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable) { |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 312 | item.cellX = -1; |
| 313 | item.cellY = -1; |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 314 | |
Adam Cohen | 558baaf | 2011-08-15 15:22:57 -0700 | [diff] [blame] | 315 | // Typically, the animateView corresponds to the DragView; however, if this is being done |
| 316 | // after a configuration activity (ie. for a Shortcut being dragged from AllApps) we |
| 317 | // will not have a view to animate |
| 318 | if (animateView != null) { |
| 319 | DragLayer dragLayer = mLauncher.getDragLayer(); |
| 320 | Rect from = new Rect(); |
| 321 | dragLayer.getViewRectRelativeToSelf(animateView, from); |
| 322 | Rect to = finalRect; |
| 323 | if (to == null) { |
| 324 | to = new Rect(); |
| 325 | Workspace workspace = mLauncher.getWorkspace(); |
| 326 | // Set cellLayout and this to it's final state to compute final animation locations |
| 327 | workspace.setFinalTransitionTransform((CellLayout) getParent().getParent()); |
| 328 | float scaleX = getScaleX(); |
| 329 | float scaleY = getScaleY(); |
| 330 | setScaleX(1.0f); |
| 331 | setScaleY(1.0f); |
| 332 | scaleRelativeToDragLayer = dragLayer.getDescendantRectRelativeToSelf(this, to); |
| 333 | // Finished computing final animation locations, restore current state |
| 334 | setScaleX(scaleX); |
| 335 | setScaleY(scaleY); |
| 336 | workspace.resetTransitionTransform((CellLayout) getParent().getParent()); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 337 | } |
Adam Cohen | 558baaf | 2011-08-15 15:22:57 -0700 | [diff] [blame] | 338 | |
| 339 | int[] center = new int[2]; |
Adam Cohen | 119e898 | 2016-02-05 14:47:50 -0800 | [diff] [blame] | 340 | float scale = getLocalCenterForIndex(index, index + 1, center); |
Adam Cohen | 558baaf | 2011-08-15 15:22:57 -0700 | [diff] [blame] | 341 | center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]); |
| 342 | center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]); |
| 343 | |
| 344 | to.offset(center[0] - animateView.getMeasuredWidth() / 2, |
Winson Chung | 5f8afe6 | 2013-08-12 16:19:28 -0700 | [diff] [blame] | 345 | center[1] - animateView.getMeasuredHeight() / 2); |
Adam Cohen | 558baaf | 2011-08-15 15:22:57 -0700 | [diff] [blame] | 346 | |
Jon Miranda | 12b616c | 2017-02-06 15:45:53 -0800 | [diff] [blame] | 347 | float finalAlpha = index < mPreviewLayoutRule.maxNumItems() ? 0.5f : 0f; |
Adam Cohen | 558baaf | 2011-08-15 15:22:57 -0700 | [diff] [blame] | 348 | |
Adam Cohen | ed66b2b | 2012-01-23 17:28:51 -0800 | [diff] [blame] | 349 | float finalScale = scale * scaleRelativeToDragLayer; |
Adam Cohen | 558baaf | 2011-08-15 15:22:57 -0700 | [diff] [blame] | 350 | dragLayer.animateView(animateView, from, to, finalAlpha, |
Adam Cohen | ed66b2b | 2012-01-23 17:28:51 -0800 | [diff] [blame] | 351 | 1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION, |
Adam Cohen | 558baaf | 2011-08-15 15:22:57 -0700 | [diff] [blame] | 352 | new DecelerateInterpolator(2), new AccelerateInterpolator(2), |
Adam Cohen | ed66b2b | 2012-01-23 17:28:51 -0800 | [diff] [blame] | 353 | postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null); |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 354 | addItem(item); |
Adam Cohen | 7a8b82b | 2013-05-29 18:41:50 -0700 | [diff] [blame] | 355 | mFolder.hideItem(item); |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 356 | |
| 357 | final PreviewItemDrawingParams params = index < mDrawingParams.size() ? |
| 358 | mDrawingParams.get(index) : null; |
| 359 | if (params != null) params.hidden = true; |
Adam Cohen | 558baaf | 2011-08-15 15:22:57 -0700 | [diff] [blame] | 360 | postDelayed(new Runnable() { |
| 361 | public void run() { |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 362 | if (params != null) params.hidden = false; |
Adam Cohen | 7a8b82b | 2013-05-29 18:41:50 -0700 | [diff] [blame] | 363 | mFolder.showItem(item); |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 364 | invalidate(); |
Adam Cohen | 558baaf | 2011-08-15 15:22:57 -0700 | [diff] [blame] | 365 | } |
| 366 | }, DROP_IN_ANIMATION_DURATION); |
| 367 | } else { |
| 368 | addItem(item); |
| 369 | } |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 370 | } |
| 371 | |
Adam Cohen | 3e8f811 | 2011-07-02 18:03:00 -0700 | [diff] [blame] | 372 | public void onDrop(DragObject d) { |
Adam Cohen | c0dcf59 | 2011-06-01 15:30:43 -0700 | [diff] [blame] | 373 | ShortcutInfo item; |
Michael Jurka | eadbfc5 | 2013-09-04 00:45:37 +0200 | [diff] [blame] | 374 | if (d.dragInfo instanceof AppInfo) { |
Adam Cohen | c0dcf59 | 2011-06-01 15:30:43 -0700 | [diff] [blame] | 375 | // Came from all apps -- make a copy |
Michael Jurka | eadbfc5 | 2013-09-04 00:45:37 +0200 | [diff] [blame] | 376 | item = ((AppInfo) d.dragInfo).makeShortcut(); |
Adam Cohen | c0dcf59 | 2011-06-01 15:30:43 -0700 | [diff] [blame] | 377 | } else { |
Adam Cohen | 3e8f811 | 2011-07-02 18:03:00 -0700 | [diff] [blame] | 378 | item = (ShortcutInfo) d.dragInfo; |
Adam Cohen | c0dcf59 | 2011-06-01 15:30:43 -0700 | [diff] [blame] | 379 | } |
Adam Cohen | 67bd9cc | 2011-07-29 14:07:04 -0700 | [diff] [blame] | 380 | mFolder.notifyDrop(); |
Sunny Goyal | e393d3a | 2016-09-09 12:42:10 -0700 | [diff] [blame] | 381 | onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable); |
Adam Cohen | c0dcf59 | 2011-06-01 15:30:43 -0700 | [diff] [blame] | 382 | } |
| 383 | |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 384 | private void computePreviewDrawingParams(int drawableSize, int totalSize) { |
Adam Cohen | aa2542a | 2016-03-21 13:40:02 -0700 | [diff] [blame] | 385 | if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize || |
| 386 | mPrevTopPadding != getPaddingTop()) { |
Adam Cohen | 2e6da15 | 2015-05-06 11:42:25 -0700 | [diff] [blame] | 387 | DeviceProfile grid = mLauncher.getDeviceProfile(); |
Winson Chung | 5f8afe6 | 2013-08-12 16:19:28 -0700 | [diff] [blame] | 388 | |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 389 | mIntrinsicIconSize = drawableSize; |
| 390 | mTotalWidth = totalSize; |
Adam Cohen | aa2542a | 2016-03-21 13:40:02 -0700 | [diff] [blame] | 391 | mPrevTopPadding = getPaddingTop(); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 392 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 393 | mBackground.setup(getResources().getDisplayMetrics(), grid, this, mTotalWidth, |
| 394 | getPaddingTop()); |
| 395 | mPreviewLayoutRule.init(mBackground.previewSize, mIntrinsicIconSize, |
Adam Cohen | 119e898 | 2016-02-05 14:47:50 -0800 | [diff] [blame] | 396 | Utilities.isRtl(getResources())); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 397 | |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 398 | updateItemDrawingParams(false); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 399 | } |
| 400 | } |
| 401 | |
| 402 | private void computePreviewDrawingParams(Drawable d) { |
| 403 | computePreviewDrawingParams(d.getIntrinsicWidth(), getMeasuredWidth()); |
| 404 | } |
| 405 | |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 406 | public void setBadgeInfo(FolderBadgeInfo badgeInfo) { |
Tony Wickham | 0530e8c | 2017-04-26 18:13:56 -0700 | [diff] [blame] | 407 | updateBadgeScale(mBadgeInfo.hasBadge(), badgeInfo.hasBadge()); |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 408 | mBadgeInfo = badgeInfo; |
Tony Wickham | 1e61849 | 2017-02-02 12:57:18 -0800 | [diff] [blame] | 409 | } |
| 410 | |
Jon Miranda | 4717011 | 2017-03-03 14:57:14 -0800 | [diff] [blame] | 411 | public PreviewLayoutRule getLayoutRule() { |
| 412 | return mPreviewLayoutRule; |
| 413 | } |
| 414 | |
Tony Wickham | 1e61849 | 2017-02-02 12:57:18 -0800 | [diff] [blame] | 415 | /** |
Tony Wickham | 0530e8c | 2017-04-26 18:13:56 -0700 | [diff] [blame] | 416 | * Sets mBadgeScale to 1 or 0, animating if wasBadged or isBadged is false |
Tony Wickham | 1e61849 | 2017-02-02 12:57:18 -0800 | [diff] [blame] | 417 | * (the badge is being added or removed). |
| 418 | */ |
Tony Wickham | 0530e8c | 2017-04-26 18:13:56 -0700 | [diff] [blame] | 419 | private void updateBadgeScale(boolean wasBadged, boolean isBadged) { |
Tony Wickham | 1e61849 | 2017-02-02 12:57:18 -0800 | [diff] [blame] | 420 | float newBadgeScale = isBadged ? 1f : 0f; |
| 421 | // Animate when a badge is first added or when it is removed. |
| 422 | if ((wasBadged ^ isBadged) && isShown()) { |
| 423 | ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, newBadgeScale).start(); |
| 424 | } else { |
| 425 | mBadgeScale = newBadgeScale; |
| 426 | invalidate(); |
| 427 | } |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 428 | } |
| 429 | |
Sunny Goyal | 2611943 | 2016-02-18 22:09:23 +0000 | [diff] [blame] | 430 | static class PreviewItemDrawingParams { |
| 431 | PreviewItemDrawingParams(float transX, float transY, float scale, float overlayAlpha) { |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 432 | this.transX = transX; |
| 433 | this.transY = transY; |
| 434 | this.scale = scale; |
| 435 | this.overlayAlpha = overlayAlpha; |
| 436 | } |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 437 | |
| 438 | public void update(float transX, float transY, float scale) { |
| 439 | // We ensure the update will not interfere with an animation on the layout params |
| 440 | // If the final values differ, we cancel the animation. |
| 441 | if (anim != null) { |
| 442 | if (anim.finalTransX == transX || anim.finalTransY == transY |
| 443 | || anim.finalScale == scale) { |
| 444 | return; |
| 445 | } |
| 446 | anim.cancel(); |
| 447 | } |
| 448 | |
| 449 | this.transX = transX; |
| 450 | this.transY = transY; |
| 451 | this.scale = scale; |
| 452 | } |
| 453 | |
Sunny Goyal | 2611943 | 2016-02-18 22:09:23 +0000 | [diff] [blame] | 454 | float transX; |
| 455 | float transY; |
| 456 | float scale; |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 457 | public float overlayAlpha; |
| 458 | boolean hidden; |
| 459 | FolderPreviewItemAnim anim; |
Sunny Goyal | 2611943 | 2016-02-18 22:09:23 +0000 | [diff] [blame] | 460 | Drawable drawable; |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 461 | } |
| 462 | |
Adam Cohen | 119e898 | 2016-02-05 14:47:50 -0800 | [diff] [blame] | 463 | private float getLocalCenterForIndex(int index, int curNumItems, int[] center) { |
Jon Miranda | 12b616c | 2017-02-06 15:45:53 -0800 | [diff] [blame] | 464 | mTmpParams = computePreviewItemDrawingParams( |
| 465 | Math.min(mPreviewLayoutRule.maxNumItems(), index), curNumItems, mTmpParams); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 466 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 467 | mTmpParams.transX += mBackground.basePreviewOffsetX; |
| 468 | mTmpParams.transY += mBackground.basePreviewOffsetY; |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 469 | float offsetX = mTmpParams.transX + (mTmpParams.scale * mIntrinsicIconSize) / 2; |
| 470 | float offsetY = mTmpParams.transY + (mTmpParams.scale * mIntrinsicIconSize) / 2; |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 471 | |
Adam Cohen | ac8c876 | 2011-07-13 11:15:27 -0700 | [diff] [blame] | 472 | center[0] = (int) Math.round(offsetX); |
| 473 | center[1] = (int) Math.round(offsetY); |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 474 | return mTmpParams.scale; |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 475 | } |
| 476 | |
Adam Cohen | 119e898 | 2016-02-05 14:47:50 -0800 | [diff] [blame] | 477 | private PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems, |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 478 | PreviewItemDrawingParams params) { |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 479 | // We use an index of -1 to represent an icon on the workspace for the destroy and |
| 480 | // create animations |
| 481 | if (index == -1) { |
| 482 | return getFinalIconParams(params); |
| 483 | } |
Adam Cohen | 119e898 | 2016-02-05 14:47:50 -0800 | [diff] [blame] | 484 | return mPreviewLayoutRule.computePreviewItemDrawingParams(index, curNumItems, params); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 485 | } |
| 486 | |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 487 | private PreviewItemDrawingParams getFinalIconParams(PreviewItemDrawingParams params) { |
| 488 | float iconSize = mLauncher.getDeviceProfile().iconSizePx; |
| 489 | |
| 490 | final float scale = iconSize / mReferenceDrawable.getIntrinsicWidth(); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 491 | final float trans = (mBackground.previewSize - iconSize) / 2; |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 492 | |
| 493 | params.update(trans, trans, scale); |
| 494 | return params; |
| 495 | } |
| 496 | |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 497 | private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) { |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 498 | canvas.save(Canvas.MATRIX_SAVE_FLAG); |
Adam Cohen | 119e898 | 2016-02-05 14:47:50 -0800 | [diff] [blame] | 499 | canvas.translate(params.transX, params.transY); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 500 | canvas.scale(params.scale, params.scale); |
| 501 | Drawable d = params.drawable; |
| 502 | |
| 503 | if (d != null) { |
Tony Wickham | 1237df0 | 2017-02-24 08:59:36 -0800 | [diff] [blame] | 504 | mTempBounds.set(d.getBounds()); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 505 | d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize); |
Sunny Goyal | c5c60ad | 2014-07-14 12:02:01 -0700 | [diff] [blame] | 506 | if (d instanceof FastBitmapDrawable) { |
| 507 | FastBitmapDrawable fd = (FastBitmapDrawable) d; |
Sunny Goyal | 55cb70b | 2016-11-12 09:58:29 -0800 | [diff] [blame] | 508 | fd.drawWithBrightness(canvas, params.overlayAlpha); |
Sunny Goyal | c5c60ad | 2014-07-14 12:02:01 -0700 | [diff] [blame] | 509 | } else { |
Winson | c088049 | 2015-08-21 11:16:27 -0700 | [diff] [blame] | 510 | d.setColorFilter(Color.argb((int) (params.overlayAlpha * 255), 255, 255, 255), |
Sunny Goyal | c5c60ad | 2014-07-14 12:02:01 -0700 | [diff] [blame] | 511 | PorterDuff.Mode.SRC_ATOP); |
| 512 | d.draw(canvas); |
| 513 | d.clearColorFilter(); |
| 514 | } |
Tony Wickham | 1237df0 | 2017-02-24 08:59:36 -0800 | [diff] [blame] | 515 | d.setBounds(mTempBounds); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 516 | } |
| 517 | canvas.restore(); |
| 518 | } |
| 519 | |
Adam Cohen | f172b74 | 2016-03-30 19:28:34 -0700 | [diff] [blame] | 520 | /** |
| 521 | * This object represents a FolderIcon preview background. It stores drawing / measurement |
| 522 | * information, handles drawing, and animation (accept state <--> rest state). |
| 523 | */ |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 524 | public static class PreviewBackground { |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 525 | |
| 526 | private final PorterDuffXfermode mClipPorterDuffXfermode |
| 527 | = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); |
| 528 | // Create a RadialGradient such that it draws a black circle and then extends with |
| 529 | // transparent. To achieve this, we keep the gradient to black for the range [0, 1) and |
| 530 | // just at the edge quickly change it to transparent. |
| 531 | private final RadialGradient mClipShader = new RadialGradient(0, 0, 1, |
| 532 | new int[] {Color.BLACK, Color.BLACK, Color.TRANSPARENT }, |
| 533 | new float[] {0, 0.999f, 1}, |
| 534 | Shader.TileMode.CLAMP); |
| 535 | |
| 536 | private final PorterDuffXfermode mShadowPorterDuffXfermode |
| 537 | = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT); |
| 538 | private RadialGradient mShadowShader = null; |
| 539 | |
| 540 | private final Matrix mShaderMatrix = new Matrix(); |
| 541 | private final Path mPath = new Path(); |
| 542 | |
| 543 | private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); |
| 544 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 545 | private float mScale = 1f; |
| 546 | private float mColorMultiplier = 1f; |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 547 | private float mStrokeWidth; |
Jon Miranda | bdb5424 | 2017-04-06 14:53:52 -0700 | [diff] [blame] | 548 | private int mStrokeAlpha = MAX_BG_OPACITY; |
Adam Cohen | f172b74 | 2016-03-30 19:28:34 -0700 | [diff] [blame] | 549 | private View mInvalidateDelegate; |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 550 | |
| 551 | public int previewSize; |
| 552 | private int basePreviewOffsetX; |
| 553 | private int basePreviewOffsetY; |
| 554 | |
| 555 | private CellLayout mDrawingDelegate; |
| 556 | public int delegateCellX; |
| 557 | public int delegateCellY; |
| 558 | |
Adam Cohen | f172b74 | 2016-03-30 19:28:34 -0700 | [diff] [blame] | 559 | // When the PreviewBackground is drawn under an icon (for creating a folder) the border |
| 560 | // should not occlude the icon |
| 561 | public boolean isClipping = true; |
| 562 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 563 | // Drawing / animation configurations |
| 564 | private static final float ACCEPT_SCALE_FACTOR = 1.25f; |
| 565 | private static final float ACCEPT_COLOR_MULTIPLIER = 1.5f; |
| 566 | |
| 567 | // Expressed on a scale from 0 to 255. |
| 568 | private static final int BG_OPACITY = 160; |
| 569 | private static final int MAX_BG_OPACITY = 225; |
| 570 | private static final int BG_INTENSITY = 245; |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 571 | private static final int SHADOW_OPACITY = 40; |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 572 | |
| 573 | ValueAnimator mScaleAnimator; |
Jon Miranda | bdb5424 | 2017-04-06 14:53:52 -0700 | [diff] [blame] | 574 | ObjectAnimator mStrokeAlphaAnimator; |
| 575 | |
| 576 | private static final Property<PreviewBackground, Integer> STROKE_ALPHA = |
| 577 | new Property<PreviewBackground, Integer>(Integer.class, "strokeAlpha") { |
| 578 | @Override |
| 579 | public Integer get(PreviewBackground previewBackground) { |
| 580 | return previewBackground.mStrokeAlpha; |
| 581 | } |
| 582 | |
| 583 | @Override |
| 584 | public void set(PreviewBackground previewBackground, Integer alpha) { |
| 585 | previewBackground.mStrokeAlpha = alpha; |
| 586 | previewBackground.invalidate(); |
| 587 | } |
| 588 | }; |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 589 | |
Adam Cohen | f172b74 | 2016-03-30 19:28:34 -0700 | [diff] [blame] | 590 | public void setup(DisplayMetrics dm, DeviceProfile grid, View invalidateDelegate, |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 591 | int availableSpace, int topPadding) { |
Adam Cohen | f172b74 | 2016-03-30 19:28:34 -0700 | [diff] [blame] | 592 | mInvalidateDelegate = invalidateDelegate; |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 593 | |
| 594 | final int previewSize = grid.folderIconSizePx; |
| 595 | final int previewPadding = grid.folderIconPreviewPadding; |
| 596 | |
| 597 | this.previewSize = (previewSize - 2 * previewPadding); |
| 598 | |
| 599 | basePreviewOffsetX = (availableSpace - this.previewSize) / 2; |
| 600 | basePreviewOffsetY = previewPadding + grid.folderBackgroundOffset + topPadding; |
| 601 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 602 | // Stroke width is 1dp |
| 603 | mStrokeWidth = dm.density; |
| 604 | |
| 605 | float radius = getScaledRadius(); |
| 606 | float shadowRadius = radius + mStrokeWidth; |
| 607 | int shadowColor = Color.argb(SHADOW_OPACITY, 0, 0, 0); |
| 608 | mShadowShader = new RadialGradient(0, 0, 1, |
| 609 | new int[] {shadowColor, Color.TRANSPARENT}, |
| 610 | new float[] {radius / shadowRadius, 1}, |
| 611 | Shader.TileMode.CLAMP); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 612 | |
| 613 | invalidate(); |
| 614 | } |
| 615 | |
| 616 | int getRadius() { |
| 617 | return previewSize / 2; |
| 618 | } |
| 619 | |
| 620 | int getScaledRadius() { |
| 621 | return (int) (mScale * getRadius()); |
| 622 | } |
| 623 | |
| 624 | int getOffsetX() { |
| 625 | return basePreviewOffsetX - (getScaledRadius() - getRadius()); |
| 626 | } |
| 627 | |
| 628 | int getOffsetY() { |
| 629 | return basePreviewOffsetY - (getScaledRadius() - getRadius()); |
| 630 | } |
| 631 | |
Tony Wickham | 1e61849 | 2017-02-02 12:57:18 -0800 | [diff] [blame] | 632 | /** |
| 633 | * Returns the progress of the scale animation, where 0 means the scale is at 1f |
| 634 | * and 1 means the scale is at ACCEPT_SCALE_FACTOR. |
| 635 | */ |
| 636 | float getScaleProgress() { |
| 637 | return (mScale - 1f) / (ACCEPT_SCALE_FACTOR - 1f); |
| 638 | } |
| 639 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 640 | void invalidate() { |
Adam Cohen | f172b74 | 2016-03-30 19:28:34 -0700 | [diff] [blame] | 641 | if (mInvalidateDelegate != null) { |
| 642 | mInvalidateDelegate.invalidate(); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 643 | } |
| 644 | |
| 645 | if (mDrawingDelegate != null) { |
| 646 | mDrawingDelegate.invalidate(); |
| 647 | } |
| 648 | } |
| 649 | |
Adam Cohen | f172b74 | 2016-03-30 19:28:34 -0700 | [diff] [blame] | 650 | void setInvalidateDelegate(View invalidateDelegate) { |
| 651 | mInvalidateDelegate = invalidateDelegate; |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 652 | invalidate(); |
| 653 | } |
| 654 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 655 | public void drawBackground(Canvas canvas) { |
| 656 | mPaint.setStyle(Paint.Style.FILL); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 657 | int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier); |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 658 | mPaint.setColor(Color.argb(alpha, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY)); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 659 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 660 | drawCircle(canvas, 0 /* deltaRadius */); |
| 661 | |
| 662 | // Draw shadow. |
| 663 | if (mShadowShader == null) { |
| 664 | return; |
| 665 | } |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 666 | float radius = getScaledRadius(); |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 667 | float shadowRadius = radius + mStrokeWidth; |
| 668 | mPaint.setColor(Color.BLACK); |
| 669 | int offsetX = getOffsetX(); |
| 670 | int offsetY = getOffsetY(); |
| 671 | final int saveCount; |
| 672 | if (canvas.isHardwareAccelerated()) { |
| 673 | saveCount = canvas.saveLayer(offsetX - mStrokeWidth, offsetY, |
| 674 | offsetX + radius + shadowRadius, offsetY + shadowRadius + shadowRadius, |
| 675 | null, Canvas.CLIP_TO_LAYER_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 676 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 677 | } else { |
| 678 | saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); |
| 679 | clipCanvasSoftware(canvas, Region.Op.DIFFERENCE); |
| 680 | } |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 681 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 682 | mShaderMatrix.setScale(shadowRadius, shadowRadius); |
| 683 | mShaderMatrix.postTranslate(radius + offsetX, shadowRadius + offsetY); |
| 684 | mShadowShader.setLocalMatrix(mShaderMatrix); |
| 685 | mPaint.setShader(mShadowShader); |
| 686 | canvas.drawPaint(mPaint); |
| 687 | mPaint.setShader(null); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 688 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 689 | if (canvas.isHardwareAccelerated()) { |
| 690 | mPaint.setXfermode(mShadowPorterDuffXfermode); |
| 691 | canvas.drawCircle(radius + offsetX, radius + offsetY, radius, mPaint); |
| 692 | mPaint.setXfermode(null); |
| 693 | } |
| 694 | |
| 695 | canvas.restoreToCount(saveCount); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 696 | } |
| 697 | |
Jon Miranda | bdb5424 | 2017-04-06 14:53:52 -0700 | [diff] [blame] | 698 | public void animateBackgroundStroke() { |
| 699 | if (mStrokeAlphaAnimator != null) { |
| 700 | mStrokeAlphaAnimator.cancel(); |
| 701 | } |
| 702 | mStrokeAlphaAnimator = ObjectAnimator |
| 703 | .ofArgb(this, STROKE_ALPHA, MAX_BG_OPACITY / 2, MAX_BG_OPACITY) |
| 704 | .setDuration(100); |
| 705 | mStrokeAlphaAnimator.addListener(new AnimatorListenerAdapter() { |
| 706 | @Override |
| 707 | public void onAnimationEnd(Animator animation) { |
| 708 | mStrokeAlphaAnimator = null; |
| 709 | } |
| 710 | }); |
| 711 | mStrokeAlphaAnimator.start(); |
| 712 | } |
| 713 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 714 | public void drawBackgroundStroke(Canvas canvas) { |
Jon Miranda | bdb5424 | 2017-04-06 14:53:52 -0700 | [diff] [blame] | 715 | mPaint.setColor(Color.argb(mStrokeAlpha, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY)); |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 716 | mPaint.setStyle(Paint.Style.STROKE); |
| 717 | mPaint.setStrokeWidth(mStrokeWidth); |
| 718 | drawCircle(canvas, 1 /* deltaRadius */); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 719 | } |
| 720 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 721 | public void drawLeaveBehind(Canvas canvas) { |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 722 | float originalScale = mScale; |
| 723 | mScale = 0.5f; |
| 724 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 725 | mPaint.setStyle(Paint.Style.FILL); |
| 726 | mPaint.setColor(Color.argb(160, 245, 245, 245)); |
| 727 | drawCircle(canvas, 0 /* deltaRadius */); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 728 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 729 | mScale = originalScale; |
| 730 | } |
| 731 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 732 | private void drawCircle(Canvas canvas,float deltaRadius) { |
| 733 | float radius = getScaledRadius(); |
| 734 | canvas.drawCircle(radius + getOffsetX(), radius + getOffsetY(), |
| 735 | radius - deltaRadius, mPaint); |
| 736 | } |
| 737 | |
| 738 | // It is the callers responsibility to save and restore the canvas layers. |
| 739 | private void clipCanvasSoftware(Canvas canvas, Region.Op op) { |
| 740 | mPath.reset(); |
| 741 | float r = getScaledRadius(); |
| 742 | mPath.addCircle(r + getOffsetX(), r + getOffsetY(), r, Path.Direction.CW); |
| 743 | canvas.clipPath(mPath, op); |
| 744 | } |
| 745 | |
| 746 | // It is the callers responsibility to save and restore the canvas layers. |
| 747 | private void clipCanvasHardware(Canvas canvas) { |
| 748 | mPaint.setColor(Color.BLACK); |
| 749 | mPaint.setXfermode(mClipPorterDuffXfermode); |
| 750 | |
| 751 | float radius = getScaledRadius(); |
| 752 | mShaderMatrix.setScale(radius, radius); |
| 753 | mShaderMatrix.postTranslate(radius + getOffsetX(), radius + getOffsetY()); |
| 754 | mClipShader.setLocalMatrix(mShaderMatrix); |
| 755 | mPaint.setShader(mClipShader); |
| 756 | canvas.drawPaint(mPaint); |
| 757 | mPaint.setXfermode(null); |
| 758 | mPaint.setShader(null); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 759 | } |
| 760 | |
| 761 | private void delegateDrawing(CellLayout delegate, int cellX, int cellY) { |
| 762 | if (mDrawingDelegate != delegate) { |
| 763 | delegate.addFolderBackground(this); |
| 764 | } |
| 765 | |
| 766 | mDrawingDelegate = delegate; |
| 767 | delegateCellX = cellX; |
| 768 | delegateCellY = cellY; |
| 769 | |
| 770 | invalidate(); |
| 771 | } |
| 772 | |
| 773 | private void clearDrawingDelegate() { |
| 774 | if (mDrawingDelegate != null) { |
| 775 | mDrawingDelegate.removeFolderBackground(this); |
| 776 | } |
| 777 | |
| 778 | mDrawingDelegate = null; |
| 779 | invalidate(); |
| 780 | } |
| 781 | |
| 782 | private boolean drawingDelegated() { |
| 783 | return mDrawingDelegate != null; |
| 784 | } |
| 785 | |
| 786 | private void animateScale(float finalScale, float finalMultiplier, |
| 787 | final Runnable onStart, final Runnable onEnd) { |
| 788 | final float scale0 = mScale; |
| 789 | final float scale1 = finalScale; |
| 790 | |
| 791 | final float bgMultiplier0 = mColorMultiplier; |
| 792 | final float bgMultiplier1 = finalMultiplier; |
| 793 | |
| 794 | if (mScaleAnimator != null) { |
| 795 | mScaleAnimator.cancel(); |
| 796 | } |
| 797 | |
Jon Miranda | cda3bfb | 2017-02-06 15:54:41 -0800 | [diff] [blame] | 798 | mScaleAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 799 | |
| 800 | mScaleAnimator.addUpdateListener(new AnimatorUpdateListener() { |
| 801 | @Override |
| 802 | public void onAnimationUpdate(ValueAnimator animation) { |
| 803 | float prog = animation.getAnimatedFraction(); |
| 804 | mScale = prog * scale1 + (1 - prog) * scale0; |
| 805 | mColorMultiplier = prog * bgMultiplier1 + (1 - prog) * bgMultiplier0; |
| 806 | invalidate(); |
| 807 | } |
| 808 | }); |
| 809 | mScaleAnimator.addListener(new AnimatorListenerAdapter() { |
| 810 | @Override |
| 811 | public void onAnimationStart(Animator animation) { |
| 812 | if (onStart != null) { |
| 813 | onStart.run(); |
| 814 | } |
| 815 | } |
| 816 | |
| 817 | @Override |
| 818 | public void onAnimationEnd(Animator animation) { |
| 819 | if (onEnd != null) { |
| 820 | onEnd.run(); |
| 821 | } |
| 822 | mScaleAnimator = null; |
| 823 | } |
| 824 | }); |
| 825 | |
| 826 | mScaleAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION); |
| 827 | mScaleAnimator.start(); |
| 828 | } |
| 829 | |
| 830 | public void animateToAccept(final CellLayout cl, final int cellX, final int cellY) { |
| 831 | Runnable onStart = new Runnable() { |
| 832 | @Override |
| 833 | public void run() { |
| 834 | delegateDrawing(cl, cellX, cellY); |
| 835 | } |
| 836 | }; |
| 837 | animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER, onStart, null); |
| 838 | } |
| 839 | |
| 840 | public void animateToRest() { |
| 841 | // This can be called multiple times -- we need to make sure the drawing delegate |
| 842 | // is saved and restored at the beginning of the animation, since cancelling the |
| 843 | // existing animation can clear the delgate. |
| 844 | final CellLayout cl = mDrawingDelegate; |
| 845 | final int cellX = delegateCellX; |
| 846 | final int cellY = delegateCellY; |
| 847 | |
| 848 | Runnable onStart = new Runnable() { |
| 849 | @Override |
| 850 | public void run() { |
| 851 | delegateDrawing(cl, cellX, cellY); |
| 852 | } |
| 853 | }; |
| 854 | Runnable onEnd = new Runnable() { |
| 855 | @Override |
| 856 | public void run() { |
| 857 | clearDrawingDelegate(); |
| 858 | } |
| 859 | }; |
| 860 | animateScale(1f, 1f, onStart, onEnd); |
| 861 | } |
Jon Miranda | 4717011 | 2017-03-03 14:57:14 -0800 | [diff] [blame] | 862 | |
| 863 | public int getBackgroundAlpha() { |
| 864 | return (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier); |
| 865 | } |
| 866 | |
| 867 | public float getStrokeWidth() { |
| 868 | return mStrokeWidth; |
| 869 | } |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 870 | } |
| 871 | |
| 872 | public void setFolderBackground(PreviewBackground bg) { |
| 873 | mBackground = bg; |
Adam Cohen | f172b74 | 2016-03-30 19:28:34 -0700 | [diff] [blame] | 874 | mBackground.setInvalidateDelegate(this); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 875 | } |
| 876 | |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 877 | @Override |
Adam Cohen | c0dcf59 | 2011-06-01 15:30:43 -0700 | [diff] [blame] | 878 | protected void dispatchDraw(Canvas canvas) { |
Adam Cohen | 76fc085 | 2011-06-17 13:26:23 -0700 | [diff] [blame] | 879 | super.dispatchDraw(canvas); |
| 880 | |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 881 | if (mReferenceDrawable != null) { |
| 882 | computePreviewDrawingParams(mReferenceDrawable); |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 883 | } |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 884 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 885 | if (!mBackground.drawingDelegated()) { |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 886 | mBackground.drawBackground(canvas); |
Adam Cohen | 119e898 | 2016-02-05 14:47:50 -0800 | [diff] [blame] | 887 | } |
| 888 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 889 | if (mFolder == null) return; |
| 890 | if (mFolder.getItemCount() == 0 && !mAnimating) return; |
| 891 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 892 | final int saveCount; |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 893 | |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 894 | if (canvas.isHardwareAccelerated()) { |
| 895 | saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, |
| 896 | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); |
| 897 | } else { |
| 898 | saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); |
| 899 | if (mPreviewLayoutRule.clipToBackground()) { |
| 900 | mBackground.clipCanvasSoftware(canvas, Region.Op.INTERSECT); |
| 901 | } |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 902 | } |
| 903 | |
| 904 | // The items are drawn in coordinates relative to the preview offset |
| 905 | canvas.translate(mBackground.basePreviewOffsetX, mBackground.basePreviewOffsetY); |
| 906 | |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 907 | // The first item should be drawn last (ie. on top of later items) |
| 908 | for (int i = mDrawingParams.size() - 1; i >= 0; i--) { |
| 909 | PreviewItemDrawingParams p = mDrawingParams.get(i); |
| 910 | if (!p.hidden) { |
| 911 | drawPreviewItem(canvas, p); |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 912 | } |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 913 | } |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 914 | canvas.translate(-mBackground.basePreviewOffsetX, -mBackground.basePreviewOffsetY); |
| 915 | |
| 916 | if (mPreviewLayoutRule.clipToBackground() && canvas.isHardwareAccelerated()) { |
| 917 | mBackground.clipCanvasHardware(canvas); |
| 918 | } |
| 919 | canvas.restoreToCount(saveCount); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 920 | |
| 921 | if (mPreviewLayoutRule.clipToBackground() && !mBackground.drawingDelegated()) { |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 922 | mBackground.drawBackgroundStroke(canvas); |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 923 | } |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 924 | |
Tony Wickham | 0530e8c | 2017-04-26 18:13:56 -0700 | [diff] [blame] | 925 | if ((mBadgeInfo != null && mBadgeInfo.hasBadge()) || mBadgeScale > 0) { |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 926 | int offsetX = mBackground.getOffsetX(); |
| 927 | int offsetY = mBackground.getOffsetY(); |
| 928 | int previewSize = (int) (mBackground.previewSize * mBackground.mScale); |
Tony Wickham | 1237df0 | 2017-02-24 08:59:36 -0800 | [diff] [blame] | 929 | mTempBounds.set(offsetX, offsetY, offsetX + previewSize, offsetY + previewSize); |
Sunny Goyal | 19b93b7 | 2017-02-19 20:21:37 -0800 | [diff] [blame] | 930 | |
Tony Wickham | 1237df0 | 2017-02-24 08:59:36 -0800 | [diff] [blame] | 931 | // If we are animating to the accepting state, animate the badge out. |
Tony Wickham | 1e61849 | 2017-02-02 12:57:18 -0800 | [diff] [blame] | 932 | float badgeScale = Math.max(0, mBadgeScale - mBackground.getScaleProgress()); |
Tony Wickham | 1237df0 | 2017-02-24 08:59:36 -0800 | [diff] [blame] | 933 | mTempSpaceForBadgeOffset.set(getWidth() - mTempBounds.right, mTempBounds.top); |
Tony Wickham | e6a790e | 2017-05-16 12:07:38 -0700 | [diff] [blame] | 934 | mBadgeRenderer.draw(canvas, mBadgeInfo, mTempBounds, |
Tony Wickham | 1237df0 | 2017-02-24 08:59:36 -0800 | [diff] [blame] | 935 | badgeScale, mTempSpaceForBadgeOffset); |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 936 | } |
Adam Cohen | d044526 | 2011-07-04 23:53:22 -0700 | [diff] [blame] | 937 | } |
| 938 | |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 939 | class FolderPreviewItemAnim { |
| 940 | ValueAnimator mValueAnimator; |
| 941 | float finalScale; |
| 942 | float finalTransX; |
| 943 | float finalTransY; |
| 944 | |
| 945 | /** |
| 946 | * |
| 947 | * @param params layout params to animate |
| 948 | * @param index0 original index of the item to be animated |
| 949 | * @param nItems0 original number of items in the preview |
| 950 | * @param index1 new index of the item to be animated |
| 951 | * @param nItems1 new number of items in the preview |
| 952 | * @param duration duration in ms of the animation |
| 953 | * @param onCompleteRunnable runnable to execute upon animation completion |
| 954 | */ |
| 955 | public FolderPreviewItemAnim(final PreviewItemDrawingParams params, int index0, int nItems0, |
| 956 | int index1, int nItems1, int duration, final Runnable onCompleteRunnable) { |
| 957 | |
| 958 | computePreviewItemDrawingParams(index1, nItems1, mTmpParams); |
| 959 | |
| 960 | finalScale = mTmpParams.scale; |
| 961 | finalTransX = mTmpParams.transX; |
| 962 | finalTransY = mTmpParams.transY; |
| 963 | |
| 964 | computePreviewItemDrawingParams(index0, nItems0, mTmpParams); |
| 965 | |
| 966 | final float scale0 = mTmpParams.scale; |
| 967 | final float transX0 = mTmpParams.transX; |
| 968 | final float transY0 = mTmpParams.transY; |
| 969 | |
Jon Miranda | cda3bfb | 2017-02-06 15:54:41 -0800 | [diff] [blame] | 970 | mValueAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f); |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 971 | mValueAnimator.addUpdateListener(new AnimatorUpdateListener(){ |
| 972 | public void onAnimationUpdate(ValueAnimator animation) { |
| 973 | float progress = animation.getAnimatedFraction(); |
| 974 | |
| 975 | params.transX = transX0 + progress * (finalTransX - transX0); |
| 976 | params.transY = transY0 + progress * (finalTransY - transY0); |
| 977 | params.scale = scale0 + progress * (finalScale - scale0); |
| 978 | invalidate(); |
| 979 | } |
| 980 | }); |
| 981 | |
| 982 | mValueAnimator.addListener(new AnimatorListenerAdapter() { |
| 983 | @Override |
| 984 | public void onAnimationStart(Animator animation) { |
| 985 | } |
| 986 | |
| 987 | @Override |
| 988 | public void onAnimationEnd(Animator animation) { |
| 989 | if (onCompleteRunnable != null) { |
| 990 | onCompleteRunnable.run(); |
| 991 | } |
| 992 | params.anim = null; |
| 993 | } |
| 994 | }); |
| 995 | mValueAnimator.setDuration(duration); |
| 996 | } |
| 997 | |
| 998 | public void start() { |
| 999 | mValueAnimator.start(); |
| 1000 | } |
| 1001 | |
| 1002 | public void cancel() { |
| 1003 | mValueAnimator.cancel(); |
| 1004 | } |
| 1005 | |
| 1006 | public boolean hasEqualFinalState(FolderPreviewItemAnim anim) { |
| 1007 | return finalTransY == anim.finalTransY && finalTransX == anim.finalTransX && |
| 1008 | finalScale == anim.finalScale; |
| 1009 | |
| 1010 | } |
| 1011 | } |
| 1012 | |
Adam Cohen | fb91f30 | 2012-06-11 15:45:18 -0700 | [diff] [blame] | 1013 | private void animateFirstItem(final Drawable d, int duration, final boolean reverse, |
| 1014 | final Runnable onCompleteRunnable) { |
Adam Cohen | 119e898 | 2016-02-05 14:47:50 -0800 | [diff] [blame] | 1015 | |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 1016 | FolderPreviewItemAnim anim; |
| 1017 | if (!reverse) { |
| 1018 | anim = new FolderPreviewItemAnim(mDrawingParams.get(0), -1, -1, 0, 2, duration, |
| 1019 | onCompleteRunnable); |
| 1020 | } else { |
| 1021 | anim = new FolderPreviewItemAnim(mDrawingParams.get(0), 0, 2, -1, -1, duration, |
| 1022 | onCompleteRunnable); |
| 1023 | } |
| 1024 | anim.start(); |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 1025 | } |
| 1026 | |
Adam Cohen | 099f60d | 2011-08-23 21:07:26 -0700 | [diff] [blame] | 1027 | public void setTextVisible(boolean visible) { |
| 1028 | if (visible) { |
| 1029 | mFolderName.setVisibility(VISIBLE); |
| 1030 | } else { |
| 1031 | mFolderName.setVisibility(INVISIBLE); |
| 1032 | } |
| 1033 | } |
| 1034 | |
| 1035 | public boolean getTextVisible() { |
| 1036 | return mFolderName.getVisibility() == VISIBLE; |
| 1037 | } |
| 1038 | |
Jon Miranda | 4717011 | 2017-03-03 14:57:14 -0800 | [diff] [blame] | 1039 | public List<BubbleTextView> getItemsToDisplay() { |
Jon Miranda | 655ec42 | 2017-02-07 11:40:22 -0800 | [diff] [blame] | 1040 | mPreviewVerifier.setFolderInfo(mFolder.getInfo()); |
| 1041 | |
Jon Miranda | 4717011 | 2017-03-03 14:57:14 -0800 | [diff] [blame] | 1042 | List<BubbleTextView> itemsToDisplay = new ArrayList<>(); |
Jon Miranda | 655ec42 | 2017-02-07 11:40:22 -0800 | [diff] [blame] | 1043 | List<View> allItems = mFolder.getItemsInReadingOrder(); |
| 1044 | int numItems = allItems.size(); |
| 1045 | for (int rank = 0; rank < numItems; ++rank) { |
| 1046 | if (mPreviewVerifier.isItemInPreview(rank)) { |
Jon Miranda | 4717011 | 2017-03-03 14:57:14 -0800 | [diff] [blame] | 1047 | itemsToDisplay.add((BubbleTextView) allItems.get(rank)); |
Jon Miranda | 655ec42 | 2017-02-07 11:40:22 -0800 | [diff] [blame] | 1048 | } |
| 1049 | |
| 1050 | if (itemsToDisplay.size() == FolderIcon.NUM_ITEMS_IN_PREVIEW) { |
| 1051 | break; |
| 1052 | } |
| 1053 | } |
| 1054 | return itemsToDisplay; |
| 1055 | } |
| 1056 | |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 1057 | private void updateItemDrawingParams(boolean animate) { |
Jon Miranda | 4717011 | 2017-03-03 14:57:14 -0800 | [diff] [blame] | 1058 | List<BubbleTextView> items = getItemsToDisplay(); |
Jon Miranda | 12b616c | 2017-02-06 15:45:53 -0800 | [diff] [blame] | 1059 | int nItemsInPreview = items.size(); |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 1060 | |
| 1061 | int prevNumItems = mDrawingParams.size(); |
| 1062 | |
| 1063 | // We adjust the size of the list to match the number of items in the preview |
| 1064 | while (nItemsInPreview < mDrawingParams.size()) { |
| 1065 | mDrawingParams.remove(mDrawingParams.size() - 1); |
| 1066 | } |
| 1067 | while (nItemsInPreview > mDrawingParams.size()) { |
| 1068 | mDrawingParams.add(new PreviewItemDrawingParams(0, 0, 0, 0)); |
| 1069 | } |
| 1070 | |
| 1071 | for (int i = 0; i < mDrawingParams.size(); i++) { |
| 1072 | PreviewItemDrawingParams p = mDrawingParams.get(i); |
Jon Miranda | 4717011 | 2017-03-03 14:57:14 -0800 | [diff] [blame] | 1073 | p.drawable = items.get(i).getCompoundDrawables()[1]; |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 1074 | |
Adam Cohen | efca027 | 2016-02-24 19:19:06 -0800 | [diff] [blame] | 1075 | if (!animate || FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON) { |
Adam Cohen | 4f8071b | 2016-02-13 16:06:05 -0800 | [diff] [blame] | 1076 | computePreviewItemDrawingParams(i, nItemsInPreview, p); |
| 1077 | if (mReferenceDrawable == null) { |
| 1078 | mReferenceDrawable = p.drawable; |
| 1079 | } |
| 1080 | } else { |
| 1081 | FolderPreviewItemAnim anim = new FolderPreviewItemAnim(p, i, prevNumItems, i, |
| 1082 | nItemsInPreview, DROP_IN_ANIMATION_DURATION, null); |
| 1083 | |
| 1084 | if (p.anim != null) { |
| 1085 | if (p.anim.hasEqualFinalState(anim)) { |
| 1086 | // do nothing, let the current animation finish |
| 1087 | continue; |
| 1088 | } |
| 1089 | p.anim.cancel(); |
| 1090 | } |
| 1091 | p.anim = anim; |
| 1092 | p.anim.start(); |
| 1093 | } |
| 1094 | } |
| 1095 | } |
| 1096 | |
Sunny Goyal | c52ba71 | 2016-04-05 15:59:05 -0700 | [diff] [blame] | 1097 | @Override |
| 1098 | public void onItemsChanged(boolean animate) { |
| 1099 | updateItemDrawingParams(animate); |
Adam Cohen | 76078c4 | 2011-06-09 15:06:52 -0700 | [diff] [blame] | 1100 | invalidate(); |
| 1101 | requestLayout(); |
| 1102 | } |
| 1103 | |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 1104 | @Override |
Jon Miranda | 608d0db | 2017-02-28 13:15:28 -0800 | [diff] [blame] | 1105 | public void prepareAutoUpdate() { |
Jon Miranda | 4406094 | 2017-02-22 10:17:49 -0800 | [diff] [blame] | 1106 | } |
| 1107 | |
| 1108 | @Override |
Jon Miranda | c476d6e | 2017-05-04 16:30:01 -0700 | [diff] [blame^] | 1109 | public void onAdd(ShortcutInfo item, int rank) { |
Tony Wickham | 0530e8c | 2017-04-26 18:13:56 -0700 | [diff] [blame] | 1110 | boolean wasBadged = mBadgeInfo.hasBadge(); |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 1111 | mBadgeInfo.addBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item)); |
Tony Wickham | 0530e8c | 2017-04-26 18:13:56 -0700 | [diff] [blame] | 1112 | boolean isBadged = mBadgeInfo.hasBadge(); |
| 1113 | updateBadgeScale(wasBadged, isBadged); |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 1114 | invalidate(); |
| 1115 | requestLayout(); |
| 1116 | } |
| 1117 | |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 1118 | @Override |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 1119 | public void onRemove(ShortcutInfo item) { |
Tony Wickham | 0530e8c | 2017-04-26 18:13:56 -0700 | [diff] [blame] | 1120 | boolean wasBadged = mBadgeInfo.hasBadge(); |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 1121 | mBadgeInfo.subtractBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item)); |
Tony Wickham | 0530e8c | 2017-04-26 18:13:56 -0700 | [diff] [blame] | 1122 | boolean isBadged = mBadgeInfo.hasBadge(); |
| 1123 | updateBadgeScale(wasBadged, isBadged); |
Adam Cohen | a9cf38f | 2011-05-02 15:36:58 -0700 | [diff] [blame] | 1124 | invalidate(); |
| 1125 | requestLayout(); |
| 1126 | } |
Adam Cohen | 76fc085 | 2011-06-17 13:26:23 -0700 | [diff] [blame] | 1127 | |
Tony Wickham | 11ba507 | 2017-02-02 12:42:50 -0800 | [diff] [blame] | 1128 | @Override |
Adam Cohen | 76fc085 | 2011-06-17 13:26:23 -0700 | [diff] [blame] | 1129 | public void onTitleChanged(CharSequence title) { |
Winson Chung | 82b016c | 2015-05-08 17:00:10 -0700 | [diff] [blame] | 1130 | mFolderName.setText(title); |
Sunny Goyal | f4f89ef | 2015-09-02 15:06:12 -0700 | [diff] [blame] | 1131 | setContentDescription(getContext().getString(R.string.folder_name_format, title)); |
Adam Cohen | 76fc085 | 2011-06-17 13:26:23 -0700 | [diff] [blame] | 1132 | } |
Winson Chung | 88f3345 | 2012-02-23 15:23:44 -0800 | [diff] [blame] | 1133 | |
| 1134 | @Override |
| 1135 | public boolean onTouchEvent(MotionEvent event) { |
| 1136 | // Call the superclass onTouchEvent first, because sometimes it changes the state to |
| 1137 | // isPressed() on an ACTION_UP |
| 1138 | boolean result = super.onTouchEvent(event); |
| 1139 | |
Mady Mellor | ef044dd | 2015-06-02 15:35:07 -0700 | [diff] [blame] | 1140 | // Check for a stylus button press, if it occurs cancel any long press checks. |
Mady Mellor | bb83520 | 2015-07-15 16:34:34 -0700 | [diff] [blame] | 1141 | if (mStylusEventHelper.onMotionEvent(event)) { |
Mady Mellor | ef044dd | 2015-06-02 15:35:07 -0700 | [diff] [blame] | 1142 | mLongPressHelper.cancelLongPress(); |
| 1143 | return true; |
| 1144 | } |
| 1145 | |
Winson Chung | 88f3345 | 2012-02-23 15:23:44 -0800 | [diff] [blame] | 1146 | switch (event.getAction()) { |
| 1147 | case MotionEvent.ACTION_DOWN: |
| 1148 | mLongPressHelper.postCheckForLongPress(); |
| 1149 | break; |
| 1150 | case MotionEvent.ACTION_CANCEL: |
| 1151 | case MotionEvent.ACTION_UP: |
| 1152 | mLongPressHelper.cancelLongPress(); |
| 1153 | break; |
Jason Monk | 02dd7ae | 2014-04-15 15:23:31 -0400 | [diff] [blame] | 1154 | case MotionEvent.ACTION_MOVE: |
| 1155 | if (!Utilities.pointInView(this, event.getX(), event.getY(), mSlop)) { |
| 1156 | mLongPressHelper.cancelLongPress(); |
| 1157 | } |
| 1158 | break; |
Winson Chung | 88f3345 | 2012-02-23 15:23:44 -0800 | [diff] [blame] | 1159 | } |
| 1160 | return result; |
| 1161 | } |
| 1162 | |
| 1163 | @Override |
| 1164 | public void cancelLongPress() { |
| 1165 | super.cancelLongPress(); |
Winson Chung | 88f3345 | 2012-02-23 15:23:44 -0800 | [diff] [blame] | 1166 | mLongPressHelper.cancelLongPress(); |
| 1167 | } |
Adam Cohen | f9c184a | 2016-01-15 16:47:43 -0800 | [diff] [blame] | 1168 | |
Sunny Goyal | aaf7d1d | 2016-05-17 13:38:54 -0700 | [diff] [blame] | 1169 | public void removeListeners() { |
| 1170 | mInfo.removeListener(this); |
| 1171 | mInfo.removeListener(mFolder); |
| 1172 | } |
| 1173 | |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 1174 | public void shrinkAndFadeIn(boolean animate) { |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 1175 | // We remove and re-draw the FolderIcon in-case it has changed |
| 1176 | final PreviewImageView previewImage = PreviewImageView.get(getContext()); |
| 1177 | previewImage.removeFromParent(); |
| 1178 | copyToPreview(previewImage); |
| 1179 | |
Jon Miranda | f79e54b | 2017-03-31 13:48:39 -0700 | [diff] [blame] | 1180 | clearLeaveBehindIfExists(); |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 1181 | |
| 1182 | ObjectAnimator oa = LauncherAnimUtils.ofViewAlphaAndScale(previewImage, 1, 1, 1); |
| 1183 | oa.setDuration(getResources().getInteger(R.integer.config_folderExpandDuration)); |
| 1184 | oa.addListener(new AnimatorListenerAdapter() { |
| 1185 | @Override |
| 1186 | public void onAnimationEnd(Animator animation) { |
Jon Miranda | f79e54b | 2017-03-31 13:48:39 -0700 | [diff] [blame] | 1187 | // Remove the ImageView copy of the FolderIcon and make the original visible. |
| 1188 | previewImage.removeFromParent(); |
| 1189 | setVisibility(View.VISIBLE); |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 1190 | } |
| 1191 | }); |
| 1192 | oa.start(); |
| 1193 | if (!animate) { |
| 1194 | oa.end(); |
| 1195 | } |
| 1196 | } |
| 1197 | |
Jon Miranda | f79e54b | 2017-03-31 13:48:39 -0700 | [diff] [blame] | 1198 | public void clearLeaveBehindIfExists() { |
| 1199 | ((CellLayout.LayoutParams) getLayoutParams()).canReorder = true; |
| 1200 | if (mInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { |
| 1201 | CellLayout cl = (CellLayout) getParent().getParent(); |
| 1202 | cl.clearFolderLeaveBehind(); |
| 1203 | } |
| 1204 | } |
| 1205 | |
| 1206 | public void drawLeaveBehindIfExists() { |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 1207 | CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); |
| 1208 | // While the folder is open, the position of the icon cannot change. |
| 1209 | lp.canReorder = false; |
| 1210 | if (mInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { |
| 1211 | CellLayout cl = (CellLayout) getParent().getParent(); |
| 1212 | cl.setFolderLeaveBehindCell(lp.cellX, lp.cellY); |
| 1213 | } |
Jon Miranda | f79e54b | 2017-03-31 13:48:39 -0700 | [diff] [blame] | 1214 | } |
| 1215 | |
| 1216 | public void growAndFadeOut() { |
| 1217 | drawLeaveBehindIfExists(); |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 1218 | |
| 1219 | // Push an ImageView copy of the FolderIcon into the DragLayer and hide the original |
| 1220 | PreviewImageView previewImage = PreviewImageView.get(getContext()); |
| 1221 | copyToPreview(previewImage); |
| 1222 | setVisibility(View.INVISIBLE); |
| 1223 | |
| 1224 | ObjectAnimator oa = LauncherAnimUtils.ofViewAlphaAndScale(previewImage, 0, 1.5f, 1.5f); |
| 1225 | oa.setDuration(getResources().getInteger(R.integer.config_folderExpandDuration)); |
| 1226 | oa.start(); |
| 1227 | } |
| 1228 | |
| 1229 | /** |
| 1230 | * This method draws the FolderIcon to an ImageView and then adds and positions that ImageView |
| 1231 | * in the DragLayer in the exact absolute location of the original FolderIcon. |
| 1232 | */ |
| 1233 | private void copyToPreview(PreviewImageView previewImageView) { |
| 1234 | previewImageView.copy(this); |
| 1235 | if (mFolder != null) { |
| 1236 | previewImageView.setPivotX(mFolder.getPivotXForIconAnimation()); |
| 1237 | previewImageView.setPivotY(mFolder.getPivotYForIconAnimation()); |
| 1238 | mFolder.bringToFront(); |
| 1239 | } |
| 1240 | } |
| 1241 | |
Adam Cohen | f9c184a | 2016-01-15 16:47:43 -0800 | [diff] [blame] | 1242 | public interface PreviewLayoutRule { |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 1243 | PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems, |
Adam Cohen | f9c184a | 2016-01-15 16:47:43 -0800 | [diff] [blame] | 1244 | PreviewItemDrawingParams params); |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 1245 | void init(int availableSpace, int intrinsicIconSize, boolean rtl); |
Jon Miranda | 12b616c | 2017-02-06 15:45:53 -0800 | [diff] [blame] | 1246 | float scaleForItem(int index, int totalNumItems); |
Jon Miranda | 5fcbad0 | 2017-03-01 16:06:21 -0800 | [diff] [blame] | 1247 | float getIconSize(); |
Jon Miranda | 12b616c | 2017-02-06 15:45:53 -0800 | [diff] [blame] | 1248 | int maxNumItems(); |
Sunny Goyal | 740ac7f | 2016-09-28 16:47:32 -0700 | [diff] [blame] | 1249 | boolean clipToBackground(); |
Adam Cohen | f9c184a | 2016-01-15 16:47:43 -0800 | [diff] [blame] | 1250 | } |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1251 | } |