blob: 2e51e21c7325051ebed81092b9ff2a529a7a759d [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;
fionaxu2c91c752017-04-21 18:11:57 -070023import android.app.NotificationChannel;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080024import android.app.NotificationManager;
25import android.app.PendingIntent;
26import android.app.Service;
Wink Savillee68857d2014-10-17 15:23:05 -070027import android.app.Activity;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +090028import android.app.ActivityManagerNative;
29import android.app.IProcessObserver;
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;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +090033import android.content.pm.PackageManager;
34import android.content.pm.ResolveInfo;
Preeti Ahuja95919342013-10-01 18:18:55 -070035import android.content.res.Configuration;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053036import android.content.res.Resources;
37import android.content.res.Resources.NotFoundException;
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +010038import android.graphics.Bitmap;
39import android.graphics.BitmapFactory;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080040import android.net.Uri;
41import android.os.Bundle;
42import android.os.Handler;
43import android.os.IBinder;
44import android.os.Looper;
45import android.os.Message;
Takanori Nakanoc8054ba2016-08-15 19:18:16 +090046import android.os.Parcel;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070047import android.os.PersistableBundle;
Preeti Ahuja560be362014-11-25 19:38:24 -080048import android.os.PowerManager;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +090049import android.os.RemoteException;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070050import android.os.SystemProperties;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053051import android.os.Vibrator;
Preeti Ahuja95919342013-10-01 18:18:55 -070052import android.provider.Settings;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070053import android.telephony.CarrierConfigManager;
Wink Saville56469d52009-04-02 01:37:03 -070054import android.telephony.TelephonyManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070055import android.text.TextUtils;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080056import android.view.Gravity;
57import android.view.LayoutInflater;
58import android.view.View;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050059import android.view.WindowManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080060import android.widget.ImageView;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080061import android.widget.TextView;
62import android.widget.Toast;
Wink Savillee68857d2014-10-17 15:23:05 -070063import android.content.IntentFilter;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080064
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070065import com.android.internal.telephony.cat.AppInterface;
Preeti Ahuja95919342013-10-01 18:18:55 -070066import com.android.internal.telephony.cat.LaunchBrowserMode;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070067import com.android.internal.telephony.cat.Menu;
68import com.android.internal.telephony.cat.Item;
69import com.android.internal.telephony.cat.ResultCode;
70import com.android.internal.telephony.cat.CatCmdMessage;
71import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
Preeti Ahuja95919342013-10-01 18:18:55 -070072import com.android.internal.telephony.cat.CatCmdMessage.SetupEventListSettings;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070073import com.android.internal.telephony.cat.CatLog;
74import com.android.internal.telephony.cat.CatResponseMessage;
75import com.android.internal.telephony.cat.TextMessage;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053076import com.android.internal.telephony.cat.ToneSettings;
Wink Saville94e982b2014-07-11 07:38:14 -070077import com.android.internal.telephony.uicc.IccRefreshResponse;
Wink Savillee68857d2014-10-17 15:23:05 -070078import com.android.internal.telephony.PhoneConstants;
Preeti Ahuja95919342013-10-01 18:18:55 -070079import com.android.internal.telephony.GsmAlphabet;
Legler Wuaeefef52014-10-27 00:57:18 +080080import com.android.internal.telephony.cat.CatService;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080081
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070082import java.util.Iterator;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080083import java.util.LinkedList;
Wink Savillee68857d2014-10-17 15:23:05 -070084import java.lang.System;
85import java.util.List;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080086
Preeti Ahuja95919342013-10-01 18:18:55 -070087import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja560be362014-11-25 19:38:24 -080088 SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
89import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja95919342013-10-01 18:18:55 -070090 SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
91
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080092/**
93 * SIM toolkit application level service. Interacts with Telephopny messages,
94 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -070095 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080096 */
97public class StkAppService extends Service implements Runnable {
98
99 // members
Wink Savillee68857d2014-10-17 15:23:05 -0700100 protected class StkContext {
101 protected CatCmdMessage mMainCmd = null;
102 protected CatCmdMessage mCurrentCmd = null;
103 protected CatCmdMessage mCurrentMenuCmd = null;
104 protected Menu mCurrentMenu = null;
105 protected String lastSelectedItem = null;
106 protected boolean mMenuIsVisible = false;
107 protected boolean mIsInputPending = false;
108 protected boolean mIsMenuPending = false;
109 protected boolean mIsDialogPending = false;
110 protected boolean responseNeeded = true;
111 protected boolean launchBrowser = false;
112 protected BrowserSettings mBrowserSettings = null;
113 protected LinkedList<DelayedCmd> mCmdsQ = null;
114 protected boolean mCmdInProgress = false;
115 protected int mStkServiceState = STATE_UNKNOWN;
116 protected int mSetupMenuState = STATE_UNKNOWN;
117 protected int mMenuState = StkMenuActivity.STATE_INIT;
118 protected int mOpCode = -1;
119 private Activity mActivityInstance = null;
120 private Activity mDialogInstance = null;
121 private Activity mMainActivityInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700122 private int mSlotId = 0;
Preeti Ahuja95919342013-10-01 18:18:55 -0700123 private SetupEventListSettings mSetupEventListSettings = null;
124 private boolean mClearSelectItem = false;
125 private boolean mDisplayTextDlgIsVisibile = false;
126 private CatCmdMessage mCurrentSetupEventCmd = null;
Preeti Ahuja560be362014-11-25 19:38:24 -0800127 private CatCmdMessage mIdleModeTextCmd = null;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900128 private boolean mIdleModeTextVisible = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700129 final synchronized void setPendingActivityInstance(Activity act) {
130 CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act);
131 callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
132 }
133 final synchronized Activity getPendingActivityInstance() {
134 CatLog.d(this, "getPendingActivityInstance act : " + mSlotId + ", " +
135 mActivityInstance);
136 return mActivityInstance;
137 }
138 final synchronized void setPendingDialogInstance(Activity act) {
139 CatLog.d(this, "setPendingDialogInstance act : " + mSlotId + ", " + act);
140 callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act);
141 }
142 final synchronized Activity getPendingDialogInstance() {
143 CatLog.d(this, "getPendingDialogInstance act : " + mSlotId + ", " +
144 mDialogInstance);
145 return mDialogInstance;
146 }
147 final synchronized void setMainActivityInstance(Activity act) {
148 CatLog.d(this, "setMainActivityInstance act : " + mSlotId + ", " + act);
149 callSetActivityInstMsg(OP_SET_MAINACT_INST, mSlotId, act);
150 }
151 final synchronized Activity getMainActivityInstance() {
152 CatLog.d(this, "getMainActivityInstance act : " + mSlotId + ", " +
153 mMainActivityInstance);
154 return mMainActivityInstance;
155 }
156 }
157
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800158 private volatile Looper mServiceLooper;
159 private volatile ServiceHandler mServiceHandler;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800160 private Context mContext = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800161 private NotificationManager mNotificationManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800162 static StkAppService sInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700163 private AppInterface[] mStkService = null;
164 private StkContext[] mStkContext = null;
165 private int mSimCount = 0;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900166 private IProcessObserver.Stub mProcessObserver = null;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530167 private TonePlayer mTonePlayer = null;
168 private Vibrator mVibrator = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700169
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800170 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
171 // creating an intent.
172 private enum InitiatedByUserAction {
173 yes, // The action was started via a user initiated action
174 unknown, // Not known for sure if user initated the action
175 }
176
177 // constants
178 static final String OPCODE = "op";
179 static final String CMD_MSG = "cmd message";
180 static final String RES_ID = "response id";
181 static final String MENU_SELECTION = "menu selection";
182 static final String INPUT = "input";
183 static final String HELP = "help";
184 static final String CONFIRMATION = "confirm";
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500185 static final String CHOICE = "choice";
Wink Savillee68857d2014-10-17 15:23:05 -0700186 static final String SLOT_ID = "SLOT_ID";
187 static final String STK_CMD = "STK CMD";
188 static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/";
189 static final String STK_MENU_URI = "stk://com.android.stk/menu/";
190 static final String STK_INPUT_URI = "stk://com.android.stk/input/";
191 static final String STK_TONE_URI = "stk://com.android.stk/tone/";
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530192 static final String FINISH_TONE_ACTIVITY_ACTION =
193 "android.intent.action.stk.finish_activity";
Preeti Ahuja95919342013-10-01 18:18:55 -0700194
195 // These below constants are used for SETUP_EVENT_LIST
196 static final String SETUP_EVENT_TYPE = "event";
197 static final String SETUP_EVENT_CAUSE = "cause";
198
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800199 // operations ids for different service functionality.
200 static final int OP_CMD = 1;
201 static final int OP_RESPONSE = 2;
202 static final int OP_LAUNCH_APP = 3;
203 static final int OP_END_SESSION = 4;
204 static final int OP_BOOT_COMPLETED = 5;
205 private static final int OP_DELAYED_MSG = 6;
Wink Saville94e982b2014-07-11 07:38:14 -0700206 static final int OP_CARD_STATUS_CHANGED = 7;
Wink Savillee68857d2014-10-17 15:23:05 -0700207 static final int OP_SET_ACT_INST = 8;
208 static final int OP_SET_DAL_INST = 9;
209 static final int OP_SET_MAINACT_INST = 10;
Preeti Ahujab3d0e612014-11-20 13:29:25 -0800210 static final int OP_LOCALE_CHANGED = 11;
211 static final int OP_ALPHA_NOTIFY = 12;
Preeti Ahuja560be362014-11-25 19:38:24 -0800212 static final int OP_IDLE_SCREEN = 13;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800213
Preeti Ahuja95919342013-10-01 18:18:55 -0700214 //Invalid SetupEvent
215 static final int INVALID_SETUP_EVENT = 0xFF;
216
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530217 // Message id to signal stop tone due to play tone timeout.
218 private static final int OP_STOP_TONE = 16;
219
220 // Message id to signal stop tone on user keyback.
221 static final int OP_STOP_TONE_USER = 17;
222
223 // Message id to remove stop tone message from queue.
224 private static final int STOP_TONE_WHAT = 100;
225
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800226 // Response ids
227 static final int RES_ID_MENU_SELECTION = 11;
228 static final int RES_ID_INPUT = 12;
229 static final int RES_ID_CONFIRM = 13;
230 static final int RES_ID_DONE = 14;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500231 static final int RES_ID_CHOICE = 15;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800232
233 static final int RES_ID_TIMEOUT = 20;
234 static final int RES_ID_BACKWARD = 21;
235 static final int RES_ID_END_SESSION = 22;
236 static final int RES_ID_EXIT = 23;
Srikanth Chintalaba103002015-11-30 10:49:52 -0800237 static final int RES_ID_ERROR = 24;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800238
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500239 static final int YES = 1;
240 static final int NO = 0;
241
Wink Savillee68857d2014-10-17 15:23:05 -0700242 static final int STATE_UNKNOWN = -1;
243 static final int STATE_NOT_EXIST = 0;
244 static final int STATE_EXIST = 1;
Wink Saville79085fc2009-06-09 10:27:23 -0700245
Wink Savillee68857d2014-10-17 15:23:05 -0700246 private static final String PACKAGE_NAME = "com.android.stk";
247 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
248 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
249 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800250 // Notification id used to display Idle Mode text in NotificationManager.
251 private static final int STK_NOTIFICATION_ID = 333;
fionaxu2c91c752017-04-21 18:11:57 -0700252 // Notification channel containing all mobile service messages notifications.
253 private static final String STK_NOTIFICATION_CHANNEL_ID = "mobileServiceMessages";
254
Wink Savillee68857d2014-10-17 15:23:05 -0700255 private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
Wink Saville79085fc2009-06-09 10:27:23 -0700256
257 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800258 // session end) while the service is busy processing a previous message.
259 private class DelayedCmd {
260 // members
261 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700262 CatCmdMessage msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700263 int slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800264
Wink Savillee68857d2014-10-17 15:23:05 -0700265 DelayedCmd(int id, CatCmdMessage msg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800266 this.id = id;
267 this.msg = msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700268 this.slotId = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800269 }
270 }
271
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700272 // system property to set the STK specific default url for launch browser proactive cmds
273 private static final String STK_BROWSER_DEFAULT_URL_SYSPROP = "persist.radio.stk.default_url";
274
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800275 @Override
276 public void onCreate() {
Wink Savillee68857d2014-10-17 15:23:05 -0700277 CatLog.d(LOG_TAG, "onCreate()+");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800278 // Initialize members
Wink Savillee68857d2014-10-17 15:23:05 -0700279 int i = 0;
280 mContext = getBaseContext();
281 mSimCount = TelephonyManager.from(mContext).getSimCount();
282 CatLog.d(LOG_TAG, "simCount: " + mSimCount);
283 mStkService = new AppInterface[mSimCount];
284 mStkContext = new StkContext[mSimCount];
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900285
Wink Savillee68857d2014-10-17 15:23:05 -0700286 for (i = 0; i < mSimCount; i++) {
287 CatLog.d(LOG_TAG, "slotId: " + i);
Legler Wuaeefef52014-10-27 00:57:18 +0800288 mStkService[i] = CatService.getInstance(i);
Wink Savillee68857d2014-10-17 15:23:05 -0700289 mStkContext[i] = new StkContext();
290 mStkContext[i].mSlotId = i;
291 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
292 }
293
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800294 Thread serviceThread = new Thread(null, this, "Stk App Service");
295 serviceThread.start();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800296 mNotificationManager = (NotificationManager) mContext
297 .getSystemService(Context.NOTIFICATION_SERVICE);
298 sInstance = this;
299 }
300
301 @Override
302 public void onStart(Intent intent, int startId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700303 if (intent == null) {
304 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530305 return;
306 }
307
Wink Savillee68857d2014-10-17 15:23:05 -0700308 Bundle args = intent.getExtras();
309 if (args == null) {
310 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
311 return;
312 }
313
314 int op = args.getInt(OPCODE);
315 int slotId = 0;
316 int i = 0;
317 if (op != OP_BOOT_COMPLETED) {
318 slotId = args.getInt(SLOT_ID);
319 }
Cuihtlauac ALVARADObde7f032015-05-29 16:25:12 +0200320 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", *****");
Wink Savillee68857d2014-10-17 15:23:05 -0700321 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +0800322 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -0700323 if (mStkService[slotId] == null) {
324 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
325 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
326 //Check other StkService state.
327 //If all StkServices are not available, stop itself and uninstall apk.
328 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
329 if (i != slotId
Tsukasa Goto029332b2016-10-05 17:12:06 +0900330 && (mStkService[i] != null)
Wink Savillee68857d2014-10-17 15:23:05 -0700331 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
332 || mStkContext[i].mStkServiceState == STATE_EXIST)) {
333 break;
334 }
335 }
336 } else {
337 mStkContext[slotId].mStkServiceState = STATE_EXIST;
338 }
339 if (i == mSimCount) {
340 stopSelf();
341 StkAppInstaller.unInstall(mContext);
342 return;
343 }
344 }
345
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530346 waitForLooper();
John Wang62acae42009-10-08 11:20:23 -0700347
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800348 Message msg = mServiceHandler.obtainMessage();
Wink Savillee68857d2014-10-17 15:23:05 -0700349 msg.arg1 = op;
350 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800351 switch(msg.arg1) {
352 case OP_CMD:
353 msg.obj = args.getParcelable(CMD_MSG);
354 break;
355 case OP_RESPONSE:
Wink Saville94e982b2014-07-11 07:38:14 -0700356 case OP_CARD_STATUS_CHANGED:
Preeti Ahuja95919342013-10-01 18:18:55 -0700357 case OP_LOCALE_CHANGED:
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530358 case OP_ALPHA_NOTIFY:
Preeti Ahuja560be362014-11-25 19:38:24 -0800359 case OP_IDLE_SCREEN:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800360 msg.obj = args;
361 /* falls through */
362 case OP_LAUNCH_APP:
363 case OP_END_SESSION:
364 case OP_BOOT_COMPLETED:
365 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530366 case OP_STOP_TONE_USER:
367 msg.obj = args;
368 msg.what = STOP_TONE_WHAT;
369 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800370 default:
371 return;
372 }
373 mServiceHandler.sendMessage(msg);
374 }
375
376 @Override
377 public void onDestroy() {
Wink Savillee68857d2014-10-17 15:23:05 -0700378 CatLog.d(LOG_TAG, "onDestroy()");
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900379 unregisterProcessObserver();
Tsukasa Gotou54afbdd2016-01-07 16:30:20 +0900380 sInstance = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800381 waitForLooper();
382 mServiceLooper.quit();
383 }
384
385 @Override
386 public IBinder onBind(Intent intent) {
387 return null;
388 }
389
390 public void run() {
391 Looper.prepare();
392
393 mServiceLooper = Looper.myLooper();
394 mServiceHandler = new ServiceHandler();
395
396 Looper.loop();
397 }
398
399 /*
400 * Package api used by StkMenuActivity to indicate if its on the foreground.
401 */
Wink Savillee68857d2014-10-17 15:23:05 -0700402 void indicateMenuVisibility(boolean visibility, int slotId) {
403 if (slotId >= 0 && slotId < mSimCount) {
404 mStkContext[slotId].mMenuIsVisible = visibility;
405 }
406 }
407
Preeti Ahuja95919342013-10-01 18:18:55 -0700408 /*
409 * Package api used by StkDialogActivity to indicate if its on the foreground.
410 */
411 void setDisplayTextDlgVisibility(boolean visibility, int slotId) {
412 if (slotId >= 0 && slotId < mSimCount) {
413 mStkContext[slotId].mDisplayTextDlgIsVisibile = visibility;
414 }
415 }
416
Wink Savillee68857d2014-10-17 15:23:05 -0700417 boolean isInputPending(int slotId) {
418 if (slotId >= 0 && slotId < mSimCount) {
419 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
420 return mStkContext[slotId].mIsInputPending;
421 }
422 return false;
423 }
424
425 boolean isMenuPending(int slotId) {
426 if (slotId >= 0 && slotId < mSimCount) {
427 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
428 return mStkContext[slotId].mIsMenuPending;
429 }
430 return false;
431 }
432
433 boolean isDialogPending(int slotId) {
434 if (slotId >= 0 && slotId < mSimCount) {
435 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
436 return mStkContext[slotId].mIsDialogPending;
437 }
438 return false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800439 }
440
441 /*
442 * Package api used by StkMenuActivity to get its Menu parameter.
443 */
Wink Savillee68857d2014-10-17 15:23:05 -0700444 Menu getMenu(int slotId) {
445 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
446 if (slotId >=0 && slotId < mSimCount) {
447 return mStkContext[slotId].mCurrentMenu;
448 } else {
449 return null;
450 }
451 }
452
453 /*
454 * Package api used by StkMenuActivity to get its Main Menu parameter.
455 */
456 Menu getMainMenu(int slotId) {
457 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
w30234a08cffe2015-02-04 15:13:25 -0800458 if (slotId >=0 && slotId < mSimCount && (mStkContext[slotId].mMainCmd != null)) {
Takanori Nakanoc8054ba2016-08-15 19:18:16 +0900459 Menu menu = mStkContext[slotId].mMainCmd.getMenu();
460 if (menu != null && mSimCount > PhoneConstants.MAX_PHONE_COUNT_SINGLE_SIM) {
461 // If alpha identifier or icon identifier with the self-explanatory qualifier is
462 // specified in SET-UP MENU command, it should be more prioritized than preset ones.
463 if (menu.title == null
464 && (menu.titleIcon == null || !menu.titleIconSelfExplanatory)) {
465 StkMenuConfig config = StkMenuConfig.getInstance(getApplicationContext());
466 String label = config.getLabel(slotId);
467 Bitmap icon = config.getIcon(slotId);
468 if (label != null || icon != null) {
469 Parcel parcel = Parcel.obtain();
470 menu.writeToParcel(parcel, 0);
471 parcel.setDataPosition(0);
472 menu = Menu.CREATOR.createFromParcel(parcel);
473 parcel.recycle();
474 menu.title = label;
475 menu.titleIcon = icon;
476 menu.titleIconSelfExplanatory = false;
477 }
478 }
479 }
480 return menu;
Wink Savillee68857d2014-10-17 15:23:05 -0700481 } else {
482 return null;
483 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800484 }
485
486 /*
487 * Package api used by UI Activities and Dialogs to communicate directly
488 * with the service to deliver state information and parameters.
489 */
490 static StkAppService getInstance() {
491 return sInstance;
492 }
493
494 private void waitForLooper() {
495 while (mServiceHandler == null) {
496 synchronized (this) {
497 try {
498 wait(100);
499 } catch (InterruptedException e) {
500 }
501 }
502 }
503 }
504
505 private final class ServiceHandler extends Handler {
506 @Override
507 public void handleMessage(Message msg) {
Wink Savillee68857d2014-10-17 15:23:05 -0700508 if(null == msg) {
509 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
510 return;
511 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800512 int opcode = msg.arg1;
Wink Savillee68857d2014-10-17 15:23:05 -0700513 int slotId = msg.arg2;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800514
Wink Savillee68857d2014-10-17 15:23:05 -0700515 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
516 if (opcode == OP_CMD && msg.obj != null &&
517 ((CatCmdMessage)msg.obj).getCmdType()!= null) {
518 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
519 }
520 mStkContext[slotId].mOpCode = opcode;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800521 switch (opcode) {
522 case OP_LAUNCH_APP:
Wink Savillee68857d2014-10-17 15:23:05 -0700523 if (mStkContext[slotId].mMainCmd == null) {
524 CatLog.d(LOG_TAG, "mMainCmd is null");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800525 // nothing todo when no SET UP MENU command didn't arrive.
526 return;
527 }
Wink Savillee68857d2014-10-17 15:23:05 -0700528 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
529 mStkContext[slotId].mCmdInProgress + "]");
530
531 //If there is a pending activity for the slot id,
532 //just finish it and create a new one to handle the pending command.
533 cleanUpInstanceStackBySlot(slotId);
534
Wink Savillee68857d2014-10-17 15:23:05 -0700535 CatLog.d(LOG_TAG, "Current cmd type: " +
536 mStkContext[slotId].mCurrentCmd.getCmdType());
537 //Restore the last command from stack by slot id.
538 restoreInstanceFromStackBySlot(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800539 break;
540 case OP_CMD:
Wink Savillee68857d2014-10-17 15:23:05 -0700541 CatLog.d(LOG_TAG, "[OP_CMD]");
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700542 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800543 // There are two types of commands:
544 // 1. Interactive - user's response is required.
545 // 2. Informative - display a message, no interaction with the user.
546 //
Wink Saville79085fc2009-06-09 10:27:23 -0700547 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800548 // Interactive commands can't override each other. So if a command
549 // is already in progress, we need to queue the next command until
550 // the user has responded or a timeout expired.
551 if (!isCmdInteractive(cmdMsg)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700552 handleCmd(cmdMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800553 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700554 if (!mStkContext[slotId].mCmdInProgress) {
555 mStkContext[slotId].mCmdInProgress = true;
556 handleCmd((CatCmdMessage) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800557 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700558 CatLog.d(LOG_TAG, "[Interactive][in progress]");
559 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
560 (CatCmdMessage) msg.obj, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800561 }
562 }
563 break;
564 case OP_RESPONSE:
Preeti Ahuja414bc412013-06-25 19:31:49 -0700565 handleCmdResponse((Bundle) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800566 // call delayed commands if needed.
Wink Savillee68857d2014-10-17 15:23:05 -0700567 if (mStkContext[slotId].mCmdsQ.size() != 0) {
568 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800569 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700570 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800571 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800572 break;
573 case OP_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700574 if (!mStkContext[slotId].mCmdInProgress) {
575 mStkContext[slotId].mCmdInProgress = true;
576 handleSessionEnd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800577 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700578 mStkContext[slotId].mCmdsQ.addLast(
579 new DelayedCmd(OP_END_SESSION, null, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800580 }
581 break;
582 case OP_BOOT_COMPLETED:
Wink Savillee68857d2014-10-17 15:23:05 -0700583 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
584 int i = 0;
585 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
586 if (mStkContext[i].mMainCmd != null) {
587 break;
588 }
589 }
590 if (i == mSimCount) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800591 StkAppInstaller.unInstall(mContext);
592 }
593 break;
594 case OP_DELAYED_MSG:
Wink Savillee68857d2014-10-17 15:23:05 -0700595 handleDelayedCmd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800596 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700597 case OP_CARD_STATUS_CHANGED:
Wink Savillee68857d2014-10-17 15:23:05 -0700598 CatLog.d(LOG_TAG, "Card/Icc Status change received");
599 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
600 break;
601 case OP_SET_ACT_INST:
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900602 Activity act = (Activity) msg.obj;
603 if (mStkContext[slotId].mActivityInstance != act) {
604 CatLog.d(LOG_TAG, "Set activity instance - " + act);
605 Activity previous = mStkContext[slotId].mActivityInstance;
606 mStkContext[slotId].mActivityInstance = act;
607 // Finish the previous one if it has not been finished yet somehow.
608 if (previous != null && !previous.isDestroyed() && !previous.isFinishing()) {
609 CatLog.d(LOG_TAG, "Finish the previous pending activity - " + previous);
610 previous.finish();
611 }
612 }
Wink Savillee68857d2014-10-17 15:23:05 -0700613 break;
614 case OP_SET_DAL_INST:
615 Activity dal = new Activity();
616 CatLog.d(LOG_TAG, "Set dialog instance. " + dal);
617 dal = (Activity) msg.obj;
618 mStkContext[slotId].mDialogInstance = dal;
619 break;
620 case OP_SET_MAINACT_INST:
621 Activity mainAct = new Activity();
622 mainAct = (Activity) msg.obj;
623 CatLog.d(LOG_TAG, "Set activity instance. " + mainAct);
624 mStkContext[slotId].mMainActivityInstance = mainAct;
Wink Saville94e982b2014-07-11 07:38:14 -0700625 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700626 case OP_LOCALE_CHANGED:
627 CatLog.d(this, "Locale Changed");
Yuta Ui1481b172016-02-03 15:34:31 +0900628 for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
629 checkForSetupEvent(LANGUAGE_SELECTION_EVENT, (Bundle) msg.obj, slot);
630 }
fionaxu805eb572017-05-02 10:57:30 -0700631 // rename all registered notification channels on locale change
632 createAllChannels();
Preeti Ahuja95919342013-10-01 18:18:55 -0700633 break;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530634 case OP_ALPHA_NOTIFY:
635 handleAlphaNotify((Bundle) msg.obj);
636 break;
Preeti Ahuja560be362014-11-25 19:38:24 -0800637 case OP_IDLE_SCREEN:
638 for (int slot = 0; slot < mSimCount; slot++) {
639 if (mStkContext[slot] != null) {
640 handleIdleScreen(slot);
641 }
642 }
643 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530644 case OP_STOP_TONE_USER:
645 case OP_STOP_TONE:
646 CatLog.d(this, "Stop tone");
647 handleStopTone(msg, slotId);
648 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700649 }
650 }
651
Wink Savillee68857d2014-10-17 15:23:05 -0700652 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
Wink Saville94e982b2014-07-11 07:38:14 -0700653 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
654
Wink Savillee68857d2014-10-17 15:23:05 -0700655 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
Wink Saville94e982b2014-07-11 07:38:14 -0700656 if (cardStatus == false) {
Wink Savillee68857d2014-10-17 15:23:05 -0700657 CatLog.d(LOG_TAG, "CARD is ABSENT");
Wink Saville94e982b2014-07-11 07:38:14 -0700658 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900659 cancelIdleText(slotId);
Srikanth Chintala7c5a04c2016-09-22 19:05:01 +0530660 mStkContext[slotId].mCurrentMenu = null;
661 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700662 if (isAllOtherCardsAbsent(slotId)) {
663 CatLog.d(LOG_TAG, "All CARDs are ABSENT");
664 StkAppInstaller.unInstall(mContext);
665 stopSelf();
666 }
Wink Saville94e982b2014-07-11 07:38:14 -0700667 } else {
668 IccRefreshResponse state = new IccRefreshResponse();
669 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
670
Wink Savillee68857d2014-10-17 15:23:05 -0700671 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
Wink Saville94e982b2014-07-11 07:38:14 -0700672 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
673 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
674 // Clear Idle Text
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900675 cancelIdleText(slotId);
Wink Saville94e982b2014-07-11 07:38:14 -0700676 }
677
678 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
679 // Uninstall STkmenu
Wink Savillee68857d2014-10-17 15:23:05 -0700680 if (isAllOtherCardsAbsent(slotId)) {
681 StkAppInstaller.unInstall(mContext);
682 }
683 mStkContext[slotId].mCurrentMenu = null;
684 mStkContext[slotId].mMainCmd = null;
Wink Saville94e982b2014-07-11 07:38:14 -0700685 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800686 }
687 }
688 }
Wink Savillee68857d2014-10-17 15:23:05 -0700689 /*
690 * Check if all SIMs are absent except the id of slot equals "slotId".
691 */
692 private boolean isAllOtherCardsAbsent(int slotId) {
693 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
694 Context.TELEPHONY_SERVICE);
695 int i = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800696
Wink Savillee68857d2014-10-17 15:23:05 -0700697 for (i = 0; i < mSimCount; i++) {
698 if (i != slotId && mTm.hasIccCard(i)) {
699 break;
700 }
701 }
702 if (i == mSimCount) {
703 return true;
704 } else {
705 return false;
706 }
707 }
Preeti Ahuja95919342013-10-01 18:18:55 -0700708
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900709 /* package */ boolean isScreenIdle() {
710 ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
711 List<RunningTaskInfo> tasks = am.getRunningTasks(1);
712 if (tasks == null || tasks.isEmpty()) {
713 return false;
714 }
715
716 String top = tasks.get(0).topActivity.getPackageName();
717 if (top == null) {
718 return false;
719 }
720
721 // We can assume that the screen is idle if the home application is in the foreground.
722 final Intent intent = new Intent(Intent.ACTION_MAIN, null);
723 intent.addCategory(Intent.CATEGORY_HOME);
724
725 ResolveInfo info = getPackageManager().resolveActivity(intent,
726 PackageManager.MATCH_DEFAULT_ONLY);
727 if (info != null) {
728 if (top.equals(info.activityInfo.packageName)) {
729 return true;
730 }
731 }
732
733 return false;
Preeti Ahuja560be362014-11-25 19:38:24 -0800734 }
735
736 private void handleIdleScreen(int slotId) {
737
738 // If the idle screen event is present in the list need to send the
739 // response to SIM.
740 CatLog.d(this, "Need to send IDLE SCREEN Available event to SIM");
741 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
742
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900743 if (mStkContext[slotId].mIdleModeTextCmd != null
744 && !mStkContext[slotId].mIdleModeTextVisible) {
745 launchIdleText(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -0800746 }
747 }
748
749 private void sendScreenBusyResponse(int slotId) {
750 if (mStkContext[slotId].mCurrentCmd == null) {
751 return;
752 }
753 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
754 CatLog.d(this, "SCREEN_BUSY");
755 resMsg.setResultCode(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS);
756 mStkService[slotId].onCmdResponse(resMsg);
757 if (mStkContext[slotId].mCmdsQ.size() != 0) {
758 callDelayedMsg(slotId);
759 } else {
760 mStkContext[slotId].mCmdInProgress = false;
761 }
762 }
763
Preeti Ahuja95919342013-10-01 18:18:55 -0700764 private void sendResponse(int resId, int slotId, boolean confirm) {
765 Message msg = mServiceHandler.obtainMessage();
766 msg.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +0900767 msg.arg2 = slotId;
Preeti Ahuja95919342013-10-01 18:18:55 -0700768 Bundle args = new Bundle();
769 args.putInt(StkAppService.RES_ID, resId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700770 args.putBoolean(StkAppService.CONFIRMATION, confirm);
771 msg.obj = args;
772 mServiceHandler.sendMessage(msg);
773 }
774
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700775 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800776 switch (cmd.getCmdType()) {
777 case SEND_DTMF:
778 case SEND_SMS:
779 case SEND_SS:
780 case SEND_USSD:
781 case SET_UP_IDLE_MODE_TEXT:
782 case SET_UP_MENU:
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500783 case CLOSE_CHANNEL:
784 case RECEIVE_DATA:
785 case SEND_DATA:
Preeti Ahuja95919342013-10-01 18:18:55 -0700786 case SET_UP_EVENT_LIST:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800787 return false;
788 }
789
790 return true;
791 }
792
Wink Savillee68857d2014-10-17 15:23:05 -0700793 private void handleDelayedCmd(int slotId) {
794 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
795 if (mStkContext[slotId].mCmdsQ.size() != 0) {
796 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
797 if (cmd != null) {
798 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
799 mStkContext[slotId].mCmdsQ.size() +
800 " id: " + cmd.id + "sim id: " + cmd.slotId);
801 switch (cmd.id) {
802 case OP_CMD:
803 handleCmd(cmd.msg, cmd.slotId);
804 break;
805 case OP_END_SESSION:
806 handleSessionEnd(cmd.slotId);
807 break;
808 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800809 }
810 }
811 }
812
Wink Savillee68857d2014-10-17 15:23:05 -0700813 private void callDelayedMsg(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800814 Message msg = mServiceHandler.obtainMessage();
815 msg.arg1 = OP_DELAYED_MSG;
Wink Savillee68857d2014-10-17 15:23:05 -0700816 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800817 mServiceHandler.sendMessage(msg);
818 }
819
Wink Savillee68857d2014-10-17 15:23:05 -0700820 private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) {
821 Message msg = mServiceHandler.obtainMessage();
822 msg.obj = obj;
823 msg.arg1 = inst_type;
824 msg.arg2 = slotId;
825 mServiceHandler.sendMessage(msg);
826 }
827
828 private void handleSessionEnd(int slotId) {
Legler Wuaeefef52014-10-27 00:57:18 +0800829 // We should finish all pending activity if receiving END SESSION command.
830 cleanUpInstanceStackBySlot(slotId);
831
Wink Savillee68857d2014-10-17 15:23:05 -0700832 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
833 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
834 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
835 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
836 mStkContext[slotId].mMenuState);
837
838 mStkContext[slotId].mIsInputPending = false;
839 mStkContext[slotId].mIsMenuPending = false;
840 mStkContext[slotId].mIsDialogPending = false;
841
Wink Savillee68857d2014-10-17 15:23:05 -0700842 if (mStkContext[slotId].mMainCmd == null) {
843 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
844 }
845 mStkContext[slotId].lastSelectedItem = null;
Wink Saville79085fc2009-06-09 10:27:23 -0700846 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800847 // update the current menu member.
Wink Savillee68857d2014-10-17 15:23:05 -0700848 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
849 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800850 }
Wink Savillee68857d2014-10-17 15:23:05 -0700851 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
852 // In mutiple instance architecture, the main menu for slotId will be finished when user
853 // goes to the Stk menu of the other SIM. So, we should launch a new instance for the
854 // main menu if the main menu instance has been finished.
855 // If the current menu is secondary menu, we should launch main menu.
856 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
857 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800858 }
Wink Savillee68857d2014-10-17 15:23:05 -0700859 if (mStkContext[slotId].mCmdsQ.size() != 0) {
860 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800861 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700862 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800863 }
864 // In case a launch browser command was just confirmed, launch that url.
Wink Savillee68857d2014-10-17 15:23:05 -0700865 if (mStkContext[slotId].launchBrowser) {
866 mStkContext[slotId].launchBrowser = false;
867 launchBrowser(mStkContext[slotId].mBrowserSettings);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800868 }
869 }
870
Preeti Ahuja560be362014-11-25 19:38:24 -0800871 // returns true if any Stk related activity already has focus on the screen
Yoshiaki Nakacec55b82017-10-20 15:53:43 +0900872 boolean isTopOfStack() {
pkanwareab12f32017-02-06 08:35:03 -0800873 ActivityManager mActivityManager = (ActivityManager) mContext
Preeti Ahuja560be362014-11-25 19:38:24 -0800874 .getSystemService(ACTIVITY_SERVICE);
pkanwareab12f32017-02-06 08:35:03 -0800875 String currentPackageName = null;
876 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
877 if (tasks == null || tasks.get(0).topActivity == null) {
878 return false;
879 }
880 currentPackageName = tasks.get(0).topActivity.getPackageName();
Preeti Ahuja560be362014-11-25 19:38:24 -0800881 if (null != currentPackageName) {
882 return currentPackageName.equals(PACKAGE_NAME);
883 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800884 return false;
885 }
886
Sooraj Sasindrana4160472016-10-12 16:28:25 -0700887 /**
888 * Get the boolean config from carrier config manager.
889 *
890 * @param context the context to get carrier service
891 * @param key config key defined in CarrierConfigManager
892 * @return boolean value of corresponding key.
893 */
894 private static boolean getBooleanCarrierConfig(Context context, String key) {
895 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
896 Context.CARRIER_CONFIG_SERVICE);
897 PersistableBundle b = null;
898 if (configManager != null) {
899 b = configManager.getConfig();
900 }
901 if (b != null) {
902 return b.getBoolean(key);
903 } else {
904 // Return static default defined in CarrierConfigManager.
905 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
906 }
907 }
908
Wink Savillee68857d2014-10-17 15:23:05 -0700909 private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700910
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800911 if (cmdMsg == null) {
912 return;
913 }
914 // save local reference for state tracking.
Wink Savillee68857d2014-10-17 15:23:05 -0700915 mStkContext[slotId].mCurrentCmd = cmdMsg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800916 boolean waitForUsersResponse = true;
917
Wink Savillee68857d2014-10-17 15:23:05 -0700918 mStkContext[slotId].mIsInputPending = false;
919 mStkContext[slotId].mIsMenuPending = false;
920 mStkContext[slotId].mIsDialogPending = false;
921
922 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800923 switch (cmdMsg.getCmdType()) {
924 case DISPLAY_TEXT:
925 TextMessage msg = cmdMsg.geTextMessage();
Jeevaka Badrappan854a25c2012-12-01 16:32:03 +0200926 waitForUsersResponse = msg.responseNeeded;
Wink Savillee68857d2014-10-17 15:23:05 -0700927 if (mStkContext[slotId].lastSelectedItem != null) {
928 msg.title = mStkContext[slotId].lastSelectedItem;
929 } else if (mStkContext[slotId].mMainCmd != null){
Yoshiaki Naka28313ba2017-08-04 12:20:53 +0900930 if (!getResources().getBoolean(R.bool.show_menu_title_only_on_menu)) {
931 msg.title = mStkContext[slotId].mMainCmd.getMenu().title;
932 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800933 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800934 //If we receive a low priority Display Text and the device is
935 // not displaying any STK related activity and the screen is not idle
936 // ( that is, device is in an interactive state), then send a screen busy
937 // terminal response. Otherwise display the message. The existing
938 // displayed message shall be updated with the new display text
939 // proactive command (Refer to ETSI TS 102 384 section 27.22.4.1.4.4.2).
940 if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible
941 || mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) {
942 if(!isScreenIdle()) {
943 CatLog.d(LOG_TAG, "Screen is not idle");
944 sendScreenBusyResponse(slotId);
945 } else {
946 launchTextDialog(slotId);
947 }
948 } else {
949 launchTextDialog(slotId);
950 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800951 break;
952 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700953 CatLog.d(LOG_TAG, "SELECT_ITEM +");
954 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
955 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
956 launchMenuActivity(cmdMsg.getMenu(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800957 break;
958 case SET_UP_MENU:
Wink Savillee68857d2014-10-17 15:23:05 -0700959 mStkContext[slotId].mCmdInProgress = false;
960 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
961 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
962 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
963 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
964
965 if (removeMenu(slotId)) {
966 int i = 0;
967 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App");
968 mStkContext[slotId].mCurrentMenu = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700969 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700970 //Check other setup menu state. If all setup menu are removed, uninstall apk.
971 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
972 if (i != slotId
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +0900973 && (mStkContext[i].mSetupMenuState == STATE_UNKNOWN
974 || mStkContext[i].mSetupMenuState == STATE_EXIST)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700975 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +0900976 + mStkContext[i].mSetupMenuState);
Wink Savillee68857d2014-10-17 15:23:05 -0700977 break;
978 }
979 }
980 if (i == mSimCount) {
981 StkAppInstaller.unInstall(mContext);
982 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800983 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700984 CatLog.d(LOG_TAG, "install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800985 StkAppInstaller.install(mContext);
986 }
Wink Savillee68857d2014-10-17 15:23:05 -0700987 if (mStkContext[slotId].mMenuIsVisible) {
988 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800989 }
990 break;
991 case GET_INPUT:
992 case GET_INKEY:
Wink Savillee68857d2014-10-17 15:23:05 -0700993 launchInputActivity(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800994 break;
995 case SET_UP_IDLE_MODE_TEXT:
996 waitForUsersResponse = false;
Preeti Ahuja560be362014-11-25 19:38:24 -0800997 mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd;
998 TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900999 if (idleModeText == null || TextUtils.isEmpty(idleModeText.text)) {
1000 cancelIdleText(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -08001001 }
1002 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001003 if (mStkContext[slotId].mIdleModeTextCmd != null) {
1004 if (mStkContext[slotId].mIdleModeTextVisible || isScreenIdle()) {
1005 CatLog.d(this, "set up idle mode");
1006 launchIdleText(slotId);
1007 } else {
1008 registerProcessObserver();
1009 }
Preeti Ahuja560be362014-11-25 19:38:24 -08001010 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001011 break;
1012 case SEND_DTMF:
1013 case SEND_SMS:
1014 case SEND_SS:
1015 case SEND_USSD:
Preeti Ahuja95919342013-10-01 18:18:55 -07001016 case GET_CHANNEL_STATUS:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001017 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -07001018 launchEventMessage(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001019 break;
1020 case LAUNCH_BROWSER:
Ryuto Sawada0bdc7192016-04-18 12:10:56 +09001021 // The device setup process should not be interrupted by launching browser.
1022 if (Settings.Global.getInt(mContext.getContentResolver(),
1023 Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
1024 CatLog.d(this, "The command is not performed if the setup has not been completed.");
1025 sendScreenBusyResponse(slotId);
1026 break;
1027 }
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001028
1029 /* Check if Carrier would not want to launch browser */
1030 if (getBooleanCarrierConfig(mContext,
1031 CarrierConfigManager.KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL)) {
1032 CatLog.d(this, "Browser is not launched as per carrier.");
1033 sendResponse(RES_ID_DONE, slotId, true);
1034 break;
1035 }
1036
Srikanth Chintalaba103002015-11-30 10:49:52 -08001037 mStkContext[slotId].mBrowserSettings =
1038 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
1039 if (!isUrlAvailableToLaunchBrowser(mStkContext[slotId].mBrowserSettings)) {
1040 CatLog.d(this, "Browser url property is not set - send error");
1041 sendResponse(RES_ID_ERROR, slotId, true);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001042 } else {
Srikanth Chintalaba103002015-11-30 10:49:52 -08001043 TextMessage alphaId = mStkContext[slotId].mCurrentCmd.geTextMessage();
1044 if ((alphaId == null) || TextUtils.isEmpty(alphaId.text)) {
1045 // don't need user confirmation in this case
1046 // just launch the browser or spawn a new tab
1047 CatLog.d(this, "user confirmation is not currently needed.\n" +
1048 "supressing confirmation dialogue and confirming silently...");
1049 mStkContext[slotId].launchBrowser = true;
1050 sendResponse(RES_ID_CONFIRM, slotId, true);
1051 } else {
1052 launchConfirmationDialog(alphaId, slotId);
1053 }
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001054 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001055 break;
1056 case SET_UP_CALL:
Preeti Ahujadd240102013-08-30 17:25:06 -07001057 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg;
1058 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) {
1059 mesg.text = getResources().getString(R.string.default_setup_call_msg);
1060 }
1061 CatLog.d(this, "SET_UP_CALL mesg.text " + mesg.text);
1062 launchConfirmationDialog(mesg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001063 break;
1064 case PLAY_TONE:
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301065 handlePlayTone(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001066 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001067 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -07001068 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001069 break;
1070 case CLOSE_CHANNEL:
1071 case RECEIVE_DATA:
1072 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -07001073 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001074
1075 if ((m != null) && (m.text == null)) {
1076 switch(cmdMsg.getCmdType()) {
1077 case CLOSE_CHANNEL:
1078 m.text = getResources().getString(R.string.default_close_channel_msg);
1079 break;
1080 case RECEIVE_DATA:
1081 m.text = getResources().getString(R.string.default_receive_data_msg);
1082 break;
1083 case SEND_DATA:
1084 m.text = getResources().getString(R.string.default_send_data_msg);
1085 break;
1086 }
1087 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001088 /*
1089 * Display indication in the form of a toast to the user if required.
1090 */
Wink Savillee68857d2014-10-17 15:23:05 -07001091 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001092 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001093 case SET_UP_EVENT_LIST:
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001094 replaceEventList(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -08001095 if (isScreenIdle()) {
1096 CatLog.d(this," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List");
1097 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
1098 }
Preeti Ahuja95919342013-10-01 18:18:55 -07001099 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001100 }
1101
1102 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -07001103 if (mStkContext[slotId].mCmdsQ.size() != 0) {
1104 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001105 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001106 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001107 }
1108 }
1109 }
1110
Wink Savillee68857d2014-10-17 15:23:05 -07001111 private void handleCmdResponse(Bundle args, int slotId) {
1112 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
1113 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001114 return;
1115 }
Wink Savillee68857d2014-10-17 15:23:05 -07001116
1117 if (mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +08001118 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001119 if (mStkService[slotId] == null) {
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001120 // This should never happen (we should be responding only to a message
1121 // that arrived from StkService). It has to exist by this time
Wink Savillee68857d2014-10-17 15:23:05 -07001122 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response.");
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001123 throw new RuntimeException("mStkService is null when we need to send response");
1124 }
1125 }
1126
Wink Savillee68857d2014-10-17 15:23:05 -07001127 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001128
1129 // set result code
1130 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001131 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001132
1133 switch(args.getInt(RES_ID)) {
1134 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -07001135 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
1136 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001137 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -07001138 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001139 case SET_UP_MENU:
1140 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -07001141 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001142 if (helpRequired) {
1143 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1144 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301145 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1146 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001147 }
1148 resMsg.setMenuSelection(menuSelection);
1149 break;
1150 }
1151 break;
1152 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001153 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001154 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -07001155 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
1156 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001157 boolean yesNoSelection = input
1158 .equals(StkInputActivity.YES_STR_RESPONSE);
1159 resMsg.setYesNo(yesNoSelection);
1160 } else {
1161 if (helpRequired) {
1162 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1163 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301164 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1165 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001166 resMsg.setInput(input);
1167 }
1168 }
1169 break;
1170 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -07001171 CatLog.d(this, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001172 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -07001173 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001174 case DISPLAY_TEXT:
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301175 if (confirmed) {
1176 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1177 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
1178 } else {
1179 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1180 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001181 break;
1182 case LAUNCH_BROWSER:
1183 resMsg.setResultCode(confirmed ? ResultCode.OK
1184 : ResultCode.UICC_SESSION_TERM_BY_USER);
1185 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001186 mStkContext[slotId].launchBrowser = true;
1187 mStkContext[slotId].mBrowserSettings =
1188 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001189 }
1190 break;
1191 case SET_UP_CALL:
1192 resMsg.setResultCode(ResultCode.OK);
1193 resMsg.setConfirmation(confirmed);
1194 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001195 launchEventMessage(slotId,
1196 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001197 }
1198 break;
1199 }
1200 break;
1201 case RES_ID_DONE:
1202 resMsg.setResultCode(ResultCode.OK);
1203 break;
1204 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -07001205 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001206 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
1207 break;
1208 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -07001209 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001210 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1211 break;
1212 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001213 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -08001214 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
1215 // Clear message after delay, successful) expects result code OK.
1216 // If the command qualifier specifies no user response is required
1217 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -07001218 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1219 AppInterface.CommandType.DISPLAY_TEXT.value())
1220 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -08001221 resMsg.setResultCode(ResultCode.OK);
1222 } else {
1223 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
1224 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001225 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001226 case RES_ID_CHOICE:
1227 int choice = args.getInt(CHOICE);
1228 CatLog.d(this, "User Choice=" + choice);
1229 switch (choice) {
1230 case YES:
1231 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001232 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001233 break;
1234 case NO:
1235 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
1236 break;
1237 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001238
Wink Savillee68857d2014-10-17 15:23:05 -07001239 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1240 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001241 resMsg.setConfirmation(confirmed);
1242 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001243 break;
Srikanth Chintalaba103002015-11-30 10:49:52 -08001244 case RES_ID_ERROR:
1245 CatLog.d(LOG_TAG, "RES_ID_ERROR");
1246 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
1247 case LAUNCH_BROWSER:
1248 resMsg.setResultCode(ResultCode.LAUNCH_BROWSER_ERROR);
1249 break;
1250 }
1251 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001252 default:
Wink Savillee68857d2014-10-17 15:23:05 -07001253 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001254 return;
1255 }
Wink Savillee68857d2014-10-17 15:23:05 -07001256
1257 if (null != mStkContext[slotId].mCurrentCmd &&
1258 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1259 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1260 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1261 }
1262 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001263 }
1264
1265 /**
1266 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1267 *
1268 * @param userAction If the userAction is yes then we always return 0 otherwise
1269 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1270 * then we are the foreground app and we'll return 0 as from our perspective a
1271 * user action did cause. If it's false than we aren't the foreground app and
1272 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001273 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001274 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1275 */
Wink Savillee68857d2014-10-17 15:23:05 -07001276 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1277 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1278 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1279 }
1280 /**
1281 * This method is used for cleaning up pending instances in stack.
1282 */
1283 private void cleanUpInstanceStackBySlot(int slotId) {
1284 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1285 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1286 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
Legler Wuaeefef52014-10-27 00:57:18 +08001287 if (mStkContext[slotId].mCurrentCmd == null) {
1288 CatLog.d(LOG_TAG, "current cmd is null.");
1289 return;
1290 }
Wink Savillee68857d2014-10-17 15:23:05 -07001291 if (activity != null) {
1292 CatLog.d(LOG_TAG, "current cmd type: " +
1293 mStkContext[slotId].mCurrentCmd.getCmdType());
1294 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1295 AppInterface.CommandType.GET_INPUT.value() ||
1296 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1297 AppInterface.CommandType.GET_INKEY.value()) {
1298 mStkContext[slotId].mIsInputPending = true;
1299 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1300 AppInterface.CommandType.SET_UP_MENU.value() ||
1301 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1302 AppInterface.CommandType.SELECT_ITEM.value()) {
1303 mStkContext[slotId].mIsMenuPending = true;
1304 } else {
1305 }
1306 CatLog.d(LOG_TAG, "finish pending activity.");
1307 activity.finish();
1308 mStkContext[slotId].mActivityInstance = null;
1309 }
1310 if (dialog != null) {
1311 CatLog.d(LOG_TAG, "finish pending dialog.");
1312 mStkContext[slotId].mIsDialogPending = true;
1313 dialog.finish();
1314 mStkContext[slotId].mDialogInstance = null;
1315 }
1316 }
1317 /**
1318 * This method is used for restoring pending instances from stack.
1319 */
1320 private void restoreInstanceFromStackBySlot(int slotId) {
1321 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1322
1323 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1324 switch(cmdType) {
1325 case GET_INPUT:
1326 case GET_INKEY:
1327 launchInputActivity(slotId);
1328 //Set mMenuIsVisible to true for showing main menu for
1329 //following session end command.
1330 mStkContext[slotId].mMenuIsVisible = true;
1331 break;
1332 case DISPLAY_TEXT:
1333 launchTextDialog(slotId);
1334 break;
1335 case LAUNCH_BROWSER:
1336 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1337 slotId);
1338 break;
1339 case OPEN_CHANNEL:
1340 launchOpenChannelDialog(slotId);
1341 break;
1342 case SET_UP_CALL:
1343 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1344 confirmMsg, slotId);
1345 break;
1346 case SET_UP_MENU:
1347 case SELECT_ITEM:
1348 launchMenuActivity(null, slotId);
1349 break;
1350 default:
1351 break;
1352 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001353 }
1354
Wink Savillee68857d2014-10-17 15:23:05 -07001355 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001356 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001357 String targetActivity = STK_MENU_ACTIVITY_NAME;
1358 String uriString = STK_MENU_URI + System.currentTimeMillis();
1359 //Set unique URI to create a new instance of activity for different slotId.
1360 Uri uriData = Uri.parse(uriString);
1361
1362 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1363 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1364 + mStkContext[slotId].mMenuState);
1365 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1366 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1367
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001368 if (menu == null) {
1369 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001370 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
1371 if (mStkContext[slotId].mOpCode == OP_END_SESSION) {
1372 CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION");
1373 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1374 if (mStkContext[slotId].mMainActivityInstance != null) {
1375 CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null");
1376 return;
1377 }
Wink Savillee68857d2014-10-17 15:23:05 -07001378 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001379
Wink Savillee68857d2014-10-17 15:23:05 -07001380 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1381 //Otherwise, it should be "STATE_MAIN".
1382 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1383 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1384 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1385 } else {
1386 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1387 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1388 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001389 } else {
1390 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001391 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001392 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001393 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001394 }
Wink Savillee68857d2014-10-17 15:23:05 -07001395 newIntent.putExtra(SLOT_ID, slotId);
1396 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001397 newIntent.setFlags(intentFlags);
1398 mContext.startActivity(newIntent);
1399 }
1400
Wink Savillee68857d2014-10-17 15:23:05 -07001401 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001402 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001403 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1404 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1405 //Set unique URI to create a new instance of activity for different slotId.
1406 Uri uriData = Uri.parse(uriString);
1407
1408 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001409 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001410 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1411 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1412 newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput());
1413 newIntent.putExtra(SLOT_ID, slotId);
1414 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001415 mContext.startActivity(newIntent);
1416 }
1417
Wink Savillee68857d2014-10-17 15:23:05 -07001418 private void launchTextDialog(int slotId) {
1419 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1420 Intent newIntent = new Intent();
1421 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1422 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1423 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1424 //Set unique URI to create a new instance of activity for different slotId.
1425 Uri uriData = Uri.parse(uriString);
1426 if (newIntent != null) {
1427 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1428 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1429 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1430 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1431 newIntent.setData(uriData);
1432 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1433 newIntent.putExtra(SLOT_ID, slotId);
1434 startActivity(newIntent);
Preeti Ahuja414bc412013-06-25 19:31:49 -07001435 // For display texts with immediate response, send the terminal response
1436 // immediately. responseNeeded will be false, if display text command has
1437 // the immediate response tlv.
1438 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
1439 sendResponse(RES_ID_CONFIRM, slotId, true);
1440 }
Wink Savillee68857d2014-10-17 15:23:05 -07001441 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001442 }
1443
Wink Savillee68857d2014-10-17 15:23:05 -07001444 public boolean isStkDialogActivated(Context context) {
1445 String stkDialogActivity = "com.android.stk.StkDialogActivity";
1446 boolean activated = false;
1447 final ActivityManager am = (ActivityManager) context.getSystemService(
1448 Context.ACTIVITY_SERVICE);
1449 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName();
1450
1451 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity);
1452 if (topActivity.equals(stkDialogActivity)) {
1453 activated = true;
1454 }
1455 CatLog.d(LOG_TAG, "activated : " + activated);
1456 return activated;
Johan Hellman3aec01c2011-02-10 10:15:28 +01001457 }
1458
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001459 private void replaceEventList(int slotId) {
1460 if (mStkContext[slotId].mSetupEventListSettings != null) {
1461 for (int current : mStkContext[slotId].mSetupEventListSettings.eventList) {
1462 if (current != INVALID_SETUP_EVENT) {
1463 // Cancel the event notification if it is not listed in the new event list.
1464 if ((mStkContext[slotId].mCurrentCmd.getSetEventList() == null)
1465 || !findEvent(current, mStkContext[slotId].mCurrentCmd
1466 .getSetEventList().eventList)) {
1467 unregisterEvent(current, slotId);
1468 }
1469 }
1470 }
1471 }
1472 mStkContext[slotId].mSetupEventListSettings
1473 = mStkContext[slotId].mCurrentCmd.getSetEventList();
1474 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
1475 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
1476 registerEvents(slotId);
1477 }
1478
1479 private boolean findEvent(int event, int[] eventList) {
1480 for (int content : eventList) {
1481 if (content == event) return true;
1482 }
1483 return false;
1484 }
1485
1486 private void unregisterEvent(int event, int slotId) {
1487 switch (event) {
1488 case IDLE_SCREEN_AVAILABLE_EVENT:
1489 unregisterProcessObserver(AppInterface.CommandType.SET_UP_EVENT_LIST, slotId);
1490 break;
1491 case LANGUAGE_SELECTION_EVENT:
1492 default:
1493 break;
1494 }
1495 }
1496
1497 private void registerEvents(int slotId) {
1498 if (mStkContext[slotId].mSetupEventListSettings == null) {
1499 return;
1500 }
1501 for (int event : mStkContext[slotId].mSetupEventListSettings.eventList) {
1502 switch (event) {
1503 case IDLE_SCREEN_AVAILABLE_EVENT:
1504 registerProcessObserver();
1505 break;
1506 case LANGUAGE_SELECTION_EVENT:
1507 default:
1508 break;
1509 }
1510 }
1511 }
1512
1513 private synchronized void registerProcessObserver() {
1514 if (mProcessObserver == null) {
1515 try {
1516 IProcessObserver.Stub observer = new IProcessObserver.Stub() {
1517 @Override
1518 public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
1519 if (isScreenIdle()) {
1520 Message message = mServiceHandler.obtainMessage();
1521 message.arg1 = OP_IDLE_SCREEN;
1522 mServiceHandler.sendMessage(message);
1523 unregisterProcessObserver();
1524 }
1525 }
1526
1527 @Override
1528 public void onProcessDied(int pid, int uid) {
1529 }
1530 };
1531 ActivityManagerNative.getDefault().registerProcessObserver(observer);
1532 mProcessObserver = observer;
1533 } catch (RemoteException e) {
1534 CatLog.d(this, "Failed to register the process observer");
1535 }
1536 }
1537 }
1538
1539 private void unregisterProcessObserver(AppInterface.CommandType command, int slotId) {
1540 // Check if there is any pending command which still needs the process observer
1541 // except for the current command and slot.
1542 for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
1543 if (command != AppInterface.CommandType.SET_UP_IDLE_MODE_TEXT || slot != slotId) {
1544 if (mStkContext[slot].mIdleModeTextCmd != null
1545 && !mStkContext[slot].mIdleModeTextVisible) {
1546 // Keep the process observer registered
1547 // as there is an idle mode text which has not been visible yet.
1548 return;
1549 }
1550 }
1551 if (command != AppInterface.CommandType.SET_UP_EVENT_LIST || slot != slotId) {
1552 if (mStkContext[slot].mSetupEventListSettings != null) {
1553 if (findEvent(IDLE_SCREEN_AVAILABLE_EVENT,
1554 mStkContext[slot].mSetupEventListSettings.eventList)) {
1555 // Keep the process observer registered
1556 // as there is a SIM card which still want IDLE SCREEN AVAILABLE event.
1557 return;
1558 }
1559 }
1560 }
1561 }
1562 unregisterProcessObserver();
1563 }
1564
1565 private synchronized void unregisterProcessObserver() {
1566 if (mProcessObserver != null) {
1567 try {
1568 ActivityManagerNative.getDefault().unregisterProcessObserver(mProcessObserver);
1569 mProcessObserver = null;
1570 } catch (RemoteException e) {
1571 CatLog.d(this, "Failed to unregister the process observer");
1572 }
1573 }
1574 }
1575
Preeti Ahuja95919342013-10-01 18:18:55 -07001576 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
Preeti Ahuja414bc412013-06-25 19:31:49 -07001577 CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -07001578
1579 if (mStkContext[slotId].mCurrentSetupEventCmd == null){
1580 CatLog.e(this, "mCurrentSetupEventCmd is null");
1581 return;
1582 }
1583
1584 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd);
1585
1586 resMsg.setResultCode(ResultCode.OK);
1587 resMsg.setEventDownload(event, addedInfo);
1588
1589 mStkService[slotId].onCmdResponse(resMsg);
1590 }
1591
1592 private void checkForSetupEvent(int event, Bundle args, int slotId) {
1593 boolean eventPresent = false;
1594 byte[] addedInfo = null;
1595 CatLog.d(this, "Event :" + event);
1596
1597 if (mStkContext[slotId].mSetupEventListSettings != null) {
1598 /* Checks if the event is present in the EventList updated by last
1599 * SetupEventList Proactive Command */
1600 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) {
1601 if (event == i) {
1602 eventPresent = true;
1603 break;
1604 }
1605 }
1606
1607 /* If Event is present send the response to ICC */
1608 if (eventPresent == true) {
1609 CatLog.d(this, " Event " + event + "exists in the EventList");
1610
1611 switch (event) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001612 case IDLE_SCREEN_AVAILABLE_EVENT:
1613 sendSetUpEventResponse(event, addedInfo, slotId);
1614 removeSetUpEvent(event, slotId);
1615 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001616 case LANGUAGE_SELECTION_EVENT:
1617 String language = mContext
1618 .getResources().getConfiguration().locale.getLanguage();
1619 CatLog.d(this, "language: " + language);
1620 // Each language code is a pair of alpha-numeric characters.
1621 // Each alpha-numeric character shall be coded on one byte
1622 // using the SMS default 7-bit coded alphabet
1623 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language);
1624 sendSetUpEventResponse(event, addedInfo, slotId);
1625 break;
1626 default:
1627 break;
1628 }
1629 } else {
1630 CatLog.e(this, " Event does not exist in the EventList");
1631 }
1632 } else {
1633 CatLog.e(this, "SetupEventList is not received. Ignoring the event: " + event);
1634 }
1635 }
1636
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001637 private void removeSetUpEvent(int event, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -07001638 CatLog.d(this, "Remove Event :" + event);
1639
1640 if (mStkContext[slotId].mSetupEventListSettings != null) {
1641 /*
1642 * Make new Eventlist without the event
1643 */
1644 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
1645 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
1646 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001647
1648 switch (event) {
1649 case IDLE_SCREEN_AVAILABLE_EVENT:
1650 // The process observer can be unregistered
1651 // as the idle screen has already been available.
1652 unregisterProcessObserver();
1653 break;
1654 default:
1655 break;
1656 }
Preeti Ahuja95919342013-10-01 18:18:55 -07001657 break;
1658 }
1659 }
1660 }
1661 }
1662
1663 private void launchEventMessage(int slotId) {
1664 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
1665 }
1666
Wink Savillee68857d2014-10-17 15:23:05 -07001667 private void launchEventMessage(int slotId, TextMessage msg) {
Ryuto Sawada2ba20cc2015-12-28 17:10:35 +01001668 if (msg == null || msg.text == null || (msg.text != null && msg.text.length() == 0)) {
Wink Savillee68857d2014-10-17 15:23:05 -07001669 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001670 return;
1671 }
Wink Savillee68857d2014-10-17 15:23:05 -07001672
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001673 Toast toast = new Toast(mContext.getApplicationContext());
1674 LayoutInflater inflate = (LayoutInflater) mContext
1675 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1676 View v = inflate.inflate(R.layout.stk_event_msg, null);
1677 TextView tv = (TextView) v
1678 .findViewById(com.android.internal.R.id.message);
1679 ImageView iv = (ImageView) v
1680 .findViewById(com.android.internal.R.id.icon);
1681 if (msg.icon != null) {
1682 iv.setImageBitmap(msg.icon);
1683 } else {
1684 iv.setVisibility(View.GONE);
1685 }
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301686 /* In case of 'self explanatory' stkapp should display the specified
1687 * icon in proactive command (but not the alpha string).
1688 * If icon is non-self explanatory and if the icon could not be displayed
1689 * then alpha string or text data should be displayed
1690 * Ref: ETSI 102.223,section 6.5.4
1691 */
1692 if (mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ||
1693 msg.icon == null || !msg.iconSelfExplanatory) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001694 tv.setText(msg.text);
1695 }
1696
1697 toast.setView(v);
1698 toast.setDuration(Toast.LENGTH_LONG);
1699 toast.setGravity(Gravity.BOTTOM, 0, 0);
1700 toast.show();
1701 }
1702
Wink Savillee68857d2014-10-17 15:23:05 -07001703 private void launchConfirmationDialog(TextMessage msg, int slotId) {
1704 msg.title = mStkContext[slotId].lastSelectedItem;
1705 Intent newIntent = new Intent();
1706 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1707 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1708 //Set unique URI to create a new instance of activity for different slotId.
1709 Uri uriData = Uri.parse(uriString);
1710
1711 if (newIntent != null) {
1712 newIntent.setClassName(this, targetActivity);
1713 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1714 | Intent.FLAG_ACTIVITY_NO_HISTORY
1715 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1716 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1717 newIntent.putExtra("TEXT", msg);
1718 newIntent.putExtra(SLOT_ID, slotId);
1719 newIntent.setData(uriData);
1720 startActivity(newIntent);
1721 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001722 }
1723
1724 private void launchBrowser(BrowserSettings settings) {
1725 if (settings == null) {
1726 return;
1727 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001728
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001729 Uri data = null;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001730 String url;
1731 if (settings.url == null) {
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001732 // if the command did not contain a URL,
1733 // launch the browser to the default homepage.
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001734 CatLog.d(this, "no url data provided by proactive command." +
1735 " launching browser with stk default URL ... ");
1736 url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP,
1737 "http://www.google.com");
1738 } else {
1739 CatLog.d(this, "launch browser command has attached url = " + settings.url);
1740 url = settings.url;
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001741 }
David Brown7c03cfe2011-10-20 15:36:12 -07001742
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001743 if (url.startsWith("http://") || url.startsWith("https://")) {
1744 data = Uri.parse(url);
1745 CatLog.d(this, "launching browser with url = " + url);
1746 } else {
1747 String modifiedUrl = "http://" + url;
1748 data = Uri.parse(modifiedUrl);
1749 CatLog.d(this, "launching browser with modified url = " + modifiedUrl);
1750 }
1751
1752 Intent intent = new Intent(Intent.ACTION_VIEW);
1753 intent.setData(data);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001754 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1755 switch (settings.mode) {
1756 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001757 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1758 break;
1759 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001760 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
1761 break;
1762 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
1763 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1764 break;
1765 }
1766 // start browser activity
1767 startActivity(intent);
1768 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07001769 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001770 // followed immediately.
1771 try {
Ryuto Sawada350aaa62016-06-13 14:47:22 +09001772 Thread.sleep(3000);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001773 } catch (InterruptedException e) {}
1774 }
1775
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001776 private void cancelIdleText(int slotId) {
1777 unregisterProcessObserver(AppInterface.CommandType.SET_UP_IDLE_MODE_TEXT, slotId);
1778 mNotificationManager.cancel(getNotificationId(slotId));
1779 mStkContext[slotId].mIdleModeTextCmd = null;
1780 mStkContext[slotId].mIdleModeTextVisible = false;
1781 }
1782
Wink Savillee68857d2014-10-17 15:23:05 -07001783 private void launchIdleText(int slotId) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001784 TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001785
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001786 if (msg != null && !TextUtils.isEmpty(msg.text)) {
Preeti Ahuja95919342013-10-01 18:18:55 -07001787 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
1788 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
1789 + "] icon[" + msg.icon + "], sim id: " + slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001790 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001791 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001792 new Intent(mContext, StkAppService.class), 0);
fionaxu805eb572017-05-02 10:57:30 -07001793 createAllChannels();
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001794 final Notification.Builder notificationBuilder = new Notification.Builder(
fionaxu2c91c752017-04-21 18:11:57 -07001795 StkAppService.this, STK_NOTIFICATION_CHANNEL_ID);
Wink Savillee68857d2014-10-17 15:23:05 -07001796 if (mStkContext[slotId].mMainCmd != null &&
1797 mStkContext[slotId].mMainCmd.getMenu() != null) {
1798 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001799 } else {
1800 notificationBuilder.setContentTitle("");
1801 }
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001802 notificationBuilder
1803 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1804 notificationBuilder.setContentIntent(pendingIntent);
1805 notificationBuilder.setOngoing(true);
1806 // Set text and icon for the status bar and notification body.
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301807 if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() ||
1808 !msg.iconSelfExplanatory) {
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001809 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001810 notificationBuilder.setTicker(msg.text);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001811 }
1812 if (msg.icon != null) {
1813 notificationBuilder.setLargeIcon(msg.icon);
1814 } else {
1815 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
1816 .getResources().getSystem(),
1817 com.android.internal.R.drawable.stat_notify_sim_toolkit);
1818 notificationBuilder.setLargeIcon(bitmapIcon);
1819 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02001820 notificationBuilder.setColor(mContext.getResources().getColor(
1821 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07001822 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001823 mStkContext[slotId].mIdleModeTextVisible = true;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001824 }
1825 }
1826
fionaxu805eb572017-05-02 10:57:30 -07001827 /** Creates the notification channel and registers it with NotificationManager.
1828 * If a channel with the same ID is already registered, NotificationManager will
1829 * ignore this call.
1830 */
1831 private void createAllChannels() {
1832 mNotificationManager.createNotificationChannel(new NotificationChannel(
1833 STK_NOTIFICATION_CHANNEL_ID,
1834 getResources().getString(R.string.stk_channel_name),
1835 NotificationManager.IMPORTANCE_MIN));
1836 }
1837
Wink Savillee68857d2014-10-17 15:23:05 -07001838 private void launchToneDialog(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001839 Intent newIntent = new Intent(this, ToneDialog.class);
Wink Savillee68857d2014-10-17 15:23:05 -07001840 String uriString = STK_TONE_URI + slotId;
1841 Uri uriData = Uri.parse(uriString);
1842 //Set unique URI to create a new instance of activity for different slotId.
1843 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001844 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1845 | Intent.FLAG_ACTIVITY_NO_HISTORY
1846 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Wink Savillee68857d2014-10-17 15:23:05 -07001847 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1848 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1849 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
1850 newIntent.putExtra(SLOT_ID, slotId);
1851 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001852 startActivity(newIntent);
1853 }
1854
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301855 private void handlePlayTone(int slotId) {
1856 TextMessage toneMsg = mStkContext[slotId].mCurrentCmd.geTextMessage();
1857
1858 boolean showUser = true;
1859 boolean displayDialog = true;
1860 Resources resource = Resources.getSystem();
1861 try {
1862 displayDialog = !resource.getBoolean(
1863 com.android.internal.R.bool.config_stkNoAlphaUsrCnf);
1864 } catch (NotFoundException e) {
1865 displayDialog = true;
1866 }
1867
1868 // As per the spec 3GPP TS 11.14, 6.4.5. Play Tone.
1869 // If there is no alpha identifier tlv present, UE may show the
1870 // user information. 'config_stkNoAlphaUsrCnf' value will decide
1871 // whether to show it or not.
1872 // If alpha identifier tlv is present and its data is null, play only tone
1873 // without showing user any information.
1874 // Alpha Id is Present, but the text data is null.
1875 if ((toneMsg.text != null ) && (toneMsg.text.equals(""))) {
1876 CatLog.d(this, "Alpha identifier data is null, play only tone");
1877 showUser = false;
1878 }
1879 // Alpha Id is not present AND we need to show info to the user.
1880 if (toneMsg.text == null && displayDialog) {
1881 CatLog.d(this, "toneMsg.text " + toneMsg.text
1882 + " Starting ToneDialog activity with default message.");
1883 toneMsg.text = getResources().getString(R.string.default_tone_dialog_msg);
1884 showUser = true;
1885 }
1886 // Dont show user info, if config setting is true.
1887 if (toneMsg.text == null && !displayDialog) {
1888 CatLog.d(this, "config value stkNoAlphaUsrCnf is true");
1889 showUser = false;
1890 }
1891
1892 CatLog.d(this, "toneMsg.text: " + toneMsg.text + "showUser: " +showUser +
1893 "displayDialog: " +displayDialog);
1894 playTone(showUser, slotId);
1895 }
1896
1897 private void playTone(boolean showUserInfo, int slotId) {
1898 // Start playing tone and vibration
1899 ToneSettings settings = mStkContext[slotId].mCurrentCmd.getToneSettings();
1900 if (null == settings) {
1901 CatLog.d(this, "null settings, not playing tone.");
1902 return;
1903 }
1904
1905 mVibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
1906 mTonePlayer = new TonePlayer();
1907 mTonePlayer.play(settings.tone);
1908 int timeout = StkApp.calculateDurationInMilis(settings.duration);
1909 if (timeout == 0) {
1910 timeout = StkApp.TONE_DEFAULT_TIMEOUT;
1911 }
1912
1913 Message msg = mServiceHandler.obtainMessage();
1914 msg.arg1 = OP_STOP_TONE;
1915 msg.arg2 = slotId;
1916 msg.obj = (Integer)(showUserInfo ? 1 : 0);
1917 msg.what = STOP_TONE_WHAT;
1918 mServiceHandler.sendMessageDelayed(msg, timeout);
1919 if (settings.vibrate) {
1920 mVibrator.vibrate(timeout);
1921 }
1922
1923 // Start Tone dialog Activity to show user the information.
1924 if (showUserInfo) {
1925 Intent newIntent = new Intent(sInstance, ToneDialog.class);
1926 String uriString = STK_TONE_URI + slotId;
1927 Uri uriData = Uri.parse(uriString);
1928 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1929 | Intent.FLAG_ACTIVITY_NO_HISTORY
1930 | Intent.FLAG_ACTIVITY_SINGLE_TOP
1931 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1932 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1933 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1934 newIntent.putExtra(SLOT_ID, slotId);
1935 newIntent.setData(uriData);
1936 startActivity(newIntent);
1937 }
1938 }
1939
1940 private void finishToneDialogActivity() {
1941 Intent finishIntent = new Intent(FINISH_TONE_ACTIVITY_ACTION);
1942 sendBroadcast(finishIntent);
1943 }
1944
1945 private void handleStopTone(Message msg, int slotId) {
1946 int resId = 0;
1947
1948 // Stop the play tone in following cases:
1949 // 1.OP_STOP_TONE: play tone timer expires.
1950 // 2.STOP_TONE_USER: user pressed the back key.
1951 if (msg.arg1 == OP_STOP_TONE) {
1952 resId = RES_ID_DONE;
1953 // Dismiss Tone dialog, after finishing off playing the tone.
1954 int finishActivity = (Integer) msg.obj;
1955 if (finishActivity == 1) finishToneDialogActivity();
1956 } else if (msg.arg1 == OP_STOP_TONE_USER) {
1957 resId = RES_ID_END_SESSION;
1958 }
1959
1960 sendResponse(resId, slotId, true);
1961 mServiceHandler.removeMessages(STOP_TONE_WHAT);
1962 if (mTonePlayer != null) {
1963 mTonePlayer.stop();
1964 mTonePlayer.release();
1965 mTonePlayer = null;
1966 }
1967 if (mVibrator != null) {
1968 mVibrator.cancel();
1969 mVibrator = null;
1970 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001971 }
1972
Takanori Nakano49b12722016-02-16 14:34:14 +09001973 private void launchOpenChannelDialog(final int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -07001974 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001975 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001976 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001977 return;
1978 }
1979
1980 msg.title = getResources().getString(R.string.stk_dialog_title);
1981 if (msg.text == null) {
1982 msg.text = getResources().getString(R.string.default_open_channel_msg);
1983 }
1984
1985 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1986 .setIconAttribute(android.R.attr.alertDialogIcon)
1987 .setTitle(msg.title)
1988 .setMessage(msg.text)
1989 .setCancelable(false)
1990 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
1991 new DialogInterface.OnClickListener() {
1992 public void onClick(DialogInterface dialog, int which) {
1993 Bundle args = new Bundle();
1994 args.putInt(RES_ID, RES_ID_CHOICE);
1995 args.putInt(CHOICE, YES);
1996 Message message = mServiceHandler.obtainMessage();
1997 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09001998 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001999 message.obj = args;
2000 mServiceHandler.sendMessage(message);
2001 }
2002 })
2003 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
2004 new DialogInterface.OnClickListener() {
2005 public void onClick(DialogInterface dialog, int which) {
2006 Bundle args = new Bundle();
2007 args.putInt(RES_ID, RES_ID_CHOICE);
2008 args.putInt(CHOICE, NO);
2009 Message message = mServiceHandler.obtainMessage();
2010 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09002011 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002012 message.obj = args;
2013 mServiceHandler.sendMessage(message);
2014 }
2015 })
2016 .create();
2017
2018 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2019 if (!mContext.getResources().getBoolean(
2020 com.android.internal.R.bool.config_sf_slowBlur)) {
2021 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
2022 }
2023
2024 dialog.show();
2025 }
2026
Wink Savillee68857d2014-10-17 15:23:05 -07002027 private void launchTransientEventMessage(int slotId) {
2028 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002029 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07002030 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002031 return;
2032 }
2033
2034 msg.title = getResources().getString(R.string.stk_dialog_title);
2035
2036 final AlertDialog dialog = new AlertDialog.Builder(mContext)
2037 .setIconAttribute(android.R.attr.alertDialogIcon)
2038 .setTitle(msg.title)
2039 .setMessage(msg.text)
2040 .setCancelable(false)
2041 .setPositiveButton(getResources().getString(android.R.string.ok),
2042 new DialogInterface.OnClickListener() {
2043 public void onClick(DialogInterface dialog, int which) {
2044 }
2045 })
2046 .create();
2047
2048 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2049 if (!mContext.getResources().getBoolean(
2050 com.android.internal.R.bool.config_sf_slowBlur)) {
2051 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
2052 }
2053
2054 dialog.show();
2055 }
2056
Wink Savillee68857d2014-10-17 15:23:05 -07002057 private int getNotificationId(int slotId) {
2058 int notifyId = STK_NOTIFICATION_ID;
2059 if (slotId >= 0 && slotId < mSimCount) {
2060 notifyId += slotId;
2061 } else {
2062 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
2063 }
2064 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
2065 return notifyId;
2066 }
2067
2068 private String getItemName(int itemId, int slotId) {
2069 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002070 if (menu == null) {
2071 return null;
2072 }
2073 for (Item item : menu.items) {
2074 if (item.id == itemId) {
2075 return item.text;
2076 }
2077 }
2078 return null;
2079 }
2080
Wink Savillee68857d2014-10-17 15:23:05 -07002081 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002082 try {
Wink Savillee68857d2014-10-17 15:23:05 -07002083 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
2084 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
2085 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002086 return true;
2087 }
2088 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07002089 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
2090 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002091 return true;
2092 }
Wink Savillee68857d2014-10-17 15:23:05 -07002093 mStkContext[slotId].mSetupMenuState = STATE_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002094 return false;
2095 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05302096
Wink Savillee68857d2014-10-17 15:23:05 -07002097 StkContext getStkContext(int slotId) {
2098 if (slotId >= 0 && slotId < mSimCount) {
2099 return mStkContext[slotId];
2100 } else {
2101 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
2102 return null;
2103 }
2104 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05302105
2106 private void handleAlphaNotify(Bundle args) {
2107 String alphaString = args.getString(AppInterface.ALPHA_STRING);
2108
2109 CatLog.d(this, "Alpha string received from card: " + alphaString);
2110 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
2111 toast.setGravity(Gravity.TOP, 0, 0);
2112 toast.show();
2113 }
Srikanth Chintalaba103002015-11-30 10:49:52 -08002114
2115 private boolean isUrlAvailableToLaunchBrowser(BrowserSettings settings) {
2116 String url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP, "");
2117 if (url == "" && settings.url == null) {
2118 return false;
2119 }
2120 return true;
2121 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002122}