1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.calculator2;
18
19import android.content.Context;
20import android.util.AttributeSet;
21import android.view.GestureDetector;
22import android.view.MotionEvent;
23import android.view.View;
24import android.view.animation.Animation;
25import android.view.animation.Animation.AnimationListener;
26import android.view.animation.TranslateAnimation;
27import android.widget.FrameLayout;
28
29class PanelSwitcher extends FrameLayout implements AnimationListener {
30    private static final int MAJOR_MOVE = 60;
31    private static final int ANIM_DURATION = 400;
32
33    private GestureDetector mGestureDetector;
34    private int mCurrentView;
35    private View mChildren[] = new View[0];
36
37    private int mWidth;
38    private TranslateAnimation inLeft;
39    private TranslateAnimation outLeft;
40
41    private TranslateAnimation inRight;
42    private TranslateAnimation outRight;
43
44    private static final int LEFT  = 1;
45    private static final int RIGHT = 2;
46    private int mPreviousMove;
47
48    public interface Listener {
49        void onChange();
50    }
51
52    private Listener mListener;
53
54    public PanelSwitcher(Context context, AttributeSet attrs) {
55        super(context, attrs);
56        mCurrentView = 0;
57        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
58                @Override
59                public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
60                                       float velocityY) {
61                    int dx = (int) (e2.getX() - e1.getX());
62
63                    // don't accept the fling if it's too short
64                    // as it may conflict with a button push
65                    if (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.abs(velocityY)) {
66                        if (velocityX > 0) {
67                            moveRight();
68                        } else {
69                            moveLeft();
70                        }
71                        return true;
72                    } else {
73                        return false;
74                    }
75                }
76            });
77    }
78
79    public void setListener(Listener listener) {
80        this.mListener = listener;
81    }
82
83    void setCurrentIndex(int current) {
84        boolean changed = mCurrentView != current;
85        mCurrentView = current;
86        updateCurrentView();
87        if (changed && mListener != null) {
88            mListener.onChange();
89        }
90    }
91
92    private void updateCurrentView() {
93        for (int i = mChildren.length-1; i >= 0 ; --i) {
94            mChildren[i].setVisibility(i==mCurrentView ? View.VISIBLE : View.GONE);
95        }
96    }
97
98    @Override
99    public void onSizeChanged(int w, int h, int oldW, int oldH) {
100        mWidth = w;
101        inLeft   = new TranslateAnimation(mWidth, 0, 0, 0);
102        inLeft.setAnimationListener(this);
103        outLeft  = new TranslateAnimation(0, -mWidth, 0, 0);
104        inRight  = new TranslateAnimation(-mWidth, 0, 0, 0);
105        inRight.setAnimationListener(this);
106        outRight = new TranslateAnimation(0, mWidth, 0, 0);
107
108        inLeft.setDuration(ANIM_DURATION);
109        outLeft.setDuration(ANIM_DURATION);
110        inRight.setDuration(ANIM_DURATION);
111        outRight.setDuration(ANIM_DURATION);
112    }
113
114    @Override
115    protected void onFinishInflate() {
116        int count = getChildCount();
117        mChildren = new View[count];
118        for (int i = 0; i < count; ++i) {
119            mChildren[i] = getChildAt(i);
120        }
121        updateCurrentView();
122    }
123
124    @Override
125    public boolean onTouchEvent(MotionEvent event) {
126        mGestureDetector.onTouchEvent(event);
127        return true;
128    }
129
130    @Override
131    public boolean onInterceptTouchEvent(MotionEvent event) {
132        return mGestureDetector.onTouchEvent(event);
133    }
134
135    void moveLeft() {
136        //  <--
137        if (mCurrentView < mChildren.length - 1 && mPreviousMove != LEFT) {
138            mChildren[mCurrentView+1].setVisibility(View.VISIBLE);
139            mChildren[mCurrentView+1].startAnimation(inLeft);
140            mChildren[mCurrentView].startAnimation(outLeft);
141            mChildren[mCurrentView].setVisibility(View.GONE);
142
143            mCurrentView++;
144            mPreviousMove = LEFT;
145        }
146    }
147
148    void moveRight() {
149        //  -->
150        if (mCurrentView > 0 && mPreviousMove != RIGHT) {
151            mChildren[mCurrentView-1].setVisibility(View.VISIBLE);
152            mChildren[mCurrentView-1].startAnimation(inRight);
153            mChildren[mCurrentView].startAnimation(outRight);
154            mChildren[mCurrentView].setVisibility(View.GONE);
155
156            mCurrentView--;
157            mPreviousMove = RIGHT;
158        }
159    }
160
161    int getCurrentIndex() {
162        return mCurrentView;
163    }
164
165    @Override
166    public void onAnimationRepeat(Animation animation) {
167    }
168
169    @Override
170    public void onAnimationStart(Animation animation) {
171    }
172
173    @Override
174    public void onAnimationEnd(Animation animation) {
175        if (mListener != null) {
176            mListener.onChange();
177        }
178    }
179}
180