blob: 20ea30fe87c38055cde407477178564979c7fbdc [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;
231
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500232 static final int YES = 1;
233 static final int NO = 0;
234
Wink Savillee68857d2014-10-17 15:23:05 -0700235 static final int STATE_UNKNOWN = -1;
236 static final int STATE_NOT_EXIST = 0;
237 static final int STATE_EXIST = 1;
Wink Saville79085fc2009-06-09 10:27:23 -0700238
Wink Savillee68857d2014-10-17 15:23:05 -0700239 private static final String PACKAGE_NAME = "com.android.stk";
240 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
241 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
242 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800243 // Notification id used to display Idle Mode text in NotificationManager.
244 private static final int STK_NOTIFICATION_ID = 333;
fionaxu2c91c752017-04-21 18:11:57 -0700245 // Notification channel containing all mobile service messages notifications.
246 private static final String STK_NOTIFICATION_CHANNEL_ID = "mobileServiceMessages";
247
Wink Savillee68857d2014-10-17 15:23:05 -0700248 private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
Wink Saville79085fc2009-06-09 10:27:23 -0700249
250 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800251 // session end) while the service is busy processing a previous message.
252 private class DelayedCmd {
253 // members
254 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700255 CatCmdMessage msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700256 int slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800257
Wink Savillee68857d2014-10-17 15:23:05 -0700258 DelayedCmd(int id, CatCmdMessage msg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800259 this.id = id;
260 this.msg = msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700261 this.slotId = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800262 }
263 }
264
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700265 // system property to set the STK specific default url for launch browser proactive cmds
266 private static final String STK_BROWSER_DEFAULT_URL_SYSPROP = "persist.radio.stk.default_url";
267
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800268 @Override
269 public void onCreate() {
Wink Savillee68857d2014-10-17 15:23:05 -0700270 CatLog.d(LOG_TAG, "onCreate()+");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800271 // Initialize members
Wink Savillee68857d2014-10-17 15:23:05 -0700272 int i = 0;
273 mContext = getBaseContext();
274 mSimCount = TelephonyManager.from(mContext).getSimCount();
275 CatLog.d(LOG_TAG, "simCount: " + mSimCount);
276 mStkService = new AppInterface[mSimCount];
277 mStkContext = new StkContext[mSimCount];
Preeti Ahuja560be362014-11-25 19:38:24 -0800278 mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
279 mStkCmdReceiver = new StkCmdReceiver();
280 registerReceiver(mStkCmdReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
Wink Savillee68857d2014-10-17 15:23:05 -0700281 for (i = 0; i < mSimCount; i++) {
282 CatLog.d(LOG_TAG, "slotId: " + i);
Legler Wuaeefef52014-10-27 00:57:18 +0800283 mStkService[i] = CatService.getInstance(i);
Wink Savillee68857d2014-10-17 15:23:05 -0700284 mStkContext[i] = new StkContext();
285 mStkContext[i].mSlotId = i;
286 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
287 }
288
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800289 Thread serviceThread = new Thread(null, this, "Stk App Service");
290 serviceThread.start();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800291 mNotificationManager = (NotificationManager) mContext
292 .getSystemService(Context.NOTIFICATION_SERVICE);
293 sInstance = this;
294 }
295
296 @Override
297 public void onStart(Intent intent, int startId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700298 if (intent == null) {
299 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530300 return;
301 }
302
Wink Savillee68857d2014-10-17 15:23:05 -0700303 Bundle args = intent.getExtras();
304 if (args == null) {
305 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
306 return;
307 }
308
309 int op = args.getInt(OPCODE);
310 int slotId = 0;
311 int i = 0;
312 if (op != OP_BOOT_COMPLETED) {
313 slotId = args.getInt(SLOT_ID);
314 }
Cuihtlauac ALVARADObde7f032015-05-29 16:25:12 +0200315 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", *****");
Wink Savillee68857d2014-10-17 15:23:05 -0700316 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +0800317 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -0700318 if (mStkService[slotId] == null) {
319 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
320 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
321 //Check other StkService state.
322 //If all StkServices are not available, stop itself and uninstall apk.
323 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
324 if (i != slotId
Tsukasa Goto029332b2016-10-05 17:12:06 +0900325 && (mStkService[i] != null)
Wink Savillee68857d2014-10-17 15:23:05 -0700326 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
327 || mStkContext[i].mStkServiceState == STATE_EXIST)) {
328 break;
329 }
330 }
331 } else {
332 mStkContext[slotId].mStkServiceState = STATE_EXIST;
333 }
334 if (i == mSimCount) {
335 stopSelf();
336 StkAppInstaller.unInstall(mContext);
337 return;
338 }
339 }
340
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530341 waitForLooper();
John Wang62acae42009-10-08 11:20:23 -0700342
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800343 Message msg = mServiceHandler.obtainMessage();
Wink Savillee68857d2014-10-17 15:23:05 -0700344 msg.arg1 = op;
345 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800346 switch(msg.arg1) {
347 case OP_CMD:
348 msg.obj = args.getParcelable(CMD_MSG);
349 break;
350 case OP_RESPONSE:
Wink Saville94e982b2014-07-11 07:38:14 -0700351 case OP_CARD_STATUS_CHANGED:
Preeti Ahuja95919342013-10-01 18:18:55 -0700352 case OP_LOCALE_CHANGED:
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530353 case OP_ALPHA_NOTIFY:
Preeti Ahuja560be362014-11-25 19:38:24 -0800354 case OP_IDLE_SCREEN:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800355 msg.obj = args;
356 /* falls through */
357 case OP_LAUNCH_APP:
358 case OP_END_SESSION:
359 case OP_BOOT_COMPLETED:
360 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530361 case OP_STOP_TONE_USER:
362 msg.obj = args;
363 msg.what = STOP_TONE_WHAT;
364 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800365 default:
366 return;
367 }
368 mServiceHandler.sendMessage(msg);
369 }
370
371 @Override
372 public void onDestroy() {
Wink Savillee68857d2014-10-17 15:23:05 -0700373 CatLog.d(LOG_TAG, "onDestroy()");
Preeti Ahuja560be362014-11-25 19:38:24 -0800374 if (mStkCmdReceiver != null) {
375 unregisterReceiver(mStkCmdReceiver);
376 mStkCmdReceiver = null;
377 }
378 mPowerManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800379 waitForLooper();
380 mServiceLooper.quit();
381 }
382
383 @Override
384 public IBinder onBind(Intent intent) {
385 return null;
386 }
387
388 public void run() {
389 Looper.prepare();
390
391 mServiceLooper = Looper.myLooper();
392 mServiceHandler = new ServiceHandler();
393
394 Looper.loop();
395 }
396
397 /*
398 * Package api used by StkMenuActivity to indicate if its on the foreground.
399 */
Wink Savillee68857d2014-10-17 15:23:05 -0700400 void indicateMenuVisibility(boolean visibility, int slotId) {
401 if (slotId >= 0 && slotId < mSimCount) {
402 mStkContext[slotId].mMenuIsVisible = visibility;
403 }
404 }
405
Preeti Ahuja95919342013-10-01 18:18:55 -0700406 /*
407 * Package api used by StkDialogActivity to indicate if its on the foreground.
408 */
409 void setDisplayTextDlgVisibility(boolean visibility, int slotId) {
410 if (slotId >= 0 && slotId < mSimCount) {
411 mStkContext[slotId].mDisplayTextDlgIsVisibile = visibility;
412 }
413 }
414
Wink Savillee68857d2014-10-17 15:23:05 -0700415 boolean isInputPending(int slotId) {
416 if (slotId >= 0 && slotId < mSimCount) {
417 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
418 return mStkContext[slotId].mIsInputPending;
419 }
420 return false;
421 }
422
423 boolean isMenuPending(int slotId) {
424 if (slotId >= 0 && slotId < mSimCount) {
425 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
426 return mStkContext[slotId].mIsMenuPending;
427 }
428 return false;
429 }
430
431 boolean isDialogPending(int slotId) {
432 if (slotId >= 0 && slotId < mSimCount) {
433 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
434 return mStkContext[slotId].mIsDialogPending;
435 }
436 return false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800437 }
438
439 /*
440 * Package api used by StkMenuActivity to get its Menu parameter.
441 */
Wink Savillee68857d2014-10-17 15:23:05 -0700442 Menu getMenu(int slotId) {
443 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
444 if (slotId >=0 && slotId < mSimCount) {
445 return mStkContext[slotId].mCurrentMenu;
446 } else {
447 return null;
448 }
449 }
450
451 /*
452 * Package api used by StkMenuActivity to get its Main Menu parameter.
453 */
454 Menu getMainMenu(int slotId) {
455 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
w30234a08cffe2015-02-04 15:13:25 -0800456 if (slotId >=0 && slotId < mSimCount && (mStkContext[slotId].mMainCmd != null)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700457 return mStkContext[slotId].mMainCmd.getMenu();
458 } else {
459 return null;
460 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800461 }
462
463 /*
464 * Package api used by UI Activities and Dialogs to communicate directly
465 * with the service to deliver state information and parameters.
466 */
467 static StkAppService getInstance() {
468 return sInstance;
469 }
470
471 private void waitForLooper() {
472 while (mServiceHandler == null) {
473 synchronized (this) {
474 try {
475 wait(100);
476 } catch (InterruptedException e) {
477 }
478 }
479 }
480 }
481
482 private final class ServiceHandler extends Handler {
483 @Override
484 public void handleMessage(Message msg) {
Wink Savillee68857d2014-10-17 15:23:05 -0700485 if(null == msg) {
486 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
487 return;
488 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800489 int opcode = msg.arg1;
Wink Savillee68857d2014-10-17 15:23:05 -0700490 int slotId = msg.arg2;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800491
Wink Savillee68857d2014-10-17 15:23:05 -0700492 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
493 if (opcode == OP_CMD && msg.obj != null &&
494 ((CatCmdMessage)msg.obj).getCmdType()!= null) {
495 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
496 }
497 mStkContext[slotId].mOpCode = opcode;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800498 switch (opcode) {
499 case OP_LAUNCH_APP:
Wink Savillee68857d2014-10-17 15:23:05 -0700500 if (mStkContext[slotId].mMainCmd == null) {
501 CatLog.d(LOG_TAG, "mMainCmd is null");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800502 // nothing todo when no SET UP MENU command didn't arrive.
503 return;
504 }
Wink Savillee68857d2014-10-17 15:23:05 -0700505 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
506 mStkContext[slotId].mCmdInProgress + "]");
507
508 //If there is a pending activity for the slot id,
509 //just finish it and create a new one to handle the pending command.
510 cleanUpInstanceStackBySlot(slotId);
511
Wink Savillee68857d2014-10-17 15:23:05 -0700512 CatLog.d(LOG_TAG, "Current cmd type: " +
513 mStkContext[slotId].mCurrentCmd.getCmdType());
514 //Restore the last command from stack by slot id.
515 restoreInstanceFromStackBySlot(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800516 break;
517 case OP_CMD:
Wink Savillee68857d2014-10-17 15:23:05 -0700518 CatLog.d(LOG_TAG, "[OP_CMD]");
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700519 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800520 // There are two types of commands:
521 // 1. Interactive - user's response is required.
522 // 2. Informative - display a message, no interaction with the user.
523 //
Wink Saville79085fc2009-06-09 10:27:23 -0700524 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800525 // Interactive commands can't override each other. So if a command
526 // is already in progress, we need to queue the next command until
527 // the user has responded or a timeout expired.
528 if (!isCmdInteractive(cmdMsg)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700529 handleCmd(cmdMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800530 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700531 if (!mStkContext[slotId].mCmdInProgress) {
532 mStkContext[slotId].mCmdInProgress = true;
533 handleCmd((CatCmdMessage) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800534 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700535 CatLog.d(LOG_TAG, "[Interactive][in progress]");
536 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
537 (CatCmdMessage) msg.obj, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800538 }
539 }
540 break;
541 case OP_RESPONSE:
Preeti Ahuja414bc412013-06-25 19:31:49 -0700542 handleCmdResponse((Bundle) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800543 // call delayed commands if needed.
Wink Savillee68857d2014-10-17 15:23:05 -0700544 if (mStkContext[slotId].mCmdsQ.size() != 0) {
545 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800546 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700547 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800548 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800549 break;
550 case OP_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700551 if (!mStkContext[slotId].mCmdInProgress) {
552 mStkContext[slotId].mCmdInProgress = true;
553 handleSessionEnd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800554 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700555 mStkContext[slotId].mCmdsQ.addLast(
556 new DelayedCmd(OP_END_SESSION, null, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800557 }
558 break;
559 case OP_BOOT_COMPLETED:
Wink Savillee68857d2014-10-17 15:23:05 -0700560 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
561 int i = 0;
562 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
563 if (mStkContext[i].mMainCmd != null) {
564 break;
565 }
566 }
567 if (i == mSimCount) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800568 StkAppInstaller.unInstall(mContext);
569 }
570 break;
571 case OP_DELAYED_MSG:
Wink Savillee68857d2014-10-17 15:23:05 -0700572 handleDelayedCmd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800573 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700574 case OP_CARD_STATUS_CHANGED:
Wink Savillee68857d2014-10-17 15:23:05 -0700575 CatLog.d(LOG_TAG, "Card/Icc Status change received");
576 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
577 break;
578 case OP_SET_ACT_INST:
579 Activity act = new Activity();
580 act = (Activity) msg.obj;
581 CatLog.d(LOG_TAG, "Set activity instance. " + act);
582 mStkContext[slotId].mActivityInstance = act;
583 break;
584 case OP_SET_DAL_INST:
585 Activity dal = new Activity();
586 CatLog.d(LOG_TAG, "Set dialog instance. " + dal);
587 dal = (Activity) msg.obj;
588 mStkContext[slotId].mDialogInstance = dal;
589 break;
590 case OP_SET_MAINACT_INST:
591 Activity mainAct = new Activity();
592 mainAct = (Activity) msg.obj;
593 CatLog.d(LOG_TAG, "Set activity instance. " + mainAct);
594 mStkContext[slotId].mMainActivityInstance = mainAct;
Wink Saville94e982b2014-07-11 07:38:14 -0700595 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700596 case OP_LOCALE_CHANGED:
597 CatLog.d(this, "Locale Changed");
Yuta Ui1481b172016-02-03 15:34:31 +0900598 for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
599 checkForSetupEvent(LANGUAGE_SELECTION_EVENT, (Bundle) msg.obj, slot);
600 }
fionaxu805eb572017-05-02 10:57:30 -0700601 // rename all registered notification channels on locale change
602 createAllChannels();
Preeti Ahuja95919342013-10-01 18:18:55 -0700603 break;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530604 case OP_ALPHA_NOTIFY:
605 handleAlphaNotify((Bundle) msg.obj);
606 break;
Preeti Ahuja560be362014-11-25 19:38:24 -0800607 case OP_IDLE_SCREEN:
608 for (int slot = 0; slot < mSimCount; slot++) {
609 if (mStkContext[slot] != null) {
610 handleIdleScreen(slot);
611 }
612 }
613 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530614 case OP_STOP_TONE_USER:
615 case OP_STOP_TONE:
616 CatLog.d(this, "Stop tone");
617 handleStopTone(msg, slotId);
618 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700619 }
620 }
621
Wink Savillee68857d2014-10-17 15:23:05 -0700622 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
Wink Saville94e982b2014-07-11 07:38:14 -0700623 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
624
Wink Savillee68857d2014-10-17 15:23:05 -0700625 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
Wink Saville94e982b2014-07-11 07:38:14 -0700626 if (cardStatus == false) {
Wink Savillee68857d2014-10-17 15:23:05 -0700627 CatLog.d(LOG_TAG, "CARD is ABSENT");
Wink Saville94e982b2014-07-11 07:38:14 -0700628 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
Wink Savillee68857d2014-10-17 15:23:05 -0700629 mNotificationManager.cancel(getNotificationId(slotId));
Srikanth Chintala7c5a04c2016-09-22 19:05:01 +0530630 mStkContext[slotId].mCurrentMenu = null;
631 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700632 if (isAllOtherCardsAbsent(slotId)) {
633 CatLog.d(LOG_TAG, "All CARDs are ABSENT");
634 StkAppInstaller.unInstall(mContext);
635 stopSelf();
636 }
Wink Saville94e982b2014-07-11 07:38:14 -0700637 } else {
638 IccRefreshResponse state = new IccRefreshResponse();
639 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
640
Wink Savillee68857d2014-10-17 15:23:05 -0700641 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
Wink Saville94e982b2014-07-11 07:38:14 -0700642 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
643 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
644 // Clear Idle Text
Wink Savillee68857d2014-10-17 15:23:05 -0700645 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville94e982b2014-07-11 07:38:14 -0700646 }
647
648 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
649 // Uninstall STkmenu
Wink Savillee68857d2014-10-17 15:23:05 -0700650 if (isAllOtherCardsAbsent(slotId)) {
651 StkAppInstaller.unInstall(mContext);
652 }
653 mStkContext[slotId].mCurrentMenu = null;
654 mStkContext[slotId].mMainCmd = null;
Wink Saville94e982b2014-07-11 07:38:14 -0700655 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800656 }
657 }
658 }
Wink Savillee68857d2014-10-17 15:23:05 -0700659 /*
660 * Check if all SIMs are absent except the id of slot equals "slotId".
661 */
662 private boolean isAllOtherCardsAbsent(int slotId) {
663 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
664 Context.TELEPHONY_SERVICE);
665 int i = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800666
Wink Savillee68857d2014-10-17 15:23:05 -0700667 for (i = 0; i < mSimCount; i++) {
668 if (i != slotId && mTm.hasIccCard(i)) {
669 break;
670 }
671 }
672 if (i == mSimCount) {
673 return true;
674 } else {
675 return false;
676 }
677 }
Preeti Ahuja95919342013-10-01 18:18:55 -0700678
Preeti Ahuja560be362014-11-25 19:38:24 -0800679 /*
680 * If the device is not in an interactive state, we can assume
681 * that the screen is idle.
682 */
683 private boolean isScreenIdle() {
684 return (!mPowerManager.isInteractive());
685 }
686
687 private void handleIdleScreen(int slotId) {
688
689 // If the idle screen event is present in the list need to send the
690 // response to SIM.
691 CatLog.d(this, "Need to send IDLE SCREEN Available event to SIM");
692 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
693
694 if (mStkContext[slotId].mIdleModeTextCmd != null) {
695 launchIdleText(slotId);
696 }
697 }
698
699 private void sendScreenBusyResponse(int slotId) {
700 if (mStkContext[slotId].mCurrentCmd == null) {
701 return;
702 }
703 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
704 CatLog.d(this, "SCREEN_BUSY");
705 resMsg.setResultCode(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS);
706 mStkService[slotId].onCmdResponse(resMsg);
707 if (mStkContext[slotId].mCmdsQ.size() != 0) {
708 callDelayedMsg(slotId);
709 } else {
710 mStkContext[slotId].mCmdInProgress = false;
711 }
712 }
713
Preeti Ahuja95919342013-10-01 18:18:55 -0700714 private void sendResponse(int resId, int slotId, boolean confirm) {
715 Message msg = mServiceHandler.obtainMessage();
716 msg.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +0900717 msg.arg2 = slotId;
Preeti Ahuja95919342013-10-01 18:18:55 -0700718 Bundle args = new Bundle();
719 args.putInt(StkAppService.RES_ID, resId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700720 args.putBoolean(StkAppService.CONFIRMATION, confirm);
721 msg.obj = args;
722 mServiceHandler.sendMessage(msg);
723 }
724
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700725 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800726 switch (cmd.getCmdType()) {
727 case SEND_DTMF:
728 case SEND_SMS:
729 case SEND_SS:
730 case SEND_USSD:
731 case SET_UP_IDLE_MODE_TEXT:
732 case SET_UP_MENU:
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500733 case CLOSE_CHANNEL:
734 case RECEIVE_DATA:
735 case SEND_DATA:
Preeti Ahuja95919342013-10-01 18:18:55 -0700736 case SET_UP_EVENT_LIST:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800737 return false;
738 }
739
740 return true;
741 }
742
Wink Savillee68857d2014-10-17 15:23:05 -0700743 private void handleDelayedCmd(int slotId) {
744 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
745 if (mStkContext[slotId].mCmdsQ.size() != 0) {
746 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
747 if (cmd != null) {
748 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
749 mStkContext[slotId].mCmdsQ.size() +
750 " id: " + cmd.id + "sim id: " + cmd.slotId);
751 switch (cmd.id) {
752 case OP_CMD:
753 handleCmd(cmd.msg, cmd.slotId);
754 break;
755 case OP_END_SESSION:
756 handleSessionEnd(cmd.slotId);
757 break;
758 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800759 }
760 }
761 }
762
Wink Savillee68857d2014-10-17 15:23:05 -0700763 private void callDelayedMsg(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800764 Message msg = mServiceHandler.obtainMessage();
765 msg.arg1 = OP_DELAYED_MSG;
Wink Savillee68857d2014-10-17 15:23:05 -0700766 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800767 mServiceHandler.sendMessage(msg);
768 }
769
Wink Savillee68857d2014-10-17 15:23:05 -0700770 private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) {
771 Message msg = mServiceHandler.obtainMessage();
772 msg.obj = obj;
773 msg.arg1 = inst_type;
774 msg.arg2 = slotId;
775 mServiceHandler.sendMessage(msg);
776 }
777
778 private void handleSessionEnd(int slotId) {
Legler Wuaeefef52014-10-27 00:57:18 +0800779 // We should finish all pending activity if receiving END SESSION command.
780 cleanUpInstanceStackBySlot(slotId);
781
Wink Savillee68857d2014-10-17 15:23:05 -0700782 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
783 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
784 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
785 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
786 mStkContext[slotId].mMenuState);
787
788 mStkContext[slotId].mIsInputPending = false;
789 mStkContext[slotId].mIsMenuPending = false;
790 mStkContext[slotId].mIsDialogPending = false;
791
Wink Savillee68857d2014-10-17 15:23:05 -0700792 if (mStkContext[slotId].mMainCmd == null) {
793 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
794 }
795 mStkContext[slotId].lastSelectedItem = null;
Wink Saville79085fc2009-06-09 10:27:23 -0700796 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800797 // update the current menu member.
Wink Savillee68857d2014-10-17 15:23:05 -0700798 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
799 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800800 }
Wink Savillee68857d2014-10-17 15:23:05 -0700801 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
802 // In mutiple instance architecture, the main menu for slotId will be finished when user
803 // goes to the Stk menu of the other SIM. So, we should launch a new instance for the
804 // main menu if the main menu instance has been finished.
805 // If the current menu is secondary menu, we should launch main menu.
806 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
807 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800808 }
Wink Savillee68857d2014-10-17 15:23:05 -0700809 if (mStkContext[slotId].mCmdsQ.size() != 0) {
810 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800811 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700812 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800813 }
814 // In case a launch browser command was just confirmed, launch that url.
Wink Savillee68857d2014-10-17 15:23:05 -0700815 if (mStkContext[slotId].launchBrowser) {
816 mStkContext[slotId].launchBrowser = false;
817 launchBrowser(mStkContext[slotId].mBrowserSettings);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800818 }
819 }
820
Preeti Ahuja560be362014-11-25 19:38:24 -0800821 // returns true if any Stk related activity already has focus on the screen
822 private boolean isTopOfStack() {
pkanwareab12f32017-02-06 08:35:03 -0800823 ActivityManager mActivityManager = (ActivityManager) mContext
Preeti Ahuja560be362014-11-25 19:38:24 -0800824 .getSystemService(ACTIVITY_SERVICE);
pkanwareab12f32017-02-06 08:35:03 -0800825 String currentPackageName = null;
826 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
827 if (tasks == null || tasks.get(0).topActivity == null) {
828 return false;
829 }
830 currentPackageName = tasks.get(0).topActivity.getPackageName();
Preeti Ahuja560be362014-11-25 19:38:24 -0800831 if (null != currentPackageName) {
832 return currentPackageName.equals(PACKAGE_NAME);
833 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800834 return false;
835 }
836
Sooraj Sasindrana4160472016-10-12 16:28:25 -0700837 /**
838 * Get the boolean config from carrier config manager.
839 *
840 * @param context the context to get carrier service
841 * @param key config key defined in CarrierConfigManager
842 * @return boolean value of corresponding key.
843 */
844 private static boolean getBooleanCarrierConfig(Context context, String key) {
845 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
846 Context.CARRIER_CONFIG_SERVICE);
847 PersistableBundle b = null;
848 if (configManager != null) {
849 b = configManager.getConfig();
850 }
851 if (b != null) {
852 return b.getBoolean(key);
853 } else {
854 // Return static default defined in CarrierConfigManager.
855 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
856 }
857 }
858
Wink Savillee68857d2014-10-17 15:23:05 -0700859 private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700860
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800861 if (cmdMsg == null) {
862 return;
863 }
864 // save local reference for state tracking.
Wink Savillee68857d2014-10-17 15:23:05 -0700865 mStkContext[slotId].mCurrentCmd = cmdMsg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800866 boolean waitForUsersResponse = true;
867
Wink Savillee68857d2014-10-17 15:23:05 -0700868 mStkContext[slotId].mIsInputPending = false;
869 mStkContext[slotId].mIsMenuPending = false;
870 mStkContext[slotId].mIsDialogPending = false;
871
872 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800873 switch (cmdMsg.getCmdType()) {
874 case DISPLAY_TEXT:
875 TextMessage msg = cmdMsg.geTextMessage();
Jeevaka Badrappan854a25c2012-12-01 16:32:03 +0200876 waitForUsersResponse = msg.responseNeeded;
Wink Savillee68857d2014-10-17 15:23:05 -0700877 if (mStkContext[slotId].lastSelectedItem != null) {
878 msg.title = mStkContext[slotId].lastSelectedItem;
879 } else if (mStkContext[slotId].mMainCmd != null){
Yoshiaki Naka28313ba2017-08-04 12:20:53 +0900880 if (!getResources().getBoolean(R.bool.show_menu_title_only_on_menu)) {
881 msg.title = mStkContext[slotId].mMainCmd.getMenu().title;
882 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800883 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800884 //If we receive a low priority Display Text and the device is
885 // not displaying any STK related activity and the screen is not idle
886 // ( that is, device is in an interactive state), then send a screen busy
887 // terminal response. Otherwise display the message. The existing
888 // displayed message shall be updated with the new display text
889 // proactive command (Refer to ETSI TS 102 384 section 27.22.4.1.4.4.2).
890 if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible
891 || mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) {
892 if(!isScreenIdle()) {
893 CatLog.d(LOG_TAG, "Screen is not idle");
894 sendScreenBusyResponse(slotId);
895 } else {
896 launchTextDialog(slotId);
897 }
898 } else {
899 launchTextDialog(slotId);
900 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800901 break;
902 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700903 CatLog.d(LOG_TAG, "SELECT_ITEM +");
904 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
905 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
906 launchMenuActivity(cmdMsg.getMenu(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800907 break;
908 case SET_UP_MENU:
Wink Savillee68857d2014-10-17 15:23:05 -0700909 mStkContext[slotId].mCmdInProgress = false;
910 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
911 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
912 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
913 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
914
915 if (removeMenu(slotId)) {
916 int i = 0;
917 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App");
918 mStkContext[slotId].mCurrentMenu = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700919 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700920 //Check other setup menu state. If all setup menu are removed, uninstall apk.
921 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
922 if (i != slotId
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +0900923 && (mStkContext[i].mSetupMenuState == STATE_UNKNOWN
924 || mStkContext[i].mSetupMenuState == STATE_EXIST)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700925 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +0900926 + mStkContext[i].mSetupMenuState);
Wink Savillee68857d2014-10-17 15:23:05 -0700927 break;
928 }
929 }
930 if (i == mSimCount) {
931 StkAppInstaller.unInstall(mContext);
932 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800933 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700934 CatLog.d(LOG_TAG, "install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800935 StkAppInstaller.install(mContext);
936 }
Wink Savillee68857d2014-10-17 15:23:05 -0700937 if (mStkContext[slotId].mMenuIsVisible) {
938 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800939 }
940 break;
941 case GET_INPUT:
942 case GET_INKEY:
Wink Savillee68857d2014-10-17 15:23:05 -0700943 launchInputActivity(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800944 break;
945 case SET_UP_IDLE_MODE_TEXT:
946 waitForUsersResponse = false;
Preeti Ahuja560be362014-11-25 19:38:24 -0800947 mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd;
948 TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage();
949 if (idleModeText == null) {
950 launchIdleText(slotId);
951 mStkContext[slotId].mIdleModeTextCmd = null;
952 }
953 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
954 if ((mStkContext[slotId].mIdleModeTextCmd != null) && isScreenIdle()) {
955 CatLog.d(this, "set up idle mode");
956 launchIdleText(slotId);
957 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800958 break;
959 case SEND_DTMF:
960 case SEND_SMS:
961 case SEND_SS:
962 case SEND_USSD:
Preeti Ahuja95919342013-10-01 18:18:55 -0700963 case GET_CHANNEL_STATUS:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800964 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700965 launchEventMessage(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800966 break;
967 case LAUNCH_BROWSER:
Ryuto Sawada0bdc7192016-04-18 12:10:56 +0900968 // The device setup process should not be interrupted by launching browser.
969 if (Settings.Global.getInt(mContext.getContentResolver(),
970 Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
971 CatLog.d(this, "The command is not performed if the setup has not been completed.");
972 sendScreenBusyResponse(slotId);
973 break;
974 }
Sooraj Sasindrana4160472016-10-12 16:28:25 -0700975
976 /* Check if Carrier would not want to launch browser */
977 if (getBooleanCarrierConfig(mContext,
978 CarrierConfigManager.KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL)) {
979 CatLog.d(this, "Browser is not launched as per carrier.");
980 sendResponse(RES_ID_DONE, slotId, true);
981 break;
982 }
983
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700984 TextMessage alphaId = mStkContext[slotId].mCurrentCmd.geTextMessage();
985 if ((mStkContext[slotId].mCurrentCmd.getBrowserSettings().mode
986 == LaunchBrowserMode.LAUNCH_IF_NOT_ALREADY_LAUNCHED) &&
987 ((alphaId == null) || TextUtils.isEmpty(alphaId.text))) {
988 // don't need user confirmation in this case
989 // just launch the browser or spawn a new tab
990 CatLog.d(this, "Browser mode is: launch if not already launched " +
991 "and user confirmation is not currently needed.\n" +
992 "supressing confirmation dialogue and confirming silently...");
993 mStkContext[slotId].launchBrowser = true;
994 mStkContext[slotId].mBrowserSettings =
995 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
996 sendResponse(RES_ID_CONFIRM, slotId, true);
997 } else {
998 launchConfirmationDialog(alphaId, slotId);
999 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001000 break;
1001 case SET_UP_CALL:
Preeti Ahujadd240102013-08-30 17:25:06 -07001002 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg;
1003 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) {
1004 mesg.text = getResources().getString(R.string.default_setup_call_msg);
1005 }
1006 CatLog.d(this, "SET_UP_CALL mesg.text " + mesg.text);
1007 launchConfirmationDialog(mesg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001008 break;
1009 case PLAY_TONE:
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301010 handlePlayTone(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001011 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001012 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -07001013 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001014 break;
1015 case CLOSE_CHANNEL:
1016 case RECEIVE_DATA:
1017 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -07001018 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001019
1020 if ((m != null) && (m.text == null)) {
1021 switch(cmdMsg.getCmdType()) {
1022 case CLOSE_CHANNEL:
1023 m.text = getResources().getString(R.string.default_close_channel_msg);
1024 break;
1025 case RECEIVE_DATA:
1026 m.text = getResources().getString(R.string.default_receive_data_msg);
1027 break;
1028 case SEND_DATA:
1029 m.text = getResources().getString(R.string.default_send_data_msg);
1030 break;
1031 }
1032 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001033 /*
1034 * Display indication in the form of a toast to the user if required.
1035 */
Wink Savillee68857d2014-10-17 15:23:05 -07001036 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001037 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001038 case SET_UP_EVENT_LIST:
1039 mStkContext[slotId].mSetupEventListSettings =
1040 mStkContext[slotId].mCurrentCmd.getSetEventList();
1041 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
1042 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
Preeti Ahuja560be362014-11-25 19:38:24 -08001043 if (isScreenIdle()) {
1044 CatLog.d(this," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List");
1045 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
1046 }
Preeti Ahuja95919342013-10-01 18:18:55 -07001047 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001048 }
1049
1050 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -07001051 if (mStkContext[slotId].mCmdsQ.size() != 0) {
1052 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001053 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001054 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001055 }
1056 }
1057 }
1058
Wink Savillee68857d2014-10-17 15:23:05 -07001059 private void handleCmdResponse(Bundle args, int slotId) {
1060 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
1061 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001062 return;
1063 }
Wink Savillee68857d2014-10-17 15:23:05 -07001064
1065 if (mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +08001066 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001067 if (mStkService[slotId] == null) {
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001068 // This should never happen (we should be responding only to a message
1069 // that arrived from StkService). It has to exist by this time
Wink Savillee68857d2014-10-17 15:23:05 -07001070 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response.");
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001071 throw new RuntimeException("mStkService is null when we need to send response");
1072 }
1073 }
1074
Wink Savillee68857d2014-10-17 15:23:05 -07001075 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001076
1077 // set result code
1078 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001079 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001080
1081 switch(args.getInt(RES_ID)) {
1082 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -07001083 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
1084 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001085 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -07001086 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001087 case SET_UP_MENU:
1088 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -07001089 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001090 if (helpRequired) {
1091 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1092 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301093 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1094 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001095 }
1096 resMsg.setMenuSelection(menuSelection);
1097 break;
1098 }
1099 break;
1100 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001101 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001102 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -07001103 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
1104 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001105 boolean yesNoSelection = input
1106 .equals(StkInputActivity.YES_STR_RESPONSE);
1107 resMsg.setYesNo(yesNoSelection);
1108 } else {
1109 if (helpRequired) {
1110 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1111 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301112 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1113 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001114 resMsg.setInput(input);
1115 }
1116 }
1117 break;
1118 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -07001119 CatLog.d(this, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001120 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -07001121 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001122 case DISPLAY_TEXT:
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301123 if (confirmed) {
1124 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1125 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
1126 } else {
1127 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1128 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001129 break;
1130 case LAUNCH_BROWSER:
1131 resMsg.setResultCode(confirmed ? ResultCode.OK
1132 : ResultCode.UICC_SESSION_TERM_BY_USER);
1133 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001134 mStkContext[slotId].launchBrowser = true;
1135 mStkContext[slotId].mBrowserSettings =
1136 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001137 }
1138 break;
1139 case SET_UP_CALL:
1140 resMsg.setResultCode(ResultCode.OK);
1141 resMsg.setConfirmation(confirmed);
1142 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001143 launchEventMessage(slotId,
1144 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001145 }
1146 break;
1147 }
1148 break;
1149 case RES_ID_DONE:
1150 resMsg.setResultCode(ResultCode.OK);
1151 break;
1152 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -07001153 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001154 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
1155 break;
1156 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -07001157 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001158 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1159 break;
1160 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001161 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -08001162 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
1163 // Clear message after delay, successful) expects result code OK.
1164 // If the command qualifier specifies no user response is required
1165 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -07001166 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1167 AppInterface.CommandType.DISPLAY_TEXT.value())
1168 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -08001169 resMsg.setResultCode(ResultCode.OK);
1170 } else {
1171 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
1172 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001173 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001174 case RES_ID_CHOICE:
1175 int choice = args.getInt(CHOICE);
1176 CatLog.d(this, "User Choice=" + choice);
1177 switch (choice) {
1178 case YES:
1179 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001180 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001181 break;
1182 case NO:
1183 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
1184 break;
1185 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001186
Wink Savillee68857d2014-10-17 15:23:05 -07001187 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1188 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001189 resMsg.setConfirmation(confirmed);
1190 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001191 break;
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001192
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001193 default:
Wink Savillee68857d2014-10-17 15:23:05 -07001194 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001195 return;
1196 }
Wink Savillee68857d2014-10-17 15:23:05 -07001197
1198 if (null != mStkContext[slotId].mCurrentCmd &&
1199 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1200 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1201 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1202 }
1203 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001204 }
1205
1206 /**
1207 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1208 *
1209 * @param userAction If the userAction is yes then we always return 0 otherwise
1210 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1211 * then we are the foreground app and we'll return 0 as from our perspective a
1212 * user action did cause. If it's false than we aren't the foreground app and
1213 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001214 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001215 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1216 */
Wink Savillee68857d2014-10-17 15:23:05 -07001217 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1218 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1219 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1220 }
1221 /**
1222 * This method is used for cleaning up pending instances in stack.
1223 */
1224 private void cleanUpInstanceStackBySlot(int slotId) {
1225 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1226 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1227 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
Legler Wuaeefef52014-10-27 00:57:18 +08001228 if (mStkContext[slotId].mCurrentCmd == null) {
1229 CatLog.d(LOG_TAG, "current cmd is null.");
1230 return;
1231 }
Wink Savillee68857d2014-10-17 15:23:05 -07001232 if (activity != null) {
1233 CatLog.d(LOG_TAG, "current cmd type: " +
1234 mStkContext[slotId].mCurrentCmd.getCmdType());
1235 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1236 AppInterface.CommandType.GET_INPUT.value() ||
1237 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1238 AppInterface.CommandType.GET_INKEY.value()) {
1239 mStkContext[slotId].mIsInputPending = true;
1240 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1241 AppInterface.CommandType.SET_UP_MENU.value() ||
1242 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1243 AppInterface.CommandType.SELECT_ITEM.value()) {
1244 mStkContext[slotId].mIsMenuPending = true;
1245 } else {
1246 }
1247 CatLog.d(LOG_TAG, "finish pending activity.");
1248 activity.finish();
1249 mStkContext[slotId].mActivityInstance = null;
1250 }
1251 if (dialog != null) {
1252 CatLog.d(LOG_TAG, "finish pending dialog.");
1253 mStkContext[slotId].mIsDialogPending = true;
1254 dialog.finish();
1255 mStkContext[slotId].mDialogInstance = null;
1256 }
1257 }
1258 /**
1259 * This method is used for restoring pending instances from stack.
1260 */
1261 private void restoreInstanceFromStackBySlot(int slotId) {
1262 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1263
1264 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1265 switch(cmdType) {
1266 case GET_INPUT:
1267 case GET_INKEY:
1268 launchInputActivity(slotId);
1269 //Set mMenuIsVisible to true for showing main menu for
1270 //following session end command.
1271 mStkContext[slotId].mMenuIsVisible = true;
1272 break;
1273 case DISPLAY_TEXT:
1274 launchTextDialog(slotId);
1275 break;
1276 case LAUNCH_BROWSER:
1277 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1278 slotId);
1279 break;
1280 case OPEN_CHANNEL:
1281 launchOpenChannelDialog(slotId);
1282 break;
1283 case SET_UP_CALL:
1284 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1285 confirmMsg, slotId);
1286 break;
1287 case SET_UP_MENU:
1288 case SELECT_ITEM:
1289 launchMenuActivity(null, slotId);
1290 break;
1291 default:
1292 break;
1293 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001294 }
1295
Wink Savillee68857d2014-10-17 15:23:05 -07001296 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001297 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001298 String targetActivity = STK_MENU_ACTIVITY_NAME;
1299 String uriString = STK_MENU_URI + System.currentTimeMillis();
1300 //Set unique URI to create a new instance of activity for different slotId.
1301 Uri uriData = Uri.parse(uriString);
1302
1303 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1304 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1305 + mStkContext[slotId].mMenuState);
1306 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1307 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1308
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001309 if (menu == null) {
1310 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001311 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
1312 if (mStkContext[slotId].mOpCode == OP_END_SESSION) {
1313 CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION");
1314 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1315 if (mStkContext[slotId].mMainActivityInstance != null) {
1316 CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null");
1317 return;
1318 }
Wink Savillee68857d2014-10-17 15:23:05 -07001319 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001320
Wink Savillee68857d2014-10-17 15:23:05 -07001321 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1322 //Otherwise, it should be "STATE_MAIN".
1323 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1324 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1325 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1326 } else {
1327 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1328 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1329 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001330 } else {
1331 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001332 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001333 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001334 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001335 }
Wink Savillee68857d2014-10-17 15:23:05 -07001336 newIntent.putExtra(SLOT_ID, slotId);
1337 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001338 newIntent.setFlags(intentFlags);
1339 mContext.startActivity(newIntent);
1340 }
1341
Wink Savillee68857d2014-10-17 15:23:05 -07001342 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001343 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001344 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1345 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1346 //Set unique URI to create a new instance of activity for different slotId.
1347 Uri uriData = Uri.parse(uriString);
1348
1349 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001350 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001351 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1352 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1353 newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput());
1354 newIntent.putExtra(SLOT_ID, slotId);
1355 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001356 mContext.startActivity(newIntent);
1357 }
1358
Wink Savillee68857d2014-10-17 15:23:05 -07001359 private void launchTextDialog(int slotId) {
1360 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1361 Intent newIntent = new Intent();
1362 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1363 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1364 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1365 //Set unique URI to create a new instance of activity for different slotId.
1366 Uri uriData = Uri.parse(uriString);
1367 if (newIntent != null) {
1368 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1369 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1370 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1371 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1372 newIntent.setData(uriData);
1373 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1374 newIntent.putExtra(SLOT_ID, slotId);
1375 startActivity(newIntent);
Preeti Ahuja414bc412013-06-25 19:31:49 -07001376 // For display texts with immediate response, send the terminal response
1377 // immediately. responseNeeded will be false, if display text command has
1378 // the immediate response tlv.
1379 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
1380 sendResponse(RES_ID_CONFIRM, slotId, true);
1381 }
Wink Savillee68857d2014-10-17 15:23:05 -07001382 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001383 }
1384
Wink Savillee68857d2014-10-17 15:23:05 -07001385 public boolean isStkDialogActivated(Context context) {
1386 String stkDialogActivity = "com.android.stk.StkDialogActivity";
1387 boolean activated = false;
1388 final ActivityManager am = (ActivityManager) context.getSystemService(
1389 Context.ACTIVITY_SERVICE);
1390 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName();
1391
1392 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity);
1393 if (topActivity.equals(stkDialogActivity)) {
1394 activated = true;
1395 }
1396 CatLog.d(LOG_TAG, "activated : " + activated);
1397 return activated;
Johan Hellman3aec01c2011-02-10 10:15:28 +01001398 }
1399
Preeti Ahuja95919342013-10-01 18:18:55 -07001400 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
Preeti Ahuja414bc412013-06-25 19:31:49 -07001401 CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -07001402
1403 if (mStkContext[slotId].mCurrentSetupEventCmd == null){
1404 CatLog.e(this, "mCurrentSetupEventCmd is null");
1405 return;
1406 }
1407
1408 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd);
1409
1410 resMsg.setResultCode(ResultCode.OK);
1411 resMsg.setEventDownload(event, addedInfo);
1412
1413 mStkService[slotId].onCmdResponse(resMsg);
1414 }
1415
1416 private void checkForSetupEvent(int event, Bundle args, int slotId) {
1417 boolean eventPresent = false;
1418 byte[] addedInfo = null;
1419 CatLog.d(this, "Event :" + event);
1420
1421 if (mStkContext[slotId].mSetupEventListSettings != null) {
1422 /* Checks if the event is present in the EventList updated by last
1423 * SetupEventList Proactive Command */
1424 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) {
1425 if (event == i) {
1426 eventPresent = true;
1427 break;
1428 }
1429 }
1430
1431 /* If Event is present send the response to ICC */
1432 if (eventPresent == true) {
1433 CatLog.d(this, " Event " + event + "exists in the EventList");
1434
1435 switch (event) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001436 case IDLE_SCREEN_AVAILABLE_EVENT:
1437 sendSetUpEventResponse(event, addedInfo, slotId);
1438 removeSetUpEvent(event, slotId);
1439 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001440 case LANGUAGE_SELECTION_EVENT:
1441 String language = mContext
1442 .getResources().getConfiguration().locale.getLanguage();
1443 CatLog.d(this, "language: " + language);
1444 // Each language code is a pair of alpha-numeric characters.
1445 // Each alpha-numeric character shall be coded on one byte
1446 // using the SMS default 7-bit coded alphabet
1447 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language);
1448 sendSetUpEventResponse(event, addedInfo, slotId);
1449 break;
1450 default:
1451 break;
1452 }
1453 } else {
1454 CatLog.e(this, " Event does not exist in the EventList");
1455 }
1456 } else {
1457 CatLog.e(this, "SetupEventList is not received. Ignoring the event: " + event);
1458 }
1459 }
1460
1461 private void removeSetUpEvent(int event, int slotId) {
1462 CatLog.d(this, "Remove Event :" + event);
1463
1464 if (mStkContext[slotId].mSetupEventListSettings != null) {
1465 /*
1466 * Make new Eventlist without the event
1467 */
1468 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
1469 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
1470 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
1471 break;
1472 }
1473 }
1474 }
1475 }
1476
1477 private void launchEventMessage(int slotId) {
1478 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
1479 }
1480
Wink Savillee68857d2014-10-17 15:23:05 -07001481 private void launchEventMessage(int slotId, TextMessage msg) {
1482 if (msg == null || (msg.text != null && msg.text.length() == 0)) {
1483 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001484 return;
1485 }
Wink Savillee68857d2014-10-17 15:23:05 -07001486
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001487 Toast toast = new Toast(mContext.getApplicationContext());
1488 LayoutInflater inflate = (LayoutInflater) mContext
1489 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1490 View v = inflate.inflate(R.layout.stk_event_msg, null);
1491 TextView tv = (TextView) v
1492 .findViewById(com.android.internal.R.id.message);
1493 ImageView iv = (ImageView) v
1494 .findViewById(com.android.internal.R.id.icon);
1495 if (msg.icon != null) {
1496 iv.setImageBitmap(msg.icon);
1497 } else {
1498 iv.setVisibility(View.GONE);
1499 }
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301500 /* In case of 'self explanatory' stkapp should display the specified
1501 * icon in proactive command (but not the alpha string).
1502 * If icon is non-self explanatory and if the icon could not be displayed
1503 * then alpha string or text data should be displayed
1504 * Ref: ETSI 102.223,section 6.5.4
1505 */
1506 if (mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ||
1507 msg.icon == null || !msg.iconSelfExplanatory) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001508 tv.setText(msg.text);
1509 }
1510
1511 toast.setView(v);
1512 toast.setDuration(Toast.LENGTH_LONG);
1513 toast.setGravity(Gravity.BOTTOM, 0, 0);
1514 toast.show();
1515 }
1516
Wink Savillee68857d2014-10-17 15:23:05 -07001517 private void launchConfirmationDialog(TextMessage msg, int slotId) {
1518 msg.title = mStkContext[slotId].lastSelectedItem;
1519 Intent newIntent = new Intent();
1520 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1521 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1522 //Set unique URI to create a new instance of activity for different slotId.
1523 Uri uriData = Uri.parse(uriString);
1524
1525 if (newIntent != null) {
1526 newIntent.setClassName(this, targetActivity);
1527 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1528 | Intent.FLAG_ACTIVITY_NO_HISTORY
1529 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1530 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1531 newIntent.putExtra("TEXT", msg);
1532 newIntent.putExtra(SLOT_ID, slotId);
1533 newIntent.setData(uriData);
1534 startActivity(newIntent);
1535 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001536 }
1537
1538 private void launchBrowser(BrowserSettings settings) {
1539 if (settings == null) {
1540 return;
1541 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001542
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001543 Uri data = null;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001544 String url;
1545 if (settings.url == null) {
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001546 // if the command did not contain a URL,
1547 // launch the browser to the default homepage.
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001548 CatLog.d(this, "no url data provided by proactive command." +
1549 " launching browser with stk default URL ... ");
1550 url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP,
1551 "http://www.google.com");
1552 } else {
1553 CatLog.d(this, "launch browser command has attached url = " + settings.url);
1554 url = settings.url;
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001555 }
David Brown7c03cfe2011-10-20 15:36:12 -07001556
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001557 if (url.startsWith("http://") || url.startsWith("https://")) {
1558 data = Uri.parse(url);
1559 CatLog.d(this, "launching browser with url = " + url);
1560 } else {
1561 String modifiedUrl = "http://" + url;
1562 data = Uri.parse(modifiedUrl);
1563 CatLog.d(this, "launching browser with modified url = " + modifiedUrl);
1564 }
1565
1566 Intent intent = new Intent(Intent.ACTION_VIEW);
1567 intent.setData(data);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001568 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1569 switch (settings.mode) {
1570 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001571 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1572 break;
1573 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001574 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
1575 break;
1576 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
1577 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1578 break;
1579 }
1580 // start browser activity
1581 startActivity(intent);
1582 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07001583 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001584 // followed immediately.
1585 try {
Ryuto Sawada350aaa62016-06-13 14:47:22 +09001586 Thread.sleep(3000);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001587 } catch (InterruptedException e) {}
1588 }
1589
Wink Savillee68857d2014-10-17 15:23:05 -07001590 private void launchIdleText(int slotId) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001591 TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001592
Preeti Ahuja95919342013-10-01 18:18:55 -07001593 if (msg == null || msg.text ==null) {
1594 CatLog.d(LOG_TAG, msg == null ? "mCurrent.getTextMessage is NULL"
1595 : "mCurrent.getTextMessage.text is NULL");
Wink Savillee68857d2014-10-17 15:23:05 -07001596 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville046db4b2011-11-01 20:42:54 -07001597 return;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001598 } else {
Preeti Ahuja95919342013-10-01 18:18:55 -07001599 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
1600 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
1601 + "] icon[" + msg.icon + "], sim id: " + slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001602 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001603 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001604 new Intent(mContext, StkAppService.class), 0);
fionaxu805eb572017-05-02 10:57:30 -07001605 createAllChannels();
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001606 final Notification.Builder notificationBuilder = new Notification.Builder(
fionaxu2c91c752017-04-21 18:11:57 -07001607 StkAppService.this, STK_NOTIFICATION_CHANNEL_ID);
Wink Savillee68857d2014-10-17 15:23:05 -07001608 if (mStkContext[slotId].mMainCmd != null &&
1609 mStkContext[slotId].mMainCmd.getMenu() != null) {
1610 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001611 } else {
1612 notificationBuilder.setContentTitle("");
1613 }
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001614 notificationBuilder
1615 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1616 notificationBuilder.setContentIntent(pendingIntent);
1617 notificationBuilder.setOngoing(true);
1618 // Set text and icon for the status bar and notification body.
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301619 if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() ||
1620 !msg.iconSelfExplanatory) {
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001621 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001622 notificationBuilder.setTicker(msg.text);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001623 }
1624 if (msg.icon != null) {
1625 notificationBuilder.setLargeIcon(msg.icon);
1626 } else {
1627 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
1628 .getResources().getSystem(),
1629 com.android.internal.R.drawable.stat_notify_sim_toolkit);
1630 notificationBuilder.setLargeIcon(bitmapIcon);
1631 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02001632 notificationBuilder.setColor(mContext.getResources().getColor(
1633 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07001634 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001635 }
1636 }
1637
fionaxu805eb572017-05-02 10:57:30 -07001638 /** Creates the notification channel and registers it with NotificationManager.
1639 * If a channel with the same ID is already registered, NotificationManager will
1640 * ignore this call.
1641 */
1642 private void createAllChannels() {
1643 mNotificationManager.createNotificationChannel(new NotificationChannel(
1644 STK_NOTIFICATION_CHANNEL_ID,
1645 getResources().getString(R.string.stk_channel_name),
1646 NotificationManager.IMPORTANCE_MIN));
1647 }
1648
Wink Savillee68857d2014-10-17 15:23:05 -07001649 private void launchToneDialog(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001650 Intent newIntent = new Intent(this, ToneDialog.class);
Wink Savillee68857d2014-10-17 15:23:05 -07001651 String uriString = STK_TONE_URI + slotId;
1652 Uri uriData = Uri.parse(uriString);
1653 //Set unique URI to create a new instance of activity for different slotId.
1654 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001655 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1656 | Intent.FLAG_ACTIVITY_NO_HISTORY
1657 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Wink Savillee68857d2014-10-17 15:23:05 -07001658 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1659 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1660 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
1661 newIntent.putExtra(SLOT_ID, slotId);
1662 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001663 startActivity(newIntent);
1664 }
1665
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301666 private void handlePlayTone(int slotId) {
1667 TextMessage toneMsg = mStkContext[slotId].mCurrentCmd.geTextMessage();
1668
1669 boolean showUser = true;
1670 boolean displayDialog = true;
1671 Resources resource = Resources.getSystem();
1672 try {
1673 displayDialog = !resource.getBoolean(
1674 com.android.internal.R.bool.config_stkNoAlphaUsrCnf);
1675 } catch (NotFoundException e) {
1676 displayDialog = true;
1677 }
1678
1679 // As per the spec 3GPP TS 11.14, 6.4.5. Play Tone.
1680 // If there is no alpha identifier tlv present, UE may show the
1681 // user information. 'config_stkNoAlphaUsrCnf' value will decide
1682 // whether to show it or not.
1683 // If alpha identifier tlv is present and its data is null, play only tone
1684 // without showing user any information.
1685 // Alpha Id is Present, but the text data is null.
1686 if ((toneMsg.text != null ) && (toneMsg.text.equals(""))) {
1687 CatLog.d(this, "Alpha identifier data is null, play only tone");
1688 showUser = false;
1689 }
1690 // Alpha Id is not present AND we need to show info to the user.
1691 if (toneMsg.text == null && displayDialog) {
1692 CatLog.d(this, "toneMsg.text " + toneMsg.text
1693 + " Starting ToneDialog activity with default message.");
1694 toneMsg.text = getResources().getString(R.string.default_tone_dialog_msg);
1695 showUser = true;
1696 }
1697 // Dont show user info, if config setting is true.
1698 if (toneMsg.text == null && !displayDialog) {
1699 CatLog.d(this, "config value stkNoAlphaUsrCnf is true");
1700 showUser = false;
1701 }
1702
1703 CatLog.d(this, "toneMsg.text: " + toneMsg.text + "showUser: " +showUser +
1704 "displayDialog: " +displayDialog);
1705 playTone(showUser, slotId);
1706 }
1707
1708 private void playTone(boolean showUserInfo, int slotId) {
1709 // Start playing tone and vibration
1710 ToneSettings settings = mStkContext[slotId].mCurrentCmd.getToneSettings();
1711 if (null == settings) {
1712 CatLog.d(this, "null settings, not playing tone.");
1713 return;
1714 }
1715
1716 mVibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
1717 mTonePlayer = new TonePlayer();
1718 mTonePlayer.play(settings.tone);
1719 int timeout = StkApp.calculateDurationInMilis(settings.duration);
1720 if (timeout == 0) {
1721 timeout = StkApp.TONE_DEFAULT_TIMEOUT;
1722 }
1723
1724 Message msg = mServiceHandler.obtainMessage();
1725 msg.arg1 = OP_STOP_TONE;
1726 msg.arg2 = slotId;
1727 msg.obj = (Integer)(showUserInfo ? 1 : 0);
1728 msg.what = STOP_TONE_WHAT;
1729 mServiceHandler.sendMessageDelayed(msg, timeout);
1730 if (settings.vibrate) {
1731 mVibrator.vibrate(timeout);
1732 }
1733
1734 // Start Tone dialog Activity to show user the information.
1735 if (showUserInfo) {
1736 Intent newIntent = new Intent(sInstance, ToneDialog.class);
1737 String uriString = STK_TONE_URI + slotId;
1738 Uri uriData = Uri.parse(uriString);
1739 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1740 | Intent.FLAG_ACTIVITY_NO_HISTORY
1741 | Intent.FLAG_ACTIVITY_SINGLE_TOP
1742 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1743 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1744 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1745 newIntent.putExtra(SLOT_ID, slotId);
1746 newIntent.setData(uriData);
1747 startActivity(newIntent);
1748 }
1749 }
1750
1751 private void finishToneDialogActivity() {
1752 Intent finishIntent = new Intent(FINISH_TONE_ACTIVITY_ACTION);
1753 sendBroadcast(finishIntent);
1754 }
1755
1756 private void handleStopTone(Message msg, int slotId) {
1757 int resId = 0;
1758
1759 // Stop the play tone in following cases:
1760 // 1.OP_STOP_TONE: play tone timer expires.
1761 // 2.STOP_TONE_USER: user pressed the back key.
1762 if (msg.arg1 == OP_STOP_TONE) {
1763 resId = RES_ID_DONE;
1764 // Dismiss Tone dialog, after finishing off playing the tone.
1765 int finishActivity = (Integer) msg.obj;
1766 if (finishActivity == 1) finishToneDialogActivity();
1767 } else if (msg.arg1 == OP_STOP_TONE_USER) {
1768 resId = RES_ID_END_SESSION;
1769 }
1770
1771 sendResponse(resId, slotId, true);
1772 mServiceHandler.removeMessages(STOP_TONE_WHAT);
1773 if (mTonePlayer != null) {
1774 mTonePlayer.stop();
1775 mTonePlayer.release();
1776 mTonePlayer = null;
1777 }
1778 if (mVibrator != null) {
1779 mVibrator.cancel();
1780 mVibrator = null;
1781 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001782 }
1783
Takanori Nakano49b12722016-02-16 14:34:14 +09001784 private void launchOpenChannelDialog(final int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -07001785 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001786 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001787 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001788 return;
1789 }
1790
1791 msg.title = getResources().getString(R.string.stk_dialog_title);
1792 if (msg.text == null) {
1793 msg.text = getResources().getString(R.string.default_open_channel_msg);
1794 }
1795
1796 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1797 .setIconAttribute(android.R.attr.alertDialogIcon)
1798 .setTitle(msg.title)
1799 .setMessage(msg.text)
1800 .setCancelable(false)
1801 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
1802 new DialogInterface.OnClickListener() {
1803 public void onClick(DialogInterface dialog, int which) {
1804 Bundle args = new Bundle();
1805 args.putInt(RES_ID, RES_ID_CHOICE);
1806 args.putInt(CHOICE, YES);
1807 Message message = mServiceHandler.obtainMessage();
1808 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09001809 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001810 message.obj = args;
1811 mServiceHandler.sendMessage(message);
1812 }
1813 })
1814 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
1815 new DialogInterface.OnClickListener() {
1816 public void onClick(DialogInterface dialog, int which) {
1817 Bundle args = new Bundle();
1818 args.putInt(RES_ID, RES_ID_CHOICE);
1819 args.putInt(CHOICE, NO);
1820 Message message = mServiceHandler.obtainMessage();
1821 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09001822 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001823 message.obj = args;
1824 mServiceHandler.sendMessage(message);
1825 }
1826 })
1827 .create();
1828
1829 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1830 if (!mContext.getResources().getBoolean(
1831 com.android.internal.R.bool.config_sf_slowBlur)) {
1832 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1833 }
1834
1835 dialog.show();
1836 }
1837
Wink Savillee68857d2014-10-17 15:23:05 -07001838 private void launchTransientEventMessage(int slotId) {
1839 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001840 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001841 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001842 return;
1843 }
1844
1845 msg.title = getResources().getString(R.string.stk_dialog_title);
1846
1847 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1848 .setIconAttribute(android.R.attr.alertDialogIcon)
1849 .setTitle(msg.title)
1850 .setMessage(msg.text)
1851 .setCancelable(false)
1852 .setPositiveButton(getResources().getString(android.R.string.ok),
1853 new DialogInterface.OnClickListener() {
1854 public void onClick(DialogInterface dialog, int which) {
1855 }
1856 })
1857 .create();
1858
1859 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1860 if (!mContext.getResources().getBoolean(
1861 com.android.internal.R.bool.config_sf_slowBlur)) {
1862 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1863 }
1864
1865 dialog.show();
1866 }
1867
Wink Savillee68857d2014-10-17 15:23:05 -07001868 private int getNotificationId(int slotId) {
1869 int notifyId = STK_NOTIFICATION_ID;
1870 if (slotId >= 0 && slotId < mSimCount) {
1871 notifyId += slotId;
1872 } else {
1873 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1874 }
1875 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
1876 return notifyId;
1877 }
1878
1879 private String getItemName(int itemId, int slotId) {
1880 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001881 if (menu == null) {
1882 return null;
1883 }
1884 for (Item item : menu.items) {
1885 if (item.id == itemId) {
1886 return item.text;
1887 }
1888 }
1889 return null;
1890 }
1891
Wink Savillee68857d2014-10-17 15:23:05 -07001892 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001893 try {
Wink Savillee68857d2014-10-17 15:23:05 -07001894 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
1895 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
1896 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001897 return true;
1898 }
1899 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07001900 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
1901 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001902 return true;
1903 }
Wink Savillee68857d2014-10-17 15:23:05 -07001904 mStkContext[slotId].mSetupMenuState = STATE_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001905 return false;
1906 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301907
Wink Savillee68857d2014-10-17 15:23:05 -07001908 StkContext getStkContext(int slotId) {
1909 if (slotId >= 0 && slotId < mSimCount) {
1910 return mStkContext[slotId];
1911 } else {
1912 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1913 return null;
1914 }
1915 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301916
1917 private void handleAlphaNotify(Bundle args) {
1918 String alphaString = args.getString(AppInterface.ALPHA_STRING);
1919
1920 CatLog.d(this, "Alpha string received from card: " + alphaString);
1921 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
1922 toast.setGravity(Gravity.TOP, 0, 0);
1923 toast.show();
1924 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001925}