blob: 85a6a7249d35bef8ac2473f80af5e53466093c28 [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;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080028import android.content.Context;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050029import android.content.DialogInterface;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080030import android.content.Intent;
Preeti Ahuja95919342013-10-01 18:18:55 -070031import android.content.res.Configuration;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053032import android.content.res.Resources;
33import android.content.res.Resources.NotFoundException;
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +010034import android.graphics.Bitmap;
35import android.graphics.BitmapFactory;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080036import android.net.Uri;
37import android.os.Bundle;
38import android.os.Handler;
39import android.os.IBinder;
40import android.os.Looper;
41import android.os.Message;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070042import android.os.PersistableBundle;
Preeti Ahuja560be362014-11-25 19:38:24 -080043import android.os.PowerManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070044import android.os.SystemProperties;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053045import android.os.Vibrator;
Preeti Ahuja95919342013-10-01 18:18:55 -070046import android.provider.Settings;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070047import android.telephony.CarrierConfigManager;
Wink Saville56469d52009-04-02 01:37:03 -070048import android.telephony.TelephonyManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070049import android.text.TextUtils;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080050import android.view.Gravity;
51import android.view.LayoutInflater;
52import android.view.View;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050053import android.view.WindowManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080054import android.widget.ImageView;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080055import android.widget.TextView;
56import android.widget.Toast;
Wink Savillee68857d2014-10-17 15:23:05 -070057import android.content.IntentFilter;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080058
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070059import com.android.internal.telephony.cat.AppInterface;
Preeti Ahuja95919342013-10-01 18:18:55 -070060import com.android.internal.telephony.cat.LaunchBrowserMode;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070061import com.android.internal.telephony.cat.Menu;
62import com.android.internal.telephony.cat.Item;
63import com.android.internal.telephony.cat.ResultCode;
64import com.android.internal.telephony.cat.CatCmdMessage;
65import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
Preeti Ahuja95919342013-10-01 18:18:55 -070066import com.android.internal.telephony.cat.CatCmdMessage.SetupEventListSettings;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070067import com.android.internal.telephony.cat.CatLog;
68import com.android.internal.telephony.cat.CatResponseMessage;
69import com.android.internal.telephony.cat.TextMessage;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053070import com.android.internal.telephony.cat.ToneSettings;
Wink Saville94e982b2014-07-11 07:38:14 -070071import com.android.internal.telephony.uicc.IccRefreshResponse;
Wink Savillee68857d2014-10-17 15:23:05 -070072import com.android.internal.telephony.PhoneConstants;
Preeti Ahuja95919342013-10-01 18:18:55 -070073import com.android.internal.telephony.GsmAlphabet;
Legler Wuaeefef52014-10-27 00:57:18 +080074import com.android.internal.telephony.cat.CatService;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080075
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070076import java.util.Iterator;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080077import java.util.LinkedList;
Wink Savillee68857d2014-10-17 15:23:05 -070078import java.lang.System;
79import java.util.List;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080080
Preeti Ahuja95919342013-10-01 18:18:55 -070081import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja560be362014-11-25 19:38:24 -080082 SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
83import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja95919342013-10-01 18:18:55 -070084 SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
85
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080086/**
87 * SIM toolkit application level service. Interacts with Telephopny messages,
88 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -070089 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080090 */
91public class StkAppService extends Service implements Runnable {
92
93 // members
Wink Savillee68857d2014-10-17 15:23:05 -070094 protected class StkContext {
95 protected CatCmdMessage mMainCmd = null;
96 protected CatCmdMessage mCurrentCmd = null;
97 protected CatCmdMessage mCurrentMenuCmd = null;
98 protected Menu mCurrentMenu = null;
99 protected String lastSelectedItem = null;
100 protected boolean mMenuIsVisible = false;
101 protected boolean mIsInputPending = false;
102 protected boolean mIsMenuPending = false;
103 protected boolean mIsDialogPending = false;
104 protected boolean responseNeeded = true;
105 protected boolean launchBrowser = false;
106 protected BrowserSettings mBrowserSettings = null;
107 protected LinkedList<DelayedCmd> mCmdsQ = null;
108 protected boolean mCmdInProgress = false;
109 protected int mStkServiceState = STATE_UNKNOWN;
110 protected int mSetupMenuState = STATE_UNKNOWN;
111 protected int mMenuState = StkMenuActivity.STATE_INIT;
112 protected int mOpCode = -1;
113 private Activity mActivityInstance = null;
114 private Activity mDialogInstance = null;
115 private Activity mMainActivityInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700116 private int mSlotId = 0;
Preeti Ahuja95919342013-10-01 18:18:55 -0700117 private SetupEventListSettings mSetupEventListSettings = null;
118 private boolean mClearSelectItem = false;
119 private boolean mDisplayTextDlgIsVisibile = false;
120 private CatCmdMessage mCurrentSetupEventCmd = null;
Preeti Ahuja560be362014-11-25 19:38:24 -0800121 private CatCmdMessage mIdleModeTextCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700122 final synchronized void setPendingActivityInstance(Activity act) {
123 CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act);
124 callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
125 }
126 final synchronized Activity getPendingActivityInstance() {
127 CatLog.d(this, "getPendingActivityInstance act : " + mSlotId + ", " +
128 mActivityInstance);
129 return mActivityInstance;
130 }
131 final synchronized void setPendingDialogInstance(Activity act) {
132 CatLog.d(this, "setPendingDialogInstance act : " + mSlotId + ", " + act);
133 callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act);
134 }
135 final synchronized Activity getPendingDialogInstance() {
136 CatLog.d(this, "getPendingDialogInstance act : " + mSlotId + ", " +
137 mDialogInstance);
138 return mDialogInstance;
139 }
140 final synchronized void setMainActivityInstance(Activity act) {
141 CatLog.d(this, "setMainActivityInstance act : " + mSlotId + ", " + act);
142 callSetActivityInstMsg(OP_SET_MAINACT_INST, mSlotId, act);
143 }
144 final synchronized Activity getMainActivityInstance() {
145 CatLog.d(this, "getMainActivityInstance act : " + mSlotId + ", " +
146 mMainActivityInstance);
147 return mMainActivityInstance;
148 }
149 }
150
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800151 private volatile Looper mServiceLooper;
152 private volatile ServiceHandler mServiceHandler;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800153 private Context mContext = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800154 private NotificationManager mNotificationManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800155 static StkAppService sInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700156 private AppInterface[] mStkService = null;
157 private StkContext[] mStkContext = null;
158 private int mSimCount = 0;
Preeti Ahuja560be362014-11-25 19:38:24 -0800159 private PowerManager mPowerManager = null;
160 private StkCmdReceiver mStkCmdReceiver = null;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530161 private TonePlayer mTonePlayer = null;
162 private Vibrator mVibrator = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700163
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800164 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
165 // creating an intent.
166 private enum InitiatedByUserAction {
167 yes, // The action was started via a user initiated action
168 unknown, // Not known for sure if user initated the action
169 }
170
171 // constants
172 static final String OPCODE = "op";
173 static final String CMD_MSG = "cmd message";
174 static final String RES_ID = "response id";
175 static final String MENU_SELECTION = "menu selection";
176 static final String INPUT = "input";
177 static final String HELP = "help";
178 static final String CONFIRMATION = "confirm";
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500179 static final String CHOICE = "choice";
Wink Savillee68857d2014-10-17 15:23:05 -0700180 static final String SLOT_ID = "SLOT_ID";
181 static final String STK_CMD = "STK CMD";
182 static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/";
183 static final String STK_MENU_URI = "stk://com.android.stk/menu/";
184 static final String STK_INPUT_URI = "stk://com.android.stk/input/";
185 static final String STK_TONE_URI = "stk://com.android.stk/tone/";
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530186 static final String FINISH_TONE_ACTIVITY_ACTION =
187 "android.intent.action.stk.finish_activity";
Preeti Ahuja95919342013-10-01 18:18:55 -0700188
189 // These below constants are used for SETUP_EVENT_LIST
190 static final String SETUP_EVENT_TYPE = "event";
191 static final String SETUP_EVENT_CAUSE = "cause";
192
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800193 // operations ids for different service functionality.
194 static final int OP_CMD = 1;
195 static final int OP_RESPONSE = 2;
196 static final int OP_LAUNCH_APP = 3;
197 static final int OP_END_SESSION = 4;
198 static final int OP_BOOT_COMPLETED = 5;
199 private static final int OP_DELAYED_MSG = 6;
Wink Saville94e982b2014-07-11 07:38:14 -0700200 static final int OP_CARD_STATUS_CHANGED = 7;
Wink Savillee68857d2014-10-17 15:23:05 -0700201 static final int OP_SET_ACT_INST = 8;
202 static final int OP_SET_DAL_INST = 9;
203 static final int OP_SET_MAINACT_INST = 10;
Preeti Ahujab3d0e612014-11-20 13:29:25 -0800204 static final int OP_LOCALE_CHANGED = 11;
205 static final int OP_ALPHA_NOTIFY = 12;
Preeti Ahuja560be362014-11-25 19:38:24 -0800206 static final int OP_IDLE_SCREEN = 13;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800207
Preeti Ahuja95919342013-10-01 18:18:55 -0700208 //Invalid SetupEvent
209 static final int INVALID_SETUP_EVENT = 0xFF;
210
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530211 // Message id to signal stop tone due to play tone timeout.
212 private static final int OP_STOP_TONE = 16;
213
214 // Message id to signal stop tone on user keyback.
215 static final int OP_STOP_TONE_USER = 17;
216
217 // Message id to remove stop tone message from queue.
218 private static final int STOP_TONE_WHAT = 100;
219
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800220 // Response ids
221 static final int RES_ID_MENU_SELECTION = 11;
222 static final int RES_ID_INPUT = 12;
223 static final int RES_ID_CONFIRM = 13;
224 static final int RES_ID_DONE = 14;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500225 static final int RES_ID_CHOICE = 15;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800226
227 static final int RES_ID_TIMEOUT = 20;
228 static final int RES_ID_BACKWARD = 21;
229 static final int RES_ID_END_SESSION = 22;
230 static final int RES_ID_EXIT = 23;
Srikanth Chintalaba103002015-11-30 10:49:52 -0800231 static final int RES_ID_ERROR = 24;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800232
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500233 static final int YES = 1;
234 static final int NO = 0;
235
Wink Savillee68857d2014-10-17 15:23:05 -0700236 static final int STATE_UNKNOWN = -1;
237 static final int STATE_NOT_EXIST = 0;
238 static final int STATE_EXIST = 1;
Wink Saville79085fc2009-06-09 10:27:23 -0700239
Wink Savillee68857d2014-10-17 15:23:05 -0700240 private static final String PACKAGE_NAME = "com.android.stk";
241 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
242 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
243 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800244 // Notification id used to display Idle Mode text in NotificationManager.
245 private static final int STK_NOTIFICATION_ID = 333;
fionaxu2c91c752017-04-21 18:11:57 -0700246 // Notification channel containing all mobile service messages notifications.
247 private static final String STK_NOTIFICATION_CHANNEL_ID = "mobileServiceMessages";
248
Wink Savillee68857d2014-10-17 15:23:05 -0700249 private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
Wink Saville79085fc2009-06-09 10:27:23 -0700250
251 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800252 // session end) while the service is busy processing a previous message.
253 private class DelayedCmd {
254 // members
255 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700256 CatCmdMessage msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700257 int slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800258
Wink Savillee68857d2014-10-17 15:23:05 -0700259 DelayedCmd(int id, CatCmdMessage msg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800260 this.id = id;
261 this.msg = msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700262 this.slotId = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800263 }
264 }
265
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700266 // system property to set the STK specific default url for launch browser proactive cmds
267 private static final String STK_BROWSER_DEFAULT_URL_SYSPROP = "persist.radio.stk.default_url";
268
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800269 @Override
270 public void onCreate() {
Wink Savillee68857d2014-10-17 15:23:05 -0700271 CatLog.d(LOG_TAG, "onCreate()+");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800272 // Initialize members
Wink Savillee68857d2014-10-17 15:23:05 -0700273 int i = 0;
274 mContext = getBaseContext();
275 mSimCount = TelephonyManager.from(mContext).getSimCount();
276 CatLog.d(LOG_TAG, "simCount: " + mSimCount);
277 mStkService = new AppInterface[mSimCount];
278 mStkContext = new StkContext[mSimCount];
Preeti Ahuja560be362014-11-25 19:38:24 -0800279 mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
280 mStkCmdReceiver = new StkCmdReceiver();
281 registerReceiver(mStkCmdReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
Wink Savillee68857d2014-10-17 15:23:05 -0700282 for (i = 0; i < mSimCount; i++) {
283 CatLog.d(LOG_TAG, "slotId: " + i);
Legler Wuaeefef52014-10-27 00:57:18 +0800284 mStkService[i] = CatService.getInstance(i);
Wink Savillee68857d2014-10-17 15:23:05 -0700285 mStkContext[i] = new StkContext();
286 mStkContext[i].mSlotId = i;
287 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
288 }
289
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800290 Thread serviceThread = new Thread(null, this, "Stk App Service");
291 serviceThread.start();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800292 mNotificationManager = (NotificationManager) mContext
293 .getSystemService(Context.NOTIFICATION_SERVICE);
294 sInstance = this;
295 }
296
297 @Override
298 public void onStart(Intent intent, int startId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700299 if (intent == null) {
300 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530301 return;
302 }
303
Wink Savillee68857d2014-10-17 15:23:05 -0700304 Bundle args = intent.getExtras();
305 if (args == null) {
306 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
307 return;
308 }
309
310 int op = args.getInt(OPCODE);
311 int slotId = 0;
312 int i = 0;
313 if (op != OP_BOOT_COMPLETED) {
314 slotId = args.getInt(SLOT_ID);
315 }
Cuihtlauac ALVARADObde7f032015-05-29 16:25:12 +0200316 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", *****");
Wink Savillee68857d2014-10-17 15:23:05 -0700317 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +0800318 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -0700319 if (mStkService[slotId] == null) {
320 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
321 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
322 //Check other StkService state.
323 //If all StkServices are not available, stop itself and uninstall apk.
324 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
325 if (i != slotId
Tsukasa Goto029332b2016-10-05 17:12:06 +0900326 && (mStkService[i] != null)
Wink Savillee68857d2014-10-17 15:23:05 -0700327 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
328 || mStkContext[i].mStkServiceState == STATE_EXIST)) {
329 break;
330 }
331 }
332 } else {
333 mStkContext[slotId].mStkServiceState = STATE_EXIST;
334 }
335 if (i == mSimCount) {
336 stopSelf();
337 StkAppInstaller.unInstall(mContext);
338 return;
339 }
340 }
341
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530342 waitForLooper();
John Wang62acae42009-10-08 11:20:23 -0700343
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800344 Message msg = mServiceHandler.obtainMessage();
Wink Savillee68857d2014-10-17 15:23:05 -0700345 msg.arg1 = op;
346 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800347 switch(msg.arg1) {
348 case OP_CMD:
349 msg.obj = args.getParcelable(CMD_MSG);
350 break;
351 case OP_RESPONSE:
Wink Saville94e982b2014-07-11 07:38:14 -0700352 case OP_CARD_STATUS_CHANGED:
Preeti Ahuja95919342013-10-01 18:18:55 -0700353 case OP_LOCALE_CHANGED:
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530354 case OP_ALPHA_NOTIFY:
Preeti Ahuja560be362014-11-25 19:38:24 -0800355 case OP_IDLE_SCREEN:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800356 msg.obj = args;
357 /* falls through */
358 case OP_LAUNCH_APP:
359 case OP_END_SESSION:
360 case OP_BOOT_COMPLETED:
361 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530362 case OP_STOP_TONE_USER:
363 msg.obj = args;
364 msg.what = STOP_TONE_WHAT;
365 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800366 default:
367 return;
368 }
369 mServiceHandler.sendMessage(msg);
370 }
371
372 @Override
373 public void onDestroy() {
Wink Savillee68857d2014-10-17 15:23:05 -0700374 CatLog.d(LOG_TAG, "onDestroy()");
Preeti Ahuja560be362014-11-25 19:38:24 -0800375 if (mStkCmdReceiver != null) {
376 unregisterReceiver(mStkCmdReceiver);
377 mStkCmdReceiver = null;
378 }
379 mPowerManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800380 waitForLooper();
381 mServiceLooper.quit();
382 }
383
384 @Override
385 public IBinder onBind(Intent intent) {
386 return null;
387 }
388
389 public void run() {
390 Looper.prepare();
391
392 mServiceLooper = Looper.myLooper();
393 mServiceHandler = new ServiceHandler();
394
395 Looper.loop();
396 }
397
398 /*
399 * Package api used by StkMenuActivity to indicate if its on the foreground.
400 */
Wink Savillee68857d2014-10-17 15:23:05 -0700401 void indicateMenuVisibility(boolean visibility, int slotId) {
402 if (slotId >= 0 && slotId < mSimCount) {
403 mStkContext[slotId].mMenuIsVisible = visibility;
404 }
405 }
406
Preeti Ahuja95919342013-10-01 18:18:55 -0700407 /*
408 * Package api used by StkDialogActivity to indicate if its on the foreground.
409 */
410 void setDisplayTextDlgVisibility(boolean visibility, int slotId) {
411 if (slotId >= 0 && slotId < mSimCount) {
412 mStkContext[slotId].mDisplayTextDlgIsVisibile = visibility;
413 }
414 }
415
Wink Savillee68857d2014-10-17 15:23:05 -0700416 boolean isInputPending(int slotId) {
417 if (slotId >= 0 && slotId < mSimCount) {
418 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
419 return mStkContext[slotId].mIsInputPending;
420 }
421 return false;
422 }
423
424 boolean isMenuPending(int slotId) {
425 if (slotId >= 0 && slotId < mSimCount) {
426 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
427 return mStkContext[slotId].mIsMenuPending;
428 }
429 return false;
430 }
431
432 boolean isDialogPending(int slotId) {
433 if (slotId >= 0 && slotId < mSimCount) {
434 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
435 return mStkContext[slotId].mIsDialogPending;
436 }
437 return false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800438 }
439
440 /*
441 * Package api used by StkMenuActivity to get its Menu parameter.
442 */
Wink Savillee68857d2014-10-17 15:23:05 -0700443 Menu getMenu(int slotId) {
444 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
445 if (slotId >=0 && slotId < mSimCount) {
446 return mStkContext[slotId].mCurrentMenu;
447 } else {
448 return null;
449 }
450 }
451
452 /*
453 * Package api used by StkMenuActivity to get its Main Menu parameter.
454 */
455 Menu getMainMenu(int slotId) {
456 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
w30234a08cffe2015-02-04 15:13:25 -0800457 if (slotId >=0 && slotId < mSimCount && (mStkContext[slotId].mMainCmd != null)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700458 return mStkContext[slotId].mMainCmd.getMenu();
459 } else {
460 return null;
461 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800462 }
463
464 /*
465 * Package api used by UI Activities and Dialogs to communicate directly
466 * with the service to deliver state information and parameters.
467 */
468 static StkAppService getInstance() {
469 return sInstance;
470 }
471
472 private void waitForLooper() {
473 while (mServiceHandler == null) {
474 synchronized (this) {
475 try {
476 wait(100);
477 } catch (InterruptedException e) {
478 }
479 }
480 }
481 }
482
483 private final class ServiceHandler extends Handler {
484 @Override
485 public void handleMessage(Message msg) {
Wink Savillee68857d2014-10-17 15:23:05 -0700486 if(null == msg) {
487 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
488 return;
489 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800490 int opcode = msg.arg1;
Wink Savillee68857d2014-10-17 15:23:05 -0700491 int slotId = msg.arg2;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800492
Wink Savillee68857d2014-10-17 15:23:05 -0700493 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
494 if (opcode == OP_CMD && msg.obj != null &&
495 ((CatCmdMessage)msg.obj).getCmdType()!= null) {
496 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
497 }
498 mStkContext[slotId].mOpCode = opcode;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800499 switch (opcode) {
500 case OP_LAUNCH_APP:
Wink Savillee68857d2014-10-17 15:23:05 -0700501 if (mStkContext[slotId].mMainCmd == null) {
502 CatLog.d(LOG_TAG, "mMainCmd is null");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800503 // nothing todo when no SET UP MENU command didn't arrive.
504 return;
505 }
Wink Savillee68857d2014-10-17 15:23:05 -0700506 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
507 mStkContext[slotId].mCmdInProgress + "]");
508
509 //If there is a pending activity for the slot id,
510 //just finish it and create a new one to handle the pending command.
511 cleanUpInstanceStackBySlot(slotId);
512
Wink Savillee68857d2014-10-17 15:23:05 -0700513 CatLog.d(LOG_TAG, "Current cmd type: " +
514 mStkContext[slotId].mCurrentCmd.getCmdType());
515 //Restore the last command from stack by slot id.
516 restoreInstanceFromStackBySlot(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800517 break;
518 case OP_CMD:
Wink Savillee68857d2014-10-17 15:23:05 -0700519 CatLog.d(LOG_TAG, "[OP_CMD]");
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700520 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800521 // There are two types of commands:
522 // 1. Interactive - user's response is required.
523 // 2. Informative - display a message, no interaction with the user.
524 //
Wink Saville79085fc2009-06-09 10:27:23 -0700525 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800526 // Interactive commands can't override each other. So if a command
527 // is already in progress, we need to queue the next command until
528 // the user has responded or a timeout expired.
529 if (!isCmdInteractive(cmdMsg)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700530 handleCmd(cmdMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800531 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700532 if (!mStkContext[slotId].mCmdInProgress) {
533 mStkContext[slotId].mCmdInProgress = true;
534 handleCmd((CatCmdMessage) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800535 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700536 CatLog.d(LOG_TAG, "[Interactive][in progress]");
537 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
538 (CatCmdMessage) msg.obj, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800539 }
540 }
541 break;
542 case OP_RESPONSE:
Preeti Ahuja414bc412013-06-25 19:31:49 -0700543 handleCmdResponse((Bundle) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800544 // call delayed commands if needed.
Wink Savillee68857d2014-10-17 15:23:05 -0700545 if (mStkContext[slotId].mCmdsQ.size() != 0) {
546 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800547 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700548 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800549 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800550 break;
551 case OP_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700552 if (!mStkContext[slotId].mCmdInProgress) {
553 mStkContext[slotId].mCmdInProgress = true;
554 handleSessionEnd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800555 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700556 mStkContext[slotId].mCmdsQ.addLast(
557 new DelayedCmd(OP_END_SESSION, null, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800558 }
559 break;
560 case OP_BOOT_COMPLETED:
Wink Savillee68857d2014-10-17 15:23:05 -0700561 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
562 int i = 0;
563 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
564 if (mStkContext[i].mMainCmd != null) {
565 break;
566 }
567 }
568 if (i == mSimCount) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800569 StkAppInstaller.unInstall(mContext);
570 }
571 break;
572 case OP_DELAYED_MSG:
Wink Savillee68857d2014-10-17 15:23:05 -0700573 handleDelayedCmd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800574 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700575 case OP_CARD_STATUS_CHANGED:
Wink Savillee68857d2014-10-17 15:23:05 -0700576 CatLog.d(LOG_TAG, "Card/Icc Status change received");
577 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
578 break;
579 case OP_SET_ACT_INST:
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900580 Activity act = (Activity) msg.obj;
581 if (mStkContext[slotId].mActivityInstance != act) {
582 CatLog.d(LOG_TAG, "Set activity instance - " + act);
583 Activity previous = mStkContext[slotId].mActivityInstance;
584 mStkContext[slotId].mActivityInstance = act;
585 // Finish the previous one if it has not been finished yet somehow.
586 if (previous != null && !previous.isDestroyed() && !previous.isFinishing()) {
587 CatLog.d(LOG_TAG, "Finish the previous pending activity - " + previous);
588 previous.finish();
589 }
590 }
Wink Savillee68857d2014-10-17 15:23:05 -0700591 break;
592 case OP_SET_DAL_INST:
593 Activity dal = new Activity();
594 CatLog.d(LOG_TAG, "Set dialog instance. " + dal);
595 dal = (Activity) msg.obj;
596 mStkContext[slotId].mDialogInstance = dal;
597 break;
598 case OP_SET_MAINACT_INST:
599 Activity mainAct = new Activity();
600 mainAct = (Activity) msg.obj;
601 CatLog.d(LOG_TAG, "Set activity instance. " + mainAct);
602 mStkContext[slotId].mMainActivityInstance = mainAct;
Wink Saville94e982b2014-07-11 07:38:14 -0700603 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700604 case OP_LOCALE_CHANGED:
605 CatLog.d(this, "Locale Changed");
Yuta Ui1481b172016-02-03 15:34:31 +0900606 for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
607 checkForSetupEvent(LANGUAGE_SELECTION_EVENT, (Bundle) msg.obj, slot);
608 }
fionaxu805eb572017-05-02 10:57:30 -0700609 // rename all registered notification channels on locale change
610 createAllChannels();
Preeti Ahuja95919342013-10-01 18:18:55 -0700611 break;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530612 case OP_ALPHA_NOTIFY:
613 handleAlphaNotify((Bundle) msg.obj);
614 break;
Preeti Ahuja560be362014-11-25 19:38:24 -0800615 case OP_IDLE_SCREEN:
616 for (int slot = 0; slot < mSimCount; slot++) {
617 if (mStkContext[slot] != null) {
618 handleIdleScreen(slot);
619 }
620 }
621 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530622 case OP_STOP_TONE_USER:
623 case OP_STOP_TONE:
624 CatLog.d(this, "Stop tone");
625 handleStopTone(msg, slotId);
626 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700627 }
628 }
629
Wink Savillee68857d2014-10-17 15:23:05 -0700630 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
Wink Saville94e982b2014-07-11 07:38:14 -0700631 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
632
Wink Savillee68857d2014-10-17 15:23:05 -0700633 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
Wink Saville94e982b2014-07-11 07:38:14 -0700634 if (cardStatus == false) {
Wink Savillee68857d2014-10-17 15:23:05 -0700635 CatLog.d(LOG_TAG, "CARD is ABSENT");
Wink Saville94e982b2014-07-11 07:38:14 -0700636 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
Wink Savillee68857d2014-10-17 15:23:05 -0700637 mNotificationManager.cancel(getNotificationId(slotId));
Srikanth Chintala7c5a04c2016-09-22 19:05:01 +0530638 mStkContext[slotId].mCurrentMenu = null;
639 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700640 if (isAllOtherCardsAbsent(slotId)) {
641 CatLog.d(LOG_TAG, "All CARDs are ABSENT");
642 StkAppInstaller.unInstall(mContext);
643 stopSelf();
644 }
Wink Saville94e982b2014-07-11 07:38:14 -0700645 } else {
646 IccRefreshResponse state = new IccRefreshResponse();
647 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
648
Wink Savillee68857d2014-10-17 15:23:05 -0700649 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
Wink Saville94e982b2014-07-11 07:38:14 -0700650 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
651 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
652 // Clear Idle Text
Wink Savillee68857d2014-10-17 15:23:05 -0700653 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville94e982b2014-07-11 07:38:14 -0700654 }
655
656 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
657 // Uninstall STkmenu
Wink Savillee68857d2014-10-17 15:23:05 -0700658 if (isAllOtherCardsAbsent(slotId)) {
659 StkAppInstaller.unInstall(mContext);
660 }
661 mStkContext[slotId].mCurrentMenu = null;
662 mStkContext[slotId].mMainCmd = null;
Wink Saville94e982b2014-07-11 07:38:14 -0700663 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800664 }
665 }
666 }
Wink Savillee68857d2014-10-17 15:23:05 -0700667 /*
668 * Check if all SIMs are absent except the id of slot equals "slotId".
669 */
670 private boolean isAllOtherCardsAbsent(int slotId) {
671 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
672 Context.TELEPHONY_SERVICE);
673 int i = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800674
Wink Savillee68857d2014-10-17 15:23:05 -0700675 for (i = 0; i < mSimCount; i++) {
676 if (i != slotId && mTm.hasIccCard(i)) {
677 break;
678 }
679 }
680 if (i == mSimCount) {
681 return true;
682 } else {
683 return false;
684 }
685 }
Preeti Ahuja95919342013-10-01 18:18:55 -0700686
Preeti Ahuja560be362014-11-25 19:38:24 -0800687 /*
688 * If the device is not in an interactive state, we can assume
689 * that the screen is idle.
690 */
691 private boolean isScreenIdle() {
692 return (!mPowerManager.isInteractive());
693 }
694
695 private void handleIdleScreen(int slotId) {
696
697 // If the idle screen event is present in the list need to send the
698 // response to SIM.
699 CatLog.d(this, "Need to send IDLE SCREEN Available event to SIM");
700 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
701
702 if (mStkContext[slotId].mIdleModeTextCmd != null) {
703 launchIdleText(slotId);
704 }
705 }
706
707 private void sendScreenBusyResponse(int slotId) {
708 if (mStkContext[slotId].mCurrentCmd == null) {
709 return;
710 }
711 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
712 CatLog.d(this, "SCREEN_BUSY");
713 resMsg.setResultCode(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS);
714 mStkService[slotId].onCmdResponse(resMsg);
715 if (mStkContext[slotId].mCmdsQ.size() != 0) {
716 callDelayedMsg(slotId);
717 } else {
718 mStkContext[slotId].mCmdInProgress = false;
719 }
720 }
721
Preeti Ahuja95919342013-10-01 18:18:55 -0700722 private void sendResponse(int resId, int slotId, boolean confirm) {
723 Message msg = mServiceHandler.obtainMessage();
724 msg.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +0900725 msg.arg2 = slotId;
Preeti Ahuja95919342013-10-01 18:18:55 -0700726 Bundle args = new Bundle();
727 args.putInt(StkAppService.RES_ID, resId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700728 args.putBoolean(StkAppService.CONFIRMATION, confirm);
729 msg.obj = args;
730 mServiceHandler.sendMessage(msg);
731 }
732
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700733 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800734 switch (cmd.getCmdType()) {
735 case SEND_DTMF:
736 case SEND_SMS:
737 case SEND_SS:
738 case SEND_USSD:
739 case SET_UP_IDLE_MODE_TEXT:
740 case SET_UP_MENU:
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500741 case CLOSE_CHANNEL:
742 case RECEIVE_DATA:
743 case SEND_DATA:
Preeti Ahuja95919342013-10-01 18:18:55 -0700744 case SET_UP_EVENT_LIST:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800745 return false;
746 }
747
748 return true;
749 }
750
Wink Savillee68857d2014-10-17 15:23:05 -0700751 private void handleDelayedCmd(int slotId) {
752 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
753 if (mStkContext[slotId].mCmdsQ.size() != 0) {
754 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
755 if (cmd != null) {
756 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
757 mStkContext[slotId].mCmdsQ.size() +
758 " id: " + cmd.id + "sim id: " + cmd.slotId);
759 switch (cmd.id) {
760 case OP_CMD:
761 handleCmd(cmd.msg, cmd.slotId);
762 break;
763 case OP_END_SESSION:
764 handleSessionEnd(cmd.slotId);
765 break;
766 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800767 }
768 }
769 }
770
Wink Savillee68857d2014-10-17 15:23:05 -0700771 private void callDelayedMsg(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800772 Message msg = mServiceHandler.obtainMessage();
773 msg.arg1 = OP_DELAYED_MSG;
Wink Savillee68857d2014-10-17 15:23:05 -0700774 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800775 mServiceHandler.sendMessage(msg);
776 }
777
Wink Savillee68857d2014-10-17 15:23:05 -0700778 private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) {
779 Message msg = mServiceHandler.obtainMessage();
780 msg.obj = obj;
781 msg.arg1 = inst_type;
782 msg.arg2 = slotId;
783 mServiceHandler.sendMessage(msg);
784 }
785
786 private void handleSessionEnd(int slotId) {
Legler Wuaeefef52014-10-27 00:57:18 +0800787 // We should finish all pending activity if receiving END SESSION command.
788 cleanUpInstanceStackBySlot(slotId);
789
Wink Savillee68857d2014-10-17 15:23:05 -0700790 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
791 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
792 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
793 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
794 mStkContext[slotId].mMenuState);
795
796 mStkContext[slotId].mIsInputPending = false;
797 mStkContext[slotId].mIsMenuPending = false;
798 mStkContext[slotId].mIsDialogPending = false;
799
Wink Savillee68857d2014-10-17 15:23:05 -0700800 if (mStkContext[slotId].mMainCmd == null) {
801 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
802 }
803 mStkContext[slotId].lastSelectedItem = null;
Wink Saville79085fc2009-06-09 10:27:23 -0700804 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800805 // update the current menu member.
Wink Savillee68857d2014-10-17 15:23:05 -0700806 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
807 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800808 }
Wink Savillee68857d2014-10-17 15:23:05 -0700809 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
810 // In mutiple instance architecture, the main menu for slotId will be finished when user
811 // goes to the Stk menu of the other SIM. So, we should launch a new instance for the
812 // main menu if the main menu instance has been finished.
813 // If the current menu is secondary menu, we should launch main menu.
814 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
815 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800816 }
Wink Savillee68857d2014-10-17 15:23:05 -0700817 if (mStkContext[slotId].mCmdsQ.size() != 0) {
818 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800819 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700820 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800821 }
822 // In case a launch browser command was just confirmed, launch that url.
Wink Savillee68857d2014-10-17 15:23:05 -0700823 if (mStkContext[slotId].launchBrowser) {
824 mStkContext[slotId].launchBrowser = false;
825 launchBrowser(mStkContext[slotId].mBrowserSettings);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800826 }
827 }
828
Preeti Ahuja560be362014-11-25 19:38:24 -0800829 // returns true if any Stk related activity already has focus on the screen
830 private boolean isTopOfStack() {
pkanwareab12f32017-02-06 08:35:03 -0800831 ActivityManager mActivityManager = (ActivityManager) mContext
Preeti Ahuja560be362014-11-25 19:38:24 -0800832 .getSystemService(ACTIVITY_SERVICE);
pkanwareab12f32017-02-06 08:35:03 -0800833 String currentPackageName = null;
834 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
835 if (tasks == null || tasks.get(0).topActivity == null) {
836 return false;
837 }
838 currentPackageName = tasks.get(0).topActivity.getPackageName();
Preeti Ahuja560be362014-11-25 19:38:24 -0800839 if (null != currentPackageName) {
840 return currentPackageName.equals(PACKAGE_NAME);
841 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800842 return false;
843 }
844
Sooraj Sasindrana4160472016-10-12 16:28:25 -0700845 /**
846 * Get the boolean config from carrier config manager.
847 *
848 * @param context the context to get carrier service
849 * @param key config key defined in CarrierConfigManager
850 * @return boolean value of corresponding key.
851 */
852 private static boolean getBooleanCarrierConfig(Context context, String key) {
853 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
854 Context.CARRIER_CONFIG_SERVICE);
855 PersistableBundle b = null;
856 if (configManager != null) {
857 b = configManager.getConfig();
858 }
859 if (b != null) {
860 return b.getBoolean(key);
861 } else {
862 // Return static default defined in CarrierConfigManager.
863 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
864 }
865 }
866
Wink Savillee68857d2014-10-17 15:23:05 -0700867 private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700868
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800869 if (cmdMsg == null) {
870 return;
871 }
872 // save local reference for state tracking.
Wink Savillee68857d2014-10-17 15:23:05 -0700873 mStkContext[slotId].mCurrentCmd = cmdMsg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800874 boolean waitForUsersResponse = true;
875
Wink Savillee68857d2014-10-17 15:23:05 -0700876 mStkContext[slotId].mIsInputPending = false;
877 mStkContext[slotId].mIsMenuPending = false;
878 mStkContext[slotId].mIsDialogPending = false;
879
880 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800881 switch (cmdMsg.getCmdType()) {
882 case DISPLAY_TEXT:
883 TextMessage msg = cmdMsg.geTextMessage();
Jeevaka Badrappan854a25c2012-12-01 16:32:03 +0200884 waitForUsersResponse = msg.responseNeeded;
Wink Savillee68857d2014-10-17 15:23:05 -0700885 if (mStkContext[slotId].lastSelectedItem != null) {
886 msg.title = mStkContext[slotId].lastSelectedItem;
887 } else if (mStkContext[slotId].mMainCmd != null){
Yoshiaki Naka28313ba2017-08-04 12:20:53 +0900888 if (!getResources().getBoolean(R.bool.show_menu_title_only_on_menu)) {
889 msg.title = mStkContext[slotId].mMainCmd.getMenu().title;
890 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800891 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800892 //If we receive a low priority Display Text and the device is
893 // not displaying any STK related activity and the screen is not idle
894 // ( that is, device is in an interactive state), then send a screen busy
895 // terminal response. Otherwise display the message. The existing
896 // displayed message shall be updated with the new display text
897 // proactive command (Refer to ETSI TS 102 384 section 27.22.4.1.4.4.2).
898 if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible
899 || mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) {
900 if(!isScreenIdle()) {
901 CatLog.d(LOG_TAG, "Screen is not idle");
902 sendScreenBusyResponse(slotId);
903 } else {
904 launchTextDialog(slotId);
905 }
906 } else {
907 launchTextDialog(slotId);
908 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800909 break;
910 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700911 CatLog.d(LOG_TAG, "SELECT_ITEM +");
912 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
913 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
914 launchMenuActivity(cmdMsg.getMenu(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800915 break;
916 case SET_UP_MENU:
Wink Savillee68857d2014-10-17 15:23:05 -0700917 mStkContext[slotId].mCmdInProgress = false;
918 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
919 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
920 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
921 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
922
923 if (removeMenu(slotId)) {
924 int i = 0;
925 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App");
926 mStkContext[slotId].mCurrentMenu = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700927 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700928 //Check other setup menu state. If all setup menu are removed, uninstall apk.
929 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
930 if (i != slotId
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +0900931 && (mStkContext[i].mSetupMenuState == STATE_UNKNOWN
932 || mStkContext[i].mSetupMenuState == STATE_EXIST)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700933 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +0900934 + mStkContext[i].mSetupMenuState);
Wink Savillee68857d2014-10-17 15:23:05 -0700935 break;
936 }
937 }
938 if (i == mSimCount) {
939 StkAppInstaller.unInstall(mContext);
940 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800941 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700942 CatLog.d(LOG_TAG, "install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800943 StkAppInstaller.install(mContext);
944 }
Wink Savillee68857d2014-10-17 15:23:05 -0700945 if (mStkContext[slotId].mMenuIsVisible) {
946 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800947 }
948 break;
949 case GET_INPUT:
950 case GET_INKEY:
Wink Savillee68857d2014-10-17 15:23:05 -0700951 launchInputActivity(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800952 break;
953 case SET_UP_IDLE_MODE_TEXT:
954 waitForUsersResponse = false;
Preeti Ahuja560be362014-11-25 19:38:24 -0800955 mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd;
956 TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage();
957 if (idleModeText == null) {
958 launchIdleText(slotId);
959 mStkContext[slotId].mIdleModeTextCmd = null;
960 }
961 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
962 if ((mStkContext[slotId].mIdleModeTextCmd != null) && isScreenIdle()) {
963 CatLog.d(this, "set up idle mode");
964 launchIdleText(slotId);
965 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800966 break;
967 case SEND_DTMF:
968 case SEND_SMS:
969 case SEND_SS:
970 case SEND_USSD:
Preeti Ahuja95919342013-10-01 18:18:55 -0700971 case GET_CHANNEL_STATUS:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800972 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700973 launchEventMessage(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800974 break;
975 case LAUNCH_BROWSER:
Ryuto Sawada0bdc7192016-04-18 12:10:56 +0900976 // The device setup process should not be interrupted by launching browser.
977 if (Settings.Global.getInt(mContext.getContentResolver(),
978 Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
979 CatLog.d(this, "The command is not performed if the setup has not been completed.");
980 sendScreenBusyResponse(slotId);
981 break;
982 }
Sooraj Sasindrana4160472016-10-12 16:28:25 -0700983
984 /* Check if Carrier would not want to launch browser */
985 if (getBooleanCarrierConfig(mContext,
986 CarrierConfigManager.KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL)) {
987 CatLog.d(this, "Browser is not launched as per carrier.");
988 sendResponse(RES_ID_DONE, slotId, true);
989 break;
990 }
991
Srikanth Chintalaba103002015-11-30 10:49:52 -0800992 mStkContext[slotId].mBrowserSettings =
993 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
994 if (!isUrlAvailableToLaunchBrowser(mStkContext[slotId].mBrowserSettings)) {
995 CatLog.d(this, "Browser url property is not set - send error");
996 sendResponse(RES_ID_ERROR, slotId, true);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700997 } else {
Srikanth Chintalaba103002015-11-30 10:49:52 -0800998 TextMessage alphaId = mStkContext[slotId].mCurrentCmd.geTextMessage();
999 if ((alphaId == null) || TextUtils.isEmpty(alphaId.text)) {
1000 // don't need user confirmation in this case
1001 // just launch the browser or spawn a new tab
1002 CatLog.d(this, "user confirmation is not currently needed.\n" +
1003 "supressing confirmation dialogue and confirming silently...");
1004 mStkContext[slotId].launchBrowser = true;
1005 sendResponse(RES_ID_CONFIRM, slotId, true);
1006 } else {
1007 launchConfirmationDialog(alphaId, slotId);
1008 }
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001009 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001010 break;
1011 case SET_UP_CALL:
Preeti Ahujadd240102013-08-30 17:25:06 -07001012 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg;
1013 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) {
1014 mesg.text = getResources().getString(R.string.default_setup_call_msg);
1015 }
1016 CatLog.d(this, "SET_UP_CALL mesg.text " + mesg.text);
1017 launchConfirmationDialog(mesg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001018 break;
1019 case PLAY_TONE:
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301020 handlePlayTone(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001021 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001022 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -07001023 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001024 break;
1025 case CLOSE_CHANNEL:
1026 case RECEIVE_DATA:
1027 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -07001028 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001029
1030 if ((m != null) && (m.text == null)) {
1031 switch(cmdMsg.getCmdType()) {
1032 case CLOSE_CHANNEL:
1033 m.text = getResources().getString(R.string.default_close_channel_msg);
1034 break;
1035 case RECEIVE_DATA:
1036 m.text = getResources().getString(R.string.default_receive_data_msg);
1037 break;
1038 case SEND_DATA:
1039 m.text = getResources().getString(R.string.default_send_data_msg);
1040 break;
1041 }
1042 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001043 /*
1044 * Display indication in the form of a toast to the user if required.
1045 */
Wink Savillee68857d2014-10-17 15:23:05 -07001046 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001047 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001048 case SET_UP_EVENT_LIST:
1049 mStkContext[slotId].mSetupEventListSettings =
1050 mStkContext[slotId].mCurrentCmd.getSetEventList();
1051 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
1052 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
Preeti Ahuja560be362014-11-25 19:38:24 -08001053 if (isScreenIdle()) {
1054 CatLog.d(this," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List");
1055 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
1056 }
Preeti Ahuja95919342013-10-01 18:18:55 -07001057 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001058 }
1059
1060 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -07001061 if (mStkContext[slotId].mCmdsQ.size() != 0) {
1062 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001063 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001064 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001065 }
1066 }
1067 }
1068
Wink Savillee68857d2014-10-17 15:23:05 -07001069 private void handleCmdResponse(Bundle args, int slotId) {
1070 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
1071 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001072 return;
1073 }
Wink Savillee68857d2014-10-17 15:23:05 -07001074
1075 if (mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +08001076 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001077 if (mStkService[slotId] == null) {
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001078 // This should never happen (we should be responding only to a message
1079 // that arrived from StkService). It has to exist by this time
Wink Savillee68857d2014-10-17 15:23:05 -07001080 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response.");
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001081 throw new RuntimeException("mStkService is null when we need to send response");
1082 }
1083 }
1084
Wink Savillee68857d2014-10-17 15:23:05 -07001085 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001086
1087 // set result code
1088 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001089 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001090
1091 switch(args.getInt(RES_ID)) {
1092 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -07001093 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
1094 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001095 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -07001096 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001097 case SET_UP_MENU:
1098 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -07001099 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001100 if (helpRequired) {
1101 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1102 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301103 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1104 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001105 }
1106 resMsg.setMenuSelection(menuSelection);
1107 break;
1108 }
1109 break;
1110 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001111 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001112 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -07001113 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
1114 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001115 boolean yesNoSelection = input
1116 .equals(StkInputActivity.YES_STR_RESPONSE);
1117 resMsg.setYesNo(yesNoSelection);
1118 } else {
1119 if (helpRequired) {
1120 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1121 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301122 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1123 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001124 resMsg.setInput(input);
1125 }
1126 }
1127 break;
1128 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -07001129 CatLog.d(this, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001130 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -07001131 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001132 case DISPLAY_TEXT:
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301133 if (confirmed) {
1134 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1135 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
1136 } else {
1137 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1138 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001139 break;
1140 case LAUNCH_BROWSER:
1141 resMsg.setResultCode(confirmed ? ResultCode.OK
1142 : ResultCode.UICC_SESSION_TERM_BY_USER);
1143 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001144 mStkContext[slotId].launchBrowser = true;
1145 mStkContext[slotId].mBrowserSettings =
1146 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001147 }
1148 break;
1149 case SET_UP_CALL:
1150 resMsg.setResultCode(ResultCode.OK);
1151 resMsg.setConfirmation(confirmed);
1152 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001153 launchEventMessage(slotId,
1154 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001155 }
1156 break;
1157 }
1158 break;
1159 case RES_ID_DONE:
1160 resMsg.setResultCode(ResultCode.OK);
1161 break;
1162 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -07001163 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001164 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
1165 break;
1166 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -07001167 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001168 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1169 break;
1170 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001171 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -08001172 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
1173 // Clear message after delay, successful) expects result code OK.
1174 // If the command qualifier specifies no user response is required
1175 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -07001176 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1177 AppInterface.CommandType.DISPLAY_TEXT.value())
1178 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -08001179 resMsg.setResultCode(ResultCode.OK);
1180 } else {
1181 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
1182 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001183 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001184 case RES_ID_CHOICE:
1185 int choice = args.getInt(CHOICE);
1186 CatLog.d(this, "User Choice=" + choice);
1187 switch (choice) {
1188 case YES:
1189 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001190 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001191 break;
1192 case NO:
1193 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
1194 break;
1195 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001196
Wink Savillee68857d2014-10-17 15:23:05 -07001197 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1198 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001199 resMsg.setConfirmation(confirmed);
1200 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001201 break;
Srikanth Chintalaba103002015-11-30 10:49:52 -08001202 case RES_ID_ERROR:
1203 CatLog.d(LOG_TAG, "RES_ID_ERROR");
1204 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
1205 case LAUNCH_BROWSER:
1206 resMsg.setResultCode(ResultCode.LAUNCH_BROWSER_ERROR);
1207 break;
1208 }
1209 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001210 default:
Wink Savillee68857d2014-10-17 15:23:05 -07001211 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001212 return;
1213 }
Wink Savillee68857d2014-10-17 15:23:05 -07001214
1215 if (null != mStkContext[slotId].mCurrentCmd &&
1216 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1217 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1218 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1219 }
1220 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001221 }
1222
1223 /**
1224 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1225 *
1226 * @param userAction If the userAction is yes then we always return 0 otherwise
1227 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1228 * then we are the foreground app and we'll return 0 as from our perspective a
1229 * user action did cause. If it's false than we aren't the foreground app and
1230 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001231 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001232 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1233 */
Wink Savillee68857d2014-10-17 15:23:05 -07001234 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1235 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1236 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1237 }
1238 /**
1239 * This method is used for cleaning up pending instances in stack.
1240 */
1241 private void cleanUpInstanceStackBySlot(int slotId) {
1242 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1243 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1244 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
Legler Wuaeefef52014-10-27 00:57:18 +08001245 if (mStkContext[slotId].mCurrentCmd == null) {
1246 CatLog.d(LOG_TAG, "current cmd is null.");
1247 return;
1248 }
Wink Savillee68857d2014-10-17 15:23:05 -07001249 if (activity != null) {
1250 CatLog.d(LOG_TAG, "current cmd type: " +
1251 mStkContext[slotId].mCurrentCmd.getCmdType());
1252 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1253 AppInterface.CommandType.GET_INPUT.value() ||
1254 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1255 AppInterface.CommandType.GET_INKEY.value()) {
1256 mStkContext[slotId].mIsInputPending = true;
1257 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1258 AppInterface.CommandType.SET_UP_MENU.value() ||
1259 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1260 AppInterface.CommandType.SELECT_ITEM.value()) {
1261 mStkContext[slotId].mIsMenuPending = true;
1262 } else {
1263 }
1264 CatLog.d(LOG_TAG, "finish pending activity.");
1265 activity.finish();
1266 mStkContext[slotId].mActivityInstance = null;
1267 }
1268 if (dialog != null) {
1269 CatLog.d(LOG_TAG, "finish pending dialog.");
1270 mStkContext[slotId].mIsDialogPending = true;
1271 dialog.finish();
1272 mStkContext[slotId].mDialogInstance = null;
1273 }
1274 }
1275 /**
1276 * This method is used for restoring pending instances from stack.
1277 */
1278 private void restoreInstanceFromStackBySlot(int slotId) {
1279 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1280
1281 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1282 switch(cmdType) {
1283 case GET_INPUT:
1284 case GET_INKEY:
1285 launchInputActivity(slotId);
1286 //Set mMenuIsVisible to true for showing main menu for
1287 //following session end command.
1288 mStkContext[slotId].mMenuIsVisible = true;
1289 break;
1290 case DISPLAY_TEXT:
1291 launchTextDialog(slotId);
1292 break;
1293 case LAUNCH_BROWSER:
1294 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1295 slotId);
1296 break;
1297 case OPEN_CHANNEL:
1298 launchOpenChannelDialog(slotId);
1299 break;
1300 case SET_UP_CALL:
1301 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1302 confirmMsg, slotId);
1303 break;
1304 case SET_UP_MENU:
1305 case SELECT_ITEM:
1306 launchMenuActivity(null, slotId);
1307 break;
1308 default:
1309 break;
1310 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001311 }
1312
Wink Savillee68857d2014-10-17 15:23:05 -07001313 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001314 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001315 String targetActivity = STK_MENU_ACTIVITY_NAME;
1316 String uriString = STK_MENU_URI + System.currentTimeMillis();
1317 //Set unique URI to create a new instance of activity for different slotId.
1318 Uri uriData = Uri.parse(uriString);
1319
1320 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1321 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1322 + mStkContext[slotId].mMenuState);
1323 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1324 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1325
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001326 if (menu == null) {
1327 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001328 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
1329 if (mStkContext[slotId].mOpCode == OP_END_SESSION) {
1330 CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION");
1331 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1332 if (mStkContext[slotId].mMainActivityInstance != null) {
1333 CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null");
1334 return;
1335 }
Wink Savillee68857d2014-10-17 15:23:05 -07001336 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001337
Wink Savillee68857d2014-10-17 15:23:05 -07001338 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1339 //Otherwise, it should be "STATE_MAIN".
1340 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1341 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1342 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1343 } else {
1344 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1345 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1346 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001347 } else {
1348 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001349 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001350 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001351 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001352 }
Wink Savillee68857d2014-10-17 15:23:05 -07001353 newIntent.putExtra(SLOT_ID, slotId);
1354 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001355 newIntent.setFlags(intentFlags);
1356 mContext.startActivity(newIntent);
1357 }
1358
Wink Savillee68857d2014-10-17 15:23:05 -07001359 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001360 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001361 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1362 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1363 //Set unique URI to create a new instance of activity for different slotId.
1364 Uri uriData = Uri.parse(uriString);
1365
1366 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001367 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001368 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1369 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1370 newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput());
1371 newIntent.putExtra(SLOT_ID, slotId);
1372 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001373 mContext.startActivity(newIntent);
1374 }
1375
Wink Savillee68857d2014-10-17 15:23:05 -07001376 private void launchTextDialog(int slotId) {
1377 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1378 Intent newIntent = new Intent();
1379 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1380 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1381 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1382 //Set unique URI to create a new instance of activity for different slotId.
1383 Uri uriData = Uri.parse(uriString);
1384 if (newIntent != null) {
1385 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1386 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1387 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1388 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1389 newIntent.setData(uriData);
1390 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1391 newIntent.putExtra(SLOT_ID, slotId);
1392 startActivity(newIntent);
Preeti Ahuja414bc412013-06-25 19:31:49 -07001393 // For display texts with immediate response, send the terminal response
1394 // immediately. responseNeeded will be false, if display text command has
1395 // the immediate response tlv.
1396 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
1397 sendResponse(RES_ID_CONFIRM, slotId, true);
1398 }
Wink Savillee68857d2014-10-17 15:23:05 -07001399 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001400 }
1401
Wink Savillee68857d2014-10-17 15:23:05 -07001402 public boolean isStkDialogActivated(Context context) {
1403 String stkDialogActivity = "com.android.stk.StkDialogActivity";
1404 boolean activated = false;
1405 final ActivityManager am = (ActivityManager) context.getSystemService(
1406 Context.ACTIVITY_SERVICE);
1407 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName();
1408
1409 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity);
1410 if (topActivity.equals(stkDialogActivity)) {
1411 activated = true;
1412 }
1413 CatLog.d(LOG_TAG, "activated : " + activated);
1414 return activated;
Johan Hellman3aec01c2011-02-10 10:15:28 +01001415 }
1416
Preeti Ahuja95919342013-10-01 18:18:55 -07001417 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
Preeti Ahuja414bc412013-06-25 19:31:49 -07001418 CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -07001419
1420 if (mStkContext[slotId].mCurrentSetupEventCmd == null){
1421 CatLog.e(this, "mCurrentSetupEventCmd is null");
1422 return;
1423 }
1424
1425 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd);
1426
1427 resMsg.setResultCode(ResultCode.OK);
1428 resMsg.setEventDownload(event, addedInfo);
1429
1430 mStkService[slotId].onCmdResponse(resMsg);
1431 }
1432
1433 private void checkForSetupEvent(int event, Bundle args, int slotId) {
1434 boolean eventPresent = false;
1435 byte[] addedInfo = null;
1436 CatLog.d(this, "Event :" + event);
1437
1438 if (mStkContext[slotId].mSetupEventListSettings != null) {
1439 /* Checks if the event is present in the EventList updated by last
1440 * SetupEventList Proactive Command */
1441 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) {
1442 if (event == i) {
1443 eventPresent = true;
1444 break;
1445 }
1446 }
1447
1448 /* If Event is present send the response to ICC */
1449 if (eventPresent == true) {
1450 CatLog.d(this, " Event " + event + "exists in the EventList");
1451
1452 switch (event) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001453 case IDLE_SCREEN_AVAILABLE_EVENT:
1454 sendSetUpEventResponse(event, addedInfo, slotId);
1455 removeSetUpEvent(event, slotId);
1456 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001457 case LANGUAGE_SELECTION_EVENT:
1458 String language = mContext
1459 .getResources().getConfiguration().locale.getLanguage();
1460 CatLog.d(this, "language: " + language);
1461 // Each language code is a pair of alpha-numeric characters.
1462 // Each alpha-numeric character shall be coded on one byte
1463 // using the SMS default 7-bit coded alphabet
1464 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language);
1465 sendSetUpEventResponse(event, addedInfo, slotId);
1466 break;
1467 default:
1468 break;
1469 }
1470 } else {
1471 CatLog.e(this, " Event does not exist in the EventList");
1472 }
1473 } else {
1474 CatLog.e(this, "SetupEventList is not received. Ignoring the event: " + event);
1475 }
1476 }
1477
1478 private void removeSetUpEvent(int event, int slotId) {
1479 CatLog.d(this, "Remove Event :" + event);
1480
1481 if (mStkContext[slotId].mSetupEventListSettings != null) {
1482 /*
1483 * Make new Eventlist without the event
1484 */
1485 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
1486 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
1487 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
1488 break;
1489 }
1490 }
1491 }
1492 }
1493
1494 private void launchEventMessage(int slotId) {
1495 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
1496 }
1497
Wink Savillee68857d2014-10-17 15:23:05 -07001498 private void launchEventMessage(int slotId, TextMessage msg) {
1499 if (msg == null || (msg.text != null && msg.text.length() == 0)) {
1500 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001501 return;
1502 }
Wink Savillee68857d2014-10-17 15:23:05 -07001503
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001504 Toast toast = new Toast(mContext.getApplicationContext());
1505 LayoutInflater inflate = (LayoutInflater) mContext
1506 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1507 View v = inflate.inflate(R.layout.stk_event_msg, null);
1508 TextView tv = (TextView) v
1509 .findViewById(com.android.internal.R.id.message);
1510 ImageView iv = (ImageView) v
1511 .findViewById(com.android.internal.R.id.icon);
1512 if (msg.icon != null) {
1513 iv.setImageBitmap(msg.icon);
1514 } else {
1515 iv.setVisibility(View.GONE);
1516 }
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301517 /* In case of 'self explanatory' stkapp should display the specified
1518 * icon in proactive command (but not the alpha string).
1519 * If icon is non-self explanatory and if the icon could not be displayed
1520 * then alpha string or text data should be displayed
1521 * Ref: ETSI 102.223,section 6.5.4
1522 */
1523 if (mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ||
1524 msg.icon == null || !msg.iconSelfExplanatory) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001525 tv.setText(msg.text);
1526 }
1527
1528 toast.setView(v);
1529 toast.setDuration(Toast.LENGTH_LONG);
1530 toast.setGravity(Gravity.BOTTOM, 0, 0);
1531 toast.show();
1532 }
1533
Wink Savillee68857d2014-10-17 15:23:05 -07001534 private void launchConfirmationDialog(TextMessage msg, int slotId) {
1535 msg.title = mStkContext[slotId].lastSelectedItem;
1536 Intent newIntent = new Intent();
1537 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1538 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1539 //Set unique URI to create a new instance of activity for different slotId.
1540 Uri uriData = Uri.parse(uriString);
1541
1542 if (newIntent != null) {
1543 newIntent.setClassName(this, targetActivity);
1544 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1545 | Intent.FLAG_ACTIVITY_NO_HISTORY
1546 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1547 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1548 newIntent.putExtra("TEXT", msg);
1549 newIntent.putExtra(SLOT_ID, slotId);
1550 newIntent.setData(uriData);
1551 startActivity(newIntent);
1552 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001553 }
1554
1555 private void launchBrowser(BrowserSettings settings) {
1556 if (settings == null) {
1557 return;
1558 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001559
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001560 Uri data = null;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001561 String url;
1562 if (settings.url == null) {
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001563 // if the command did not contain a URL,
1564 // launch the browser to the default homepage.
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001565 CatLog.d(this, "no url data provided by proactive command." +
1566 " launching browser with stk default URL ... ");
1567 url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP,
1568 "http://www.google.com");
1569 } else {
1570 CatLog.d(this, "launch browser command has attached url = " + settings.url);
1571 url = settings.url;
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001572 }
David Brown7c03cfe2011-10-20 15:36:12 -07001573
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001574 if (url.startsWith("http://") || url.startsWith("https://")) {
1575 data = Uri.parse(url);
1576 CatLog.d(this, "launching browser with url = " + url);
1577 } else {
1578 String modifiedUrl = "http://" + url;
1579 data = Uri.parse(modifiedUrl);
1580 CatLog.d(this, "launching browser with modified url = " + modifiedUrl);
1581 }
1582
1583 Intent intent = new Intent(Intent.ACTION_VIEW);
1584 intent.setData(data);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001585 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1586 switch (settings.mode) {
1587 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001588 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1589 break;
1590 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001591 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
1592 break;
1593 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
1594 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1595 break;
1596 }
1597 // start browser activity
1598 startActivity(intent);
1599 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07001600 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001601 // followed immediately.
1602 try {
Ryuto Sawada350aaa62016-06-13 14:47:22 +09001603 Thread.sleep(3000);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001604 } catch (InterruptedException e) {}
1605 }
1606
Wink Savillee68857d2014-10-17 15:23:05 -07001607 private void launchIdleText(int slotId) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001608 TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001609
Preeti Ahuja95919342013-10-01 18:18:55 -07001610 if (msg == null || msg.text ==null) {
1611 CatLog.d(LOG_TAG, msg == null ? "mCurrent.getTextMessage is NULL"
1612 : "mCurrent.getTextMessage.text is NULL");
Wink Savillee68857d2014-10-17 15:23:05 -07001613 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville046db4b2011-11-01 20:42:54 -07001614 return;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001615 } else {
Preeti Ahuja95919342013-10-01 18:18:55 -07001616 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
1617 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
1618 + "] icon[" + msg.icon + "], sim id: " + slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001619 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001620 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001621 new Intent(mContext, StkAppService.class), 0);
fionaxu805eb572017-05-02 10:57:30 -07001622 createAllChannels();
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001623 final Notification.Builder notificationBuilder = new Notification.Builder(
fionaxu2c91c752017-04-21 18:11:57 -07001624 StkAppService.this, STK_NOTIFICATION_CHANNEL_ID);
Wink Savillee68857d2014-10-17 15:23:05 -07001625 if (mStkContext[slotId].mMainCmd != null &&
1626 mStkContext[slotId].mMainCmd.getMenu() != null) {
1627 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001628 } else {
1629 notificationBuilder.setContentTitle("");
1630 }
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001631 notificationBuilder
1632 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1633 notificationBuilder.setContentIntent(pendingIntent);
1634 notificationBuilder.setOngoing(true);
1635 // Set text and icon for the status bar and notification body.
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301636 if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() ||
1637 !msg.iconSelfExplanatory) {
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001638 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001639 notificationBuilder.setTicker(msg.text);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001640 }
1641 if (msg.icon != null) {
1642 notificationBuilder.setLargeIcon(msg.icon);
1643 } else {
1644 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
1645 .getResources().getSystem(),
1646 com.android.internal.R.drawable.stat_notify_sim_toolkit);
1647 notificationBuilder.setLargeIcon(bitmapIcon);
1648 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02001649 notificationBuilder.setColor(mContext.getResources().getColor(
1650 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07001651 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001652 }
1653 }
1654
fionaxu805eb572017-05-02 10:57:30 -07001655 /** Creates the notification channel and registers it with NotificationManager.
1656 * If a channel with the same ID is already registered, NotificationManager will
1657 * ignore this call.
1658 */
1659 private void createAllChannels() {
1660 mNotificationManager.createNotificationChannel(new NotificationChannel(
1661 STK_NOTIFICATION_CHANNEL_ID,
1662 getResources().getString(R.string.stk_channel_name),
1663 NotificationManager.IMPORTANCE_MIN));
1664 }
1665
Wink Savillee68857d2014-10-17 15:23:05 -07001666 private void launchToneDialog(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001667 Intent newIntent = new Intent(this, ToneDialog.class);
Wink Savillee68857d2014-10-17 15:23:05 -07001668 String uriString = STK_TONE_URI + slotId;
1669 Uri uriData = Uri.parse(uriString);
1670 //Set unique URI to create a new instance of activity for different slotId.
1671 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001672 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1673 | Intent.FLAG_ACTIVITY_NO_HISTORY
1674 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Wink Savillee68857d2014-10-17 15:23:05 -07001675 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1676 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1677 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
1678 newIntent.putExtra(SLOT_ID, slotId);
1679 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001680 startActivity(newIntent);
1681 }
1682
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301683 private void handlePlayTone(int slotId) {
1684 TextMessage toneMsg = mStkContext[slotId].mCurrentCmd.geTextMessage();
1685
1686 boolean showUser = true;
1687 boolean displayDialog = true;
1688 Resources resource = Resources.getSystem();
1689 try {
1690 displayDialog = !resource.getBoolean(
1691 com.android.internal.R.bool.config_stkNoAlphaUsrCnf);
1692 } catch (NotFoundException e) {
1693 displayDialog = true;
1694 }
1695
1696 // As per the spec 3GPP TS 11.14, 6.4.5. Play Tone.
1697 // If there is no alpha identifier tlv present, UE may show the
1698 // user information. 'config_stkNoAlphaUsrCnf' value will decide
1699 // whether to show it or not.
1700 // If alpha identifier tlv is present and its data is null, play only tone
1701 // without showing user any information.
1702 // Alpha Id is Present, but the text data is null.
1703 if ((toneMsg.text != null ) && (toneMsg.text.equals(""))) {
1704 CatLog.d(this, "Alpha identifier data is null, play only tone");
1705 showUser = false;
1706 }
1707 // Alpha Id is not present AND we need to show info to the user.
1708 if (toneMsg.text == null && displayDialog) {
1709 CatLog.d(this, "toneMsg.text " + toneMsg.text
1710 + " Starting ToneDialog activity with default message.");
1711 toneMsg.text = getResources().getString(R.string.default_tone_dialog_msg);
1712 showUser = true;
1713 }
1714 // Dont show user info, if config setting is true.
1715 if (toneMsg.text == null && !displayDialog) {
1716 CatLog.d(this, "config value stkNoAlphaUsrCnf is true");
1717 showUser = false;
1718 }
1719
1720 CatLog.d(this, "toneMsg.text: " + toneMsg.text + "showUser: " +showUser +
1721 "displayDialog: " +displayDialog);
1722 playTone(showUser, slotId);
1723 }
1724
1725 private void playTone(boolean showUserInfo, int slotId) {
1726 // Start playing tone and vibration
1727 ToneSettings settings = mStkContext[slotId].mCurrentCmd.getToneSettings();
1728 if (null == settings) {
1729 CatLog.d(this, "null settings, not playing tone.");
1730 return;
1731 }
1732
1733 mVibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
1734 mTonePlayer = new TonePlayer();
1735 mTonePlayer.play(settings.tone);
1736 int timeout = StkApp.calculateDurationInMilis(settings.duration);
1737 if (timeout == 0) {
1738 timeout = StkApp.TONE_DEFAULT_TIMEOUT;
1739 }
1740
1741 Message msg = mServiceHandler.obtainMessage();
1742 msg.arg1 = OP_STOP_TONE;
1743 msg.arg2 = slotId;
1744 msg.obj = (Integer)(showUserInfo ? 1 : 0);
1745 msg.what = STOP_TONE_WHAT;
1746 mServiceHandler.sendMessageDelayed(msg, timeout);
1747 if (settings.vibrate) {
1748 mVibrator.vibrate(timeout);
1749 }
1750
1751 // Start Tone dialog Activity to show user the information.
1752 if (showUserInfo) {
1753 Intent newIntent = new Intent(sInstance, ToneDialog.class);
1754 String uriString = STK_TONE_URI + slotId;
1755 Uri uriData = Uri.parse(uriString);
1756 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1757 | Intent.FLAG_ACTIVITY_NO_HISTORY
1758 | Intent.FLAG_ACTIVITY_SINGLE_TOP
1759 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1760 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1761 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1762 newIntent.putExtra(SLOT_ID, slotId);
1763 newIntent.setData(uriData);
1764 startActivity(newIntent);
1765 }
1766 }
1767
1768 private void finishToneDialogActivity() {
1769 Intent finishIntent = new Intent(FINISH_TONE_ACTIVITY_ACTION);
1770 sendBroadcast(finishIntent);
1771 }
1772
1773 private void handleStopTone(Message msg, int slotId) {
1774 int resId = 0;
1775
1776 // Stop the play tone in following cases:
1777 // 1.OP_STOP_TONE: play tone timer expires.
1778 // 2.STOP_TONE_USER: user pressed the back key.
1779 if (msg.arg1 == OP_STOP_TONE) {
1780 resId = RES_ID_DONE;
1781 // Dismiss Tone dialog, after finishing off playing the tone.
1782 int finishActivity = (Integer) msg.obj;
1783 if (finishActivity == 1) finishToneDialogActivity();
1784 } else if (msg.arg1 == OP_STOP_TONE_USER) {
1785 resId = RES_ID_END_SESSION;
1786 }
1787
1788 sendResponse(resId, slotId, true);
1789 mServiceHandler.removeMessages(STOP_TONE_WHAT);
1790 if (mTonePlayer != null) {
1791 mTonePlayer.stop();
1792 mTonePlayer.release();
1793 mTonePlayer = null;
1794 }
1795 if (mVibrator != null) {
1796 mVibrator.cancel();
1797 mVibrator = null;
1798 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001799 }
1800
Takanori Nakano49b12722016-02-16 14:34:14 +09001801 private void launchOpenChannelDialog(final int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -07001802 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001803 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001804 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001805 return;
1806 }
1807
1808 msg.title = getResources().getString(R.string.stk_dialog_title);
1809 if (msg.text == null) {
1810 msg.text = getResources().getString(R.string.default_open_channel_msg);
1811 }
1812
1813 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1814 .setIconAttribute(android.R.attr.alertDialogIcon)
1815 .setTitle(msg.title)
1816 .setMessage(msg.text)
1817 .setCancelable(false)
1818 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
1819 new DialogInterface.OnClickListener() {
1820 public void onClick(DialogInterface dialog, int which) {
1821 Bundle args = new Bundle();
1822 args.putInt(RES_ID, RES_ID_CHOICE);
1823 args.putInt(CHOICE, YES);
1824 Message message = mServiceHandler.obtainMessage();
1825 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09001826 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001827 message.obj = args;
1828 mServiceHandler.sendMessage(message);
1829 }
1830 })
1831 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
1832 new DialogInterface.OnClickListener() {
1833 public void onClick(DialogInterface dialog, int which) {
1834 Bundle args = new Bundle();
1835 args.putInt(RES_ID, RES_ID_CHOICE);
1836 args.putInt(CHOICE, NO);
1837 Message message = mServiceHandler.obtainMessage();
1838 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09001839 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001840 message.obj = args;
1841 mServiceHandler.sendMessage(message);
1842 }
1843 })
1844 .create();
1845
1846 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1847 if (!mContext.getResources().getBoolean(
1848 com.android.internal.R.bool.config_sf_slowBlur)) {
1849 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1850 }
1851
1852 dialog.show();
1853 }
1854
Wink Savillee68857d2014-10-17 15:23:05 -07001855 private void launchTransientEventMessage(int slotId) {
1856 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001857 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001858 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001859 return;
1860 }
1861
1862 msg.title = getResources().getString(R.string.stk_dialog_title);
1863
1864 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1865 .setIconAttribute(android.R.attr.alertDialogIcon)
1866 .setTitle(msg.title)
1867 .setMessage(msg.text)
1868 .setCancelable(false)
1869 .setPositiveButton(getResources().getString(android.R.string.ok),
1870 new DialogInterface.OnClickListener() {
1871 public void onClick(DialogInterface dialog, int which) {
1872 }
1873 })
1874 .create();
1875
1876 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1877 if (!mContext.getResources().getBoolean(
1878 com.android.internal.R.bool.config_sf_slowBlur)) {
1879 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1880 }
1881
1882 dialog.show();
1883 }
1884
Wink Savillee68857d2014-10-17 15:23:05 -07001885 private int getNotificationId(int slotId) {
1886 int notifyId = STK_NOTIFICATION_ID;
1887 if (slotId >= 0 && slotId < mSimCount) {
1888 notifyId += slotId;
1889 } else {
1890 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1891 }
1892 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
1893 return notifyId;
1894 }
1895
1896 private String getItemName(int itemId, int slotId) {
1897 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001898 if (menu == null) {
1899 return null;
1900 }
1901 for (Item item : menu.items) {
1902 if (item.id == itemId) {
1903 return item.text;
1904 }
1905 }
1906 return null;
1907 }
1908
Wink Savillee68857d2014-10-17 15:23:05 -07001909 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001910 try {
Wink Savillee68857d2014-10-17 15:23:05 -07001911 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
1912 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
1913 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001914 return true;
1915 }
1916 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07001917 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
1918 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001919 return true;
1920 }
Wink Savillee68857d2014-10-17 15:23:05 -07001921 mStkContext[slotId].mSetupMenuState = STATE_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001922 return false;
1923 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301924
Wink Savillee68857d2014-10-17 15:23:05 -07001925 StkContext getStkContext(int slotId) {
1926 if (slotId >= 0 && slotId < mSimCount) {
1927 return mStkContext[slotId];
1928 } else {
1929 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1930 return null;
1931 }
1932 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301933
1934 private void handleAlphaNotify(Bundle args) {
1935 String alphaString = args.getString(AppInterface.ALPHA_STRING);
1936
1937 CatLog.d(this, "Alpha string received from card: " + alphaString);
1938 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
1939 toast.setGravity(Gravity.TOP, 0, 0);
1940 toast.show();
1941 }
Srikanth Chintalaba103002015-11-30 10:49:52 -08001942
1943 private boolean isUrlAvailableToLaunchBrowser(BrowserSettings settings) {
1944 String url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP, "");
1945 if (url == "" && settings.url == null) {
1946 return false;
1947 }
1948 return true;
1949 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001950}