blob: f7011f4d728d932988bd6344d38b057406ff5928 [file] [log] [blame]
// Copyright 2010-2014, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package org.mozc.android.inputmethod.japanese;
import com.google.common.annotations.VisibleForTesting;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
/**
* FrameLayout supporting animation when the view is shown or hidden.
*
*/
public abstract class InOutAnimatedFrameLayout extends FrameLayout {
private class OutAnimationAdapter implements AnimationListener {
private final AnimationListener baseListener;
OutAnimationAdapter(AnimationListener baseListener) {
this.baseListener = baseListener;
}
@Override
public void onAnimationEnd(Animation animation) {
if (baseListener != null) {
baseListener.onAnimationEnd(animation);
}
// We need to set this view's visibility to {@code GONE} *after* the out animation is
// finished. This listener handles it.
setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {
if (baseListener != null) {
baseListener.onAnimationRepeat(animation);
}
}
@Override
public void onAnimationStart(Animation animation) {
if (baseListener != null) {
baseListener.onAnimationStart(animation);
}
}
}
/**
* An event listener for visibility change.
*/
public interface VisibilityChangeListener {
public void onVisibilityChange();
}
/** Animation used when this view is shown. */
@VisibleForTesting Animation inAnimation;
/** Animation used when this view is hidden. */
@VisibleForTesting Animation outAnimation;
/** AnimationListener for in-animation. */
private AnimationListener inAnimationListener;
/** AnimationListener for out-animation. */
private AnimationListener outAnimationListener;
@VisibleForTesting VisibilityChangeListener onVisibilityChangeListener = null;
public InOutAnimatedFrameLayout(Context context) {
super(context);
}
public InOutAnimatedFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public InOutAnimatedFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setInAnimation(int resourceId) {
// Cancel the current "in animation".
inAnimation = loadAnimation(getContext(), resourceId);
setAnimationListenerInternal(inAnimation, inAnimationListener);
}
public void setInAnimation(Animation inAnimation) {
this.inAnimation = inAnimation;
setAnimationListenerInternal(inAnimation, inAnimationListener);
}
public void setOutAnimation(int resourceId) {
outAnimation = loadAnimation(getContext(), resourceId);
setAnimationListenerInternal(outAnimation, new OutAnimationAdapter(outAnimationListener));
}
public void setOutAnimation(Animation outAnimation) {
this.outAnimation = outAnimation;
setAnimationListenerInternal(outAnimation, new OutAnimationAdapter(outAnimationListener));
}
private static Animation loadAnimation(Context context, int resourceId) {
// Note: '0' is an invalid resource id.
if (context == null || resourceId == 0) {
return null;
}
return AnimationUtils.loadAnimation(context, resourceId);
}
public void setInAnimationListener(AnimationListener inAnimationListener) {
this.inAnimationListener = inAnimationListener;
setAnimationListenerInternal(inAnimation, inAnimationListener);
}
public void setOutAnimationListener(AnimationListener outAnimationListener) {
this.outAnimationListener = outAnimationListener;
setAnimationListenerInternal(outAnimation, new OutAnimationAdapter(outAnimationListener));
}
/**
* Registers {@code listener} to {@code animation} as its callback, iff both are non-null.
* Otherwise just do nothing.
*/
private static void setAnimationListenerInternal(
Animation animation, AnimationListener listener) {
if (animation != null && listener != null) {
animation.setAnimationListener(listener);
}
}
/**
* Starts animation to show this view. This method also controls the view's visibility.
*/
public void startInAnimation() {
if (inAnimation == null) {
// In case animation is not loaded, just set visibility.
clearAnimation();
setVisibility(View.VISIBLE);
return;
}
Animation oldAnimation = getAnimation();
if (getVisibility() != View.VISIBLE || (oldAnimation != null && oldAnimation != inAnimation)) {
setVisibility(View.VISIBLE);
startAnimation(inAnimation);
}
}
/**
* Starts animation to hide this view. This method also controls the view's visibility.
* In more precise, the visibility will be set to {@code GONE}, when the animation is finished.
*/
public void startOutAnimation() {
if (outAnimation == null) {
// In case animation is not loaded, just set visibility.
clearAnimation();
if (getVisibility() == View.VISIBLE) {
setVisibility(View.GONE);
}
return;
}
if (getVisibility() == View.VISIBLE && getAnimation() != outAnimation) {
startAnimation(outAnimation);
}
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (onVisibilityChangeListener != null) {
onVisibilityChangeListener.onVisibilityChange();
}
}
public void setOnVisibilityChangeListener(VisibilityChangeListener listner) {
onVisibilityChangeListener = listner;
}
}