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 ButtonSwitcher(Context context, AttributeSet attrs)53 public ButtonSwitcher(Context context, AttributeSet attrs) { 54 super(context, attrs); 55 } 56 ButtonSwitcher(Context context, AttributeSet attrs, int defStyle)57 public ButtonSwitcher(Context context, AttributeSet attrs, int defStyle) { 58 super(context, attrs, defStyle); 59 } 60 reset(final DictionaryListInterfaceState interfaceState)61 public void reset(final DictionaryListInterfaceState interfaceState) { 62 mStatus = NOT_INITIALIZED; 63 mAnimateToStatus = NOT_INITIALIZED; 64 mInterfaceState = interfaceState; 65 } 66 67 @Override onLayout(final boolean changed, final int left, final int top, final int right, final int bottom)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 getButton(final int status)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 setStatusAndUpdateVisuals(final int status)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 setButtonPositionWithoutAnimation(final int status)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}. animateButtonIfStatusIsEqual(final View newButton, final int newStatus)126 void animateButtonIfStatusIsEqual(final View newButton, final int newStatus) { 127 if (newStatus != mStatus) return; 128 animateButton(newButton, ANIMATION_IN); 129 } 130 animateButtonPosition(final int oldStatus, final int newStatus)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 setInternalOnClickListener(final OnClickListener listener)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 animateButton(final View button, final int direction)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