mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-19 02:38:20 +00:00
Merge "Updating gesture tutorial home animation" into ub-launcher3-rvc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
24ddf21cea
@@ -140,7 +140,6 @@ public class FallbackSwipeHandler extends
|
||||
|
||||
private final long mDuration;
|
||||
FallbackHomeAnimationFactory(long duration) {
|
||||
super(null);
|
||||
mDuration = duration;
|
||||
|
||||
if (mRunningOverHome) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.content.Context;
|
||||
@@ -28,6 +29,7 @@ import androidx.annotation.NonNull;
|
||||
import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.util.RectFSpringAnim;
|
||||
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
@@ -72,36 +74,39 @@ public class LauncherSwipeHandlerV2 extends
|
||||
mActivity.getRootView().setForceHideBackArrow(true);
|
||||
mActivity.setHintUserWillBeActive();
|
||||
|
||||
homeAnimFactory = new HomeAnimationFactory(floatingIconView) {
|
||||
|
||||
@Override
|
||||
public RectF getWindowTargetRect() {
|
||||
if (canUseWorkspaceView) {
|
||||
if (canUseWorkspaceView) {
|
||||
// We want the window alpha to be 0 once this threshold is met, so that the
|
||||
// FolderIconView can be seen morphing into the icon shape.
|
||||
float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
|
||||
homeAnimFactory = new LauncherHomeAnimationFactory() {
|
||||
@Override
|
||||
public RectF getWindowTargetRect() {
|
||||
return iconLocation;
|
||||
} else {
|
||||
return super.getWindowTargetRect();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||
// Return an empty APC here since we have an non-user controlled animation
|
||||
// to home.
|
||||
long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
|
||||
return mActivity.getStateManager().createAnimationToNewWorkspace(
|
||||
NORMAL, accuracy, 0 /* animComponents */);
|
||||
}
|
||||
@Override
|
||||
public void setAnimation(RectFSpringAnim anim) {
|
||||
anim.addAnimatorListener(floatingIconView);
|
||||
floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
|
||||
floatingIconView.setFastFinishRunnable(anim::end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playAtomicAnimation(float velocity) {
|
||||
new StaggeredWorkspaceAnim(mActivity, velocity,
|
||||
true /* animateOverviewScrim */).start();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void update(RectF currentRect, float progress, float radius) {
|
||||
floatingIconView.update(currentRect, 1f, progress, windowAlphaThreshold,
|
||||
radius, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
floatingIconView.fastFinish();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
homeAnimFactory = new LauncherHomeAnimationFactory();
|
||||
}
|
||||
} else {
|
||||
homeAnimFactory = new HomeAnimationFactory(null) {
|
||||
homeAnimFactory = new HomeAnimationFactory() {
|
||||
@Override
|
||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
|
||||
@@ -118,4 +123,22 @@ public class LauncherSwipeHandlerV2 extends
|
||||
mRecentsAnimationController.finish(
|
||||
true /* toRecents */, callback, true /* sendUserLeaveHint */);
|
||||
}
|
||||
|
||||
private class LauncherHomeAnimationFactory extends HomeAnimationFactory {
|
||||
@NonNull
|
||||
@Override
|
||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||
// Return an empty APC here since we have an non-user controlled animation
|
||||
// to home.
|
||||
long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
|
||||
return mActivity.getStateManager().createAnimationToNewWorkspace(
|
||||
NORMAL, accuracy, 0 /* animComponents */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playAtomicAnimation(float velocity) {
|
||||
new StaggeredWorkspaceAnim(mActivity, velocity,
|
||||
true /* animateOverviewScrim */).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.content.Context;
|
||||
@@ -28,7 +27,6 @@ import android.graphics.RectF;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
@@ -37,7 +35,6 @@ import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.util.RectFSpringAnim;
|
||||
import com.android.quickstep.util.TaskViewSimulator;
|
||||
import com.android.quickstep.util.TransformParams;
|
||||
@@ -148,12 +145,6 @@ public abstract class SwipeUpAnimationLogic {
|
||||
|
||||
protected abstract class HomeAnimationFactory {
|
||||
|
||||
public FloatingIconView mIconView;
|
||||
|
||||
public HomeAnimationFactory(@Nullable FloatingIconView iconView) {
|
||||
mIconView = iconView;
|
||||
}
|
||||
|
||||
public @NonNull RectF getWindowTargetRect() {
|
||||
PagedOrientationHandler orientationHandler = getOrientationHandler();
|
||||
DeviceProfile dp = mDp;
|
||||
@@ -174,6 +165,12 @@ public abstract class SwipeUpAnimationLogic {
|
||||
public void playAtomicAnimation(float velocity) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
public void setAnimation(RectFSpringAnim anim) { }
|
||||
|
||||
public void update(RectF currentRect, float progress, float radius) { }
|
||||
|
||||
public void onCancel() { }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,8 +181,6 @@ public abstract class SwipeUpAnimationLogic {
|
||||
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
|
||||
HomeAnimationFactory homeAnimationFactory) {
|
||||
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
|
||||
final FloatingIconView fiv = homeAnimationFactory.mIconView;
|
||||
final boolean isFloatingIconView = fiv != null;
|
||||
|
||||
mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor);
|
||||
mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress));
|
||||
@@ -203,11 +198,7 @@ public abstract class SwipeUpAnimationLogic {
|
||||
windowToHomePositionMap.mapRect(startRect);
|
||||
|
||||
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
|
||||
if (isFloatingIconView) {
|
||||
anim.addAnimatorListener(fiv);
|
||||
fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
|
||||
fiv.setFastFinishRunnable(anim::end);
|
||||
}
|
||||
homeAnimationFactory.setAnimation(anim);
|
||||
|
||||
SpringAnimationRunner runner = new SpringAnimationRunner(
|
||||
homeAnimationFactory, cropRectF, homeToWindowPositionMap);
|
||||
@@ -242,32 +233,27 @@ public abstract class SwipeUpAnimationLogic {
|
||||
|
||||
final RectF mWindowCurrentRect = new RectF();
|
||||
final Matrix mHomeToWindowPositionMap;
|
||||
final HomeAnimationFactory mAnimationFactory;
|
||||
|
||||
final FloatingIconView mFIV;
|
||||
final AnimatorPlaybackController mHomeAnim;
|
||||
final RectF mCropRectF;
|
||||
|
||||
final float mStartRadius;
|
||||
final float mEndRadius;
|
||||
final float mWindowAlphaThreshold;
|
||||
|
||||
SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF,
|
||||
Matrix homeToWindowPositionMap) {
|
||||
mAnimationFactory = factory;
|
||||
mHomeAnim = factory.createActivityAnimationToHome();
|
||||
mCropRectF = cropRectF;
|
||||
mHomeToWindowPositionMap = homeToWindowPositionMap;
|
||||
|
||||
cropRectF.roundOut(mCropRect);
|
||||
mFIV = factory.mIconView;
|
||||
|
||||
// End on a "round-enough" radius so that the shape reveal doesn't have to do too much
|
||||
// rounding at the end of the animation.
|
||||
mStartRadius = mTaskViewSimulator.getCurrentCornerRadius();
|
||||
mEndRadius = cropRectF.width() / 2f;
|
||||
|
||||
// We want the window alpha to be 0 once this threshold is met, so that the
|
||||
// FolderIconView can be seen morphing into the icon shape.
|
||||
mWindowAlphaThreshold = mFIV != null ? 1f - SHAPE_PROGRESS_DURATION : 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -282,10 +268,7 @@ public abstract class SwipeUpAnimationLogic {
|
||||
.setCornerRadius(cornerRadius);
|
||||
|
||||
mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
|
||||
if (mFIV != null) {
|
||||
mFIV.update(currentRect, 1f, progress,
|
||||
mWindowAlphaThreshold, mMatrix.mapRadius(cornerRadius), false);
|
||||
}
|
||||
mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -298,9 +281,7 @@ public abstract class SwipeUpAnimationLogic {
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
if (mFIV != null) {
|
||||
mFIV.fastFinish();
|
||||
}
|
||||
mAnimationFactory.onCancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
20
quickstep/res/drawable/bg_circle.xml
Normal file
20
quickstep/res/drawable/bg_circle.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 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.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#FFFFFFFF" />
|
||||
</shape>
|
||||
@@ -24,6 +24,14 @@
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/gesture_tutorial_ripple"/>
|
||||
|
||||
<com.android.launcher3.views.ClipIconView
|
||||
android:id="@+id/gesture_tutorial_fake_icon_view"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:background="@drawable/bg_circle"
|
||||
android:backgroundTint="@color/gesture_tutorial_fake_task_view_color"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<View
|
||||
android:id="@+id/gesture_tutorial_fake_task_view"
|
||||
android:layout_width="match_parent"
|
||||
@@ -41,81 +49,81 @@
|
||||
android:id="@+id/gesture_tutorial_fragment_close_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="18dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="@android:color/transparent"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_titles_container"
|
||||
android:background="@android:color/transparent"
|
||||
android:contentDescription="@string/gesture_tutorial_close_button_content_description"
|
||||
android:tint="?android:attr/textColorPrimary"
|
||||
android:src="@drawable/gesture_tutorial_close_button"/>
|
||||
android:padding="18dp"
|
||||
android:src="@drawable/gesture_tutorial_close_button"
|
||||
android:tint="?android:attr/textColorPrimary"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/gesture_tutorial_fragment_titles_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="70dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="70dp"
|
||||
android:focusable="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gesture_tutorial_fragment_title_view"
|
||||
style="@style/TextAppearance.GestureTutorial.Title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_title_margin_start_end"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_title_margin_start_end"
|
||||
style="@style/TextAppearance.GestureTutorial.Title"/>
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_title_margin_start_end"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gesture_tutorial_fragment_subtitle_view"
|
||||
style="@style/TextAppearance.GestureTutorial.Subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_subtitle_margin_start_end"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_subtitle_margin_start_end"
|
||||
style="@style/TextAppearance.GestureTutorial.Subtitle"/>
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_subtitle_margin_start_end"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gesture_tutorial_fragment_feedback_view"
|
||||
style="@style/TextAppearance.GestureTutorial.Feedback"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_above="@id/gesture_tutorial_fragment_action_button"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_feedback_margin_start_end"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_feedback_margin_start_end"
|
||||
style="@style/TextAppearance.GestureTutorial.Feedback"/>
|
||||
android:layout_marginBottom="10dp"/>
|
||||
|
||||
<!-- android:stateListAnimator="@null" removes shadow and normal on click behavior (increase
|
||||
of elevation and shadow) which is replaced by ripple effect in android:foreground -->
|
||||
<Button
|
||||
android:id="@+id/gesture_tutorial_fragment_action_button"
|
||||
style="@style/TextAppearance.GestureTutorial.ButtonLabel"
|
||||
android:layout_width="142dp"
|
||||
android:layout_height="49dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_button_margin_start_end"
|
||||
android:layout_marginBottom="48dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:stateListAnimator="@null"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_button_margin_start_end"
|
||||
android:layout_marginBottom="48dp"
|
||||
android:background="@drawable/gesture_tutorial_action_button_background"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
style="@style/TextAppearance.GestureTutorial.ButtonLabel"/>
|
||||
android:stateListAnimator="@null"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/gesture_tutorial_fragment_action_text_button"
|
||||
style="@style/TextAppearance.GestureTutorial.TextButtonLabel"
|
||||
android:layout_width="142dp"
|
||||
android:layout_height="49dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_button_margin_start_end"
|
||||
android:layout_marginBottom="48dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:stateListAnimator="@null"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_button_margin_start_end"
|
||||
android:layout_marginBottom="48dp"
|
||||
android:background="@null"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
style="@style/TextAppearance.GestureTutorial.TextButtonLabel"/>
|
||||
android:stateListAnimator="@null"/>
|
||||
</RelativeLayout>
|
||||
@@ -17,6 +17,7 @@ package com.android.quickstep.interaction;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
|
||||
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||
import static com.android.quickstep.BaseSwipeUpHandlerV2.MAX_SWIPE_DURATION;
|
||||
import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
|
||||
import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
|
||||
@@ -110,6 +111,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation, boolean isReverse) {
|
||||
mFakeIconView.setVisibility(View.INVISIBLE);
|
||||
mFakeTaskView.setVisibility(View.INVISIBLE);
|
||||
mFakeTaskView.setAlpha(1);
|
||||
mRunningWindowAnim = null;
|
||||
@@ -131,6 +133,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
});
|
||||
} else {
|
||||
anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
|
||||
anim.setViewAlpha(mFakeIconView, 0, ACCEL);
|
||||
anim.addListener(resetTaskView);
|
||||
}
|
||||
if (onEndRunnable != null) {
|
||||
@@ -202,7 +205,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
// derivative of the scroll interpolator at zero, ie. 2.
|
||||
long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
|
||||
long duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
|
||||
HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory(null) {
|
||||
HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory() {
|
||||
@Override
|
||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
|
||||
@@ -218,6 +221,24 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
fakeHomeIconLeft + fakeHomeIconSizePx,
|
||||
fakeHomeIconTop + fakeHomeIconSizePx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(RectF rect, float progress, float radius) {
|
||||
mFakeIconView.setVisibility(View.VISIBLE);
|
||||
mFakeIconView.update(rect, progress,
|
||||
1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
|
||||
radius,
|
||||
false, /* isOpening */
|
||||
mFakeIconView, mDp,
|
||||
false /* isVerticalBarLayout */);
|
||||
mFakeIconView.setAlpha(1);
|
||||
mFakeTaskView.setAlpha(getWindowAlpha(progress));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
mFakeIconView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
};
|
||||
RectFSpringAnim windowAnim = createWindowAnimationToHome(startShift, homeAnimFactory);
|
||||
windowAnim.start(mContext, velocityPxPerMs);
|
||||
|
||||
@@ -28,6 +28,7 @@ import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.views.ClipIconView;
|
||||
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureAttemptCallback;
|
||||
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureAttemptCallback;
|
||||
|
||||
@@ -46,6 +47,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
final TextView mTitleTextView;
|
||||
final TextView mSubtitleTextView;
|
||||
final TextView mFeedbackView;
|
||||
final ClipIconView mFakeIconView;
|
||||
final View mFakeTaskView;
|
||||
final View mRippleView;
|
||||
final RippleDrawable mRippleDrawable;
|
||||
@@ -66,6 +68,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
mTitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_title_view);
|
||||
mSubtitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_subtitle_view);
|
||||
mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view);
|
||||
mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
|
||||
mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
|
||||
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
|
||||
mRippleDrawable = (RippleDrawable) mRippleView.getBackground();
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.MarginLayoutParams;
|
||||
import android.view.ViewOutlineProvider;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -44,8 +45,6 @@ import androidx.dynamicanimation.animation.SpringAnimation;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.InsettableFrameLayout.LayoutParams;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
|
||||
@@ -94,7 +93,6 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
}
|
||||
};
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final int mBlurSizeOutline;
|
||||
private final boolean mIsRtl;
|
||||
|
||||
@@ -128,7 +126,6 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
|
||||
public ClipIconView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mLauncher = Launcher.getLauncher(context);
|
||||
mBlurSizeOutline = getResources().getDimensionPixelSize(
|
||||
R.dimen.blur_size_medium_outline);
|
||||
mIsRtl = Utilities.isRtl(getResources());
|
||||
@@ -143,10 +140,41 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
.setStiffness(SpringForce.STIFFNESS_LOW));
|
||||
}
|
||||
|
||||
void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
|
||||
boolean isOpening, float scale, float minSize, LayoutParams parentLp,
|
||||
boolean isVerticalBarLayout) {
|
||||
DeviceProfile dp = mLauncher.getDeviceProfile();
|
||||
/**
|
||||
* Update the icon UI to match the provided parameters during an animation frame
|
||||
*/
|
||||
public void update(RectF rect, float progress, float shapeProgressStart,
|
||||
float cornerRadius, boolean isOpening, View container,
|
||||
DeviceProfile dp, boolean isVerticalBarLayout) {
|
||||
|
||||
MarginLayoutParams lp = (MarginLayoutParams) container.getLayoutParams();
|
||||
|
||||
float dX = mIsRtl
|
||||
? rect.left - (dp.widthPx - lp.getMarginStart() - lp.width)
|
||||
: rect.left - lp.getMarginStart();
|
||||
float dY = rect.top - lp.topMargin;
|
||||
container.setTranslationX(dX);
|
||||
container.setTranslationY(dY);
|
||||
|
||||
float minSize = Math.min(lp.width, lp.height);
|
||||
float scaleX = rect.width() / minSize;
|
||||
float scaleY = rect.height() / minSize;
|
||||
float scale = Math.max(1f, Math.min(scaleX, scaleY));
|
||||
|
||||
update(rect, progress, shapeProgressStart, cornerRadius, isOpening, scale,
|
||||
minSize, lp, isVerticalBarLayout, dp);
|
||||
|
||||
container.setPivotX(0);
|
||||
container.setPivotY(0);
|
||||
container.setScaleX(scale);
|
||||
container.setScaleY(scale);
|
||||
|
||||
container.invalidate();
|
||||
}
|
||||
|
||||
private void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
|
||||
boolean isOpening, float scale, float minSize, MarginLayoutParams parentLp,
|
||||
boolean isVerticalBarLayout, DeviceProfile dp) {
|
||||
float dX = mIsRtl
|
||||
? rect.left - (dp.widthPx - parentLp.getMarginStart() - parentLp.width)
|
||||
: rect.left - parentLp.getMarginStart();
|
||||
@@ -228,8 +256,11 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
}
|
||||
}
|
||||
|
||||
void setIcon(@Nullable Drawable drawable, int iconOffset, LayoutParams lp, boolean isOpening,
|
||||
boolean isVerticalBarLayout) {
|
||||
/**
|
||||
* Sets the icon for this view as part of initial setup
|
||||
*/
|
||||
public void setIcon(@Nullable Drawable drawable, int iconOffset, MarginLayoutParams lp,
|
||||
boolean isOpening, boolean isVerticalBarLayout, DeviceProfile dp) {
|
||||
mIsAdaptiveIcon = drawable instanceof AdaptiveIconDrawable;
|
||||
if (mIsAdaptiveIcon) {
|
||||
boolean isFolderIcon = drawable instanceof FolderAdaptiveIcon;
|
||||
@@ -264,15 +295,14 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
Utilities.scaleRectAboutCenter(mStartRevealRect, IconShape.getNormalizationScale());
|
||||
}
|
||||
|
||||
float aspectRatio = mLauncher.getDeviceProfile().aspectRatio;
|
||||
if (isVerticalBarLayout) {
|
||||
lp.width = (int) Math.max(lp.width, lp.height * aspectRatio);
|
||||
lp.width = (int) Math.max(lp.width, lp.height * dp.aspectRatio);
|
||||
} else {
|
||||
lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
|
||||
lp.height = (int) Math.max(lp.height, lp.width * dp.aspectRatio);
|
||||
}
|
||||
|
||||
int left = mIsRtl
|
||||
? mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width
|
||||
? dp.widthPx - lp.getMarginStart() - lp.width
|
||||
: lp.leftMargin;
|
||||
layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import static com.android.launcher3.Utilities.getBadge;
|
||||
import static com.android.launcher3.Utilities.getFullDrawable;
|
||||
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -47,7 +48,6 @@ import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.InsettableFrameLayout;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
@@ -144,32 +144,8 @@ public class FloatingIconView extends FrameLayout implements
|
||||
public void update(RectF rect, float alpha, float progress, float shapeProgressStart,
|
||||
float cornerRadius, boolean isOpening) {
|
||||
setAlpha(alpha);
|
||||
|
||||
InsettableFrameLayout.LayoutParams lp =
|
||||
(InsettableFrameLayout.LayoutParams) getLayoutParams();
|
||||
|
||||
DeviceProfile dp = mLauncher.getDeviceProfile();
|
||||
float dX = mIsRtl
|
||||
? rect.left - (dp.widthPx - lp.getMarginStart() - lp.width)
|
||||
: rect.left - lp.getMarginStart();
|
||||
float dY = rect.top - lp.topMargin;
|
||||
setTranslationX(dX);
|
||||
setTranslationY(dY);
|
||||
|
||||
float minSize = Math.min(lp.width, lp.height);
|
||||
float scaleX = rect.width() / minSize;
|
||||
float scaleY = rect.height() / minSize;
|
||||
float scale = Math.max(1f, Math.min(scaleX, scaleY));
|
||||
|
||||
mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, isOpening, scale,
|
||||
minSize, lp, mIsVerticalBarLayout);
|
||||
|
||||
setPivotX(0);
|
||||
setPivotY(0);
|
||||
setScaleX(scale);
|
||||
setScaleY(scale);
|
||||
|
||||
invalidate();
|
||||
mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, isOpening,
|
||||
this, mLauncher.getDeviceProfile(), mIsVerticalBarLayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -336,7 +312,8 @@ public class FloatingIconView extends FrameLayout implements
|
||||
final InsettableFrameLayout.LayoutParams lp =
|
||||
(InsettableFrameLayout.LayoutParams) getLayoutParams();
|
||||
mBadge = badge;
|
||||
mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening, mIsVerticalBarLayout);
|
||||
mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening, mIsVerticalBarLayout,
|
||||
mLauncher.getDeviceProfile());
|
||||
if (drawable instanceof AdaptiveIconDrawable) {
|
||||
final int originalHeight = lp.height;
|
||||
final int originalWidth = lp.width;
|
||||
@@ -381,7 +358,7 @@ public class FloatingIconView extends FrameLayout implements
|
||||
if (mIconLoadResult.isIconLoaded) {
|
||||
setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
|
||||
mIconLoadResult.iconOffset);
|
||||
hideOriginalView(originalView);
|
||||
setIconAndDotVisible(originalView, false);
|
||||
} else {
|
||||
mIconLoadResult.onIconLoaded = () -> {
|
||||
if (cancellationSignal.isCanceled()) {
|
||||
@@ -392,22 +369,13 @@ public class FloatingIconView extends FrameLayout implements
|
||||
mIconLoadResult.iconOffset);
|
||||
|
||||
setVisibility(VISIBLE);
|
||||
hideOriginalView(originalView);
|
||||
setIconAndDotVisible(originalView, false);
|
||||
};
|
||||
mLoadIconSignal = cancellationSignal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void hideOriginalView(View originalView) {
|
||||
if (originalView instanceof IconLabelDotView) {
|
||||
((IconLabelDotView) originalView).setIconVisible(false);
|
||||
((IconLabelDotView) originalView).setForceHideDot(true);
|
||||
} else {
|
||||
originalView.setVisibility(INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@SuppressWarnings("WrongThread")
|
||||
private static int getOffsetForIconBounds(Launcher l, Drawable drawable, RectF position) {
|
||||
@@ -477,7 +445,7 @@ public class FloatingIconView extends FrameLayout implements
|
||||
}
|
||||
if (!mIsOpening) {
|
||||
// When closing an app, we want the item on the workspace to be invisible immediately
|
||||
hideOriginalView(mOriginalIcon);
|
||||
setIconAndDotVisible(mOriginalIcon, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,12 +541,7 @@ public class FloatingIconView extends FrameLayout implements
|
||||
|
||||
if (hideOriginal) {
|
||||
if (isOpening) {
|
||||
if (originalView instanceof BubbleTextView) {
|
||||
((BubbleTextView) originalView).setIconVisible(true);
|
||||
((BubbleTextView) originalView).setForceHideDot(false);
|
||||
} else {
|
||||
originalView.setVisibility(VISIBLE);
|
||||
}
|
||||
setIconAndDotVisible(originalView, true);
|
||||
view.finish(dragLayer);
|
||||
} else {
|
||||
view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer);
|
||||
@@ -615,12 +578,10 @@ public class FloatingIconView extends FrameLayout implements
|
||||
});
|
||||
|
||||
if (originalView instanceof IconLabelDotView) {
|
||||
IconLabelDotView view = (IconLabelDotView) originalView;
|
||||
fade.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
view.setIconVisible(true);
|
||||
view.setForceHideDot(false);
|
||||
setIconAndDotVisible(originalView, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,10 +15,24 @@
|
||||
*/
|
||||
package com.android.launcher3.views;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* A view that has an icon, label, and notification dot.
|
||||
*/
|
||||
public interface IconLabelDotView {
|
||||
void setIconVisible(boolean visible);
|
||||
void setForceHideDot(boolean hide);
|
||||
|
||||
/**
|
||||
* Sets the visibility of icon and dot of the view
|
||||
*/
|
||||
static void setIconAndDotVisible(View view, boolean visible) {
|
||||
if (view instanceof IconLabelDotView) {
|
||||
((IconLabelDotView) view).setIconVisible(visible);
|
||||
((IconLabelDotView) view).setForceHideDot(!visible);
|
||||
} else {
|
||||
view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user