blob: ad8c3b912b318ac766ba3a17268d4e6720e92424 [file] [log] [blame]
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001/*
2 * Copyright (C) 2007 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.stk;
18
Preeti Ahuja95919342013-10-01 18:18:55 -070019import android.app.ActivityManager;
20import android.app.ActivityManager.RunningTaskInfo;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050021import android.app.AlertDialog;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080022import android.app.Notification;
23import android.app.NotificationManager;
24import android.app.PendingIntent;
25import android.app.Service;
Wink Savillee68857d2014-10-17 15:23:05 -070026import android.app.Activity;
27import android.app.ActivityManager;
28import android.app.ActivityManager.RecentTaskInfo;
29import android.app.ActivityManager.RunningAppProcessInfo;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080030import android.content.Context;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050031import android.content.DialogInterface;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080032import android.content.Intent;
Preeti Ahuja95919342013-10-01 18:18:55 -070033import android.content.res.Configuration;
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +010034import android.graphics.Bitmap;
35import android.graphics.BitmapFactory;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080036import android.net.Uri;
37import android.os.Bundle;
38import android.os.Handler;
39import android.os.IBinder;
40import android.os.Looper;
41import android.os.Message;
Preeti Ahuja95919342013-10-01 18:18:55 -070042import android.provider.Settings;
Wink Saville56469d52009-04-02 01:37:03 -070043import android.telephony.TelephonyManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080044import android.view.Gravity;
45import android.view.LayoutInflater;
46import android.view.View;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050047import android.view.Window;
48import android.view.WindowManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080049import android.widget.ImageView;
50import android.widget.RemoteViews;
51import android.widget.TextView;
52import android.widget.Toast;
Wink Savillee68857d2014-10-17 15:23:05 -070053import android.content.BroadcastReceiver;
54import android.content.IntentFilter;
55import android.content.pm.ApplicationInfo;
56import android.content.pm.PackageManager.NameNotFoundException;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080057
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070058import com.android.internal.telephony.cat.AppInterface;
Preeti Ahuja95919342013-10-01 18:18:55 -070059import com.android.internal.telephony.cat.LaunchBrowserMode;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070060import com.android.internal.telephony.cat.Menu;
61import com.android.internal.telephony.cat.Item;
Pierre Fröjd97503262010-11-08 13:59:36 +010062import com.android.internal.telephony.cat.Input;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070063import com.android.internal.telephony.cat.ResultCode;
64import com.android.internal.telephony.cat.CatCmdMessage;
65import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
Preeti Ahuja95919342013-10-01 18:18:55 -070066import com.android.internal.telephony.cat.CatCmdMessage.SetupEventListSettings;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070067import com.android.internal.telephony.cat.CatLog;
68import com.android.internal.telephony.cat.CatResponseMessage;
69import com.android.internal.telephony.cat.TextMessage;
Wink Saville94e982b2014-07-11 07:38:14 -070070import com.android.internal.telephony.uicc.IccRefreshResponse;
71import com.android.internal.telephony.uicc.IccCardStatus.CardState;
Wink Savillee68857d2014-10-17 15:23:05 -070072import com.android.internal.telephony.PhoneConstants;
73import com.android.internal.telephony.TelephonyIntents;
74import com.android.internal.telephony.IccCardConstants;
75import com.android.internal.telephony.uicc.UiccController;
Preeti Ahuja95919342013-10-01 18:18:55 -070076import com.android.internal.telephony.GsmAlphabet;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080077
78import java.util.LinkedList;
Wink Savillee68857d2014-10-17 15:23:05 -070079import java.lang.System;
80import java.util.List;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080081
Preeti Ahuja95919342013-10-01 18:18:55 -070082import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja95919342013-10-01 18:18:55 -070083 SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
84
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080085/**
86 * SIM toolkit application level service. Interacts with Telephopny messages,
87 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -070088 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080089 */
90public class StkAppService extends Service implements Runnable {
91
92 // members
Wink Savillee68857d2014-10-17 15:23:05 -070093 protected class StkContext {
94 protected CatCmdMessage mMainCmd = null;
95 protected CatCmdMessage mCurrentCmd = null;
96 protected CatCmdMessage mCurrentMenuCmd = null;
97 protected Menu mCurrentMenu = null;
98 protected String lastSelectedItem = null;
99 protected boolean mMenuIsVisible = false;
100 protected boolean mIsInputPending = false;
101 protected boolean mIsMenuPending = false;
102 protected boolean mIsDialogPending = false;
103 protected boolean responseNeeded = true;
104 protected boolean launchBrowser = false;
105 protected BrowserSettings mBrowserSettings = null;
106 protected LinkedList<DelayedCmd> mCmdsQ = null;
107 protected boolean mCmdInProgress = false;
108 protected int mStkServiceState = STATE_UNKNOWN;
109 protected int mSetupMenuState = STATE_UNKNOWN;
110 protected int mMenuState = StkMenuActivity.STATE_INIT;
111 protected int mOpCode = -1;
112 private Activity mActivityInstance = null;
113 private Activity mDialogInstance = null;
114 private Activity mMainActivityInstance = null;
115 private boolean mBackGroundTRSent = false;
116 private int mSlotId = 0;
Preeti Ahuja95919342013-10-01 18:18:55 -0700117 private SetupEventListSettings mSetupEventListSettings = null;
118 private boolean mClearSelectItem = false;
119 private boolean mDisplayTextDlgIsVisibile = false;
120 private CatCmdMessage mCurrentSetupEventCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700121 final synchronized void setPendingActivityInstance(Activity act) {
122 CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act);
123 callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
124 }
125 final synchronized Activity getPendingActivityInstance() {
126 CatLog.d(this, "getPendingActivityInstance act : " + mSlotId + ", " +
127 mActivityInstance);
128 return mActivityInstance;
129 }
130 final synchronized void setPendingDialogInstance(Activity act) {
131 CatLog.d(this, "setPendingDialogInstance act : " + mSlotId + ", " + act);
132 callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act);
133 }
134 final synchronized Activity getPendingDialogInstance() {
135 CatLog.d(this, "getPendingDialogInstance act : " + mSlotId + ", " +
136 mDialogInstance);
137 return mDialogInstance;
138 }
139 final synchronized void setMainActivityInstance(Activity act) {
140 CatLog.d(this, "setMainActivityInstance act : " + mSlotId + ", " + act);
141 callSetActivityInstMsg(OP_SET_MAINACT_INST, mSlotId, act);
142 }
143 final synchronized Activity getMainActivityInstance() {
144 CatLog.d(this, "getMainActivityInstance act : " + mSlotId + ", " +
145 mMainActivityInstance);
146 return mMainActivityInstance;
147 }
148 }
149
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800150 private volatile Looper mServiceLooper;
151 private volatile ServiceHandler mServiceHandler;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800152 private Context mContext = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800153 private NotificationManager mNotificationManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800154 static StkAppService sInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700155 private AppInterface[] mStkService = null;
156 private StkContext[] mStkContext = null;
157 private int mSimCount = 0;
Preeti Ahuja95919342013-10-01 18:18:55 -0700158
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800159 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
160 // creating an intent.
161 private enum InitiatedByUserAction {
162 yes, // The action was started via a user initiated action
163 unknown, // Not known for sure if user initated the action
164 }
165
166 // constants
167 static final String OPCODE = "op";
168 static final String CMD_MSG = "cmd message";
169 static final String RES_ID = "response id";
170 static final String MENU_SELECTION = "menu selection";
171 static final String INPUT = "input";
172 static final String HELP = "help";
173 static final String CONFIRMATION = "confirm";
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500174 static final String CHOICE = "choice";
Wink Savillee68857d2014-10-17 15:23:05 -0700175 static final String SLOT_ID = "SLOT_ID";
176 static final String STK_CMD = "STK CMD";
177 static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/";
178 static final String STK_MENU_URI = "stk://com.android.stk/menu/";
179 static final String STK_INPUT_URI = "stk://com.android.stk/input/";
180 static final String STK_TONE_URI = "stk://com.android.stk/tone/";
Preeti Ahuja95919342013-10-01 18:18:55 -0700181
182 // These below constants are used for SETUP_EVENT_LIST
183 static final String SETUP_EVENT_TYPE = "event";
184 static final String SETUP_EVENT_CAUSE = "cause";
185
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800186 // operations ids for different service functionality.
187 static final int OP_CMD = 1;
188 static final int OP_RESPONSE = 2;
189 static final int OP_LAUNCH_APP = 3;
190 static final int OP_END_SESSION = 4;
191 static final int OP_BOOT_COMPLETED = 5;
192 private static final int OP_DELAYED_MSG = 6;
Wink Saville94e982b2014-07-11 07:38:14 -0700193 static final int OP_CARD_STATUS_CHANGED = 7;
Wink Savillee68857d2014-10-17 15:23:05 -0700194 static final int OP_SET_ACT_INST = 8;
195 static final int OP_SET_DAL_INST = 9;
196 static final int OP_SET_MAINACT_INST = 10;
Preeti Ahujab3d0e612014-11-20 13:29:25 -0800197 static final int OP_LOCALE_CHANGED = 11;
198 static final int OP_ALPHA_NOTIFY = 12;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800199
Preeti Ahuja95919342013-10-01 18:18:55 -0700200 //Invalid SetupEvent
201 static final int INVALID_SETUP_EVENT = 0xFF;
202
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800203 // Response ids
204 static final int RES_ID_MENU_SELECTION = 11;
205 static final int RES_ID_INPUT = 12;
206 static final int RES_ID_CONFIRM = 13;
207 static final int RES_ID_DONE = 14;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500208 static final int RES_ID_CHOICE = 15;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800209
210 static final int RES_ID_TIMEOUT = 20;
211 static final int RES_ID_BACKWARD = 21;
212 static final int RES_ID_END_SESSION = 22;
213 static final int RES_ID_EXIT = 23;
214
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500215 static final int YES = 1;
216 static final int NO = 0;
217
Wink Savillee68857d2014-10-17 15:23:05 -0700218 static final int STATE_UNKNOWN = -1;
219 static final int STATE_NOT_EXIST = 0;
220 static final int STATE_EXIST = 1;
Wink Saville79085fc2009-06-09 10:27:23 -0700221
Wink Savillee68857d2014-10-17 15:23:05 -0700222 private static final String PACKAGE_NAME = "com.android.stk";
223 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
224 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
225 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800226 // Notification id used to display Idle Mode text in NotificationManager.
227 private static final int STK_NOTIFICATION_ID = 333;
Wink Savillee68857d2014-10-17 15:23:05 -0700228 private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
Wink Saville79085fc2009-06-09 10:27:23 -0700229
230 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800231 // session end) while the service is busy processing a previous message.
232 private class DelayedCmd {
233 // members
234 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700235 CatCmdMessage msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700236 int slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800237
Wink Savillee68857d2014-10-17 15:23:05 -0700238 DelayedCmd(int id, CatCmdMessage msg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800239 this.id = id;
240 this.msg = msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700241 this.slotId = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800242 }
243 }
244
245 @Override
246 public void onCreate() {
Wink Savillee68857d2014-10-17 15:23:05 -0700247 CatLog.d(LOG_TAG, "onCreate()+");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800248 // Initialize members
Wink Savillee68857d2014-10-17 15:23:05 -0700249 int i = 0;
250 mContext = getBaseContext();
251 mSimCount = TelephonyManager.from(mContext).getSimCount();
252 CatLog.d(LOG_TAG, "simCount: " + mSimCount);
253 mStkService = new AppInterface[mSimCount];
254 mStkContext = new StkContext[mSimCount];
255 for (i = 0; i < mSimCount; i++) {
256 CatLog.d(LOG_TAG, "slotId: " + i);
257 if (null != UiccController.getInstance() && null != UiccController.getInstance()
258 .getUiccCard(i)) {
259 mStkService[i] = UiccController.getInstance().getUiccCard(i).getCatService();
260 } else {
261 CatLog.d(LOG_TAG, "Null instance: [" + UiccController.getInstance() + "],[" +
262 UiccController.getInstance().getUiccCard(i) + "]");
263 }
264 mStkContext[i] = new StkContext();
265 mStkContext[i].mSlotId = i;
266 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
267 }
268
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800269 Thread serviceThread = new Thread(null, this, "Stk App Service");
270 serviceThread.start();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800271 mNotificationManager = (NotificationManager) mContext
272 .getSystemService(Context.NOTIFICATION_SERVICE);
273 sInstance = this;
274 }
275
276 @Override
277 public void onStart(Intent intent, int startId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700278 if (intent == null) {
279 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530280 return;
281 }
282
Wink Savillee68857d2014-10-17 15:23:05 -0700283 Bundle args = intent.getExtras();
284 if (args == null) {
285 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
286 return;
287 }
288
289 int op = args.getInt(OPCODE);
290 int slotId = 0;
291 int i = 0;
292 if (op != OP_BOOT_COMPLETED) {
293 slotId = args.getInt(SLOT_ID);
294 }
295 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", " + args);
296 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
297 if (null != UiccController.getInstance() && null != UiccController.getInstance()
298 .getUiccCard(slotId)) {
299 mStkService[slotId] = UiccController.getInstance().getUiccCard(slotId)
300 .getCatService();
301 } else {
302 CatLog.d(LOG_TAG, "Null instance: [" + UiccController.getInstance() + "],[" +
303 UiccController.getInstance().getUiccCard(slotId)+"]");
304 }
305 if (mStkService[slotId] == null) {
306 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
307 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
308 //Check other StkService state.
309 //If all StkServices are not available, stop itself and uninstall apk.
310 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
311 if (i != slotId
312 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
313 || mStkContext[i].mStkServiceState == STATE_EXIST)) {
314 break;
315 }
316 }
317 } else {
318 mStkContext[slotId].mStkServiceState = STATE_EXIST;
319 }
320 if (i == mSimCount) {
321 stopSelf();
322 StkAppInstaller.unInstall(mContext);
323 return;
324 }
325 }
326
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530327 waitForLooper();
John Wang62acae42009-10-08 11:20:23 -0700328 // onStart() method can be passed a null intent
329 // TODO: replace onStart() with onStartCommand()
330 if (intent == null) {
331 return;
332 }
333
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800334 Message msg = mServiceHandler.obtainMessage();
Wink Savillee68857d2014-10-17 15:23:05 -0700335 msg.arg1 = op;
336 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800337 switch(msg.arg1) {
338 case OP_CMD:
339 msg.obj = args.getParcelable(CMD_MSG);
340 break;
341 case OP_RESPONSE:
Wink Saville94e982b2014-07-11 07:38:14 -0700342 case OP_CARD_STATUS_CHANGED:
Preeti Ahuja95919342013-10-01 18:18:55 -0700343 case OP_LOCALE_CHANGED:
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530344 case OP_ALPHA_NOTIFY:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800345 msg.obj = args;
346 /* falls through */
347 case OP_LAUNCH_APP:
348 case OP_END_SESSION:
349 case OP_BOOT_COMPLETED:
350 break;
351 default:
352 return;
353 }
354 mServiceHandler.sendMessage(msg);
355 }
356
357 @Override
358 public void onDestroy() {
Wink Savillee68857d2014-10-17 15:23:05 -0700359 CatLog.d(LOG_TAG, "onDestroy()");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800360 waitForLooper();
361 mServiceLooper.quit();
362 }
363
364 @Override
365 public IBinder onBind(Intent intent) {
366 return null;
367 }
368
369 public void run() {
370 Looper.prepare();
371
372 mServiceLooper = Looper.myLooper();
373 mServiceHandler = new ServiceHandler();
374
375 Looper.loop();
376 }
377
378 /*
379 * Package api used by StkMenuActivity to indicate if its on the foreground.
380 */
Wink Savillee68857d2014-10-17 15:23:05 -0700381 void indicateMenuVisibility(boolean visibility, int slotId) {
382 if (slotId >= 0 && slotId < mSimCount) {
383 mStkContext[slotId].mMenuIsVisible = visibility;
384 }
385 }
386
Preeti Ahuja95919342013-10-01 18:18:55 -0700387 /*
388 * Package api used by StkDialogActivity to indicate if its on the foreground.
389 */
390 void setDisplayTextDlgVisibility(boolean visibility, int slotId) {
391 if (slotId >= 0 && slotId < mSimCount) {
392 mStkContext[slotId].mDisplayTextDlgIsVisibile = visibility;
393 }
394 }
395
Wink Savillee68857d2014-10-17 15:23:05 -0700396 boolean isInputPending(int slotId) {
397 if (slotId >= 0 && slotId < mSimCount) {
398 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
399 return mStkContext[slotId].mIsInputPending;
400 }
401 return false;
402 }
403
404 boolean isMenuPending(int slotId) {
405 if (slotId >= 0 && slotId < mSimCount) {
406 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
407 return mStkContext[slotId].mIsMenuPending;
408 }
409 return false;
410 }
411
412 boolean isDialogPending(int slotId) {
413 if (slotId >= 0 && slotId < mSimCount) {
414 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
415 return mStkContext[slotId].mIsDialogPending;
416 }
417 return false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800418 }
419
420 /*
421 * Package api used by StkMenuActivity to get its Menu parameter.
422 */
Wink Savillee68857d2014-10-17 15:23:05 -0700423 Menu getMenu(int slotId) {
424 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
425 if (slotId >=0 && slotId < mSimCount) {
426 return mStkContext[slotId].mCurrentMenu;
427 } else {
428 return null;
429 }
430 }
431
432 /*
433 * Package api used by StkMenuActivity to get its Main Menu parameter.
434 */
435 Menu getMainMenu(int slotId) {
436 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
437 if (slotId >=0 && slotId < mSimCount) {
438 return mStkContext[slotId].mMainCmd.getMenu();
439 } else {
440 return null;
441 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800442 }
443
444 /*
445 * Package api used by UI Activities and Dialogs to communicate directly
446 * with the service to deliver state information and parameters.
447 */
448 static StkAppService getInstance() {
449 return sInstance;
450 }
451
452 private void waitForLooper() {
453 while (mServiceHandler == null) {
454 synchronized (this) {
455 try {
456 wait(100);
457 } catch (InterruptedException e) {
458 }
459 }
460 }
461 }
462
463 private final class ServiceHandler extends Handler {
464 @Override
465 public void handleMessage(Message msg) {
Wink Savillee68857d2014-10-17 15:23:05 -0700466 if(null == msg) {
467 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
468 return;
469 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800470 int opcode = msg.arg1;
Wink Savillee68857d2014-10-17 15:23:05 -0700471 int slotId = msg.arg2;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800472
Wink Savillee68857d2014-10-17 15:23:05 -0700473 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
474 if (opcode == OP_CMD && msg.obj != null &&
475 ((CatCmdMessage)msg.obj).getCmdType()!= null) {
476 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
477 }
478 mStkContext[slotId].mOpCode = opcode;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800479 switch (opcode) {
480 case OP_LAUNCH_APP:
Wink Savillee68857d2014-10-17 15:23:05 -0700481 if (mStkContext[slotId].mMainCmd == null) {
482 CatLog.d(LOG_TAG, "mMainCmd is null");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800483 // nothing todo when no SET UP MENU command didn't arrive.
484 return;
485 }
Wink Savillee68857d2014-10-17 15:23:05 -0700486 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
487 mStkContext[slotId].mCmdInProgress + "]");
488
489 //If there is a pending activity for the slot id,
490 //just finish it and create a new one to handle the pending command.
491 cleanUpInstanceStackBySlot(slotId);
492
493 //Clean up all other activities in stack.
494 for (int i = 0; i < mSimCount; i++) {
495 if (i != slotId && mStkContext[i].mCurrentCmd != null) {
496 Activity otherAct = mStkContext[i].getPendingActivityInstance();
497 Activity otherDal = mStkContext[i].getPendingDialogInstance();
498 Activity otherMainMenu = mStkContext[i].getMainActivityInstance();
499 if (otherAct != null) {
500 CatLog.d(LOG_TAG, "finish pending otherAct and send SE. slot: " + i);
501 // Send end session for the pending proactive command of slot i in
502 // onDestroy of the activity.
503 // Set mBackGroundTRSent to true for ignoring to show the main menu
504 // for the following end session event.
505 mStkContext[i].mBackGroundTRSent = true;
506 otherAct.finish();
507 mStkContext[i].mActivityInstance = null;
508 }
509 if (otherDal != null) {
510 CatLog.d(LOG_TAG, "finish pending otherDal and send TR for the dialog");
511 mStkContext[i].mBackGroundTRSent = true;
512 otherDal.finish();
513 mStkContext[i].mDialogInstance = null;
514 }
515 if (otherMainMenu != null) {
516 CatLog.d(LOG_TAG, "finish pending otherMainMenu.");
517 otherMainMenu.finish();
518 mStkContext[i].mMainActivityInstance = null;
519 }
520 }
521 }
522 CatLog.d(LOG_TAG, "Current cmd type: " +
523 mStkContext[slotId].mCurrentCmd.getCmdType());
524 //Restore the last command from stack by slot id.
525 restoreInstanceFromStackBySlot(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800526 break;
527 case OP_CMD:
Wink Savillee68857d2014-10-17 15:23:05 -0700528 CatLog.d(LOG_TAG, "[OP_CMD]");
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700529 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800530 // There are two types of commands:
531 // 1. Interactive - user's response is required.
532 // 2. Informative - display a message, no interaction with the user.
533 //
Wink Saville79085fc2009-06-09 10:27:23 -0700534 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800535 // Interactive commands can't override each other. So if a command
536 // is already in progress, we need to queue the next command until
537 // the user has responded or a timeout expired.
538 if (!isCmdInteractive(cmdMsg)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700539 handleCmd(cmdMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800540 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700541 if (!mStkContext[slotId].mCmdInProgress) {
542 mStkContext[slotId].mCmdInProgress = true;
543 handleCmd((CatCmdMessage) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800544 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700545 CatLog.d(LOG_TAG, "[Interactive][in progress]");
546 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
547 (CatCmdMessage) msg.obj, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800548 }
549 }
550 break;
551 case OP_RESPONSE:
Preeti Ahuja414bc412013-06-25 19:31:49 -0700552 handleCmdResponse((Bundle) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800553 // call delayed commands if needed.
Wink Savillee68857d2014-10-17 15:23:05 -0700554 if (mStkContext[slotId].mCmdsQ.size() != 0) {
555 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800556 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700557 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800558 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800559 break;
560 case OP_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700561 if (!mStkContext[slotId].mCmdInProgress) {
562 mStkContext[slotId].mCmdInProgress = true;
563 handleSessionEnd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800564 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700565 mStkContext[slotId].mCmdsQ.addLast(
566 new DelayedCmd(OP_END_SESSION, null, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800567 }
568 break;
569 case OP_BOOT_COMPLETED:
Wink Savillee68857d2014-10-17 15:23:05 -0700570 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
571 int i = 0;
572 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
573 if (mStkContext[i].mMainCmd != null) {
574 break;
575 }
576 }
577 if (i == mSimCount) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800578 StkAppInstaller.unInstall(mContext);
579 }
580 break;
581 case OP_DELAYED_MSG:
Wink Savillee68857d2014-10-17 15:23:05 -0700582 handleDelayedCmd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800583 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700584 case OP_CARD_STATUS_CHANGED:
Wink Savillee68857d2014-10-17 15:23:05 -0700585 CatLog.d(LOG_TAG, "Card/Icc Status change received");
586 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
587 break;
588 case OP_SET_ACT_INST:
589 Activity act = new Activity();
590 act = (Activity) msg.obj;
591 CatLog.d(LOG_TAG, "Set activity instance. " + act);
592 mStkContext[slotId].mActivityInstance = act;
593 break;
594 case OP_SET_DAL_INST:
595 Activity dal = new Activity();
596 CatLog.d(LOG_TAG, "Set dialog instance. " + dal);
597 dal = (Activity) msg.obj;
598 mStkContext[slotId].mDialogInstance = dal;
599 break;
600 case OP_SET_MAINACT_INST:
601 Activity mainAct = new Activity();
602 mainAct = (Activity) msg.obj;
603 CatLog.d(LOG_TAG, "Set activity instance. " + mainAct);
604 mStkContext[slotId].mMainActivityInstance = mainAct;
Wink Saville94e982b2014-07-11 07:38:14 -0700605 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700606 case OP_LOCALE_CHANGED:
607 CatLog.d(this, "Locale Changed");
608 checkForSetupEvent(LANGUAGE_SELECTION_EVENT,(Bundle) msg.obj, slotId);
609 break;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530610 case OP_ALPHA_NOTIFY:
611 handleAlphaNotify((Bundle) msg.obj);
612 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700613 }
614 }
615
Wink Savillee68857d2014-10-17 15:23:05 -0700616 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
Wink Saville94e982b2014-07-11 07:38:14 -0700617 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
618
Wink Savillee68857d2014-10-17 15:23:05 -0700619 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
Wink Saville94e982b2014-07-11 07:38:14 -0700620 if (cardStatus == false) {
Wink Savillee68857d2014-10-17 15:23:05 -0700621 CatLog.d(LOG_TAG, "CARD is ABSENT");
Wink Saville94e982b2014-07-11 07:38:14 -0700622 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
Wink Savillee68857d2014-10-17 15:23:05 -0700623 mNotificationManager.cancel(getNotificationId(slotId));
624 if (isAllOtherCardsAbsent(slotId)) {
625 CatLog.d(LOG_TAG, "All CARDs are ABSENT");
626 StkAppInstaller.unInstall(mContext);
627 stopSelf();
628 }
Wink Saville94e982b2014-07-11 07:38:14 -0700629 } else {
630 IccRefreshResponse state = new IccRefreshResponse();
631 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
632
Wink Savillee68857d2014-10-17 15:23:05 -0700633 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
Wink Saville94e982b2014-07-11 07:38:14 -0700634 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
635 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
636 // Clear Idle Text
Wink Savillee68857d2014-10-17 15:23:05 -0700637 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville94e982b2014-07-11 07:38:14 -0700638 }
639
640 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
641 // Uninstall STkmenu
Wink Savillee68857d2014-10-17 15:23:05 -0700642 if (isAllOtherCardsAbsent(slotId)) {
643 StkAppInstaller.unInstall(mContext);
644 }
645 mStkContext[slotId].mCurrentMenu = null;
646 mStkContext[slotId].mMainCmd = null;
Wink Saville94e982b2014-07-11 07:38:14 -0700647 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800648 }
649 }
650 }
Wink Savillee68857d2014-10-17 15:23:05 -0700651 /*
652 * Check if all SIMs are absent except the id of slot equals "slotId".
653 */
654 private boolean isAllOtherCardsAbsent(int slotId) {
655 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
656 Context.TELEPHONY_SERVICE);
657 int i = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800658
Wink Savillee68857d2014-10-17 15:23:05 -0700659 for (i = 0; i < mSimCount; i++) {
660 if (i != slotId && mTm.hasIccCard(i)) {
661 break;
662 }
663 }
664 if (i == mSimCount) {
665 return true;
666 } else {
667 return false;
668 }
669 }
Preeti Ahuja95919342013-10-01 18:18:55 -0700670
Preeti Ahuja95919342013-10-01 18:18:55 -0700671 private void sendResponse(int resId, int slotId, boolean confirm) {
672 Message msg = mServiceHandler.obtainMessage();
673 msg.arg1 = OP_RESPONSE;
674 Bundle args = new Bundle();
675 args.putInt(StkAppService.RES_ID, resId);
676 args.putInt(SLOT_ID, slotId);
677 args.putBoolean(StkAppService.CONFIRMATION, confirm);
678 msg.obj = args;
679 mServiceHandler.sendMessage(msg);
680 }
681
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700682 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800683 switch (cmd.getCmdType()) {
684 case SEND_DTMF:
685 case SEND_SMS:
686 case SEND_SS:
687 case SEND_USSD:
688 case SET_UP_IDLE_MODE_TEXT:
689 case SET_UP_MENU:
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500690 case CLOSE_CHANNEL:
691 case RECEIVE_DATA:
692 case SEND_DATA:
Preeti Ahuja95919342013-10-01 18:18:55 -0700693 case SET_UP_EVENT_LIST:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800694 return false;
695 }
696
697 return true;
698 }
699
Wink Savillee68857d2014-10-17 15:23:05 -0700700 private void handleDelayedCmd(int slotId) {
701 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
702 if (mStkContext[slotId].mCmdsQ.size() != 0) {
703 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
704 if (cmd != null) {
705 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
706 mStkContext[slotId].mCmdsQ.size() +
707 " id: " + cmd.id + "sim id: " + cmd.slotId);
708 switch (cmd.id) {
709 case OP_CMD:
710 handleCmd(cmd.msg, cmd.slotId);
711 break;
712 case OP_END_SESSION:
713 handleSessionEnd(cmd.slotId);
714 break;
715 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800716 }
717 }
718 }
719
Wink Savillee68857d2014-10-17 15:23:05 -0700720 private void callDelayedMsg(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800721 Message msg = mServiceHandler.obtainMessage();
722 msg.arg1 = OP_DELAYED_MSG;
Wink Savillee68857d2014-10-17 15:23:05 -0700723 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800724 mServiceHandler.sendMessage(msg);
725 }
726
Wink Savillee68857d2014-10-17 15:23:05 -0700727 private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) {
728 Message msg = mServiceHandler.obtainMessage();
729 msg.obj = obj;
730 msg.arg1 = inst_type;
731 msg.arg2 = slotId;
732 mServiceHandler.sendMessage(msg);
733 }
734
735 private void handleSessionEnd(int slotId) {
736 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
737 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
738 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
739 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
740 mStkContext[slotId].mMenuState);
741
742 mStkContext[slotId].mIsInputPending = false;
743 mStkContext[slotId].mIsMenuPending = false;
744 mStkContext[slotId].mIsDialogPending = false;
745
746 // We should finish all pending activity if receiving END SESSION command.
747 cleanUpInstanceStackBySlot(slotId);
748
749 if (mStkContext[slotId].mMainCmd == null) {
750 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
751 }
752 mStkContext[slotId].lastSelectedItem = null;
Wink Saville79085fc2009-06-09 10:27:23 -0700753 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800754 // update the current menu member.
Wink Savillee68857d2014-10-17 15:23:05 -0700755 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
756 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800757 }
Wink Savillee68857d2014-10-17 15:23:05 -0700758 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
759 // In mutiple instance architecture, the main menu for slotId will be finished when user
760 // goes to the Stk menu of the other SIM. So, we should launch a new instance for the
761 // main menu if the main menu instance has been finished.
762 // If the current menu is secondary menu, we should launch main menu.
763 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
764 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800765 }
Wink Savillee68857d2014-10-17 15:23:05 -0700766 if (mStkContext[slotId].mCmdsQ.size() != 0) {
767 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800768 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700769 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800770 }
771 // In case a launch browser command was just confirmed, launch that url.
Wink Savillee68857d2014-10-17 15:23:05 -0700772 if (mStkContext[slotId].launchBrowser) {
773 mStkContext[slotId].launchBrowser = false;
774 launchBrowser(mStkContext[slotId].mBrowserSettings);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800775 }
776 }
777
Wink Savillee68857d2014-10-17 15:23:05 -0700778 private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700779
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800780 if (cmdMsg == null) {
781 return;
782 }
783 // save local reference for state tracking.
Wink Savillee68857d2014-10-17 15:23:05 -0700784 mStkContext[slotId].mCurrentCmd = cmdMsg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800785 boolean waitForUsersResponse = true;
786
Wink Savillee68857d2014-10-17 15:23:05 -0700787 mStkContext[slotId].mIsInputPending = false;
788 mStkContext[slotId].mIsMenuPending = false;
789 mStkContext[slotId].mIsDialogPending = false;
790
791 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800792 switch (cmdMsg.getCmdType()) {
793 case DISPLAY_TEXT:
794 TextMessage msg = cmdMsg.geTextMessage();
Jeevaka Badrappan854a25c2012-12-01 16:32:03 +0200795 waitForUsersResponse = msg.responseNeeded;
Wink Savillee68857d2014-10-17 15:23:05 -0700796 if (mStkContext[slotId].lastSelectedItem != null) {
797 msg.title = mStkContext[slotId].lastSelectedItem;
798 } else if (mStkContext[slotId].mMainCmd != null){
799 msg.title = mStkContext[slotId].mMainCmd.getMenu().title;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800800 } else {
801 // TODO: get the carrier name from the SIM
802 msg.title = "";
803 }
Preeti Ahujab3d0e612014-11-20 13:29:25 -0800804 launchTextDialog(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800805 break;
806 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700807 CatLog.d(LOG_TAG, "SELECT_ITEM +");
808 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
809 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
810 launchMenuActivity(cmdMsg.getMenu(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800811 break;
812 case SET_UP_MENU:
Wink Savillee68857d2014-10-17 15:23:05 -0700813 mStkContext[slotId].mCmdInProgress = false;
814 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
815 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
816 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
817 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
818
819 if (removeMenu(slotId)) {
820 int i = 0;
821 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App");
822 mStkContext[slotId].mCurrentMenu = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700823 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700824 //Check other setup menu state. If all setup menu are removed, uninstall apk.
825 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
826 if (i != slotId
827 && (mStkContext[slotId].mSetupMenuState == STATE_UNKNOWN
828 || mStkContext[slotId].mSetupMenuState == STATE_EXIST)) {
829 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
830 + mStkContext[slotId].mSetupMenuState);
831 break;
832 }
833 }
834 if (i == mSimCount) {
835 StkAppInstaller.unInstall(mContext);
836 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800837 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700838 CatLog.d(LOG_TAG, "install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800839 StkAppInstaller.install(mContext);
840 }
Wink Savillee68857d2014-10-17 15:23:05 -0700841 if (mStkContext[slotId].mMenuIsVisible) {
842 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800843 }
844 break;
845 case GET_INPUT:
846 case GET_INKEY:
Wink Savillee68857d2014-10-17 15:23:05 -0700847 launchInputActivity(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800848 break;
849 case SET_UP_IDLE_MODE_TEXT:
850 waitForUsersResponse = false;
Preeti Ahujab3d0e612014-11-20 13:29:25 -0800851 launchIdleText(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800852 break;
853 case SEND_DTMF:
854 case SEND_SMS:
855 case SEND_SS:
856 case SEND_USSD:
Preeti Ahuja95919342013-10-01 18:18:55 -0700857 case GET_CHANNEL_STATUS:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800858 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700859 launchEventMessage(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800860 break;
861 case LAUNCH_BROWSER:
Wink Savillee68857d2014-10-17 15:23:05 -0700862 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800863 break;
864 case SET_UP_CALL:
Preeti Ahujadd240102013-08-30 17:25:06 -0700865 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg;
866 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) {
867 mesg.text = getResources().getString(R.string.default_setup_call_msg);
868 }
869 CatLog.d(this, "SET_UP_CALL mesg.text " + mesg.text);
870 launchConfirmationDialog(mesg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800871 break;
872 case PLAY_TONE:
Wink Savillee68857d2014-10-17 15:23:05 -0700873 launchToneDialog(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800874 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500875 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -0700876 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500877 break;
878 case CLOSE_CHANNEL:
879 case RECEIVE_DATA:
880 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -0700881 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500882
883 if ((m != null) && (m.text == null)) {
884 switch(cmdMsg.getCmdType()) {
885 case CLOSE_CHANNEL:
886 m.text = getResources().getString(R.string.default_close_channel_msg);
887 break;
888 case RECEIVE_DATA:
889 m.text = getResources().getString(R.string.default_receive_data_msg);
890 break;
891 case SEND_DATA:
892 m.text = getResources().getString(R.string.default_send_data_msg);
893 break;
894 }
895 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700896 /*
897 * Display indication in the form of a toast to the user if required.
898 */
Wink Savillee68857d2014-10-17 15:23:05 -0700899 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500900 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700901 case SET_UP_EVENT_LIST:
902 mStkContext[slotId].mSetupEventListSettings =
903 mStkContext[slotId].mCurrentCmd.getSetEventList();
904 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
905 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
Preeti Ahuja95919342013-10-01 18:18:55 -0700906 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800907 }
908
909 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -0700910 if (mStkContext[slotId].mCmdsQ.size() != 0) {
911 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800912 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700913 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800914 }
915 }
916 }
917
Wink Savillee68857d2014-10-17 15:23:05 -0700918 private void handleCmdResponse(Bundle args, int slotId) {
919 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
920 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800921 return;
922 }
Wink Savillee68857d2014-10-17 15:23:05 -0700923
924 if (mStkService[slotId] == null) {
925 if(null != UiccController.getInstance() &&
926 null != UiccController.getInstance().getUiccCard(slotId)) {
927 mStkService[slotId] = UiccController.getInstance().getUiccCard(slotId)
928 .getCatService();
929 } else {
930 CatLog.d(LOG_TAG, "Null instance: [" + UiccController.getInstance() +
931 "],["+UiccController.getInstance().getUiccCard(slotId)+"]");
932 }
933 if (mStkService[slotId] == null) {
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -0700934 // This should never happen (we should be responding only to a message
935 // that arrived from StkService). It has to exist by this time
Wink Savillee68857d2014-10-17 15:23:05 -0700936 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response.");
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -0700937 throw new RuntimeException("mStkService is null when we need to send response");
938 }
939 }
940
Wink Savillee68857d2014-10-17 15:23:05 -0700941 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800942
943 // set result code
944 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700945 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800946
947 switch(args.getInt(RES_ID)) {
948 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -0700949 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
950 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800951 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -0700952 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800953 case SET_UP_MENU:
954 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700955 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800956 if (helpRequired) {
957 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
958 } else {
959 resMsg.setResultCode(ResultCode.OK);
960 }
961 resMsg.setMenuSelection(menuSelection);
962 break;
963 }
964 break;
965 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -0700966 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800967 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -0700968 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
969 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800970 boolean yesNoSelection = input
971 .equals(StkInputActivity.YES_STR_RESPONSE);
972 resMsg.setYesNo(yesNoSelection);
973 } else {
974 if (helpRequired) {
975 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
976 } else {
977 resMsg.setResultCode(ResultCode.OK);
978 resMsg.setInput(input);
979 }
980 }
981 break;
982 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700983 CatLog.d(this, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700984 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -0700985 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800986 case DISPLAY_TEXT:
987 resMsg.setResultCode(confirmed ? ResultCode.OK
Preeti Ahuja95919342013-10-01 18:18:55 -0700988 : ResultCode.UICC_SESSION_TERM_BY_USER);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800989 break;
990 case LAUNCH_BROWSER:
991 resMsg.setResultCode(confirmed ? ResultCode.OK
992 : ResultCode.UICC_SESSION_TERM_BY_USER);
993 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -0700994 mStkContext[slotId].launchBrowser = true;
995 mStkContext[slotId].mBrowserSettings =
996 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800997 }
998 break;
999 case SET_UP_CALL:
1000 resMsg.setResultCode(ResultCode.OK);
1001 resMsg.setConfirmation(confirmed);
1002 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001003 launchEventMessage(slotId,
1004 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001005 }
1006 break;
1007 }
1008 break;
1009 case RES_ID_DONE:
1010 resMsg.setResultCode(ResultCode.OK);
1011 break;
1012 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -07001013 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001014 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
1015 break;
1016 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -07001017 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001018 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1019 break;
1020 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001021 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -08001022 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
1023 // Clear message after delay, successful) expects result code OK.
1024 // If the command qualifier specifies no user response is required
1025 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -07001026 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1027 AppInterface.CommandType.DISPLAY_TEXT.value())
1028 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -08001029 resMsg.setResultCode(ResultCode.OK);
1030 } else {
1031 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
1032 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001033 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001034 case RES_ID_CHOICE:
1035 int choice = args.getInt(CHOICE);
1036 CatLog.d(this, "User Choice=" + choice);
1037 switch (choice) {
1038 case YES:
1039 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001040 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001041 break;
1042 case NO:
1043 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
1044 break;
1045 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001046
Wink Savillee68857d2014-10-17 15:23:05 -07001047 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1048 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001049 resMsg.setConfirmation(confirmed);
1050 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001051 break;
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001052
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001053 default:
Wink Savillee68857d2014-10-17 15:23:05 -07001054 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001055 return;
1056 }
Wink Savillee68857d2014-10-17 15:23:05 -07001057
1058 if (null != mStkContext[slotId].mCurrentCmd &&
1059 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1060 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1061 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1062 }
1063 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001064 }
1065
1066 /**
1067 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1068 *
1069 * @param userAction If the userAction is yes then we always return 0 otherwise
1070 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1071 * then we are the foreground app and we'll return 0 as from our perspective a
1072 * user action did cause. If it's false than we aren't the foreground app and
1073 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001074 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001075 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1076 */
Wink Savillee68857d2014-10-17 15:23:05 -07001077 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1078 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1079 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1080 }
1081 /**
1082 * This method is used for cleaning up pending instances in stack.
1083 */
1084 private void cleanUpInstanceStackBySlot(int slotId) {
1085 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1086 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1087 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
1088 if (activity != null) {
1089 CatLog.d(LOG_TAG, "current cmd type: " +
1090 mStkContext[slotId].mCurrentCmd.getCmdType());
1091 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1092 AppInterface.CommandType.GET_INPUT.value() ||
1093 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1094 AppInterface.CommandType.GET_INKEY.value()) {
1095 mStkContext[slotId].mIsInputPending = true;
1096 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1097 AppInterface.CommandType.SET_UP_MENU.value() ||
1098 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1099 AppInterface.CommandType.SELECT_ITEM.value()) {
1100 mStkContext[slotId].mIsMenuPending = true;
1101 } else {
1102 }
1103 CatLog.d(LOG_TAG, "finish pending activity.");
1104 activity.finish();
1105 mStkContext[slotId].mActivityInstance = null;
1106 }
1107 if (dialog != null) {
1108 CatLog.d(LOG_TAG, "finish pending dialog.");
1109 mStkContext[slotId].mIsDialogPending = true;
1110 dialog.finish();
1111 mStkContext[slotId].mDialogInstance = null;
1112 }
1113 }
1114 /**
1115 * This method is used for restoring pending instances from stack.
1116 */
1117 private void restoreInstanceFromStackBySlot(int slotId) {
1118 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1119
1120 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1121 switch(cmdType) {
1122 case GET_INPUT:
1123 case GET_INKEY:
1124 launchInputActivity(slotId);
1125 //Set mMenuIsVisible to true for showing main menu for
1126 //following session end command.
1127 mStkContext[slotId].mMenuIsVisible = true;
1128 break;
1129 case DISPLAY_TEXT:
1130 launchTextDialog(slotId);
1131 break;
1132 case LAUNCH_BROWSER:
1133 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1134 slotId);
1135 break;
1136 case OPEN_CHANNEL:
1137 launchOpenChannelDialog(slotId);
1138 break;
1139 case SET_UP_CALL:
1140 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1141 confirmMsg, slotId);
1142 break;
1143 case SET_UP_MENU:
1144 case SELECT_ITEM:
1145 launchMenuActivity(null, slotId);
1146 break;
1147 default:
1148 break;
1149 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001150 }
1151
Wink Savillee68857d2014-10-17 15:23:05 -07001152 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001153 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001154 String targetActivity = STK_MENU_ACTIVITY_NAME;
1155 String uriString = STK_MENU_URI + System.currentTimeMillis();
1156 //Set unique URI to create a new instance of activity for different slotId.
1157 Uri uriData = Uri.parse(uriString);
1158
1159 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1160 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1161 + mStkContext[slotId].mMenuState);
1162 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1163 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1164
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001165 if (menu == null) {
1166 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001167 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
1168 if (mStkContext[slotId].mOpCode == OP_END_SESSION) {
1169 CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION");
1170 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1171 if (mStkContext[slotId].mMainActivityInstance != null) {
1172 CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null");
1173 return;
1174 }
1175 // If END SESSION is sent that results from the activity is finished by
1176 // stkappservice (line 457), we should igonore to display the stk main menu
1177 // of slot id.
1178 if (mStkContext[slotId].mBackGroundTRSent) {
1179 CatLog.d(LOG_TAG, "launchMenuActivity, ES is triggered by BG.");
1180 mStkContext[slotId].mBackGroundTRSent = false;
1181 return;
1182 }
1183 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001184
Wink Savillee68857d2014-10-17 15:23:05 -07001185 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1186 //Otherwise, it should be "STATE_MAIN".
1187 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1188 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1189 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1190 } else {
1191 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1192 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1193 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001194 } else {
1195 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001196 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001197 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001198 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001199 }
Wink Savillee68857d2014-10-17 15:23:05 -07001200 newIntent.putExtra(SLOT_ID, slotId);
1201 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001202 newIntent.setFlags(intentFlags);
1203 mContext.startActivity(newIntent);
1204 }
1205
Wink Savillee68857d2014-10-17 15:23:05 -07001206 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001207 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001208 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1209 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1210 //Set unique URI to create a new instance of activity for different slotId.
1211 Uri uriData = Uri.parse(uriString);
1212
1213 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001214 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001215 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1216 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1217 newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput());
1218 newIntent.putExtra(SLOT_ID, slotId);
1219 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001220 mContext.startActivity(newIntent);
1221 }
1222
Wink Savillee68857d2014-10-17 15:23:05 -07001223 private void launchTextDialog(int slotId) {
1224 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1225 Intent newIntent = new Intent();
1226 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1227 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1228 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1229 //Set unique URI to create a new instance of activity for different slotId.
1230 Uri uriData = Uri.parse(uriString);
1231 if (newIntent != null) {
1232 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1233 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1234 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1235 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1236 newIntent.setData(uriData);
1237 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1238 newIntent.putExtra(SLOT_ID, slotId);
1239 startActivity(newIntent);
Preeti Ahuja414bc412013-06-25 19:31:49 -07001240 // For display texts with immediate response, send the terminal response
1241 // immediately. responseNeeded will be false, if display text command has
1242 // the immediate response tlv.
1243 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
1244 sendResponse(RES_ID_CONFIRM, slotId, true);
1245 }
Wink Savillee68857d2014-10-17 15:23:05 -07001246 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001247 }
1248
Wink Savillee68857d2014-10-17 15:23:05 -07001249 public boolean isStkDialogActivated(Context context) {
1250 String stkDialogActivity = "com.android.stk.StkDialogActivity";
1251 boolean activated = false;
1252 final ActivityManager am = (ActivityManager) context.getSystemService(
1253 Context.ACTIVITY_SERVICE);
1254 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName();
1255
1256 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity);
1257 if (topActivity.equals(stkDialogActivity)) {
1258 activated = true;
1259 }
1260 CatLog.d(LOG_TAG, "activated : " + activated);
1261 return activated;
Johan Hellman3aec01c2011-02-10 10:15:28 +01001262 }
1263
Preeti Ahuja95919342013-10-01 18:18:55 -07001264 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
Preeti Ahuja414bc412013-06-25 19:31:49 -07001265 CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -07001266
1267 if (mStkContext[slotId].mCurrentSetupEventCmd == null){
1268 CatLog.e(this, "mCurrentSetupEventCmd is null");
1269 return;
1270 }
1271
1272 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd);
1273
1274 resMsg.setResultCode(ResultCode.OK);
1275 resMsg.setEventDownload(event, addedInfo);
1276
1277 mStkService[slotId].onCmdResponse(resMsg);
1278 }
1279
1280 private void checkForSetupEvent(int event, Bundle args, int slotId) {
1281 boolean eventPresent = false;
1282 byte[] addedInfo = null;
1283 CatLog.d(this, "Event :" + event);
1284
1285 if (mStkContext[slotId].mSetupEventListSettings != null) {
1286 /* Checks if the event is present in the EventList updated by last
1287 * SetupEventList Proactive Command */
1288 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) {
1289 if (event == i) {
1290 eventPresent = true;
1291 break;
1292 }
1293 }
1294
1295 /* If Event is present send the response to ICC */
1296 if (eventPresent == true) {
1297 CatLog.d(this, " Event " + event + "exists in the EventList");
1298
1299 switch (event) {
Preeti Ahuja95919342013-10-01 18:18:55 -07001300 case LANGUAGE_SELECTION_EVENT:
1301 String language = mContext
1302 .getResources().getConfiguration().locale.getLanguage();
1303 CatLog.d(this, "language: " + language);
1304 // Each language code is a pair of alpha-numeric characters.
1305 // Each alpha-numeric character shall be coded on one byte
1306 // using the SMS default 7-bit coded alphabet
1307 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language);
1308 sendSetUpEventResponse(event, addedInfo, slotId);
1309 break;
1310 default:
1311 break;
1312 }
1313 } else {
1314 CatLog.e(this, " Event does not exist in the EventList");
1315 }
1316 } else {
1317 CatLog.e(this, "SetupEventList is not received. Ignoring the event: " + event);
1318 }
1319 }
1320
1321 private void removeSetUpEvent(int event, int slotId) {
1322 CatLog.d(this, "Remove Event :" + event);
1323
1324 if (mStkContext[slotId].mSetupEventListSettings != null) {
1325 /*
1326 * Make new Eventlist without the event
1327 */
1328 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
1329 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
1330 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
1331 break;
1332 }
1333 }
1334 }
1335 }
1336
1337 private void launchEventMessage(int slotId) {
1338 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
1339 }
1340
Wink Savillee68857d2014-10-17 15:23:05 -07001341 private void launchEventMessage(int slotId, TextMessage msg) {
1342 if (msg == null || (msg.text != null && msg.text.length() == 0)) {
1343 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001344 return;
1345 }
Wink Savillee68857d2014-10-17 15:23:05 -07001346
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001347 Toast toast = new Toast(mContext.getApplicationContext());
1348 LayoutInflater inflate = (LayoutInflater) mContext
1349 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1350 View v = inflate.inflate(R.layout.stk_event_msg, null);
1351 TextView tv = (TextView) v
1352 .findViewById(com.android.internal.R.id.message);
1353 ImageView iv = (ImageView) v
1354 .findViewById(com.android.internal.R.id.icon);
1355 if (msg.icon != null) {
1356 iv.setImageBitmap(msg.icon);
1357 } else {
1358 iv.setVisibility(View.GONE);
1359 }
1360 if (!msg.iconSelfExplanatory) {
1361 tv.setText(msg.text);
1362 }
1363
1364 toast.setView(v);
1365 toast.setDuration(Toast.LENGTH_LONG);
1366 toast.setGravity(Gravity.BOTTOM, 0, 0);
1367 toast.show();
1368 }
1369
Wink Savillee68857d2014-10-17 15:23:05 -07001370 private void launchConfirmationDialog(TextMessage msg, int slotId) {
1371 msg.title = mStkContext[slotId].lastSelectedItem;
1372 Intent newIntent = new Intent();
1373 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1374 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1375 //Set unique URI to create a new instance of activity for different slotId.
1376 Uri uriData = Uri.parse(uriString);
1377
1378 if (newIntent != null) {
1379 newIntent.setClassName(this, targetActivity);
1380 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1381 | Intent.FLAG_ACTIVITY_NO_HISTORY
1382 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1383 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1384 newIntent.putExtra("TEXT", msg);
1385 newIntent.putExtra(SLOT_ID, slotId);
1386 newIntent.setData(uriData);
1387 startActivity(newIntent);
1388 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001389 }
1390
1391 private void launchBrowser(BrowserSettings settings) {
1392 if (settings == null) {
1393 return;
1394 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001395
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001396 Intent intent = null;
1397 Uri data = null;
David Brown7c03cfe2011-10-20 15:36:12 -07001398
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001399 if (settings.url != null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001400 CatLog.d(LOG_TAG, "settings.url = " + settings.url);
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001401 if ((settings.url.startsWith("http://") || (settings.url.startsWith("https://")))) {
dujin.cha486c1d02011-11-02 22:14:25 +09001402 data = Uri.parse(settings.url);
1403 } else {
1404 String modifiedUrl = "http://" + settings.url;
Wink Savillee68857d2014-10-17 15:23:05 -07001405 CatLog.d(LOG_TAG, "modifiedUrl = " + modifiedUrl);
dujin.cha486c1d02011-11-02 22:14:25 +09001406 data = Uri.parse(modifiedUrl);
1407 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001408 }
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001409 if (data != null) {
1410 intent = new Intent(Intent.ACTION_VIEW);
1411 intent.setData(data);
1412 } else {
1413 // if the command did not contain a URL,
1414 // launch the browser to the default homepage.
Wink Savillee68857d2014-10-17 15:23:05 -07001415 CatLog.d(LOG_TAG, "launch browser with default URL ");
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001416 intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
1417 Intent.CATEGORY_APP_BROWSER);
1418 }
David Brown7c03cfe2011-10-20 15:36:12 -07001419
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001420 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1421 switch (settings.mode) {
1422 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001423 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1424 break;
1425 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001426 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
1427 break;
1428 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
1429 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1430 break;
1431 }
1432 // start browser activity
1433 startActivity(intent);
1434 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07001435 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001436 // followed immediately.
1437 try {
1438 Thread.sleep(10000);
1439 } catch (InterruptedException e) {}
1440 }
1441
Wink Savillee68857d2014-10-17 15:23:05 -07001442 private void launchIdleText(int slotId) {
Preeti Ahujab3d0e612014-11-20 13:29:25 -08001443 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001444
Preeti Ahuja95919342013-10-01 18:18:55 -07001445 if (msg == null || msg.text ==null) {
1446 CatLog.d(LOG_TAG, msg == null ? "mCurrent.getTextMessage is NULL"
1447 : "mCurrent.getTextMessage.text is NULL");
Wink Savillee68857d2014-10-17 15:23:05 -07001448 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville046db4b2011-11-01 20:42:54 -07001449 return;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001450 } else {
Preeti Ahuja95919342013-10-01 18:18:55 -07001451 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
1452 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
1453 + "] icon[" + msg.icon + "], sim id: " + slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001454 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001455 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001456 new Intent(mContext, StkAppService.class), 0);
1457
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001458 final Notification.Builder notificationBuilder = new Notification.Builder(
1459 StkAppService.this);
Wink Savillee68857d2014-10-17 15:23:05 -07001460 if (mStkContext[slotId].mMainCmd != null &&
1461 mStkContext[slotId].mMainCmd.getMenu() != null) {
1462 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001463 } else {
1464 notificationBuilder.setContentTitle("");
1465 }
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001466 notificationBuilder
1467 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1468 notificationBuilder.setContentIntent(pendingIntent);
1469 notificationBuilder.setOngoing(true);
1470 // Set text and icon for the status bar and notification body.
1471 if (!msg.iconSelfExplanatory) {
1472 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001473 notificationBuilder.setTicker(msg.text);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001474 }
1475 if (msg.icon != null) {
1476 notificationBuilder.setLargeIcon(msg.icon);
1477 } else {
1478 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
1479 .getResources().getSystem(),
1480 com.android.internal.R.drawable.stat_notify_sim_toolkit);
1481 notificationBuilder.setLargeIcon(bitmapIcon);
1482 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02001483 notificationBuilder.setColor(mContext.getResources().getColor(
1484 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07001485 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001486 }
1487 }
1488
Wink Savillee68857d2014-10-17 15:23:05 -07001489 private void launchToneDialog(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001490 Intent newIntent = new Intent(this, ToneDialog.class);
Wink Savillee68857d2014-10-17 15:23:05 -07001491 String uriString = STK_TONE_URI + slotId;
1492 Uri uriData = Uri.parse(uriString);
1493 //Set unique URI to create a new instance of activity for different slotId.
1494 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001495 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1496 | Intent.FLAG_ACTIVITY_NO_HISTORY
1497 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Wink Savillee68857d2014-10-17 15:23:05 -07001498 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1499 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1500 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
1501 newIntent.putExtra(SLOT_ID, slotId);
1502 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001503 startActivity(newIntent);
1504 }
1505
Wink Savillee68857d2014-10-17 15:23:05 -07001506 private void launchOpenChannelDialog(int slotId) {
1507 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001508 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001509 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001510 return;
1511 }
1512
1513 msg.title = getResources().getString(R.string.stk_dialog_title);
1514 if (msg.text == null) {
1515 msg.text = getResources().getString(R.string.default_open_channel_msg);
1516 }
1517
1518 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1519 .setIconAttribute(android.R.attr.alertDialogIcon)
1520 .setTitle(msg.title)
1521 .setMessage(msg.text)
1522 .setCancelable(false)
1523 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
1524 new DialogInterface.OnClickListener() {
1525 public void onClick(DialogInterface dialog, int which) {
1526 Bundle args = new Bundle();
1527 args.putInt(RES_ID, RES_ID_CHOICE);
1528 args.putInt(CHOICE, YES);
1529 Message message = mServiceHandler.obtainMessage();
1530 message.arg1 = OP_RESPONSE;
1531 message.obj = args;
1532 mServiceHandler.sendMessage(message);
1533 }
1534 })
1535 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
1536 new DialogInterface.OnClickListener() {
1537 public void onClick(DialogInterface dialog, int which) {
1538 Bundle args = new Bundle();
1539 args.putInt(RES_ID, RES_ID_CHOICE);
1540 args.putInt(CHOICE, NO);
1541 Message message = mServiceHandler.obtainMessage();
1542 message.arg1 = OP_RESPONSE;
1543 message.obj = args;
1544 mServiceHandler.sendMessage(message);
1545 }
1546 })
1547 .create();
1548
1549 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1550 if (!mContext.getResources().getBoolean(
1551 com.android.internal.R.bool.config_sf_slowBlur)) {
1552 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1553 }
1554
1555 dialog.show();
1556 }
1557
Wink Savillee68857d2014-10-17 15:23:05 -07001558 private void launchTransientEventMessage(int slotId) {
1559 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001560 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001561 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001562 return;
1563 }
1564
1565 msg.title = getResources().getString(R.string.stk_dialog_title);
1566
1567 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1568 .setIconAttribute(android.R.attr.alertDialogIcon)
1569 .setTitle(msg.title)
1570 .setMessage(msg.text)
1571 .setCancelable(false)
1572 .setPositiveButton(getResources().getString(android.R.string.ok),
1573 new DialogInterface.OnClickListener() {
1574 public void onClick(DialogInterface dialog, int which) {
1575 }
1576 })
1577 .create();
1578
1579 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1580 if (!mContext.getResources().getBoolean(
1581 com.android.internal.R.bool.config_sf_slowBlur)) {
1582 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1583 }
1584
1585 dialog.show();
1586 }
1587
Wink Savillee68857d2014-10-17 15:23:05 -07001588 private int getNotificationId(int slotId) {
1589 int notifyId = STK_NOTIFICATION_ID;
1590 if (slotId >= 0 && slotId < mSimCount) {
1591 notifyId += slotId;
1592 } else {
1593 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1594 }
1595 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
1596 return notifyId;
1597 }
1598
1599 private String getItemName(int itemId, int slotId) {
1600 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001601 if (menu == null) {
1602 return null;
1603 }
1604 for (Item item : menu.items) {
1605 if (item.id == itemId) {
1606 return item.text;
1607 }
1608 }
1609 return null;
1610 }
1611
Wink Savillee68857d2014-10-17 15:23:05 -07001612 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001613 try {
Wink Savillee68857d2014-10-17 15:23:05 -07001614 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
1615 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
1616 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001617 return true;
1618 }
1619 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07001620 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
1621 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001622 return true;
1623 }
Wink Savillee68857d2014-10-17 15:23:05 -07001624 mStkContext[slotId].mSetupMenuState = STATE_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001625 return false;
1626 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301627
Wink Savillee68857d2014-10-17 15:23:05 -07001628 StkContext getStkContext(int slotId) {
1629 if (slotId >= 0 && slotId < mSimCount) {
1630 return mStkContext[slotId];
1631 } else {
1632 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1633 return null;
1634 }
1635 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301636
1637 private void handleAlphaNotify(Bundle args) {
1638 String alphaString = args.getString(AppInterface.ALPHA_STRING);
1639
1640 CatLog.d(this, "Alpha string received from card: " + alphaString);
1641 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
1642 toast.setGravity(Gravity.TOP, 0, 0);
1643 toast.show();
1644 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001645}