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.graphics.Rect;
21import android.text.Editable;
22import android.text.InputType;
23import android.text.Spanned;
24import android.text.method.NumberKeyListener;
25import android.util.AttributeSet;
26import android.view.animation.TranslateAnimation;
27import android.widget.EditText;
28import android.widget.ViewSwitcher;
29
30/**
31 * Provides vertical scrolling for the input/result EditText.
32 */
33class CalculatorDisplay extends ViewSwitcher {
34
35    private static final String ATTR_MAX_DIGITS = "maxDigits";
36    private static final int DEFAULT_MAX_DIGITS = 10;
37
38    // only these chars are accepted from keyboard
39    private static final char[] ACCEPTED_CHARS =
40        "0123456789.+-*/\u2212\u00d7\u00f7()!%^".toCharArray();
41
42    private static final int ANIM_DURATION = 500;
43
44    enum Scroll { UP, DOWN, NONE }
45
46    TranslateAnimation inAnimUp;
47    TranslateAnimation outAnimUp;
48    TranslateAnimation inAnimDown;
49    TranslateAnimation outAnimDown;
50
51    private int mMaxDigits = DEFAULT_MAX_DIGITS;
52
53    public CalculatorDisplay(Context context, AttributeSet attrs) {
54        super(context, attrs);
55        mMaxDigits = attrs.getAttributeIntValue(null, ATTR_MAX_DIGITS, DEFAULT_MAX_DIGITS);
56    }
57
58    public int getMaxDigits() {
59        return mMaxDigits;
60    }
61
62    protected void setLogic(Logic logic) {
63        NumberKeyListener calculatorKeyListener =
64            new NumberKeyListener() {
65                public int getInputType() {
66                    return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
67                }
68
69                @Override
70                protected char[] getAcceptedChars() {
71                    return ACCEPTED_CHARS;
72                }
73
74                @Override
75                public CharSequence filter(CharSequence source, int start, int end,
76                                           Spanned dest, int dstart, int dend) {
77                    /* the EditText should still accept letters (eg. 'sin')
78                       coming from the on-screen touch buttons, so don't filter anything.
79                    */
80                    return null;
81                }
82            };
83
84        Editable.Factory factory = new CalculatorEditable.Factory(logic);
85        for (int i = 0; i < 2; ++i) {
86            EditText text = (EditText) getChildAt(i);
87            text.setBackground(null);
88            text.setEditableFactory(factory);
89            text.setKeyListener(calculatorKeyListener);
90            text.setSingleLine();
91        }
92    }
93
94    @Override
95    public void setOnKeyListener(OnKeyListener l) {
96        getChildAt(0).setOnKeyListener(l);
97        getChildAt(1).setOnKeyListener(l);
98    }
99
100    @Override
101    protected void onSizeChanged(int w, int h, int oldW, int oldH) {
102        inAnimUp = new TranslateAnimation(0, 0, h, 0);
103        inAnimUp.setDuration(ANIM_DURATION);
104        outAnimUp = new TranslateAnimation(0, 0, 0, -h);
105        outAnimUp.setDuration(ANIM_DURATION);
106
107        inAnimDown = new TranslateAnimation(0, 0, -h, 0);
108        inAnimDown.setDuration(ANIM_DURATION);
109        outAnimDown = new TranslateAnimation(0, 0, 0, h);
110        outAnimDown.setDuration(ANIM_DURATION);
111    }
112
113    void insert(String delta) {
114        EditText editor = (EditText) getCurrentView();
115        int cursor = editor.getSelectionStart();
116        editor.getText().insert(cursor, delta);
117    }
118
119    EditText getEditText() {
120        return (EditText) getCurrentView();
121    }
122
123    Editable getText() {
124        EditText text = (EditText) getCurrentView();
125        return text.getText();
126    }
127
128    void setText(CharSequence text, Scroll dir) {
129        if (getText().length() == 0) {
130            dir = Scroll.NONE;
131        }
132
133        if (dir == Scroll.UP) {
134            setInAnimation(inAnimUp);
135            setOutAnimation(outAnimUp);
136        } else if (dir == Scroll.DOWN) {
137            setInAnimation(inAnimDown);
138            setOutAnimation(outAnimDown);
139        } else { // Scroll.NONE
140            setInAnimation(null);
141            setOutAnimation(null);
142        }
143
144        EditText editText = (EditText) getNextView();
145        editText.setText(text);
146        //Calculator.log("selection to " + text.length() + "; " + text);
147        editText.setSelection(text.length());
148        showNext();
149    }
150
151    int getSelectionStart() {
152        EditText text = (EditText) getCurrentView();
153        return text.getSelectionStart();
154    }
155
156    @Override
157    protected void onFocusChanged(boolean gain, int direction, Rect prev) {
158        //Calculator.log("focus " + gain + "; " + direction + "; " + prev);
159        if (!gain) {
160            requestFocus();
161        }
162    }
163}
164