blob: 8c479483c980f51fd402e7b1607a962064f584a8 [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
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050019import android.app.AlertDialog;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080020import android.app.Notification;
21import android.app.NotificationManager;
22import android.app.PendingIntent;
23import android.app.Service;
Wink Savillee68857d2014-10-17 15:23:05 -070024import android.app.Activity;
25import android.app.ActivityManager;
26import android.app.ActivityManager.RecentTaskInfo;
27import android.app.ActivityManager.RunningAppProcessInfo;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080028import android.content.Context;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050029import android.content.DialogInterface;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080030import android.content.Intent;
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +010031import android.graphics.Bitmap;
32import android.graphics.BitmapFactory;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080033import android.net.Uri;
34import android.os.Bundle;
35import android.os.Handler;
36import android.os.IBinder;
37import android.os.Looper;
38import android.os.Message;
Wink Saville56469d52009-04-02 01:37:03 -070039import android.telephony.TelephonyManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080040import android.view.Gravity;
41import android.view.LayoutInflater;
42import android.view.View;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050043import android.view.Window;
44import android.view.WindowManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080045import android.widget.ImageView;
46import android.widget.RemoteViews;
47import android.widget.TextView;
48import android.widget.Toast;
Wink Savillee68857d2014-10-17 15:23:05 -070049import android.content.BroadcastReceiver;
50import android.content.IntentFilter;
51import android.content.pm.ApplicationInfo;
52import android.content.pm.PackageManager.NameNotFoundException;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080053
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070054import com.android.internal.telephony.cat.AppInterface;
55import com.android.internal.telephony.cat.Menu;
56import com.android.internal.telephony.cat.Item;
Pierre Fröjd97503262010-11-08 13:59:36 +010057import com.android.internal.telephony.cat.Input;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070058import com.android.internal.telephony.cat.ResultCode;
59import com.android.internal.telephony.cat.CatCmdMessage;
60import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
61import com.android.internal.telephony.cat.CatLog;
62import com.android.internal.telephony.cat.CatResponseMessage;
63import com.android.internal.telephony.cat.TextMessage;
Wink Saville94e982b2014-07-11 07:38:14 -070064import com.android.internal.telephony.uicc.IccRefreshResponse;
65import com.android.internal.telephony.uicc.IccCardStatus.CardState;
Wink Savillee68857d2014-10-17 15:23:05 -070066import com.android.internal.telephony.PhoneConstants;
67import com.android.internal.telephony.TelephonyIntents;
68import com.android.internal.telephony.IccCardConstants;
69import com.android.internal.telephony.uicc.UiccController;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080070
71import java.util.LinkedList;
Wink Savillee68857d2014-10-17 15:23:05 -070072import java.lang.System;
73import java.util.List;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080074
75/**
76 * SIM toolkit application level service. Interacts with Telephopny messages,
77 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -070078 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080079 */
80public class StkAppService extends Service implements Runnable {
81
82 // members
Wink Savillee68857d2014-10-17 15:23:05 -070083 protected class StkContext {
84 protected CatCmdMessage mMainCmd = null;
85 protected CatCmdMessage mCurrentCmd = null;
86 protected CatCmdMessage mCurrentMenuCmd = null;
87 protected Menu mCurrentMenu = null;
88 protected String lastSelectedItem = null;
89 protected boolean mMenuIsVisible = false;
90 protected boolean mIsInputPending = false;
91 protected boolean mIsMenuPending = false;
92 protected boolean mIsDialogPending = false;
93 protected boolean responseNeeded = true;
94 protected boolean launchBrowser = false;
95 protected BrowserSettings mBrowserSettings = null;
96 protected LinkedList<DelayedCmd> mCmdsQ = null;
97 protected boolean mCmdInProgress = false;
98 protected int mStkServiceState = STATE_UNKNOWN;
99 protected int mSetupMenuState = STATE_UNKNOWN;
100 protected int mMenuState = StkMenuActivity.STATE_INIT;
101 protected int mOpCode = -1;
102 private Activity mActivityInstance = null;
103 private Activity mDialogInstance = null;
104 private Activity mMainActivityInstance = null;
105 private boolean mBackGroundTRSent = false;
106 private int mSlotId = 0;
107 final synchronized void setPendingActivityInstance(Activity act) {
108 CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act);
109 callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
110 }
111 final synchronized Activity getPendingActivityInstance() {
112 CatLog.d(this, "getPendingActivityInstance act : " + mSlotId + ", " +
113 mActivityInstance);
114 return mActivityInstance;
115 }
116 final synchronized void setPendingDialogInstance(Activity act) {
117 CatLog.d(this, "setPendingDialogInstance act : " + mSlotId + ", " + act);
118 callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act);
119 }
120 final synchronized Activity getPendingDialogInstance() {
121 CatLog.d(this, "getPendingDialogInstance act : " + mSlotId + ", " +
122 mDialogInstance);
123 return mDialogInstance;
124 }
125 final synchronized void setMainActivityInstance(Activity act) {
126 CatLog.d(this, "setMainActivityInstance act : " + mSlotId + ", " + act);
127 callSetActivityInstMsg(OP_SET_MAINACT_INST, mSlotId, act);
128 }
129 final synchronized Activity getMainActivityInstance() {
130 CatLog.d(this, "getMainActivityInstance act : " + mSlotId + ", " +
131 mMainActivityInstance);
132 return mMainActivityInstance;
133 }
134 }
135
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800136 private volatile Looper mServiceLooper;
137 private volatile ServiceHandler mServiceHandler;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800138 private Context mContext = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800139 private NotificationManager mNotificationManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800140 static StkAppService sInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700141 private AppInterface[] mStkService = null;
142 private StkContext[] mStkContext = null;
143 private int mSimCount = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800144 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
145 // creating an intent.
146 private enum InitiatedByUserAction {
147 yes, // The action was started via a user initiated action
148 unknown, // Not known for sure if user initated the action
149 }
150
151 // constants
152 static final String OPCODE = "op";
153 static final String CMD_MSG = "cmd message";
154 static final String RES_ID = "response id";
155 static final String MENU_SELECTION = "menu selection";
156 static final String INPUT = "input";
157 static final String HELP = "help";
158 static final String CONFIRMATION = "confirm";
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500159 static final String CHOICE = "choice";
Wink Savillee68857d2014-10-17 15:23:05 -0700160 static final String SLOT_ID = "SLOT_ID";
161 static final String STK_CMD = "STK CMD";
162 static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/";
163 static final String STK_MENU_URI = "stk://com.android.stk/menu/";
164 static final String STK_INPUT_URI = "stk://com.android.stk/input/";
165 static final String STK_TONE_URI = "stk://com.android.stk/tone/";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800166 // operations ids for different service functionality.
167 static final int OP_CMD = 1;
168 static final int OP_RESPONSE = 2;
169 static final int OP_LAUNCH_APP = 3;
170 static final int OP_END_SESSION = 4;
171 static final int OP_BOOT_COMPLETED = 5;
172 private static final int OP_DELAYED_MSG = 6;
Wink Saville94e982b2014-07-11 07:38:14 -0700173 static final int OP_CARD_STATUS_CHANGED = 7;
Wink Savillee68857d2014-10-17 15:23:05 -0700174 static final int OP_SET_ACT_INST = 8;
175 static final int OP_SET_DAL_INST = 9;
176 static final int OP_SET_MAINACT_INST = 10;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530177 static final int OP_ALPHA_NOTIFY = 13;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800178
179 // Response ids
180 static final int RES_ID_MENU_SELECTION = 11;
181 static final int RES_ID_INPUT = 12;
182 static final int RES_ID_CONFIRM = 13;
183 static final int RES_ID_DONE = 14;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500184 static final int RES_ID_CHOICE = 15;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800185
186 static final int RES_ID_TIMEOUT = 20;
187 static final int RES_ID_BACKWARD = 21;
188 static final int RES_ID_END_SESSION = 22;
189 static final int RES_ID_EXIT = 23;
190
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500191 static final int YES = 1;
192 static final int NO = 0;
193
Wink Savillee68857d2014-10-17 15:23:05 -0700194 static final int STATE_UNKNOWN = -1;
195 static final int STATE_NOT_EXIST = 0;
196 static final int STATE_EXIST = 1;
Wink Saville79085fc2009-06-09 10:27:23 -0700197
Wink Savillee68857d2014-10-17 15:23:05 -0700198 private static final String PACKAGE_NAME = "com.android.stk";
199 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
200 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
201 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800202 // Notification id used to display Idle Mode text in NotificationManager.
203 private static final int STK_NOTIFICATION_ID = 333;
Wink Savillee68857d2014-10-17 15:23:05 -0700204 private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
Wink Saville79085fc2009-06-09 10:27:23 -0700205
206 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800207 // session end) while the service is busy processing a previous message.
208 private class DelayedCmd {
209 // members
210 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700211 CatCmdMessage msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700212 int slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800213
Wink Savillee68857d2014-10-17 15:23:05 -0700214 DelayedCmd(int id, CatCmdMessage msg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800215 this.id = id;
216 this.msg = msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700217 this.slotId = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800218 }
219 }
220
221 @Override
222 public void onCreate() {
Wink Savillee68857d2014-10-17 15:23:05 -0700223 CatLog.d(LOG_TAG, "onCreate()+");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800224 // Initialize members
Wink Savillee68857d2014-10-17 15:23:05 -0700225 int i = 0;
226 mContext = getBaseContext();
227 mSimCount = TelephonyManager.from(mContext).getSimCount();
228 CatLog.d(LOG_TAG, "simCount: " + mSimCount);
229 mStkService = new AppInterface[mSimCount];
230 mStkContext = new StkContext[mSimCount];
231 for (i = 0; i < mSimCount; i++) {
232 CatLog.d(LOG_TAG, "slotId: " + i);
233 if (null != UiccController.getInstance() && null != UiccController.getInstance()
234 .getUiccCard(i)) {
235 mStkService[i] = UiccController.getInstance().getUiccCard(i).getCatService();
236 } else {
237 CatLog.d(LOG_TAG, "Null instance: [" + UiccController.getInstance() + "],[" +
238 UiccController.getInstance().getUiccCard(i) + "]");
239 }
240 mStkContext[i] = new StkContext();
241 mStkContext[i].mSlotId = i;
242 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
243 }
244
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800245 Thread serviceThread = new Thread(null, this, "Stk App Service");
246 serviceThread.start();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800247 mNotificationManager = (NotificationManager) mContext
248 .getSystemService(Context.NOTIFICATION_SERVICE);
249 sInstance = this;
250 }
251
252 @Override
253 public void onStart(Intent intent, int startId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700254 if (intent == null) {
255 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530256 return;
257 }
258
Wink Savillee68857d2014-10-17 15:23:05 -0700259 Bundle args = intent.getExtras();
260 if (args == null) {
261 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
262 return;
263 }
264
265 int op = args.getInt(OPCODE);
266 int slotId = 0;
267 int i = 0;
268 if (op != OP_BOOT_COMPLETED) {
269 slotId = args.getInt(SLOT_ID);
270 }
271 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", " + args);
272 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
273 if (null != UiccController.getInstance() && null != UiccController.getInstance()
274 .getUiccCard(slotId)) {
275 mStkService[slotId] = UiccController.getInstance().getUiccCard(slotId)
276 .getCatService();
277 } else {
278 CatLog.d(LOG_TAG, "Null instance: [" + UiccController.getInstance() + "],[" +
279 UiccController.getInstance().getUiccCard(slotId)+"]");
280 }
281 if (mStkService[slotId] == null) {
282 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
283 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
284 //Check other StkService state.
285 //If all StkServices are not available, stop itself and uninstall apk.
286 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
287 if (i != slotId
288 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
289 || mStkContext[i].mStkServiceState == STATE_EXIST)) {
290 break;
291 }
292 }
293 } else {
294 mStkContext[slotId].mStkServiceState = STATE_EXIST;
295 }
296 if (i == mSimCount) {
297 stopSelf();
298 StkAppInstaller.unInstall(mContext);
299 return;
300 }
301 }
302
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530303 waitForLooper();
John Wang62acae42009-10-08 11:20:23 -0700304 // onStart() method can be passed a null intent
305 // TODO: replace onStart() with onStartCommand()
306 if (intent == null) {
307 return;
308 }
309
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800310 Message msg = mServiceHandler.obtainMessage();
Wink Savillee68857d2014-10-17 15:23:05 -0700311 msg.arg1 = op;
312 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800313 switch(msg.arg1) {
314 case OP_CMD:
315 msg.obj = args.getParcelable(CMD_MSG);
316 break;
317 case OP_RESPONSE:
Wink Saville94e982b2014-07-11 07:38:14 -0700318 case OP_CARD_STATUS_CHANGED:
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530319 case OP_ALPHA_NOTIFY:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800320 msg.obj = args;
321 /* falls through */
322 case OP_LAUNCH_APP:
323 case OP_END_SESSION:
324 case OP_BOOT_COMPLETED:
325 break;
326 default:
327 return;
328 }
329 mServiceHandler.sendMessage(msg);
330 }
331
332 @Override
333 public void onDestroy() {
Wink Savillee68857d2014-10-17 15:23:05 -0700334 CatLog.d(LOG_TAG, "onDestroy()");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800335 waitForLooper();
336 mServiceLooper.quit();
337 }
338
339 @Override
340 public IBinder onBind(Intent intent) {
341 return null;
342 }
343
344 public void run() {
345 Looper.prepare();
346
347 mServiceLooper = Looper.myLooper();
348 mServiceHandler = new ServiceHandler();
349
350 Looper.loop();
351 }
352
353 /*
354 * Package api used by StkMenuActivity to indicate if its on the foreground.
355 */
Wink Savillee68857d2014-10-17 15:23:05 -0700356 void indicateMenuVisibility(boolean visibility, int slotId) {
357 if (slotId >= 0 && slotId < mSimCount) {
358 mStkContext[slotId].mMenuIsVisible = visibility;
359 }
360 }
361
362 boolean isInputPending(int slotId) {
363 if (slotId >= 0 && slotId < mSimCount) {
364 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
365 return mStkContext[slotId].mIsInputPending;
366 }
367 return false;
368 }
369
370 boolean isMenuPending(int slotId) {
371 if (slotId >= 0 && slotId < mSimCount) {
372 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
373 return mStkContext[slotId].mIsMenuPending;
374 }
375 return false;
376 }
377
378 boolean isDialogPending(int slotId) {
379 if (slotId >= 0 && slotId < mSimCount) {
380 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
381 return mStkContext[slotId].mIsDialogPending;
382 }
383 return false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800384 }
385
386 /*
387 * Package api used by StkMenuActivity to get its Menu parameter.
388 */
Wink Savillee68857d2014-10-17 15:23:05 -0700389 Menu getMenu(int slotId) {
390 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
391 if (slotId >=0 && slotId < mSimCount) {
392 return mStkContext[slotId].mCurrentMenu;
393 } else {
394 return null;
395 }
396 }
397
398 /*
399 * Package api used by StkMenuActivity to get its Main Menu parameter.
400 */
401 Menu getMainMenu(int slotId) {
402 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
403 if (slotId >=0 && slotId < mSimCount) {
404 return mStkContext[slotId].mMainCmd.getMenu();
405 } else {
406 return null;
407 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800408 }
409
410 /*
411 * Package api used by UI Activities and Dialogs to communicate directly
412 * with the service to deliver state information and parameters.
413 */
414 static StkAppService getInstance() {
415 return sInstance;
416 }
417
418 private void waitForLooper() {
419 while (mServiceHandler == null) {
420 synchronized (this) {
421 try {
422 wait(100);
423 } catch (InterruptedException e) {
424 }
425 }
426 }
427 }
428
429 private final class ServiceHandler extends Handler {
430 @Override
431 public void handleMessage(Message msg) {
Wink Savillee68857d2014-10-17 15:23:05 -0700432 if(null == msg) {
433 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
434 return;
435 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800436 int opcode = msg.arg1;
Wink Savillee68857d2014-10-17 15:23:05 -0700437 int slotId = msg.arg2;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800438
Wink Savillee68857d2014-10-17 15:23:05 -0700439 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
440 if (opcode == OP_CMD && msg.obj != null &&
441 ((CatCmdMessage)msg.obj).getCmdType()!= null) {
442 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
443 }
444 mStkContext[slotId].mOpCode = opcode;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800445 switch (opcode) {
446 case OP_LAUNCH_APP:
Wink Savillee68857d2014-10-17 15:23:05 -0700447 if (mStkContext[slotId].mMainCmd == null) {
448 CatLog.d(LOG_TAG, "mMainCmd is null");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800449 // nothing todo when no SET UP MENU command didn't arrive.
450 return;
451 }
Wink Savillee68857d2014-10-17 15:23:05 -0700452 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
453 mStkContext[slotId].mCmdInProgress + "]");
454
455 //If there is a pending activity for the slot id,
456 //just finish it and create a new one to handle the pending command.
457 cleanUpInstanceStackBySlot(slotId);
458
459 //Clean up all other activities in stack.
460 for (int i = 0; i < mSimCount; i++) {
461 if (i != slotId && mStkContext[i].mCurrentCmd != null) {
462 Activity otherAct = mStkContext[i].getPendingActivityInstance();
463 Activity otherDal = mStkContext[i].getPendingDialogInstance();
464 Activity otherMainMenu = mStkContext[i].getMainActivityInstance();
465 if (otherAct != null) {
466 CatLog.d(LOG_TAG, "finish pending otherAct and send SE. slot: " + i);
467 // Send end session for the pending proactive command of slot i in
468 // onDestroy of the activity.
469 // Set mBackGroundTRSent to true for ignoring to show the main menu
470 // for the following end session event.
471 mStkContext[i].mBackGroundTRSent = true;
472 otherAct.finish();
473 mStkContext[i].mActivityInstance = null;
474 }
475 if (otherDal != null) {
476 CatLog.d(LOG_TAG, "finish pending otherDal and send TR for the dialog");
477 mStkContext[i].mBackGroundTRSent = true;
478 otherDal.finish();
479 mStkContext[i].mDialogInstance = null;
480 }
481 if (otherMainMenu != null) {
482 CatLog.d(LOG_TAG, "finish pending otherMainMenu.");
483 otherMainMenu.finish();
484 mStkContext[i].mMainActivityInstance = null;
485 }
486 }
487 }
488 CatLog.d(LOG_TAG, "Current cmd type: " +
489 mStkContext[slotId].mCurrentCmd.getCmdType());
490 //Restore the last command from stack by slot id.
491 restoreInstanceFromStackBySlot(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800492 break;
493 case OP_CMD:
Wink Savillee68857d2014-10-17 15:23:05 -0700494 CatLog.d(LOG_TAG, "[OP_CMD]");
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700495 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800496 // There are two types of commands:
497 // 1. Interactive - user's response is required.
498 // 2. Informative - display a message, no interaction with the user.
499 //
Wink Saville79085fc2009-06-09 10:27:23 -0700500 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800501 // Interactive commands can't override each other. So if a command
502 // is already in progress, we need to queue the next command until
503 // the user has responded or a timeout expired.
504 if (!isCmdInteractive(cmdMsg)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700505 handleCmd(cmdMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800506 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700507 if (!mStkContext[slotId].mCmdInProgress) {
508 mStkContext[slotId].mCmdInProgress = true;
509 handleCmd((CatCmdMessage) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800510 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700511 CatLog.d(LOG_TAG, "[Interactive][in progress]");
512 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
513 (CatCmdMessage) msg.obj, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800514 }
515 }
516 break;
517 case OP_RESPONSE:
Wink Savillee68857d2014-10-17 15:23:05 -0700518 if (mStkContext[slotId].responseNeeded) {
519 handleCmdResponse((Bundle) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800520 }
521 // call delayed commands if needed.
Wink Savillee68857d2014-10-17 15:23:05 -0700522 if (mStkContext[slotId].mCmdsQ.size() != 0) {
523 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800524 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700525 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800526 }
527 // reset response needed state var to its original value.
Wink Savillee68857d2014-10-17 15:23:05 -0700528 mStkContext[slotId].responseNeeded = true;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800529 break;
530 case OP_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700531 if (!mStkContext[slotId].mCmdInProgress) {
532 mStkContext[slotId].mCmdInProgress = true;
533 handleSessionEnd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800534 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700535 mStkContext[slotId].mCmdsQ.addLast(
536 new DelayedCmd(OP_END_SESSION, null, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800537 }
538 break;
539 case OP_BOOT_COMPLETED:
Wink Savillee68857d2014-10-17 15:23:05 -0700540 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
541 int i = 0;
542 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
543 if (mStkContext[i].mMainCmd != null) {
544 break;
545 }
546 }
547 if (i == mSimCount) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800548 StkAppInstaller.unInstall(mContext);
549 }
550 break;
551 case OP_DELAYED_MSG:
Wink Savillee68857d2014-10-17 15:23:05 -0700552 handleDelayedCmd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800553 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700554 case OP_CARD_STATUS_CHANGED:
Wink Savillee68857d2014-10-17 15:23:05 -0700555 CatLog.d(LOG_TAG, "Card/Icc Status change received");
556 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
557 break;
558 case OP_SET_ACT_INST:
559 Activity act = new Activity();
560 act = (Activity) msg.obj;
561 CatLog.d(LOG_TAG, "Set activity instance. " + act);
562 mStkContext[slotId].mActivityInstance = act;
563 break;
564 case OP_SET_DAL_INST:
565 Activity dal = new Activity();
566 CatLog.d(LOG_TAG, "Set dialog instance. " + dal);
567 dal = (Activity) msg.obj;
568 mStkContext[slotId].mDialogInstance = dal;
569 break;
570 case OP_SET_MAINACT_INST:
571 Activity mainAct = new Activity();
572 mainAct = (Activity) msg.obj;
573 CatLog.d(LOG_TAG, "Set activity instance. " + mainAct);
574 mStkContext[slotId].mMainActivityInstance = mainAct;
Wink Saville94e982b2014-07-11 07:38:14 -0700575 break;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530576 case OP_ALPHA_NOTIFY:
577 handleAlphaNotify((Bundle) msg.obj);
578 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700579 }
580 }
581
Wink Savillee68857d2014-10-17 15:23:05 -0700582 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
Wink Saville94e982b2014-07-11 07:38:14 -0700583 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
584
Wink Savillee68857d2014-10-17 15:23:05 -0700585 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
Wink Saville94e982b2014-07-11 07:38:14 -0700586 if (cardStatus == false) {
Wink Savillee68857d2014-10-17 15:23:05 -0700587 CatLog.d(LOG_TAG, "CARD is ABSENT");
Wink Saville94e982b2014-07-11 07:38:14 -0700588 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
Wink Savillee68857d2014-10-17 15:23:05 -0700589 mNotificationManager.cancel(getNotificationId(slotId));
590 if (isAllOtherCardsAbsent(slotId)) {
591 CatLog.d(LOG_TAG, "All CARDs are ABSENT");
592 StkAppInstaller.unInstall(mContext);
593 stopSelf();
594 }
Wink Saville94e982b2014-07-11 07:38:14 -0700595 } else {
596 IccRefreshResponse state = new IccRefreshResponse();
597 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
598
Wink Savillee68857d2014-10-17 15:23:05 -0700599 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
Wink Saville94e982b2014-07-11 07:38:14 -0700600 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
601 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
602 // Clear Idle Text
Wink Savillee68857d2014-10-17 15:23:05 -0700603 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville94e982b2014-07-11 07:38:14 -0700604 }
605
606 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
607 // Uninstall STkmenu
Wink Savillee68857d2014-10-17 15:23:05 -0700608 if (isAllOtherCardsAbsent(slotId)) {
609 StkAppInstaller.unInstall(mContext);
610 }
611 mStkContext[slotId].mCurrentMenu = null;
612 mStkContext[slotId].mMainCmd = null;
Wink Saville94e982b2014-07-11 07:38:14 -0700613 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800614 }
615 }
616 }
Wink Savillee68857d2014-10-17 15:23:05 -0700617 /*
618 * Check if all SIMs are absent except the id of slot equals "slotId".
619 */
620 private boolean isAllOtherCardsAbsent(int slotId) {
621 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
622 Context.TELEPHONY_SERVICE);
623 int i = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800624
Wink Savillee68857d2014-10-17 15:23:05 -0700625 for (i = 0; i < mSimCount; i++) {
626 if (i != slotId && mTm.hasIccCard(i)) {
627 break;
628 }
629 }
630 if (i == mSimCount) {
631 return true;
632 } else {
633 return false;
634 }
635 }
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700636 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800637 switch (cmd.getCmdType()) {
638 case SEND_DTMF:
639 case SEND_SMS:
640 case SEND_SS:
641 case SEND_USSD:
642 case SET_UP_IDLE_MODE_TEXT:
643 case SET_UP_MENU:
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500644 case CLOSE_CHANNEL:
645 case RECEIVE_DATA:
646 case SEND_DATA:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800647 return false;
648 }
649
650 return true;
651 }
652
Wink Savillee68857d2014-10-17 15:23:05 -0700653 private void handleDelayedCmd(int slotId) {
654 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
655 if (mStkContext[slotId].mCmdsQ.size() != 0) {
656 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
657 if (cmd != null) {
658 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
659 mStkContext[slotId].mCmdsQ.size() +
660 " id: " + cmd.id + "sim id: " + cmd.slotId);
661 switch (cmd.id) {
662 case OP_CMD:
663 handleCmd(cmd.msg, cmd.slotId);
664 break;
665 case OP_END_SESSION:
666 handleSessionEnd(cmd.slotId);
667 break;
668 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800669 }
670 }
671 }
672
Wink Savillee68857d2014-10-17 15:23:05 -0700673 private void callDelayedMsg(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800674 Message msg = mServiceHandler.obtainMessage();
675 msg.arg1 = OP_DELAYED_MSG;
Wink Savillee68857d2014-10-17 15:23:05 -0700676 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800677 mServiceHandler.sendMessage(msg);
678 }
679
Wink Savillee68857d2014-10-17 15:23:05 -0700680 private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) {
681 Message msg = mServiceHandler.obtainMessage();
682 msg.obj = obj;
683 msg.arg1 = inst_type;
684 msg.arg2 = slotId;
685 mServiceHandler.sendMessage(msg);
686 }
687
688 private void handleSessionEnd(int slotId) {
689 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
690 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
691 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
692 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
693 mStkContext[slotId].mMenuState);
694
695 mStkContext[slotId].mIsInputPending = false;
696 mStkContext[slotId].mIsMenuPending = false;
697 mStkContext[slotId].mIsDialogPending = false;
698
699 // We should finish all pending activity if receiving END SESSION command.
700 cleanUpInstanceStackBySlot(slotId);
701
702 if (mStkContext[slotId].mMainCmd == null) {
703 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
704 }
705 mStkContext[slotId].lastSelectedItem = null;
Wink Saville79085fc2009-06-09 10:27:23 -0700706 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800707 // update the current menu member.
Wink Savillee68857d2014-10-17 15:23:05 -0700708 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
709 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800710 }
Wink Savillee68857d2014-10-17 15:23:05 -0700711 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
712 // In mutiple instance architecture, the main menu for slotId will be finished when user
713 // goes to the Stk menu of the other SIM. So, we should launch a new instance for the
714 // main menu if the main menu instance has been finished.
715 // If the current menu is secondary menu, we should launch main menu.
716 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
717 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800718 }
Wink Savillee68857d2014-10-17 15:23:05 -0700719 if (mStkContext[slotId].mCmdsQ.size() != 0) {
720 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800721 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700722 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800723 }
724 // In case a launch browser command was just confirmed, launch that url.
Wink Savillee68857d2014-10-17 15:23:05 -0700725 if (mStkContext[slotId].launchBrowser) {
726 mStkContext[slotId].launchBrowser = false;
727 launchBrowser(mStkContext[slotId].mBrowserSettings);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800728 }
729 }
730
Wink Savillee68857d2014-10-17 15:23:05 -0700731 private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800732 if (cmdMsg == null) {
733 return;
734 }
735 // save local reference for state tracking.
Wink Savillee68857d2014-10-17 15:23:05 -0700736 mStkContext[slotId].mCurrentCmd = cmdMsg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800737 boolean waitForUsersResponse = true;
738
Wink Savillee68857d2014-10-17 15:23:05 -0700739 mStkContext[slotId].mIsInputPending = false;
740 mStkContext[slotId].mIsMenuPending = false;
741 mStkContext[slotId].mIsDialogPending = false;
742
743 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800744 switch (cmdMsg.getCmdType()) {
745 case DISPLAY_TEXT:
746 TextMessage msg = cmdMsg.geTextMessage();
Wink Savillee68857d2014-10-17 15:23:05 -0700747 mStkContext[slotId].responseNeeded = msg.responseNeeded;
Jeevaka Badrappan854a25c2012-12-01 16:32:03 +0200748 waitForUsersResponse = msg.responseNeeded;
Wink Savillee68857d2014-10-17 15:23:05 -0700749 if (mStkContext[slotId].lastSelectedItem != null) {
750 msg.title = mStkContext[slotId].lastSelectedItem;
751 } else if (mStkContext[slotId].mMainCmd != null){
752 msg.title = mStkContext[slotId].mMainCmd.getMenu().title;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800753 } else {
754 // TODO: get the carrier name from the SIM
755 msg.title = "";
756 }
Wink Savillee68857d2014-10-17 15:23:05 -0700757 launchTextDialog(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800758 break;
759 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700760 CatLog.d(LOG_TAG, "SELECT_ITEM +");
761 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
762 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
763 launchMenuActivity(cmdMsg.getMenu(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800764 break;
765 case SET_UP_MENU:
Wink Savillee68857d2014-10-17 15:23:05 -0700766 mStkContext[slotId].mCmdInProgress = false;
767 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
768 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
769 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
770 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
771
772 if (removeMenu(slotId)) {
773 int i = 0;
774 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App");
775 mStkContext[slotId].mCurrentMenu = null;
776 //Check other setup menu state. If all setup menu are removed, uninstall apk.
777 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
778 if (i != slotId
779 && (mStkContext[slotId].mSetupMenuState == STATE_UNKNOWN
780 || mStkContext[slotId].mSetupMenuState == STATE_EXIST)) {
781 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
782 + mStkContext[slotId].mSetupMenuState);
783 break;
784 }
785 }
786 if (i == mSimCount) {
787 StkAppInstaller.unInstall(mContext);
788 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800789 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700790 CatLog.d(LOG_TAG, "install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800791 StkAppInstaller.install(mContext);
792 }
Wink Savillee68857d2014-10-17 15:23:05 -0700793 if (mStkContext[slotId].mMenuIsVisible) {
794 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800795 }
796 break;
797 case GET_INPUT:
798 case GET_INKEY:
Wink Savillee68857d2014-10-17 15:23:05 -0700799 launchInputActivity(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800800 break;
801 case SET_UP_IDLE_MODE_TEXT:
802 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700803 launchIdleText(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800804 break;
805 case SEND_DTMF:
806 case SEND_SMS:
807 case SEND_SS:
808 case SEND_USSD:
809 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700810 launchEventMessage(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800811 break;
812 case LAUNCH_BROWSER:
Wink Savillee68857d2014-10-17 15:23:05 -0700813 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800814 break;
815 case SET_UP_CALL:
Wink Savillee68857d2014-10-17 15:23:05 -0700816 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings()
817 .confirmMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800818 break;
819 case PLAY_TONE:
Wink Savillee68857d2014-10-17 15:23:05 -0700820 launchToneDialog(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800821 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500822 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -0700823 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500824 break;
825 case CLOSE_CHANNEL:
826 case RECEIVE_DATA:
827 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -0700828 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500829
830 if ((m != null) && (m.text == null)) {
831 switch(cmdMsg.getCmdType()) {
832 case CLOSE_CHANNEL:
833 m.text = getResources().getString(R.string.default_close_channel_msg);
834 break;
835 case RECEIVE_DATA:
836 m.text = getResources().getString(R.string.default_receive_data_msg);
837 break;
838 case SEND_DATA:
839 m.text = getResources().getString(R.string.default_send_data_msg);
840 break;
841 }
842 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700843 /*
844 * Display indication in the form of a toast to the user if required.
845 */
Wink Savillee68857d2014-10-17 15:23:05 -0700846 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500847 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800848 }
849
850 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -0700851 if (mStkContext[slotId].mCmdsQ.size() != 0) {
852 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800853 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700854 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800855 }
856 }
857 }
858
Wink Savillee68857d2014-10-17 15:23:05 -0700859 private void handleCmdResponse(Bundle args, int slotId) {
860 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
861 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800862 return;
863 }
Wink Savillee68857d2014-10-17 15:23:05 -0700864
865 if (mStkService[slotId] == null) {
866 if(null != UiccController.getInstance() &&
867 null != UiccController.getInstance().getUiccCard(slotId)) {
868 mStkService[slotId] = UiccController.getInstance().getUiccCard(slotId)
869 .getCatService();
870 } else {
871 CatLog.d(LOG_TAG, "Null instance: [" + UiccController.getInstance() +
872 "],["+UiccController.getInstance().getUiccCard(slotId)+"]");
873 }
874 if (mStkService[slotId] == null) {
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -0700875 // This should never happen (we should be responding only to a message
876 // that arrived from StkService). It has to exist by this time
Wink Savillee68857d2014-10-17 15:23:05 -0700877 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response.");
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -0700878 throw new RuntimeException("mStkService is null when we need to send response");
879 }
880 }
881
Wink Savillee68857d2014-10-17 15:23:05 -0700882 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800883
884 // set result code
885 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700886 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800887
888 switch(args.getInt(RES_ID)) {
889 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -0700890 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
891 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800892 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -0700893 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800894 case SET_UP_MENU:
895 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700896 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800897 if (helpRequired) {
898 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
899 } else {
900 resMsg.setResultCode(ResultCode.OK);
901 }
902 resMsg.setMenuSelection(menuSelection);
903 break;
904 }
905 break;
906 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -0700907 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800908 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -0700909 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
910 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800911 boolean yesNoSelection = input
912 .equals(StkInputActivity.YES_STR_RESPONSE);
913 resMsg.setYesNo(yesNoSelection);
914 } else {
915 if (helpRequired) {
916 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
917 } else {
918 resMsg.setResultCode(ResultCode.OK);
919 resMsg.setInput(input);
920 }
921 }
922 break;
923 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700924 CatLog.d(this, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700925 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -0700926 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800927 case DISPLAY_TEXT:
928 resMsg.setResultCode(confirmed ? ResultCode.OK
929 : ResultCode.UICC_SESSION_TERM_BY_USER);
930 break;
931 case LAUNCH_BROWSER:
932 resMsg.setResultCode(confirmed ? ResultCode.OK
933 : ResultCode.UICC_SESSION_TERM_BY_USER);
934 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -0700935 mStkContext[slotId].launchBrowser = true;
936 mStkContext[slotId].mBrowserSettings =
937 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800938 }
939 break;
940 case SET_UP_CALL:
941 resMsg.setResultCode(ResultCode.OK);
942 resMsg.setConfirmation(confirmed);
943 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -0700944 launchEventMessage(slotId,
945 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800946 }
947 break;
948 }
949 break;
950 case RES_ID_DONE:
951 resMsg.setResultCode(ResultCode.OK);
952 break;
953 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -0700954 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800955 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
956 break;
957 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700958 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800959 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
960 break;
961 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -0700962 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -0800963 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
964 // Clear message after delay, successful) expects result code OK.
965 // If the command qualifier specifies no user response is required
966 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -0700967 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
968 AppInterface.CommandType.DISPLAY_TEXT.value())
969 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -0800970 resMsg.setResultCode(ResultCode.OK);
971 } else {
972 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
973 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800974 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500975 case RES_ID_CHOICE:
976 int choice = args.getInt(CHOICE);
977 CatLog.d(this, "User Choice=" + choice);
978 switch (choice) {
979 case YES:
980 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700981 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500982 break;
983 case NO:
984 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
985 break;
986 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700987
Wink Savillee68857d2014-10-17 15:23:05 -0700988 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
989 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700990 resMsg.setConfirmation(confirmed);
991 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500992 break;
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -0700993
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800994 default:
Wink Savillee68857d2014-10-17 15:23:05 -0700995 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800996 return;
997 }
Wink Savillee68857d2014-10-17 15:23:05 -0700998
999 if (null != mStkContext[slotId].mCurrentCmd &&
1000 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1001 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1002 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1003 }
1004 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001005 }
1006
1007 /**
1008 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1009 *
1010 * @param userAction If the userAction is yes then we always return 0 otherwise
1011 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1012 * then we are the foreground app and we'll return 0 as from our perspective a
1013 * user action did cause. If it's false than we aren't the foreground app and
1014 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001015 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001016 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1017 */
Wink Savillee68857d2014-10-17 15:23:05 -07001018 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1019 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1020 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1021 }
1022 /**
1023 * This method is used for cleaning up pending instances in stack.
1024 */
1025 private void cleanUpInstanceStackBySlot(int slotId) {
1026 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1027 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1028 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
1029 if (activity != null) {
1030 CatLog.d(LOG_TAG, "current cmd type: " +
1031 mStkContext[slotId].mCurrentCmd.getCmdType());
1032 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1033 AppInterface.CommandType.GET_INPUT.value() ||
1034 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1035 AppInterface.CommandType.GET_INKEY.value()) {
1036 mStkContext[slotId].mIsInputPending = true;
1037 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1038 AppInterface.CommandType.SET_UP_MENU.value() ||
1039 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1040 AppInterface.CommandType.SELECT_ITEM.value()) {
1041 mStkContext[slotId].mIsMenuPending = true;
1042 } else {
1043 }
1044 CatLog.d(LOG_TAG, "finish pending activity.");
1045 activity.finish();
1046 mStkContext[slotId].mActivityInstance = null;
1047 }
1048 if (dialog != null) {
1049 CatLog.d(LOG_TAG, "finish pending dialog.");
1050 mStkContext[slotId].mIsDialogPending = true;
1051 dialog.finish();
1052 mStkContext[slotId].mDialogInstance = null;
1053 }
1054 }
1055 /**
1056 * This method is used for restoring pending instances from stack.
1057 */
1058 private void restoreInstanceFromStackBySlot(int slotId) {
1059 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1060
1061 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1062 switch(cmdType) {
1063 case GET_INPUT:
1064 case GET_INKEY:
1065 launchInputActivity(slotId);
1066 //Set mMenuIsVisible to true for showing main menu for
1067 //following session end command.
1068 mStkContext[slotId].mMenuIsVisible = true;
1069 break;
1070 case DISPLAY_TEXT:
1071 launchTextDialog(slotId);
1072 break;
1073 case LAUNCH_BROWSER:
1074 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1075 slotId);
1076 break;
1077 case OPEN_CHANNEL:
1078 launchOpenChannelDialog(slotId);
1079 break;
1080 case SET_UP_CALL:
1081 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1082 confirmMsg, slotId);
1083 break;
1084 case SET_UP_MENU:
1085 case SELECT_ITEM:
1086 launchMenuActivity(null, slotId);
1087 break;
1088 default:
1089 break;
1090 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001091 }
1092
Wink Savillee68857d2014-10-17 15:23:05 -07001093 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001094 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001095 String targetActivity = STK_MENU_ACTIVITY_NAME;
1096 String uriString = STK_MENU_URI + System.currentTimeMillis();
1097 //Set unique URI to create a new instance of activity for different slotId.
1098 Uri uriData = Uri.parse(uriString);
1099
1100 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1101 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1102 + mStkContext[slotId].mMenuState);
1103 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1104 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1105
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001106 if (menu == null) {
1107 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001108 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
1109 if (mStkContext[slotId].mOpCode == OP_END_SESSION) {
1110 CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION");
1111 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1112 if (mStkContext[slotId].mMainActivityInstance != null) {
1113 CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null");
1114 return;
1115 }
1116 // If END SESSION is sent that results from the activity is finished by
1117 // stkappservice (line 457), we should igonore to display the stk main menu
1118 // of slot id.
1119 if (mStkContext[slotId].mBackGroundTRSent) {
1120 CatLog.d(LOG_TAG, "launchMenuActivity, ES is triggered by BG.");
1121 mStkContext[slotId].mBackGroundTRSent = false;
1122 return;
1123 }
1124 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001125
Wink Savillee68857d2014-10-17 15:23:05 -07001126 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1127 //Otherwise, it should be "STATE_MAIN".
1128 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1129 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1130 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1131 } else {
1132 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1133 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1134 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001135 } else {
1136 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001137 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001138 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001139 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001140 }
Wink Savillee68857d2014-10-17 15:23:05 -07001141 newIntent.putExtra(SLOT_ID, slotId);
1142 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001143 newIntent.setFlags(intentFlags);
1144 mContext.startActivity(newIntent);
1145 }
1146
Wink Savillee68857d2014-10-17 15:23:05 -07001147 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001148 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001149 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1150 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1151 //Set unique URI to create a new instance of activity for different slotId.
1152 Uri uriData = Uri.parse(uriString);
1153
1154 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001155 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001156 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1157 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1158 newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput());
1159 newIntent.putExtra(SLOT_ID, slotId);
1160 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001161 mContext.startActivity(newIntent);
1162 }
1163
Wink Savillee68857d2014-10-17 15:23:05 -07001164 private void launchTextDialog(int slotId) {
1165 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1166 Intent newIntent = new Intent();
1167 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1168 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1169 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1170 //Set unique URI to create a new instance of activity for different slotId.
1171 Uri uriData = Uri.parse(uriString);
1172 if (newIntent != null) {
1173 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1174 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1175 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1176 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1177 newIntent.setData(uriData);
1178 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1179 newIntent.putExtra(SLOT_ID, slotId);
1180 startActivity(newIntent);
1181 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001182 }
1183
Wink Savillee68857d2014-10-17 15:23:05 -07001184 public boolean isStkDialogActivated(Context context) {
1185 String stkDialogActivity = "com.android.stk.StkDialogActivity";
1186 boolean activated = false;
1187 final ActivityManager am = (ActivityManager) context.getSystemService(
1188 Context.ACTIVITY_SERVICE);
1189 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName();
1190
1191 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity);
1192 if (topActivity.equals(stkDialogActivity)) {
1193 activated = true;
1194 }
1195 CatLog.d(LOG_TAG, "activated : " + activated);
1196 return activated;
Johan Hellman3aec01c2011-02-10 10:15:28 +01001197 }
1198
Wink Savillee68857d2014-10-17 15:23:05 -07001199 private void launchEventMessage(int slotId, TextMessage msg) {
1200 if (msg == null || (msg.text != null && msg.text.length() == 0)) {
1201 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001202 return;
1203 }
Wink Savillee68857d2014-10-17 15:23:05 -07001204
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001205 Toast toast = new Toast(mContext.getApplicationContext());
1206 LayoutInflater inflate = (LayoutInflater) mContext
1207 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1208 View v = inflate.inflate(R.layout.stk_event_msg, null);
1209 TextView tv = (TextView) v
1210 .findViewById(com.android.internal.R.id.message);
1211 ImageView iv = (ImageView) v
1212 .findViewById(com.android.internal.R.id.icon);
1213 if (msg.icon != null) {
1214 iv.setImageBitmap(msg.icon);
1215 } else {
1216 iv.setVisibility(View.GONE);
1217 }
1218 if (!msg.iconSelfExplanatory) {
1219 tv.setText(msg.text);
1220 }
1221
1222 toast.setView(v);
1223 toast.setDuration(Toast.LENGTH_LONG);
1224 toast.setGravity(Gravity.BOTTOM, 0, 0);
1225 toast.show();
1226 }
1227
Wink Savillee68857d2014-10-17 15:23:05 -07001228 private void launchEventMessage(int slotId) {
1229 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
1230 }
1231
1232 private void launchConfirmationDialog(TextMessage msg, int slotId) {
1233 msg.title = mStkContext[slotId].lastSelectedItem;
1234 Intent newIntent = new Intent();
1235 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1236 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1237 //Set unique URI to create a new instance of activity for different slotId.
1238 Uri uriData = Uri.parse(uriString);
1239
1240 if (newIntent != null) {
1241 newIntent.setClassName(this, targetActivity);
1242 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1243 | Intent.FLAG_ACTIVITY_NO_HISTORY
1244 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1245 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1246 newIntent.putExtra("TEXT", msg);
1247 newIntent.putExtra(SLOT_ID, slotId);
1248 newIntent.setData(uriData);
1249 startActivity(newIntent);
1250 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001251 }
1252
1253 private void launchBrowser(BrowserSettings settings) {
1254 if (settings == null) {
1255 return;
1256 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001257
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001258 Intent intent = null;
1259 Uri data = null;
David Brown7c03cfe2011-10-20 15:36:12 -07001260
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001261 if (settings.url != null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001262 CatLog.d(LOG_TAG, "settings.url = " + settings.url);
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001263 if ((settings.url.startsWith("http://") || (settings.url.startsWith("https://")))) {
dujin.cha486c1d02011-11-02 22:14:25 +09001264 data = Uri.parse(settings.url);
1265 } else {
1266 String modifiedUrl = "http://" + settings.url;
Wink Savillee68857d2014-10-17 15:23:05 -07001267 CatLog.d(LOG_TAG, "modifiedUrl = " + modifiedUrl);
dujin.cha486c1d02011-11-02 22:14:25 +09001268 data = Uri.parse(modifiedUrl);
1269 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001270 }
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001271 if (data != null) {
1272 intent = new Intent(Intent.ACTION_VIEW);
1273 intent.setData(data);
1274 } else {
1275 // if the command did not contain a URL,
1276 // launch the browser to the default homepage.
Wink Savillee68857d2014-10-17 15:23:05 -07001277 CatLog.d(LOG_TAG, "launch browser with default URL ");
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001278 intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
1279 Intent.CATEGORY_APP_BROWSER);
1280 }
David Brown7c03cfe2011-10-20 15:36:12 -07001281
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001282 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1283 switch (settings.mode) {
1284 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001285 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1286 break;
1287 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001288 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
1289 break;
1290 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
1291 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1292 break;
1293 }
1294 // start browser activity
1295 startActivity(intent);
1296 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07001297 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001298 // followed immediately.
1299 try {
1300 Thread.sleep(10000);
1301 } catch (InterruptedException e) {}
1302 }
1303
Wink Savillee68857d2014-10-17 15:23:05 -07001304 private void launchIdleText(int slotId) {
1305 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001306
Wink Saville046db4b2011-11-01 20:42:54 -07001307 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001308 CatLog.d(LOG_TAG, "mCurrent.getTextMessage is NULL");
1309 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville046db4b2011-11-01 20:42:54 -07001310 return;
1311 }
Wink Savillee68857d2014-10-17 15:23:05 -07001312 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
1313 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
1314 + "] icon[" + msg.icon + "], sim id: " + slotId);
1315
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001316 if (msg.text == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001317 CatLog.d(LOG_TAG, "cancel IdleMode text");
1318 mNotificationManager.cancel(getNotificationId(slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001319 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001320 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001321 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001322 new Intent(mContext, StkAppService.class), 0);
1323
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001324 final Notification.Builder notificationBuilder = new Notification.Builder(
1325 StkAppService.this);
Wink Savillee68857d2014-10-17 15:23:05 -07001326 if (mStkContext[slotId].mMainCmd != null &&
1327 mStkContext[slotId].mMainCmd.getMenu() != null) {
1328 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001329 } else {
1330 notificationBuilder.setContentTitle("");
1331 }
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001332 notificationBuilder
1333 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1334 notificationBuilder.setContentIntent(pendingIntent);
1335 notificationBuilder.setOngoing(true);
1336 // Set text and icon for the status bar and notification body.
1337 if (!msg.iconSelfExplanatory) {
1338 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001339 notificationBuilder.setTicker(msg.text);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001340 }
1341 if (msg.icon != null) {
1342 notificationBuilder.setLargeIcon(msg.icon);
1343 } else {
1344 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
1345 .getResources().getSystem(),
1346 com.android.internal.R.drawable.stat_notify_sim_toolkit);
1347 notificationBuilder.setLargeIcon(bitmapIcon);
1348 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02001349 notificationBuilder.setColor(mContext.getResources().getColor(
1350 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07001351 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001352 }
1353 }
1354
Wink Savillee68857d2014-10-17 15:23:05 -07001355 private void launchToneDialog(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001356 Intent newIntent = new Intent(this, ToneDialog.class);
Wink Savillee68857d2014-10-17 15:23:05 -07001357 String uriString = STK_TONE_URI + slotId;
1358 Uri uriData = Uri.parse(uriString);
1359 //Set unique URI to create a new instance of activity for different slotId.
1360 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001361 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1362 | Intent.FLAG_ACTIVITY_NO_HISTORY
1363 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Wink Savillee68857d2014-10-17 15:23:05 -07001364 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1365 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1366 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
1367 newIntent.putExtra(SLOT_ID, slotId);
1368 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001369 startActivity(newIntent);
1370 }
1371
Wink Savillee68857d2014-10-17 15:23:05 -07001372 private void launchOpenChannelDialog(int slotId) {
1373 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001374 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001375 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001376 return;
1377 }
1378
1379 msg.title = getResources().getString(R.string.stk_dialog_title);
1380 if (msg.text == null) {
1381 msg.text = getResources().getString(R.string.default_open_channel_msg);
1382 }
1383
1384 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1385 .setIconAttribute(android.R.attr.alertDialogIcon)
1386 .setTitle(msg.title)
1387 .setMessage(msg.text)
1388 .setCancelable(false)
1389 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
1390 new DialogInterface.OnClickListener() {
1391 public void onClick(DialogInterface dialog, int which) {
1392 Bundle args = new Bundle();
1393 args.putInt(RES_ID, RES_ID_CHOICE);
1394 args.putInt(CHOICE, YES);
1395 Message message = mServiceHandler.obtainMessage();
1396 message.arg1 = OP_RESPONSE;
1397 message.obj = args;
1398 mServiceHandler.sendMessage(message);
1399 }
1400 })
1401 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
1402 new DialogInterface.OnClickListener() {
1403 public void onClick(DialogInterface dialog, int which) {
1404 Bundle args = new Bundle();
1405 args.putInt(RES_ID, RES_ID_CHOICE);
1406 args.putInt(CHOICE, NO);
1407 Message message = mServiceHandler.obtainMessage();
1408 message.arg1 = OP_RESPONSE;
1409 message.obj = args;
1410 mServiceHandler.sendMessage(message);
1411 }
1412 })
1413 .create();
1414
1415 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1416 if (!mContext.getResources().getBoolean(
1417 com.android.internal.R.bool.config_sf_slowBlur)) {
1418 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1419 }
1420
1421 dialog.show();
1422 }
1423
Wink Savillee68857d2014-10-17 15:23:05 -07001424 private void launchTransientEventMessage(int slotId) {
1425 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001426 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001427 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001428 return;
1429 }
1430
1431 msg.title = getResources().getString(R.string.stk_dialog_title);
1432
1433 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1434 .setIconAttribute(android.R.attr.alertDialogIcon)
1435 .setTitle(msg.title)
1436 .setMessage(msg.text)
1437 .setCancelable(false)
1438 .setPositiveButton(getResources().getString(android.R.string.ok),
1439 new DialogInterface.OnClickListener() {
1440 public void onClick(DialogInterface dialog, int which) {
1441 }
1442 })
1443 .create();
1444
1445 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1446 if (!mContext.getResources().getBoolean(
1447 com.android.internal.R.bool.config_sf_slowBlur)) {
1448 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1449 }
1450
1451 dialog.show();
1452 }
1453
Wink Savillee68857d2014-10-17 15:23:05 -07001454 private int getNotificationId(int slotId) {
1455 int notifyId = STK_NOTIFICATION_ID;
1456 if (slotId >= 0 && slotId < mSimCount) {
1457 notifyId += slotId;
1458 } else {
1459 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1460 }
1461 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
1462 return notifyId;
1463 }
1464
1465 private String getItemName(int itemId, int slotId) {
1466 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001467 if (menu == null) {
1468 return null;
1469 }
1470 for (Item item : menu.items) {
1471 if (item.id == itemId) {
1472 return item.text;
1473 }
1474 }
1475 return null;
1476 }
1477
Wink Savillee68857d2014-10-17 15:23:05 -07001478 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001479 try {
Wink Savillee68857d2014-10-17 15:23:05 -07001480 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
1481 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
1482 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001483 return true;
1484 }
1485 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07001486 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
1487 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001488 return true;
1489 }
Wink Savillee68857d2014-10-17 15:23:05 -07001490 mStkContext[slotId].mSetupMenuState = STATE_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001491 return false;
1492 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301493
Wink Savillee68857d2014-10-17 15:23:05 -07001494 StkContext getStkContext(int slotId) {
1495 if (slotId >= 0 && slotId < mSimCount) {
1496 return mStkContext[slotId];
1497 } else {
1498 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1499 return null;
1500 }
1501 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301502
1503 private void handleAlphaNotify(Bundle args) {
1504 String alphaString = args.getString(AppInterface.ALPHA_STRING);
1505
1506 CatLog.d(this, "Alpha string received from card: " + alphaString);
1507 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
1508 toast.setGravity(Gravity.TOP, 0, 0);
1509 toast.show();
1510 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001511}