Merge "Removing horizontal bar from page indicator" into ub-launcher3-master
diff --git a/quickstep/res/drawable/task_thumbnail_background.xml b/quickstep/res/drawable/task_thumbnail_background.xml
index 603380e..f1f48ac 100644
--- a/quickstep/res/drawable/task_thumbnail_background.xml
+++ b/quickstep/res/drawable/task_thumbnail_background.xml
@@ -14,6 +14,5 @@
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
- <solid android:color="#FF000000" />
<corners android:radius="2dp" />
</shape>
diff --git a/src/com/android/launcher3/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
similarity index 80%
rename from src/com/android/launcher3/states/AllAppsState.java
rename to quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index ed3023a..1064492 100644
--- a/src/com/android/launcher3/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.states;
+package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
+import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN;
import android.view.View;
@@ -30,8 +31,6 @@
*/
public class AllAppsState extends LauncherState {
- public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
-
private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
public AllAppsState(int id) {
@@ -57,4 +56,15 @@
public View getFinalFocus(Launcher launcher) {
return launcher.getAppsView();
}
+
+ @Override
+ public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
+ // TODO: interpolate
+ return LauncherState.OVERVIEW.getWorkspaceScaleAndTranslation(launcher);
+ }
+
+ @Override
+ public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
+ return (i) -> 0;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java b/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java
new file mode 100644
index 0000000..1977e93
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.uioverrides;
+
+import com.android.launcher3.Alarm;
+import com.android.launcher3.OnAlarmListener;
+
+/**
+ * Utility class to detect a pause during a drag.
+ */
+public class DragPauseDetector implements OnAlarmListener {
+
+ private static final float MAX_VELOCITY_TO_PAUSE = 0.2f;
+ private static final long PAUSE_DURATION = 100;
+
+ private final Alarm mAlarm;
+ private final Runnable mOnPauseCallback;
+
+ private boolean mEnabled = true;
+ private boolean mTriggered = false;
+
+ public DragPauseDetector(Runnable onPauseCallback) {
+ mOnPauseCallback = onPauseCallback;
+
+ mAlarm = new Alarm();
+ mAlarm.setOnAlarmListener(this);
+ mAlarm.setAlarm(PAUSE_DURATION);
+ }
+
+ public void onDrag(float displacement, float velocity) {
+ if (mTriggered || !mEnabled) {
+ return;
+ }
+
+ if (Math.abs(velocity) > MAX_VELOCITY_TO_PAUSE) {
+ // Cancel any previous alarm and set a new alarm
+ mAlarm.setAlarm(PAUSE_DURATION);
+ }
+ }
+
+ @Override
+ public void onAlarm(Alarm alarm) {
+ if (!mTriggered && mEnabled) {
+ mTriggered = true;
+ mOnPauseCallback.run();
+ }
+ }
+
+ public boolean isTriggered () {
+ return mTriggered;
+ }
+
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ public void setEnabled(boolean isEnabled) {
+ if (mEnabled != isEnabled) {
+ mEnabled = isEnabled;
+ if (isEnabled && !mTriggered) {
+ mAlarm.setAlarm(PAUSE_DURATION);
+ } else if (!isEnabled) {
+ mAlarm.cancelAlarm();
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index a70ee70..3458a3f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -17,10 +17,12 @@
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
+import android.graphics.Rect;
import android.view.View;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.RecentsView;
@@ -29,7 +31,7 @@
*/
public class OverviewState extends LauncherState {
- private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE
+ private static final int STATE_FLAGS = FLAG_SHOW_SCRIM
| FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED;
public OverviewState(int id) {
@@ -38,8 +40,20 @@
@Override
public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
- // TODO: Find a better transition
- return new float[] {0f, 0};
+ Rect pageRect = new Rect();
+ RecentsView.getPageRect(launcher, pageRect);
+ Workspace ws = launcher.getWorkspace();
+ float childWidth = ws.getNormalChildWidth();
+ if (childWidth <= 0 || pageRect.isEmpty()) {
+ return super.getWorkspaceScaleAndTranslation(launcher);
+ }
+
+ Rect insets = launcher.getDragLayer().getInsets();
+ float scale = pageRect.width() / childWidth;
+
+ float halfHeight = ws.getHeight() / 2;
+ float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
+ return new float[] {scale, pageRect.top - childTop};
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index da1eff9..60cd0c2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -15,39 +15,90 @@
*/
package com.android.launcher3.uioverrides;
-import static com.android.launcher3.WorkspaceStateTransitionAnimation.NO_ANIM_PROPERTY_SETTER;
-
-import android.animation.AnimatorSet;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.view.View;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.WorkspaceStateTransitionAnimation.AnimatedPropertySetter;
-import com.android.launcher3.WorkspaceStateTransitionAnimation.PropertySetter;
-import com.android.launcher3.anim.AnimationLayerSet;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.Interpolators;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.RecentsView;
public class RecentsViewStateController implements StateHandler {
private final Launcher mLauncher;
+ private final RecentsView mRecentsView;
+
+ private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::applyProgress);
+ // The fraction representing the visibility of the RecentsView. This allows delaying the
+ // overall transition while the RecentsView is being shown or hidden.
+ private final AnimatedFloat mVisibilityMultiplier = new AnimatedFloat(this::applyProgress);
public RecentsViewStateController(Launcher launcher) {
mLauncher = launcher;
+ mRecentsView = launcher.getOverviewPanel();
+ mRecentsView.setStateController(this);
}
@Override
public void setState(LauncherState state) {
- setState(state, NO_ANIM_PROPERTY_SETTER);
+ setVisibility(state == LauncherState.OVERVIEW);
+ setTransitionProgress(state == LauncherState.OVERVIEW ? 1 : 0);
}
@Override
- public void setStateWithAnimation(LauncherState toState, AnimationLayerSet layerViews,
- AnimatorSet anim, AnimationConfig config) {
- setState(toState, new AnimatedPropertySetter(config.duration, layerViews, anim));
+ public void setStateWithAnimation(LauncherState toState,
+ AnimatorSetBuilder builder, AnimationConfig config) {
+ ObjectAnimator progressAnim =
+ mTransitionProgress.animateToValue(toState == LauncherState.OVERVIEW ? 1 : 0);
+ progressAnim.setDuration(config.duration);
+ progressAnim.setInterpolator(Interpolators.LINEAR);
+ builder.play(progressAnim);
+
+ ObjectAnimator visibilityAnim = animateVisibility(toState == LauncherState.OVERVIEW);
+ visibilityAnim.setDuration(config.duration);
+ visibilityAnim.setInterpolator(Interpolators.LINEAR);
+ builder.play(visibilityAnim);
}
- private void setState(LauncherState state, PropertySetter setter) {
- setter.setViewAlpha(null, mLauncher.getOverviewPanel(),
- state == LauncherState.OVERVIEW ? 1 : 0);
+ public void setVisibility(boolean isVisible) {
+ mVisibilityMultiplier.cancelAnimation();
+ mRecentsView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
+ mVisibilityMultiplier.updateValue(isVisible ? 1 : 0);
+ }
+
+ public ObjectAnimator animateVisibility(boolean isVisible) {
+ ObjectAnimator anim = mVisibilityMultiplier.animateToValue(isVisible ? 1 : 0);
+ if (isVisible) {
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mRecentsView.setVisibility(View.VISIBLE);
+ }
+ });
+ } else {
+ anim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ mRecentsView.setVisibility(View.GONE);
+ }
+ });
+ }
+ return anim;
+ }
+
+ public void setTransitionProgress(float progress) {
+ mTransitionProgress.cancelAnimation();
+ mTransitionProgress.updateValue(progress);
+ }
+
+ private void applyProgress() {
+ mRecentsView.setAlpha(mTransitionProgress.value * mVisibilityMultiplier.value);
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java b/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java
new file mode 100644
index 0000000..651a753
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.uioverrides;
+
+import android.animation.Animator;
+import android.util.SparseArray;
+
+import com.android.launcher3.anim.AnimatorSetBuilder;
+
+import java.util.Collections;
+import java.util.List;
+
+public class TaggedAnimatorSetBuilder extends AnimatorSetBuilder {
+
+ /**
+ * Map of the index in {@link #mAnims} to tag. All the animations in {@link #mAnims} starting
+ * from this index correspond to the tag (until a new tag is specified for an index)
+ */
+ private final SparseArray<Object> mTags = new SparseArray<>();
+
+ @Override
+ public void startTag(Object obj) {
+ mTags.put(mAnims.size(), obj);
+ }
+
+ public List<Animator> getAnimationsForTag(Object tag) {
+ int startIndex = mTags.indexOfValue(tag);
+ if (startIndex < 0) {
+ return Collections.emptyList();
+ }
+ int startPos = mTags.keyAt(startIndex);
+
+ int endIndex = startIndex + 1;
+ int endPos = endIndex >= mTags.size() ? mAnims.size() : mTags.keyAt(endIndex);
+
+ return mAnims.subList(startPos, endPos);
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
new file mode 100644
index 0000000..299db47
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
@@ -0,0 +1,490 @@
+/*
+ * Copyright (C) 2017 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.uioverrides;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+import static com.android.launcher3.anim.SpringAnimationHandler.Y_DIRECTION;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.support.animation.SpringAnimation;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.LauncherStateManager.AnimationConfig;
+import com.android.launcher3.LauncherStateManager.StateHandler;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.SpringAnimationHandler;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.util.TouchController;
+
+import java.util.ArrayList;
+
+/**
+ * Handles vertical touch gesture on the DragLayer
+ */
+public class TwoStepSwipeController extends AnimatorListenerAdapter
+ implements TouchController, SwipeDetector.Listener {
+
+ private static final String TAG = "TwoStepSwipeController";
+
+ private static final float RECATCH_REJECTION_FRACTION = .0875f;
+ private static final int SINGLE_FRAME_MS = 16;
+ private static final long QUICK_SNAP_TO_OVERVIEW_DURATION = 250;
+
+ // Progress after which the transition is assumed to be a success in case user does not fling
+ private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
+
+ /**
+ * Index of the vertical swipe handles in {@link LauncherStateManager#getStateHandlers()}.
+ */
+ private static final int SWIPE_HANDLER_INDEX = 0;
+
+ /**
+ * Index of various UI handlers in {@link LauncherStateManager#getStateHandlers()} not related
+ * to vertical swipe.
+ */
+ private static final int OTHER_HANDLERS_START_INDEX = SWIPE_HANDLER_INDEX + 1;
+
+ private final Launcher mLauncher;
+ private final SwipeDetector mDetector;
+
+ private boolean mNoIntercept;
+ private int mStartContainerType;
+
+ private DragPauseDetector mDragPauseDetector;
+ private TaggedAnimatorSetBuilder mTaggedAnimatorSetBuilder;
+ private AnimatorSet mQuickOverviewAnimation;
+ private boolean mAnimatingToOverview;
+ private TwoStateAnimationController mTwoStateAnimationController;
+
+ private AnimatorPlaybackController mCurrentAnimation;
+ private LauncherState mToState;
+
+ private float mStartProgress;
+ // Ratio of transition process [0, 1] to drag displacement (px)
+ private float mProgressMultiplier;
+
+ private SpringAnimationHandler[] mSpringHandlers;
+
+ public TwoStepSwipeController(Launcher l) {
+ mLauncher = l;
+ mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
+ }
+
+ private boolean canInterceptTouch(MotionEvent ev) {
+ if (!mLauncher.isInState(NORMAL) && !mLauncher.isInState(ALL_APPS)) {
+ // Don't listen for the swipe gesture if we are already in some other state.
+ return false;
+ }
+ if (mAnimatingToOverview) {
+ return false;
+ }
+ if (mCurrentAnimation != null) {
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (mLauncher.isInState(ALL_APPS) && !mLauncher.getAppsView().shouldContainerScroll(ev)) {
+ return false;
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (mCurrentAnimation != null && animation == mCurrentAnimation.getOriginalTarget()) {
+ Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception());
+ clearState();
+ }
+ }
+
+ private void initSprings() {
+ AllAppsContainerView appsView = mLauncher.getAppsView();
+
+ SpringAnimationHandler handler = appsView.getSpringAnimationHandler();
+ if (handler == null) {
+ mSpringHandlers = new SpringAnimationHandler[0];
+ return;
+ }
+
+ ArrayList<SpringAnimationHandler> handlers = new ArrayList<>();
+ handlers.add(handler);
+
+ SpringAnimation searchSpring = appsView.getSearchUiManager().getSpringForFling();
+ if (searchSpring != null) {
+ SpringAnimationHandler searchHandler =
+ new SpringAnimationHandler(Y_DIRECTION, handler.getFactory());
+ searchHandler.add(searchSpring, true /* setDefaultValues */);
+ handlers.add(searchHandler);
+ }
+
+ mSpringHandlers = handlers.toArray(new SpringAnimationHandler[handlers.size()]);
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mNoIntercept = !canInterceptTouch(ev);
+ if (mNoIntercept) {
+ return false;
+ }
+
+ // Now figure out which direction scroll events the controller will start
+ // calling the callbacks.
+ final int directionsToDetectScroll;
+ boolean ignoreSlopWhenSettling = false;
+
+ if (mCurrentAnimation != null) {
+ if (mCurrentAnimation.getProgressFraction() > 1 - RECATCH_REJECTION_FRACTION) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ } else if (mCurrentAnimation.getProgressFraction() < RECATCH_REJECTION_FRACTION ) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
+ } else {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
+ ignoreSlopWhenSettling = true;
+ }
+ } else {
+ if (mLauncher.isInState(ALL_APPS)) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
+ mStartContainerType = ContainerType.ALLAPPS;
+ } else {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ mStartContainerType = mLauncher.getDragLayer().isEventOverHotseat(ev) ?
+ ContainerType.HOTSEAT : ContainerType.WORKSPACE;
+ }
+ }
+
+ mDetector.setDetectableScrollConditions(
+ directionsToDetectScroll, ignoreSlopWhenSettling);
+
+ if (mSpringHandlers == null) {
+ initSprings();
+ }
+ }
+
+ if (mNoIntercept) {
+ return false;
+ }
+
+ onControllerTouchEvent(ev);
+ return mDetector.isDraggingOrSettling();
+ }
+
+ @Override
+ public boolean onControllerTouchEvent(MotionEvent ev) {
+ for (SpringAnimationHandler h : mSpringHandlers) {
+ h.addMovement(ev);
+ }
+ return mDetector.onTouchEvent(ev);
+ }
+
+ @Override
+ public void onDragStart(boolean start) {
+ if (mCurrentAnimation == null) {
+ float range = getShiftRange();
+ long maxAccuracy = (long) (2 * range);
+
+ mDragPauseDetector = new DragPauseDetector(this::onDragPauseDetected);
+ mTaggedAnimatorSetBuilder = new TaggedAnimatorSetBuilder();
+
+ // Build current animation
+ mToState = mLauncher.isInState(ALL_APPS) ? NORMAL : ALL_APPS;
+ mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(
+ mToState, mTaggedAnimatorSetBuilder, maxAccuracy);
+
+ mCurrentAnimation.getTarget().addListener(this);
+ mStartProgress = 0;
+ mProgressMultiplier = (mLauncher.isInState(ALL_APPS) ? 1 : -1) / range;
+ mCurrentAnimation.dispatchOnStart();
+ } else {
+ mCurrentAnimation.pause();
+ mStartProgress = mCurrentAnimation.getProgressFraction();
+ }
+
+ for (SpringAnimationHandler h : mSpringHandlers) {
+ h.skipToEnd();
+ }
+ }
+
+ private float getShiftRange() {
+ return mLauncher.getAllAppsController().getShiftRange();
+ }
+
+ @Override
+ public boolean onDrag(float displacement, float velocity) {
+ mDragPauseDetector.onDrag(displacement, velocity);
+
+ float deltaProgress = mProgressMultiplier * displacement;
+ mCurrentAnimation.setPlayFraction(deltaProgress + mStartProgress);
+ return true;
+ }
+
+ @Override
+ public void onDragEnd(float velocity, boolean fling) {
+ if (!fling && mDragPauseDetector.isEnabled() && mDragPauseDetector.isTriggered()) {
+ snapToOverview(velocity);
+ return;
+ }
+
+ final long animationDuration;
+ final int logAction;
+ final LauncherState targetState;
+ final float progress = mCurrentAnimation.getProgressFraction();
+
+ if (fling) {
+ logAction = Touch.FLING;
+ if (velocity < 0) {
+ targetState = ALL_APPS;
+ animationDuration = SwipeDetector.calculateDuration(velocity,
+ mToState == ALL_APPS ? (1 - progress) : progress);
+ } else {
+ targetState = NORMAL;
+ animationDuration = SwipeDetector.calculateDuration(velocity,
+ mToState == ALL_APPS ? progress : (1 - progress));
+ }
+ // snap to top or bottom using the release velocity
+ } else {
+ logAction = Touch.SWIPE;
+ if (progress > SUCCESS_TRANSITION_PROGRESS) {
+ targetState = mToState;
+ animationDuration = SwipeDetector.calculateDuration(velocity, 1 - progress);
+ } else {
+ targetState = mToState == ALL_APPS ? NORMAL : ALL_APPS;
+ animationDuration = SwipeDetector.calculateDuration(velocity, progress);
+ }
+ }
+
+ if (fling && targetState == ALL_APPS) {
+ for (SpringAnimationHandler h : mSpringHandlers) {
+ // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
+ h.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
+ }
+ }
+ mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState, logAction));
+
+ float nextFrameProgress = Utilities.boundToRange(
+ progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
+
+ ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
+ anim.setFloatValues(nextFrameProgress, targetState == mToState ? 1f : 0f);
+ anim.setDuration(animationDuration);
+ anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
+ anim.start();
+
+ // TODO: Re-enable later
+ mDragPauseDetector.setEnabled(false);
+ }
+
+ private void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+ if (targetState == mToState) {
+ // Transition complete. log the action
+ mLauncher.getUserEventDispatcher().logActionOnContainer(logAction,
+ mToState == ALL_APPS ? Direction.UP : Direction.DOWN,
+ mStartContainerType, mLauncher.getWorkspace().getCurrentPage());
+ }
+ clearState();
+
+ // TODO: mQuickOverviewAnimation might still be running in which changing a state instantly
+ // may cause a jump. Animate the state change with a short duration in this case?
+ mLauncher.getStateManager().goToState(targetState, false /* animated */);
+ }
+
+ private void snapToOverview(float velocity) {
+ mAnimatingToOverview = true;
+
+ final float progress = mCurrentAnimation.getProgressFraction();
+ float endProgress = mToState == NORMAL ? 1f : 0f;
+ long animationDuration = SwipeDetector.calculateDuration(
+ velocity, Math.abs(endProgress - progress));
+ float nextFrameProgress = Utilities.boundToRange(
+ progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
+
+ mCurrentAnimation.setEndAction(() -> {
+ // TODO: Add logging
+ clearState();
+ mLauncher.getStateManager().goToState(OVERVIEW, false /* animated */);
+ });
+
+ if (mTwoStateAnimationController != null) {
+ mTwoStateAnimationController.goBackToStart(endProgress);
+ }
+
+ ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
+ anim.setFloatValues(nextFrameProgress, endProgress);
+ anim.setDuration(animationDuration);
+ anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
+ anim.start();
+ }
+
+ private void onDragPauseDetected() {
+ final ValueAnimator twoStepAnimator = ValueAnimator.ofFloat(0, 1);
+ twoStepAnimator.setDuration(mCurrentAnimation.getDuration());
+ StateHandler[] handlers = mLauncher.getStateManager().getStateHandlers();
+
+ // Change the current animation to only play the vertical handle
+ AnimatorSet anim = new AnimatorSet();
+ anim.playTogether(mTaggedAnimatorSetBuilder.getAnimationsForTag(
+ handlers[SWIPE_HANDLER_INDEX]));
+ anim.play(twoStepAnimator);
+ mCurrentAnimation = mCurrentAnimation.cloneFor(anim);
+
+ AnimatorSetBuilder builder = new AnimatorSetBuilder();
+ AnimationConfig config = new AnimationConfig();
+ config.duration = QUICK_SNAP_TO_OVERVIEW_DURATION;
+ for (int i = OTHER_HANDLERS_START_INDEX; i < handlers.length; i++) {
+ handlers[i].setStateWithAnimation(OVERVIEW, builder, config);
+ }
+ mQuickOverviewAnimation = builder.build();
+ mQuickOverviewAnimation.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ onQuickOverviewAnimationComplete(twoStepAnimator);
+ }
+ });
+ mQuickOverviewAnimation.start();
+ }
+
+ private void onQuickOverviewAnimationComplete(ValueAnimator twoStepAnimator) {
+ if (mAnimatingToOverview) {
+ return;
+ }
+
+ // The remaining state handlers are on the OVERVIEW state. Create two animations, one
+ // towards the NORMAL state and one towards ALL_APPS state and control them based on the
+ // swipe progress.
+ AnimationConfig config = new AnimationConfig();
+ config.duration = (long) (2 * getShiftRange());
+ config.userControlled = true;
+
+ LauncherState fromState = mToState == ALL_APPS ? NORMAL : ALL_APPS;
+ AnimatorSetBuilder builderToTargetState = new AnimatorSetBuilder();
+ AnimatorSetBuilder builderToSourceState = new AnimatorSetBuilder();
+
+ StateHandler[] handlers = mLauncher.getStateManager().getStateHandlers();
+ for (int i = OTHER_HANDLERS_START_INDEX; i < handlers.length; i++) {
+ handlers[i].setStateWithAnimation(mToState, builderToTargetState, config);
+ handlers[i].setStateWithAnimation(fromState, builderToSourceState, config);
+ }
+
+ mTwoStateAnimationController = new TwoStateAnimationController(
+ AnimatorPlaybackController.wrap(builderToSourceState.build(), config.duration),
+ AnimatorPlaybackController.wrap(builderToTargetState.build(), config.duration),
+ twoStepAnimator.getAnimatedFraction());
+ twoStepAnimator.addUpdateListener(mTwoStateAnimationController);
+ }
+
+ private void clearState() {
+ mCurrentAnimation = null;
+ mTaggedAnimatorSetBuilder = null;
+ if (mDragPauseDetector != null) {
+ mDragPauseDetector.setEnabled(false);
+ }
+ mDragPauseDetector = null;
+
+ if (mQuickOverviewAnimation != null) {
+ mQuickOverviewAnimation.cancel();
+ mQuickOverviewAnimation = null;
+ }
+ mTwoStateAnimationController = null;
+ mAnimatingToOverview = false;
+
+ mDetector.finishedScrolling();
+ }
+
+ /**
+ * {@link AnimatorUpdateListener} which interpolates two animations based the progress
+ */
+ private static class TwoStateAnimationController implements AnimatorUpdateListener {
+
+ private final AnimatorPlaybackController mControllerTowardsStart;
+ private final AnimatorPlaybackController mControllerTowardsEnd;
+
+ private Interpolator mInterpolator = Interpolators.LINEAR;
+ private float mStartFraction;
+ private float mLastFraction;
+
+ TwoStateAnimationController(AnimatorPlaybackController controllerTowardsStart,
+ AnimatorPlaybackController controllerTowardsEnd, float startFraction) {
+ mControllerTowardsStart = controllerTowardsStart;
+ mControllerTowardsEnd = controllerTowardsEnd;
+ mLastFraction = mStartFraction = startFraction;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ mLastFraction = mInterpolator.getInterpolation(valueAnimator.getAnimatedFraction());
+ if (mLastFraction > mStartFraction) {
+ if (mStartFraction >= 1) {
+ mControllerTowardsEnd.setPlayFraction(0);
+ } else {
+ mControllerTowardsEnd.setPlayFraction(
+ (mLastFraction - mStartFraction) / (1 - mStartFraction));
+ }
+ } else {
+ if (mStartFraction <= 0) {
+ mControllerTowardsStart.setPlayFraction(0);
+ } else {
+ mControllerTowardsStart.setPlayFraction(
+ (mStartFraction - mLastFraction) / mStartFraction);
+ }
+ }
+ }
+
+ /**
+ * Changes the interpolator such that from this point ({@link #mLastFraction}), the
+ * animation run towards {@link #mStartFraction}. This allows us to animate the UI back
+ * to the original point.
+ * @param endFraction expected end point for this animation. Should either be 0 or 1.
+ */
+ public void goBackToStart(float endFraction) {
+ if (mLastFraction == mStartFraction || mLastFraction == endFraction) {
+ mInterpolator = (v) -> mStartFraction;
+ } else if (mLastFraction > mStartFraction && endFraction < mStartFraction) {
+ mInterpolator = (v) -> Math.max(v, mStartFraction);
+ } else if (mLastFraction < mStartFraction && endFraction > mStartFraction) {
+ mInterpolator = (v) -> Math.min(mStartFraction, v);
+ } else {
+ final float start = mLastFraction;
+ final float range = endFraction - mLastFraction;
+ mInterpolator = (v) ->
+ SwipeDetector.interpolate(start, mStartFraction, (v - start) / range);
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index a48a65c..5e280b6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -24,14 +24,13 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.R;
-import com.android.launcher3.VerticalSwipeController;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.widget.WidgetsFullSheet;
public class UiFactory {
public static TouchController[] createTouchControllers(Launcher launcher) {
- return new TouchController[] {new VerticalSwipeController(launcher)};
+ return new TouchController[] {new TwoStepSwipeController(launcher)};
}
public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() {
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java
index 1f6781e..214b3f3 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java
@@ -47,9 +47,7 @@
}
public ObjectAnimator animateToValue(float v) {
- if (mValueAnimator != null) {
- mValueAnimator.cancel();
- }
+ cancelAnimation();
mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, v);
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -73,6 +71,12 @@
}
}
+ public void cancelAnimation() {
+ if (mValueAnimator != null) {
+ mValueAnimator.cancel();
+ }
+ }
+
public ObjectAnimator getCurrentAnimation() {
return mValueAnimator;
}
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 4c3a9ad..75db45b 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -42,6 +42,7 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.states.InternalStateHandler;
+import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.TraceHelper;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.Task;
@@ -94,6 +95,7 @@
private Launcher mLauncher;
private SnapshotDragView mDragView;
private RecentsView mRecentsView;
+ private RecentsViewStateController mStateController;
private Hotseat mHotseat;
private RecentsTaskLoadPlan mLoadPlan;
@@ -178,11 +180,13 @@
mDragView.setPivotX(0);
mDragView.setPivotY(0);
mRecentsView = mLauncher.getOverviewPanel();
+ mStateController = mRecentsView.getStateController();
mHotseat = mLauncher.getHotseat();
// Optimization
mLauncher.getAppsView().setVisibility(View.GONE);
- mRecentsView.setVisibility(View.GONE);
+ mStateController.setTransitionProgress(1);
+ mStateController.setVisibility(false);
TraceHelper.partitionSection("TouchInt", "Launcher on new intent");
}
@@ -209,17 +213,9 @@
}
if (mTargetRect.isEmpty()) {
+ RecentsView.getPageRect(mLauncher, mTargetRect);
DragLayer dl = mLauncher.getDragLayer();
mSourceRect.set(0, 0, dl.getWidth(), dl.getHeight());
- Rect targetPadding = RecentsView.getPadding(mLauncher);
- Rect insets = dl.getInsets();
- mTargetRect.set(
- targetPadding.left + insets.left,
- targetPadding.top + insets.top,
- mSourceRect.right - targetPadding.right - insets.right,
- mSourceRect.bottom - targetPadding.bottom - insets.bottom);
- mTargetRect.top += mLauncher.getResources()
- .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
}
float shift = mCurrentShift.value * mActivityMultiplier.value;
@@ -246,12 +242,15 @@
private void setTaskPlanToUi() {
mRecentsView.update(mLoadPlan);
- mRecentsView.setVisibility(View.VISIBLE);
-
- // Animate alpha
- mRecentsView.setAlpha(0);
- mRecentsView.animate().alpha(1).setDuration(RECENTS_VIEW_VISIBILITY_DURATION)
- .withEndAction(() -> mStateCallback.setState(STATE_RECENTS_FULLY_VISIBLE));
+ ObjectAnimator anim = mStateController.animateVisibility(true /* isVisible */)
+ .setDuration(RECENTS_VIEW_VISIBILITY_DURATION);
+ anim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ mStateCallback.setState(STATE_RECENTS_FULLY_VISIBLE);
+ }
+ });
+ anim.start();
}
@UiThread
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 34ed7f1..a107343 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -16,6 +16,7 @@
package com.android.quickstep;
+import android.animation.LayoutTransition;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Rect;
@@ -25,8 +26,11 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.RecentsTaskLoader;
import com.android.systemui.shared.recents.model.Task;
@@ -56,6 +60,7 @@
private boolean mOverviewStateEnabled;
private boolean mTaskStackListenerRegistered;
+ private LayoutTransition mLayoutTransition;
private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
@Override
@@ -70,6 +75,8 @@
}
};
+ private RecentsViewStateController mStateController;
+
public RecentsView(Context context) {
this(context, null);
}
@@ -83,6 +90,18 @@
setWillNotDraw(false);
setPageSpacing((int) getResources().getDimension(R.dimen.recents_page_spacing));
enableFreeScroll(true);
+ setupLayoutTransition();
+ }
+
+ private void setupLayoutTransition() {
+ // We want to show layout transitions when pages are deleted, to close the gap.
+ mLayoutTransition = new LayoutTransition();
+ mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);
+ mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
+
+ mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);
+ mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
+ setLayoutTransition(mLayoutTransition);
}
@Override
@@ -111,6 +130,14 @@
updateTaskStackListenerState();
}
+ public void setStateController(RecentsViewStateController stateController) {
+ mStateController = stateController;
+ }
+
+ public RecentsViewStateController getStateController() {
+ return mStateController;
+ }
+
public void setOverviewStateEnabled(boolean enabled) {
mOverviewStateEnabled = enabled;
updateTaskStackListenerState();
@@ -129,6 +156,7 @@
// necessary)
final LayoutInflater inflater = LayoutInflater.from(getContext());
final ArrayList<Task> tasks = stack.getTasks();
+ setLayoutTransition(null);
for (int i = getChildCount(); i < tasks.size(); i++) {
final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false);
addView(taskView);
@@ -138,6 +166,7 @@
removeView(taskView);
loader.unloadTaskData(taskView.getTask());
}
+ setLayoutTransition(mLayoutTransition);
// Rebind all task views
for (int i = tasks.size() - 1; i >= 0; i--) {
@@ -171,7 +200,7 @@
}
}
- public static Rect getPadding(Launcher launcher) {
+ private static Rect getPadding(Launcher launcher) {
DeviceProfile profile = launcher.getDeviceProfile();
Rect stableInsets = new Rect();
WindowManagerWrapper.getInstance().getStableInsets(stableInsets);
@@ -185,6 +214,19 @@
return padding;
}
+ public static void getPageRect(Launcher launcher, Rect outRect) {
+ DragLayer dl = launcher.getDragLayer();
+ Rect targetPadding = getPadding(launcher);
+ Rect insets = dl.getInsets();
+ outRect.set(
+ targetPadding.left + insets.left,
+ targetPadding.top + insets.top,
+ dl.getWidth() - targetPadding.right - insets.right,
+ dl.getHeight() - targetPadding.bottom - insets.bottom);
+ outRect.top += launcher.getResources()
+ .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+ }
+
@Override
public void computeScroll() {
super.computeScroll();
@@ -223,4 +265,12 @@
}
}
}
+
+ public void onTaskDismissed(TaskView taskView) {
+ ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
+ removeView(taskView);
+ if (getChildCount() == 0) {
+ Launcher.getLauncher(getContext()).getStateManager().goToState(LauncherState.NORMAL);
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index ac9a778..a0ad618 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -16,15 +16,25 @@
package com.android.quickstep;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.app.ActivityOptions;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Property;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.OverviewState;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.touch.SwipeDetector;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -39,11 +49,38 @@
/**
* A task in the Recents view.
*/
-public class TaskView extends FrameLayout implements TaskCallbacks {
+public class TaskView extends FrameLayout implements TaskCallbacks, SwipeDetector.Listener {
+
+ private static final int SWIPE_DIRECTIONS = SwipeDetector.DIRECTION_POSITIVE;
+
+ /**
+ * The task will appear fully dismissed when the distance swiped
+ * reaches this percentage of the card height.
+ */
+ private static final float SWIPE_DISTANCE_HEIGHT_PERCENTAGE = 0.38f;
+
+ private static final Property<TaskView, Float> PROPERTY_SWIPE_PROGRESS =
+ new Property<TaskView, Float>(Float.class, "swipe_progress") {
+
+ @Override
+ public Float get(TaskView taskView) {
+ return taskView.mSwipeProgress;
+ }
+
+ @Override
+ public void set(TaskView taskView, Float progress) {
+ taskView.setSwipeProgress(progress);
+ }
+ };
private Task mTask;
private TaskThumbnailView mSnapshotView;
private ImageView mIconView;
+ private SwipeDetector mSwipeDetector;
+ private float mSwipeDistance;
+ private float mSwipeProgress;
+ private Interpolator mAlphaInterpolator;
+ private Interpolator mSwipeAnimInterpolator;
public TaskView(Context context) {
this(context, null);
@@ -58,6 +95,11 @@
setOnClickListener((view) -> {
launchTask(true /* animate */);
});
+
+ mSwipeDetector = new SwipeDetector(getContext(), this, SwipeDetector.VERTICAL);
+ mSwipeDetector.setDetectableScrollConditions(SWIPE_DIRECTIONS, false);
+ mAlphaInterpolator = Interpolators.ACCEL_1_5;
+ mSwipeAnimInterpolator = Interpolators.SCROLL_CUBIC;
}
@Override
@@ -67,6 +109,15 @@
mIconView = findViewById(R.id.icon);
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ View p = (View) getParent();
+ mSwipeDistance = (getMeasuredHeight() - p.getPaddingTop() - p.getPaddingBottom())
+ * SWIPE_DISTANCE_HEIGHT_PERCENTAGE;
+ }
+
/**
* Updates this task view to the given {@param task}.
*/
@@ -134,4 +185,78 @@
public void onTaskWindowingModeChanged() {
// Do nothing
}
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ mSwipeDetector.onTouchEvent(ev);
+ return super.onInterceptTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ mSwipeDetector.onTouchEvent(event);
+ return mSwipeDetector.isDraggingOrSettling() || super.onTouchEvent(event);
+ }
+
+ // Swipe detector methods
+
+ @Override
+ public void onDragStart(boolean start) {
+ getParent().requestDisallowInterceptTouchEvent(true);
+ }
+
+ @Override
+ public boolean onDrag(float displacement, float velocity) {
+ setSwipeProgress(Utilities.boundToRange(displacement / mSwipeDistance,
+ allowsSwipeUp() ? -1 : 0, allowsSwipeDown() ? 1 : 0));
+ return true;
+ }
+
+ /**
+ * Indicates the page is being removed.
+ * @param progress Ranges from -1 (fading upwards) to 1 (fading downwards).
+ */
+ private void setSwipeProgress(float progress) {
+ mSwipeProgress = progress;
+ float translationY = mSwipeProgress * mSwipeDistance;
+ float alpha = 1f - mAlphaInterpolator.getInterpolation(Math.abs(mSwipeProgress));
+ // Only change children to avoid changing our properties while dragging.
+ mIconView.setTranslationY(translationY);
+ mSnapshotView.setTranslationY(translationY);
+ mIconView.setAlpha(alpha);
+ mSnapshotView.setAlpha(alpha);
+ }
+
+ private boolean allowsSwipeUp() {
+ return (SWIPE_DIRECTIONS & SwipeDetector.DIRECTION_POSITIVE) != 0;
+ }
+
+ private boolean allowsSwipeDown() {
+ return (SWIPE_DIRECTIONS & SwipeDetector.DIRECTION_NEGATIVE) != 0;
+ }
+
+ @Override
+ public void onDragEnd(float velocity, boolean fling) {
+ boolean movingAwayFromCenter = velocity < 0 == mSwipeProgress < 0;
+ boolean flingAway = fling && movingAwayFromCenter
+ && (allowsSwipeUp() && velocity < 0 || allowsSwipeDown() && velocity > 0);
+ final boolean shouldRemove = flingAway || (!fling && Math.abs(mSwipeProgress) > 0.5f);
+ float fromProgress = mSwipeProgress;
+ float toProgress = !shouldRemove ? 0f : mSwipeProgress < 0 ? -1f : 1f;
+ ValueAnimator swipeAnimator = ObjectAnimator.ofFloat(this, PROPERTY_SWIPE_PROGRESS,
+ fromProgress, toProgress);
+ swipeAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (shouldRemove) {
+ ((RecentsView) getParent()).onTaskDismissed(TaskView.this);
+ }
+ mSwipeDetector.finishedScrolling();
+ }
+ });
+ swipeAnimator.setDuration(SwipeDetector.calculateDuration(velocity,
+ Math.abs(toProgress - fromProgress)));
+ swipeAnimator.setInterpolator(mSwipeAnimInterpolator);
+ swipeAnimator.start();
+ }
}
diff --git a/res/color/all_apps_work_tab_text.xml b/res/color/all_apps_work_tab_text.xml
new file mode 100644
index 0000000..7279bf8
--- /dev/null
+++ b/res/color/all_apps_work_tab_text.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@color/work_profile_color" android:state_selected="true"/>
+ <item android:color="?android:attr/textColorTertiary"/>
+</selector>
\ No newline at end of file
diff --git a/res/layout-land/all_apps_fast_scroller.xml b/res/layout-land/all_apps_fast_scroller.xml
index 6a68f84..16aa2af 100644
--- a/res/layout-land/all_apps_fast_scroller.xml
+++ b/res/layout-land/all_apps_fast_scroller.xml
@@ -21,7 +21,7 @@
android:id="@+id/fast_scroller_popup"
style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true"
- android:layout_alignTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginTop="-5dp"
android:layout_marginEnd="-45dp" />
@@ -31,7 +31,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
- android:layout_alignParentTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginEnd="-88dp"
android:layout_marginTop="14dp"
launcher:canThumbDetach="true" />
diff --git a/res/layout-sw720dp/all_apps_fast_scroller.xml b/res/layout-sw720dp/all_apps_fast_scroller.xml
index 12c15cc..5537bc6 100644
--- a/res/layout-sw720dp/all_apps_fast_scroller.xml
+++ b/res/layout-sw720dp/all_apps_fast_scroller.xml
@@ -21,7 +21,7 @@
android:id="@+id/fast_scroller_popup"
style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true"
- android:layout_alignTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
<com.android.launcher3.views.RecyclerViewFastScroller
@@ -30,7 +30,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
- android:layout_alignTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginEnd="@dimen/fastscroll_end_margin"
launcher:canThumbDetach="true" />
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index c42c15c..3f6be2c 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -31,7 +31,7 @@
<include layout="@layout/all_apps_fast_scroller" />
- <RelativeLayout
+ <com.android.launcher3.allapps.FloatingHeaderView
android:id="@+id/all_apps_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -39,41 +39,48 @@
android:clipToPadding="false"
android:layout_below="@id/search_container_all_apps" >
- <com.android.launcher3.allapps.PredictionRowView
- android:id="@+id/header_content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ <include layout="@layout/predictions_view" android:id="@+id/header_content" />
<include layout="@layout/all_apps_divider"
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
+ android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
android:layout_alignBottom="@+id/tabs" />
- <com.android.launcher3.views.SlidingTabStrip
+ <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="@dimen/all_apps_header_tab_height"
+ android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
+ android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
android:layout_below="@id/header_content"
- android:orientation="horizontal" >
+ android:orientation="horizontal">
<Button
android:id="@+id/tab_personal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:fontFamily="sans-serif-medium"
android:text="@string/all_apps_personal_tab"
+ android:textAllCaps="true"
android:textColor="@color/all_apps_tab_text"
- android:background="?android:attr/selectableItemBackground"/>
+ android:textSize="14sp"/>
<Button
android:id="@+id/tab_work"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:fontFamily="sans-serif-medium"
android:text="@string/all_apps_work_tab"
- android:textColor="@color/all_apps_tab_text"
- android:background="?android:attr/selectableItemBackground"/>
- </com.android.launcher3.views.SlidingTabStrip>
- </RelativeLayout>
+ android:textAllCaps="true"
+ android:textColor="@color/all_apps_work_tab_text"
+ android:textSize="14sp"/>
+ </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
+ </com.android.launcher3.allapps.FloatingHeaderView>
<!-- Note: we are reusing/repurposing a system attribute for search layout, because of a
platform bug, which prevents using custom attributes in <include> tag -->
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
index 12c15cc..5537bc6 100644
--- a/res/layout/all_apps_fast_scroller.xml
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -21,7 +21,7 @@
android:id="@+id/fast_scroller_popup"
style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true"
- android:layout_alignTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
<com.android.launcher3.views.RecyclerViewFastScroller
@@ -30,7 +30,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
- android:layout_alignTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginEnd="@dimen/fastscroll_end_margin"
launcher:canThumbDetach="true" />
diff --git a/res/layout/predictions_view.xml b/res/layout/predictions_view.xml
new file mode 100644
index 0000000..280290c
--- /dev/null
+++ b/res/layout/predictions_view.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<com.android.launcher3.allapps.PredictionRowView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
\ No newline at end of file
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 294425d..3e34e16 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -132,4 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Pessoal"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Trabalho"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabalho"</string>
+ <!-- no translation found for bottom_work_tab_user_education_title (5785851780786322825) -->
+ <skip />
+ <!-- no translation found for bottom_work_tab_user_education_body (5834430249581360068) -->
+ <skip />
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 60f249e..93c5114 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -96,6 +96,7 @@
<dimen name="all_apps_prediction_row_divider_height">17dp</dimen>
<dimen name="all_apps_work_profile_tab_footer_top_padding">16dp</dimen>
<dimen name="all_apps_work_profile_tab_footer_bottom_padding">20dp</dimen>
+ <dimen name="all_apps_tabs_side_padding">12dp</dimen>
<!-- Search bar in All Apps -->
<dimen name="all_apps_header_max_elevation">3dp</dimen>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 2c6629d..da464c0 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -59,6 +59,10 @@
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
| TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP;
+ // Type of popups which should be kept open during launcher rebind
+ public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
+ | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP;
+
protected boolean mIsOpen;
public AbstractFloatingView(Context context, AttributeSet attrs) {
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index b315980..76c7845 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -17,13 +17,11 @@
package com.android.launcher3;
import android.content.Context;
-import android.graphics.Canvas;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.TextView;
import com.android.launcher3.views.RecyclerViewFastScroller;
@@ -68,6 +66,7 @@
ViewGroup parent = (ViewGroup) getParent().getParent();
mScrollbar = parent.findViewById(R.id.fast_scroller);
mScrollbar.setRecyclerView(this, parent.findViewById(R.id.fast_scroller_popup));
+ onUpdateScrollbar(0);
}
/**
@@ -90,8 +89,10 @@
*/
private boolean handleTouchEvent(MotionEvent ev) {
// Move to mScrollbar's coordinate system.
- int left = getLeft() - mScrollbar.getLeft();
- int top = getTop() - mScrollbar.getTop();
+ // We need to take parent into account (view pager's location)
+ ViewGroup parent = (ViewGroup) getParent();
+ int left = parent.getLeft() + getLeft() - mScrollbar.getLeft();
+ int top = parent.getTop() + getTop() - mScrollbar.getTop() - getScrollBarTop();
ev.offsetLocation(left, top);
try {
return mScrollbar.handleTouchEvent(ev);
@@ -112,7 +113,7 @@
* Returns the height of the fast scroll bar
*/
public int getScrollbarTrackHeight() {
- return getHeight() - getScrollBarTop() - getPaddingBottom();
+ return mScrollbar.getHeight() - getScrollBarTop() - getPaddingBottom();
}
/**
@@ -130,12 +131,6 @@
return availableScrollBarHeight;
}
- @Override
- protected void dispatchDraw(Canvas canvas) {
- onUpdateScrollbar(0);
- super.dispatchDraw(canvas);
- }
-
/**
* Updates the scrollbar thumb offset to match the visible scroll of the recycler view. It does
* this by mapping the available scroll area of the recycler view to the available space for the
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index 3eca5cd..106671f 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -17,7 +17,7 @@
package com.android.launcher3;
import static com.android.launcher3.AlphaUpdateListener.updateVisibility;
-import static com.android.launcher3.Utilities.isAccessibilityEnabled;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.TimeInterpolator;
import android.content.Context;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 9ee59cc..44660ec 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -42,13 +42,11 @@
import android.annotation.TargetApi;
import android.app.ActivityOptions;
import android.app.AlertDialog;
-import android.app.SearchManager;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
-import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.DialogInterface;
@@ -70,8 +68,6 @@
import android.os.StrictMode;
import android.os.UserHandle;
import android.support.annotation.Nullable;
-import android.text.Selection;
-import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.Log;
@@ -89,7 +85,6 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
-import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import com.android.launcher3.DropTarget.DragObject;
@@ -98,10 +93,10 @@
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
-import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
@@ -119,7 +114,6 @@
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.shortcuts.DeepShortcutManager;
-import com.android.launcher3.states.AllAppsState;
import com.android.launcher3.states.InternalStateHandler;
import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -240,8 +234,6 @@
// that results in widgets being inflated in the wrong orientation.
private int mOrientation;
- private SpannableStringBuilder mDefaultKeySsb = null;
-
@Thunk boolean mWorkspaceLoading = true;
private boolean mPaused = true;
@@ -256,14 +248,13 @@
private ModelWriter mModelWriter;
private IconCache mIconCache;
private LauncherAccessibilityDelegate mAccessibilityDelegate;
- private boolean mHasFocus = false;
private ObjectAnimator mScrimAnimator;
private boolean mShouldFadeInScrim;
private PopupDataProvider mPopupDataProvider;
- private final ArrayList<Integer> mSynchronouslyBoundPages = new ArrayList<>();
+ private int mSynchronouslyBoundPage = PagedView.INVALID_PAGE;
// We only want to get the SharedPreferences once since it does an FS stat each time we get
// it from the context.
@@ -397,8 +388,7 @@
}
// For handling default keys
- mDefaultKeySsb = new SpannableStringBuilder();
- Selection.setSelection(mDefaultKeySsb, 0);
+ setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
// On large interfaces, or on devices that a user has specifically enabled screen rotation,
// we want the screen to auto-rotate based on the current orientation
@@ -843,15 +833,11 @@
// Refresh shortcuts if the permission changed.
mModel.refreshShortcutsIfRequired();
- if (shouldShowDiscoveryBounce()) {
- mAllAppsController.showDiscoveryBounce();
- }
+ DiscoveryBounce.showIfNeeded(this);
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onResume();
}
- clearTypedText();
-
TraceHelper.endSection("ON_RESUME");
}
@@ -919,72 +905,6 @@
}
}
- @Override
- public Object onRetainNonConfigurationInstance() {
- // Flag the loader to stop early before switching
- if (mModel.isCurrentCallbacks(this)) {
- mModel.stopLoader();
- }
- //TODO(hyunyoungs): stop the widgets loader when there is a rotation.
-
- return Boolean.TRUE;
- }
-
- // We can't hide the IME if it was forced open. So don't bother
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- mHasFocus = hasFocus;
-
- if (mLauncherCallbacks != null) {
- mLauncherCallbacks.onWindowFocusChanged(hasFocus);
- }
- }
-
- private boolean acceptFilter() {
- final InputMethodManager inputManager = (InputMethodManager)
- getSystemService(Context.INPUT_METHOD_SERVICE);
- return !inputManager.isFullscreenMode();
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- final int uniChar = event.getUnicodeChar();
- final boolean handled = super.onKeyDown(keyCode, event);
- final boolean isKeyNotWhitespace = uniChar > 0 && !Character.isWhitespace(uniChar);
- if (!handled && acceptFilter() && isKeyNotWhitespace) {
- boolean gotKey = TextKeyListener.getInstance().onKeyDown(mWorkspace, mDefaultKeySsb,
- keyCode, event);
- if (gotKey && mDefaultKeySsb != null && mDefaultKeySsb.length() > 0) {
- // something usable has been typed - start a search
- // the typed text will be retrieved and cleared by
- // showSearchDialog()
- // If there are multiple keystrokes before the search dialog takes focus,
- // onSearchRequested() will be called for every keystroke,
- // but it is idempotent, so it's fine.
- return onSearchRequested();
- }
- }
-
- // Eat the long press event so the keyboard doesn't come up.
- if (keyCode == KeyEvent.KEYCODE_MENU && event.isLongPress()) {
- return true;
- }
-
- return handled;
- }
-
- private String getTypedText() {
- return mDefaultKeySsb.toString();
- }
-
- @Override
- public void clearTypedText() {
- mDefaultKeySsb.clear();
- mDefaultKeySsb.clearSpans();
- Selection.setSelection(mDefaultKeySsb, 0);
- }
-
public boolean isInState(LauncherState state) {
return mStateManager.getState() == state;
}
@@ -1002,7 +922,7 @@
int stateOrdinal = savedState.getInt(RUNTIME_STATE, NORMAL.ordinal);
LauncherState[] stateValues = LauncherState.values();
LauncherState state = stateValues[stateOrdinal];
- if (!state.doNotRestore) {
+ if (!state.disableRestore) {
mStateManager.goToState(state, false /* animated */);
}
@@ -1035,7 +955,7 @@
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
// Setup the drag layer
- mDragLayer.setup(this, mDragController, mAllAppsController);
+ mDragLayer.setup(this, mDragController);
// Setup the hotseat
mHotseat = (Hotseat) findViewById(R.id.hotseat);
@@ -1328,7 +1248,7 @@
TraceHelper.beginSection("NEW_INTENT");
super.onNewIntent(intent);
- boolean alreadyOnHome = mHasFocus && ((intent.getFlags() &
+ boolean alreadyOnHome = hasWindowFocus() && ((intent.getFlags() &
Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
!= Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
@@ -1384,9 +1304,7 @@
@Override
public void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
- for (int page: mSynchronouslyBoundPages) {
- mWorkspace.restoreInstanceStateForChild(page);
- }
+ mWorkspace.restoreInstanceStateForChild(mSynchronouslyBoundPage);
}
@Override
@@ -1450,7 +1368,6 @@
} catch (NullPointerException ex) {
Log.w(TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex);
}
- mAppWidgetHost = null;
TextKeyListener.getInstance().release();
WallpaperColorInfo.getInstance(this).setOnThemeChangeListener(null);
@@ -1495,11 +1412,6 @@
@Override
public void startSearch(String initialQuery, boolean selectInitialQuery,
Bundle appSearchData, boolean globalSearch) {
-
- if (initialQuery == null) {
- // Use any text typed in the launcher as the initial query
- initialQuery = getTypedText();
- }
if (appSearchData == null) {
appSearchData = new Bundle();
appSearchData.putString("source", "launcher-search");
@@ -1508,69 +1420,13 @@
if (mLauncherCallbacks == null ||
!mLauncherCallbacks.startSearch(initialQuery, selectInitialQuery, appSearchData)) {
// Starting search from the callbacks failed. Start the default global search.
- startGlobalSearch(initialQuery, selectInitialQuery, appSearchData, null);
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, true);
}
// We need to show the workspace after starting the search
mStateManager.goToState(NORMAL);
}
- /**
- * Starts the global search activity. This code is a copied from SearchManager
- */
- public void startGlobalSearch(String initialQuery,
- boolean selectInitialQuery, Bundle appSearchData, Rect sourceBounds) {
- final SearchManager searchManager =
- (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- ComponentName globalSearchActivity = searchManager.getGlobalSearchActivity();
- if (globalSearchActivity == null) {
- Log.w(TAG, "No global search activity found.");
- return;
- }
- Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setComponent(globalSearchActivity);
- // Make sure that we have a Bundle to put source in
- if (appSearchData == null) {
- appSearchData = new Bundle();
- } else {
- appSearchData = new Bundle(appSearchData);
- }
- // Set source to package name of app that starts global search if not set already.
- if (!appSearchData.containsKey("source")) {
- appSearchData.putString("source", getPackageName());
- }
- intent.putExtra(SearchManager.APP_DATA, appSearchData);
- if (!TextUtils.isEmpty(initialQuery)) {
- intent.putExtra(SearchManager.QUERY, initialQuery);
- }
- if (selectInitialQuery) {
- intent.putExtra(SearchManager.EXTRA_SELECT_QUERY, selectInitialQuery);
- }
- intent.setSourceBounds(sourceBounds);
- try {
- startActivity(intent);
- } catch (ActivityNotFoundException ex) {
- Log.e(TAG, "Global search activity not found: " + globalSearchActivity);
- }
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- if (mLauncherCallbacks != null) {
- return mLauncherCallbacks.onPrepareOptionsMenu(menu);
- }
- return false;
- }
-
- @Override
- public boolean onSearchRequested() {
- startSearch(null, false, null, true);
- // Use a custom animation for launching search
- return true;
- }
-
public boolean isWorkspaceLocked() {
return mWorkspaceLoading || mPendingRequestArgs != null;
}
@@ -2395,7 +2251,7 @@
// we are starting a fresh bind, close all such panels as all the icons are about
// to go away.
AbstractFloatingView.closeOpenViews(this, true,
- AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_WIDGETS_FULL_SHEET);
+ AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
setWorkspaceLoading(true);
@@ -2737,7 +2593,7 @@
}
public void onPageBoundSynchronously(int page) {
- mSynchronouslyBoundPages.add(page);
+ mSynchronouslyBoundPage = page;
}
@Override
@@ -2787,11 +2643,7 @@
* Implementation of the method from LauncherModel.Callbacks.
*/
public void finishBindingItems() {
- Runnable r = new Runnable() {
- public void run() {
- finishBindingItems();
- }
- };
+ Runnable r = this::finishBindingItems;
if (waitUntilResume(r)) {
return;
}
@@ -3036,12 +2888,6 @@
return mRotationEnabled;
}
- private boolean shouldShowDiscoveryBounce() {
- return isInState(NORMAL)
- && !mSharedPrefs.getBoolean(AllAppsState.APPS_VIEW_SHOWN, false)
- && !UserManagerCompat.getInstance(this).isDemoUser();
- }
-
/**
* $ adb shell dumpsys activity com.android.launcher3.Launcher [--all]
*/
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 928258f..914d9eb 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -48,10 +48,8 @@
void onActivityResult(int requestCode, int resultCode, Intent data);
void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults);
- void onWindowFocusChanged(boolean hasFocus);
void onAttachedToWindow();
void onDetachedFromWindow();
- boolean onPrepareOptionsMenu(Menu menu);
void dump(String prefix, FileDescriptor fd, PrintWriter w, String[] args);
void onHomeIntent();
boolean handleBackPressed();
diff --git a/src/com/android/launcher3/LauncherExterns.java b/src/com/android/launcher3/LauncherExterns.java
index 887859c..272bbf6 100644
--- a/src/com/android/launcher3/LauncherExterns.java
+++ b/src/com/android/launcher3/LauncherExterns.java
@@ -24,11 +24,9 @@
*/
public interface LauncherExterns {
- public boolean setLauncherCallbacks(LauncherCallbacks callbacks);
+ boolean setLauncherCallbacks(LauncherCallbacks callbacks);
- public SharedPreferences getSharedPrefs();
+ SharedPreferences getSharedPrefs();
- public void setLauncherOverlay(Launcher.LauncherOverlay overlay);
-
- void clearTypedText();
+ void setLauncherOverlay(Launcher.LauncherOverlay overlay);
}
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 01d53da..dfb935f 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -21,7 +21,7 @@
import android.view.View;
-import com.android.launcher3.states.AllAppsState;
+import com.android.launcher3.uioverrides.AllAppsState;
import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.uioverrides.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -37,13 +37,16 @@
protected static final int FLAG_SHOW_SCRIM = 1 << 0;
protected static final int FLAG_MULTI_PAGE = 1 << 1;
protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 2;
- protected static final int FLAG_DO_NOT_RESTORE = 1 << 3;
+ protected static final int FLAG_DISABLE_RESTORE = 1 << 3;
protected static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 4;
+ protected static final int FLAG_DISABLE_PAGE_CLIPPING = 1 << 5;
+
+ protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER = (i) -> 1f;
private static final LauncherState[] sAllStates = new LauncherState[4];
public static final LauncherState NORMAL = new LauncherState(0, ContainerType.WORKSPACE,
- 0, 1f, FLAG_DO_NOT_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
+ 0, 1f, FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
public static final LauncherState ALL_APPS = new AllAppsState(1);
@@ -61,7 +64,7 @@
/**
* True if the state can be persisted across activity restarts.
*/
- public final boolean doNotRestore;
+ public final boolean disableRestore;
/**
* True if workspace has multiple pages visible.
@@ -94,6 +97,12 @@
*/
public final boolean workspaceIconsCanBeDragged;
+ /**
+ * True if the workspace pages should not be clipped relative to the workspace bounds
+ * for this state.
+ */
+ public final boolean disablePageClipping;
+
public LauncherState(int id, int containerType, int transitionDuration, float verticalProgress,
int flags) {
this.containerType = containerType;
@@ -104,8 +113,9 @@
this.workspaceAccessibilityFlag = (flags & FLAG_DISABLE_ACCESSIBILITY) != 0
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: IMPORTANT_FOR_ACCESSIBILITY_AUTO;
- this.doNotRestore = (flags & FLAG_DO_NOT_RESTORE) != 0;
+ this.disableRestore = (flags & FLAG_DISABLE_RESTORE) != 0;
this.workspaceIconsCanBeDragged = (flags & FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED) != 0;
+ this.disablePageClipping = (flags & FLAG_DISABLE_PAGE_CLIPPING) != 0;
this.verticalProgress = verticalProgress;
@@ -135,7 +145,20 @@
return launcher.getWorkspace().getCurrentPageDescription();
}
+ public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
+ if (this != NORMAL || !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
+ return DEFAULT_ALPHA_PROVIDER;
+ }
+ int centerPage = launcher.getWorkspace().getPageNearestToCenterOfScreen();
+ return (childIndex) -> childIndex != centerPage ? 0 : 1f;
+ }
+
protected static void dispatchWindowStateChanged(Launcher launcher) {
launcher.getWindow().getDecorView().sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED);
}
+
+ public interface PageAlphaProvider {
+
+ float getPageAlpha(int pageIndex);
+ }
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 1e6016b..0137b26 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -25,9 +25,9 @@
import android.os.Looper;
import android.view.View;
-import com.android.launcher3.anim.AnimationLayerSet;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.uioverrides.UiFactory;
/**
@@ -93,7 +93,7 @@
return mState;
}
- private StateHandler[] getStateHandlers() {
+ public StateHandler[] getStateHandlers() {
if (mStateHandlers == null) {
mStateHandlers = UiFactory.getStateHandler(mLauncher);
}
@@ -158,14 +158,14 @@
mConfig.reset();
if (!animated) {
- setState(state);
+ onStateTransitionStart(state);
for (StateHandler handler : getStateHandlers()) {
handler.setState(state);
}
if (mStateListener != null) {
mStateListener.onStateSetImmediately(state);
}
- mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
+ onStateTransitionEnd(state);
// Run any queued runnable
if (onCompleteRunnable != null) {
@@ -178,7 +178,8 @@
// transition plays in reverse and use the same duration as previous state.
mConfig.duration = state == NORMAL ? mState.transitionDuration : state.transitionDuration;
- AnimatorSet animation = createAnimationToNewWorkspaceInternal(state, onCompleteRunnable);
+ AnimatorSet animation = createAnimationToNewWorkspaceInternal(
+ state, new AnimatorSetBuilder(), onCompleteRunnable);
Runnable runnable = new StartAnimRunnable(animation, state.getFinalFocus(mLauncher));
if (delay > 0) {
mUiHandler.postDelayed(runnable, delay);
@@ -196,28 +197,32 @@
*/
public AnimatorPlaybackController createAnimationToNewWorkspace(
LauncherState state, long duration) {
+ return createAnimationToNewWorkspace(state, new AnimatorSetBuilder(), duration);
+ }
+
+ public AnimatorPlaybackController createAnimationToNewWorkspace(
+ LauncherState state, AnimatorSetBuilder builder, long duration) {
mConfig.reset();
mConfig.userControlled = true;
mConfig.duration = duration;
return AnimatorPlaybackController.wrap(
- createAnimationToNewWorkspaceInternal(state, null), duration);
+ createAnimationToNewWorkspaceInternal(state, builder, null), duration);
}
protected AnimatorSet createAnimationToNewWorkspaceInternal(final LauncherState state,
- final Runnable onCompleteRunnable) {
- final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
- final AnimationLayerSet layerViews = new AnimationLayerSet();
-
+ AnimatorSetBuilder builder, final Runnable onCompleteRunnable) {
for (StateHandler handler : getStateHandlers()) {
- handler.setStateWithAnimation(state, layerViews, animation, mConfig);
+ builder.startTag(handler);
+ handler.setStateWithAnimation(state, builder, mConfig);
}
- animation.addListener(layerViews);
+
+ final AnimatorSet animation = builder.build();
animation.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
// Change the internal state only when the transition actually starts
- setState(state);
+ onStateTransitionStart(state);
if (mStateListener != null) {
mStateListener.onStateTransitionStart(state);
}
@@ -237,19 +242,28 @@
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
-
- mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
+ onStateTransitionEnd(state);
}
});
mConfig.setAnimation(animation);
return mConfig.mCurrentAnimation;
}
- private void setState(LauncherState state) {
+ private void onStateTransitionStart(LauncherState state) {
mState.onStateDisabled(mLauncher);
mState = state;
mState.onStateEnabled(mLauncher);
mLauncher.getAppWidgetHost().setResumed(state == LauncherState.NORMAL);
+
+ if (state.disablePageClipping) {
+ // Only disable clipping if needed, otherwise leave it as previous value.
+ mLauncher.getWorkspace().setClipChildren(false);
+ }
+ }
+
+ private void onStateTransitionEnd(LauncherState state) {
+ mLauncher.getWorkspace().setClipChildren(!state.disablePageClipping);
+ mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
}
/**
@@ -321,8 +335,8 @@
/**
* Sets the UI to {@param state} by animating any changes.
*/
- void setStateWithAnimation(LauncherState toState, AnimationLayerSet layerViews,
- AnimatorSet anim, AnimationConfig config);
+ void setStateWithAnimation(LauncherState toState,
+ AnimatorSetBuilder builder, AnimationConfig config);
}
public interface StateListener {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 9f6efb3..d6b5656 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -16,6 +16,9 @@
package com.android.launcher3;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
@@ -41,7 +44,6 @@
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
@@ -521,9 +523,7 @@
}
private void sendScrollAccessibilityEvent() {
- AccessibilityManager am =
- (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (am.isEnabled()) {
+ if (isObservedEventType(getContext(), AccessibilityEvent.TYPE_VIEW_SCROLLED)) {
if (mCurrentPage != getNextPage()) {
AccessibilityEvent ev =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
@@ -572,9 +572,7 @@
}
onPostReorderingAnimationCompleted();
- AccessibilityManager am = (AccessibilityManager)
- getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (am.isEnabled()) {
+ if (isAccessibilityEnabled(getContext())) {
// Notify the user when the page changes
announceForAccessibility(getCurrentPageDescription());
}
@@ -593,6 +591,11 @@
- mInsets.top - mInsets.bottom;
}
+ public int getNormalChildWidth() {
+ return getViewportWidth() - getPaddingLeft() - getPaddingRight()
+ - mInsets.left - mInsets.right;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getChildCount() == 0) {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index e6bc770..ca235eb 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -47,8 +47,6 @@
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
import com.android.launcher3.config.FeatureFlags;
@@ -614,23 +612,6 @@
return c == null || c.isEmpty();
}
- public static boolean isAccessibilityEnabled(Context context) {
- AccessibilityManager accessibilityManager = (AccessibilityManager)
- context.getSystemService(Context.ACCESSIBILITY_SERVICE);
- return accessibilityManager.isEnabled();
- }
-
- public static void sendCustomAccessibilityEvent(View target, int type, String text) {
- AccessibilityManager accessibilityManager = (AccessibilityManager)
- target.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (accessibilityManager.isEnabled()) {
- AccessibilityEvent event = AccessibilityEvent.obtain(type);
- target.onInitializeAccessibilityEvent(event);
- event.getText().add(text);
- accessibilityManager.sendAccessibilityEvent(event);
- }
- }
-
public static boolean isBinderSizeError(Exception e) {
return e.getCause() instanceof TransactionTooLargeException
|| e.getCause() instanceof DeadObjectException;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 749afd0..417366d 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -22,11 +22,10 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
-import static com.android.launcher3.Utilities.isAccessibilityEnabled;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
@@ -63,7 +62,7 @@
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate;
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
-import com.android.launcher3.anim.AnimationLayerSet;
+import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.badge.FolderBadgeInfo;
import com.android.launcher3.compat.AppWidgetManagerCompat;
@@ -193,10 +192,6 @@
private static final int HOTSEAT_STATE_ALPHA_INDEX = 2;
/**
- * These values correspond to {@link Direction#X} & {@link Direction#Y}
- */
- private final float[] mPageAlpha = new float[] {1, 1};
- /**
* Hotseat alpha can be changed when moving horizontally, vertically, changing states.
* The values correspond to {@link Direction#X}, {@link Direction#Y} &
* {@link #HOTSEAT_STATE_ALPHA_INDEX} respectively.
@@ -436,7 +431,6 @@
mCurrentPage = DEFAULT_PAGE;
DeviceProfile grid = mLauncher.getDeviceProfile();
setWillNotDraw(false);
- setClipChildren(false);
setClipToPadding(false);
setupLayoutTransition();
@@ -1191,33 +1185,21 @@
// TODO(adamcohen): figure out a final effect here. We may need to recommend
// different effects based on device performance. On at least one relatively high-end
// device I've tried, translating the launcher causes things to get quite laggy.
- setWorkspaceTranslationAndAlpha(Direction.X, transX, alpha);
+ setWorkspaceTranslationAndAlpha(transX, alpha);
setHotseatTranslationAndAlpha(Direction.X, transX, alpha);
}
/**
- * Moves the workspace UI in the Y direction.
- * @param translation the amount of shift.
- * @param alpha the alpha for the workspace page
- */
- public void setWorkspaceYTranslationAndAlpha(float translation, float alpha) {
- setWorkspaceTranslationAndAlpha(Direction.Y, translation, alpha);
- }
-
- /**
* Moves the workspace UI in the provided direction.
- * @param direction the direction to move the workspace
- * @param translation the amount of shift.
+ * @param translation the amount of horizontal shift.
* @param alpha the alpha for the workspace page
*/
- private void setWorkspaceTranslationAndAlpha(Direction direction, float translation, float alpha) {
- Property<View, Float> property = direction.viewProperty;
- mPageAlpha[direction.ordinal()] = alpha;
- float finalAlpha = mPageAlpha[0] * mPageAlpha[1];
+ private void setWorkspaceTranslationAndAlpha(float translation, float alpha) {
+ float finalAlpha = alpha;
View currentChild = getChildAt(getCurrentPage());
if (currentChild != null) {
- property.set(currentChild, translation);
+ currentChild.setTranslationX(translation);
currentChild.setAlpha(finalAlpha);
}
@@ -1225,7 +1207,7 @@
if (Float.compare(translation, 0) == 0) {
for (int i = getChildCount() - 1; i >= 0; i--) {
View child = getChildAt(i);
- property.set(child, translation);
+ child.setTranslationX(0);
child.setAlpha(finalAlpha);
}
}
@@ -1564,10 +1546,10 @@
* Sets the current workspace {@link LauncherState}, then animates the UI
*/
@Override
- public void setStateWithAnimation(LauncherState toState, AnimationLayerSet layerViews,
- AnimatorSet anim, AnimationConfig config) {
+ public void setStateWithAnimation(LauncherState toState,
+ AnimatorSetBuilder builder, AnimationConfig config) {
StateTransitionListener listener = new StateTransitionListener(toState);
- mStateTransitionAnimation.setStateWithAnimation(toState, anim, layerViews, config);
+ mStateTransitionAnimation.setStateWithAnimation(toState, builder, config);
// Invalidate the pages now, so that we have the visible pages before the
// animation is started
@@ -1579,8 +1561,8 @@
ValueAnimator stepAnimator = ValueAnimator.ofFloat(0, 1);
stepAnimator.addUpdateListener(listener);
stepAnimator.setDuration(config.duration);
- anim.play(stepAnimator);
- anim.addListener(listener);
+ stepAnimator.addListener(listener);
+ builder.play(stepAnimator);
}
public void updateAccessibilityFlags() {
@@ -3519,17 +3501,17 @@
mRefreshPending = false;
- mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- if (view instanceof PendingAppWidgetHostView && mInfos.contains(info)) {
- mLauncher.removeItem(view, info, false /* deleteFromDb */);
- mLauncher.bindAppWidget((LauncherAppWidgetInfo) info);
- }
- // process all the shortcuts
- return false;
+ ArrayList<PendingAppWidgetHostView> views = new ArrayList<>(mInfos.size());
+ mapOverItems(MAP_NO_RECURSE, (info, view) -> {
+ if (view instanceof PendingAppWidgetHostView && mInfos.contains(info)) {
+ views.add((PendingAppWidgetHostView) view);
}
+ // process all children
+ return false;
});
+ for (PendingAppWidgetHostView view : views) {
+ view.reinflate();
+ }
}
@Override
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 8edec40..9f76b6f 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -18,21 +18,19 @@
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
import android.util.Property;
import android.view.View;
-import android.view.accessibility.AccessibilityManager;
+import com.android.launcher3.LauncherState.PageAlphaProvider;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
-import com.android.launcher3.anim.AnimationLayerSet;
+import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
/**
@@ -97,28 +95,23 @@
private final Launcher mLauncher;
private final Workspace mWorkspace;
- private final boolean mWorkspaceFadeInAdjacentScreens;
-
private float mNewScale;
public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) {
mLauncher = launcher;
mWorkspace = workspace;
-
- DeviceProfile grid = mLauncher.getDeviceProfile();
- Resources res = launcher.getResources();
- mWorkspaceScrimAlpha = res.getInteger(R.integer.config_workspaceScrimAlpha);
- mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
+ mWorkspaceScrimAlpha = launcher.getResources()
+ .getInteger(R.integer.config_workspaceScrimAlpha);
}
public void setState(LauncherState toState) {
setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER);
}
- public void setStateWithAnimation(LauncherState toState, AnimatorSet anim,
- AnimationLayerSet layerViews, AnimationConfig config) {
+ public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder,
+ AnimationConfig config) {
AnimatedPropertySetter propertySetter =
- new AnimatedPropertySetter(config.duration, layerViews, anim);
+ new AnimatedPropertySetter(config.duration, builder);
setWorkspaceProperty(toState, propertySetter);
}
@@ -134,10 +127,10 @@
mNewScale = scaleAndTranslationY[0];
final float finalWorkspaceTranslationY = scaleAndTranslationY[1];
- int toPage = mWorkspace.getPageNearestToCenterOfScreen();
+ PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
final int childCount = mWorkspace.getChildCount();
for (int i = 0; i < childCount; i++) {
- applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, toPage,
+ applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider,
propertySetter);
}
@@ -151,21 +144,16 @@
}
public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
- applyChildState(state, cl, childIndex, mWorkspace.getPageNearestToCenterOfScreen(),
+ applyChildState(state, cl, childIndex, state.getWorkspacePageAlphaProvider(mLauncher),
NO_ANIM_PROPERTY_SETTER);
}
private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
- int centerPage, PropertySetter propertySetter) {
+ PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter) {
propertySetter.setInt(cl.getScrimBackground(),
DRAWABLE_ALPHA, state.hasScrim ? 255 : 0, Interpolators.ZOOM_IN);
-
- // Only animate the page alpha when we actually fade pages
- if (mWorkspaceFadeInAdjacentScreens) {
- float finalAlpha = state == LauncherState.NORMAL && childIndex != centerPage ? 0 : 1f;
- propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
- finalAlpha, Interpolators.ZOOM_IN);
- }
+ propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
+ pageAlphaProvider.getPageAlpha(childIndex), Interpolators.DEACCEL_2);
}
public static class PropertySetter {
@@ -176,7 +164,7 @@
return;
}
view.setAlpha(alpha);
- AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view));
+ AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view.getContext()));
}
public <T> void setFloat(T target, Property<T, Float> property, float value,
@@ -188,25 +176,16 @@
TimeInterpolator interpolator) {
property.set(target, value);
}
-
- protected boolean isAccessibilityEnabled(View v) {
- AccessibilityManager am = (AccessibilityManager)
- v.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- return am.isEnabled();
- }
}
public static class AnimatedPropertySetter extends PropertySetter {
private final long mDuration;
- private final AnimationLayerSet mLayerViews;
- private final AnimatorSet mStateAnimator;
+ private final AnimatorSetBuilder mStateAnimator;
- public AnimatedPropertySetter(
- long duration, AnimationLayerSet layerView, AnimatorSet anim) {
+ public AnimatedPropertySetter(long duration, AnimatorSetBuilder builder) {
mDuration = duration;
- mLayerViews = layerView;
- mStateAnimator = anim;
+ mStateAnimator = builder;
}
@Override
@@ -216,11 +195,11 @@
return;
}
anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
- anim.addListener(new AlphaUpdateListener(view, isAccessibilityEnabled(view)));
+ anim.addListener(new AlphaUpdateListener(view,
+ isAccessibilityEnabled(view.getContext())));
}
anim.setDuration(mDuration).setInterpolator(getFadeInterpolator(alpha));
- mLayerViews.addView(view);
mStateAnimator.play(anim);
}
diff --git a/src/com/android/launcher3/accessibility/DragViewStateAnnouncer.java b/src/com/android/launcher3/accessibility/DragViewStateAnnouncer.java
index 99deb7b..fdf2786 100644
--- a/src/com/android/launcher3/accessibility/DragViewStateAnnouncer.java
+++ b/src/com/android/launcher3/accessibility/DragViewStateAnnouncer.java
@@ -16,10 +16,10 @@
package com.android.launcher3.accessibility;
-import android.content.Context;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
+
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
import com.android.launcher3.Launcher;
@@ -59,11 +59,6 @@
}
public static DragViewStateAnnouncer createFor(View v) {
- if (((AccessibilityManager) v.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE))
- .isEnabled()) {
- return new DragViewStateAnnouncer(v);
- } else {
- return null;
- }
+ return isAccessibilityEnabled(v.getContext()) ? new DragViewStateAnnouncer(v) : null;
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index f4026f2..7b89c5c 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -61,7 +61,6 @@
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.TransformingTouchDelegate;
import com.android.launcher3.views.BottomUserEducationView;
-import com.android.launcher3.views.SlidingTabStrip;
import java.util.HashMap;
import java.util.List;
@@ -85,8 +84,7 @@
private SearchUiManager mSearchUiManager;
private View mSearchContainer;
private InterceptingViewPager mViewPager;
- private ViewGroup mHeader;
- private FloatingHeaderHandler mFloatingHeaderHandler;
+ private FloatingHeaderView mHeader;
private TabsPagerAdapter mTabsPagerAdapter;
private SpannableStringBuilder mSearchQueryBuilder = null;
@@ -234,8 +232,8 @@
for (int i = 0; i < mAH.length; i++) {
updatePromiseAppProgress(app, mAH[i].recyclerView);
}
- if (mFloatingHeaderHandler != null) {
- updatePromiseAppProgress(app, mFloatingHeaderHandler.getContentView());
+ if (isHeaderVisible()) {
+ updatePromiseAppProgress(app, mHeader.getPredictionRow());
}
}
@@ -262,9 +260,6 @@
if (mLauncher.getDragLayer().isEventOverView(mSearchContainer, ev)) {
return true;
}
- if (mUsingTabs && mLauncher.getDragLayer().isEventOverView(mHeader, ev)) {
- return true;
- }
AllAppsRecyclerView rv = getActiveRecyclerView();
return rv == null || rv.shouldContainerScroll(ev, mLauncher.getDragLayer());
}
@@ -286,8 +281,8 @@
mAH[i].recyclerView.scrollToTop();
}
}
- if (mFloatingHeaderHandler != null) {
- mFloatingHeaderHandler.reset();
+ if (isHeaderVisible()) {
+ mHeader.reset();
}
// Reset the search bar and base recycler view after transitioning home
mSearchUiManager.reset();
@@ -309,7 +304,6 @@
});
mHeader = findViewById(R.id.all_apps_header);
- mFloatingHeaderHandler = new FloatingHeaderHandler(mHeader);
rebindAdapters(mUsingTabs);
mSearchContainer = findViewById(R.id.search_container_all_apps);
@@ -447,7 +441,6 @@
if (FeatureFlags.ALL_APPS_PREDICTION_ROW_VIEW) {
setupHeader();
} else {
- mFloatingHeaderHandler = null;
mHeader.setVisibility(View.GONE);
}
}
@@ -489,29 +482,19 @@
if (mTabsPagerAdapter != null) {
return;
}
- final SlidingTabStrip tabs = findViewById(R.id.tabs);
+ final PersonalWorkSlidingTabStrip tabs = findViewById(R.id.tabs);
mViewPager.setAdapter(mTabsPagerAdapter = new TabsPagerAdapter());
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
- boolean mVisible = true;
-
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
tabs.updateIndicatorPosition(position, positionOffset);
- if (positionOffset == 0 && !mVisible || positionOffset > 0 && mVisible) {
- mVisible = positionOffset == 0;
- for (int i = 0; i < mAH.length; i++) {
- if (mAH[i].recyclerView != null) {
- mAH[i].recyclerView.getScrollbar().setAlpha(mVisible ? 1 : 0);
- }
- }
- }
}
@Override
public void onPageSelected(int pos) {
tabs.updateTabTextColor(pos);
- mFloatingHeaderHandler.setMainActive(pos == 0);
+ mHeader.setMainActive(pos == 0);
applyTouchDelegate();
if (mAH[pos].recyclerView != null) {
mAH[pos].recyclerView.bindFastScrollbar();
@@ -525,6 +508,7 @@
public void onPageScrollStateChanged(int state) {
}
});
+ mAH[AdapterHolder.MAIN].recyclerView.bindFastScrollbar();
findViewById(R.id.tab_personal)
.setOnClickListener((View view) -> mViewPager.setCurrentItem(0));
@@ -533,14 +517,16 @@
}
public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
- if (mFloatingHeaderHandler != null) {
- mFloatingHeaderHandler.getContentView().setPredictedApps(apps);
+ if (isHeaderVisible()) {
+ mHeader.getPredictionRow().setPredictedApps(apps);
}
mAH[AdapterHolder.MAIN].appsList.setPredictedApps(apps);
boolean hasPredictions = !apps.isEmpty();
if (mHasPredictions != hasPredictions) {
mHasPredictions = hasPredictions;
- setupHeader();
+ if (FeatureFlags.ALL_APPS_PREDICTION_ROW_VIEW) {
+ setupHeader();
+ }
}
}
@@ -556,29 +542,18 @@
return mUsingTabs;
}
- public FloatingHeaderHandler getFloatingHeaderHandler() {
- return mFloatingHeaderHandler;
+ public FloatingHeaderView getFloatingHeaderView() {
+ return mHeader;
}
private void setupHeader() {
- if (mFloatingHeaderHandler == null) {
+ if (mHeader == null) {
return;
}
mHeader.setVisibility(View.VISIBLE);
+ mHeader.setup(mAH, mComponentToAppMap, mNumPredictedAppsPerRow);
- boolean usePredictionRow = mHasPredictions && !mSearchModeWhileUsingTabs;
- int contentHeight = usePredictionRow ? mLauncher.getDeviceProfile().allAppsCellHeightPx : 0;;
- if (usePredictionRow && !mUsingTabs) {
- contentHeight += getResources()
- .getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height);
- }
- RecyclerView mainRV = mAH[AdapterHolder.MAIN].recyclerView;
- RecyclerView workRV = mAH[AdapterHolder.WORK].recyclerView;
- mFloatingHeaderHandler.setup(mainRV, workRV, contentHeight);
- mFloatingHeaderHandler.getContentView().setup(mAH[AdapterHolder.MAIN].adapter,
- mComponentToAppMap, mNumPredictedAppsPerRow);
-
- int padding = contentHeight;
+ int padding = mHeader.getPredictionRow().getExpectedHeight();
if (mHasPredictions && !mUsingTabs) {
padding += mHeader.getPaddingTop() + mHeader.getPaddingBottom();
}
@@ -593,7 +568,7 @@
mAH[i].adapter.setLastSearchQuery(query);
}
boolean hasQuery = !TextUtils.isEmpty(query);
- if (mFloatingHeaderHandler != null && mUsingTabs && hasQuery) {
+ if (mUsingTabs && hasQuery) {
mSearchModeWhileUsingTabs = true;
rebindAdapters(false); // hide tabs
} else if (mSearchModeWhileUsingTabs && !hasQuery) {
@@ -639,12 +614,16 @@
public List<AppInfo> getPredictedApps() {
if (mUsingTabs) {
- return mFloatingHeaderHandler.getContentView().getPredictedApps();
+ return mHeader.getPredictionRow().getPredictedApps();
} else {
return mAH[AdapterHolder.MAIN].appsList.getPredictedApps();
}
}
+ private boolean isHeaderVisible() {
+ return mHeader != null && mHeader.getVisibility() == View.VISIBLE;
+ }
+
public class AdapterHolder {
public static final int MAIN = 0;
public static final int WORK = 1;
@@ -694,8 +673,8 @@
? paddingTopForTabs : padding.top;
recyclerView.setPadding(padding.left, paddingTop, padding.right, padding.bottom);
}
- if (mFloatingHeaderHandler != null) {
- mFloatingHeaderHandler.getContentView()
+ if (isHeaderVisible()) {
+ mHeader.getPredictionRow()
.setPadding(padding.left, 0 , padding.right, 0);
}
}
@@ -707,8 +686,8 @@
}
adapter.setNumAppsPerRow(mNumAppsPerRow);
appsList.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
- if (mFloatingHeaderHandler != null) {
- mFloatingHeaderHandler.getContentView()
+ if (isHeaderVisible()) {
+ mHeader.getPredictionRow()
.setNumAppsPerRow(mNumPredictedAppsPerRow);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 5789b67..fd80784 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -31,7 +31,6 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.config.FeatureFlags;
@@ -53,7 +52,6 @@
private AlphabeticalAppsList mApps;
private AllAppsFastScrollHelper mFastScrollHelper;
private int mNumAppsPerRow;
- private int mUserProfileTabContentHeight;
// The specific view heights that we use to calculate scroll
private SparseIntArray mViewHeights = new SparseIntArray();
@@ -127,8 +125,6 @@
public void setApps(AlphabeticalAppsList apps, boolean usingTabs) {
mApps = apps;
mFastScrollHelper = new AllAppsFastScrollHelper(this, apps);
- mUserProfileTabContentHeight = usingTabs
- ? Launcher.getLauncher(getContext()).getDeviceProfile().allAppsCellHeightPx : 0;;
}
public AlphabeticalAppsList getApps() {
@@ -362,6 +358,9 @@
*/
@Override
public void onUpdateScrollbar(int dy) {
+ if (mApps == null) {
+ return;
+ }
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
// Skip early if there are no items or we haven't been measured
@@ -488,18 +487,11 @@
@Override
protected int getAvailableScrollHeight() {
return getPaddingTop() + getCurrentScrollY(getAdapter().getItemCount(), 0)
- - getHeight() + getPaddingBottom() + mUserProfileTabContentHeight;
+ - getHeight() + getPaddingBottom();
}
public int getScrollBarTop() {
- return super.getScrollBarTop() + mUserProfileTabContentHeight;
- }
-
- /**
- * Returns the height of the fast scroll bar
- */
- public int getScrollbarTrackHeight() {
- return super.getScrollbarTrackHeight() + mUserProfileTabContentHeight;
+ return getResources().getDimensionPixelOffset(R.dimen.all_apps_header_top_padding);
}
public RecyclerViewFastScroller getScrollbar() {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index eb26704..5de58b4 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -4,9 +4,7 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import android.animation.Animator;
-import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.util.Property;
import android.view.View;
@@ -20,8 +18,8 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
-import com.android.launcher3.anim.AnimationLayerSet;
import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.graphics.GradientView;
import com.android.launcher3.util.SystemUiController;
@@ -54,10 +52,9 @@
}
};
- private final Interpolator mWorkspaceAccelnterpolator = Interpolators.ACCEL_2;
private final Interpolator mHotseatAccelInterpolator = Interpolators.ACCEL_1_5;
- private static final float PARALLAX_COEFFICIENT = .125f;
+ public static final float PARALLAX_COEFFICIENT = .125f;
private AllAppsContainerView mAppsView;
private Workspace mWorkspace;
@@ -77,8 +74,6 @@
private static final float DEFAULT_SHIFT_RANGE = 10;
- private boolean mIsTranslateWithoutWorkspace = false;
- private Animator mDiscoBounceAnimation;
private GradientView mGradientView;
public AllAppsTransitionController(Launcher l) {
@@ -126,7 +121,7 @@
* @param progress value between 0 and 1, 0 shows all apps and 1 shows workspace
*
* @see #setState(LauncherState)
- * @see #setStateWithAnimation(LauncherState, AnimationLayerSet, AnimatorSet, AnimationConfig)
+ * @see #setStateWithAnimation(LauncherState, AnimatorSetBuilder, AnimationConfig)
*/
public void setProgress(float progress) {
mProgress = progress;
@@ -134,7 +129,6 @@
float workspaceHotseatAlpha = Utilities.boundToRange(progress, 0f, 1f);
float alpha = 1 - workspaceHotseatAlpha;
- float workspaceAlpha = mWorkspaceAccelnterpolator.getInterpolation(workspaceHotseatAlpha);
float hotseatAlpha = mHotseatAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
updateAllAppsBg(alpha);
@@ -150,12 +144,6 @@
hotseatAlpha);
}
- if (mIsTranslateWithoutWorkspace) {
- return;
- }
- mWorkspace.setWorkspaceYTranslationAndAlpha(
- PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent), workspaceAlpha);
-
updateLightStatusBar(shiftCurrent);
}
@@ -178,8 +166,8 @@
* dependent UI using various animation events
*/
@Override
- public void setStateWithAnimation(LauncherState toState, AnimationLayerSet layerViews,
- AnimatorSet animationOut, AnimationConfig config) {
+ public void setStateWithAnimation(LauncherState toState,
+ AnimatorSetBuilder builder, AnimationConfig config) {
if (Float.compare(mProgress, toState.verticalProgress) == 0) {
// Fail fast
onProgressAnimationEnd();
@@ -191,7 +179,13 @@
this, PROGRESS, mProgress, toState.verticalProgress);
anim.setDuration(config.duration);
anim.setInterpolator(interpolator);
- anim.addListener(new AnimationSuccessListener() {
+ anim.addListener(getProgressAnimatorListener());
+
+ builder.play(anim);
+ }
+
+ public AnimatorListenerAdapter getProgressAnimatorListener() {
+ return new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
onProgressAnimationEnd();
@@ -201,50 +195,7 @@
public void onAnimationStart(Animator animation) {
onProgressAnimationStart();
}
- });
-
- animationOut.play(anim);
- }
-
- public void showDiscoveryBounce() {
- // cancel existing animation in case user locked and unlocked at a super human speed.
- cancelDiscoveryAnimation();
-
- // assumption is that this variable is always null
- mDiscoBounceAnimation = AnimatorInflater.loadAnimator(mLauncher,
- R.animator.discovery_bounce);
- mDiscoBounceAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animator) {
- mIsTranslateWithoutWorkspace = true;
- onProgressAnimationStart();
- }
-
- @Override
- public void onAnimationEnd(Animator animator) {
- onProgressAnimationEnd();
- mDiscoBounceAnimation = null;
- mIsTranslateWithoutWorkspace = false;
- }
- });
- mDiscoBounceAnimation.setTarget(this);
- mAppsView.post(new Runnable() {
- @Override
- public void run() {
- if (mDiscoBounceAnimation == null) {
- return;
- }
- mDiscoBounceAnimation.start();
- }
- });
- }
-
- public void cancelDiscoveryAnimation() {
- if (mDiscoBounceAnimation == null) {
- return;
- }
- mDiscoBounceAnimation.cancel();
- mDiscoBounceAnimation = null;
+ };
}
public void setupViews(AllAppsContainerView appsView, Hotseat hotseat, Workspace workspace) {
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
new file mode 100644
index 0000000..550fcf9
--- /dev/null
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 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.allapps;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorListenerAdapter;
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.compat.UserManagerCompat;
+
+/**
+ * Floating view responsible for showing discovery bounce animation
+ */
+public class DiscoveryBounce extends AbstractFloatingView {
+
+ public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
+
+ private final Launcher mLauncher;
+ private final Animator mDiscoBounceAnimation;
+
+ public DiscoveryBounce(Launcher launcher) {
+ super(launcher, null);
+ mLauncher = launcher;
+
+ mDiscoBounceAnimation = AnimatorInflater.loadAnimator(mLauncher,
+ R.animator.discovery_bounce);
+ AllAppsTransitionController controller = mLauncher.getAllAppsController();
+ mDiscoBounceAnimation.setTarget(controller);
+ mDiscoBounceAnimation.addListener(controller.getProgressAnimatorListener());
+
+ mDiscoBounceAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ handleClose(false);
+ }
+ });
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mDiscoBounceAnimation.start();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mDiscoBounceAnimation.isRunning()) {
+ mDiscoBounceAnimation.end();
+ }
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ handleClose(false);
+ return false;
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ if (mIsOpen) {
+ mIsOpen = false;
+ mLauncher.getDragLayer().removeView(this);
+ }
+ }
+
+ @Override
+ public void logActionCommand(int command) {
+ // Since this is on-boarding popup, it is not a user controlled action.
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_ON_BOARD_POPUP) != 0;
+ }
+
+ public static void showIfNeeded(Launcher launcher) {
+ if (!launcher.isInState(NORMAL)
+ || launcher.getSharedPrefs().getBoolean(APPS_VIEW_SHOWN, false)
+ || AbstractFloatingView.getTopOpenView(launcher) != null
+ || UserManagerCompat.getInstance(launcher).isDemoUser()) {
+ return;
+ }
+
+ DiscoveryBounce view = new DiscoveryBounce(launcher);
+ view.mIsOpen = true;
+ launcher.getDragLayer().addView(view);
+ }
+}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderHandler.java b/src/com/android/launcher3/allapps/FloatingHeaderHandler.java
deleted file mode 100644
index c4b533b..0000000
--- a/src/com/android/launcher3/allapps/FloatingHeaderHandler.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2017 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.allapps;
-
-import android.animation.ValueAnimator;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.RelativeLayout;
-
-import com.android.launcher3.R;
-
-public class FloatingHeaderHandler extends RecyclerView.OnScrollListener
- implements ValueAnimator.AnimatorUpdateListener {
-
- private final View mHeaderView;
- private final PredictionRowView mPredictionRow;
- private final ViewGroup mTabLayout;
- private final View mDivider;
- private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
- private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
-
- private RecyclerView mMainRV;
- private RecyclerView mWorkRV;
- private boolean mTopOnlyMode;
- private boolean mHeaderHidden;
- private int mMaxTranslation;
- private int mSnappedScrolledY;
- private int mTranslationY;
- private int mMainScrolledY;
- private int mWorkScrolledY;
- private boolean mMainRVActive;
-
- public FloatingHeaderHandler(@NonNull ViewGroup header) {
- mHeaderView = header;
- mTabLayout = header.findViewById(R.id.tabs);
- mDivider = header.findViewById(R.id.divider);
- mPredictionRow = header.findViewById(R.id.header_content);
- }
-
- public void setup(@NonNull RecyclerView personalRV, @Nullable RecyclerView workRV,
- int predictionRowHeight) {
- mTopOnlyMode = workRV == null;
- mTabLayout.setVisibility(mTopOnlyMode ? View.GONE : View.VISIBLE);
- mPredictionRow.getLayoutParams().height = predictionRowHeight;
- mMaxTranslation = predictionRowHeight;
- mMainRV = personalRV;
- mMainRV.addOnScrollListener(this);
- mWorkRV = workRV;
- if (workRV != null) {
- workRV.addOnScrollListener(this);
- }
- setMainActive(true);
- setupDivider();
- }
-
- private void setupDivider() {
- Resources res = mHeaderView.getResources();
- int verticalGap = res.getDimensionPixelSize(R.dimen.all_apps_divider_margin_vertical);
- int sideGap = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
- mDivider.setPadding(sideGap, verticalGap,sideGap, mTopOnlyMode ? verticalGap : 0);
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mDivider.getLayoutParams();
- lp.removeRule(RelativeLayout.ALIGN_BOTTOM);
- lp.addRule(RelativeLayout.ALIGN_BOTTOM, mTopOnlyMode ? R.id.header_content : R.id.tabs);
- mDivider.setLayoutParams(lp);
- }
-
- public void setMainActive(boolean active) {
- mMainRVActive = active;
- mSnappedScrolledY = getCurrentScroll() - mMaxTranslation;
- setExpanded(true);
- }
-
- public View getHeaderView() {
- return mHeaderView;
- }
-
- public PredictionRowView getContentView() {
- return mPredictionRow;
- }
-
- public ViewGroup getTabLayout() {
- return mTabLayout;
- }
-
- public View getDivider() {
- return mDivider;
- }
-
- @Override
- public void onScrolled(RecyclerView rv, int dx, int dy) {
- boolean isMainRV = rv == mMainRV;
- if (isMainRV != mMainRVActive) {
- return;
- }
-
- if (mAnimator.isStarted()) {
- mAnimator.cancel();
- }
-
- int current = isMainRV
- ? (mMainScrolledY -= dy)
- : (mWorkScrolledY -= dy);
-
- moved(current);
- apply();
- }
-
- public void reset() {
- mMainScrolledY = 0;
- mWorkScrolledY = 0;
- setExpanded(true);
- }
-
- private boolean canSnapAt(int currentScrollY) {
- return !mTopOnlyMode || Math.abs(currentScrollY) <= mPredictionRow.getHeight();
- }
-
- private void moved(final int currentScrollY) {
- if (mHeaderHidden) {
- if (currentScrollY <= mSnappedScrolledY) {
- if (canSnapAt(currentScrollY)) {
- mSnappedScrolledY = currentScrollY;
- }
- } else {
- mHeaderHidden = false;
- }
- mTranslationY = currentScrollY;
- } else if (!mHeaderHidden) {
- mTranslationY = currentScrollY - mSnappedScrolledY - mMaxTranslation;
-
- // update state vars
- if (mTranslationY >= 0) { // expanded: must not move down further
- mTranslationY = 0;
- mSnappedScrolledY = currentScrollY - mMaxTranslation;
- } else if (mTranslationY <= -mMaxTranslation) { // hide or stay hidden
- mHeaderHidden = true;
- mSnappedScrolledY = currentScrollY;
- }
- }
- }
-
- private void apply() {
- int uncappedTranslationY = mTranslationY;
- mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
- if (mTranslationY != uncappedTranslationY) {
- // we hide it completely if already capped (for opening search anim)
- mPredictionRow.setVisibility(View.INVISIBLE);
- } else {
- mPredictionRow.setVisibility(View.VISIBLE);
- mPredictionRow.setTranslationY(uncappedTranslationY);
- }
- mTabLayout.setTranslationY(mTranslationY);
- mDivider.setTranslationY(mTopOnlyMode ? uncappedTranslationY : mTranslationY);
- mClip.top = mMaxTranslation + mTranslationY;
- // clipping on a draw might cause additional redraw
- mMainRV.setClipBounds(mClip);
- if (mWorkRV != null) {
- mWorkRV.setClipBounds(mClip);
- }
- }
-
- @Override
- public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
- if (!mTopOnlyMode && newState == RecyclerView.SCROLL_STATE_IDLE
- && mTranslationY != -mMaxTranslation && mTranslationY != 0) {
- float scroll = Math.abs(getCurrentScroll());
- boolean expand = scroll > mMaxTranslation
- ? Math.abs(mTranslationY) < mMaxTranslation / 2 : true;
- setExpanded(expand);
- }
- }
-
- private void setExpanded(boolean expand) {
- int translateTo = expand ? 0 : -mMaxTranslation;
- mAnimator.setIntValues(mTranslationY, translateTo);
- mAnimator.addUpdateListener(this);
- mAnimator.setDuration(150);
- mAnimator.start();
- mHeaderHidden = !expand;
- mSnappedScrolledY = expand ? getCurrentScroll() - mMaxTranslation : getCurrentScroll();
- }
-
- public boolean isExpanded() {
- return !mHeaderHidden;
- }
-
- private int getCurrentScroll() {
- return mMainRVActive ? mMainScrolledY : mWorkScrolledY;
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mTranslationY = (Integer) animation.getAnimatedValue();
- apply();
- }
-
-}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
new file mode 100644
index 0000000..dc3afb5
--- /dev/null
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2017 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.allapps;
+
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.util.ComponentKey;
+
+import java.util.HashMap;
+
+public class FloatingHeaderView extends RelativeLayout implements
+ ValueAnimator.AnimatorUpdateListener {
+
+
+ private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
+ private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
+ private final Point mTempOffset = new Point();
+ private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ }
+
+ @Override
+ public void onScrolled(RecyclerView rv, int dx, int dy) {
+ if (rv != mCurrentRV) {
+ return;
+ }
+
+ if (mAnimator.isStarted()) {
+ mAnimator.cancel();
+ }
+
+ int current = -mCurrentRV.getCurrentScrollY();
+ moved(current);
+ apply();
+ }
+ };
+
+ private PredictionRowView mPredictionRow;
+ private ViewGroup mTabLayout;
+ private View mDivider;
+ private AllAppsRecyclerView mMainRV;
+ private AllAppsRecyclerView mWorkRV;
+ private AllAppsRecyclerView mCurrentRV;
+ private ViewGroup mParent;
+ private boolean mTabsHidden;
+ private boolean mHeaderCollapsed;
+ private int mMaxTranslation;
+ private int mSnappedScrolledY;
+ private int mTranslationY;
+ private boolean mForwardToRecyclerView;
+
+ public FloatingHeaderView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public FloatingHeaderView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mTabLayout = findViewById(R.id.tabs);
+ mDivider = findViewById(R.id.divider);
+ mPredictionRow = findViewById(R.id.header_content);
+ }
+
+ public void setup(AllAppsContainerView.AdapterHolder[] mAH,
+ HashMap<ComponentKey, AppInfo> componentToAppMap, int numPredictedAppsPerRow) {
+ mTabsHidden = mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null;
+ mTabLayout.setVisibility(mTabsHidden ? View.GONE : View.VISIBLE);
+ mPredictionRow.setPadding(0, 0, 0, mTabsHidden ? getResources()
+ .getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height) : 0);
+ mPredictionRow.setup(mAH[AllAppsContainerView.AdapterHolder.MAIN].adapter,
+ componentToAppMap, numPredictedAppsPerRow);
+ mMaxTranslation = mPredictionRow.getExpectedHeight();
+ mMainRV = setupRV(mMainRV, mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView);
+ mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView);
+ mParent = (ViewGroup) mMainRV.getParent();
+ setMainActive(true);
+ setupDivider();
+ }
+
+ private AllAppsRecyclerView setupRV(AllAppsRecyclerView old, AllAppsRecyclerView updated) {
+ if (old != updated && updated != null ) {
+ updated.addOnScrollListener(mOnScrollListener);
+ }
+ return updated;
+ }
+
+ private void setupDivider() {
+ Resources res = getResources();
+ int verticalGap = res.getDimensionPixelSize(R.dimen.all_apps_divider_margin_vertical);
+ int sideGap = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
+ mDivider.setPadding(sideGap, verticalGap,sideGap, mTabsHidden ? verticalGap : 0);
+ RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mDivider.getLayoutParams();
+ lp.removeRule(RelativeLayout.ALIGN_BOTTOM);
+ lp.addRule(RelativeLayout.ALIGN_BOTTOM, mTabsHidden ? R.id.header_content : R.id.tabs);
+ mDivider.setLayoutParams(lp);
+ }
+
+ public void setMainActive(boolean active) {
+ mCurrentRV = active ? mMainRV : mWorkRV;
+ mSnappedScrolledY = mCurrentRV.getCurrentScrollY() - mMaxTranslation;
+ setExpanded(true);
+ }
+
+ public PredictionRowView getPredictionRow() {
+ return mPredictionRow;
+ }
+
+ public View getDivider() {
+ return mDivider;
+ }
+
+ public void reset() {
+ setExpanded(true);
+ }
+
+ private boolean canSnapAt(int currentScrollY) {
+ return Math.abs(currentScrollY) <= mPredictionRow.getHeight();
+ }
+
+ private void moved(final int currentScrollY) {
+ if (mHeaderCollapsed) {
+ if (currentScrollY <= mSnappedScrolledY) {
+ if (canSnapAt(currentScrollY)) {
+ mSnappedScrolledY = currentScrollY;
+ }
+ } else {
+ mHeaderCollapsed = false;
+ }
+ mTranslationY = currentScrollY;
+ } else if (!mHeaderCollapsed) {
+ mTranslationY = currentScrollY - mSnappedScrolledY - mMaxTranslation;
+
+ // update state vars
+ if (mTranslationY >= 0) { // expanded: must not move down further
+ mTranslationY = 0;
+ mSnappedScrolledY = currentScrollY - mMaxTranslation;
+ } else if (mTranslationY <= -mMaxTranslation) { // hide or stay hidden
+ mHeaderCollapsed = true;
+ mSnappedScrolledY = currentScrollY;
+ }
+ }
+ }
+
+ private void apply() {
+ int uncappedTranslationY = mTranslationY;
+ mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
+ if (mTranslationY != uncappedTranslationY) {
+ // we hide it completely if already capped (for opening search anim)
+ mPredictionRow.setVisibility(View.INVISIBLE);
+ } else {
+ mPredictionRow.setVisibility(View.VISIBLE);
+ mPredictionRow.setTranslationY(uncappedTranslationY);
+ }
+ mTabLayout.setTranslationY(mTranslationY);
+ mDivider.setTranslationY(mTabsHidden ? uncappedTranslationY : mTranslationY);
+ mClip.top = mMaxTranslation + mTranslationY;
+ // clipping on a draw might cause additional redraw
+ mMainRV.setClipBounds(mClip);
+ if (mWorkRV != null) {
+ mWorkRV.setClipBounds(mClip);
+ }
+ }
+
+ private void setExpanded(boolean expand) {
+ int translateTo = expand ? 0 : -mMaxTranslation;
+ mAnimator.setIntValues(mTranslationY, translateTo);
+ mAnimator.addUpdateListener(this);
+ mAnimator.setDuration(150);
+ mAnimator.start();
+ mHeaderCollapsed = !expand;
+ mSnappedScrolledY = expand
+ ? mCurrentRV.getCurrentScrollY() - mMaxTranslation
+ : mCurrentRV.getCurrentScrollY();
+ }
+
+ public boolean isExpanded() {
+ return !mHeaderCollapsed;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mTranslationY = (Integer) animation.getAnimatedValue();
+ apply();
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ calcOffset(mTempOffset);
+ ev.offsetLocation(mTempOffset.x, mTempOffset.y);
+ mForwardToRecyclerView = mCurrentRV.onInterceptTouchEvent(ev);
+ ev.offsetLocation(-mTempOffset.x, -mTempOffset.y);
+ return mForwardToRecyclerView || super.onInterceptTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (mForwardToRecyclerView) {
+ // take this view's and parent view's (view pager) location into account
+ calcOffset(mTempOffset);
+ event.offsetLocation(mTempOffset.x, mTempOffset.y);
+ try {
+ return mCurrentRV.onTouchEvent(event);
+ } finally {
+ event.offsetLocation(-mTempOffset.x, -mTempOffset.y);
+ }
+ } else {
+ return super.onTouchEvent(event);
+ }
+ }
+
+ private void calcOffset(Point p) {
+ p.x = getLeft() - mCurrentRV.getLeft() - mParent.getLeft();
+ p.y = getTop() - mCurrentRV.getTop() - mParent.getTop();
+ }
+
+}
+
+
diff --git a/src/com/android/launcher3/views/SlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
similarity index 64%
rename from src/com/android/launcher3/views/SlidingTabStrip.java
rename to src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index c2ef41b..54948b0 100644
--- a/src/com/android/launcher3/views/SlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.views;
+package com.android.launcher3.allapps;
import android.content.Context;
import android.graphics.Canvas;
@@ -26,25 +26,39 @@
import android.widget.LinearLayout;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.util.Themes;
-public class SlidingTabStrip extends LinearLayout {
+/**
+ * Supports two indicator colors, dedicated for personal and work tabs.
+ */
+public class PersonalWorkSlidingTabStrip extends LinearLayout {
+ private final Paint mPersonalTabIndicatorPaint;
+ private final Paint mWorkTabIndicatorPaint;
- private final Paint mSelectedIndicatorPaint;
private int mSelectedIndicatorHeight;
private int mIndicatorLeft = -1;
private int mIndicatorRight = -1;
private int mSelectedPosition = 0;
private float mSelectionOffset;
+ private boolean mIsRtl;
- public SlidingTabStrip(@NonNull Context context, @Nullable AttributeSet attrs) {
+ public PersonalWorkSlidingTabStrip(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setOrientation(HORIZONTAL);
setWillNotDraw(false);
- mSelectedIndicatorPaint = new Paint();
- mSelectedIndicatorPaint.setColor(Themes.getAttrColor(context, android.R.attr.colorAccent));
- mSelectedIndicatorHeight = getResources()
- .getDimensionPixelSize(R.dimen.all_apps_tabs_indicator_height);
+
+ mSelectedIndicatorHeight =
+ getResources().getDimensionPixelSize(R.dimen.all_apps_tabs_indicator_height);
+
+ mPersonalTabIndicatorPaint = new Paint();
+ mPersonalTabIndicatorPaint.setColor(
+ Themes.getAttrColor(context, android.R.attr.colorAccent));
+
+ mWorkTabIndicatorPaint = new Paint();
+ mWorkTabIndicatorPaint.setColor(getResources().getColor(R.color.work_profile_color));
+
+ mIsRtl = Utilities.isRtl(getResources());
}
public void updateIndicatorPosition(int position, float positionOffset) {
@@ -54,7 +68,7 @@
}
public void updateTabTextColor(int pos) {
- for (int i=0; i < getChildCount(); i++) {
+ for (int i = 0; i < getChildCount(); i++) {
Button tab = (Button) getChildAt(i);
tab.setSelected(i == pos);
}
@@ -101,7 +115,20 @@
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
- canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
- mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
+
+ final float middleX = getWidth() / 2.0f;
+ if (mIndicatorLeft <= middleX) {
+ canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
+ middleX, getHeight(), getPaint(true /* firstHalf */));
+ }
+ if (mIndicatorRight > middleX) {
+ canvas.drawRect(middleX, getHeight() - mSelectedIndicatorHeight,
+ mIndicatorRight, getHeight(), getPaint(false /* firstHalf */));
+ }
}
-}
\ No newline at end of file
+
+ private Paint getPaint(boolean firstHalf) {
+ boolean isPersonal = mIsRtl ^ firstHalf;
+ return isPersonal ? mPersonalTabIndicatorPaint : mWorkTabIndicatorPaint;
+ }
+}
diff --git a/src/com/android/launcher3/allapps/PredictionRowView.java b/src/com/android/launcher3/allapps/PredictionRowView.java
index ea91770..1aee948 100644
--- a/src/com/android/launcher3/allapps/PredictionRowView.java
+++ b/src/com/android/launcher3/allapps/PredictionRowView.java
@@ -26,6 +26,7 @@
import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Launcher;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ComponentKeyMapper;
@@ -57,11 +58,28 @@
setOrientation(LinearLayout.HORIZONTAL);
}
- public void setup(AllAppsGridAdapter adapter,
- HashMap<ComponentKey, AppInfo> componentToAppMap, int numPredictedAppsPerRow) {
+ public void setup(AllAppsGridAdapter adapter, HashMap<ComponentKey, AppInfo> componentToAppMap,
+ int numPredictedAppsPerRow) {
mAdapter = adapter;
mComponentToAppMap = componentToAppMap;
mNumPredictedAppsPerRow = numPredictedAppsPerRow;
+ setVisibility(mPredictedAppComponents.isEmpty() ? View.GONE : View.VISIBLE);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getExpectedHeight(),
+ MeasureSpec.EXACTLY));
+ }
+
+ public int getExpectedHeight() {
+ int height = 0;
+ if (!mPredictedAppComponents.isEmpty()) {
+ height += Launcher.getLauncher(getContext())
+ .getDeviceProfile().allAppsCellHeightPx;
+ height += getPaddingTop() + getPaddingBottom();
+ }
+ return height;
}
/**
@@ -93,6 +111,7 @@
public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
mPredictedAppComponents.clear();
mPredictedAppComponents.addAll(apps);
+ mPredictedApps.clear();
mPredictedApps.addAll(processPredictedAppComponents(mPredictedAppComponents));
onAppsUpdated();
}
diff --git a/src/com/android/launcher3/anim/AnimationLayerSet.java b/src/com/android/launcher3/anim/AnimationLayerSet.java
deleted file mode 100644
index f0b3458..0000000
--- a/src/com/android/launcher3/anim/AnimationLayerSet.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 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.anim;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.util.ArrayMap;
-import android.view.View;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * Helper class to automatically build view hardware layers for the duration of an animation.
- */
-public class AnimationLayerSet extends AnimatorListenerAdapter {
-
- private final ArrayMap<View, Integer> mViewsToLayerTypeMap;
-
- public AnimationLayerSet() {
- mViewsToLayerTypeMap = new ArrayMap<>();
- }
-
- public AnimationLayerSet(View v) {
- mViewsToLayerTypeMap = new ArrayMap<>(1);
- addView(v);
- }
-
- public void addView(View v) {
- mViewsToLayerTypeMap.put(v, v.getLayerType());
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- // Enable all necessary layers
- Iterator<Map.Entry<View, Integer>> itr = mViewsToLayerTypeMap.entrySet().iterator();
- while (itr.hasNext()) {
- Map.Entry<View, Integer> entry = itr.next();
- View v = entry.getKey();
- entry.setValue(v.getLayerType());
- v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- if (v.isAttachedToWindow() && v.getVisibility() == View.VISIBLE) {
- v.buildLayer();
- }
- }
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- Iterator<Map.Entry<View, Integer>> itr = mViewsToLayerTypeMap.entrySet().iterator();
- while (itr.hasNext()) {
- Map.Entry<View, Integer> entry = itr.next();
- entry.getKey().setLayerType(entry.getValue(), null);
- }
- }
-}
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index 826a20e..6819386 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -45,12 +45,14 @@
private final long mDuration;
protected final AnimatorSet mAnim;
+ private AnimatorSet mOriginalTarget;
protected float mCurrentFraction;
private Runnable mEndAction;
protected AnimatorPlaybackController(AnimatorSet anim, long duration) {
mAnim = anim;
+ mOriginalTarget = mAnim;
mDuration = duration;
mAnimationPlayer = ValueAnimator.ofFloat(0, 1);
@@ -63,6 +65,25 @@
return mAnim;
}
+ public void setOriginalTarget(AnimatorSet anim) {
+ mOriginalTarget = anim;
+ }
+
+ public AnimatorSet getOriginalTarget() {
+ return mOriginalTarget;
+ }
+
+ public long getDuration() {
+ return mDuration;
+ }
+
+ public AnimatorPlaybackController cloneFor(AnimatorSet anim) {
+ AnimatorPlaybackController controller = AnimatorPlaybackController.wrap(anim, mDuration);
+ controller.setOriginalTarget(mOriginalTarget);
+ controller.setPlayFraction(mCurrentFraction);
+ return controller;
+ }
+
/**
* Starts playing the animation forward from current position.
*/
@@ -211,6 +232,6 @@
}
private static <T> List<T> nonNullList(ArrayList<T> list) {
- return list == null ? Collections.<T>emptyList() : list;
+ return list == null ? Collections.emptyList() : list;
}
}
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
new file mode 100644
index 0000000..63e67ff
--- /dev/null
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.anim;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+
+import com.android.launcher3.LauncherAnimUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Utility class for building animator set
+ */
+public class AnimatorSetBuilder {
+
+ protected final ArrayList<Animator> mAnims = new ArrayList<>();
+
+ /**
+ * Associates a tag with all the animations added after this call.
+ */
+ public void startTag(Object obj) { }
+
+ public void play(Animator anim) {
+ mAnims.add(anim);
+ }
+
+ public AnimatorSet build() {
+ AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+ anim.playTogether(mAnims);
+ return anim;
+ }
+}
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
new file mode 100644
index 0000000..0c78381
--- /dev/null
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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.compat;
+
+import android.content.Context;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+
+public class AccessibilityManagerCompat {
+
+ public static boolean isAccessibilityEnabled(Context context) {
+ return getManager(context).isEnabled();
+ }
+
+ public static boolean isObservedEventType(Context context, int eventType) {
+ // TODO: Use new API once available
+ return isAccessibilityEnabled(context);
+ }
+
+ public static void sendCustomAccessibilityEvent(View target, int type, String text) {
+ if (isObservedEventType(target.getContext(), type)) {
+ AccessibilityEvent event = AccessibilityEvent.obtain(type);
+ target.onInitializeAccessibilityEvent(event);
+ event.getText().add(text);
+ getManager(target.getContext()).sendAccessibilityEvent(event);
+ }
+ }
+
+ private static AccessibilityManager getManager(Context context) {
+ return (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ }
+}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 7cf3da0..0d92d45 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -60,7 +60,7 @@
public static final boolean GO_DISABLE_WIDGETS = false;
// When enabled shows a work profile tab in all apps
- public static final boolean ALL_APPS_TABS_ENABLED = false;
+ public static final boolean ALL_APPS_TABS_ENABLED = true;
// When enabled prediction row is rendered as it's own custom view
- public static final boolean ALL_APPS_PREDICTION_ROW_VIEW = false;
+ public static final boolean ALL_APPS_PREDICTION_ROW_VIEW = true;
}
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 9f9822c..27d6b89 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -16,6 +16,8 @@
package com.android.launcher3.dragndrop;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
@@ -45,7 +47,6 @@
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@@ -90,9 +91,6 @@
private final ViewGroupFocusHelper mFocusIndicatorHelper;
private final PageCutOutScrimDrawable mPageCutOutScrim;
- // Handles all apps pull up interaction
- private AllAppsTransitionController mAllAppsController;
-
protected TouchController[] mControllers;
private TouchController mActiveController;
/**
@@ -113,11 +111,9 @@
mPageCutOutScrim.setCallback(this);
}
- public void setup(Launcher launcher, DragController dragController,
- AllAppsTransitionController allAppsTransitionController) {
+ public void setup(Launcher launcher, DragController dragController) {
mLauncher = launcher;
mDragController = dragController;
- mAllAppsController = allAppsTransitionController;
mControllers = UiFactory.createTouchControllers(mLauncher);
}
@@ -156,12 +152,7 @@
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
- if (action == MotionEvent.ACTION_DOWN) {
- // Cancel discovery bounce animation when a user start interacting on anywhere on
- // dray layer even if mAllAppsController is NOT the active controller.
- // TODO: handle other input other than touch
- mAllAppsController.cancelDiscoveryAnimation();
- } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
mTouchCompleteListener.onTouchComplete();
}
@@ -233,7 +224,7 @@
private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
- Utilities.sendCustomAccessibilityEvent(
+ sendCustomAccessibilityEvent(
this, AccessibilityEvent.TYPE_VIEW_FOCUSED, getContext().getString(stringId));
}
@@ -800,6 +791,6 @@
}
public interface TouchCompleteListener {
- public void onTouchComplete();
+ void onTouchComplete();
}
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 2168001..b78e470 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -346,7 +347,7 @@
mFolderName.setHint(sDefaultFolderName.contentEquals(newTitle) ? sHintText : null);
- Utilities.sendCustomAccessibilityEvent(
+ sendCustomAccessibilityEvent(
this, AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
getContext().getString(R.string.folder_renamed, newTitle));
@@ -540,7 +541,7 @@
mFolderIcon.setBackgroundVisible(false);
mFolderIcon.drawLeaveBehindIfExists();
- Utilities.sendCustomAccessibilityEvent(
+ sendCustomAccessibilityEvent(
Folder.this,
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
mContent.getAccessibilityDescription());
@@ -654,7 +655,7 @@
}
@Override
public void onAnimationStart(Animator animation) {
- Utilities.sendCustomAccessibilityEvent(
+ sendCustomAccessibilityEvent(
Folder.this,
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
getContext().getString(R.string.folder_closed));
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 3dc58a1..a166dff 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -85,6 +85,7 @@
import java.util.Map;
import java.util.Set;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import static com.android.launcher3.notification.NotificationMainView.NOTIFICATION_ITEM_INFO;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
@@ -573,7 +574,7 @@
@Override
public void onAnimationEnd(Animator animation) {
mOpenCloseAnimator = null;
- Utilities.sendCustomAccessibilityEvent(
+ sendCustomAccessibilityEvent(
PopupContainerWithArrow.this,
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
getContext().getString(R.string.action_deep_shortcut));
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 1d90a08..995cdaa 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -35,7 +35,8 @@
public class SpringLoadedState extends LauncherState {
private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
- FLAG_DISABLE_ACCESSIBILITY | FLAG_DO_NOT_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED;
+ FLAG_DISABLE_ACCESSIBILITY | FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED |
+ FLAG_DISABLE_PAGE_CLIPPING;
// Determines how long to wait after a rotation before restoring the screen orientation to
// match the sensor state.
diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
index 351f88d..ff5f64c 100644
--- a/src/com/android/launcher3/touch/SwipeDetector.java
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -336,7 +336,7 @@
/**
* Returns the linear interpolation between two values
*/
- private static float interpolate(float from, float to, float alpha) {
+ public static float interpolate(float from, float to, float alpha) {
return (1.0f - alpha) * from + alpha * to;
}
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 8f20a8d..fc121d3 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -141,10 +141,11 @@
}
public void setRecyclerView(BaseRecyclerView rv, TextView popupView) {
- mRv = rv;
- if (mOnScrollListener != null) {
+ if (mRv != null && mOnScrollListener != null) {
mRv.removeOnScrollListener(mOnScrollListener);
}
+ mRv = rv;
+
mRv.addOnScrollListener(mOnScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
@@ -321,7 +322,7 @@
* Returns whether the specified point is inside the thumb bounds.
*/
private boolean isNearThumb(int x, int y) {
- int offset = y - mRv.getScrollBarTop() - mThumbOffsetY;
+ int offset = y - mThumbOffsetY;
return x >= 0 && x < getWidth() && offset >= 0 && offset <= mThumbHeight;
}
diff --git a/src/com/android/launcher3/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
similarity index 76%
copy from src/com/android/launcher3/states/AllAppsState.java
copy to src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
index ed3023a..bd5ddfe 100644
--- a/src/com/android/launcher3/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.states;
+package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
+import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN;
import android.view.View;
@@ -23,6 +24,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
@@ -30,8 +32,6 @@
*/
public class AllAppsState extends LauncherState {
- public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
-
private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
public AllAppsState(int id) {
@@ -57,4 +57,16 @@
public View getFinalFocus(Launcher launcher) {
return launcher.getAppsView();
}
+
+ @Override
+ public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
+ return new float[] { 1f,
+ -launcher.getAllAppsController().getShiftRange()
+ * AllAppsTransitionController.PARALLAX_COEFFICIENT};
+ }
+
+ @Override
+ public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
+ return (i) -> 0;
+ }
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
index 3ce1014..b23927b 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.WorkspaceStateTransitionAnimation.NO_ANIM_PROPERTY_SETTER;
-import android.animation.AnimatorSet;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -37,7 +36,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.WorkspaceStateTransitionAnimation.AnimatedPropertySetter;
import com.android.launcher3.WorkspaceStateTransitionAnimation.PropertySetter;
-import com.android.launcher3.anim.AnimationLayerSet;
+import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.widget.WidgetsFullSheet;
@@ -168,9 +167,9 @@
}
@Override
- public void setStateWithAnimation(LauncherState toState, AnimationLayerSet layerViews,
- AnimatorSet anim, AnimationConfig config) {
- setState(toState, new AnimatedPropertySetter(config.duration, layerViews, anim));
+ public void setStateWithAnimation(LauncherState toState,
+ AnimatorSetBuilder builder, AnimationConfig config) {
+ setState(toState, new AnimatedPropertySetter(config.duration, builder));
}
private void setState(LauncherState state, PropertySetter setter) {
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
index dcf7453..bcbe61c 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
@@ -16,7 +16,7 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
-import static com.android.launcher3.Utilities.isAccessibilityEnabled;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.graphics.Rect;
import android.view.View;
@@ -36,7 +36,8 @@
// The percent to shrink the workspace during overview mode
private static final float SCALE_FACTOR = 0.7f;
- private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE;
+ private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
+ FLAG_DISABLE_PAGE_CLIPPING;
public OverviewState(int id) {
super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, 1f, STATE_FLAGS);
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/PinchToOverviewListener.java b/src_ui_overrides/com/android/launcher3/uioverrides/PinchToOverviewListener.java
index 40bf057..a7c8cee 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/PinchToOverviewListener.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/PinchToOverviewListener.java
@@ -19,7 +19,7 @@
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.Utilities.isAccessibilityEnabled;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;