blob: 1bff98e8e91bcb944bc8d86467c840e631000e78 [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:
Wink Savillee68857d2014-10-17 15:23:05 -0700865 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings()
866 .confirmMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800867 break;
868 case PLAY_TONE:
Wink Savillee68857d2014-10-17 15:23:05 -0700869 launchToneDialog(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800870 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500871 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -0700872 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500873 break;
874 case CLOSE_CHANNEL:
875 case RECEIVE_DATA:
876 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -0700877 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500878
879 if ((m != null) && (m.text == null)) {
880 switch(cmdMsg.getCmdType()) {
881 case CLOSE_CHANNEL:
882 m.text = getResources().getString(R.string.default_close_channel_msg);
883 break;
884 case RECEIVE_DATA:
885 m.text = getResources().getString(R.string.default_receive_data_msg);
886 break;
887 case SEND_DATA:
888 m.text = getResources().getString(R.string.default_send_data_msg);
889 break;
890 }
891 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700892 /*
893 * Display indication in the form of a toast to the user if required.
894 */
Wink Savillee68857d2014-10-17 15:23:05 -0700895 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500896 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700897 case SET_UP_EVENT_LIST:
898 mStkContext[slotId].mSetupEventListSettings =
899 mStkContext[slotId].mCurrentCmd.getSetEventList();
900 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
901 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
Preeti Ahuja95919342013-10-01 18:18:55 -0700902 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800903 }
904
905 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -0700906 if (mStkContext[slotId].mCmdsQ.size() != 0) {
907 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800908 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700909 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800910 }
911 }
912 }
913
Wink Savillee68857d2014-10-17 15:23:05 -0700914 private void handleCmdResponse(Bundle args, int slotId) {
915 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
916 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800917 return;
918 }
Wink Savillee68857d2014-10-17 15:23:05 -0700919
920 if (mStkService[slotId] == null) {
921 if(null != UiccController.getInstance() &&
922 null != UiccController.getInstance().getUiccCard(slotId)) {
923 mStkService[slotId] = UiccController.getInstance().getUiccCard(slotId)
924 .getCatService();
925 } else {
926 CatLog.d(LOG_TAG, "Null instance: [" + UiccController.getInstance() +
927 "],["+UiccController.getInstance().getUiccCard(slotId)+"]");
928 }
929 if (mStkService[slotId] == null) {
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -0700930 // This should never happen (we should be responding only to a message
931 // that arrived from StkService). It has to exist by this time
Wink Savillee68857d2014-10-17 15:23:05 -0700932 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response.");
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -0700933 throw new RuntimeException("mStkService is null when we need to send response");
934 }
935 }
936
Wink Savillee68857d2014-10-17 15:23:05 -0700937 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800938
939 // set result code
940 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700941 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800942
943 switch(args.getInt(RES_ID)) {
944 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -0700945 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
946 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800947 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -0700948 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800949 case SET_UP_MENU:
950 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700951 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800952 if (helpRequired) {
953 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
954 } else {
955 resMsg.setResultCode(ResultCode.OK);
956 }
957 resMsg.setMenuSelection(menuSelection);
958 break;
959 }
960 break;
961 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -0700962 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800963 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -0700964 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
965 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800966 boolean yesNoSelection = input
967 .equals(StkInputActivity.YES_STR_RESPONSE);
968 resMsg.setYesNo(yesNoSelection);
969 } else {
970 if (helpRequired) {
971 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
972 } else {
973 resMsg.setResultCode(ResultCode.OK);
974 resMsg.setInput(input);
975 }
976 }
977 break;
978 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700979 CatLog.d(this, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700980 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -0700981 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800982 case DISPLAY_TEXT:
983 resMsg.setResultCode(confirmed ? ResultCode.OK
Preeti Ahuja95919342013-10-01 18:18:55 -0700984 : ResultCode.UICC_SESSION_TERM_BY_USER);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800985 break;
986 case LAUNCH_BROWSER:
987 resMsg.setResultCode(confirmed ? ResultCode.OK
988 : ResultCode.UICC_SESSION_TERM_BY_USER);
989 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -0700990 mStkContext[slotId].launchBrowser = true;
991 mStkContext[slotId].mBrowserSettings =
992 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800993 }
994 break;
995 case SET_UP_CALL:
996 resMsg.setResultCode(ResultCode.OK);
997 resMsg.setConfirmation(confirmed);
998 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -0700999 launchEventMessage(slotId,
1000 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001001 }
1002 break;
1003 }
1004 break;
1005 case RES_ID_DONE:
1006 resMsg.setResultCode(ResultCode.OK);
1007 break;
1008 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -07001009 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001010 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
1011 break;
1012 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -07001013 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001014 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1015 break;
1016 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001017 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -08001018 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
1019 // Clear message after delay, successful) expects result code OK.
1020 // If the command qualifier specifies no user response is required
1021 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -07001022 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1023 AppInterface.CommandType.DISPLAY_TEXT.value())
1024 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -08001025 resMsg.setResultCode(ResultCode.OK);
1026 } else {
1027 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
1028 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001029 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001030 case RES_ID_CHOICE:
1031 int choice = args.getInt(CHOICE);
1032 CatLog.d(this, "User Choice=" + choice);
1033 switch (choice) {
1034 case YES:
1035 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001036 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001037 break;
1038 case NO:
1039 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
1040 break;
1041 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001042
Wink Savillee68857d2014-10-17 15:23:05 -07001043 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1044 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001045 resMsg.setConfirmation(confirmed);
1046 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001047 break;
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001048
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001049 default:
Wink Savillee68857d2014-10-17 15:23:05 -07001050 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001051 return;
1052 }
Wink Savillee68857d2014-10-17 15:23:05 -07001053
1054 if (null != mStkContext[slotId].mCurrentCmd &&
1055 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1056 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1057 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1058 }
1059 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001060 }
1061
1062 /**
1063 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1064 *
1065 * @param userAction If the userAction is yes then we always return 0 otherwise
1066 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1067 * then we are the foreground app and we'll return 0 as from our perspective a
1068 * user action did cause. If it's false than we aren't the foreground app and
1069 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001070 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001071 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1072 */
Wink Savillee68857d2014-10-17 15:23:05 -07001073 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1074 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1075 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1076 }
1077 /**
1078 * This method is used for cleaning up pending instances in stack.
1079 */
1080 private void cleanUpInstanceStackBySlot(int slotId) {
1081 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1082 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1083 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
1084 if (activity != null) {
1085 CatLog.d(LOG_TAG, "current cmd type: " +
1086 mStkContext[slotId].mCurrentCmd.getCmdType());
1087 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1088 AppInterface.CommandType.GET_INPUT.value() ||
1089 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1090 AppInterface.CommandType.GET_INKEY.value()) {
1091 mStkContext[slotId].mIsInputPending = true;
1092 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1093 AppInterface.CommandType.SET_UP_MENU.value() ||
1094 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1095 AppInterface.CommandType.SELECT_ITEM.value()) {
1096 mStkContext[slotId].mIsMenuPending = true;
1097 } else {
1098 }
1099 CatLog.d(LOG_TAG, "finish pending activity.");
1100 activity.finish();
1101 mStkContext[slotId].mActivityInstance = null;
1102 }
1103 if (dialog != null) {
1104 CatLog.d(LOG_TAG, "finish pending dialog.");
1105 mStkContext[slotId].mIsDialogPending = true;
1106 dialog.finish();
1107 mStkContext[slotId].mDialogInstance = null;
1108 }
1109 }
1110 /**
1111 * This method is used for restoring pending instances from stack.
1112 */
1113 private void restoreInstanceFromStackBySlot(int slotId) {
1114 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1115
1116 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1117 switch(cmdType) {
1118 case GET_INPUT:
1119 case GET_INKEY:
1120 launchInputActivity(slotId);
1121 //Set mMenuIsVisible to true for showing main menu for
1122 //following session end command.
1123 mStkContext[slotId].mMenuIsVisible = true;
1124 break;
1125 case DISPLAY_TEXT:
1126 launchTextDialog(slotId);
1127 break;
1128 case LAUNCH_BROWSER:
1129 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1130 slotId);
1131 break;
1132 case OPEN_CHANNEL:
1133 launchOpenChannelDialog(slotId);
1134 break;
1135 case SET_UP_CALL:
1136 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1137 confirmMsg, slotId);
1138 break;
1139 case SET_UP_MENU:
1140 case SELECT_ITEM:
1141 launchMenuActivity(null, slotId);
1142 break;
1143 default:
1144 break;
1145 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001146 }
1147
Wink Savillee68857d2014-10-17 15:23:05 -07001148 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001149 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001150 String targetActivity = STK_MENU_ACTIVITY_NAME;
1151 String uriString = STK_MENU_URI + System.currentTimeMillis();
1152 //Set unique URI to create a new instance of activity for different slotId.
1153 Uri uriData = Uri.parse(uriString);
1154
1155 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1156 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1157 + mStkContext[slotId].mMenuState);
1158 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1159 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1160
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001161 if (menu == null) {
1162 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001163 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
1164 if (mStkContext[slotId].mOpCode == OP_END_SESSION) {
1165 CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION");
1166 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1167 if (mStkContext[slotId].mMainActivityInstance != null) {
1168 CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null");
1169 return;
1170 }
1171 // If END SESSION is sent that results from the activity is finished by
1172 // stkappservice (line 457), we should igonore to display the stk main menu
1173 // of slot id.
1174 if (mStkContext[slotId].mBackGroundTRSent) {
1175 CatLog.d(LOG_TAG, "launchMenuActivity, ES is triggered by BG.");
1176 mStkContext[slotId].mBackGroundTRSent = false;
1177 return;
1178 }
1179 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001180
Wink Savillee68857d2014-10-17 15:23:05 -07001181 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1182 //Otherwise, it should be "STATE_MAIN".
1183 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1184 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1185 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1186 } else {
1187 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1188 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1189 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001190 } else {
1191 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001192 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001193 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001194 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001195 }
Wink Savillee68857d2014-10-17 15:23:05 -07001196 newIntent.putExtra(SLOT_ID, slotId);
1197 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001198 newIntent.setFlags(intentFlags);
1199 mContext.startActivity(newIntent);
1200 }
1201
Wink Savillee68857d2014-10-17 15:23:05 -07001202 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001203 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001204 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1205 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1206 //Set unique URI to create a new instance of activity for different slotId.
1207 Uri uriData = Uri.parse(uriString);
1208
1209 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001210 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001211 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1212 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1213 newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput());
1214 newIntent.putExtra(SLOT_ID, slotId);
1215 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001216 mContext.startActivity(newIntent);
1217 }
1218
Wink Savillee68857d2014-10-17 15:23:05 -07001219 private void launchTextDialog(int slotId) {
1220 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1221 Intent newIntent = new Intent();
1222 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1223 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1224 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1225 //Set unique URI to create a new instance of activity for different slotId.
1226 Uri uriData = Uri.parse(uriString);
1227 if (newIntent != null) {
1228 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1229 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1230 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1231 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1232 newIntent.setData(uriData);
1233 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1234 newIntent.putExtra(SLOT_ID, slotId);
1235 startActivity(newIntent);
Preeti Ahuja414bc412013-06-25 19:31:49 -07001236 // For display texts with immediate response, send the terminal response
1237 // immediately. responseNeeded will be false, if display text command has
1238 // the immediate response tlv.
1239 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
1240 sendResponse(RES_ID_CONFIRM, slotId, true);
1241 }
Wink Savillee68857d2014-10-17 15:23:05 -07001242 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001243 }
1244
Wink Savillee68857d2014-10-17 15:23:05 -07001245 public boolean isStkDialogActivated(Context context) {
1246 String stkDialogActivity = "com.android.stk.StkDialogActivity";
1247 boolean activated = false;
1248 final ActivityManager am = (ActivityManager) context.getSystemService(
1249 Context.ACTIVITY_SERVICE);
1250 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName();
1251
1252 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity);
1253 if (topActivity.equals(stkDialogActivity)) {
1254 activated = true;
1255 }
1256 CatLog.d(LOG_TAG, "activated : " + activated);
1257 return activated;
Johan Hellman3aec01c2011-02-10 10:15:28 +01001258 }
1259
Preeti Ahuja95919342013-10-01 18:18:55 -07001260 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
Preeti Ahuja414bc412013-06-25 19:31:49 -07001261 CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -07001262
1263 if (mStkContext[slotId].mCurrentSetupEventCmd == null){
1264 CatLog.e(this, "mCurrentSetupEventCmd is null");
1265 return;
1266 }
1267
1268 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd);
1269
1270 resMsg.setResultCode(ResultCode.OK);
1271 resMsg.setEventDownload(event, addedInfo);
1272
1273 mStkService[slotId].onCmdResponse(resMsg);
1274 }
1275
1276 private void checkForSetupEvent(int event, Bundle args, int slotId) {
1277 boolean eventPresent = false;
1278 byte[] addedInfo = null;
1279 CatLog.d(this, "Event :" + event);
1280
1281 if (mStkContext[slotId].mSetupEventListSettings != null) {
1282 /* Checks if the event is present in the EventList updated by last
1283 * SetupEventList Proactive Command */
1284 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) {
1285 if (event == i) {
1286 eventPresent = true;
1287 break;
1288 }
1289 }
1290
1291 /* If Event is present send the response to ICC */
1292 if (eventPresent == true) {
1293 CatLog.d(this, " Event " + event + "exists in the EventList");
1294
1295 switch (event) {
Preeti Ahuja95919342013-10-01 18:18:55 -07001296 case LANGUAGE_SELECTION_EVENT:
1297 String language = mContext
1298 .getResources().getConfiguration().locale.getLanguage();
1299 CatLog.d(this, "language: " + language);
1300 // Each language code is a pair of alpha-numeric characters.
1301 // Each alpha-numeric character shall be coded on one byte
1302 // using the SMS default 7-bit coded alphabet
1303 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language);
1304 sendSetUpEventResponse(event, addedInfo, slotId);
1305 break;
1306 default:
1307 break;
1308 }
1309 } else {
1310 CatLog.e(this, " Event does not exist in the EventList");
1311 }
1312 } else {
1313 CatLog.e(this, "SetupEventList is not received. Ignoring the event: " + event);
1314 }
1315 }
1316
1317 private void removeSetUpEvent(int event, int slotId) {
1318 CatLog.d(this, "Remove Event :" + event);
1319
1320 if (mStkContext[slotId].mSetupEventListSettings != null) {
1321 /*
1322 * Make new Eventlist without the event
1323 */
1324 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
1325 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
1326 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
1327 break;
1328 }
1329 }
1330 }
1331 }
1332
1333 private void launchEventMessage(int slotId) {
1334 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
1335 }
1336
Wink Savillee68857d2014-10-17 15:23:05 -07001337 private void launchEventMessage(int slotId, TextMessage msg) {
1338 if (msg == null || (msg.text != null && msg.text.length() == 0)) {
1339 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001340 return;
1341 }
Wink Savillee68857d2014-10-17 15:23:05 -07001342
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001343 Toast toast = new Toast(mContext.getApplicationContext());
1344 LayoutInflater inflate = (LayoutInflater) mContext
1345 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1346 View v = inflate.inflate(R.layout.stk_event_msg, null);
1347 TextView tv = (TextView) v
1348 .findViewById(com.android.internal.R.id.message);
1349 ImageView iv = (ImageView) v
1350 .findViewById(com.android.internal.R.id.icon);
1351 if (msg.icon != null) {
1352 iv.setImageBitmap(msg.icon);
1353 } else {
1354 iv.setVisibility(View.GONE);
1355 }
1356 if (!msg.iconSelfExplanatory) {
1357 tv.setText(msg.text);
1358 }
1359
1360 toast.setView(v);
1361 toast.setDuration(Toast.LENGTH_LONG);
1362 toast.setGravity(Gravity.BOTTOM, 0, 0);
1363 toast.show();
1364 }
1365
Wink Savillee68857d2014-10-17 15:23:05 -07001366 private void launchConfirmationDialog(TextMessage msg, int slotId) {
1367 msg.title = mStkContext[slotId].lastSelectedItem;
1368 Intent newIntent = new Intent();
1369 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1370 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1371 //Set unique URI to create a new instance of activity for different slotId.
1372 Uri uriData = Uri.parse(uriString);
1373
1374 if (newIntent != null) {
1375 newIntent.setClassName(this, targetActivity);
1376 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1377 | Intent.FLAG_ACTIVITY_NO_HISTORY
1378 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1379 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1380 newIntent.putExtra("TEXT", msg);
1381 newIntent.putExtra(SLOT_ID, slotId);
1382 newIntent.setData(uriData);
1383 startActivity(newIntent);
1384 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001385 }
1386
1387 private void launchBrowser(BrowserSettings settings) {
1388 if (settings == null) {
1389 return;
1390 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001391
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001392 Intent intent = null;
1393 Uri data = null;
David Brown7c03cfe2011-10-20 15:36:12 -07001394
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001395 if (settings.url != null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001396 CatLog.d(LOG_TAG, "settings.url = " + settings.url);
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001397 if ((settings.url.startsWith("http://") || (settings.url.startsWith("https://")))) {
dujin.cha486c1d02011-11-02 22:14:25 +09001398 data = Uri.parse(settings.url);
1399 } else {
1400 String modifiedUrl = "http://" + settings.url;
Wink Savillee68857d2014-10-17 15:23:05 -07001401 CatLog.d(LOG_TAG, "modifiedUrl = " + modifiedUrl);
dujin.cha486c1d02011-11-02 22:14:25 +09001402 data = Uri.parse(modifiedUrl);
1403 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001404 }
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001405 if (data != null) {
1406 intent = new Intent(Intent.ACTION_VIEW);
1407 intent.setData(data);
1408 } else {
1409 // if the command did not contain a URL,
1410 // launch the browser to the default homepage.
Wink Savillee68857d2014-10-17 15:23:05 -07001411 CatLog.d(LOG_TAG, "launch browser with default URL ");
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001412 intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
1413 Intent.CATEGORY_APP_BROWSER);
1414 }
David Brown7c03cfe2011-10-20 15:36:12 -07001415
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001416 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1417 switch (settings.mode) {
1418 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001419 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1420 break;
1421 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001422 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
1423 break;
1424 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
1425 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1426 break;
1427 }
1428 // start browser activity
1429 startActivity(intent);
1430 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07001431 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001432 // followed immediately.
1433 try {
1434 Thread.sleep(10000);
1435 } catch (InterruptedException e) {}
1436 }
1437
Wink Savillee68857d2014-10-17 15:23:05 -07001438 private void launchIdleText(int slotId) {
Preeti Ahujab3d0e612014-11-20 13:29:25 -08001439 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001440
Preeti Ahuja95919342013-10-01 18:18:55 -07001441 if (msg == null || msg.text ==null) {
1442 CatLog.d(LOG_TAG, msg == null ? "mCurrent.getTextMessage is NULL"
1443 : "mCurrent.getTextMessage.text is NULL");
Wink Savillee68857d2014-10-17 15:23:05 -07001444 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville046db4b2011-11-01 20:42:54 -07001445 return;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001446 } else {
Preeti Ahuja95919342013-10-01 18:18:55 -07001447 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
1448 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
1449 + "] icon[" + msg.icon + "], sim id: " + slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001450 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001451 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001452 new Intent(mContext, StkAppService.class), 0);
1453
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001454 final Notification.Builder notificationBuilder = new Notification.Builder(
1455 StkAppService.this);
Wink Savillee68857d2014-10-17 15:23:05 -07001456 if (mStkContext[slotId].mMainCmd != null &&
1457 mStkContext[slotId].mMainCmd.getMenu() != null) {
1458 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001459 } else {
1460 notificationBuilder.setContentTitle("");
1461 }
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001462 notificationBuilder
1463 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1464 notificationBuilder.setContentIntent(pendingIntent);
1465 notificationBuilder.setOngoing(true);
1466 // Set text and icon for the status bar and notification body.
1467 if (!msg.iconSelfExplanatory) {
1468 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001469 notificationBuilder.setTicker(msg.text);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001470 }
1471 if (msg.icon != null) {
1472 notificationBuilder.setLargeIcon(msg.icon);
1473 } else {
1474 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
1475 .getResources().getSystem(),
1476 com.android.internal.R.drawable.stat_notify_sim_toolkit);
1477 notificationBuilder.setLargeIcon(bitmapIcon);
1478 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02001479 notificationBuilder.setColor(mContext.getResources().getColor(
1480 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07001481 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001482 }
1483 }
1484
Wink Savillee68857d2014-10-17 15:23:05 -07001485 private void launchToneDialog(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001486 Intent newIntent = new Intent(this, ToneDialog.class);
Wink Savillee68857d2014-10-17 15:23:05 -07001487 String uriString = STK_TONE_URI + slotId;
1488 Uri uriData = Uri.parse(uriString);
1489 //Set unique URI to create a new instance of activity for different slotId.
1490 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001491 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1492 | Intent.FLAG_ACTIVITY_NO_HISTORY
1493 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Wink Savillee68857d2014-10-17 15:23:05 -07001494 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1495 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1496 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
1497 newIntent.putExtra(SLOT_ID, slotId);
1498 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001499 startActivity(newIntent);
1500 }
1501
Wink Savillee68857d2014-10-17 15:23:05 -07001502 private void launchOpenChannelDialog(int slotId) {
1503 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001504 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001505 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001506 return;
1507 }
1508
1509 msg.title = getResources().getString(R.string.stk_dialog_title);
1510 if (msg.text == null) {
1511 msg.text = getResources().getString(R.string.default_open_channel_msg);
1512 }
1513
1514 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1515 .setIconAttribute(android.R.attr.alertDialogIcon)
1516 .setTitle(msg.title)
1517 .setMessage(msg.text)
1518 .setCancelable(false)
1519 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
1520 new DialogInterface.OnClickListener() {
1521 public void onClick(DialogInterface dialog, int which) {
1522 Bundle args = new Bundle();
1523 args.putInt(RES_ID, RES_ID_CHOICE);
1524 args.putInt(CHOICE, YES);
1525 Message message = mServiceHandler.obtainMessage();
1526 message.arg1 = OP_RESPONSE;
1527 message.obj = args;
1528 mServiceHandler.sendMessage(message);
1529 }
1530 })
1531 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
1532 new DialogInterface.OnClickListener() {
1533 public void onClick(DialogInterface dialog, int which) {
1534 Bundle args = new Bundle();
1535 args.putInt(RES_ID, RES_ID_CHOICE);
1536 args.putInt(CHOICE, NO);
1537 Message message = mServiceHandler.obtainMessage();
1538 message.arg1 = OP_RESPONSE;
1539 message.obj = args;
1540 mServiceHandler.sendMessage(message);
1541 }
1542 })
1543 .create();
1544
1545 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1546 if (!mContext.getResources().getBoolean(
1547 com.android.internal.R.bool.config_sf_slowBlur)) {
1548 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1549 }
1550
1551 dialog.show();
1552 }
1553
Wink Savillee68857d2014-10-17 15:23:05 -07001554 private void launchTransientEventMessage(int slotId) {
1555 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001556 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001557 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001558 return;
1559 }
1560
1561 msg.title = getResources().getString(R.string.stk_dialog_title);
1562
1563 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1564 .setIconAttribute(android.R.attr.alertDialogIcon)
1565 .setTitle(msg.title)
1566 .setMessage(msg.text)
1567 .setCancelable(false)
1568 .setPositiveButton(getResources().getString(android.R.string.ok),
1569 new DialogInterface.OnClickListener() {
1570 public void onClick(DialogInterface dialog, int which) {
1571 }
1572 })
1573 .create();
1574
1575 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1576 if (!mContext.getResources().getBoolean(
1577 com.android.internal.R.bool.config_sf_slowBlur)) {
1578 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1579 }
1580
1581 dialog.show();
1582 }
1583
Wink Savillee68857d2014-10-17 15:23:05 -07001584 private int getNotificationId(int slotId) {
1585 int notifyId = STK_NOTIFICATION_ID;
1586 if (slotId >= 0 && slotId < mSimCount) {
1587 notifyId += slotId;
1588 } else {
1589 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1590 }
1591 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
1592 return notifyId;
1593 }
1594
1595 private String getItemName(int itemId, int slotId) {
1596 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001597 if (menu == null) {
1598 return null;
1599 }
1600 for (Item item : menu.items) {
1601 if (item.id == itemId) {
1602 return item.text;
1603 }
1604 }
1605 return null;
1606 }
1607
Wink Savillee68857d2014-10-17 15:23:05 -07001608 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001609 try {
Wink Savillee68857d2014-10-17 15:23:05 -07001610 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
1611 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
1612 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001613 return true;
1614 }
1615 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07001616 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
1617 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001618 return true;
1619 }
Wink Savillee68857d2014-10-17 15:23:05 -07001620 mStkContext[slotId].mSetupMenuState = STATE_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001621 return false;
1622 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301623
Wink Savillee68857d2014-10-17 15:23:05 -07001624 StkContext getStkContext(int slotId) {
1625 if (slotId >= 0 && slotId < mSimCount) {
1626 return mStkContext[slotId];
1627 } else {
1628 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1629 return null;
1630 }
1631 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301632
1633 private void handleAlphaNotify(Bundle args) {
1634 String alphaString = args.getString(AppInterface.ALPHA_STRING);
1635
1636 CatLog.d(this, "Alpha string received from card: " + alphaString);
1637 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
1638 toast.setGravity(Gravity.TOP, 0, 0);
1639 toast.show();
1640 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001641}