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 OnClickListener mOnClickListener; 51 ButtonSwitcher(Context context, AttributeSet attrs)52 public ButtonSwitcher(Context context, AttributeSet attrs) { 53 super(context, attrs); 54 } 55 ButtonSwitcher(Context context, AttributeSet attrs, int defStyle)56 public ButtonSwitcher(Context context, AttributeSet attrs, int defStyle) { 57 super(context, attrs, defStyle); 58 } 59 60 @Override onLayout(final boolean changed, final int left, final int top, final int right, final int bottom)61 protected void onLayout(final boolean changed, final int left, final int top, final int right, 62 final int bottom) { 63 super.onLayout(changed, left, top, right, bottom); 64 mInstallButton = (Button)findViewById(R.id.dict_install_button); 65 mCancelButton = (Button)findViewById(R.id.dict_cancel_button); 66 mDeleteButton = (Button)findViewById(R.id.dict_delete_button); 67 mInstallButton.setOnClickListener(mOnClickListener); 68 mCancelButton.setOnClickListener(mOnClickListener); 69 mDeleteButton.setOnClickListener(mOnClickListener); 70 setButtonPositionWithoutAnimation(mStatus); 71 if (mAnimateToStatus != NOT_INITIALIZED) { 72 // We have been asked to animate before we were ready, so we took a note of it. 73 // We are now ready: launch the animation. 74 animateButtonPosition(mStatus, mAnimateToStatus); 75 mStatus = mAnimateToStatus; 76 mAnimateToStatus = NOT_INITIALIZED; 77 } 78 } 79 getButton(final int status)80 private Button getButton(final int status) { 81 switch(status) { 82 case STATUS_INSTALL: 83 return mInstallButton; 84 case STATUS_CANCEL: 85 return mCancelButton; 86 case STATUS_DELETE: 87 return mDeleteButton; 88 default: 89 return null; 90 } 91 } 92 setStatusAndUpdateVisuals(final int status)93 public void setStatusAndUpdateVisuals(final int status) { 94 if (mStatus == NOT_INITIALIZED) { 95 setButtonPositionWithoutAnimation(status); 96 mStatus = status; 97 } else { 98 if (null == mInstallButton) { 99 // We may come here before we have been layout. In this case we don't know our 100 // size yet so we can't start animations so we need to remember what animation to 101 // start once layout has gone through. 102 mAnimateToStatus = status; 103 } else { 104 animateButtonPosition(mStatus, status); 105 mStatus = status; 106 } 107 } 108 } 109 setButtonPositionWithoutAnimation(final int status)110 private void setButtonPositionWithoutAnimation(final int status) { 111 // This may be called by setStatus() before the layout has come yet. 112 if (null == mInstallButton) return; 113 final int width = getWidth(); 114 // Set to out of the screen if that's not the currently displayed status 115 mInstallButton.setTranslationX(STATUS_INSTALL == status ? 0 : width); 116 mCancelButton.setTranslationX(STATUS_CANCEL == status ? 0 : width); 117 mDeleteButton.setTranslationX(STATUS_DELETE == status ? 0 : width); 118 } 119 animateButtonPosition(final int oldStatus, final int newStatus)120 private void animateButtonPosition(final int oldStatus, final int newStatus) { 121 final View oldButton = getButton(oldStatus); 122 final View newButton = getButton(newStatus); 123 if (null != oldButton && null != newButton) { 124 // Transition between two buttons : animate out, then in 125 animateButton(oldButton, ANIMATION_OUT).setListener( 126 new AnimatorListenerAdapter() { 127 @Override 128 public void onAnimationEnd(final Animator animation) { 129 if (newStatus != mStatus) return; 130 animateButton(newButton, ANIMATION_IN); 131 } 132 }); 133 } else if (null != oldButton) { 134 animateButton(oldButton, ANIMATION_OUT); 135 } else if (null != newButton) { 136 animateButton(newButton, ANIMATION_IN); 137 } 138 } 139 setInternalOnClickListener(final OnClickListener listener)140 public void setInternalOnClickListener(final OnClickListener listener) { 141 mOnClickListener = listener; 142 } 143 animateButton(final View button, final int direction)144 private ViewPropertyAnimator animateButton(final View button, final int direction) { 145 final float outerX = getWidth(); 146 final float innerX = button.getX() - button.getTranslationX(); 147 if (ANIMATION_IN == direction) { 148 button.setClickable(true); 149 return button.animate().translationX(0); 150 } else { 151 button.setClickable(false); 152 return button.animate().translationX(outerX - innerX); 153 } 154 } 155 } 156