diff options
author | Jon <jonmiranda@google.com> | 2018-05-31 13:15:31 -0400 |
---|---|---|
committer | Jon <jonmiranda@google.com> | 2018-05-31 13:15:57 -0400 |
commit | bf29023212a107481b6cbf3dbe4fda52c6f50180 (patch) | |
tree | 58cf13d9da0fde15896d03148bfece106ad78f61 | |
parent | aea65680e6f3da83636dbc6af2ef1381de06d2a8 (diff) | |
parent | f4392dbf5aa43140a84f357537f0b22decd42946 (diff) | |
download | android_packages_apps_Trebuchet-bf29023212a107481b6cbf3dbe4fda52c6f50180.tar.gz android_packages_apps_Trebuchet-bf29023212a107481b6cbf3dbe4fda52c6f50180.tar.bz2 android_packages_apps_Trebuchet-bf29023212a107481b6cbf3dbe4fda52c6f50180.zip |
Merge branch 'ub-launcher3-edmonton' into pi-dev
Bug: 80134723
Test: manual
Change-Id: If8e9c1b1aacf547ab7a1edaccaa9fed5e976a980
46 files changed, 537 insertions, 258 deletions
diff --git a/proguard.flags b/proguard.flags index 555d13e44..e4011165e 100644 --- a/proguard.flags +++ b/proguard.flags @@ -112,6 +112,11 @@ public <init>(...); } +# UserEventDispatcherExtension +-keep class com.android.quickstep.logging.UserEventDispatcherExtension { + public <init>(...); +} + -keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** { *; } diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto index cab20a3be..06e6a923d 100644 --- a/protos/launcher_log.proto +++ b/protos/launcher_log.proto @@ -110,6 +110,8 @@ enum ControlType { QUICK_SCRUB_BUTTON = 12; CLEAR_ALL_BUTTON = 13; CANCEL_TARGET = 14; + TASK_PREVIEW = 15; + SPLIT_SCREEN_TARGET = 16; } enum TipType { diff --git a/quickstep/res/layout/fallback_recents_activity.xml b/quickstep/res/layout/fallback_recents_activity.xml index 7ecab3201..84e13add5 100644 --- a/quickstep/res/layout/fallback_recents_activity.xml +++ b/quickstep/res/layout/fallback_recents_activity.xml @@ -24,6 +24,7 @@ android:id="@+id/overview_panel_container" android:layout_width="match_parent" android:layout_height="match_parent" + android:clipChildren="false" > <include layout="@layout/overview_clear_all_button"/> @@ -33,6 +34,7 @@ android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false" + android:outlineProvider="none" android:focusableInTouchMode="true" android:theme="@style/HomeScreenElementTheme" > diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml index 919afdb37..840b040ac 100644 --- a/quickstep/res/layout/overview_panel.xml +++ b/quickstep/res/layout/overview_panel.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:clipChildren="false" android:visibility="invisible" > <include layout="@layout/overview_clear_all_button"/> @@ -28,6 +29,7 @@ android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false" + android:outlineProvider="none" android:focusableInTouchMode="true" android:accessibilityPaneTitle="@string/accessibility_recent_apps" android:theme="@style/HomeScreenElementTheme" diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml index 7673f6994..c29437634 100644 --- a/quickstep/res/values/config.xml +++ b/quickstep/res/values/config.xml @@ -18,5 +18,5 @@ <string name="overview_callbacks_class" translatable="false"></string> - <string name="user_event_dispatcher_class" translatable="false">com.google.quickstep.logging.UserEventDispatcherExtension</string> + <string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherExtension</string> </resources> diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 6703bb546..2630edb3d 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -50,6 +50,7 @@ import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; import android.util.Log; @@ -105,6 +106,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag private static final int APP_LAUNCH_ALPHA_DURATION = 50; public static final int RECENTS_LAUNCH_DURATION = 336; + public static final int RECENTS_QUICKSCRUB_LAUNCH_DURATION = 300; private static final int LAUNCHER_RESUME_START_DELAY = 100; private static final int CLOSING_TRANSITION_DURATION_MS = 250; @@ -236,8 +238,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return bounds; } - public void setRemoteAnimationProvider(RemoteAnimationProvider animationProvider) { + public void setRemoteAnimationProvider(final RemoteAnimationProvider animationProvider, + CancellationSignal cancellationSignal) { mRemoteAnimationProvider = animationProvider; + cancellationSignal.setOnCancelListener(() -> { + if (animationProvider == mRemoteAnimationProvider) { + mRemoteAnimationProvider = null; + } + }); } /** @@ -253,15 +261,21 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag RecentsView recentsView = mLauncher.getOverviewPanel(); boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING); boolean skipLauncherChanges = !launcherClosing; + boolean isLaunchingFromQuickscrub = + recentsView.getQuickScrubController().isWaitingForTaskLaunch(); TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets); if (taskView == null) { return false; } + int duration = isLaunchingFromQuickscrub + ? RECENTS_QUICKSCRUB_LAUNCH_DURATION + : RECENTS_LAUNCH_DURATION; + ClipAnimationHelper helper = new ClipAnimationHelper(); target.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets, helper) - .setDuration(RECENTS_LAUNCH_DURATION)); + .setDuration(duration)); Animator childStateAnimation = null; // Found a visible recents task that matches the opening app, lets launch the app from there @@ -270,7 +284,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag if (launcherClosing) { launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView, helper); launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); - launcherAnim.setDuration(RECENTS_LAUNCH_DURATION); + launcherAnim.setDuration(duration); // Make sure recents gets fixed up by resetting task alphas and scales, etc. windowAnimEndListener = new AnimatorListenerAdapter() { @@ -282,11 +296,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag }; } else { AnimatorPlaybackController controller = - mLauncher.getStateManager() - .createAnimationToNewWorkspace(NORMAL, RECENTS_LAUNCH_DURATION); + mLauncher.getStateManager().createAnimationToNewWorkspace(NORMAL, duration); controller.dispatchOnStart(); childStateAnimation = controller.getTarget(); - launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION); + launcherAnim = controller.getAnimationPlayer().setDuration(duration); windowAnimEndListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -581,11 +594,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag float offsetX = (scaledWindowWidth - iconWidth) / 2; float offsetY = (scaledWindowHeight - iconHeight) / 2; - if (mLauncher.isInMultiWindowModeCompat()) { - mFloatingView.getLocationOnScreen(floatingViewBounds); - } else { - mFloatingView.getLocationInWindow(floatingViewBounds); - } + mFloatingView.getLocationOnScreen(floatingViewBounds); + float transX0 = floatingViewBounds[0] - offsetX; float transY0 = floatingViewBounds[1] - offsetY; matrix.postTranslate(transX0, transY0); diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java index e5e377f83..08b6bfc6a 100644 --- a/quickstep/src/com/android/launcher3/LauncherInitListener.java +++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Handler; import com.android.launcher3.states.InternalStateHandler; @@ -48,10 +49,11 @@ public class LauncherInitListener extends InternalStateHandler implements Activi // Set a one-time animation provider. After the first call, this will get cleared. // TODO: Probably also check the intended target id. + CancellationSignal cancellationSignal = new CancellationSignal(); appTransitionManager.setRemoteAnimationProvider((targets) -> { // On the first call clear the reference. - appTransitionManager.setRemoteAnimationProvider(null); + cancellationSignal.cancel(); RemoteAnimationProvider provider = mRemoteAnimationProvider; mRemoteAnimationProvider = null; @@ -59,7 +61,7 @@ public class LauncherInitListener extends InternalStateHandler implements Activi return provider.createWindowAnimation(targets); } return null; - }); + }, cancellationSignal); } OverviewCallbacks.get(launcher).onInitOverviewTransition(); return mOnInitListener.test(launcher, alreadyOnHome); diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java index 43d982230..26453022f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java @@ -34,7 +34,7 @@ public class FastOverviewState extends OverviewState { /** * Vertical transition of the task previews relative to the full container. */ - public static final float OVERVIEW_TRANSLATION_FACTOR = 0.5f; + public static final float OVERVIEW_TRANSLATION_FACTOR = 0.4f; private static final int STATE_FLAGS = FLAG_DISABLE_RESTORE | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI | FLAG_HIDE_BACK_BUTTON | FLAG_DISABLE_ACCESSIBILITY; @@ -76,4 +76,10 @@ public class FastOverviewState extends OverviewState { return Math.min(Math.min(dp.availableHeightPx / usedHeight, dp.availableWidthPx / usedWidth), MAX_PREVIEW_SCALE_UP); } + + @Override + public void onStateDisabled(Launcher launcher) { + super.onStateDisabled(launcher); + launcher.<RecentsView>getOverviewPanel().getQuickScrubController().cancelActiveQuickscrub(); + } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index e3aabd6c8..ea27eb25b 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -76,15 +76,16 @@ public class RecentsViewStateController implements StateHandler { } PropertySetter setter = config.getPropertySetter(builder); float[] scaleTranslationYFactor = toState.getOverviewScaleAndTranslationYFactor(mLauncher); - Interpolator scaleInterpolator = builder.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR); - setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleTranslationYFactor[0], scaleInterpolator); - Interpolator transYInterpolator = scaleInterpolator; + Interpolator scaleAndTransYInterpolator = builder.getInterpolator( + ANIM_OVERVIEW_SCALE, LINEAR); if (mLauncher.getStateManager().getState() == OVERVIEW && toState == FAST_OVERVIEW) { - transYInterpolator = Interpolators.clampToProgress(QUICK_SCRUB_START_INTERPOLATOR, 0, - QUICK_SCRUB_TRANSLATION_Y_FACTOR); + scaleAndTransYInterpolator = Interpolators.clampToProgress( + QUICK_SCRUB_START_INTERPOLATOR, 0, QUICK_SCRUB_TRANSLATION_Y_FACTOR); } + setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleTranslationYFactor[0], + scaleAndTransYInterpolator); setter.setFloat(mRecentsView, TRANSLATION_Y_FACTOR, scaleTranslationYFactor[1], - transYInterpolator); + scaleAndTransYInterpolator); setter.setFloat(mRecentsViewContainer, CONTENT_ALPHA, toState.overviewUi ? 1 : 0, builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index d0c7b2117..dd5dcbeaf 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -25,14 +25,19 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN; import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; +import android.animation.AnimatorSet; +import android.animation.ValueAnimator; import android.app.Activity; import android.content.Context; +import android.os.CancellationSignal; import android.util.Base64; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppTransitionManagerImpl; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; import com.android.launcher3.LauncherStateManager.StateHandler; @@ -41,6 +46,8 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.util.TouchController; import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.RecentsModel; +import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.RemoteFadeOutAnimationListener; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.ActivityCompat; import com.android.systemui.shared.system.WindowManagerWrapper; @@ -179,6 +186,23 @@ public class UiFactory { } } + public static void useFadeOutAnimationForLauncherStart(Launcher launcher, + CancellationSignal cancellationSignal) { + LauncherAppTransitionManagerImpl appTransitionManager = + (LauncherAppTransitionManagerImpl) launcher.getAppTransitionManager(); + appTransitionManager.setRemoteAnimationProvider((targets) -> { + + // On the first call clear the reference. + cancellationSignal.cancel(); + + ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0); + fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(targets)); + AnimatorSet anim = new AnimatorSet(); + anim.play(fadeAnimation); + return anim; + }, cancellationSignal); + } + public static boolean dumpActivity(Activity activity, PrintWriter writer) { if (!Utilities.IS_DEBUG_DEVICE) { return false; diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index e202c574a..52a6dd5fe 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -46,6 +46,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherInitListener; import com.android.launcher3.LauncherState; +import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.AnimatorPlaybackController; @@ -82,7 +83,8 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { void onQuickInteractionStart(T activity, @Nullable RunningTaskInfo taskInfo, boolean activityVisible); - float getTranslationYForQuickScrub(T activity); + float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp, + Context context); void executeOnWindowAvailable(T activity, Runnable action); @@ -151,10 +153,15 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { } @Override - public float getTranslationYForQuickScrub(Launcher activity) { - LauncherRecentsView recentsView = activity.getOverviewPanel(); - return recentsView.computeTranslationYForFactor( - FastOverviewState.OVERVIEW_TRANSLATION_FACTOR); + public float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp, + Context context) { + // The padding calculations are exactly same as that of RecentsView.setInsets + int topMargin = context.getResources() + .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin); + int paddingTop = targetRect.rect.top - topMargin - dp.getInsets().top; + int paddingBottom = dp.availableHeightPx + dp.getInsets().top - targetRect.rect.bottom; + + return FastOverviewState.OVERVIEW_TRANSLATION_FACTOR * (paddingBottom - paddingTop); } @Override @@ -380,7 +387,8 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { } @Override - public float getTranslationYForQuickScrub(RecentsActivity activity) { + public float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp, + Context context) { return 0; } diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java index 84dfa457e..84dfdbd1d 100644 --- a/quickstep/src/com/android/quickstep/AnimatedFloat.java +++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java @@ -46,9 +46,9 @@ public class AnimatedFloat { mUpdateCallback = updateCallback; } - public ObjectAnimator animateToValue(float v) { + public ObjectAnimator animateToValue(float start, float end) { cancelAnimation(); - mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, v); + mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, start, end); mValueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { diff --git a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java index b92678a2e..8e83bd079 100644 --- a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java @@ -64,6 +64,16 @@ public class DeferredTouchConsumer implements TouchConsumer { } @Override + public void onQuickStep(MotionEvent ev) { + mTarget.onQuickStep(ev); + } + + @Override + public void onCommand(int command) { + mTarget.onCommand(command); + } + + @Override public void preProcessMotionEvent(MotionEvent ev) { mVelocityTracker.addMovement(ev); } @@ -92,6 +102,11 @@ public class DeferredTouchConsumer implements TouchConsumer { return target == null ? true : target.deferNextEventToMainThread(); } + @Override + public void onShowOverviewFromAltTab() { + mTarget.onShowOverviewFromAltTab(); + } + public interface DeferredTouchProvider { TouchConsumer createTouchConsumer(VelocityTracker tracker); diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java index 15f5aa524..f73be6cba 100644 --- a/quickstep/src/com/android/quickstep/MotionEventQueue.java +++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java @@ -55,6 +55,8 @@ public class MotionEventQueue { ACTION_VIRTUAL | (6 << ACTION_POINTER_INDEX_SHIFT); private static final int ACTION_QUICK_STEP = ACTION_VIRTUAL | (7 << ACTION_POINTER_INDEX_SHIFT); + private static final int ACTION_COMMAND = + ACTION_VIRTUAL | (8 << ACTION_POINTER_INDEX_SHIFT); private final EventArray mEmptyArray = new EventArray(); private final Object mExecutionLock = new Object(); @@ -165,6 +167,9 @@ public class MotionEventQueue { case ACTION_QUICK_STEP: mConsumer.onQuickStep(event); break; + case ACTION_COMMAND: + mConsumer.onCommand(event.getSource()); + break; default: Log.e(TAG, "Invalid virtual event: " + event.getAction()); } @@ -222,6 +227,12 @@ public class MotionEventQueue { queueVirtualAction(ACTION_DEFER_INIT, 0); } + public void onCommand(int command) { + MotionEvent ev = MotionEvent.obtain(0, 0, ACTION_COMMAND, 0, 0, 0); + ev.setSource(command); + queueNoPreProcess(ev); + } + public TouchConsumer getConsumer() { return mConsumer; } diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java index 9ba332831..c85628263 100644 --- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java @@ -37,6 +37,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Looper; import android.os.SystemClock; +import android.util.SparseArray; import android.view.Choreographer; import android.view.Display; import android.view.MotionEvent; @@ -69,6 +70,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150; + private final SparseArray<RecentsAnimationState> mAnimationStates = new SparseArray<>(); private final RunningTaskInfo mRunningTask; private final RecentsModel mRecentsModel; private final Intent mHomeIntent; @@ -183,7 +185,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC case ACTION_UP: { TraceHelper.endSection("TouchInt"); - finishTouchTracking(); + finishTouchTracking(ev); break; } } @@ -212,8 +214,9 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private void startTouchTrackingForWindowAnimation(long touchTimeMs) { // Create the shared handler + RecentsAnimationState animationState = new RecentsAnimationState(); final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler( - mRunningTask, this, touchTimeMs, mActivityControlHelper); + animationState.id, mRunningTask, this, touchTimeMs, mActivityControlHelper); // Preload the plan mRecentsModel.loadTasks(mRunningTask.id, null); @@ -237,31 +240,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC public void onHandleAssistData(Bundle bundle) { mRecentsModel.preloadAssistData(mRunningTask.id, bundle); } - }, - new RecentsAnimationListener() { - public void onAnimationStart( - RecentsAnimationControllerCompat controller, - RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, - Rect minimizedHomeBounds) { - if (mInteractionHandler == handler) { - TraceHelper.partitionSection("RecentsController", "Received"); - handler.onRecentsAnimationStart(controller, - new RemoteAnimationTargetSet(apps, MODE_CLOSING), - homeContentInsets, minimizedHomeBounds); - } else { - TraceHelper.endSection("RecentsController", "Finishing no handler"); - controller.finish(false /* toHome */); - } - } - - public void onAnimationCanceled() { - TraceHelper.endSection("RecentsController", - "Cancelled: " + mInteractionHandler); - if (mInteractionHandler == handler) { - handler.onRecentsAnimationCanceled(); - } - } - }, null, null); + }, animationState, null, null); if (Looper.myLooper() != Looper.getMainLooper()) { startActivity.run(); @@ -277,12 +256,22 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC } } + @Override + public void onCommand(int command) { + RecentsAnimationState state = mAnimationStates.get(command); + if (state != null) { + state.execute(); + } + } + /** * Called when the gesture has ended. Does not correlate to the completion of the interaction as * the animation can still be running. */ - private void finishTouchTracking() { + private void finishTouchTracking(MotionEvent ev) { if (mPassedInitialSlop && mInteractionHandler != null) { + mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement); + mVelocityTracker.computeCurrentVelocity(1000, ViewConfiguration.get(this).getScaledMaximumFlingVelocity()); @@ -398,4 +387,55 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC // TODO: Consider also check if the eventQueue is using mainThread of not. return mInteractionHandler != null; } + + private class RecentsAnimationState implements RecentsAnimationListener { + + private final int id; + + private RecentsAnimationControllerCompat mController; + private RemoteAnimationTargetSet mTargets; + private Rect mHomeContentInsets; + private Rect mMinimizedHomeBounds; + private boolean mCancelled; + + public RecentsAnimationState() { + id = mAnimationStates.size(); + mAnimationStates.put(id, this); + } + + @Override + public void onAnimationStart( + RecentsAnimationControllerCompat controller, + RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, + Rect minimizedHomeBounds) { + mController = controller; + mTargets = new RemoteAnimationTargetSet(apps, MODE_CLOSING); + mHomeContentInsets = homeContentInsets; + mMinimizedHomeBounds = minimizedHomeBounds; + mEventQueue.onCommand(id); + } + + @Override + public void onAnimationCanceled() { + mCancelled = true; + mEventQueue.onCommand(id); + } + + public void execute() { + if (mInteractionHandler == null || mInteractionHandler.id != id) { + if (!mCancelled && mController != null) { + TraceHelper.endSection("RecentsController", "Finishing no handler"); + mController.finish(false /* toHome */); + } + } else if (mCancelled) { + TraceHelper.endSection("RecentsController", + "Cancelled: " + mInteractionHandler); + mInteractionHandler.onRecentsAnimationCanceled(); + } else { + TraceHelper.partitionSection("RecentsController", "Received"); + mInteractionHandler.onRecentsAnimationStart(mController, mTargets, + mHomeContentInsets, mMinimizedHomeBounds); + } + } + } } diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java index 8e1a3d5d8..7a79c6f4d 100644 --- a/quickstep/src/com/android/quickstep/QuickScrubController.java +++ b/quickstep/src/com/android/quickstep/QuickScrubController.java @@ -40,7 +40,7 @@ import com.android.quickstep.views.TaskView; public class QuickScrubController implements OnAlarmListener { public static final int QUICK_SCRUB_FROM_APP_START_DURATION = 240; - public static final int QUICK_SCRUB_FROM_HOME_START_DURATION = 150; + public static final int QUICK_SCRUB_FROM_HOME_START_DURATION = 200; // We want the translation y to finish faster than the rest of the animation. public static final float QUICK_SCRUB_TRANSLATION_Y_FACTOR = 5f / 6; public static final Interpolator QUICK_SCRUB_START_INTERPOLATOR = FAST_OUT_SLOW_IN; @@ -132,6 +132,17 @@ public class QuickScrubController implements OnAlarmListener { } } + public void cancelActiveQuickscrub() { + if (!mInQuickScrub) { + return; + } + Log.d(TAG, "Quickscrub was active, cancelling"); + mInQuickScrub = false; + mActivityControlHelper = null; + mOnFinishedTransitionToQuickScrubRunnable = null; + mRecentsView.setNextPageSwitchRunnable(null); + } + /** * Initializes the UI for quick scrub, returns true if success. */ @@ -145,6 +156,10 @@ public class QuickScrubController implements OnAlarmListener { return true; } + public boolean isWaitingForTaskLaunch() { + return mWaitingForTaskLaunch; + } + /** * Attempts to go to normal overview or back to home, so UI doesn't prevent user interaction. */ diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java index aed995957..2c3f77f21 100644 --- a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java +++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java @@ -20,6 +20,7 @@ import android.content.Context; import com.android.launcher3.MainProcessInitializer; import com.android.systemui.shared.system.ThreadedRendererCompat; +@SuppressWarnings("unused") public class QuickstepProcessInitializer extends MainProcessInitializer { public QuickstepProcessInitializer(Context context) { } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java index 30b10b0ea..34d42ac92 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java @@ -20,6 +20,8 @@ import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.UiThreadHelper; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; + +import java.util.ArrayList; import java.util.concurrent.ExecutorService; /** @@ -27,6 +29,10 @@ import java.util.concurrent.ExecutorService; */ public class RecentsAnimationWrapper { + // A list of callbacks to run when we receive the recents animation target. There are different + // than the state callbacks as these run on the current worker thread. + private final ArrayList<Runnable> mCallbacks = new ArrayList<>(); + public RemoteAnimationTargetSet targetSet; private RecentsAnimationControllerCompat mController; @@ -46,6 +52,21 @@ public class RecentsAnimationWrapper { if (mInputConsumerEnabled) { enableInputConsumer(); } + + if (!mCallbacks.isEmpty()) { + for (Runnable action : new ArrayList<>(mCallbacks)) { + action.run(); + } + mCallbacks.clear(); + } + } + + public synchronized void runOnInit(Runnable action) { + if (targetSet == null) { + mCallbacks.add(action); + } else { + action.run(); + } } /** diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java index 228af8e90..f82ff8c53 100644 --- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java +++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java @@ -16,6 +16,8 @@ package com.android.quickstep; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; + import android.content.ComponentName; import android.content.Intent; import android.graphics.Bitmap; @@ -35,6 +37,7 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.popup.SystemShortcut; +import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.InstantAppResolver; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskThumbnailView; @@ -166,7 +169,8 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut Log.w(TAG, "Failed to notify SysUI of split screen: ", e); return; } - + activity.getUserEventDispatcher().logActionOnControl(TAP, + LauncherLogProto.ControlType.SPLIT_SCREEN_TARGET); // Add a device profile change listener to kick off animating the side tasks // once we enter multiwindow mode and relayout activity.addOnDeviceProfileChangeListener(onDeviceProfileChangeListener); diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java index aa844d80d..4cecffa2b 100644 --- a/quickstep/src/com/android/quickstep/TouchConsumer.java +++ b/quickstep/src/com/android/quickstep/TouchConsumer.java @@ -48,6 +48,8 @@ public interface TouchConsumer extends Consumer<MotionEvent> { default void onQuickStep(MotionEvent ev) { } + default void onCommand(int command) { } + /** * Called on the binder thread to allow the consumer to process the motion event before it is * posted on a handler thread. diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 191c237f6..b1663b169 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -16,6 +16,7 @@ package com.android.quickstep; import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER; +import static com.android.launcher3.Utilities.SINGLE_FRAME_MS; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.LINEAR; @@ -29,6 +30,7 @@ import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; +import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; @@ -36,6 +38,7 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; +import android.os.UserHandle; import android.support.annotation.AnyThread; import android.support.annotation.UiThread; import android.support.annotation.WorkerThread; @@ -51,6 +54,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.logging.UserEventDispatcher; @@ -65,11 +69,12 @@ import com.android.quickstep.ActivityControlHelper.AnimationFactory; import com.android.quickstep.ActivityControlHelper.LayoutListener; import com.android.quickstep.TouchConsumer.InteractionType; import com.android.quickstep.util.ClipAnimationHelper; -import com.android.quickstep.util.TransformedRect; import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.TransformedRect; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.LatencyTrackerCompat; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; @@ -167,6 +172,12 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); + // An increasing identifier per single instance of OtherActivityTouchConsumer. Generally one + // instance of OtherActivityTouchConsumer will only have one swipe handle, but sometimes we can + // end up with multiple handlers if we get recents command in the middle of a swipe gesture. + // This is used to match the corresponding activity manager callbacks in + // OtherActivityTouchConsumer + public final int id; private final Context mContext; private final ActivityControlHelper<T> mActivityControlHelper; private final ActivityInitListener mActivityInitListener; @@ -199,6 +210,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { InputConsumerController.getRecentsAnimationInputConsumer(); private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper(); + private final long mTouchTimeMs; private long mLauncherFrameDrawnTime; @@ -207,8 +219,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { private float mLongSwipeDisplacement = 0; private LongSwipeHelper mLongSwipeController; - WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs, - ActivityControlHelper<T> controller) { + WindowTransformSwipeHandler(int id, RunningTaskInfo runningTaskInfo, Context context, + long touchTimeMs, ActivityControlHelper<T> controller) { + this.id = id; mContext = context; mRunningTaskInfo = runningTaskInfo; mRunningTaskId = runningTaskInfo.id; @@ -453,11 +466,40 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { "Can't change interaction type to " + interactionType); } mInteractionType = interactionType; + mRecentsAnimationWrapper.runOnInit(this::shiftAnimationDestinationForQuickscrub); setStateOnUiThread(STATE_QUICK_SCRUB_START | STATE_GESTURE_COMPLETED); // Start the window animation without waiting for launcher. - animateToProgress(1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR); + animateToProgress(mCurrentShift.value, 1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR); + } + + private void shiftAnimationDestinationForQuickscrub() { + TransformedRect tempRect = new TransformedRect(); + mActivityControlHelper + .getSwipeUpDestinationAndLength(mDp, mContext, mInteractionType, tempRect); + mClipAnimationHelper.updateTargetRect(tempRect); + + float offsetY = + mActivityControlHelper.getTranslationYForQuickScrub(tempRect, mDp, mContext); + float scale, offsetX; + Resources res = mContext.getResources(); + + if (ActivityManagerWrapper.getInstance().getRecentTasks(2, UserHandle.myUserId()).size() + < 2) { + // There are not enough tasks, we don't need to shift + offsetX = 0; + scale = 1; + } else { + offsetX = res.getDimensionPixelSize(R.dimen.recents_page_spacing) + + tempRect.rect.width(); + float distanceToReachEdge = mDp.widthPx / 2 + tempRect.rect.width() / 2 + + res.getDimensionPixelSize(R.dimen.recents_page_spacing); + float interpolation = Math.min(1, offsetX / distanceToReachEdge); + scale = TaskView.getCurveScaleForInterpolation(interpolation); + } + mClipAnimationHelper.offsetTarget(scale, Utilities.isRtl(res) ? -offsetX : offsetX, offsetY, + QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR); } @WorkerThread @@ -606,11 +648,13 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { private void handleNormalGestureEnd(float endVelocity, boolean isFling) { long duration = MAX_SWIPE_DURATION; final float endShift; + final float startShift; if (!isFling) { endShift = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW && mGestureStarted ? 1 : 0; long expectedDuration = Math.abs(Math.round((endShift - mCurrentShift.value) * MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER)); duration = Math.min(MAX_SWIPE_DURATION, expectedDuration); + startShift = mCurrentShift.value; } else { endShift = endVelocity < 0 ? 1 : 0; float minFlingVelocity = mContext.getResources() @@ -624,9 +668,11 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { long baseDuration = Math.round(1000 * Math.abs(distanceToTravel / endVelocity)); duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration); } + startShift = Utilities.boundToRange(mCurrentShift.value - endVelocity * SINGLE_FRAME_MS + / (mTransitionDragLength * 1000), 0, 1); } - animateToProgress(endShift, duration, DEACCEL); + animateToProgress(startShift, endShift, duration, DEACCEL); } private void doLogGesture(boolean toLauncher) { @@ -646,9 +692,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { } /** Animates to the given progress, where 0 is the current app and 1 is overview. */ - private void animateToProgress(float progress, long duration, Interpolator interpolator) { - mIsGoingToHome = Float.compare(progress, 1) == 0; - ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration); + private void animateToProgress(float start, float end, long duration, + Interpolator interpolator) { + mIsGoingToHome = Float.compare(end, 1) == 0; + ObjectAnimator anim = mCurrentShift.animateToValue(start, end).setDuration(duration); anim.setInterpolator(interpolator); anim.addListener(new AnimationSuccessListener() { @Override @@ -658,7 +705,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { : STATE_SCALED_CONTROLLER_APP); } }); - anim.start(); + mRecentsAnimationWrapper.runOnInit(anim::start); } @UiThread @@ -700,6 +747,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { mRecentsView.setRunningTaskHidden(false); mRecentsView.setRunningTaskIconScaledDown(false /* isScaledDown */, false /* animate */); + mQuickScrubController.cancelActiveQuickscrub(); } private void notifyTransitionCancelled() { @@ -785,30 +833,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { // Inform the last progress in case we skipped before. mQuickScrubController.onQuickScrubProgress(mCurrentQuickScrubProgress); - - // Make sure the window follows the first task if it moves, e.g. during quick scrub. - TaskView firstTask = mRecentsView.getPageAt(0); - // The first task may be null if we are swiping up from a task that does not - // appear in the list (i.e. the assistant) - if (firstTask != null) { - int scrollForFirstTask = mRecentsView.getScrollForPage(0); - int scrollForSecondTask = mRecentsView.getChildCount() > 1 - ? mRecentsView.getScrollForPage(1) : scrollForFirstTask; - float offsetFromFirstTask = scrollForFirstTask - scrollForSecondTask; - - TransformedRect tempRect = new TransformedRect(); - mActivityControlHelper - .getSwipeUpDestinationAndLength(mDp, mContext, mInteractionType, tempRect); - float distanceToReachEdge = mDp.widthPx / 2 + tempRect.rect.width() / 2 + - mContext.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing); - float interpolation = Math.min(1, - Math.abs(offsetFromFirstTask) / distanceToReachEdge); - - mClipAnimationHelper.offsetTarget( - firstTask.getCurveScaleForInterpolation(interpolation), offsetFromFirstTask, - mActivityControlHelper.getTranslationYForQuickScrub(mActivity), - QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR); - } } private void onFinishedTransitionToQuickScrub() { diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index c5d74c7d9..9e2de3395 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -20,10 +20,8 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; -import android.view.accessibility.AccessibilityNodeInfo; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.R; import com.android.quickstep.RecentsActivity; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.RecentsView; @@ -73,21 +71,4 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> { // Just use the activity task size for multi-window as well. return false; } - - @Override - public void addTaskAccessibilityActionsExtra(AccessibilityNodeInfo info) { - info.addAction( - new AccessibilityNodeInfo.AccessibilityAction( - R.string.recents_clear_all, - getContext().getText(R.string.recents_clear_all))); - } - - @Override - public boolean performTaskAccessibilityActionExtra(int action) { - if (action == R.string.recents_clear_all) { - dismissAllTasks(); - return true; - } - return false; - } } diff --git a/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java index 04153cc99..6dff187ea 100644 --- a/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java +++ b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java @@ -15,10 +15,9 @@ */ package com.android.quickstep.logging; +import android.content.Context; import android.util.Log; -import static com.android.launcher3.logging.LoggerUtils.newAction; -import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CANCEL_TARGET; import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE; @@ -27,20 +26,20 @@ import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_QUICK import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_SWIPE_UP_ONBOARDING_TIP; import com.android.launcher3.logging.UserEventDispatcher; -import com.android.launcher3.model.nano.LauncherDumpProto; -import com.android.launcher3.userevent.nano.LauncherLogExtensions; import com.android.launcher3.userevent.nano.LauncherLogProto; -import com.android.systemui.shared.system.LauncherEventUtil; import com.android.systemui.shared.system.MetricsLoggerCompat; /** * This class handles AOSP MetricsLogger function calls and logging around * quickstep interactions. */ +@SuppressWarnings("unused") public class UserEventDispatcherExtension extends UserEventDispatcher { private static final String TAG = "UserEventDispatcher"; + public UserEventDispatcherExtension(Context context) { } + public void logStateChangeAction(int action, int dir, int srcChildTargetType, int srcParentContainerType, int dstContainerType, int pageIndex) { diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java new file mode 100644 index 000000000..40dd74bbb --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 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.quickstep.util; + +import static com.android.quickstep.util.RemoteAnimationProvider.prepareTargetsForFirstFrame; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; + +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; + +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.shared.system.TransactionCompat; + +/** + * Animation listener which fades out the closing targets + */ +public class RemoteFadeOutAnimationListener implements AnimatorUpdateListener { + + private final RemoteAnimationTargetSet mTarget; + private boolean mFirstFrame = true; + + public RemoteFadeOutAnimationListener(RemoteAnimationTargetCompat[] targets) { + mTarget = new RemoteAnimationTargetSet(targets, MODE_CLOSING); + } + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + TransactionCompat t = new TransactionCompat(); + if (mFirstFrame) { + prepareTargetsForFirstFrame(mTarget.unfilteredApps, t, MODE_CLOSING); + mFirstFrame = false; + } + + float alpha = 1 - valueAnimator.getAnimatedFraction(); + for (RemoteAnimationTargetCompat app : mTarget.apps) { + t.setAlpha(app.leash, alpha); + } + t.apply(); + } +} diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java index 25e3dc6c1..0025df136 100644 --- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java +++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java @@ -16,13 +16,11 @@ package com.android.quickstep.views; -import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS; - import android.content.Context; import android.graphics.Rect; -import android.os.Bundle; import android.support.annotation.Nullable; import android.util.AttributeSet; +import android.view.accessibility.AccessibilityNodeInfo; import android.widget.Button; public class ClearAllButton extends Button { @@ -37,12 +35,9 @@ public class ClearAllButton extends Button { } @Override - public boolean performAccessibilityAction(int action, Bundle arguments) { - final boolean res = super.performAccessibilityAction(action, arguments); - if (action == ACTION_ACCESSIBILITY_FOCUS) { - mRecentsView.revealClearAllButton(); - } - return res; + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setParent(mRecentsView); // Pretend we are a part of the task carousel. } @Override diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index dee15d0d7..d550edcd3 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -39,6 +39,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; import android.support.annotation.Nullable; @@ -386,7 +387,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl private void updateClearAllButtonAlpha() { if (mClearAllButton != null) { final float alpha = calculateClearAllButtonAlpha(); - mIsClearAllButtonFullyRevealed = alpha == 1; + final boolean revealed = alpha == 1; + if (mIsClearAllButtonFullyRevealed != revealed) { + mIsClearAllButtonFullyRevealed = revealed; + mClearAllButton.setImportantForAccessibility(revealed ? + IMPORTANT_FOR_ACCESSIBILITY_YES : + IMPORTANT_FOR_ACCESSIBILITY_NO); + } mClearAllButton.setAlpha(alpha * mContentAlpha); } } @@ -507,6 +514,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl DeviceProfile dp = mActivity.getDeviceProfile(); getTaskSize(dp, mTempRect); + // Keep this logic in sync with ActivityControlHelper.getTranslationYForQuickScrub. mTempRect.top -= mTaskTopMargin; setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top, dp.availableWidthPx + mInsets.left - mTempRect.right, @@ -1285,7 +1293,30 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl } @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + if (getChildCount() > 0) { + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + if (!mIsClearAllButtonFullyRevealed && getCurrentPage() == getPageCount() - 1) { + revealClearAllButton(); + return true; + } + } + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + if (mIsClearAllButtonFullyRevealed) { + setCurrentPage(getChildCount() - 1); + return true; + } + } + break; + } + } + return super.performAccessibilityAction(action, arguments); + } + + @Override public void addChildrenForAccessibility(ArrayList<View> outChildren) { + outChildren.add(mClearAllButton); for (int i = getChildCount() - 1; i >= 0; --i) { outChildren.add(getChildAt(i)); } @@ -1295,6 +1326,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); + if (getChildCount() > 0) { + info.addAction(mIsClearAllButtonFullyRevealed ? + AccessibilityNodeInfo.ACTION_SCROLL_FORWARD : + AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + info.setScrollable(true); + } + final AccessibilityNodeInfo.CollectionInfo collectionInfo = AccessibilityNodeInfo.CollectionInfo.obtain( 1, getChildCount(), false, @@ -1306,11 +1344,15 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { - final int visiblePageNumber = getChildCount() - getCurrentPage() - 1; - event.setFromIndex(visiblePageNumber); - event.setToIndex(visiblePageNumber); - event.setItemCount(getChildCount()); + event.setScrollable(getPageCount() > 0); + + if (!mIsClearAllButtonFullyRevealed + && event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { + final int childCount = getChildCount(); + final int[] visibleTasks = getVisibleChildrenRange(); + event.setFromIndex(childCount - visibleTasks[1] - 1); + event.setToIndex(childCount - visibleTasks[0] - 1); + event.setItemCount(childCount); } } @@ -1325,9 +1367,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl return true; } - public void addTaskAccessibilityActionsExtra(AccessibilityNodeInfo info) { - } - public boolean performTaskAccessibilityActionExtra(int action) { return false; } diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java index 31c8b6448..c6cd52769 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java +++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java @@ -124,4 +124,9 @@ public class RecentsViewContainer extends InsettableFrameLayout { return mRecentsView.requestFocus(direction, previouslyFocusedRect) || super.requestFocus(direction, previouslyFocusedRect); } + + @Override + public void addChildrenForAccessibility(ArrayList<View> outChildren) { + outChildren.add(mRecentsView); + } }
\ No newline at end of file diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java index aca8351a0..c780b6234 100644 --- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java +++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java @@ -28,9 +28,6 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.Path.Direction; import android.graphics.Path.Op; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.util.AttributeSet; import com.android.launcher3.DeviceProfile; @@ -48,11 +45,6 @@ import com.android.launcher3.views.ScrimView; */ public class ShelfScrimView extends ScrimView { - private static final int THRESHOLD_ALPHA_DARK = 102; - private static final int THRESHOLD_ALPHA_LIGHT = 46; - private static final int THRESHOLD_ALPHA_SUPER_LIGHT = 128; - private static final int CLEAR_ALL_TASKS = R.string.recents_clear_all; - // In transposed layout, we simply draw a flat color. private boolean mDrawingFlatColor; @@ -81,13 +73,7 @@ public class ShelfScrimView extends ScrimView { mMaxScrimAlpha = OVERVIEW.getWorkspaceScrimAlpha(mLauncher); mEndAlpha = Color.alpha(mEndScrim); - if (Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark)) { - mThresholdAlpha = THRESHOLD_ALPHA_DARK; - } else if (Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) { - mThresholdAlpha = THRESHOLD_ALPHA_SUPER_LIGHT; - } else { - mThresholdAlpha = THRESHOLD_ALPHA_LIGHT; - } + mThresholdAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha); mRadius = mLauncher.getResources().getDimension(R.dimen.shelf_surface_radius); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -208,43 +194,4 @@ public class ShelfScrimView extends ScrimView { mRadius, mRadius, mPaint); return minTop - mDragHandleSize - top; } - - @NonNull - @Override - protected AccessibilityHelper createAccessibilityHelper() { - return new ShelfScrimAccessibilityHelper(); - } - - protected class ShelfScrimAccessibilityHelper extends AccessibilityHelper { - @Override - protected void onPopulateNodeForVirtualView(int virtualViewId, - AccessibilityNodeInfoCompat node) { - super.onPopulateNodeForVirtualView(virtualViewId, node); - - if (mLauncher.isInState(OVERVIEW)) { - final RecentsView overviewPanel = mLauncher.getOverviewPanel(); - if (overviewPanel.getChildCount() != 0) { - node.addAction( - new AccessibilityNodeInfoCompat.AccessibilityActionCompat( - CLEAR_ALL_TASKS, - getContext().getText(CLEAR_ALL_TASKS))); - } - } - } - - @Override - protected boolean onPerformActionForVirtualView( - int virtualViewId, int action, Bundle arguments) { - if (super.onPerformActionForVirtualView(virtualViewId, action, arguments)) return true; - - if (action == CLEAR_ALL_TASKS) { - if (mLauncher.isInState(OVERVIEW)) { - mLauncher.<RecentsView>getOverviewPanel().dismissAllTasks(); - } - return true; - } - - return false; - } - } } diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index 128a19e06..d9dfd1815 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -29,6 +29,7 @@ import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Shader; +import android.support.v4.graphics.ColorUtils; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Property; @@ -37,8 +38,10 @@ import android.view.View; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.SystemUiController; +import com.android.launcher3.util.Themes; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskOverlayFactory.TaskOverlay; import com.android.systemui.shared.recents.model.Task; @@ -50,6 +53,7 @@ import com.android.systemui.shared.recents.model.ThumbnailData; public class TaskThumbnailView extends View { private static final LightingColorFilter[] sDimFilterCache = new LightingColorFilter[256]; + private static final LightingColorFilter[] sHighlightFilterCache = new LightingColorFilter[256]; public static final Property<TaskThumbnailView, Float> DIM_ALPHA_MULTIPLIER = new FloatProperty<TaskThumbnailView>("dimAlphaMultiplier") { @@ -68,6 +72,7 @@ public class TaskThumbnailView extends View { private final BaseActivity mActivity; private final TaskOverlay mOverlay; + private final boolean mIsDarkTextTheme; private final Paint mPaint = new Paint(); private final Paint mBackgroundPaint = new Paint(); @@ -97,6 +102,7 @@ public class TaskThumbnailView extends View { mPaint.setFilterBitmap(true); mBackgroundPaint.setColor(Color.WHITE); mActivity = BaseActivity.fromContext(context); + mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText); } public void bind() { @@ -198,7 +204,7 @@ public class TaskThumbnailView extends View { private void updateThumbnailPaintFilter() { int mul = (int) ((1 - mDimAlpha * mDimAlphaMultiplier) * 255); if (mBitmapShader != null) { - LightingColorFilter filter = getLightingColorFilter(mul); + LightingColorFilter filter = getDimmingColorFilter(mul, mIsDarkTextTheme); mPaint.setColorFilter(filter); mBackgroundPaint.setColorFilter(filter); } else { @@ -287,16 +293,25 @@ public class TaskThumbnailView extends View { updateThumbnailMatrix(); } - private static LightingColorFilter getLightingColorFilter(int dimColor) { - if (dimColor < 0) { - dimColor = 0; - } else if (dimColor > 255) { - dimColor = 255; + private static LightingColorFilter getDimmingColorFilter(int intensity, boolean shouldLighten) { + intensity = Utilities.boundToRange(intensity, 0, 255); + if (intensity == 255) { + return null; } - if (sDimFilterCache[dimColor] == null) { - sDimFilterCache[dimColor] = - new LightingColorFilter(Color.argb(255, dimColor, dimColor, dimColor), 0); + if (shouldLighten) { + if (sHighlightFilterCache[intensity] == null) { + int colorAdd = 255 - intensity; + sHighlightFilterCache[intensity] = new LightingColorFilter( + Color.argb(255, intensity, intensity, intensity), + Color.argb(255, colorAdd, colorAdd, colorAdd)); + } + return sHighlightFilterCache[intensity]; + } else { + if (sDimFilterCache[intensity] == null) { + sDimFilterCache[intensity] = new LightingColorFilter( + Color.argb(255, intensity, intensity, intensity), 0); + } + return sDimFilterCache[intensity]; } - return sDimFilterCache[dimColor]; } } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 5413a1319..b5f31b8e2 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -250,12 +250,12 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f); } - public float getCurveScaleForInterpolation(float linearInterpolation) { + public static float getCurveScaleForInterpolation(float linearInterpolation) { float curveInterpolation = CURVE_INTERPOLATOR.getInterpolation(linearInterpolation); return getCurveScaleForCurveInterpolation(curveInterpolation); } - private float getCurveScaleForCurveInterpolation(float curveInterpolation) { + private static float getCurveScaleForCurveInterpolation(float curveInterpolation) { return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR; } @@ -321,8 +321,6 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback } final RecentsView recentsView = getRecentsView(); - recentsView.addTaskAccessibilityActionsExtra(info); - final AccessibilityNodeInfo.CollectionItemInfo itemInfo = AccessibilityNodeInfo.CollectionItemInfo.obtain( 0, 1, recentsView.getChildCount() - recentsView.indexOfChild(this) - 1, 1, diff --git a/res/layout/longpress_options_menu.xml b/res/layout/longpress_options_menu.xml index 168dbc3a2..20bb5b81b 100644 --- a/res/layout/longpress_options_menu.xml +++ b/res/layout/longpress_options_menu.xml @@ -22,4 +22,5 @@ android:clipToPadding="false" android:clipChildren="false" android:elevation="@dimen/deep_shortcuts_elevation" + android:importantForAccessibility="yes" android:orientation="vertical" /> diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 64ca05e3c..30091a5f7 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -20,6 +20,7 @@ <!-- Attributes used for launcher theme --> <attr name="allAppsScrimColor" format="color" /> + <attr name="allAppsInterimScrimAlpha" format="integer" /> <attr name="allAppsNavBarScrimColor" format="color" /> <attr name="popupColorPrimary" format="color" /> <attr name="popupColorSecondary" format="color" /> diff --git a/res/values/styles.xml b/res/values/styles.xml index 2b760f349..31cbaa11a 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -29,6 +29,7 @@ <style name="BaseLauncherThemeWithCustomAttrs" parent="@style/BaseLauncherTheme"> <item name="allAppsScrimColor">#EAFFFFFF</item> + <item name="allAppsInterimScrimAlpha">46</item> <item name="allAppsNavBarScrimColor">#66FFFFFF</item> <item name="popupColorPrimary">#FFF</item> <item name="popupColorSecondary">#F5F5F5</item> <!-- Gray 100 --> @@ -47,6 +48,7 @@ <style name="LauncherTheme.DarkText" parent="@style/LauncherTheme"> <item name="workspaceTextColor">#FF212121</item> + <item name="allAppsInterimScrimAlpha">128</item> <item name="workspaceShadowColor">@android:color/transparent</item> <item name="workspaceAmbientShadowColor">@android:color/transparent</item> <item name="workspaceKeyShadowColor">@android:color/transparent</item> @@ -62,6 +64,7 @@ <item name="android:colorControlHighlight">#A0FFFFFF</item> <item name="android:colorPrimary">#FF212121</item> <item name="allAppsScrimColor">#EA212121</item> + <item name="allAppsInterimScrimAlpha">102</item> <item name="allAppsNavBarScrimColor">#80000000</item> <item name="popupColorPrimary">?android:attr/colorPrimary</item> <item name="popupColorSecondary">#424242</item> <!-- Gray 800 --> @@ -71,6 +74,7 @@ </style> <style name="LauncherThemeDark.DarKText" parent="@style/LauncherThemeDark"> + <item name="allAppsInterimScrimAlpha">25</item> <item name="workspaceTextColor">#FF212121</item> <item name="workspaceShadowColor">@android:color/transparent</item> <item name="workspaceAmbientShadowColor">@android:color/transparent</item> diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java index b5eef8bd3..05c515bf4 100644 --- a/src/com/android/launcher3/LauncherStateManager.java +++ b/src/com/android/launcher3/LauncherStateManager.java @@ -17,7 +17,6 @@ package com.android.launcher3; import static android.view.View.VISIBLE; - import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE; @@ -222,7 +221,8 @@ public class LauncherStateManager { } } - // Cancel the current animation + // Cancel the current animation. This will reset mState to mCurrentStableState, so store it. + LauncherState fromState = mState; mConfig.reset(); if (!animated) { @@ -245,10 +245,10 @@ public class LauncherStateManager { // Since state NORMAL can be reached from multiple states, just assume that the // transition plays in reverse and use the same duration as previous state. - mConfig.duration = state == NORMAL ? mState.transitionDuration : state.transitionDuration; + mConfig.duration = state == NORMAL ? fromState.transitionDuration : state.transitionDuration; AnimatorSetBuilder builder = new AnimatorSetBuilder(); - prepareForAtomicAnimation(mState, state, builder); + prepareForAtomicAnimation(fromState, state, builder); AnimatorSet animation = createAnimationToNewWorkspaceInternal( state, builder, onCompleteRunnable); Runnable runnable = new StartAnimRunnable(animation); @@ -348,6 +348,12 @@ public class LauncherStateManager { } @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); + mState = mCurrentStableState; + } + + @Override public void onAnimationSuccess(Animator animator) { // Run any queued runnables if (onCompleteRunnable != null) { @@ -432,7 +438,6 @@ public class LauncherStateManager { } public void setCurrentUserControlledAnimation(AnimatorPlaybackController controller) { - clearCurrentAnimation(); setCurrentAnimation(controller.getTarget()); mConfig.userControlled = true; mConfig.playbackController = controller; diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 5cc2e8fc5..de9cd986f 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -152,6 +152,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou // Similar to the platform implementation of isLayoutValid(); protected boolean mIsLayoutValid; + private int[] mTmpIntPair = new int[2]; + public PagedView(Context context) { this(context, null); } @@ -1448,6 +1450,10 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou protected boolean snapToPage(int whichPage, int delta, int duration, boolean immediate, TimeInterpolator interpolator) { + if (mFirstLayout) { + setCurrentPage(whichPage); + return false; + } if (FeatureFlags.IS_DOGFOOD_BUILD) { duration *= Settings.System.getFloat(getContext().getContentResolver(), @@ -1600,4 +1606,33 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou boolean shouldIncludeView(View view); } + + public int[] getVisibleChildrenRange() { + float visibleLeft = 0; + float visibleRight = visibleLeft + getMeasuredWidth(); + float scaleX = getScaleX(); + if (scaleX < 1 && scaleX > 0) { + float mid = getMeasuredWidth() / 2; + visibleLeft = mid - ((mid - visibleLeft) / scaleX); + visibleRight = mid + ((visibleRight - mid) / scaleX); + } + + int leftChild = -1; + int rightChild = -1; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getPageAt(i); + + float left = child.getLeft() + child.getTranslationX() - getScrollX(); + if (left <= visibleRight && (left + child.getMeasuredWidth()) >= visibleLeft) { + if (leftChild == -1) { + leftChild = i; + } + rightChild = i; + } + } + mTmpIntPair[0] = leftChild; + mTmpIntPair[1] = rightChild; + return mTmpIntPair; + } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 06eb82e3e..66fb3c6b3 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1381,28 +1381,9 @@ public class Workspace extends PagedView<WorkspacePageIndicator> if (mChildrenLayersEnabled) { final int screenCount = getChildCount(); - float visibleLeft = 0; - float visibleRight = visibleLeft + getMeasuredWidth(); - float scaleX = getScaleX(); - if (scaleX < 1 && scaleX > 0) { - float mid = getMeasuredWidth() / 2; - visibleLeft = mid - ((mid - visibleLeft) / scaleX); - visibleRight = mid + ((visibleRight - mid) / scaleX); - } - - int leftScreen = -1; - int rightScreen = -1; - for (int i = 0; i < screenCount; i++) { - final View child = getPageAt(i); - - float left = child.getLeft() + child.getTranslationX() - getScrollX(); - if (left <= visibleRight && (left + child.getMeasuredWidth()) >= visibleLeft) { - if (leftScreen == -1) { - leftScreen = i; - } - rightScreen = i; - } - } + final int[] visibleScreens = getVisibleChildrenRange(); + int leftScreen = visibleScreens[0]; + int rightScreen = visibleScreens[1]; if (mForceDrawAdjacentPages) { // In overview mode, make sure that the two side pages are visible. leftScreen = Utilities.boundToRange(getCurrentPage() - 1, 0, rightScreen); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 68ad6e346..72ba418b2 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -466,9 +466,12 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo */ public void addSpringFromFlingUpdateListener(ValueAnimator animator, float velocity) { animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + boolean shouldSpring = true; + @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { - if (valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) { + if (shouldSpring + && valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) { int searchViewId = getSearchView().getId(); addSpringView(searchViewId); @@ -481,7 +484,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo } }); - animator.removeUpdateListener(this); + shouldSpring = false; } } }); diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java index df4a7c1f5..1e84b416b 100644 --- a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java @@ -159,7 +159,7 @@ public abstract class BaseItemDragListener extends InternalStateHandler implemen postCleanup(); } - private void postCleanup() { + protected void postCleanup() { clearReference(); if (mLauncher != null) { // Remove any drag params from the launcher intent since the drag operation is complete. diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java index 924bb4c25..07eb0d60b 100644 --- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java @@ -22,14 +22,17 @@ import android.content.pm.LauncherApps.PinItemRequest; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; +import android.os.CancellationSignal; import android.view.DragEvent; import android.view.View; import android.widget.RemoteViews; import com.android.launcher3.DragSource; import com.android.launcher3.ItemInfo; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.PendingAddItemInfo; +import com.android.launcher3.uioverrides.UiFactory; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; @@ -44,11 +47,13 @@ import com.android.launcher3.widget.WidgetAddFlowHandler; public class PinItemDragListener extends BaseItemDragListener { private final PinItemRequest mRequest; + private final CancellationSignal mCancelSignal; public PinItemDragListener(PinItemRequest request, Rect previewRect, int previewBitmapWidth, int previewViewWidth) { super(previewRect, previewBitmapWidth, previewViewWidth); mRequest = request; + mCancelSignal = new CancellationSignal(); } @Override @@ -60,6 +65,15 @@ public class PinItemDragListener extends BaseItemDragListener { } @Override + public boolean init(Launcher launcher, boolean alreadyOnHome) { + super.init(launcher, alreadyOnHome); + if (!alreadyOnHome) { + UiFactory.useFadeOutAnimationForLauncherStart(launcher, mCancelSignal); + } + return false; + } + + @Override protected PendingItemDragHelper createDragHelper() { final PendingAddItemInfo item; if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) { @@ -95,6 +109,12 @@ public class PinItemDragListener extends BaseItemDragListener { targetParent.containerType = LauncherLogProto.ContainerType.PINITEM; } + @Override + protected void postCleanup() { + super.postCleanup(); + mCancelSignal.cancel(); + } + public static RemoteViews getPreview(PinItemRequest request) { Bundle extras = request.getExtras(); if (extras != null && diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java index f020d2d7c..89ba72abf 100644 --- a/src/com/android/launcher3/graphics/LauncherIcons.java +++ b/src/com/android/launcher3/graphics/LauncherIcons.java @@ -330,9 +330,9 @@ public class LauncherIcons implements AutoCloseable { mOldBounds.set(icon.getBounds()); if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) { - int offset = Math.max((int)(BLUR_FACTOR * textureWidth), Math.min(left, top)); + int offset = Math.max((int) Math.ceil(BLUR_FACTOR * textureWidth), Math.max(left, top)); int size = Math.max(width, height); - icon.setBounds(offset, offset, size, size); + icon.setBounds(offset, offset, offset + size, offset + size); } else { icon.setBounds(left, top, left+width, top+height); } diff --git a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java index bd5c06e5b..fde220cbf 100644 --- a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java +++ b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java @@ -18,7 +18,6 @@ package com.android.launcher3.keyboard; import android.graphics.Rect; import android.view.View; -import android.view.View.OnFocusChangeListener; import com.android.launcher3.PagedView; @@ -52,8 +51,8 @@ public class ViewGroupFocusHelper extends FocusIndicatorHelper { private void computeLocationRelativeToContainer(View child, Rect outRect) { View parent = (View) child.getParent(); - outRect.left += child.getLeft(); - outRect.top += child.getTop(); + outRect.left += child.getX(); + outRect.top += child.getY(); if (parent != mContainer) { if (parent instanceof PagedView) { @@ -64,22 +63,4 @@ public class ViewGroupFocusHelper extends FocusIndicatorHelper { computeLocationRelativeToContainer(parent, outRect); } } - - /** - * Sets the alpha of this FocusIndicatorHelper to 0 when a view with this listener - * receives focus. - */ - public View.OnFocusChangeListener getHideIndicatorOnFocusListener() { - return new OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) { - endCurrentAnimation(); - setCurrentView(null); - setAlpha(0); - invalidateDirty(); - } - } - }; - } } diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index f276fbfea..172cf41e0 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -527,6 +527,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, protected void closeComplete() { super.closeComplete(); mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible()); + mOriginalIcon.forceHideBadge(false); } @Override diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java index b83d3c0cd..b1dd003f8 100644 --- a/src/com/android/launcher3/provider/ImportDataTask.java +++ b/src/com/android/launcher3/provider/ImportDataTask.java @@ -142,6 +142,8 @@ public class ImportDataTask { // First row of first screen is not empty createEmptyRowOnFirstScreen = c.moveToNext(); } + } else { + createEmptyRowOnFirstScreen = false; } ArrayList<ContentProviderOperation> insertOperations = new ArrayList<>(BATCH_INSERT_SIZE); diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java index 65acaa973..b26d39fda 100644 --- a/src/com/android/launcher3/qsb/QsbContainerView.java +++ b/src/com/android/launcher3/qsb/QsbContainerView.java @@ -36,7 +36,6 @@ import android.widget.FrameLayout; import com.android.launcher3.AppWidgetResizeFrame; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -68,6 +67,10 @@ public class QsbContainerView extends FrameLayout { super.setPadding(0, 0, 0, 0); } + protected void setPaddingUnchecked(int left, int top, int right, int bottom) { + super.setPadding(left, top, right, bottom); + } + /** * A fragment to display the QSB. */ @@ -100,7 +103,7 @@ public class QsbContainerView extends FrameLayout { mWrapper = new FrameLayout(getActivity()); // Only add the view when enabled - if (FeatureFlags.QSB_ON_FIRST_SCREEN) { + if (isQsbEnabled()) { mWrapper.addView(createQsb(mWrapper)); } return mWrapper; @@ -212,7 +215,7 @@ public class QsbContainerView extends FrameLayout { private void rebindFragment() { // Exit if the embedded qsb is disabled - if (!FeatureFlags.QSB_ON_FIRST_SCREEN) { + if (!isQsbEnabled()) { return; } @@ -221,6 +224,10 @@ public class QsbContainerView extends FrameLayout { mWrapper.addView(createQsb(mWrapper)); } } + + public boolean isQsbEnabled() { + return FeatureFlags.QSB_ON_FIRST_SCREEN; + } } /** diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java index d22509344..5f965a341 100644 --- a/src/com/android/launcher3/util/Themes.java +++ b/src/com/android/launcher3/util/Themes.java @@ -52,6 +52,13 @@ public class Themes { return value; } + public static int getAttrInteger(Context context, int attr) { + TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); + int value = ta.getInteger(0, 0); + ta.recycle(); + return value; + } + /** * Returns the alpha corresponding to the theme attribute {@param attr}, in the range [0, 255]. */ diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index db98f9a80..5a7e50fae 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -18,6 +18,7 @@ package com.android.launcher3.uioverrides; import android.app.Activity; import android.content.Context; +import android.os.CancellationSignal; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherStateManager.StateHandler; @@ -51,6 +52,9 @@ public class UiFactory { public static void onTrimMemory(Launcher launcher, int level) { } + public static void useFadeOutAnimationForLauncherStart(Launcher launcher, + CancellationSignal cancellationSignal) { } + public static boolean dumpActivity(Activity activity, PrintWriter writer) { return false; } |