blob: 7f4e784457590399959cd3cd9b9177818b80aa45 [file] [log] [blame]
/*
* Copyright (C) 2022 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.systemui.accessibility.floatingmenu;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.view.MotionEvent;
import androidx.annotation.NonNull;
import androidx.dynamicanimation.animation.DynamicAnimation;
import com.android.systemui.R;
import com.android.wm.shell.bubbles.DismissView;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
/**
* Controls the interaction between {@link MagnetizedObject} and
* {@link MagnetizedObject.MagneticTarget}.
*/
class DismissAnimationController {
private static final boolean ENABLE_FLING_TO_DISMISS_MENU = false;
private static final float COMPLETELY_OPAQUE = 1.0f;
private static final float COMPLETELY_TRANSPARENT = 0.0f;
private static final float CIRCLE_VIEW_DEFAULT_SCALE = 1.0f;
private static final float ANIMATING_MAX_ALPHA = 0.7f;
private final DismissView mDismissView;
private final MenuView mMenuView;
private final ValueAnimator mDismissAnimator;
private final MagnetizedObject<?> mMagnetizedObject;
private float mMinDismissSize;
private float mSizePercent;
DismissAnimationController(DismissView dismissView, MenuView menuView) {
mDismissView = dismissView;
mDismissView.setPivotX(dismissView.getWidth() / 2.0f);
mDismissView.setPivotY(dismissView.getHeight() / 2.0f);
mMenuView = menuView;
updateResources();
mDismissAnimator = ValueAnimator.ofFloat(COMPLETELY_OPAQUE, COMPLETELY_TRANSPARENT);
mDismissAnimator.addUpdateListener(dismissAnimation -> {
final float animatedValue = (float) dismissAnimation.getAnimatedValue();
final float scaleValue = Math.max(animatedValue, mSizePercent);
dismissView.getCircle().setScaleX(scaleValue);
dismissView.getCircle().setScaleY(scaleValue);
menuView.setAlpha(Math.max(animatedValue, ANIMATING_MAX_ALPHA));
});
mDismissAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
super.onAnimationEnd(animation, isReverse);
if (isReverse) {
mDismissView.getCircle().setScaleX(CIRCLE_VIEW_DEFAULT_SCALE);
mDismissView.getCircle().setScaleY(CIRCLE_VIEW_DEFAULT_SCALE);
mMenuView.setAlpha(COMPLETELY_OPAQUE);
}
}
});
mMagnetizedObject =
new MagnetizedObject<MenuView>(mMenuView.getContext(), mMenuView,
new MenuAnimationController.MenuPositionProperty(
DynamicAnimation.TRANSLATION_X),
new MenuAnimationController.MenuPositionProperty(
DynamicAnimation.TRANSLATION_Y)) {
@Override
public void getLocationOnScreen(MenuView underlyingObject, int[] loc) {
underlyingObject.getLocationOnScreen(loc);
}
@Override
public float getHeight(MenuView underlyingObject) {
return underlyingObject.getHeight();
}
@Override
public float getWidth(MenuView underlyingObject) {
return underlyingObject.getWidth();
}
};
final MagnetizedObject.MagneticTarget magneticTarget = new MagnetizedObject.MagneticTarget(
dismissView.getCircle(), (int) mMinDismissSize);
mMagnetizedObject.addTarget(magneticTarget);
mMagnetizedObject.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_MENU);
}
void showDismissView(boolean show) {
if (show) {
mDismissView.show();
} else {
mDismissView.hide();
}
}
void setMagnetListener(MagnetizedObject.MagnetListener magnetListener) {
mMagnetizedObject.setMagnetListener(magnetListener);
}
void maybeConsumeDownMotionEvent(MotionEvent event) {
mMagnetizedObject.maybeConsumeMotionEvent(event);
}
/**
* This used to pass {@link MotionEvent#ACTION_DOWN} to the magnetized object to check if it was
* within the magnetic field. It should be used in the {@link MenuListViewTouchHandler}.
*
* @param event that move the magnetized object which is also the menu list view.
* @return true if the location of the motion events moves within the magnetic field of a
* target, but false if didn't set
* {@link DismissAnimationController#setMagnetListener(MagnetizedObject.MagnetListener)}.
*/
boolean maybeConsumeMoveMotionEvent(MotionEvent event) {
return mMagnetizedObject.maybeConsumeMotionEvent(event);
}
/**
* This used to pass {@link MotionEvent#ACTION_UP} to the magnetized object to check if it was
* within the magnetic field. It should be used in the {@link MenuListViewTouchHandler}.
*
* @param event that move the magnetized object which is also the menu list view.
* @return true if the location of the motion events moves within the magnetic field of a
* target, but false if didn't set
* {@link DismissAnimationController#setMagnetListener(MagnetizedObject.MagnetListener)}.
*/
boolean maybeConsumeUpMotionEvent(MotionEvent event) {
return mMagnetizedObject.maybeConsumeMotionEvent(event);
}
void animateDismissMenu(boolean scaleUp) {
if (scaleUp) {
mDismissAnimator.start();
} else {
mDismissAnimator.reverse();
}
}
void updateResources() {
final float maxDismissSize = mDismissView.getResources().getDimensionPixelSize(
R.dimen.dismiss_circle_size);
mMinDismissSize = mDismissView.getResources().getDimensionPixelSize(
R.dimen.dismiss_circle_small);
mSizePercent = mMinDismissSize / maxDismissSize;
}
interface DismissCallback {
void onDismiss();
}
}