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