blob: 0f44587d989eebc1fe67a9527120fa714d36026f [file] [log] [blame]
/*
* 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.wallpaper.picker.individual;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnHoverListener;
import android.widget.ImageView;
import com.android.wallpaper.R;
/**
* Implementation of {@code SelectionAnimator} which uses a checkmark and inset around the tile to
* indicate a selected state.
*/
public class CheckmarkSelectionAnimator implements SelectionAnimator {
private static final int HOVER_TIMEOUT_MS = 200;
private static final float HOVER_CHECK_CIRCLE_OPACITY = 0.67f;
private Context mAppContext;
private View mTile;
private ImageView mCheckCircle;
private View mLoadingIndicatorContainer;
private boolean mIsSelected;
private boolean mIsHovered;
private Handler mHoverHandler;
private Runnable mHoverEnterRunnable = new Runnable() {
@Override
public void run() {
mIsHovered = true;
mCheckCircle.setImageDrawable(mAppContext.getDrawable(
R.drawable.material_ic_check_circle_white_24));
mCheckCircle.setVisibility(View.VISIBLE);
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(
mCheckCircle, "alpha", 0f, HOVER_CHECK_CIRCLE_OPACITY);
alphaAnimator.start();
alphaAnimator.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
mIsHovered = true;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
};
private Runnable mHoverExitRunnable = new Runnable() {
@Override
public void run() {
mIsHovered = false;
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(
mCheckCircle, "alpha", HOVER_CHECK_CIRCLE_OPACITY, 0f);
alphaAnimator.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
mCheckCircle.setVisibility(View.GONE);
mIsHovered = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
alphaAnimator.start();
}
};
public CheckmarkSelectionAnimator(Context appContext, View itemView) {
mAppContext = appContext;
mTile = itemView.findViewById(R.id.tile);
mCheckCircle = (ImageView) itemView.findViewById(R.id.check_circle);
mLoadingIndicatorContainer = itemView.findViewById(R.id.loading_indicator_container);
mHoverHandler = new Handler();
mTile.setOnHoverListener(new OnHoverListener() {
@Override
public boolean onHover(View v, MotionEvent event) {
// If this ViewHolder is already selected, then don't change the state of the check circle.
if (mIsSelected) {
return false;
}
int actionMasked = event.getActionMasked();
switch (actionMasked) {
case MotionEvent.ACTION_HOVER_ENTER:
animateHoverEnter();
break;
case MotionEvent.ACTION_HOVER_EXIT:
animateHoverExit();
break;
default:
// fall out
}
return false;
}
});
}
@Override
public void selectImmediately() {
mIsSelected = true;
int insetPx = mAppContext.getResources().getDimensionPixelSize(
R.dimen.grid_item_individual_wallpaper_selected_inset);
mTile.setPadding(insetPx, insetPx, insetPx, insetPx);
mCheckCircle.setImageDrawable(mAppContext.getDrawable(R.drawable.check_circle_blue));
mCheckCircle.setVisibility(View.VISIBLE);
mCheckCircle.setAlpha(1f);
mLoadingIndicatorContainer.setVisibility(View.GONE);
}
@Override
public void deselectImmediately() {
mIsSelected = false;
mCheckCircle.setAlpha(0f);
mCheckCircle.setVisibility(View.GONE);
mTile.setPadding(0, 0, 0, 0);
mLoadingIndicatorContainer.setVisibility(View.GONE);
}
@Override
public void animateSelected() {
// If already selected, do nothing.
if (mIsSelected) {
return;
}
mLoadingIndicatorContainer.setVisibility(View.GONE);
int[][] values = new int[2][4];
values[0] = new int[]{0, 0, 0, 0};
int insetPx = mAppContext.getResources().getDimensionPixelSize(
R.dimen.grid_item_individual_wallpaper_selected_inset);
values[1] = new int[]{insetPx, insetPx, insetPx, insetPx};
ObjectAnimator paddingAnimator = ObjectAnimator.ofMultiInt(mTile, "padding", values);
ObjectAnimator checkCircleAlphaAnimator = ObjectAnimator.ofFloat(mCheckCircle, "alpha", 0f, 1f);
mCheckCircle.setImageDrawable(mAppContext.getDrawable(R.drawable.check_circle_blue));
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(paddingAnimator, checkCircleAlphaAnimator);
animatorSet.setDuration(200);
animatorSet.start();
mCheckCircle.setVisibility(View.VISIBLE);
mIsSelected = true;
}
@Override
public void animateDeselected() {
mLoadingIndicatorContainer.setVisibility(View.GONE);
// If already deselected, do nothing.
if (!mIsSelected) {
return;
}
int[][] values = new int[2][4];
int insetPx = mAppContext.getResources().getDimensionPixelSize(
R.dimen.grid_item_individual_wallpaper_selected_inset);
values[0] = new int[]{insetPx, insetPx, insetPx, insetPx};
values[1] = new int[]{0, 0, 0, 0};
ObjectAnimator paddingAnimator = ObjectAnimator.ofMultiInt(mTile, "padding", values);
ObjectAnimator checkCircleAlphaAnimator = ObjectAnimator.ofFloat(mCheckCircle, "alpha", 1f, 0f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(paddingAnimator, checkCircleAlphaAnimator);
animatorSet.setDuration(200);
animatorSet.start();
checkCircleAlphaAnimator.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
mCheckCircle.setVisibility(View.GONE);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mIsSelected = false;
}
@Override
public void showLoading() {
mLoadingIndicatorContainer.setVisibility(View.VISIBLE);
}
@Override
public void showNotLoading() {
mLoadingIndicatorContainer.setVisibility(View.GONE);
}
private void animateHoverEnter() {
removeHoverHandlerCallbacks();
if (mIsHovered) {
return;
}
mHoverHandler.postDelayed(mHoverEnterRunnable, HOVER_TIMEOUT_MS);
}
private void animateHoverExit() {
removeHoverHandlerCallbacks();
if (!mIsHovered) {
return;
}
mHoverHandler.postDelayed(mHoverExitRunnable, HOVER_TIMEOUT_MS);
}
@Override
public boolean isSelected() {
return mIsSelected;
}
private void removeHoverHandlerCallbacks() {
mHoverHandler.removeCallbacks(mHoverEnterRunnable);
mHoverHandler.removeCallbacks(mHoverExitRunnable);
}
}