diff options
Diffstat (limited to 'src/com/android/launcher3/Workspace.java')
-rw-r--r-- | src/com/android/launcher3/Workspace.java | 1346 |
1 files changed, 360 insertions, 986 deletions
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 95215402c..fb0a54d3c 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -17,20 +17,18 @@ package com.android.launcher3; import android.animation.Animator; -import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; import android.animation.LayoutTransition; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; -import android.animation.TimeInterpolator; -import android.animation.ValueAnimator; -import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.app.WallpaperManager; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.content.res.TypedArray; @@ -43,12 +41,12 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region.Op; import android.graphics.drawable.Drawable; -import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Parcelable; -import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; @@ -66,14 +64,20 @@ import com.android.launcher3.FolderIcon.FolderRingAnimator; import com.android.launcher3.Launcher.CustomContentCallbacks; import com.android.launcher3.Launcher.LauncherOverlay; import com.android.launcher3.LauncherSettings.Favorites; -import com.android.launcher3.compat.PackageInstallerCompat; -import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; +import com.android.launcher3.UninstallDropTarget.UninstallSource; +import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; +import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource; +import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate; import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.util.LongArrayMap; +import com.android.launcher3.util.Thunk; +import com.android.launcher3.util.WallpaperUtils; +import com.android.launcher3.widget.PendingAddShortcutInfo; +import com.android.launcher3.widget.PendingAddWidgetInfo; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.concurrent.atomic.AtomicInteger; /** @@ -81,60 +85,45 @@ import java.util.concurrent.atomic.AtomicInteger; * Each page contains a number of icons, folders or widgets the user can * interact with. A workspace is meant to be used with a fixed width only. */ -public class Workspace extends SmoothPagedView +public class Workspace extends PagedView implements DropTarget, DragSource, DragScroller, View.OnTouchListener, DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener, - Insettable { + Insettable, UninstallSource, AccessibilityDragSource, Stats.LaunchSourceProvider { private static final String TAG = "Launcher.Workspace"; - private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0; - private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375; - private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100; + private static boolean ENFORCE_DRAG_EVENT_ORDER = false; protected static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400; protected static final int FADE_EMPTY_SCREEN_DURATION = 150; - private static final int BACKGROUND_FADE_OUT_DURATION = 350; private static final int ADJACENT_SCREEN_DROP_DURATION = 300; - private static final int FLING_THRESHOLD_VELOCITY = 500; - - private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f; static final boolean MAP_NO_RECURSE = false; static final boolean MAP_RECURSE = true; - // These animators are used to fade the children's outlines - private ObjectAnimator mChildrenOutlineFadeInAnimation; - private ObjectAnimator mChildrenOutlineFadeOutAnimation; - private float mChildrenOutlineAlpha = 0; - - // These properties refer to the background protection gradient used for AllApps and Customize - private ValueAnimator mBackgroundFadeInAnimation; - private ValueAnimator mBackgroundFadeOutAnimation; - private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200; private long mTouchDownTime = -1; private long mCustomContentShowTime = -1; private LayoutTransition mLayoutTransition; - private final WallpaperManager mWallpaperManager; - private IBinder mWindowToken; + @Thunk final WallpaperManager mWallpaperManager; + @Thunk IBinder mWindowToken; private int mOriginalDefaultPage; private int mDefaultPage; private ShortcutAndWidgetContainer mDragSourceInternal; - private static boolean sAccessibilityEnabled; // The screen id used for the empty screen always present to the right. final static long EXTRA_EMPTY_SCREEN_ID = -201; private final static long CUSTOM_CONTENT_SCREEN_ID = -301; - private HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>(); - private ArrayList<Long> mScreenOrder = new ArrayList<Long>(); + @Thunk LongArrayMap<CellLayout> mWorkspaceScreens = new LongArrayMap<>(); + @Thunk ArrayList<Long> mScreenOrder = new ArrayList<Long>(); - private Runnable mRemoveEmptyScreenRunnable; - private boolean mDeferRemoveExtraEmptyScreen = false; + @Thunk Runnable mRemoveEmptyScreenRunnable; + @Thunk boolean mDeferRemoveExtraEmptyScreen = false; + @Thunk boolean mAddNewPageOnDrag = true; /** * CellInfo for the cell that is currently being dragged @@ -144,7 +133,7 @@ public class Workspace extends SmoothPagedView /** * Target drop area calculated during last acceptDrop call. */ - private int[] mTargetCell = new int[2]; + @Thunk int[] mTargetCell = new int[2]; private int mDragOverX = -1; private int mDragOverY = -1; @@ -159,7 +148,7 @@ public class Workspace extends SmoothPagedView /** * The CellLayout that is currently being dragged over */ - private CellLayout mDragTargetLayout = null; + @Thunk CellLayout mDragTargetLayout = null; /** * The CellLayout that we will show as glowing */ @@ -170,16 +159,16 @@ public class Workspace extends SmoothPagedView */ private CellLayout mDropToLayout = null; - private Launcher mLauncher; - private IconCache mIconCache; - private DragController mDragController; + @Thunk Launcher mLauncher; + @Thunk IconCache mIconCache; + @Thunk DragController mDragController; // These are temporary variables to prevent having to allocate a new object just to // return an (x, y) value from helper functions. Do NOT use them to maintain other state. private int[] mTempCell = new int[2]; private int[] mTempPt = new int[2]; private int[] mTempEstimate = new int[2]; - private float[] mDragViewVisualCenter = new float[2]; + @Thunk float[] mDragViewVisualCenter = new float[2]; private float[] mTempCellLayoutCenterCoordinates = new float[2]; private Matrix mTempInverseMatrix = new Matrix(); @@ -204,20 +193,19 @@ public class Workspace extends SmoothPagedView private boolean mInScrollArea = false; private HolographicOutlineHelper mOutlineHelper; - private Bitmap mDragOutline = null; + @Thunk Bitmap mDragOutline = null; private static final Rect sTempRect = new Rect(); private final int[] mTempXY = new int[2]; private int[] mTempVisiblePagesRange = new int[2]; - private boolean mOverscrollEffectSet; public static final int DRAG_BITMAP_PADDING = 2; private boolean mWorkspaceFadeInAdjacentScreens; WallpaperOffsetInterpolator mWallpaperOffset; - private boolean mWallpaperIsLiveWallpaper; - private int mNumPagesForWallpaperParallax; - private float mLastSetWallpaperOffsetSteps = 0; + @Thunk boolean mWallpaperIsLiveWallpaper; + @Thunk int mNumPagesForWallpaperParallax; + @Thunk float mLastSetWallpaperOffsetSteps = 0; - private Runnable mDelayedResizeRunnable; + @Thunk Runnable mDelayedResizeRunnable; private Runnable mDelayedSnapToPageRunnable; private Point mDisplaySize = new Point(); @@ -226,11 +214,10 @@ public class Workspace extends SmoothPagedView public static final int REORDER_TIMEOUT = 350; private final Alarm mFolderCreationAlarm = new Alarm(); private final Alarm mReorderAlarm = new Alarm(); - private FolderRingAnimator mDragFolderRingAnimator = null; + @Thunk FolderRingAnimator mDragFolderRingAnimator = null; private FolderIcon mDragOverFolderIcon = null; private boolean mCreateUserFolderOnDrop = false; private boolean mAddToExistingFolderOnDrop = false; - private DropTarget.DragEnforcer mDragEnforcer; private float mMaxDistanceForFolderCreation; private final Canvas mCanvas = new Canvas(); @@ -255,8 +242,8 @@ public class Workspace extends SmoothPagedView private static final int DRAG_MODE_ADD_TO_FOLDER = 2; private static final int DRAG_MODE_REORDER = 3; private int mDragMode = DRAG_MODE_NONE; - private int mLastReorderX = -1; - private int mLastReorderY = -1; + @Thunk int mLastReorderX = -1; + @Thunk int mLastReorderY = -1; private SparseArray<Parcelable> mSavedStates; private final ArrayList<Integer> mRestoredPages = new ArrayList<Integer>(); @@ -267,18 +254,9 @@ public class Workspace extends SmoothPagedView private float mSavedTranslationX; private float mCurrentScale; - private float mNewScale; - private float[] mOldBackgroundAlphas; - private float[] mOldAlphas; - private float[] mNewBackgroundAlphas; - private float[] mNewAlphas; - private int mLastChildCount = -1; private float mTransitionProgress; - private Animator mStateAnimator = null; - float mOverScrollEffect = 0f; - - private Runnable mDeferredAction; + @Thunk Runnable mDeferredAction; private boolean mDeferDropAfterUninstall; private boolean mUninstallSuccessful; @@ -289,6 +267,11 @@ public class Workspace extends SmoothPagedView boolean mShouldSendPageSettled; int mLastOverlaySroll = 0; + // Handles workspace state transitions + private WorkspaceStateTransitionAnimation mStateTransitionAnimation; + + private AccessibilityDelegate mPagesAccessibilityDelegate; + private final Runnable mBindPages = new Runnable() { @Override public void run() { @@ -315,28 +298,22 @@ public class Workspace extends SmoothPagedView */ public Workspace(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mContentIsRefreshable = false; mOutlineHelper = HolographicOutlineHelper.obtain(context); - mDragEnforcer = new DropTarget.DragEnforcer(context); - // With workspace, data is available straight from the get-go - setDataIsReady(); - mLauncher = (Launcher) context; + mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this); final Resources res = getResources(); - mWorkspaceFadeInAdjacentScreens = LauncherAppState.getInstance().getDynamicGrid(). - getDeviceProfile().shouldFadeAdjacentWorkspaceScreens(); + DeviceProfile grid = mLauncher.getDeviceProfile(); + mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens(); mFadeInAdjacentScreens = false; mWallpaperManager = WallpaperManager.getInstance(context); - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0); mSpringLoadedShrinkFactor = res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f; - mOverviewModeShrinkFactor = grid.getOverviewModeScale(); + mOverviewModeShrinkFactor = grid.getOverviewModeScale(mIsRtl); mOriginalDefaultPage = mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1); a.recycle(); @@ -347,7 +324,6 @@ public class Workspace extends SmoothPagedView // Disable multitouch across the workspace/all apps/customize tray setMotionEventSplittingEnabled(true); - setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } @Override @@ -365,13 +341,12 @@ public class Workspace extends SmoothPagedView // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each // dimension if unsuccessful - public int[] estimateItemSize(int hSpan, int vSpan, - ItemInfo itemInfo, boolean springLoaded) { + public int[] estimateItemSize(ItemInfo itemInfo, boolean springLoaded) { int[] size = new int[2]; if (getChildCount() > 0) { // Use the first non-custom page to estimate the child position CellLayout cl = (CellLayout) getChildAt(numCustomPages()); - Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan); + Rect r = estimateItemPosition(cl, itemInfo, 0, 0, itemInfo.spanX, itemInfo.spanY); size[0] = r.width(); size[1] = r.height(); if (springLoaded) { @@ -393,32 +368,39 @@ public class Workspace extends SmoothPagedView return r; } + @Override public void onDragStart(final DragSource source, Object info, int dragAction) { + if (ENFORCE_DRAG_EVENT_ORDER) { + enfoceDragParity("onDragStart", 0, 0); + } + mIsDragOccuring = true; updateChildrenLayersEnabled(false); mLauncher.lockScreenOrientation(); mLauncher.onInteractionBegin(); - setChildrenBackgroundAlphaMultipliers(1f); // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging InstallShortcutReceiver.enableInstallQueue(); - UninstallShortcutReceiver.enableUninstallQueue(); - post(new Runnable() { - @Override - public void run() { - if (mIsDragOccuring) { - mDeferRemoveExtraEmptyScreen = false; - addExtraEmptyScreenOnDrag(); - } - } - }); + + if (mAddNewPageOnDrag) { + mDeferRemoveExtraEmptyScreen = false; + addExtraEmptyScreenOnDrag(); + } } + public void setAddNewPageOnDrag(boolean addPage) { + mAddNewPageOnDrag = addPage; + } public void deferRemoveExtraEmptyScreen() { mDeferRemoveExtraEmptyScreen = true; } + @Override public void onDragEnd() { + if (ENFORCE_DRAG_EVENT_ORDER) { + enfoceDragParity("onDragEnd", 0, 0); + } + if (!mDeferRemoveExtraEmptyScreen) { removeExtraEmptyScreen(true, mDragSourceInternal != null); } @@ -429,7 +411,6 @@ public class Workspace extends SmoothPagedView // Re-enable any Un/InstallShortcutReceiver and now process any queued items InstallShortcutReceiver.disableAndFlushInstallQueue(getContext()); - UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext()); mDragSourceInternal = null; mLauncher.onInteractionEnd(); @@ -441,7 +422,7 @@ public class Workspace extends SmoothPagedView protected void initWorkspace() { mCurrentPage = mDefaultPage; LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); mIconCache = app.getIconCache(); setWillNotDraw(false); setClipChildren(false); @@ -456,10 +437,11 @@ public class Workspace extends SmoothPagedView display.getSize(mDisplaySize); mMaxDistanceForFolderCreation = (0.55f * grid.iconSizePx); - mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity); // Set the wallpaper dimensions when Launcher starts up setWallpaperDimension(); + + setEdgeGlowColor(getResources().getColor(R.color.workspace_edge_effect_color)); } private void setupLayoutTransition() { @@ -480,11 +462,6 @@ public class Workspace extends SmoothPagedView } @Override - protected int getScrollMode() { - return SmoothPagedView.X_LARGE_MODE; - } - - @Override public void onChildViewAdded(View parent, View child) { if (!(child instanceof CellLayout)) { throw new IllegalArgumentException("A Workspace can only have CellLayout children."); @@ -492,7 +469,7 @@ public class Workspace extends SmoothPagedView CellLayout cl = ((CellLayout) child); cl.setOnInterceptTouchListener(this); cl.setClickable(true); - cl.setImportantForAccessibility(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO); + cl.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); super.onChildViewAdded(parent, child); } @@ -507,7 +484,7 @@ public class Workspace extends SmoothPagedView /** * @return The open folder on the current screen, or null if there is none */ - Folder getOpenFolder() { + public Folder getOpenFolder() { DragLayer dragLayer = mLauncher.getDragLayer(); int count = dragLayer.getChildCount(); for (int i = 0; i < count; i++) { @@ -561,16 +538,14 @@ public class Workspace extends SmoothPagedView } public long insertNewWorkspaceScreen(long screenId, int insertIndex) { - // Log to disk - Launcher.addDumpLog(TAG, "11683562 - insertNewWorkspaceScreen(): " + screenId + - " at index: " + insertIndex, true); - if (mWorkspaceScreens.containsKey(screenId)) { throw new RuntimeException("Screen id " + screenId + " already exists!"); } - CellLayout newScreen = (CellLayout) - mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null); + // Inflate the cell layout, but do not add it automatically so that we can get the newly + // created CellLayout. + CellLayout newScreen = (CellLayout) mLauncher.getLayoutInflater().inflate( + R.layout.workspace_screen, this, false /* attachToRoot */); newScreen.setOnLongClickListener(mLongClickListener); newScreen.setOnClickListener(mLauncher); @@ -578,13 +553,18 @@ public class Workspace extends SmoothPagedView mWorkspaceScreens.put(screenId, newScreen); mScreenOrder.add(insertIndex, screenId); addView(newScreen, insertIndex); + + LauncherAccessibilityDelegate delegate = + LauncherAppState.getInstance().getAccessibilityDelegate(); + if (delegate != null && delegate.isInAccessibleDrag()) { + newScreen.enableAccessibleDrag(true, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG); + } return screenId; } public void createCustomContentContainer() { CellLayout customScreen = (CellLayout) - mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null); - customScreen.disableBackground(); + mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, this, false); customScreen.disableDragTarget(); mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen); @@ -664,9 +644,6 @@ public class Workspace extends SmoothPagedView } public void addExtraEmptyScreenOnDrag() { - // Log to disk - Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreenOnDrag()", true); - boolean lastChildOnScreen = false; boolean childOnFinalScreen = false; @@ -693,9 +670,6 @@ public class Workspace extends SmoothPagedView } public boolean addExtraEmptyScreen() { - // Log to disk - Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreen()", true); - if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) { insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID); return true; @@ -704,9 +678,6 @@ public class Workspace extends SmoothPagedView } private void convertFinalScreenToEmptyScreenIfNecessary() { - // Log to disk - Launcher.addDumpLog(TAG, "11683562 - convertFinalScreenToEmptyScreenIfNecessary()", true); - if (mLauncher.isWorkspaceLoading()) { // Invalid and dangerous operation if workspace is loading Launcher.addDumpLog(TAG, " - workspace loading, skip", true); @@ -731,7 +702,6 @@ public class Workspace extends SmoothPagedView // Update the model if we have changed any screens mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder); - Launcher.addDumpLog(TAG, "11683562 - extra empty screen: " + finalScreenId, true); } } @@ -741,8 +711,6 @@ public class Workspace extends SmoothPagedView public void removeExtraEmptyScreenDelayed(final boolean animate, final Runnable onComplete, final int delay, final boolean stripEmptyScreens) { - // Log to disk - Launcher.addDumpLog(TAG, "11683562 - removeExtraEmptyScreen()", true); if (mLauncher.isWorkspaceLoading()) { // Don't strip empty screens if the workspace is still loading Launcher.addDumpLog(TAG, " - workspace loading, skip", true); @@ -767,6 +735,7 @@ public class Workspace extends SmoothPagedView fadeAndRemoveEmptyScreen(SNAP_OFF_EMPTY_SCREEN_DURATION, FADE_EMPTY_SCREEN_DURATION, onComplete, stripEmptyScreens); } else { + snapToPage(getNextPage(), 0); fadeAndRemoveEmptyScreen(0, FADE_EMPTY_SCREEN_DURATION, onComplete, stripEmptyScreens); } @@ -784,9 +753,7 @@ public class Workspace extends SmoothPagedView private void fadeAndRemoveEmptyScreen(int delay, int duration, final Runnable onComplete, final boolean stripEmptyScreens) { - // Log to disk // XXX: Do we need to update LM workspace screens below? - Launcher.addDumpLog(TAG, "11683562 - fadeAndRemoveEmptyScreen()", true); PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f); PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", 0f); @@ -830,8 +797,6 @@ public class Workspace extends SmoothPagedView } public long commitExtraEmptyScreen() { - // Log to disk - Launcher.addDumpLog(TAG, "11683562 - commitExtraEmptyScreen()", true); if (mLauncher.isWorkspaceLoading()) { // Invalid and dangerous operation if workspace is loading Launcher.addDumpLog(TAG, " - workspace loading, skip", true); @@ -864,12 +829,9 @@ public class Workspace extends SmoothPagedView } public long getIdForScreen(CellLayout layout) { - Iterator<Long> iter = mWorkspaceScreens.keySet().iterator(); - while (iter.hasNext()) { - long id = iter.next(); - if (mWorkspaceScreens.get(id) == layout) { - return id; - } + int index = mWorkspaceScreens.indexOfValue(layout); + if (index != -1) { + return mWorkspaceScreens.keyAt(index); } return -1; } @@ -885,14 +847,11 @@ public class Workspace extends SmoothPagedView return -1; } - ArrayList<Long> getScreenOrder() { + public ArrayList<Long> getScreenOrder() { return mScreenOrder; } public void stripEmptyScreens() { - // Log to disk - Launcher.addDumpLog(TAG, "11683562 - stripEmptyScreens()", true); - if (mLauncher.isWorkspaceLoading()) { // Don't strip empty screens if the workspace is still loading. // This is dangerous and can result in data loss. @@ -907,8 +866,10 @@ public class Workspace extends SmoothPagedView int currentPage = getNextPage(); ArrayList<Long> removeScreens = new ArrayList<Long>(); - for (Long id: mWorkspaceScreens.keySet()) { - CellLayout cl = mWorkspaceScreens.get(id); + int total = mWorkspaceScreens.size(); + for (int i = 0; i < total; i++) { + long id = mWorkspaceScreens.keyAt(i); + CellLayout cl = mWorkspaceScreens.valueAt(i); if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) { removeScreens.add(id); } @@ -920,7 +881,6 @@ public class Workspace extends SmoothPagedView int pageShift = 0; for (Long id: removeScreens) { - Launcher.addDumpLog(TAG, "11683562 - removing id: " + id, true); CellLayout cl = mWorkspaceScreens.get(id); mWorkspaceScreens.remove(id); mScreenOrder.remove(id); @@ -1064,6 +1024,7 @@ public class Workspace extends SmoothPagedView * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout * that it should intercept touch events, which is not something that is normally supported. */ + @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouch(View v, MotionEvent event) { return (workspaceInModalState() || !isFinishedSwitchingState()) @@ -1105,7 +1066,7 @@ public class Workspace extends SmoothPagedView case MotionEvent.ACTION_UP: if (mTouchState == TOUCH_STATE_REST) { final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage); - if (currentPage != null && !currentPage.lastDownOnOccupiedCell()) { + if (currentPage != null) { onWallpaperTap(ev); } } @@ -1167,7 +1128,7 @@ public class Workspace extends SmoothPagedView boolean passRightSwipesToCustomContent = (mTouchDownTime - mCustomContentShowTime) > CUSTOM_CONTENT_GESTURE_DELAY; - boolean swipeInIgnoreDirection = isLayoutRtl() ? deltaX < 0 : deltaX > 0; + boolean swipeInIgnoreDirection = mIsRtl ? deltaX < 0 : deltaX > 0; boolean onCustomContentScreen = getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID; if (swipeInIgnoreDirection && onCustomContentScreen && passRightSwipesToCustomContent) { @@ -1274,15 +1235,14 @@ public class Workspace extends SmoothPagedView @Override protected void overScroll(float amount) { - boolean isRtl = isLayoutRtl(); - boolean shouldOverScroll = (amount <= 0 && (!hasCustomContent() || isRtl)) || - (amount >= 0 && (!hasCustomContent() || !isRtl)); + boolean shouldOverScroll = (amount <= 0 && (!hasCustomContent() || mIsRtl)) || + (amount >= 0 && (!hasCustomContent() || !mIsRtl)); boolean shouldScrollOverlay = mLauncherOverlay != null && - ((amount <= 0 && !isRtl) || (amount >= 0 && isRtl)); + ((amount <= 0 && !mIsRtl) || (amount >= 0 && mIsRtl)); boolean shouldZeroOverlay = mLauncherOverlay != null && mLastOverlaySroll != 0 && - ((amount >= 0 && !isRtl) || (amount <= 0 && isRtl)); + ((amount >= 0 && !mIsRtl) || (amount <= 0 && mIsRtl)); if (shouldScrollOverlay) { if (!mStartedSendingScrollEvents && mScrollInteractionBegan) { @@ -1296,20 +1256,24 @@ public class Workspace extends SmoothPagedView int progress = (int) Math.abs((f * 100)); mLastOverlaySroll = progress; - mLauncherOverlay.onScrollChange(progress, isRtl); + mLauncherOverlay.onScrollChange(progress, mIsRtl); } else if (shouldOverScroll) { dampedOverScroll(amount); - mOverScrollEffect = acceleratedOverFactor(amount); - } else { - mOverScrollEffect = 0; } if (shouldZeroOverlay) { - mLauncherOverlay.onScrollChange(0, isRtl); + mLauncherOverlay.onScrollChange(0, mIsRtl); } } @Override + protected void getEdgeVerticalPostion(int[] pos) { + View child = getChildAt(getPageCount() - 1); + pos[0] = child.getTop(); + pos[1] = child.getBottom(); + } + + @Override protected void notifyPageSwitchListener() { super.notifyPageSwitchListener(); @@ -1334,10 +1298,10 @@ public class Workspace extends SmoothPagedView protected void setWallpaperDimension() { new AsyncTask<Void, Void, Void>() { public Void doInBackground(Void ... args) { - String spKey = WallpaperCropActivity.getSharedPreferencesKey(); + String spKey = LauncherFiles.WALLPAPER_CROP_PREFERENCES_KEY; SharedPreferences sp = mLauncher.getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS); - LauncherWallpaperPickerActivity.suggestWallpaperDimension(mLauncher.getResources(), + WallpaperUtils.suggestWallpaperDimension(mLauncher.getResources(), sp, mLauncher.getWindowManager(), mWallpaperManager, mLauncher.overrideWallpaperDimensions()); return null; @@ -1427,7 +1391,22 @@ public class Workspace extends SmoothPagedView } private float wallpaperOffsetForCurrentScroll() { + // TODO: do different behavior if it's a live wallpaper? + // Don't use up all the wallpaper parallax until you have at least + // MIN_PARALLAX_PAGE_SPAN pages + int numScrollingPages = getNumScreensExcludingEmptyAndCustom(); + int parallaxPageSpan; + if (mWallpaperIsLiveWallpaper) { + parallaxPageSpan = numScrollingPages - 1; + } else { + parallaxPageSpan = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages - 1); + } + mNumPagesForWallpaperParallax = parallaxPageSpan; + if (getChildCount() <= 1) { + if (mIsRtl) { + return 1 - 1.0f/mNumPagesForWallpaperParallax; + } return 0; } @@ -1436,7 +1415,7 @@ public class Workspace extends SmoothPagedView int firstIndex = numCustomPages(); // Exclude the last extra empty screen (if we have > MIN_PARALLAX_PAGE_SPAN pages) int lastIndex = getChildCount() - 1 - emptyExtraPages; - if (isLayoutRtl()) { + if (mIsRtl) { int temp = firstIndex; firstIndex = lastIndex; lastIndex = temp; @@ -1447,28 +1426,20 @@ public class Workspace extends SmoothPagedView if (scrollRange == 0) { return 0; } else { - // TODO: do different behavior if it's a live wallpaper? // Sometimes the left parameter of the pages is animated during a layout transition; // this parameter offsets it to keep the wallpaper from animating as well int adjustedScroll = getScrollX() - firstPageScrollX - getLayoutTransitionOffsetForPage(0); float offset = Math.min(1, adjustedScroll / (float) scrollRange); offset = Math.max(0, offset); - // Don't use up all the wallpaper parallax until you have at least - // MIN_PARALLAX_PAGE_SPAN pages - int numScrollingPages = getNumScreensExcludingEmptyAndCustom(); - int parallaxPageSpan; - if (mWallpaperIsLiveWallpaper) { - parallaxPageSpan = numScrollingPages - 1; - } else { - parallaxPageSpan = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages - 1); - } - mNumPagesForWallpaperParallax = parallaxPageSpan; // On RTL devices, push the wallpaper offset to the right if we don't have enough // pages (ie if numScrollingPages < MIN_PARALLAX_PAGE_SPAN) - int padding = isLayoutRtl() ? parallaxPageSpan - numScrollingPages + 1 : 0; - return offset * (padding + numScrollingPages - 1) / parallaxPageSpan; + if (!mWallpaperIsLiveWallpaper && numScrollingPages < MIN_PARALLAX_PAGE_SPAN + && mIsRtl) { + return offset * (parallaxPageSpan - numScrollingPages + 1) / parallaxPageSpan; + } + return offset * (numScrollingPages - 1) / parallaxPageSpan; } } @@ -1548,81 +1519,17 @@ public class Workspace extends SmoothPagedView @Override public void announceForAccessibility(CharSequence text) { // Don't announce if apps is on top of us. - if (!mLauncher.isAllAppsVisible()) { + if (!mLauncher.isAppsViewVisible()) { super.announceForAccessibility(text); } } - void showOutlines() { - if (!workspaceInModalState() && !mIsSwitchingState) { - if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel(); - if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel(); - mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f); - mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION); - mChildrenOutlineFadeInAnimation.start(); - } - } - - void hideOutlines() { - if (!workspaceInModalState() && !mIsSwitchingState) { - if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel(); - if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel(); - mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f); - mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION); - mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY); - mChildrenOutlineFadeOutAnimation.start(); - } - } - public void showOutlinesTemporarily() { if (!mIsPageMoving && !isTouchActive()) { snapToPage(mCurrentPage); } } - public void setChildrenOutlineAlpha(float alpha) { - mChildrenOutlineAlpha = alpha; - for (int i = 0; i < getChildCount(); i++) { - CellLayout cl = (CellLayout) getChildAt(i); - cl.setBackgroundAlpha(alpha); - } - } - - public float getChildrenOutlineAlpha() { - return mChildrenOutlineAlpha; - } - - private void animateBackgroundGradient(float finalAlpha, boolean animated) { - final DragLayer dragLayer = mLauncher.getDragLayer(); - - if (mBackgroundFadeInAnimation != null) { - mBackgroundFadeInAnimation.cancel(); - mBackgroundFadeInAnimation = null; - } - if (mBackgroundFadeOutAnimation != null) { - mBackgroundFadeOutAnimation.cancel(); - mBackgroundFadeOutAnimation = null; - } - float startAlpha = dragLayer.getBackgroundAlpha(); - if (finalAlpha != startAlpha) { - if (animated) { - mBackgroundFadeOutAnimation = - LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha); - mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() { - public void onAnimationUpdate(ValueAnimator animation) { - dragLayer.setBackgroundAlpha( - ((Float)animation.getAnimatedValue()).floatValue()); - } - }); - mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f)); - mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION); - mBackgroundFadeOutAnimation.start(); - } else { - dragLayer.setBackgroundAlpha(finalAlpha); - } - } - } - float backgroundAlphaInterpolator(float r) { float pivotA = 0.1f; float pivotB = 0.4f; @@ -1636,28 +1543,38 @@ public class Workspace extends SmoothPagedView } private void updatePageAlphaValues(int screenCenter) { - boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX; if (mWorkspaceFadeInAdjacentScreens && !workspaceInModalState() && - !mIsSwitchingState && - !isInOverscroll) { + !mIsSwitchingState) { for (int i = numCustomPages(); i < getChildCount(); i++) { CellLayout child = (CellLayout) getChildAt(i); if (child != null) { float scrollProgress = getScrollProgress(screenCenter, child, i); float alpha = 1 - Math.abs(scrollProgress); child.getShortcutsAndWidgets().setAlpha(alpha); - //child.setBackgroundAlphaMultiplier(1 - alpha); } } } } - private void setChildrenBackgroundAlphaMultipliers(float a) { + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @Override + public void enableAccessibleDrag(boolean enable) { for (int i = 0; i < getChildCount(); i++) { CellLayout child = (CellLayout) getChildAt(i); - child.setBackgroundAlphaMultiplier(a); + child.enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG); + } + + if (enable) { + // We need to allow our individual children to become click handlers in this case + setOnClickListener(null); + } else { + // Reset our click listener + setOnClickListener(mLauncher); } + mLauncher.getSearchBar().enableAccessibleDrag(enable); + mLauncher.getHotseat().getLayout() + .enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG); } public boolean hasCustomContent() { @@ -1684,7 +1601,7 @@ public class Workspace extends SmoothPagedView translationX = scrollRange - scrollDelta; progress = (scrollRange - scrollDelta) / scrollRange; - if (isLayoutRtl()) { + if (mIsRtl) { translationX = Math.min(0, translationX); } else { translationX = Math.max(0, translationX); @@ -1701,7 +1618,11 @@ public class Workspace extends SmoothPagedView mLastCustomContentScrollProgress = progress; - mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f); + // We should only update the drag layer background alpha if we are not in all apps or the + // widgets tray + if (mState == State.NORMAL) { + mLauncher.getDragLayer().setBackgroundAlpha(progress == 1 ? 0 : progress * 0.8f); + } if (mLauncher.getHotseat() != null) { mLauncher.getHotseat().setTranslationX(translationX); @@ -1726,7 +1647,7 @@ public class Workspace extends SmoothPagedView OnClickListener listener = new OnClickListener() { @Override public void onClick(View arg0) { - enterOverviewMode(); + mLauncher.showOverviewMode(true); } }; return listener; @@ -1734,35 +1655,9 @@ public class Workspace extends SmoothPagedView @Override protected void screenScrolled(int screenCenter) { - final boolean isRtl = isLayoutRtl(); - super.screenScrolled(screenCenter); - updatePageAlphaValues(screenCenter); updateStateForCustomContent(screenCenter); enableHwLayersOnVisiblePages(); - - boolean shouldOverScroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX; - - if (shouldOverScroll) { - int index = 0; - final int lowerIndex = 0; - final int upperIndex = getChildCount() - 1; - - final boolean isLeftPage = mOverScrollX < 0; - index = (!isRtl && isLeftPage) || (isRtl && !isLeftPage) ? lowerIndex : upperIndex; - - CellLayout cl = (CellLayout) getChildAt(index); - float effect = Math.abs(mOverScrollEffect); - cl.setOverScrollAmount(Math.abs(effect), isLeftPage); - - mOverscrollEffectSet = true; - } else { - if (mOverscrollEffectSet && getChildCount() > 0) { - mOverscrollEffectSet = false; - ((CellLayout) getChildAt(0)).setOverScrollAmount(0, false); - ((CellLayout) getChildAt(getChildCount() - 1)).setOverScrollAmount(0, false); - } - } } protected void onAttachedToWindow() { @@ -1786,9 +1681,6 @@ public class Workspace extends SmoothPagedView getPageIndicator().setOnClickListener(listener); } } - AccessibilityManager am = (AccessibilityManager) - getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); - sAccessibilityEnabled = am.isEnabled(); // Update wallpaper dimensions if they were changed since last onResume // (we also always set the wallpaper dimensions in the constructor) @@ -1820,7 +1712,7 @@ public class Workspace extends SmoothPagedView @Override protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { - if (!mLauncher.isAllAppsVisible()) { + if (!mLauncher.isAppsViewVisible()) { final Folder openFolder = getOpenFolder(); if (openFolder != null) { return openFolder.requestFocus(direction, previouslyFocusedRect); @@ -1841,7 +1733,7 @@ public class Workspace extends SmoothPagedView @Override public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { - if (!mLauncher.isAllAppsVisible()) { + if (!mLauncher.isAppsViewVisible()) { final Folder openFolder = getOpenFolder(); if (openFolder != null) { openFolder.addFocusables(views, direction); @@ -1886,7 +1778,7 @@ public class Workspace extends SmoothPagedView } } - private void updateChildrenLayersEnabled(boolean force) { + @Thunk void updateChildrenLayersEnabled(boolean force) { boolean small = mState == State.OVERVIEW || mIsSwitchingState; boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving(); @@ -1959,64 +1851,6 @@ public class Workspace extends SmoothPagedView } /* - * This interpolator emulates the rate at which the perceived scale of an object changes - * as its distance from a camera increases. When this interpolator is applied to a scale - * animation on a view, it evokes the sense that the object is shrinking due to moving away - * from the camera. - */ - static class ZInterpolator implements TimeInterpolator { - private float focalLength; - - public ZInterpolator(float foc) { - focalLength = foc; - } - - public float getInterpolation(float input) { - return (1.0f - focalLength / (focalLength + input)) / - (1.0f - focalLength / (focalLength + 1.0f)); - } - } - - /* - * The exact reverse of ZInterpolator. - */ - static class InverseZInterpolator implements TimeInterpolator { - private ZInterpolator zInterpolator; - public InverseZInterpolator(float foc) { - zInterpolator = new ZInterpolator(foc); - } - public float getInterpolation(float input) { - return 1 - zInterpolator.getInterpolation(1 - input); - } - } - - /* - * ZInterpolator compounded with an ease-out. - */ - static class ZoomOutInterpolator implements TimeInterpolator { - private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f); - private final ZInterpolator zInterpolator = new ZInterpolator(0.13f); - - public float getInterpolation(float input) { - return decelerate.getInterpolation(zInterpolator.getInterpolation(input)); - } - } - - /* - * InvereZInterpolator compounded with an ease-out. - */ - static class ZoomInInterpolator implements TimeInterpolator { - private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f); - private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f); - - public float getInterpolation(float input) { - return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input)); - } - } - - private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator(); - - /* * * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace @@ -2042,16 +1876,14 @@ public class Workspace extends SmoothPagedView public void onExternalDragStartedWithItem(View v) { // Compose a drag bitmap with the view scaled to the icon size - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); int iconSize = grid.iconSizePx; int bmpWidth = v.getMeasuredWidth(); int bmpHeight = v.getMeasuredHeight(); // If this is a text view, use its drawable instead if (v instanceof TextView) { - TextView tv = (TextView) v; - Drawable d = tv.getCompoundDrawables()[1]; + Drawable d = getTextViewIcon((TextView) v); Rect bounds = getDrawableBounds(d); bmpWidth = bounds.width(); bmpHeight = bounds.height(); @@ -2069,7 +1901,7 @@ public class Workspace extends SmoothPagedView } public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) { - int[] size = estimateItemSize(info.spanX, info.spanY, info, false); + int[] size = estimateItemSize(info, false); // The outline is used to visualize where the item will land if dropped mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha); @@ -2080,21 +1912,6 @@ public class Workspace extends SmoothPagedView dragLayer.clearAllResizeFrames(); } - private void initAnimationArrays() { - final int childCount = getChildCount(); - if (mLastChildCount == childCount) return; - - mOldBackgroundAlphas = new float[childCount]; - mOldAlphas = new float[childCount]; - mNewBackgroundAlphas = new float[childCount]; - mNewAlphas = new float[childCount]; - } - - Animator getChangeStateAnimation(final State state, boolean animated, - HashMap<View, Integer> layerViews) { - return getChangeStateAnimation(state, animated, 0, -1, layerViews); - } - @Override protected void getFreeScrollPageRange(int[] range) { getOverviewModePages(range); @@ -2108,14 +1925,13 @@ public class Workspace extends SmoothPagedView range[1] = Math.max(0, end); } - protected void onStartReordering() { + public void onStartReordering() { super.onStartReordering(); - showOutlines(); // Reordering handles its own animations, disable the automatic ones. disableLayoutTransitions(); } - protected void onEndReordering() { + public void onEndReordering() { super.onEndReordering(); if (mLauncher.isWorkspaceLoading()) { @@ -2123,7 +1939,6 @@ public class Workspace extends SmoothPagedView return; } - hideOutlines(); mScreenOrder.clear(); int count = getChildCount(); for (int i = 0; i < count; i++) { @@ -2141,44 +1956,8 @@ public class Workspace extends SmoothPagedView return mState == State.OVERVIEW; } - public boolean enterOverviewMode() { - if (mTouchState != TOUCH_STATE_REST) { - return false; - } - enableOverviewMode(true, -1, true); - return true; - } - - public void exitOverviewMode(boolean animated) { - exitOverviewMode(-1, animated); - } - - public void exitOverviewMode(int snapPage, boolean animated) { - enableOverviewMode(false, snapPage, animated); - } - - private void enableOverviewMode(boolean enable, int snapPage, boolean animated) { - State finalState = Workspace.State.OVERVIEW; - if (!enable) { - finalState = Workspace.State.NORMAL; - } - - Animator workspaceAnim = getChangeStateAnimation(finalState, animated, 0, snapPage); - if (workspaceAnim != null) { - onTransitionPrepare(); - workspaceAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator arg0) { - onTransitionEnd(); - } - }); - workspaceAnim.start(); - } - } - int getOverviewModeTranslationY() { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); Rect overviewBar = grid.getOverviewModeButtonBarRect(); int availableHeight = getViewportHeight(); @@ -2190,343 +1969,72 @@ public class Workspace extends SmoothPagedView return -offsetFromTopEdge + mInsets.top + offsetToCenterInOverview; } - public void updateInteractionForState() { - if (mState != State.NORMAL) { - mLauncher.onInteractionBegin(); - } else { - mLauncher.onInteractionEnd(); - } - } - - private void setState(State state) { - mState = state; - updateInteractionForState(); + /** + * Sets the current workspace {@link State}, returning an animation transitioning the workspace + * to that new state. + */ + public Animator setStateWithAnimation(State toState, int toPage, boolean animated, + boolean hasOverlaySearchBar, HashMap<View, Integer> layerViews) { + // Create the animation to the new state + Animator workspaceAnim = mStateTransitionAnimation.getAnimationToState(getState(), + toState, toPage, animated, hasOverlaySearchBar, layerViews); + + // Update the current state + mState = toState; updateAccessibilityFlags(); + + return workspaceAnim; } State getState() { return mState; } - private void updateAccessibilityFlags() { - int accessible = mState == State.NORMAL ? - ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES : - ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; - setImportantForAccessibility(accessible); - } - - private static final int HIDE_WORKSPACE_DURATION = 100; - - Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) { - return getChangeStateAnimation(state, animated, delay, snapPage, null); - } - - Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage, - HashMap<View, Integer> layerViews) { - if (mState == state) { - return null; - } - - // Initialize animation arrays for the first time if necessary - initAnimationArrays(); - - AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null; - - // We only want a single instance of a workspace animation to be running at once, so - // we cancel any incomplete transition. - if (mStateAnimator != null) { - mStateAnimator.cancel(); - } - mStateAnimator = anim; - - final State oldState = mState; - final boolean oldStateIsNormal = (oldState == State.NORMAL); - final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED); - final boolean oldStateIsNormalHidden = (oldState == State.NORMAL_HIDDEN); - final boolean oldStateIsOverviewHidden = (oldState == State.OVERVIEW_HIDDEN); - final boolean oldStateIsOverview = (oldState == State.OVERVIEW); - setState(state); - final boolean stateIsNormal = (state == State.NORMAL); - final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED); - final boolean stateIsNormalHidden = (state == State.NORMAL_HIDDEN); - final boolean stateIsOverviewHidden = (state == State.OVERVIEW_HIDDEN); - final boolean stateIsOverview = (state == State.OVERVIEW); - float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f; - float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f; - float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f; - float finalSearchBarAlpha = !stateIsNormal ? 0f : 1f; - float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ? - getOverviewModeTranslationY() : 0; - - boolean workspaceToAllApps = (oldStateIsNormal && stateIsNormalHidden); - boolean overviewToAllApps = (oldStateIsOverview && stateIsOverviewHidden); - boolean allAppsToWorkspace = (stateIsNormalHidden && stateIsNormal); - boolean workspaceToOverview = (oldStateIsNormal && stateIsOverview); - boolean overviewToWorkspace = (oldStateIsOverview && stateIsNormal); - - mNewScale = 1.0f; - - if (oldStateIsOverview) { - disableFreeScroll(); - } else if (stateIsOverview) { - enableFreeScroll(); - } - - if (state != State.NORMAL) { - if (stateIsSpringLoaded) { - mNewScale = mSpringLoadedShrinkFactor; - } else if (stateIsOverview || stateIsOverviewHidden) { - mNewScale = mOverviewModeShrinkFactor; - } - } - - final int duration; - if (workspaceToAllApps || overviewToAllApps) { - duration = HIDE_WORKSPACE_DURATION; //getResources().getInteger(R.integer.config_workspaceUnshrinkTime); - } else if (workspaceToOverview || overviewToWorkspace) { - duration = getResources().getInteger(R.integer.config_overviewTransitionTime); - } else { - duration = getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime); - } - - if (snapPage == -1) { - snapPage = getPageNearestToCenterOfScreen(); - } - snapToPage(snapPage, duration, mZoomInInterpolator); - - for (int i = 0; i < getChildCount(); i++) { - final CellLayout cl = (CellLayout) getChildAt(i); - boolean isCurrentPage = (i == snapPage); - float initialAlpha = cl.getShortcutsAndWidgets().getAlpha(); - float finalAlpha; - if (stateIsNormalHidden || stateIsOverviewHidden) { - finalAlpha = 0f; - } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) { - finalAlpha = (i == snapPage || i < numCustomPages()) ? 1f : 0f; - } else { - finalAlpha = 1f; - } - - // If we are animating to/from the small state, then hide the side pages and fade the - // current page in - if (!mIsSwitchingState) { - if (workspaceToAllApps || allAppsToWorkspace) { - if (allAppsToWorkspace && isCurrentPage) { - initialAlpha = 0f; - } else if (!isCurrentPage) { - initialAlpha = finalAlpha = 0f; - } - cl.setShortcutAndWidgetAlpha(initialAlpha); - } - } - - mOldAlphas[i] = initialAlpha; - mNewAlphas[i] = finalAlpha; - if (animated) { - mOldBackgroundAlphas[i] = cl.getBackgroundAlpha(); - mNewBackgroundAlphas[i] = finalBackgroundAlpha; - } else { - cl.setBackgroundAlpha(finalBackgroundAlpha); - cl.setShortcutAndWidgetAlpha(finalAlpha); - } - } - - final View searchBar = mLauncher.getQsbBar(); - final View overviewPanel = mLauncher.getOverviewPanel(); - final View hotseat = mLauncher.getHotseat(); - final View pageIndicator = getPageIndicator(); - if (animated) { - LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this); - scale.scaleX(mNewScale) - .scaleY(mNewScale) - .translationY(finalWorkspaceTranslationY) - .setDuration(duration) - .setInterpolator(mZoomInInterpolator); - anim.play(scale); - for (int index = 0; index < getChildCount(); index++) { - final int i = index; - final CellLayout cl = (CellLayout) getChildAt(i); - float currentAlpha = cl.getShortcutsAndWidgets().getAlpha(); - if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) { - cl.setBackgroundAlpha(mNewBackgroundAlphas[i]); - cl.setShortcutAndWidgetAlpha(mNewAlphas[i]); - } else { - if (layerViews != null) { - layerViews.put(cl, Launcher.BUILD_LAYER); - } - if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) { - LauncherViewPropertyAnimator alphaAnim = - new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets()); - alphaAnim.alpha(mNewAlphas[i]) - .setDuration(duration) - .setInterpolator(mZoomInInterpolator); - anim.play(alphaAnim); - } - if (mOldBackgroundAlphas[i] != 0 || - mNewBackgroundAlphas[i] != 0) { - ValueAnimator bgAnim = - LauncherAnimUtils.ofFloat(cl, 0f, 1f); - bgAnim.setInterpolator(mZoomInInterpolator); - bgAnim.setDuration(duration); - bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() { - public void onAnimationUpdate(float a, float b) { - cl.setBackgroundAlpha( - a * mOldBackgroundAlphas[i] + - b * mNewBackgroundAlphas[i]); - } - }); - anim.play(bgAnim); - } - } + public void updateAccessibilityFlags() { + if (Utilities.isLmpOrAbove()) { + int total = getPageCount(); + for (int i = numCustomPages(); i < total; i++) { + updateAccessibilityFlags((CellLayout) getPageAt(i), i); } - Animator pageIndicatorAlpha = null; - if (pageIndicator != null) { - pageIndicatorAlpha = new LauncherViewPropertyAnimator(pageIndicator) - .alpha(finalHotseatAndPageIndicatorAlpha).withLayer(); - pageIndicatorAlpha.addListener(new AlphaUpdateListener(pageIndicator)); - } else { - // create a dummy animation so we don't need to do null checks later - pageIndicatorAlpha = ValueAnimator.ofFloat(0, 0); - } - - LauncherViewPropertyAnimator hotseatAlpha = new LauncherViewPropertyAnimator(hotseat) - .alpha(finalHotseatAndPageIndicatorAlpha); - hotseatAlpha.addListener(new AlphaUpdateListener(hotseat)); - - LauncherViewPropertyAnimator overviewPanelAlpha = - new LauncherViewPropertyAnimator(overviewPanel).alpha(finalOverviewPanelAlpha); - overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel)); - - // For animation optimations, we may need to provide the Launcher transition - // with a set of views on which to force build layers in certain scenarios. - hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null); - overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null); - if (layerViews != null) { - // If layerViews is not null, we add these views, and indicate that - // the caller can manage layer state. - layerViews.put(hotseat, Launcher.BUILD_AND_SET_LAYER); - layerViews.put(overviewPanel, Launcher.BUILD_AND_SET_LAYER); - } else { - // Otherwise let the animator handle layer management. - hotseatAlpha.withLayer(); - overviewPanelAlpha.withLayer(); - } - - if (workspaceToOverview) { - pageIndicatorAlpha.setInterpolator(new DecelerateInterpolator(2)); - hotseatAlpha.setInterpolator(new DecelerateInterpolator(2)); - overviewPanelAlpha.setInterpolator(null); - } else if (overviewToWorkspace) { - pageIndicatorAlpha.setInterpolator(null); - hotseatAlpha.setInterpolator(null); - overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2)); - } - - overviewPanelAlpha.setDuration(duration); - pageIndicatorAlpha.setDuration(duration); - hotseatAlpha.setDuration(duration); - - if (searchBar != null) { - LauncherViewPropertyAnimator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar) - .alpha(finalSearchBarAlpha); - searchBarAlpha.addListener(new AlphaUpdateListener(searchBar)); - searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null); - if (layerViews != null) { - // If layerViews is not null, we add these views, and indicate that - // the caller can manage layer state. - layerViews.put(searchBar, Launcher.BUILD_AND_SET_LAYER); - } else { - // Otherwise let the animator handle layer management. - searchBarAlpha.withLayer(); - } - searchBarAlpha.setDuration(duration); - anim.play(searchBarAlpha); - } - - anim.play(overviewPanelAlpha); - anim.play(hotseatAlpha); - anim.play(pageIndicatorAlpha); - anim.setStartDelay(delay); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mStateAnimator = null; - } - }); - } else { - overviewPanel.setAlpha(finalOverviewPanelAlpha); - AlphaUpdateListener.updateVisibility(overviewPanel); - hotseat.setAlpha(finalHotseatAndPageIndicatorAlpha); - AlphaUpdateListener.updateVisibility(hotseat); - if (pageIndicator != null) { - pageIndicator.setAlpha(finalHotseatAndPageIndicatorAlpha); - AlphaUpdateListener.updateVisibility(pageIndicator); - } - if (searchBar != null) { - searchBar.setAlpha(finalSearchBarAlpha); - AlphaUpdateListener.updateVisibility(searchBar); - } - updateCustomContentVisibility(); - setScaleX(mNewScale); - setScaleY(mNewScale); - setTranslationY(finalWorkspaceTranslationY); - } - - if (stateIsNormal) { - animateBackgroundGradient(0f, animated); } else { - animateBackgroundGradient(getResources().getInteger( - R.integer.config_workspaceScrimAlpha) / 100f, animated); + int accessible = mState == State.NORMAL ? + IMPORTANT_FOR_ACCESSIBILITY_AUTO : + IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; + setImportantForAccessibility(accessible); } - return anim; } - static class AlphaUpdateListener implements AnimatorUpdateListener, AnimatorListener { - View view; - public AlphaUpdateListener(View v) { - view = v; - } - - @Override - public void onAnimationUpdate(ValueAnimator arg0) { - updateVisibility(view); - } + private void updateAccessibilityFlags(CellLayout page, int pageNo) { + if (mState == State.OVERVIEW) { + page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + page.getShortcutsAndWidgets().setImportantForAccessibility( + IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + page.setContentDescription(getPageDescription(pageNo)); - public static void updateVisibility(View view) { - // We want to avoid the extra layout pass by setting the views to GONE unless - // accessibility is on, in which case not setting them to GONE causes a glitch. - int invisibleState = sAccessibilityEnabled ? GONE : INVISIBLE; - if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) { - view.setVisibility(invisibleState); - } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD - && view.getVisibility() != VISIBLE) { - view.setVisibility(VISIBLE); + if (mPagesAccessibilityDelegate == null) { + mPagesAccessibilityDelegate = new OverviewScreenAccessibilityDelegate(this); } - } - - @Override - public void onAnimationCancel(Animator arg0) { - } - - @Override - public void onAnimationEnd(Animator arg0) { - updateVisibility(view); - } - - @Override - public void onAnimationRepeat(Animator arg0) { - } - - @Override - public void onAnimationStart(Animator arg0) { - // We want the views to be visible for animation, so fade-in/out is visible - view.setVisibility(VISIBLE); + page.setAccessibilityDelegate(mPagesAccessibilityDelegate); + } else { + int accessible = mState == State.NORMAL ? + IMPORTANT_FOR_ACCESSIBILITY_AUTO : + IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; + page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + page.getShortcutsAndWidgets().setImportantForAccessibility(accessible); + page.setContentDescription(null); + page.setAccessibilityDelegate(null); } } @Override public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) { - onTransitionPrepare(); + mIsSwitchingState = true; + + // Invalidate here to ensure that the pages are rendered during the state change transition. + invalidate(); + + updateChildrenLayersEnabled(false); + hideCustomContentIfNecessary(); } @Override @@ -2540,17 +2048,9 @@ public class Workspace extends SmoothPagedView @Override public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) { - onTransitionEnd(); - } - - private void onTransitionPrepare() { - mIsSwitchingState = true; - - // Invalidate here to ensure that the pages are rendered during the state change transition. - invalidate(); - + mIsSwitchingState = false; updateChildrenLayersEnabled(false); - hideCustomContentIfNecessary(); + showCustomContentIfNecessary(); } void updateCustomContentVisibility() { @@ -2576,15 +2076,17 @@ public class Workspace extends SmoothPagedView } } - private void onTransitionEnd() { - mIsSwitchingState = false; - updateChildrenLayersEnabled(false); - showCustomContentIfNecessary(); - } - - @Override - public View getContent() { - return this; + /** + * Returns the drawable for the given text view. + */ + public static Drawable getTextViewIcon(TextView tv) { + final Drawable[] drawables = tv.getCompoundDrawables(); + for (int i = 0; i < drawables.length; i++) { + if (drawables[i] != null) { + return drawables[i]; + } + } + return null; } /** @@ -2602,7 +2104,7 @@ public class Workspace extends SmoothPagedView destCanvas.save(); if (v instanceof TextView) { - Drawable d = ((TextView) v).getCompoundDrawables()[1]; + Drawable d = getTextViewIcon((TextView) v); Rect bounds = getDrawableBounds(d); clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding); destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top); @@ -2639,7 +2141,7 @@ public class Workspace extends SmoothPagedView int padding = expectedPadding.get(); if (v instanceof TextView) { - Drawable d = ((TextView) v).getCompoundDrawables()[1]; + Drawable d = getTextViewIcon((TextView) v); Rect bounds = getDrawableBounds(d); b = Bitmap.createBitmap(bounds.width() + padding, bounds.height() + padding, Bitmap.Config.ARGB_8888); @@ -2700,7 +2202,12 @@ public class Workspace extends SmoothPagedView return b; } - void startDrag(CellLayout.CellInfo cellInfo) { + public void startDrag(CellLayout.CellInfo cellInfo) { + startDrag(cellInfo, false); + } + + @Override + public void startDrag(CellLayout.CellInfo cellInfo, boolean accessible) { View child = cellInfo.cell; // Make sure the drag was started by a long press as opposed to a long click. @@ -2713,10 +2220,15 @@ public class Workspace extends SmoothPagedView CellLayout layout = (CellLayout) child.getParent().getParent(); layout.prepareChildForDrag(child); - beginDragShared(child, this); + beginDragShared(child, this, accessible); + } + + public void beginDragShared(View child, DragSource source, boolean accessible) { + beginDragShared(child, new Point(), source, accessible); } - public void beginDragShared(View child, DragSource source) { + public void beginDragShared(View child, Point relativeTouchPos, DragSource source, + boolean accessible) { child.clearFocus(); child.setPressed(false); @@ -2736,16 +2248,27 @@ public class Workspace extends SmoothPagedView int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2 - padding.get() / 2); - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); Point dragVisualizeOffset = null; Rect dragRect = null; if (child instanceof BubbleTextView) { + BubbleTextView icon = (BubbleTextView) child; int iconSize = grid.iconSizePx; int top = child.getPaddingTop(); int left = (bmpWidth - iconSize) / 2; int right = left + iconSize; int bottom = top + iconSize; + if (icon.isLayoutHorizontal()) { + // If the layout is horizontal, then if we are just picking up the icon, then just + // use the child position since the icon is top-left aligned. Otherwise, offset + // the drag layer position horizontally so that the icon is under the current + // touch position. + if (icon.getIcon().getBounds().contains(relativeTouchPos.x, relativeTouchPos.y)) { + dragLayerX = Math.round(mTempXY[0]); + } else { + dragLayerX = Math.round(mTempXY[0] + relativeTouchPos.x - (bmpWidth / 2)); + } + } dragLayerY += top; // Note: The drag region is used to calculate drag layer offsets, but the // dragVisualizeOffset in addition to the dragRect (the size) to position the outline. @@ -2770,7 +2293,7 @@ public class Workspace extends SmoothPagedView } DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), - DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale); + DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale, accessible); dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor()); if (child.getParent() instanceof ShortcutAndWidgetContainer) { @@ -2781,8 +2304,7 @@ public class Workspace extends SmoothPagedView } public void beginExternalDragShared(View child, DragSource source) { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); int iconSize = grid.iconSizePx; // Notify launcher of drag start @@ -2820,25 +2342,13 @@ public class Workspace extends SmoothPagedView // Start the drag DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), - DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale); + DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale, false); dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor()); // Recycle temporary bitmaps tmpB.recycle(); } - void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId, - int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) { - View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info); - - final int[] cellXY = new int[2]; - target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY); - addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst); - - LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0], - cellXY[1]); - } - public boolean transitionStateShouldAllowDrop() { return ((!isSwitchingState() || mTransitionProgress > 0.5f) && (mState == State.NORMAL || mState == State.SPRING_LOADED)); @@ -2857,8 +2367,7 @@ public class Workspace extends SmoothPagedView } if (!transitionStateShouldAllowDrop()) return false; - mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, - d.dragView, mDragViewVisualCenter); + mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter); // We want the point to be mapped to the dragTarget. if (mLauncher.isHotseatLayout(dropTargetLayout)) { @@ -3059,10 +2568,11 @@ public class Workspace extends SmoothPagedView return false; } - public void onDrop(final DragObject d) { - mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, - mDragViewVisualCenter); + @Override + public void prepareAccessibilityDrop() { } + public void onDrop(final DragObject d) { + mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter); CellLayout dropTargetLayout = mDropToLayout; // We want the point to be mapped to the dragTarget. @@ -3074,7 +2584,7 @@ public class Workspace extends SmoothPagedView } } - int snapScreen = -1; + int snapScreen = WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE; boolean resizeOnDrop = false; if (d.dragSource != this) { final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0], @@ -3178,7 +2688,8 @@ public class Workspace extends SmoothPagedView final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell; AppWidgetProviderInfo pInfo = hostView.getAppWidgetInfo(); - if (pInfo != null && pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) { + if (pInfo != null && pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE + && !d.accessibleDrag) { final Runnable addResizeFrame = new Runnable() { public void run() { DragLayer dragLayer = mLauncher.getDragLayer(); @@ -3234,7 +2745,9 @@ public class Workspace extends SmoothPagedView animateWidgetDrop(info, parent, d.dragView, onCompleteRunnable, animationType, cell, false); } else { - int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION; + int duration = snapScreen < 0 ? + WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE : + ADJACENT_SCREEN_DROP_DURATION; mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration, onCompleteRunnable, this); } @@ -3281,8 +2794,12 @@ public class Workspace extends SmoothPagedView location[1] = vY - y; } + @Override public void onDragEnter(DragObject d) { - mDragEnforcer.onDragEnter(); + if (ENFORCE_DRAG_EVENT_ORDER) { + enfoceDragParity("onDragEnter", 1, 1); + } + mCreateUserFolderOnDrop = false; mAddToExistingFolderOnDrop = false; @@ -3300,42 +2817,46 @@ public class Workspace extends SmoothPagedView * widthGap/heightGap (right, bottom) */ static Rect getCellLayoutMetrics(Launcher launcher, int orientation) { LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + InvariantDeviceProfile inv = app.getInvariantDeviceProfile(); Display display = launcher.getWindowManager().getDefaultDisplay(); Point smallestSize = new Point(); Point largestSize = new Point(); display.getCurrentSizeRange(smallestSize, largestSize); - int countX = (int) grid.numColumns; - int countY = (int) grid.numRows; + int countX = (int) inv.numColumns; + int countY = (int) inv.numRows; + boolean isLayoutRtl = Utilities.isRtl(launcher.getResources()); if (orientation == CellLayout.LANDSCAPE) { if (mLandscapeCellLayoutMetrics == null) { - Rect padding = grid.getWorkspacePadding(CellLayout.LANDSCAPE); + Rect padding = inv.landscapeProfile.getWorkspacePadding(isLayoutRtl); int width = largestSize.x - padding.left - padding.right; int height = smallestSize.y - padding.top - padding.bottom; mLandscapeCellLayoutMetrics = new Rect(); mLandscapeCellLayoutMetrics.set( - grid.calculateCellWidth(width, countX), - grid.calculateCellHeight(height, countY), 0, 0); + DeviceProfile.calculateCellWidth(width, countX), + DeviceProfile.calculateCellHeight(height, countY), 0, 0); } return mLandscapeCellLayoutMetrics; } else if (orientation == CellLayout.PORTRAIT) { if (mPortraitCellLayoutMetrics == null) { - Rect padding = grid.getWorkspacePadding(CellLayout.PORTRAIT); + Rect padding = inv.portraitProfile.getWorkspacePadding(isLayoutRtl); int width = smallestSize.x - padding.left - padding.right; int height = largestSize.y - padding.top - padding.bottom; mPortraitCellLayoutMetrics = new Rect(); mPortraitCellLayoutMetrics.set( - grid.calculateCellWidth(width, countX), - grid.calculateCellHeight(height, countY), 0, 0); + DeviceProfile.calculateCellWidth(width, countX), + DeviceProfile.calculateCellHeight(height, countY), 0, 0); } return mPortraitCellLayoutMetrics; } return null; } + @Override public void onDragExit(DragObject d) { - mDragEnforcer.onDragExit(); + if (ENFORCE_DRAG_EVENT_ORDER) { + enfoceDragParity("onDragExit", -1, 0); + } // Here we store the final page that will be dropped to, if the workspace in fact // receives the drop @@ -3364,12 +2885,27 @@ public class Workspace extends SmoothPagedView mSpringLoadedDragController.cancel(); - if (!mIsPageMoving) { - hideOutlines(); - } mLauncher.getDragLayer().hidePageHints(); } + private void enfoceDragParity(String event, int update, int expectedValue) { + enfoceDragParity(this, event, update, expectedValue); + for (int i = 0; i < getChildCount(); i++) { + enfoceDragParity(getChildAt(i), event, update, expectedValue); + } + } + + private void enfoceDragParity(View v, String event, int update, int expectedValue) { + Object tag = v.getTag(R.id.drag_event_parity); + int value = tag == null ? 0 : (Integer) tag; + value += update; + v.setTag(R.id.drag_event_parity, value); + + if (value != expectedValue) { + Log.e(TAG, event + ": Drag contract violated: " + value); + } + } + void setCurrentDropLayout(CellLayout layout) { if (mDragTargetLayout != null) { mDragTargetLayout.revertTempState(); @@ -3473,8 +3009,7 @@ public class Workspace extends SmoothPagedView mTempPt[1] = y; mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true); - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); r = grid.getHotseatRect(); if (r.contains(mTempPt[0], mTempPt[1])) { return true; @@ -3568,38 +3103,6 @@ public class Workspace extends SmoothPagedView return bestMatchingScreen; } - // This is used to compute the visual center of the dragView. This point is then - // used to visualize drop locations and determine where to drop an item. The idea is that - // the visual center represents the user's interpretation of where the item is, and hence - // is the appropriate point to use when determining drop location. - private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset, - DragView dragView, float[] recycle) { - float res[]; - if (recycle == null) { - res = new float[2]; - } else { - res = recycle; - } - - // First off, the drag view has been shifted in a way that is not represented in the - // x and y values or the x/yOffsets. Here we account for that shift. - x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX); - y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY); - - // These represent the visual top and left of drag view if a dragRect was provided. - // If a dragRect was not provided, then they correspond to the actual view left and - // top, as the dragRect is in that case taken to be the entire dragView. - // R.dimen.dragViewOffsetY. - int left = x - xOffset; - int top = y - yOffset; - - // In order to find the visual center, we shift by half the dragRect - res[0] = left + dragView.getDragRegion().width() / 2; - res[1] = top + dragView.getDragRegion().height() / 2; - - return res; - } - private boolean isDragWidget(DragObject d) { return (d.dragInfo instanceof LauncherAppWidgetInfo || d.dragInfo instanceof PendingAddWidgetInfo); @@ -3624,8 +3127,7 @@ public class Workspace extends SmoothPagedView // Ensure that we have proper spans for the item that we are dropping if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found"); - mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, - d.dragView, mDragViewVisualCenter); + mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter); final View child = (mDragInfo == null) ? null : mDragInfo.cell; // Identify whether we have dragged over a side page @@ -3700,7 +3202,7 @@ public class Workspace extends SmoothPagedView mTargetCell[1]); manageFolderFeedback(info, mDragTargetLayout, mTargetCell, - targetCellDistance, dragOverView); + targetCellDistance, dragOverView, d.accessibleDrag); boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX, @@ -3738,15 +3240,21 @@ public class Workspace extends SmoothPagedView } private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout, - int[] targetCell, float distance, View dragOverView) { + int[] targetCell, float distance, View dragOverView, boolean accessibleDrag) { boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance, false); - if (mDragMode == DRAG_MODE_NONE && userFolderPending && !mFolderCreationAlarm.alarmPending()) { - mFolderCreationAlarm.setOnAlarmListener(new - FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1])); - mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT); + + FolderCreationAlarmListener listener = new + FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]); + + if (!accessibleDrag) { + mFolderCreationAlarm.setOnAlarmListener(listener); + mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT); + } else { + listener.onAlarm(mFolderCreationAlarm); + } return; } @@ -3983,8 +3491,7 @@ public class Workspace extends SmoothPagedView // Came from all apps -- make a copy info = ((AppInfo) info).makeShortcut(); } - view = mLauncher.createShortcut(R.layout.application, cellLayout, - (ShortcutInfo) info); + view = mLauncher.createShortcut(cellLayout, (ShortcutInfo) info); break; case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout, @@ -4043,8 +3550,7 @@ public class Workspace extends SmoothPagedView } public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) { - int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX, - widgetInfo.spanY, widgetInfo, false); + int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo, false); int visibility = layout.getVisibility(); layout.setVisibility(VISIBLE); @@ -4115,7 +3621,6 @@ public class Workspace extends SmoothPagedView // In the case where we've prebound the widget, we remove it from the DragLayer if (finalView instanceof AppWidgetHostView && external) { - Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView"); mLauncher.getDragLayer().removeView(finalView); } @@ -4161,8 +3666,8 @@ public class Workspace extends SmoothPagedView public void setFinalTransitionTransform(CellLayout layout) { if (isSwitchingState()) { mCurrentScale = getScaleX(); - setScaleX(mNewScale); - setScaleY(mNewScale); + setScaleX(mStateTransitionAnimation.getFinalScale()); + setScaleY(mStateTransitionAnimation.getFinalScale()); } } public void resetTransitionTransform(CellLayout layout) { @@ -4199,7 +3704,7 @@ public class Workspace extends SmoothPagedView * * pixelX and pixelY should be in the coordinate system of layout */ - private int[] findNearestArea(int pixelX, int pixelY, + @Thunk int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, CellLayout layout, int[] recycle) { return layout.findNearestArea( pixelX, pixelY, spanX, spanY, recycle); @@ -4236,19 +3741,14 @@ public class Workspace extends SmoothPagedView removeWorkspaceItem(mDragInfo.cell); } } else if (mDragInfo != null) { - CellLayout cellLayout; - if (mLauncher.isHotseatLayout(target)) { - cellLayout = mLauncher.getHotseat().getLayout(); - } else { - cellLayout = getScreenWithId(mDragInfo.screenId); - } - if (cellLayout == null && LauncherAppState.isDogfoodBuild()) { - throw new RuntimeException("Invalid state: cellLayout == null in " - + "Workspace#onDropCompleted. Please file a bug. "); - } + final CellLayout cellLayout = mLauncher.getCellLayout( + mDragInfo.container, mDragInfo.screenId); if (cellLayout != null) { cellLayout.onDropChild(mDragInfo.cell); - } + } else if (LauncherAppState.isDogfoodBuild()) { + throw new RuntimeException("Invalid state: cellLayout == null in " + + "Workspace#onDropCompleted. Please file a bug. "); + }; } if ((d.cancelled || (beingCalledAfterUninstall && !mUninstallSuccessful)) && mDragInfo.cell != null) { @@ -4258,6 +3758,9 @@ public class Workspace extends SmoothPagedView mDragInfo = null; } + /** + * For opposite operation. See {@link #addInScreen}. + */ public void removeWorkspaceItem(View v) { CellLayout parentCell = getParentCellLayoutForView(v); if (parentCell != null) { @@ -4270,11 +3773,13 @@ public class Workspace extends SmoothPagedView } } + @Override public void deferCompleteDropAfterUninstallActivity() { mDeferDropAfterUninstall = true; } /// maybe move this into a smaller part + @Override public void onUninstallActivityReturned(boolean success) { mDeferDropAfterUninstall = false; mUninstallSuccessful = success; @@ -4306,88 +3811,6 @@ public class Workspace extends SmoothPagedView } } - ArrayList<ComponentName> getUniqueComponents(boolean stripDuplicates, ArrayList<ComponentName> duplicates) { - ArrayList<ComponentName> uniqueIntents = new ArrayList<ComponentName>(); - getUniqueIntents((CellLayout) mLauncher.getHotseat().getLayout(), uniqueIntents, duplicates, false); - int count = getChildCount(); - for (int i = 0; i < count; i++) { - CellLayout cl = (CellLayout) getChildAt(i); - getUniqueIntents(cl, uniqueIntents, duplicates, false); - } - return uniqueIntents; - } - - void getUniqueIntents(CellLayout cl, ArrayList<ComponentName> uniqueIntents, - ArrayList<ComponentName> duplicates, boolean stripDuplicates) { - int count = cl.getShortcutsAndWidgets().getChildCount(); - - ArrayList<View> children = new ArrayList<View>(); - for (int i = 0; i < count; i++) { - View v = cl.getShortcutsAndWidgets().getChildAt(i); - children.add(v); - } - - for (int i = 0; i < count; i++) { - View v = children.get(i); - ItemInfo info = (ItemInfo) v.getTag(); - // Null check required as the AllApps button doesn't have an item info - if (info instanceof ShortcutInfo) { - ShortcutInfo si = (ShortcutInfo) info; - ComponentName cn = si.intent.getComponent(); - - Uri dataUri = si.intent.getData(); - // If dataUri is not null / empty or if this component isn't one that would - // have previously showed up in the AllApps list, then this is a widget-type - // shortcut, so ignore it. - if (dataUri != null && !dataUri.equals(Uri.EMPTY)) { - continue; - } - - if (!uniqueIntents.contains(cn)) { - uniqueIntents.add(cn); - } else { - if (stripDuplicates) { - cl.removeViewInLayout(v); - LauncherModel.deleteItemFromDatabase(mLauncher, si); - } - if (duplicates != null) { - duplicates.add(cn); - } - } - } - if (v instanceof FolderIcon) { - FolderIcon fi = (FolderIcon) v; - ArrayList<View> items = fi.getFolder().getItemsInReadingOrder(); - for (int j = 0; j < items.size(); j++) { - if (items.get(j).getTag() instanceof ShortcutInfo) { - ShortcutInfo si = (ShortcutInfo) items.get(j).getTag(); - ComponentName cn = si.intent.getComponent(); - - Uri dataUri = si.intent.getData(); - // If dataUri is not null / empty or if this component isn't one that would - // have previously showed up in the AllApps list, then this is a widget-type - // shortcut, so ignore it. - if (dataUri != null && !dataUri.equals(Uri.EMPTY)) { - continue; - } - - if (!uniqueIntents.contains(cn)) { - uniqueIntents.add(cn); - } else { - if (stripDuplicates) { - fi.getFolderInfo().remove(si); - LauncherModel.deleteItemFromDatabase(mLauncher, si); - } - if (duplicates != null) { - duplicates.add(cn); - } - } - } - } - } - } - } - void saveWorkspaceToDb() { saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout()); int count = getChildCount(); @@ -4420,8 +3843,7 @@ public class Workspace extends SmoothPagedView cellX = hotseat.getCellXFromOrder((int) info.screenId); cellY = hotseat.getCellYFromOrder((int) info.screenId); } - LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, cellX, - cellY, false); + LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, cellX, cellY); } if (v instanceof FolderIcon) { FolderIcon fi = (FolderIcon) v; @@ -4451,7 +3873,7 @@ public class Workspace extends SmoothPagedView } @Override - public void onFlingToDelete(DragObject d, int x, int y, PointF vec) { + public void onFlingToDelete(DragObject d, PointF vec) { // Do nothing } @@ -4518,7 +3940,7 @@ public class Workspace extends SmoothPagedView @Override public boolean onEnterScrollArea(int x, int y, int direction) { // Ignore the scroll area if we are dragging over the hot seat - boolean isPortrait = !LauncherAppState.isScreenLandscape(getContext()); + boolean isPortrait = !mLauncher.getDeviceProfile().isLandscape; if (mLauncher.getHotseat() != null && isPortrait) { Rect r = new Rect(); mLauncher.getHotseat().getHitRect(r); @@ -4695,7 +4117,7 @@ public class Workspace extends SmoothPagedView && packageNames.contains(cn.getPackageName())) { shortcutInfo.isDisabled |= reason; BubbleTextView shortcut = (BubbleTextView) v; - shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false); + shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache); if (parent != null) { parent.invalidate(); @@ -4879,9 +4301,9 @@ public class Workspace extends SmoothPagedView updates.contains(info)) { ShortcutInfo si = (ShortcutInfo) info; BubbleTextView shortcut = (BubbleTextView) v; - boolean oldPromiseState = shortcut.getCompoundDrawables()[1] + boolean oldPromiseState = getTextViewIcon(shortcut) instanceof PreloadIconDrawable; - shortcut.applyFromShortcutInfo(si, mIconCache, true, + shortcut.applyFromShortcutInfo(si, mIconCache, si.isPromise() != oldPromiseState); if (parent != null) { @@ -4901,31 +4323,17 @@ public class Workspace extends SmoothPagedView removeItemsByPackageName(packages, user); } - public void updatePackageBadge(final String packageName, final UserHandleCompat user) { + public void updateRestoreItems(final HashSet<ItemInfo> updates) { mapOverItems(MAP_RECURSE, new ItemOperator() { @Override public boolean evaluate(ItemInfo info, View v, View parent) { - if (info instanceof ShortcutInfo && v instanceof BubbleTextView) { - ShortcutInfo shortcutInfo = (ShortcutInfo) info; - ComponentName cn = shortcutInfo.getTargetComponent(); - if (user.equals(shortcutInfo.user) && cn != null - && shortcutInfo.isPromise() - && packageName.equals(cn.getPackageName())) { - if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) { - // For auto install apps update the icon as well as label. - mIconCache.getTitleAndIcon(shortcutInfo, - shortcutInfo.promisedIntent, user, true); - } else { - // Only update the icon for restored apps. - shortcutInfo.updateIcon(mIconCache); - } - BubbleTextView shortcut = (BubbleTextView) v; - shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false); - - if (parent != null) { - parent.invalidate(); - } - } + if (info instanceof ShortcutInfo && v instanceof BubbleTextView + && updates.contains(info)) { + ((BubbleTextView) v).applyState(false); + } else if (v instanceof PendingAppWidgetHostView + && info instanceof LauncherAppWidgetInfo + && updates.contains(info)) { + ((PendingAppWidgetHostView) v).applyState(); } // process all the shortcuts return false; @@ -4933,42 +4341,6 @@ public class Workspace extends SmoothPagedView }); } - public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) { - for (final PackageInstallInfo installInfo : installInfos) { - if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) { - continue; - } - - mapOverItems(MAP_RECURSE, new ItemOperator() { - @Override - public boolean evaluate(ItemInfo info, View v, View parent) { - if (info instanceof ShortcutInfo && v instanceof BubbleTextView) { - ShortcutInfo si = (ShortcutInfo) info; - ComponentName cn = si.getTargetComponent(); - if (si.isPromise() && (cn != null) - && installInfo.packageName.equals(cn.getPackageName())) { - si.setInstallProgress(installInfo.progress); - if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) { - // Mark this info as broken. - si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE; - } - ((BubbleTextView)v).applyState(false); - } - } else if (v instanceof PendingAppWidgetHostView - && info instanceof LauncherAppWidgetInfo - && ((LauncherAppWidgetInfo) info).providerName.getPackageName() - .equals(installInfo.packageName)) { - ((LauncherAppWidgetInfo) info).installProgress = installInfo.progress; - ((PendingAppWidgetHostView) v).applyState(); - } - - // process all the shortcuts - return false; - } - }); - } - } - void widgetsRestored(ArrayList<LauncherAppWidgetInfo> changedInfo) { if (!changedInfo.isEmpty()) { DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo, @@ -5039,25 +4411,21 @@ public class Workspace extends SmoothPagedView return super.getPageIndicatorMarker(pageIndex); } - @Override - public void syncPages() { - } - - @Override - public void syncPageItems(int page, boolean immediate) { - } - protected String getPageIndicatorDescription() { String settings = getResources().getString(R.string.settings_button_text); return getCurrentPageDescription() + ", " + settings; } protected String getCurrentPageDescription() { - int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage; - int delta = numCustomPages(); if (hasCustomContent() && getNextPage() == 0) { return mCustomContentDescription; } + int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage; + return getPageDescription(page); + } + + private String getPageDescription(int page) { + int delta = numCustomPages(); return String.format(getContext().getString(R.string.workspace_scroll_format), page + 1 - delta, getChildCount() - delta); } @@ -5066,6 +4434,12 @@ public class Workspace extends SmoothPagedView mLauncher.getDragLayer().getLocationInDragLayer(this, loc); } + @Override + public void fillInLaunchSourceData(Bundle sourceData) { + sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOMESCREEN); + sourceData.putInt(Stats.SOURCE_EXTRA_CONTAINER_PAGE, getCurrentPage()); + } + /** * Used as a workaround to ensure that the AppWidgetService receives the * PACKAGE_ADDED broadcast before updating widgets. |