1/*
2 * Copyright (C) 2007 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 of
6 * 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.stk;
18
19import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.graphics.drawable.BitmapDrawable;
23import android.os.Bundle;
24import android.os.Handler;
25import android.os.Message;
26import android.text.Editable;
27import android.text.InputFilter;
28import android.text.InputType;
29import android.text.TextWatcher;
30import android.text.method.PasswordTransformationMethod;
31import android.view.KeyEvent;
32import android.view.MenuItem;
33import android.view.View;
34import android.view.Window;
35import android.widget.Button;
36import android.widget.TextView;
37import android.widget.EditText;
38import android.widget.TextView.BufferType;
39
40import com.android.internal.telephony.cat.FontSize;
41import com.android.internal.telephony.cat.Input;
42
43/**
44 * Display a request for a text input a long with a text edit form.
45 */
46public class StkInputActivity extends Activity implements View.OnClickListener,
47        TextWatcher {
48
49    // Members
50    private int mState;
51    private Context mContext;
52    private EditText mTextIn = null;
53    private TextView mPromptView = null;
54    private View mYesNoLayout = null;
55    private View mNormalLayout = null;
56    private Input mStkInput = null;
57
58    // Constants
59    private static final int STATE_TEXT = 1;
60    private static final int STATE_YES_NO = 2;
61
62    static final String YES_STR_RESPONSE = "YES";
63    static final String NO_STR_RESPONSE = "NO";
64
65    // Font size factor values.
66    static final float NORMAL_FONT_FACTOR = 1;
67    static final float LARGE_FONT_FACTOR = 2;
68    static final float SMALL_FONT_FACTOR = (1 / 2);
69
70    // message id for time out
71    private static final int MSG_ID_TIMEOUT = 1;
72
73    Handler mTimeoutHandler = new Handler() {
74        @Override
75        public void handleMessage(Message msg) {
76            switch(msg.what) {
77            case MSG_ID_TIMEOUT:
78                //mAcceptUsersInput = false;
79                sendResponse(StkAppService.RES_ID_TIMEOUT);
80                finish();
81                break;
82            }
83        }
84    };
85
86    // Click listener to handle buttons press..
87    public void onClick(View v) {
88        String input = null;
89
90        switch (v.getId()) {
91        case R.id.button_ok:
92            // Check that text entered is valid .
93            if (!verfiyTypedText()) {
94                return;
95            }
96            input = mTextIn.getText().toString();
97            break;
98        // Yes/No layout buttons.
99        case R.id.button_yes:
100            input = YES_STR_RESPONSE;
101            break;
102        case R.id.button_no:
103            input = NO_STR_RESPONSE;
104            break;
105        }
106
107        sendResponse(StkAppService.RES_ID_INPUT, input, false);
108        finish();
109    }
110
111    @Override
112    public void onCreate(Bundle icicle) {
113        super.onCreate(icicle);
114
115        // Set the layout for this activity.
116        requestWindowFeature(Window.FEATURE_LEFT_ICON);
117        setContentView(R.layout.stk_input);
118
119        // Initialize members
120        mTextIn = (EditText) this.findViewById(R.id.in_text);
121        mPromptView = (TextView) this.findViewById(R.id.prompt);
122
123        // Set buttons listeners.
124        Button okButton = (Button) findViewById(R.id.button_ok);
125        Button yesButton = (Button) findViewById(R.id.button_yes);
126        Button noButton = (Button) findViewById(R.id.button_no);
127
128        okButton.setOnClickListener(this);
129        yesButton.setOnClickListener(this);
130        noButton.setOnClickListener(this);
131
132        mYesNoLayout = findViewById(R.id.yes_no_layout);
133        mNormalLayout = findViewById(R.id.normal_layout);
134
135        // Get the calling intent type: text/key, and setup the
136        // display parameters.
137        Intent intent = getIntent();
138        if (intent != null) {
139            mStkInput = intent.getParcelableExtra("INPUT");
140            if (mStkInput == null) {
141                finish();
142            } else {
143                mState = mStkInput.yesNo ? STATE_YES_NO : STATE_TEXT;
144                configInputDisplay();
145            }
146        } else {
147            finish();
148        }
149        mContext = getBaseContext();
150    }
151
152    @Override
153    protected void onPostCreate(Bundle savedInstanceState) {
154        super.onPostCreate(savedInstanceState);
155
156        mTextIn.addTextChangedListener(this);
157    }
158
159    @Override
160    public void onResume() {
161        super.onResume();
162
163        startTimeOut();
164    }
165
166    @Override
167    public void onPause() {
168        super.onPause();
169
170        cancelTimeOut();
171    }
172
173    @Override
174    public boolean onKeyDown(int keyCode, KeyEvent event) {
175        switch (keyCode) {
176        case KeyEvent.KEYCODE_BACK:
177            sendResponse(StkAppService.RES_ID_BACKWARD, null, false);
178            finish();
179            break;
180        }
181        return super.onKeyDown(keyCode, event);
182    }
183
184    private void sendResponse(int resId) {
185        sendResponse(resId, null, false);
186    }
187
188    private void sendResponse(int resId, String input, boolean help) {
189        Bundle args = new Bundle();
190        args.putInt(StkAppService.OPCODE, StkAppService.OP_RESPONSE);
191        args.putInt(StkAppService.RES_ID, resId);
192        if (input != null) {
193            args.putString(StkAppService.INPUT, input);
194        }
195        args.putBoolean(StkAppService.HELP, help);
196        mContext.startService(new Intent(mContext, StkAppService.class)
197                .putExtras(args));
198    }
199
200    @Override
201    public boolean onCreateOptionsMenu(android.view.Menu menu) {
202        super.onCreateOptionsMenu(menu);
203        menu.add(android.view.Menu.NONE, StkApp.MENU_ID_END_SESSION, 1,
204                R.string.menu_end_session);
205        menu.add(0, StkApp.MENU_ID_HELP, 2, R.string.help);
206
207        return true;
208    }
209
210    @Override
211    public boolean onPrepareOptionsMenu(android.view.Menu menu) {
212        super.onPrepareOptionsMenu(menu);
213        menu.findItem(StkApp.MENU_ID_END_SESSION).setVisible(true);
214        menu.findItem(StkApp.MENU_ID_HELP).setVisible(mStkInput.helpAvailable);
215
216        return true;
217    }
218
219    @Override
220    public boolean onOptionsItemSelected(MenuItem item) {
221        switch (item.getItemId()) {
222        case StkApp.MENU_ID_END_SESSION:
223            sendResponse(StkAppService.RES_ID_END_SESSION);
224            finish();
225            return true;
226        case StkApp.MENU_ID_HELP:
227            sendResponse(StkAppService.RES_ID_INPUT, "", true);
228            finish();
229            return true;
230        }
231        return super.onOptionsItemSelected(item);
232    }
233
234    public void beforeTextChanged(CharSequence s, int start, int count,
235            int after) {
236    }
237
238    public void onTextChanged(CharSequence s, int start, int before, int count) {
239        // Reset timeout.
240        startTimeOut();
241    }
242
243    public void afterTextChanged(Editable s) {
244    }
245
246    private boolean verfiyTypedText() {
247        // If not enough input was typed in stay on the edit screen.
248        if (mTextIn.getText().length() < mStkInput.minLen) {
249            return false;
250        }
251
252        return true;
253    }
254
255    private void cancelTimeOut() {
256        mTimeoutHandler.removeMessages(MSG_ID_TIMEOUT);
257    }
258
259    private void startTimeOut() {
260        int duration = StkApp.calculateDurationInMilis(mStkInput.duration);
261
262        if (duration <= 0) {
263            duration = StkApp.UI_TIMEOUT;
264        }
265        cancelTimeOut();
266        mTimeoutHandler.sendMessageDelayed(mTimeoutHandler
267                .obtainMessage(MSG_ID_TIMEOUT), duration);
268    }
269
270    private void configInputDisplay() {
271        TextView numOfCharsView = (TextView) findViewById(R.id.num_of_chars);
272        TextView inTypeView = (TextView) findViewById(R.id.input_type);
273
274        int inTypeId = R.string.alphabet;
275
276        // set the prompt.
277        mPromptView.setText(mStkInput.text);
278
279        // Set input type (alphabet/digit) info close to the InText form.
280        if (mStkInput.digitOnly) {
281            mTextIn.setKeyListener(StkDigitsKeyListener.getInstance());
282            inTypeId = R.string.digits;
283        }
284        inTypeView.setText(inTypeId);
285
286        if (mStkInput.icon != null) {
287            setFeatureDrawable(Window.FEATURE_LEFT_ICON, new BitmapDrawable(
288                    mStkInput.icon));
289        }
290
291        // Handle specific global and text attributes.
292        switch (mState) {
293        case STATE_TEXT:
294            int maxLen = mStkInput.maxLen;
295            int minLen = mStkInput.minLen;
296            mTextIn.setFilters(new InputFilter[] {new InputFilter.LengthFilter(
297                    maxLen)});
298
299            // Set number of chars info.
300            String lengthLimit = String.valueOf(minLen);
301            if (maxLen != minLen) {
302                lengthLimit = minLen + " - " + maxLen;
303            }
304            numOfCharsView.setText(lengthLimit);
305
306            if (!mStkInput.echo) {
307                mTextIn.setInputType(InputType.TYPE_CLASS_NUMBER
308                                     | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
309            }
310            // Set default text if present.
311            if (mStkInput.defaultText != null) {
312                mTextIn.setText(mStkInput.defaultText);
313            } else {
314                // make sure the text is cleared
315                mTextIn.setText("", BufferType.EDITABLE);
316            }
317
318            break;
319        case STATE_YES_NO:
320            // Set display mode - normal / yes-no layout
321            mYesNoLayout.setVisibility(View.VISIBLE);
322            mNormalLayout.setVisibility(View.GONE);
323            break;
324        }
325    }
326
327    private float getFontSizeFactor(FontSize size) {
328        final float[] fontSizes =
329            {NORMAL_FONT_FACTOR, LARGE_FONT_FACTOR, SMALL_FONT_FACTOR};
330
331        return fontSizes[size.ordinal()];
332    }
333}
334