Home | History | Annotate | Download | only in dictionarypack
      1 /**
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy
      6  * of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations
     14  * under the License.
     15  */
     16 
     17 package com.android.inputmethod.dictionarypack;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.content.Context;
     22 import android.util.AttributeSet;
     23 import android.view.View;
     24 import android.view.ViewPropertyAnimator;
     25 import android.widget.Button;
     26 import android.widget.FrameLayout;
     27 
     28 import com.android.inputmethod.latin.R;
     29 
     30 /**
     31  * A view that handles buttons inside it according to a status.
     32  */
     33 public class ButtonSwitcher extends FrameLayout {
     34     public static final int NOT_INITIALIZED = -1;
     35     public static final int STATUS_NO_BUTTON = 0;
     36     public static final int STATUS_INSTALL = 1;
     37     public static final int STATUS_CANCEL = 2;
     38     public static final int STATUS_DELETE = 3;
     39     // One of the above
     40     private int mStatus = NOT_INITIALIZED;
     41     private int mAnimateToStatus = NOT_INITIALIZED;
     42 
     43     // Animation directions
     44     public static final int ANIMATION_IN = 1;
     45     public static final int ANIMATION_OUT = 2;
     46 
     47     private Button mInstallButton;
     48     private Button mCancelButton;
     49     private Button mDeleteButton;
     50     private DictionaryListInterfaceState mInterfaceState;
     51     private OnClickListener mOnClickListener;
     52 
     53     public ButtonSwitcher(Context context, AttributeSet attrs) {
     54         super(context, attrs);
     55     }
     56 
     57     public ButtonSwitcher(Context context, AttributeSet attrs, int defStyle) {
     58         super(context, attrs, defStyle);
     59     }
     60 
     61     public void reset(final DictionaryListInterfaceState interfaceState) {
     62         mStatus = NOT_INITIALIZED;
     63         mAnimateToStatus = NOT_INITIALIZED;
     64         mInterfaceState = interfaceState;
     65     }
     66 
     67     @Override
     68     protected void onLayout(final boolean changed, final int left, final int top, final int right,
     69             final int bottom) {
     70         super.onLayout(changed, left, top, right, bottom);
     71         mInstallButton = (Button)findViewById(R.id.dict_install_button);
     72         mCancelButton = (Button)findViewById(R.id.dict_cancel_button);
     73         mDeleteButton = (Button)findViewById(R.id.dict_delete_button);
     74         setInternalOnClickListener(mOnClickListener);
     75         setButtonPositionWithoutAnimation(mStatus);
     76         if (mAnimateToStatus != NOT_INITIALIZED) {
     77             // We have been asked to animate before we were ready, so we took a note of it.
     78             // We are now ready: launch the animation.
     79             animateButtonPosition(mStatus, mAnimateToStatus);
     80             mStatus = mAnimateToStatus;
     81             mAnimateToStatus = NOT_INITIALIZED;
     82         }
     83     }
     84 
     85     private Button getButton(final int status) {
     86         switch(status) {
     87         case STATUS_INSTALL:
     88             return mInstallButton;
     89         case STATUS_CANCEL:
     90             return mCancelButton;
     91         case STATUS_DELETE:
     92             return mDeleteButton;
     93         default:
     94             return null;
     95         }
     96     }
     97 
     98     public void setStatusAndUpdateVisuals(final int status) {
     99         if (mStatus == NOT_INITIALIZED) {
    100             setButtonPositionWithoutAnimation(status);
    101             mStatus = status;
    102         } else {
    103             if (null == mInstallButton) {
    104                 // We may come here before we have been layout. In this case we don't know our
    105                 // size yet so we can't start animations so we need to remember what animation to
    106                 // start once layout has gone through.
    107                 mAnimateToStatus = status;
    108             } else {
    109                 animateButtonPosition(mStatus, status);
    110                 mStatus = status;
    111             }
    112         }
    113     }
    114 
    115     private void setButtonPositionWithoutAnimation(final int status) {
    116         // This may be called by setStatus() before the layout has come yet.
    117         if (null == mInstallButton) return;
    118         final int width = getWidth();
    119         // Set to out of the screen if that's not the currently displayed status
    120         mInstallButton.setTranslationX(STATUS_INSTALL == status ? 0 : width);
    121         mCancelButton.setTranslationX(STATUS_CANCEL == status ? 0 : width);
    122         mDeleteButton.setTranslationX(STATUS_DELETE == status ? 0 : width);
    123     }
    124 
    125     // The helper method for {@link AnimatorListenerAdapter}.
    126     void animateButtonIfStatusIsEqual(final View newButton, final int newStatus) {
    127         if (newStatus != mStatus) return;
    128         animateButton(newButton, ANIMATION_IN);
    129     }
    130 
    131     private void animateButtonPosition(final int oldStatus, final int newStatus) {
    132         final View oldButton = getButton(oldStatus);
    133         final View newButton = getButton(newStatus);
    134         if (null != oldButton && null != newButton) {
    135             // Transition between two buttons : animate out, then in
    136             animateButton(oldButton, ANIMATION_OUT).setListener(new AnimatorListenerAdapter() {
    137                 @Override
    138                 public void onAnimationEnd(final Animator animation) {
    139                     animateButtonIfStatusIsEqual(newButton, newStatus);
    140                 }
    141             });
    142         } else if (null != oldButton) {
    143             animateButton(oldButton, ANIMATION_OUT);
    144         } else if (null != newButton) {
    145             animateButton(newButton, ANIMATION_IN);
    146         }
    147     }
    148 
    149     public void setInternalOnClickListener(final OnClickListener listener) {
    150         mOnClickListener = listener;
    151         if (null != mInstallButton) {
    152             // Already laid out : do it now
    153             mInstallButton.setOnClickListener(mOnClickListener);
    154             mCancelButton.setOnClickListener(mOnClickListener);
    155             mDeleteButton.setOnClickListener(mOnClickListener);
    156         }
    157     }
    158 
    159     private ViewPropertyAnimator animateButton(final View button, final int direction) {
    160         final float outerX = getWidth();
    161         final float innerX = button.getX() - button.getTranslationX();
    162         mInterfaceState.removeFromCache((View)getParent());
    163         if (ANIMATION_IN == direction) {
    164             button.setClickable(true);
    165             return button.animate().translationX(0);
    166         }
    167         button.setClickable(false);
    168         return button.animate().translationX(outerX - innerX);
    169     }
    170 }
    171