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 animateButtonPosition(final int oldStatus, final int newStatus)125 private void animateButtonPosition(final int oldStatus, final int newStatus) { 126 final View oldButton = getButton(oldStatus); 127 final View newButton = getButton(newStatus); 128 if (null != oldButton && null != newButton) { 129 // Transition between two buttons : animate out, then in 130 animateButton(oldButton, ANIMATION_OUT).setListener( 131 new AnimatorListenerAdapter() { 132 @Override 133 public void onAnimationEnd(final Animator animation) { 134 if (newStatus != mStatus) return; 135 animateButton(newButton, ANIMATION_IN); 136 } 137 }); 138 } else if (null != oldButton) { 139 animateButton(oldButton, ANIMATION_OUT); 140 } else if (null != newButton) { 141 animateButton(newButton, ANIMATION_IN); 142 } 143 } 144 setInternalOnClickListener(final OnClickListener listener)145 public void setInternalOnClickListener(final OnClickListener listener) { 146 mOnClickListener = listener; 147 if (null != mInstallButton) { 148 // Already laid out : do it now 149 mInstallButton.setOnClickListener(mOnClickListener); 150 mCancelButton.setOnClickListener(mOnClickListener); 151 mDeleteButton.setOnClickListener(mOnClickListener); 152 } 153 } 154 animateButton(final View button, final int direction)155 private ViewPropertyAnimator animateButton(final View button, final int direction) { 156 final float outerX = getWidth(); 157 final float innerX = button.getX() - button.getTranslationX(); 158 mInterfaceState.removeFromCache((View)getParent()); 159 if (ANIMATION_IN == direction) { 160 button.setClickable(true); 161 return button.animate().translationX(0); 162 } else { 163 button.setClickable(false); 164 return button.animate().translationX(outerX - innerX); 165 } 166 } 167 } 168