Home | History | Annotate | Download | only in stk
      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 
     17 package com.android.stk;
     18 
     19 import android.app.Activity;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.graphics.drawable.BitmapDrawable;
     23 import android.os.Bundle;
     24 import android.os.Handler;
     25 import android.os.Message;
     26 import android.text.Editable;
     27 import android.text.InputFilter;
     28 import android.text.InputType;
     29 import android.text.TextWatcher;
     30 import android.text.method.PasswordTransformationMethod;
     31 import android.view.KeyEvent;
     32 import android.view.MenuItem;
     33 import android.view.View;
     34 import android.view.Window;
     35 import android.widget.Button;
     36 import android.widget.TextView;
     37 import android.widget.EditText;
     38 import android.widget.TextView.BufferType;
     39 import com.android.internal.telephony.cat.CatLog;
     40 import com.android.internal.telephony.cat.FontSize;
     41 import com.android.internal.telephony.cat.Input;
     42 
     43 /**
     44  * Display a request for a text input a long with a text edit form.
     45  */
     46 public 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 
     57     // Constants
     58     private static final String className = new Object(){}.getClass().getEnclosingClass().getName();
     59     private static final String LOG_TAG = className.substring(className.lastIndexOf('.') + 1);
     60 
     61     private Input mStkInput = null;
     62     private boolean mAcceptUsersInput = true;
     63     // Constants
     64     private static final int STATE_TEXT = 1;
     65     private static final int STATE_YES_NO = 2;
     66 
     67     static final String YES_STR_RESPONSE = "YES";
     68     static final String NO_STR_RESPONSE = "NO";
     69 
     70     // Font size factor values.
     71     static final float NORMAL_FONT_FACTOR = 1;
     72     static final float LARGE_FONT_FACTOR = 2;
     73     static final float SMALL_FONT_FACTOR = (1 / 2);
     74 
     75     // message id for time out
     76     private static final int MSG_ID_TIMEOUT = 1;
     77     private StkAppService appService = StkAppService.getInstance();
     78 
     79     private boolean mIsResponseSent = false;
     80     private int mSlotId = -1;
     81     Activity mInstance = null;
     82 
     83     Handler mTimeoutHandler = new Handler() {
     84         @Override
     85         public void handleMessage(Message msg) {
     86             switch(msg.what) {
     87             case MSG_ID_TIMEOUT:
     88                 CatLog.d(LOG_TAG, "Msg timeout.");
     89                 mAcceptUsersInput = false;
     90                 appService.getStkContext(mSlotId).setPendingActivityInstance(mInstance);
     91                 sendResponse(StkAppService.RES_ID_TIMEOUT);
     92                 break;
     93             }
     94         }
     95     };
     96 
     97     // Click listener to handle buttons press..
     98     public void onClick(View v) {
     99         String input = null;
    100         if (!mAcceptUsersInput) {
    101             CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
    102             return;
    103         }
    104 
    105         switch (v.getId()) {
    106         case R.id.button_ok:
    107             // Check that text entered is valid .
    108             if (!verfiyTypedText()) {
    109                 CatLog.d(LOG_TAG, "handleClick, invalid text");
    110                 return;
    111             }
    112             mAcceptUsersInput = false;
    113             input = mTextIn.getText().toString();
    114             break;
    115         // Yes/No layout buttons.
    116         case R.id.button_yes:
    117             mAcceptUsersInput = false;
    118             input = YES_STR_RESPONSE;
    119             break;
    120         case R.id.button_no:
    121             mAcceptUsersInput = false;
    122             input = NO_STR_RESPONSE;
    123             break;
    124         }
    125         CatLog.d(LOG_TAG, "handleClick, ready to response");
    126         cancelTimeOut();
    127         appService.getStkContext(mSlotId).setPendingActivityInstance(this);
    128         sendResponse(StkAppService.RES_ID_INPUT, input, false);
    129     }
    130 
    131     @Override
    132     public void onCreate(Bundle icicle) {
    133         super.onCreate(icicle);
    134 
    135         CatLog.d(LOG_TAG, "onCreate - mIsResponseSent[" + mIsResponseSent + "]");
    136 
    137         // Set the layout for this activity.
    138         requestWindowFeature(Window.FEATURE_LEFT_ICON);
    139         setContentView(R.layout.stk_input);
    140 
    141         // Initialize members
    142         mTextIn = (EditText) this.findViewById(R.id.in_text);
    143         mPromptView = (TextView) this.findViewById(R.id.prompt);
    144         mInstance = this;
    145         // Set buttons listeners.
    146         Button okButton = (Button) findViewById(R.id.button_ok);
    147         Button yesButton = (Button) findViewById(R.id.button_yes);
    148         Button noButton = (Button) findViewById(R.id.button_no);
    149 
    150         okButton.setOnClickListener(this);
    151         yesButton.setOnClickListener(this);
    152         noButton.setOnClickListener(this);
    153 
    154         mYesNoLayout = findViewById(R.id.yes_no_layout);
    155         mNormalLayout = findViewById(R.id.normal_layout);
    156         initFromIntent(getIntent());
    157         mContext = getBaseContext();
    158         mAcceptUsersInput = true;
    159     }
    160 
    161     @Override
    162     protected void onPostCreate(Bundle savedInstanceState) {
    163         super.onPostCreate(savedInstanceState);
    164 
    165         mTextIn.addTextChangedListener(this);
    166     }
    167 
    168     @Override
    169     public void onResume() {
    170         super.onResume();
    171         CatLog.d(LOG_TAG, "onResume - mIsResponseSent[" + mIsResponseSent +
    172                 "], slot id: " + mSlotId);
    173         startTimeOut();
    174         appService.getStkContext(mSlotId).setPendingActivityInstance(null);
    175         if (mIsResponseSent) {
    176             cancelTimeOut();
    177             finish();
    178         }
    179     }
    180 
    181     @Override
    182     public void onPause() {
    183         super.onPause();
    184         CatLog.d(LOG_TAG, "onPause - mIsResponseSent[" + mIsResponseSent + "]");
    185     }
    186 
    187     @Override
    188     public void onStop() {
    189         super.onStop();
    190         CatLog.d(LOG_TAG, "onStop - mIsResponseSent[" + mIsResponseSent + "]");
    191         if (mIsResponseSent) {
    192             cancelTimeOut();
    193             finish();
    194         } else {
    195             appService.getStkContext(mSlotId).setPendingActivityInstance(this);
    196         }
    197     }
    198 
    199     @Override
    200     public void onDestroy() {
    201         super.onDestroy();
    202         CatLog.d(LOG_TAG, "onDestroy - before Send End Session mIsResponseSent[" +
    203                 mIsResponseSent + " , " + mSlotId + "]");
    204         //If the input activity is finished by stkappservice
    205         //when receiving OP_LAUNCH_APP from the other SIM, we can not send TR here
    206         //, since the input cmd is waiting user to process.
    207         if (!mIsResponseSent && !appService.isInputPending(mSlotId)) {
    208             CatLog.d(LOG_TAG, "handleDestroy - Send End Session");
    209             sendResponse(StkAppService.RES_ID_END_SESSION);
    210         }
    211         cancelTimeOut();
    212     }
    213 
    214     @Override
    215     public boolean onKeyDown(int keyCode, KeyEvent event) {
    216         if (!mAcceptUsersInput) {
    217             CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
    218             return true;
    219         }
    220 
    221         switch (keyCode) {
    222         case KeyEvent.KEYCODE_BACK:
    223             CatLog.d(LOG_TAG, "onKeyDown - KEYCODE_BACK");
    224             mAcceptUsersInput = false;
    225             cancelTimeOut();
    226             appService.getStkContext(mSlotId).setPendingActivityInstance(this);
    227             sendResponse(StkAppService.RES_ID_BACKWARD, null, false);
    228             return true;
    229         }
    230         return super.onKeyDown(keyCode, event);
    231     }
    232 
    233     void sendResponse(int resId) {
    234         sendResponse(resId, null, false);
    235     }
    236 
    237     void sendResponse(int resId, String input, boolean help) {
    238         if (mSlotId == -1) {
    239             CatLog.d(LOG_TAG, "slot id is invalid");
    240             return;
    241         }
    242 
    243         if (StkAppService.getInstance() == null) {
    244             CatLog.d(LOG_TAG, "StkAppService is null, Ignore response: id is " + resId);
    245             return;
    246         }
    247 
    248         CatLog.d(LOG_TAG, "sendResponse resID[" + resId + "] input[*****] help["
    249                 + help + "]");
    250         mIsResponseSent = true;
    251         Bundle args = new Bundle();
    252         args.putInt(StkAppService.OPCODE, StkAppService.OP_RESPONSE);
    253         args.putInt(StkAppService.SLOT_ID, mSlotId);
    254         args.putInt(StkAppService.RES_ID, resId);
    255         if (input != null) {
    256             args.putString(StkAppService.INPUT, input);
    257         }
    258         args.putBoolean(StkAppService.HELP, help);
    259         mContext.startService(new Intent(mContext, StkAppService.class)
    260                 .putExtras(args));
    261     }
    262 
    263     @Override
    264     public boolean onCreateOptionsMenu(android.view.Menu menu) {
    265         super.onCreateOptionsMenu(menu);
    266         menu.add(android.view.Menu.NONE, StkApp.MENU_ID_END_SESSION, 1,
    267                 R.string.menu_end_session);
    268         menu.add(0, StkApp.MENU_ID_HELP, 2, R.string.help);
    269 
    270         return true;
    271     }
    272 
    273     @Override
    274     public boolean onPrepareOptionsMenu(android.view.Menu menu) {
    275         super.onPrepareOptionsMenu(menu);
    276         menu.findItem(StkApp.MENU_ID_END_SESSION).setVisible(true);
    277         menu.findItem(StkApp.MENU_ID_HELP).setVisible(mStkInput.helpAvailable);
    278 
    279         return true;
    280     }
    281 
    282     @Override
    283     public boolean onOptionsItemSelected(MenuItem item) {
    284         if (!mAcceptUsersInput) {
    285             CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
    286             return true;
    287         }
    288         switch (item.getItemId()) {
    289         case StkApp.MENU_ID_END_SESSION:
    290             mAcceptUsersInput = false;
    291             cancelTimeOut();
    292             sendResponse(StkAppService.RES_ID_END_SESSION);
    293             finish();
    294             return true;
    295         case StkApp.MENU_ID_HELP:
    296             mAcceptUsersInput = false;
    297             cancelTimeOut();
    298             sendResponse(StkAppService.RES_ID_INPUT, "", true);
    299             finish();
    300             return true;
    301         }
    302         return super.onOptionsItemSelected(item);
    303     }
    304 
    305     @Override
    306     protected void onSaveInstanceState(Bundle outState) {
    307         CatLog.d(LOG_TAG, "onSaveInstanceState: " + mSlotId);
    308         outState.putBoolean("ACCEPT_USERS_INPUT", mAcceptUsersInput);
    309     }
    310 
    311     @Override
    312     protected void onRestoreInstanceState(Bundle savedInstanceState) {
    313         CatLog.d(LOG_TAG, "onRestoreInstanceState: " + mSlotId);
    314         mAcceptUsersInput = savedInstanceState.getBoolean("ACCEPT_USERS_INPUT");
    315     }
    316 
    317     public void beforeTextChanged(CharSequence s, int start, int count,
    318             int after) {
    319     }
    320 
    321     public void onTextChanged(CharSequence s, int start, int before, int count) {
    322         // Reset timeout.
    323         startTimeOut();
    324     }
    325 
    326     public void afterTextChanged(Editable s) {
    327     }
    328 
    329     private boolean verfiyTypedText() {
    330         // If not enough input was typed in stay on the edit screen.
    331         if (mTextIn.getText().length() < mStkInput.minLen) {
    332             return false;
    333         }
    334 
    335         return true;
    336     }
    337 
    338     private void cancelTimeOut() {
    339         mTimeoutHandler.removeMessages(MSG_ID_TIMEOUT);
    340     }
    341 
    342     private void startTimeOut() {
    343         int duration = StkApp.calculateDurationInMilis(mStkInput.duration);
    344 
    345         if (duration <= 0) {
    346             duration = StkApp.UI_TIMEOUT;
    347         }
    348         cancelTimeOut();
    349         mTimeoutHandler.sendMessageDelayed(mTimeoutHandler
    350                 .obtainMessage(MSG_ID_TIMEOUT), duration);
    351     }
    352 
    353     private void configInputDisplay() {
    354         TextView numOfCharsView = (TextView) findViewById(R.id.num_of_chars);
    355         TextView inTypeView = (TextView) findViewById(R.id.input_type);
    356 
    357         int inTypeId = R.string.alphabet;
    358 
    359         // set the prompt.
    360         mPromptView.setText(mStkInput.text);
    361 
    362         // Set input type (alphabet/digit) info close to the InText form.
    363         if (mStkInput.digitOnly) {
    364             mTextIn.setKeyListener(StkDigitsKeyListener.getInstance());
    365             inTypeId = R.string.digits;
    366         }
    367         inTypeView.setText(inTypeId);
    368 
    369         if (mStkInput.icon != null) {
    370             setFeatureDrawable(Window.FEATURE_LEFT_ICON, new BitmapDrawable(
    371                     mStkInput.icon));
    372         }
    373 
    374         // Handle specific global and text attributes.
    375         switch (mState) {
    376         case STATE_TEXT:
    377             int maxLen = mStkInput.maxLen;
    378             int minLen = mStkInput.minLen;
    379             mTextIn.setFilters(new InputFilter[] {new InputFilter.LengthFilter(
    380                     maxLen)});
    381 
    382             // Set number of chars info.
    383             String lengthLimit = String.valueOf(minLen);
    384             if (maxLen != minLen) {
    385                 lengthLimit = minLen + " - " + maxLen;
    386             }
    387             numOfCharsView.setText(lengthLimit);
    388 
    389             if (!mStkInput.echo) {
    390                 mTextIn.setInputType(InputType.TYPE_CLASS_NUMBER
    391                                      | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
    392             }
    393             // Set default text if present.
    394             if (mStkInput.defaultText != null) {
    395                 mTextIn.setText(mStkInput.defaultText);
    396             } else {
    397                 // make sure the text is cleared
    398                 mTextIn.setText("", BufferType.EDITABLE);
    399             }
    400 
    401             break;
    402         case STATE_YES_NO:
    403             // Set display mode - normal / yes-no layout
    404             mYesNoLayout.setVisibility(View.VISIBLE);
    405             mNormalLayout.setVisibility(View.GONE);
    406             break;
    407         }
    408     }
    409 
    410     private float getFontSizeFactor(FontSize size) {
    411         final float[] fontSizes =
    412             {NORMAL_FONT_FACTOR, LARGE_FONT_FACTOR, SMALL_FONT_FACTOR};
    413 
    414         return fontSizes[size.ordinal()];
    415     }
    416 
    417     private void initFromIntent(Intent intent) {
    418         // Get the calling intent type: text/key, and setup the
    419         // display parameters.
    420         CatLog.d(LOG_TAG, "initFromIntent - slot id: " + mSlotId);
    421         if (intent != null) {
    422             mStkInput = intent.getParcelableExtra("INPUT");
    423             mSlotId = intent.getIntExtra(StkAppService.SLOT_ID, -1);
    424             CatLog.d(LOG_TAG, "onCreate - slot id: " + mSlotId);
    425             if (mStkInput == null) {
    426                 finish();
    427             } else {
    428                 mState = mStkInput.yesNo ? STATE_YES_NO :
    429                         STATE_TEXT;
    430                 configInputDisplay();
    431             }
    432         } else {
    433             finish();
    434         }
    435     }
    436 }
    437