FolderIcon.java revision df6af5740da6ee9f78e846218d71941b02fc0283
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/* 231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License. 631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at 731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and 1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License. 1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2; 1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 192801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohenimport android.animation.Animator; 202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohenimport android.animation.AnimatorListenerAdapter; 212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohenimport android.animation.ValueAnimator; 222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohenimport android.animation.ValueAnimator.AnimatorUpdateListener; 2331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context; 2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.res.Resources; 25a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohenimport android.graphics.Canvas; 26f4b08913677e18a8412930972237b91d5a946d95Adam Cohenimport android.graphics.Color; 27badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohenimport android.graphics.PorterDuff; 283e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.graphics.Rect; 2931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.drawable.Drawable; 30099f60d51f6310e1290687e83958e665b3324504Adam Cohenimport android.os.Parcelable; 3131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet; 3231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.LayoutInflater; 337c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohenimport android.view.View; 3431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup; 353e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.AccelerateInterpolator; 363e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.DecelerateInterpolator; 3776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.widget.ImageView; 3876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.widget.LinearLayout; 39a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohenimport android.widget.TextView; 4031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 41edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guyimport com.android.launcher.R; 42c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport com.android.launcher2.DropTarget.DragObject; 43a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohenimport com.android.launcher2.FolderInfo.FolderListener; 44edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guy 45c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.ArrayList; 46c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen 4731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/** 4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * An icon that can appear on in the workspace representing an {@link UserFolder}. 4931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 5076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenpublic class FolderIcon extends LinearLayout implements FolderListener { 5131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private Launcher mLauncher; 52a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen Folder mFolder; 53a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen FolderInfo mInfo; 54099f60d51f6310e1290687e83958e665b3324504Adam Cohen private static boolean sStaticValuesDirty = true; 55a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen 56badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen // The number of icons to display in the 5776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen private static final int NUM_ITEMS_IN_PREVIEW = 3; 58f4b08913677e18a8412930972237b91d5a946d95Adam Cohen private static final int CONSUMPTION_ANIMATION_DURATION = 100; 59d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private static final int DROP_IN_ANIMATION_DURATION = 400; 608dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen private static final int INITIAL_ITEM_ANIMATION_DURATION = 350; 61badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen 62badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen // The degree to which the inner ring grows when accepting drop 6369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen private static final float INNER_RING_GROWTH_FACTOR = 0.15f; 64badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen 65badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen // The degree to which the outer ring is scaled in its natural state 6669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen private static final float OUTER_RING_GROWTH_FACTOR = 0.3f; 67badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen 68badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen // The amount of vertical spread between items in the stack [0...1] 6976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen private static final float PERSPECTIVE_SHIFT_FACTOR = 0.24f; 70badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen 71badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen // The degree to which the item in the back of the stack is scaled [0...1] 72badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen // (0 means it's not scaled at all, 1 means it's scaled to nothing) 7376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen private static final float PERSPECTIVE_SCALE_FACTOR = 0.35f; 7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 75c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public static Drawable sSharedFolderLeaveBehind = null; 76c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 7776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen private ImageView mPreviewBackground; 7876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen private BubbleTextView mFolderName; 79073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen 8019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen FolderRingAnimator mFolderRingAnimator = null; 812801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 82d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen // These variables are all associated with the drawing of the preview; they are stored 83d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen // as member variables for shared usage and to avoid computation on each frame 84d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private int mIntrinsicIconSize; 85d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private float mBaselineIconScale; 86d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private int mBaselineIconSize; 87d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private int mAvailableSpaceInPreview; 88d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private int mTotalWidth = -1; 89d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private int mPreviewOffsetX; 90d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private int mPreviewOffsetY; 91d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private float mMaxPerspectiveShift; 92d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen boolean mAnimating = false; 93d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private PreviewItemDrawingParams mParams = new PreviewItemDrawingParams(0, 0, 0, 0); 94d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0); 95d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 9631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public FolderIcon(Context context, AttributeSet attrs) { 9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs); 9831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 9931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public FolderIcon(Context context) { 10131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context); 10231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 10331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public boolean isDropEnabled() { 1057a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung final ViewGroup cellLayoutChildren = (ViewGroup) getParent(); 1067a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent(); 1077a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung final Workspace workspace = (Workspace) cellLayout.getParent(); 1087a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung return !workspace.isSmall(); 1090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 1100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 11131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group, 112df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen FolderInfo folderInfo, IconCache iconCache) { 11331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 114d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen if (INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION) { 115d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen throw new IllegalStateException("DROP_IN_ANIMATION_DURATION must be greater than " + 116d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " + 117d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen "is dependent on this"); 118d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 119d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 12031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false); 12131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 122d2eca6b66e654e71fb46ae718910af3ec6c2cf9cAdam Cohen icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name); 12376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen icon.mFolderName.setText(folderInfo.title); 12476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen icon.mPreviewBackground = (ImageView) icon.findViewById(R.id.preview_background); 1256a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung icon.mPreviewBackground.setContentDescription(folderInfo.title); 12676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 12731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project icon.setTag(folderInfo); 12831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project icon.setOnClickListener(launcher); 12931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project icon.mInfo = folderInfo; 13031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project icon.mLauncher = launcher; 131a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen 132a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen Folder folder = Folder.fromXml(launcher); 133a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen folder.setDragController(launcher.getDragController()); 1342801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen folder.setFolderIcon(icon); 135a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen folder.bind(folderInfo); 136a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen icon.mFolder = folder; 137c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen Resources res = launcher.getResources(); 138099f60d51f6310e1290687e83958e665b3324504Adam Cohen 139099f60d51f6310e1290687e83958e665b3324504Adam Cohen icon.mFolderRingAnimator = new FolderRingAnimator(launcher, icon); 140099f60d51f6310e1290687e83958e665b3324504Adam Cohen folderInfo.addListener(icon); 141099f60d51f6310e1290687e83958e665b3324504Adam Cohen 14219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen return icon; 14319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 14419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen 145099f60d51f6310e1290687e83958e665b3324504Adam Cohen @Override 146099f60d51f6310e1290687e83958e665b3324504Adam Cohen protected Parcelable onSaveInstanceState() { 147099f60d51f6310e1290687e83958e665b3324504Adam Cohen sStaticValuesDirty = true; 148099f60d51f6310e1290687e83958e665b3324504Adam Cohen return super.onSaveInstanceState(); 149099f60d51f6310e1290687e83958e665b3324504Adam Cohen } 150099f60d51f6310e1290687e83958e665b3324504Adam Cohen 15119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen public static class FolderRingAnimator { 15269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public int mCellX; 15369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public int mCellY; 15469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen private CellLayout mCellLayout; 15576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public float mOuterRingSize; 15676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public float mInnerRingSize; 15719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen public FolderIcon mFolderIcon = null; 158c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen public Drawable mOuterRingDrawable = null; 159c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen public Drawable mInnerRingDrawable = null; 160c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen public static Drawable sSharedOuterRingDrawable = null; 161c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen public static Drawable sSharedInnerRingDrawable = null; 16276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public static int sPreviewSize = -1; 16376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public static int sPreviewPadding = -1; 16476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 165c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen private ValueAnimator mAcceptAnimator; 166c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen private ValueAnimator mNeutralAnimator; 16719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen 16819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen public FolderRingAnimator(Launcher launcher, FolderIcon folderIcon) { 16919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen mFolderIcon = folderIcon; 17076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen Resources res = launcher.getResources(); 17176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen mOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo); 17276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen mInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_holo); 17376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 174099f60d51f6310e1290687e83958e665b3324504Adam Cohen // We need to reload the static values when configuration changes in case they are 175099f60d51f6310e1290687e83958e665b3324504Adam Cohen // different in another configuration 176099f60d51f6310e1290687e83958e665b3324504Adam Cohen if (sStaticValuesDirty) { 17776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen sPreviewSize = res.getDimensionPixelSize(R.dimen.folder_preview_size); 17876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding); 17976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo); 18076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_holo); 181df6af5740da6ee9f78e846218d71941b02fc0283Adam Cohen sSharedFolderLeaveBehind = res.getDrawable(R.drawable.portal_ring_rest); 182099f60d51f6310e1290687e83958e665b3324504Adam Cohen sStaticValuesDirty = false; 18319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 184073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen } 185a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen 18619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen public void animateToAcceptState() { 187c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (mNeutralAnimator != null) { 188c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mNeutralAnimator.cancel(); 189c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen } 190c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mAcceptAnimator = ValueAnimator.ofFloat(0f, 1f); 191c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mAcceptAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION); 192c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mAcceptAnimator.addUpdateListener(new AnimatorUpdateListener() { 19319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 19419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen final float percent = (Float) animation.getAnimatedValue(); 19576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen mOuterRingSize = (1 + percent * OUTER_RING_GROWTH_FACTOR) * sPreviewSize; 19676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen mInnerRingSize = (1 + percent * INNER_RING_GROWTH_FACTOR) * sPreviewSize; 19769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen if (mCellLayout != null) { 19869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mCellLayout.invalidate(); 19919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 20019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 20119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen }); 202c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mAcceptAnimator.addListener(new AnimatorListenerAdapter() { 20319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen @Override 204c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen public void onAnimationStart(Animator animation) { 20519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen if (mFolderIcon != null) { 20676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen mFolderIcon.mPreviewBackground.setVisibility(INVISIBLE); 20719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 20819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 20919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen }); 210c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mAcceptAnimator.start(); 21119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 21219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen 21319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen public void animateToNaturalState() { 214c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (mAcceptAnimator != null) { 215c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mAcceptAnimator.cancel(); 216c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen } 217c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mNeutralAnimator = ValueAnimator.ofFloat(0f, 1f); 218c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mNeutralAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION); 219c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mNeutralAnimator.addUpdateListener(new AnimatorUpdateListener() { 22019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 22119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen final float percent = (Float) animation.getAnimatedValue(); 22276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen mOuterRingSize = (1 + (1 - percent) * OUTER_RING_GROWTH_FACTOR) * sPreviewSize; 22376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen mInnerRingSize = (1 + (1 - percent) * INNER_RING_GROWTH_FACTOR) * sPreviewSize; 22469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen if (mCellLayout != null) { 22569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mCellLayout.invalidate(); 22619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 22719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 22819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen }); 229c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mNeutralAnimator.addListener(new AnimatorListenerAdapter() { 23019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen @Override 23119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen public void onAnimationEnd(Animator animation) { 23269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen if (mCellLayout != null) { 23369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mCellLayout.hideFolderAccept(FolderRingAnimator.this); 23469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 23519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen if (mFolderIcon != null) { 23676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen mFolderIcon.mPreviewBackground.setVisibility(VISIBLE); 23719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 23819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 23919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen }); 240c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen mNeutralAnimator.start(); 24119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 24219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen 243c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen // Location is expressed in window coordinates 24469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void getCell(int[] loc) { 24569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen loc[0] = mCellX; 24669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen loc[1] = mCellY; 24769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 24869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 24969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Location is expressed in window coordinates 25069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void setCell(int x, int y) { 25169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mCellX = x; 25269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mCellY = y; 25369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 25469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 25569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void setCellLayout(CellLayout layout) { 25669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mCellLayout = layout; 25719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 25819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen 25976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public float getOuterRingSize() { 26076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen return mOuterRingSize; 26119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen } 26219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen 26376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public float getInnerRingSize() { 26476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen return mInnerRingSize; 265f4b08913677e18a8412930972237b91d5a946d95Adam Cohen } 26631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 26731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 268073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen private boolean willAcceptItem(ItemInfo item) { 26931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int itemType = item.itemType; 2702801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || 2712801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) && 272c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen !mFolder.isFull() && item != mInfo && !mInfo.opened); 273073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen } 274073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen 275c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen public boolean acceptDrop(Object dragInfo) { 276c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen final ItemInfo item = (ItemInfo) dragInfo; 277073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen return willAcceptItem(item); 27831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 27931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 280df0353815c629fc678824b07a234b89a1ff94208Adam Cohen public void addItem(ShortcutInfo item) { 281df0353815c629fc678824b07a234b89a1ff94208Adam Cohen mInfo.add(item); 282a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY); 283df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 284df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 285c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen public void onDragEnter(Object dragInfo) { 286c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (!willAcceptItem((ItemInfo) dragInfo)) return; 28769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); 28869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen CellLayout layout = (CellLayout) getParent().getParent(); 28969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderRingAnimator.setCell(lp.cellX, lp.cellY); 29069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderRingAnimator.setCellLayout(layout); 29119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen mFolderRingAnimator.animateToAcceptState(); 29269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen layout.showFolderAccept(mFolderRingAnimator); 293073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen } 294073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen 295c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen public void onDragOver(Object dragInfo) { 296073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen } 297073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen 298d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen public void performCreateAnimation(final ShortcutInfo destInfo, final View destView, 299557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung final ShortcutInfo srcInfo, final View srcView, Rect dstRect, 300ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen float scaleRelativeToDragLayer, Runnable postAnimationRunnable) { 301d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 302d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1]; 303d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth()); 304ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen 305d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen // This will animate the dragView (srcView) into the new folder 306ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable); 307d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 308d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen // This will animate the first item from it's position as an icon into its 309d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen // position as the first item in the preview 3108dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION); 311d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 312d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen postDelayed(new Runnable() { 313d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen public void run() { 314d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen addItem(destInfo); 315d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 316d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen }, INITIAL_ITEM_ANIMATION_DURATION); 317d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 318d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 319c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen public void onDragExit(Object dragInfo) { 320c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (!willAcceptItem((ItemInfo) dragInfo)) return; 32119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen mFolderRingAnimator.animateToNaturalState(); 322073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen } 323073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen 324ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen private void onDrop(final ShortcutInfo item, View animateView, Rect finalRect, 325ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable) { 326d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen item.cellX = -1; 327d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen item.cellY = -1; 328d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 329558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen // Typically, the animateView corresponds to the DragView; however, if this is being done 330558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen // after a configuration activity (ie. for a Shortcut being dragged from AllApps) we 331558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen // will not have a view to animate 332558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen if (animateView != null) { 333558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen DragLayer dragLayer = mLauncher.getDragLayer(); 334558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen Rect from = new Rect(); 335558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen dragLayer.getViewRectRelativeToSelf(animateView, from); 336558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen Rect to = finalRect; 337558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen if (to == null) { 338558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen to = new Rect(); 339558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen Workspace workspace = mLauncher.getWorkspace(); 340558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen // Set cellLayout and this to it's final state to compute final animation locations 341558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen workspace.setFinalTransitionTransform((CellLayout) getParent().getParent()); 342558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen float scaleX = getScaleX(); 343558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen float scaleY = getScaleY(); 344558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen setScaleX(1.0f); 345558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen setScaleY(1.0f); 346558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen scaleRelativeToDragLayer = dragLayer.getDescendantRectRelativeToSelf(this, to); 347558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen // Finished computing final animation locations, restore current state 348558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen setScaleX(scaleX); 349558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen setScaleY(scaleY); 350558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen workspace.resetTransitionTransform((CellLayout) getParent().getParent()); 351558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen } 352ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen 353558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen int[] center = new int[2]; 354558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen float scale = getLocalCenterForIndex(index, center); 355558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]); 356558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]); 357d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 358558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen to.offset(center[0] - animateView.getMeasuredWidth() / 2, 359558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen center[1] - animateView.getMeasuredHeight() / 2); 360d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 361558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen float finalAlpha = index < NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f; 362558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen 363558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen dragLayer.animateView(animateView, from, to, finalAlpha, 364558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen scale * scaleRelativeToDragLayer, DROP_IN_ANIMATION_DURATION, 365558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen new DecelerateInterpolator(2), new AccelerateInterpolator(2), 366558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen postAnimationRunnable, false); 367558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen postDelayed(new Runnable() { 368558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen public void run() { 369558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen addItem(item); 370558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen } 371558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen }, DROP_IN_ANIMATION_DURATION); 372558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen } else { 373558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen addItem(item); 374558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen } 375d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 376d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 3773e8f811f31a2275e778244427271f77f4116c08bAdam Cohen public void onDrop(DragObject d) { 378c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen ShortcutInfo item; 3793e8f811f31a2275e778244427271f77f4116c08bAdam Cohen if (d.dragInfo instanceof ApplicationInfo) { 380c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen // Came from all apps -- make a copy 3813e8f811f31a2275e778244427271f77f4116c08bAdam Cohen item = ((ApplicationInfo) d.dragInfo).makeShortcut(); 382c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen } else { 3833e8f811f31a2275e778244427271f77f4116c08bAdam Cohen item = (ShortcutInfo) d.dragInfo; 384c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen } 38567bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen mFolder.notifyDrop(); 386ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable); 387c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen } 388c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen 389cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen public DropTarget getDropTargetDelegate(DragObject d) { 390440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy return null; 391440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 392a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen 393d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private void computePreviewDrawingParams(int drawableSize, int totalSize) { 394d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize) { 395d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mIntrinsicIconSize = drawableSize; 396d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mTotalWidth = totalSize; 39776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 398d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen final int previewSize = FolderRingAnimator.sPreviewSize; 399d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen final int previewPadding = FolderRingAnimator.sPreviewPadding; 400a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen 401d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mAvailableSpaceInPreview = (previewSize - 2 * previewPadding); 402d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen // cos(45) = 0.707 + ~= 0.1) = 0.8f 403d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen int adjustedAvailableSpace = (int) ((mAvailableSpaceInPreview / 2) * (1 + 0.8f)); 404d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 405d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen int unscaledHeight = (int) (mIntrinsicIconSize * (1 + PERSPECTIVE_SHIFT_FACTOR)); 406d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mBaselineIconScale = (1.0f * adjustedAvailableSpace / unscaledHeight); 407a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen 408d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mBaselineIconSize = (int) (mIntrinsicIconSize * mBaselineIconScale); 409d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mMaxPerspectiveShift = mBaselineIconSize * PERSPECTIVE_SHIFT_FACTOR; 410d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 411d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mPreviewOffsetX = (mTotalWidth - mAvailableSpaceInPreview) / 2; 412d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mPreviewOffsetY = previewPadding; 413073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen } 414d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 41576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 416d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private void computePreviewDrawingParams(Drawable d) { 417d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen computePreviewDrawingParams(d.getIntrinsicWidth(), getMeasuredWidth()); 418d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 419073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen 420d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen class PreviewItemDrawingParams { 421d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen PreviewItemDrawingParams(float transX, float transY, float scale, int overlayAlpha) { 422d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen this.transX = transX; 423d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen this.transY = transY; 424d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen this.scale = scale; 425d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen this.overlayAlpha = overlayAlpha; 426d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 427d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float transX; 428d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float transY; 429d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float scale; 430d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen int overlayAlpha; 431d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen Drawable drawable; 432d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 433badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen 434ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen private float getLocalCenterForIndex(int index, int[] center) { 435d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mParams = computePreviewItemDrawingParams(Math.min(NUM_ITEMS_IN_PREVIEW, index), mParams); 436a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen 437d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mParams.transX += mPreviewOffsetX; 438d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mParams.transY += mPreviewOffsetY; 439ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen float offsetX = mParams.transX + (mParams.scale * mIntrinsicIconSize) / 2; 440ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen float offsetY = mParams.transY + (mParams.scale * mIntrinsicIconSize) / 2; 441badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen 442ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen center[0] = (int) Math.round(offsetX); 443ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen center[1] = (int) Math.round(offsetY); 444d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen return mParams.scale; 445d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 446badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen 447d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private PreviewItemDrawingParams computePreviewItemDrawingParams(int index, 448d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen PreviewItemDrawingParams params) { 449d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen index = NUM_ITEMS_IN_PREVIEW - index - 1; 450d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float r = (index * 1.0f) / (NUM_ITEMS_IN_PREVIEW - 1); 451d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float scale = (1 - PERSPECTIVE_SCALE_FACTOR * (1 - r)); 452d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 453d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float offset = (1 - r) * mMaxPerspectiveShift; 454d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float scaledSize = scale * mBaselineIconSize; 455d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float scaleOffsetCorrection = (1 - scale) * mBaselineIconSize; 456d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 457d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen // We want to imagine our coordinates from the bottom left, growing up and to the 458d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen // right. This is natural for the x-axis, but for the y-axis, we have to invert things. 459d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float transY = mAvailableSpaceInPreview - (offset + scaledSize + scaleOffsetCorrection); 460d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float transX = offset + scaleOffsetCorrection; 461d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float totalScale = mBaselineIconScale * scale; 462d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen final int overlayAlpha = (int) (80 * (1 - r)); 463d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 464d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen if (params == null) { 465d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen params = new PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha); 466d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } else { 467d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen params.transX = transX; 468d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen params.transY = transY; 469d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen params.scale = totalScale; 470d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen params.overlayAlpha = overlayAlpha; 471d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 472d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen return params; 473d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 474badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen 475d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) { 476d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen canvas.save(); 477d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen canvas.translate(params.transX + mPreviewOffsetX, params.transY + mPreviewOffsetY); 478d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen canvas.scale(params.scale, params.scale); 479d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen Drawable d = params.drawable; 480d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 481d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen if (d != null) { 482d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize); 483d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen d.setFilterBitmap(true); 484d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen d.setColorFilter(Color.argb(params.overlayAlpha, 0, 0, 0), PorterDuff.Mode.SRC_ATOP); 485d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen d.draw(canvas); 486d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen d.clearColorFilter(); 487d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen d.setFilterBitmap(false); 488d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 489d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen canvas.restore(); 490d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 49176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 492d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen @Override 493d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen protected void dispatchDraw(Canvas canvas) { 494d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen super.dispatchDraw(canvas); 495badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen 496d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen if (mFolder == null) return; 497d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen if (mFolder.getItemCount() == 0 && !mAnimating) return; 498d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 499d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen ArrayList<View> items = mFolder.getItemsInReadingOrder(false); 500d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen Drawable d; 501d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen TextView v; 502d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 503d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen // Update our drawing parameters if necessary 504d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen if (mAnimating) { 505d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen computePreviewDrawingParams(mAnimParams.drawable); 506d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } else { 507d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen v = (TextView) items.get(0); 508a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen d = v.getCompoundDrawables()[1]; 509d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen computePreviewDrawingParams(d); 510d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 511a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen 512d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW); 513d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen if (!mAnimating) { 514d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen for (int i = nItemsInPreview - 1; i >= 0; i--) { 515d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen v = (TextView) items.get(i); 516d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen d = v.getCompoundDrawables()[1]; 517d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 518d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mParams = computePreviewItemDrawingParams(i, mParams); 519d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mParams.drawable = d; 520d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen drawPreviewItem(canvas, mParams); 521a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen } 522d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } else { 523d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen drawPreviewItem(canvas, mAnimParams); 524a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen } 525d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 526d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 527d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen private void animateFirstItem(final Drawable d, int duration) { 528d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen computePreviewDrawingParams(d); 529d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null); 530d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 531d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen final float scale0 = 1.0f; 5321d4ee4e46218fb98a43cf584d8d4e3e569850f78Adam Cohen final float transX0 = (mAvailableSpaceInPreview - d.getIntrinsicWidth()) / 2; 5331d4ee4e46218fb98a43cf584d8d4e3e569850f78Adam Cohen final float transY0 = (mAvailableSpaceInPreview - d.getIntrinsicHeight()) / 2; 534d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mAnimParams.drawable = d; 535d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 536d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen ValueAnimator va = ValueAnimator.ofFloat(0f, 1.0f); 537d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen va.addUpdateListener(new AnimatorUpdateListener(){ 538d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen public void onAnimationUpdate(ValueAnimator animation) { 539d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen float progress = (Float) animation.getAnimatedValue(); 540d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen 541d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mAnimParams.transX = transX0 + progress * (finalParams.transX - transX0); 542d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mAnimParams.transY = transY0 + progress * (finalParams.transY - transY0); 543d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mAnimParams.scale = scale0 + progress * (finalParams.scale - scale0); 544d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen invalidate(); 545d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 546d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen }); 547d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen va.addListener(new AnimatorListenerAdapter() { 548d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen @Override 549d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen public void onAnimationStart(Animator animation) { 550d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mAnimating = true; 551d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 552d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen @Override 553d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen public void onAnimationEnd(Animator animation) { 554d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen mAnimating = false; 555d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen } 556d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen }); 557d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen va.setDuration(duration); 558d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen va.start(); 559a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen } 560a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen 561099f60d51f6310e1290687e83958e665b3324504Adam Cohen public void setTextVisible(boolean visible) { 562099f60d51f6310e1290687e83958e665b3324504Adam Cohen if (visible) { 563099f60d51f6310e1290687e83958e665b3324504Adam Cohen mFolderName.setVisibility(VISIBLE); 564099f60d51f6310e1290687e83958e665b3324504Adam Cohen } else { 565099f60d51f6310e1290687e83958e665b3324504Adam Cohen mFolderName.setVisibility(INVISIBLE); 566099f60d51f6310e1290687e83958e665b3324504Adam Cohen } 567099f60d51f6310e1290687e83958e665b3324504Adam Cohen } 568099f60d51f6310e1290687e83958e665b3324504Adam Cohen 569099f60d51f6310e1290687e83958e665b3324504Adam Cohen public boolean getTextVisible() { 570099f60d51f6310e1290687e83958e665b3324504Adam Cohen return mFolderName.getVisibility() == VISIBLE; 571099f60d51f6310e1290687e83958e665b3324504Adam Cohen } 572099f60d51f6310e1290687e83958e665b3324504Adam Cohen 57376078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen public void onItemsChanged() { 57476078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen invalidate(); 57576078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen requestLayout(); 57676078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen } 57776078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen 578a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen public void onAdd(ShortcutInfo item) { 579a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen invalidate(); 580a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen requestLayout(); 581a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen } 582a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen 583a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen public void onRemove(ShortcutInfo item) { 584a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen invalidate(); 585a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen requestLayout(); 586a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen } 58776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 58876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public void onTitleChanged(CharSequence title) { 589d63cfa96814fa1a51490950b8df9853eef305cbbAdam Cohen mFolderName.setText(title.toString()); 5906a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung mPreviewBackground.setContentDescription(title.toString()); 59176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen } 59231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 593