diff options
19 files changed, 271 insertions, 448 deletions
diff --git a/res/values/config.xml b/res/values/config.xml index fbce3a41f..73de79417 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -20,6 +20,7 @@ <!-- DragController --> <integer name="config_flingToDeleteMinVelocity">-1500</integer> + <item type="id" name="drag_event_parity" /> <!-- AllApps & Launcher transitions --> <!-- The alpha of the AppsCustomize bg in spring loaded mode --> diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 2b1cfe0e4..61567ac00 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -168,7 +168,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { private int[] mDirectionVector = new int[2]; int[] mPreviousReorderDirection = new int[2]; private static final int INVALID_DIRECTION = -100; - private DropTarget.DragEnforcer mDragEnforcer; private final Rect mTempRect = new Rect(); @@ -188,7 +187,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { public CellLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mDragEnforcer = new DropTarget.DragEnforcer(context); // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show // the user where a dragged item will land when dropped. @@ -2637,7 +2635,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { * or it may have begun on another layout. */ void onDragEnter() { - mDragEnforcer.onDragEnter(); mDragging = true; } @@ -2645,7 +2642,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { * Called when drag has left this CellLayout or has been completed (successfully or not) */ void onDragExit() { - mDragEnforcer.onDragExit(); // This can actually be called when we aren't in a drag, e.g. when adding a new // item to this layout via the customize drawer. // Guard against that case. diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java index 423a9a3d5..41e053eed 100644 --- a/src/com/android/launcher3/DragLayer.java +++ b/src/com/android/launcher3/DragLayer.java @@ -918,7 +918,7 @@ public class DragLayer extends InsettableFrameLayout { void showPageHints() { mShowPageHints = true; Workspace workspace = mLauncher.getWorkspace(); - getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.getChildCount() - 1), + getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.numCustomPages()), mScrollChildPosition); invalidate(); } diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java index a3828c1d0..c8fac5466 100644 --- a/src/com/android/launcher3/DropTarget.java +++ b/src/com/android/launcher3/DropTarget.java @@ -16,10 +16,8 @@ package com.android.launcher3; -import android.content.Context; import android.graphics.PointF; import android.graphics.Rect; -import android.util.Log; /** * Interface defining an object that can receive a drag. @@ -93,43 +91,6 @@ public interface DropTarget { } } - public static class DragEnforcer implements DragController.DragListener { - int dragParity = 0; - - public DragEnforcer(Context context) { - Launcher launcher = (Launcher) context; - launcher.getDragController().addDragListener(this); - } - - void onDragEnter() { - dragParity++; - if (dragParity != 1) { - Log.e(TAG, "onDragEnter: Drag contract violated: " + dragParity); - } - } - - void onDragExit() { - dragParity--; - if (dragParity != 0) { - Log.e(TAG, "onDragExit: Drag contract violated: " + dragParity); - } - } - - @Override - public void onDragStart(DragSource source, Object info, int dragAction) { - if (dragParity != 0) { - Log.e(TAG, "onDragEnter: Drag contract violated: " + dragParity); - } - } - - @Override - public void onDragEnd() { - if (dragParity != 0) { - Log.e(TAG, "onDragExit: Drag contract violated: " + dragParity); - } - } - } - /** * Used to temporarily disable certain drop targets * diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index a3376c42f..6dfca9ef3 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -365,13 +365,6 @@ public class IconCache { } /** - * Empty out the cache. - */ - public synchronized void flush() { - mCache.clear(); - } - - /** * Fetches high-res icon for the provided ItemInfo and updates the caller when done. * @return a request ID that can be used to cancel the request. */ diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 5dd64e0e2..5dac3b3da 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -88,6 +88,7 @@ import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; +import android.view.animation.OvershootInterpolator; import android.view.inputmethod.InputMethodManager; import android.widget.Advanceable; import android.widget.FrameLayout; @@ -111,11 +112,8 @@ import com.android.launcher3.widget.PendingAddWidgetInfo; import com.android.launcher3.widget.WidgetHostViewLoader; import com.android.launcher3.widget.WidgetsContainerView; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.File; import java.io.FileDescriptor; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; @@ -163,14 +161,14 @@ public class Launcher extends Activity private static final int WORKSPACE_BACKGROUND_TRANSPARENT = 1; private static final int WORKSPACE_BACKGROUND_BLACK = 2; + private static final float BOUNCE_ANIMATION_TENSION = 1.3f; + /** * IntentStarter uses request codes starting with this. This must be greater than all activity * request codes used internally. */ protected static final int REQUEST_LAST = 100; - static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate"; - static final int SCREEN_COUNT = 5; // To turn on these properties, type @@ -309,8 +307,6 @@ public class Launcher extends Activity private boolean mHasFocus = false; private boolean mAttached = false; - @Thunk static LocaleConfiguration sLocaleConfiguration = null; - private static LongArrayMap<FolderInfo> sFolders = new LongArrayMap<>(); private View.OnTouchListener mHapticFeedbackTouchListener; @@ -468,7 +464,6 @@ public class Launcher extends Activity Environment.getExternalStorageDirectory() + "/launcher"); } - checkForLocaleChange(); setContentView(R.layout.launcher); setupViews(); @@ -558,6 +553,35 @@ public class Launcher extends Activity } } }); + mLauncherCallbacks.setLauncherSearchCallback(new Launcher.LauncherSearchCallbacks() { + private boolean mImportanceStored = false; + private int mWorkspaceImportanceForAccessibility = + View.IMPORTANT_FOR_ACCESSIBILITY_AUTO; + private int mHotseatImportanceForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO; + + @Override + public void onSearchOverlayOpened() { + if (mImportanceStored) { + return; + } + // The underlying workspace and hotseat are temporarily suppressed by the search + // overlay. So they sholudn't be accessible. + mWorkspaceImportanceForAccessibility = mWorkspace.getImportantForAccessibility(); + mHotseatImportanceForAccessibility = mHotseat.getImportantForAccessibility(); + mWorkspace.setImportantForAccessibility( + View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + mHotseat.setImportantForAccessibility( + View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + mImportanceStored = true; + } + + @Override + public void onSearchOverlayClosed() { + mWorkspace.setImportantForAccessibility(mWorkspaceImportanceForAccessibility); + mHotseat.setImportantForAccessibility(mHotseatImportanceForAccessibility); + mImportanceStored = false; + } + }); return true; } @@ -606,108 +630,6 @@ public class Launcher extends Activity } } - @Thunk void checkForLocaleChange() { - if (sLocaleConfiguration == null) { - new AsyncTask<Void, Void, LocaleConfiguration>() { - @Override - protected LocaleConfiguration doInBackground(Void... unused) { - LocaleConfiguration localeConfiguration = new LocaleConfiguration(); - readConfiguration(Launcher.this, localeConfiguration); - return localeConfiguration; - } - - @Override - protected void onPostExecute(LocaleConfiguration result) { - sLocaleConfiguration = result; - checkForLocaleChange(); // recursive, but now with a locale configuration - } - }.execute(); - return; - } - - final Configuration configuration = getResources().getConfiguration(); - - final String previousLocale = sLocaleConfiguration.locale; - final String locale = configuration.locale.toString(); - - final int previousMcc = sLocaleConfiguration.mcc; - final int mcc = configuration.mcc; - - final int previousMnc = sLocaleConfiguration.mnc; - final int mnc = configuration.mnc; - - boolean localeChanged = !locale.equals(previousLocale) || mcc != previousMcc || mnc != previousMnc; - - if (localeChanged) { - sLocaleConfiguration.locale = locale; - sLocaleConfiguration.mcc = mcc; - sLocaleConfiguration.mnc = mnc; - - mIconCache.flush(); - - final LocaleConfiguration localeConfiguration = sLocaleConfiguration; - new AsyncTask<Void, Void, Void>() { - public Void doInBackground(Void ... args) { - writeConfiguration(Launcher.this, localeConfiguration); - return null; - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); - } - } - - @Thunk static class LocaleConfiguration { - public String locale; - public int mcc = -1; - public int mnc = -1; - } - - @Thunk static void readConfiguration(Context context, LocaleConfiguration configuration) { - DataInputStream in = null; - try { - in = new DataInputStream(context.openFileInput(LauncherFiles.LAUNCHER_PREFERENCES)); - configuration.locale = in.readUTF(); - configuration.mcc = in.readInt(); - configuration.mnc = in.readInt(); - } catch (FileNotFoundException e) { - // Ignore - } catch (IOException e) { - // Ignore - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - // Ignore - } - } - } - } - - @Thunk static void writeConfiguration(Context context, LocaleConfiguration configuration) { - DataOutputStream out = null; - try { - out = new DataOutputStream(context.openFileOutput( - LauncherFiles.LAUNCHER_PREFERENCES, MODE_PRIVATE)); - out.writeUTF(configuration.locale); - out.writeInt(configuration.mcc); - out.writeInt(configuration.mnc); - out.flush(); - } catch (FileNotFoundException e) { - // Ignore - } catch (IOException e) { - //noinspection ResultOfMethodCallIgnored - context.getFileStreamPath(LauncherFiles.LAUNCHER_PREFERENCES).delete(); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - // Ignore - } - } - } - } - public Stats getStats() { return mStats; } @@ -1055,8 +977,8 @@ public class Launcher extends Activity } // Background was set to gradient in onPause(), restore to transparent if in all apps. - setWorkspaceBackground(mState == State.WORKSPACE ? WORKSPACE_BACKGROUND_TRANSPARENT - : WORKSPACE_BACKGROUND_GRADIENT); + setWorkspaceBackground(mState == State.WORKSPACE ? WORKSPACE_BACKGROUND_GRADIENT + : WORKSPACE_BACKGROUND_TRANSPARENT); mPaused = false; if (mRestoring || mOnResumeNeedsLoad) { @@ -1207,6 +1129,18 @@ public class Launcher extends Activity public void dismissAllApps(); } + public interface LauncherSearchCallbacks { + /** + * Called when the search overlay is shown. + */ + public void onSearchOverlayOpened(); + + /** + * Called when the search overlay is dismissed. + */ + public void onSearchOverlayClosed(); + } + public interface LauncherOverlayCallbacks { /** * This method indicates whether a call to {@link #enterFullImmersion()} will succeed, @@ -4194,7 +4128,7 @@ public class Launcher extends Activity PropertyValuesHolder.ofFloat("scaleY", 1f)); bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION); bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY); - bounceAnim.setInterpolator(new SmoothPagedView.OvershootInterpolator()); + bounceAnim.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION)); return bounceAnim; } diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java index 6ff76665c..6a248a332 100644 --- a/src/com/android/launcher3/LauncherAnimUtils.java +++ b/src/com/android/launcher3/LauncherAnimUtils.java @@ -26,6 +26,9 @@ import android.os.Build; import android.view.View; import android.view.ViewAnimationUtils; import android.view.ViewTreeObserver; + +import com.android.launcher3.util.UiThreadCircularReveal; + import java.util.HashSet; import java.util.WeakHashMap; @@ -130,13 +133,11 @@ public class LauncherAnimUtils { } @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public static Animator createCircularReveal(View view, int centerX, + public static ValueAnimator createCircularReveal(View view, int centerX, int centerY, float startRadius, float endRadius) { - Animator anim = ViewAnimationUtils.createCircularReveal(view, centerX, + ValueAnimator anim = UiThreadCircularReveal.createCircularReveal(view, centerX, centerY, startRadius, endRadius); - if (anim instanceof ValueAnimator) { - new FirstFrameAnimatorHelper((ValueAnimator) anim, view); - } + new FirstFrameAnimatorHelper(anim, view); return anim; } } diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java index 0124d1f28..a5f36ba93 100644 --- a/src/com/android/launcher3/LauncherCallbacks.java +++ b/src/com/android/launcher3/LauncherCallbacks.java @@ -119,4 +119,11 @@ public interface LauncherCallbacks { */ public void setLauncherAppsCallback(Object callbacks); + /** + * Sets the callbacks to allow reacting the actions of search overlays of the launcher. + * + * @param callbacks A set of callbacks to the Launcher, is actually a LauncherSearchCallback, + * but for implementation purposes is passed around as an object. + */ + public void setLauncherSearchCallback(Object callbacks); } diff --git a/src/com/android/launcher3/LauncherExtension.java b/src/com/android/launcher3/LauncherExtension.java index 14ad6016c..09a105bcc 100644 --- a/src/com/android/launcher3/LauncherExtension.java +++ b/src/com/android/launcher3/LauncherExtension.java @@ -289,6 +289,11 @@ public class LauncherExtension extends Launcher { // Do nothing } + @Override + public void setLauncherSearchCallback(Object callbacks) { + // Do nothing + } + class LauncherExtensionOverlay implements LauncherOverlay { LauncherOverlayCallbacks mLauncherOverlayCallbacks; ViewGroup mOverlayView; diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java index 03ec4bf7a..c08cd0bf5 100644 --- a/src/com/android/launcher3/LauncherFiles.java +++ b/src/com/android/launcher3/LauncherFiles.java @@ -17,7 +17,6 @@ public class LauncherFiles { public static final String DEFAULT_WALLPAPER_THUMBNAIL = "default_thumb2.jpg"; public static final String DEFAULT_WALLPAPER_THUMBNAIL_OLD = "default_thumb.jpg"; public static final String LAUNCHER_DB = "launcher.db"; - public static final String LAUNCHER_PREFERENCES = "launcher.preferences"; public static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs"; public static final String WALLPAPER_CROP_PREFERENCES_KEY = "com.android.launcher3.WallpaperCropActivity"; @@ -31,7 +30,6 @@ public class LauncherFiles { DEFAULT_WALLPAPER_THUMBNAIL, DEFAULT_WALLPAPER_THUMBNAIL_OLD, LAUNCHER_DB, - LAUNCHER_PREFERENCES, SHARED_PREFERENCES_KEY + XML, WALLPAPER_CROP_PREFERENCES_KEY + XML, WALLPAPER_IMAGES_DB, @@ -43,5 +41,6 @@ public class LauncherFiles { public static final List<String> OBSOLETE_FILES = Collections.unmodifiableList(Arrays.asList( "launches.log", "stats.log", + "launcher.preferences", "com.android.launcher3.compat.PackageInstallerCompatV16.queue")); } diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java index f373fde2d..a006d141b 100644 --- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java +++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java @@ -26,12 +26,14 @@ import android.annotation.SuppressLint; import android.content.res.Resources; import android.util.Log; import android.view.View; -import android.view.ViewAnimationUtils; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; + import com.android.launcher3.allapps.AllAppsContainerView; +import com.android.launcher3.util.UiThreadCircularReveal; import com.android.launcher3.util.Thunk; import com.android.launcher3.widget.WidgetsContainerView; + import java.util.HashMap; /** @@ -320,7 +322,7 @@ public class LauncherStateTransitionAnimation { float startRadius = pCb.getMaterialRevealViewStartFinalRadius(); AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener( revealView, allAppsButtonView); - Animator reveal = ViewAnimationUtils.createCircularReveal(revealView, width / 2, + Animator reveal = UiThreadCircularReveal.createCircularReveal(revealView, width / 2, height / 2, startRadius, revealRadius); reveal.setDuration(revealDuration); reveal.setInterpolator(new LogDecelerateInterpolator(100, 0)); @@ -587,14 +589,14 @@ public class LauncherStateTransitionAnimation { TimeInterpolator decelerateInterpolator = material ? new LogDecelerateInterpolator(100, 0) : new DecelerateInterpolator(1f); - ObjectAnimator panelDriftY = LauncherAnimUtils.ofFloat(revealView, "translationY", + ObjectAnimator panelDriftY = ObjectAnimator.ofFloat(revealView, "translationY", 0, revealViewToYDrift); panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY); panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); panelDriftY.setInterpolator(decelerateInterpolator); mStateAnimation.play(panelDriftY); - ObjectAnimator panelDriftX = LauncherAnimUtils.ofFloat(revealView, "translationX", + ObjectAnimator panelDriftX = ObjectAnimator.ofFloat(revealView, "translationX", 0, revealViewToXDrift); panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY); panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); @@ -605,7 +607,7 @@ public class LauncherStateTransitionAnimation { final float revealViewToAlpha = !material ? 0f : pCb.getMaterialRevealViewFinalAlpha(revealView); if (revealViewToAlpha != 1f) { - ObjectAnimator panelAlpha = LauncherAnimUtils.ofFloat(revealView, "alpha", + ObjectAnimator panelAlpha = ObjectAnimator.ofFloat(revealView, "alpha", 1f, revealViewToAlpha); panelAlpha.setDuration(material ? revealDuration : 150); panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY); @@ -617,7 +619,7 @@ public class LauncherStateTransitionAnimation { layerViews.put(contentView, BUILD_AND_SET_LAYER); // Create the individual animators - ObjectAnimator pageDrift = LauncherAnimUtils.ofFloat(contentView, "translationY", + ObjectAnimator pageDrift = ObjectAnimator.ofFloat(contentView, "translationY", 0, revealViewToYDrift); contentView.setTranslationY(0); pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY); @@ -626,7 +628,7 @@ public class LauncherStateTransitionAnimation { mStateAnimation.play(pageDrift); contentView.setAlpha(1f); - ObjectAnimator itemsAlpha = LauncherAnimUtils.ofFloat(contentView, "alpha", 1f, 0f); + ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 1f, 0f); itemsAlpha.setDuration(100); itemsAlpha.setInterpolator(decelerateInterpolator); mStateAnimation.play(itemsAlpha); @@ -636,9 +638,8 @@ public class LauncherStateTransitionAnimation { float finalRadius = pCb.getMaterialRevealViewStartFinalRadius(); AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener(revealView, allAppsButtonView); - Animator reveal = - LauncherAnimUtils.createCircularReveal(revealView, width / 2, - height / 2, revealRadius, finalRadius); + Animator reveal = UiThreadCircularReveal.createCircularReveal(revealView, width / 2, + height / 2, revealRadius, finalRadius); reveal.setInterpolator(new LogDecelerateInterpolator(100, 0)); reveal.setDuration(revealDuration); reveal.setStartDelay(itemsAlphaStagger); @@ -782,4 +783,4 @@ public class LauncherStateTransitionAnimation { mStateAnimation = null; } } -}
\ No newline at end of file +} diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index dda9a166c..9271e8b15 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -146,7 +146,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected OnLongClickListener mLongClickListener; protected int mTouchSlop; - private int mPagingTouchSlop; private int mMaximumVelocity; protected int mPageLayoutWidthGap; protected int mPageLayoutHeightGap; @@ -172,14 +171,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // If true, modify alpha of neighboring pages as user scrolls left/right protected boolean mFadeInAdjacentScreens = false; - // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding - // to switch to a new page - protected boolean mUsePagingTouchSlop = true; - - // If true, the subclass should directly update scrollX itself in its computeScroll method - // (SmoothPagedView does this) - protected boolean mDeferScrollUpdate = false; - protected boolean mIsPageMoving = false; private boolean mWasInOverscroll = false; @@ -264,7 +255,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc final ViewConfiguration configuration = ViewConfiguration.get(getContext()); mTouchSlop = configuration.getScaledPagingTouchSlop(); - mPagingTouchSlop = configuration.getScaledPagingTouchSlop(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); mDensity = getResources().getDisplayMetrics().density; @@ -633,6 +623,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (mCurrentPage != getNextPage()) { AccessibilityEvent ev = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); + ev.setScrollable(true); + ev.setScrollX(getScrollX()); + ev.setScrollY(getScrollY()); + ev.setMaxScrollX(mMaxScrollX); + ev.setMaxScrollY(0); sendAccessibilityEventUnchecked(ev); } @@ -853,7 +848,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc int offsetY = getViewportOffsetY(); // Update the viewport offsets - mViewport.offset(offsetX, offsetY); + mViewport.offset(offsetX, offsetY); final int startIndex = mIsRtl ? childCount - 1 : 0; final int endIndex = mIsRtl ? -1 : childCount; @@ -1434,25 +1429,20 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return; final int xDiff = (int) Math.abs(x - mLastMotionX); - final int yDiff = (int) Math.abs(y - mLastMotionY); final int touchSlop = Math.round(touchSlopScale * mTouchSlop); - boolean xPaged = xDiff > mPagingTouchSlop; boolean xMoved = xDiff > touchSlop; - boolean yMoved = yDiff > touchSlop; - if (xMoved || xPaged || yMoved) { - if (mUsePagingTouchSlop ? xPaged : xMoved) { - // Scroll if the user moved far enough along the X axis - mTouchState = TOUCH_STATE_SCROLLING; - mTotalMotionX += Math.abs(mLastMotionX - x); - mLastMotionX = x; - mLastMotionXRemainder = 0; - mTouchX = getViewportOffsetX() + getScrollX(); - mSmoothingTime = System.nanoTime() / NANOTIME_DIV; - onScrollInteractionBegin(); - pageBeginMoving(); - } + if (xMoved) { + // Scroll if the user moved far enough along the X axis + mTouchState = TOUCH_STATE_SCROLLING; + mTotalMotionX += Math.abs(mLastMotionX - x); + mLastMotionX = x; + mLastMotionXRemainder = 0; + mTouchX = getViewportOffsetX() + getScrollX(); + mSmoothingTime = System.nanoTime() / NANOTIME_DIV; + onScrollInteractionBegin(); + pageBeginMoving(); } } @@ -1697,12 +1687,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (Math.abs(deltaX) >= 1.0f) { mTouchX += deltaX; mSmoothingTime = System.nanoTime() / NANOTIME_DIV; - if (!mDeferScrollUpdate) { - scrollBy((int) deltaX, 0); - if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX); - } else { - invalidate(); - } + scrollBy((int) deltaX, 0); mLastMotionX = x; mLastMotionXRemainder = deltaX - (int) deltaX; } else { @@ -2098,7 +2083,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc snapToPage(whichPage, delta, duration); } - protected void snapToPage(int whichPage) { + public void snapToPage(int whichPage) { snapToPage(whichPage, getPageSnapDuration()); } @@ -2347,6 +2332,15 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (getCurrentPage() > 0) { info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); } + info.setClassName(getClass().getName()); + + // Accessibility-wise, PagedView doesn't support long click, so disabling it. + // Besides disabling the accessibility long-click, this also prevents this view from getting + // accessibility focus. + info.setLongClickable(false); + if (Utilities.isLmpOrAbove()) { + info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK); + } } @Override @@ -2360,7 +2354,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); - event.setScrollable(true); + event.setScrollable(getPageCount() > 1); } @Override diff --git a/src/com/android/launcher3/SmoothPagedView.java b/src/com/android/launcher3/SmoothPagedView.java deleted file mode 100644 index 0f9b23cda..000000000 --- a/src/com/android/launcher3/SmoothPagedView.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.animation.Interpolator; - -public abstract class SmoothPagedView extends PagedView { - private static final float SMOOTHING_SPEED = 0.75f; - private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED)); - - private float mBaseLineFlingVelocity; - private float mFlingVelocityInfluence; - - static final int DEFAULT_MODE = 0; - static final int X_LARGE_MODE = 1; - - int mScrollMode; - - private Interpolator mScrollInterpolator; - - public static class OvershootInterpolator implements Interpolator { - private static final float DEFAULT_TENSION = 1.3f; - private float mTension; - - public OvershootInterpolator() { - mTension = DEFAULT_TENSION; - } - - public void setDistance(int distance) { - mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION; - } - - public void disableSettle() { - mTension = 0.f; - } - - public float getInterpolation(float t) { - t -= 1.0f; - return t * t * ((mTension + 1) * t + mTension) + 1.0f; - } - } - - /** - * Used to inflate the Workspace from XML. - * - * @param context The application's context. - * @param attrs The attributes set containing the Workspace's customization values. - */ - public SmoothPagedView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - /** - * Used to inflate the Workspace from XML. - * - * @param context The application's context. - * @param attrs The attributes set containing the Workspace's customization values. - * @param defStyle Unused. - */ - public SmoothPagedView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - mUsePagingTouchSlop = false; - - // This means that we'll take care of updating the scroll parameter ourselves (we do it - // in computeScroll), we only do this in the OVERSHOOT_MODE, ie. on phones - mDeferScrollUpdate = mScrollMode != X_LARGE_MODE; - } - - protected int getScrollMode() { - return X_LARGE_MODE; - } - - /** - * Initializes various states for this workspace. - */ - @Override - protected void init() { - super.init(); - - mScrollMode = getScrollMode(); - if (mScrollMode == DEFAULT_MODE) { - mBaseLineFlingVelocity = 2500.0f; - mFlingVelocityInfluence = 0.4f; - mScrollInterpolator = new OvershootInterpolator(); - setDefaultInterpolator(mScrollInterpolator); - } - } - - @Override - protected void snapToDestination() { - if (mScrollMode == X_LARGE_MODE) { - super.snapToDestination(); - } else { - snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0); - } - } - - @Override - protected void snapToPageWithVelocity(int whichPage, int velocity) { - if (mScrollMode == X_LARGE_MODE) { - super.snapToPageWithVelocity(whichPage, velocity); - } else { - snapToPageWithVelocity(whichPage, 0, true); - } - } - - private void snapToPageWithVelocity(int whichPage, int velocity, boolean settle) { - // if (!mScroller.isFinished()) return; - - whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1)); - - final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage)); - final int newX = getScrollForPage(whichPage); - final int delta = newX - mUnboundedScrollX; - int duration = (screenDelta + 1) * 100; - - if (!mScroller.isFinished()) { - mScroller.abortAnimation(); - } - - if (settle) { - ((OvershootInterpolator) mScrollInterpolator).setDistance(screenDelta); - } else { - ((OvershootInterpolator) mScrollInterpolator).disableSettle(); - } - - velocity = Math.abs(velocity); - if (velocity > 0) { - duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence; - } else { - duration += 100; - } - - snapToPage(whichPage, delta, duration); - } - - @Override - public void snapToPage(int whichPage) { - if (mScrollMode == X_LARGE_MODE) { - super.snapToPage(whichPage); - } else { - snapToPageWithVelocity(whichPage, 0, false); - } - } - - @Override - public void computeScroll() { - if (mScrollMode == X_LARGE_MODE) { - super.computeScroll(); - } else { - boolean scrollComputed = computeScrollHelper(); - - if (!scrollComputed && mTouchState == TOUCH_STATE_SCROLLING) { - final float now = System.nanoTime() / NANOTIME_DIV; - final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT); - - final float dx = mTouchX - mUnboundedScrollX; - scrollTo(Math.round(mUnboundedScrollX + dx * e), getScrollY()); - mSmoothingTime = now; - - // Keep generating points as long as we're more than 1px away from the target - if (dx > 1.f || dx < -1.f) { - invalidate(); - } - } - } - } -} diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 6c4b7207b..256eba020 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -127,6 +127,11 @@ public final class Utilities { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; } + public static boolean isLmpMR1OrAbove() { + // TODO(adamcohen): update to Build.VERSION_CODES.LOLLIPOP_MR1 once building against 22; + return Build.VERSION.SDK_INT >= 22; + } + static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) { byte[] data = c.getBlob(iconIndex); try { @@ -588,7 +593,6 @@ public final class Utilities { } public static final Comparator<ItemInfo> RANK_COMPARATOR = new Comparator<ItemInfo>() { - @Override public int compare(ItemInfo lhs, ItemInfo rhs) { return lhs.rank - rhs.rank; diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index d2c37d209..aee77b826 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -64,8 +64,8 @@ import com.android.launcher3.Launcher.LauncherOverlay; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.UninstallDropTarget.UninstallSource; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; -import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate; 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; @@ -83,12 +83,14 @@ 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, UninstallSource, AccessibilityDragSource { private static final String TAG = "Launcher.Workspace"; + 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; @@ -215,7 +217,6 @@ public class Workspace extends SmoothPagedView 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(); @@ -301,9 +302,6 @@ public class Workspace extends SmoothPagedView mOutlineHelper = HolographicOutlineHelper.obtain(context); - mDragEnforcer = new DropTarget.DragEnforcer(context); - // With workspace, data is available straight from the get-go - mLauncher = (Launcher) context; mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this); final Resources res = getResources(); @@ -327,7 +325,6 @@ public class Workspace extends SmoothPagedView // Disable multitouch across the workspace/all apps/customize tray setMotionEventSplittingEnabled(true); - setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } @Override @@ -372,22 +369,23 @@ 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(); // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging InstallShortcutReceiver.enableInstallQueue(); - post(new Runnable() { - @Override - public void run() { - if (mIsDragOccuring && mAddNewPageOnDrag) { - mDeferRemoveExtraEmptyScreen = false; - addExtraEmptyScreenOnDrag(); - } - } - }); + + if (mAddNewPageOnDrag) { + mDeferRemoveExtraEmptyScreen = false; + addExtraEmptyScreenOnDrag(); + } } public void setAddNewPageOnDrag(boolean addPage) { @@ -398,7 +396,12 @@ public class Workspace extends SmoothPagedView mDeferRemoveExtraEmptyScreen = true; } + @Override public void onDragEnd() { + if (ENFORCE_DRAG_EVENT_ORDER) { + enfoceDragParity("onDragEnd", 0, 0); + } + if (!mDeferRemoveExtraEmptyScreen) { removeExtraEmptyScreen(true, mDragSourceInternal != null); } @@ -458,11 +461,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."); @@ -2019,14 +2017,9 @@ public class Workspace extends SmoothPagedView for (int i = numCustomPages(); i < total; i++) { updateAccessibilityFlags((CellLayout) getPageAt(i), i); } - if (mState == State.NORMAL) { - setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); - } else { - setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); - } } else { int accessible = mState == State.NORMAL ? - IMPORTANT_FOR_ACCESSIBILITY_NO : + IMPORTANT_FOR_ACCESSIBILITY_AUTO : IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; setImportantForAccessibility(accessible); } @@ -2045,7 +2038,7 @@ public class Workspace extends SmoothPagedView page.setAccessibilityDelegate(mPagesAccessibilityDelegate); } else { int accessible = mState == State.NORMAL ? - IMPORTANT_FOR_ACCESSIBILITY_NO : + IMPORTANT_FOR_ACCESSIBILITY_AUTO : IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); page.getShortcutsAndWidgets().setImportantForAccessibility(accessible); @@ -2827,8 +2820,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; @@ -2881,8 +2878,11 @@ public class Workspace extends SmoothPagedView 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 @@ -2914,6 +2914,24 @@ public class Workspace extends SmoothPagedView 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(); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 60f9ab347..d81f97f24 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -447,7 +447,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc @Override protected void onFixedBoundsUpdated() { // Update the number of items in the grid - LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = mLauncher.getDeviceProfile(); if (grid.updateAppsViewNumCols(getContext().getResources(), mFixedBounds.width())) { mNumAppsPerRow = grid.allAppsNumCols; diff --git a/src/com/android/launcher3/util/RevealOutlineProvider.java b/src/com/android/launcher3/util/RevealOutlineProvider.java new file mode 100644 index 000000000..0db3984f8 --- /dev/null +++ b/src/com/android/launcher3/util/RevealOutlineProvider.java @@ -0,0 +1,49 @@ +package com.android.launcher3.util; + +import android.annotation.TargetApi; +import android.graphics.Outline; +import android.graphics.Rect; +import android.os.Build; +import android.view.View; +import android.view.ViewOutlineProvider; + +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +public class RevealOutlineProvider extends ViewOutlineProvider { + + private int mCenterX; + private int mCenterY; + private float mRadius0; + private float mRadius1; + private int mCurrentRadius; + + private final Rect mOval; + + /** + * @param x reveal center x + * @param y reveal center y + * @param r0 initial radius + * @param r1 final radius + */ + public RevealOutlineProvider(int x, int y, float r0, float r1) { + mCenterX = x; + mCenterY = y; + mRadius0 = r0; + mRadius1 = r1; + + mOval = new Rect(); + } + + public void setProgress(float progress) { + mCurrentRadius = (int) ((1 - progress) * mRadius0 + progress * mRadius1); + + mOval.left = mCenterX - mCurrentRadius; + mOval.top = mCenterY - mCurrentRadius; + mOval.right = mCenterX + mCurrentRadius; + mOval.bottom = mCenterY + mCurrentRadius; + } + + @Override + public void getOutline(View v, Outline outline) { + outline.setRoundRect(mOval, mCurrentRadius); + } +} diff --git a/src/com/android/launcher3/util/UiThreadCircularReveal.java b/src/com/android/launcher3/util/UiThreadCircularReveal.java new file mode 100644 index 000000000..c7324fb1b --- /dev/null +++ b/src/com/android/launcher3/util/UiThreadCircularReveal.java @@ -0,0 +1,55 @@ +package com.android.launcher3.util; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.annotation.TargetApi; +import android.os.Build; +import android.view.View; +import android.view.ViewOutlineProvider; + +import com.android.launcher3.Utilities; + +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +public class UiThreadCircularReveal { + + public static ValueAnimator createCircularReveal(View v, int x, int y, float r0, float r1) { + ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); + + final View revealView = v; + final RevealOutlineProvider outlineProvider = new RevealOutlineProvider(x, y, r0, r1); + final ViewOutlineProvider originalProvider = revealView.getOutlineProvider(); + final float elevation = v.getElevation(); + + va.addListener(new AnimatorListenerAdapter() { + public void onAnimationStart(Animator animation) { + revealView.setOutlineProvider(outlineProvider); + revealView.setClipToOutline(true); + revealView.setTranslationZ(-elevation); + } + + public void onAnimationEnd(Animator animation) { + revealView.setOutlineProvider(originalProvider); + revealView.setClipToOutline(false); + revealView.setTranslationZ(0); + } + + }); + + va.addUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator arg0) { + float progress = arg0.getAnimatedFraction(); + outlineProvider.setProgress(progress); + if (Utilities.isLmpMR1OrAbove()) { + revealView.invalidateOutline(); + } else { + // On L, a bug requires calling a full view invalidate. + revealView.invalidate(); + } + } + }); + return va; + } +} diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index 05e842e71..778cf9ef1 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -35,7 +35,6 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.DragController; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget.DragObject; -import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.Folder; import com.android.launcher3.IconCache; import com.android.launcher3.ItemInfo; @@ -46,6 +45,7 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.WidgetPreviewLoader; import com.android.launcher3.Workspace; +import com.android.launcher3.model.WidgetsModel; /** * The widgets list view container. @@ -56,8 +56,6 @@ public class WidgetsContainerView extends BaseContainerView private static final String TAG = "WidgetsContainerView"; private static final boolean DEBUG = false; - private static final int SPRING_MODE_DELAY_MS = 150; - /* Coefficient multiplied to the screen height for preloading widgets. */ private static final int PRELOAD_SCREEN_HEIGHT_MULTIPLE = 1; @@ -186,18 +184,11 @@ public class WidgetsContainerView extends BaseContainerView Log.e(TAG, "Unexpected dragging view: " + v); } - // We delay entering spring-loaded mode slightly to make sure the UI - // thread is free of any work. - postDelayed(new Runnable() { - @Override - public void run() { - // We don't enter spring-loaded mode if the drag has been cancelled - if (mLauncher.getDragController().isDragging()) { - // Go into spring loaded mode (must happen before we startDrag()) - mLauncher.enterSpringLoadedDragMode(); - } - } - }, SPRING_MODE_DELAY_MS); + // We don't enter spring-loaded mode if the drag has been cancelled + if (mLauncher.getDragController().isDragging()) { + // Go into spring loaded mode (must happen before we startDrag()) + mLauncher.enterSpringLoadedDragMode(); + } return true; } |