12cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard/** 22cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * Copyright (C) 2013 The Android Open Source Project 32cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * 42cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * Licensed under the Apache License, Version 2.0 (the "License"); you may not 52cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * use this file except in compliance with the License. You may obtain a copy 62cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * of the License at 72cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * 82cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * http://www.apache.org/licenses/LICENSE-2.0 92cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * 102cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * Unless required by applicable law or agreed to in writing, software 112cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 122cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 132cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * License for the specific language governing permissions and limitations 142cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * under the License. 152cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard */ 162cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard 172cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalardpackage com.android.inputmethod.dictionarypack; 182cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard 19513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalardimport android.animation.Animator; 20513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalardimport android.animation.AnimatorListenerAdapter; 212cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalardimport android.content.Context; 222cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalardimport android.util.AttributeSet; 232cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalardimport android.view.View; 24513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalardimport android.view.ViewPropertyAnimator; 252cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalardimport android.widget.Button; 262cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalardimport android.widget.FrameLayout; 272cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard 282cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalardimport com.android.inputmethod.latin.R; 292cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard 302cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard/** 312cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard * A view that handles buttons inside it according to a status. 322cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard */ 332cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalardpublic class ButtonSwitcher extends FrameLayout { 342d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard public static final int NOT_INITIALIZED = -1; 352d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard public static final int STATUS_NO_BUTTON = 0; 362d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard public static final int STATUS_INSTALL = 1; 372d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard public static final int STATUS_CANCEL = 2; 382d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard public static final int STATUS_DELETE = 3; 392d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard // One of the above 402d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard private int mStatus = NOT_INITIALIZED; 412d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard private int mAnimateToStatus = NOT_INITIALIZED; 422d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard 432cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard // Animation directions 442cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard public static final int ANIMATION_IN = 1; 452cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard public static final int ANIMATION_OUT = 2; 462cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard 472d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard private Button mInstallButton; 482d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard private Button mCancelButton; 492d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard private Button mDeleteButton; 506912342a48b9ebf6f4dcd714b697eadac48afbdeJean Chalard private DictionaryListInterfaceState mInterfaceState; 512d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard private OnClickListener mOnClickListener; 522d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard 532cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard public ButtonSwitcher(Context context, AttributeSet attrs) { 542cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard super(context, attrs); 552cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard } 562cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard 572cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard public ButtonSwitcher(Context context, AttributeSet attrs, int defStyle) { 582cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard super(context, attrs, defStyle); 592cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard } 602cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard 616912342a48b9ebf6f4dcd714b697eadac48afbdeJean Chalard public void reset(final DictionaryListInterfaceState interfaceState) { 622b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard mStatus = NOT_INITIALIZED; 632b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard mAnimateToStatus = NOT_INITIALIZED; 646912342a48b9ebf6f4dcd714b697eadac48afbdeJean Chalard mInterfaceState = interfaceState; 652b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard } 662b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard 672d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard @Override 682d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard protected void onLayout(final boolean changed, final int left, final int top, final int right, 692d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard final int bottom) { 702d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard super.onLayout(changed, left, top, right, bottom); 712d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mInstallButton = (Button)findViewById(R.id.dict_install_button); 722d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mCancelButton = (Button)findViewById(R.id.dict_cancel_button); 732d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mDeleteButton = (Button)findViewById(R.id.dict_delete_button); 742b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard setInternalOnClickListener(mOnClickListener); 752d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard setButtonPositionWithoutAnimation(mStatus); 762d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard if (mAnimateToStatus != NOT_INITIALIZED) { 772d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard // We have been asked to animate before we were ready, so we took a note of it. 782d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard // We are now ready: launch the animation. 792d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard animateButtonPosition(mStatus, mAnimateToStatus); 802d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mStatus = mAnimateToStatus; 812d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mAnimateToStatus = NOT_INITIALIZED; 822d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard } 832cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard } 842cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard 852d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard private Button getButton(final int status) { 862d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard switch(status) { 872d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard case STATUS_INSTALL: 882d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard return mInstallButton; 892d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard case STATUS_CANCEL: 902d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard return mCancelButton; 912d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard case STATUS_DELETE: 922d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard return mDeleteButton; 932d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard default: 942d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard return null; 952d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard } 962d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard } 972d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard 982d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard public void setStatusAndUpdateVisuals(final int status) { 992d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard if (mStatus == NOT_INITIALIZED) { 1002d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard setButtonPositionWithoutAnimation(status); 1012d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mStatus = status; 1022d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard } else { 1032d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard if (null == mInstallButton) { 1042d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard // We may come here before we have been layout. In this case we don't know our 1052d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard // size yet so we can't start animations so we need to remember what animation to 1062d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard // start once layout has gone through. 1072d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mAnimateToStatus = status; 1082d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard } else { 1092d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard animateButtonPosition(mStatus, status); 1102d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mStatus = status; 1112d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard } 1122d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard } 1132d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard } 1142d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard 1152d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard private void setButtonPositionWithoutAnimation(final int status) { 1162d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard // This may be called by setStatus() before the layout has come yet. 1172d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard if (null == mInstallButton) return; 1182d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard final int width = getWidth(); 1192d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard // Set to out of the screen if that's not the currently displayed status 1202d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mInstallButton.setTranslationX(STATUS_INSTALL == status ? 0 : width); 1212d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mCancelButton.setTranslationX(STATUS_CANCEL == status ? 0 : width); 1222d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mDeleteButton.setTranslationX(STATUS_DELETE == status ? 0 : width); 1232d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard } 1242d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard 1252d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard private void animateButtonPosition(final int oldStatus, final int newStatus) { 126513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard final View oldButton = getButton(oldStatus); 127513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard final View newButton = getButton(newStatus); 128513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard if (null != oldButton && null != newButton) { 129513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard // Transition between two buttons : animate out, then in 130513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard animateButton(oldButton, ANIMATION_OUT).setListener( 131513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard new AnimatorListenerAdapter() { 132513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard @Override 133513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard public void onAnimationEnd(final Animator animation) { 134d4fc13d261c77b3ccf6847e69d28cb2da583fd5cJean Chalard if (newStatus != mStatus) return; 135513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard animateButton(newButton, ANIMATION_IN); 136513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard } 137513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard }); 138513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard } else if (null != oldButton) { 139513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard animateButton(oldButton, ANIMATION_OUT); 140513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard } else if (null != newButton) { 141513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard animateButton(newButton, ANIMATION_IN); 142513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard } 1432cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard } 1442cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard 1452cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard public void setInternalOnClickListener(final OnClickListener listener) { 1462d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard mOnClickListener = listener; 1472b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard if (null != mInstallButton) { 1482b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard // Already laid out : do it now 1492b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard mInstallButton.setOnClickListener(mOnClickListener); 1502b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard mCancelButton.setOnClickListener(mOnClickListener); 1512b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard mDeleteButton.setOnClickListener(mOnClickListener); 1522b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard } 1532cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard } 1542cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard 155513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard private ViewPropertyAnimator animateButton(final View button, final int direction) { 1562cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard final float outerX = getWidth(); 1572cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard final float innerX = button.getX() - button.getTranslationX(); 1586912342a48b9ebf6f4dcd714b697eadac48afbdeJean Chalard mInterfaceState.removeFromCache((View)getParent()); 1592cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard if (ANIMATION_IN == direction) { 160d4fc13d261c77b3ccf6847e69d28cb2da583fd5cJean Chalard button.setClickable(true); 161513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard return button.animate().translationX(0); 1622cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard } else { 163d4fc13d261c77b3ccf6847e69d28cb2da583fd5cJean Chalard button.setClickable(false); 164513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard return button.animate().translationX(outerX - innerX); 1652cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard } 1662cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard } 1672cf450f48283bcf1452cb717b7ae3a9f0c729105Jean Chalard} 168