blob: a85402cfee3e3f658979253b9749584798abd173 [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;
Yuta Uife965802017-11-07 20:12:37 +090022import android.app.KeyguardManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080023import android.app.Notification;
fionaxu2c91c752017-04-21 18:11:57 -070024import android.app.NotificationChannel;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080025import android.app.NotificationManager;
26import android.app.PendingIntent;
27import android.app.Service;
Wink Savillee68857d2014-10-17 15:23:05 -070028import android.app.Activity;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +090029import android.app.ActivityManagerNative;
30import android.app.IProcessObserver;
Yuta Uife965802017-11-07 20:12:37 +090031import android.content.BroadcastReceiver;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080032import android.content.Context;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050033import android.content.DialogInterface;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080034import android.content.Intent;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +090035import android.content.pm.PackageManager;
36import android.content.pm.ResolveInfo;
Preeti Ahuja95919342013-10-01 18:18:55 -070037import android.content.res.Configuration;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053038import android.content.res.Resources;
39import android.content.res.Resources.NotFoundException;
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +010040import android.graphics.Bitmap;
41import android.graphics.BitmapFactory;
Yuta Uife965802017-11-07 20:12:37 +090042import android.media.RingtoneManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080043import android.net.Uri;
44import android.os.Bundle;
45import android.os.Handler;
46import android.os.IBinder;
47import android.os.Looper;
48import android.os.Message;
Takanori Nakanoc8054ba2016-08-15 19:18:16 +090049import android.os.Parcel;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070050import android.os.PersistableBundle;
Preeti Ahuja560be362014-11-25 19:38:24 -080051import android.os.PowerManager;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +090052import android.os.RemoteException;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070053import android.os.SystemProperties;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053054import android.os.Vibrator;
Preeti Ahuja95919342013-10-01 18:18:55 -070055import android.provider.Settings;
Takanori Nakano3776e2c2016-10-14 16:54:28 +090056import android.support.v4.content.LocalBroadcastManager;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070057import android.telephony.CarrierConfigManager;
Wink Saville56469d52009-04-02 01:37:03 -070058import android.telephony.TelephonyManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070059import android.text.TextUtils;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080060import android.view.Gravity;
61import android.view.LayoutInflater;
62import android.view.View;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050063import android.view.WindowManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080064import android.widget.ImageView;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080065import android.widget.TextView;
66import android.widget.Toast;
Wink Savillee68857d2014-10-17 15:23:05 -070067import android.content.IntentFilter;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080068
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070069import com.android.internal.telephony.cat.AppInterface;
Yuta Uife965802017-11-07 20:12:37 +090070import com.android.internal.telephony.cat.Input;
Preeti Ahuja95919342013-10-01 18:18:55 -070071import com.android.internal.telephony.cat.LaunchBrowserMode;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070072import com.android.internal.telephony.cat.Menu;
73import com.android.internal.telephony.cat.Item;
74import com.android.internal.telephony.cat.ResultCode;
75import com.android.internal.telephony.cat.CatCmdMessage;
76import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
Preeti Ahuja95919342013-10-01 18:18:55 -070077import com.android.internal.telephony.cat.CatCmdMessage.SetupEventListSettings;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070078import com.android.internal.telephony.cat.CatLog;
79import com.android.internal.telephony.cat.CatResponseMessage;
80import com.android.internal.telephony.cat.TextMessage;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053081import com.android.internal.telephony.cat.ToneSettings;
Wink Saville94e982b2014-07-11 07:38:14 -070082import com.android.internal.telephony.uicc.IccRefreshResponse;
Wink Savillee68857d2014-10-17 15:23:05 -070083import com.android.internal.telephony.PhoneConstants;
Preeti Ahuja95919342013-10-01 18:18:55 -070084import com.android.internal.telephony.GsmAlphabet;
Legler Wuaeefef52014-10-27 00:57:18 +080085import com.android.internal.telephony.cat.CatService;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080086
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070087import java.util.Iterator;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080088import java.util.LinkedList;
Wink Savillee68857d2014-10-17 15:23:05 -070089import java.lang.System;
90import java.util.List;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080091
Preeti Ahuja95919342013-10-01 18:18:55 -070092import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja560be362014-11-25 19:38:24 -080093 SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
94import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja95919342013-10-01 18:18:55 -070095 SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
96
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080097/**
98 * SIM toolkit application level service. Interacts with Telephopny messages,
99 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -0700100 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800101 */
102public class StkAppService extends Service implements Runnable {
103
104 // members
Wink Savillee68857d2014-10-17 15:23:05 -0700105 protected class StkContext {
106 protected CatCmdMessage mMainCmd = null;
107 protected CatCmdMessage mCurrentCmd = null;
108 protected CatCmdMessage mCurrentMenuCmd = null;
109 protected Menu mCurrentMenu = null;
110 protected String lastSelectedItem = null;
111 protected boolean mMenuIsVisible = false;
112 protected boolean mIsInputPending = false;
113 protected boolean mIsMenuPending = false;
114 protected boolean mIsDialogPending = false;
Yuta Uife965802017-11-07 20:12:37 +0900115 protected boolean mNotificationOnKeyguard = false;
116 protected boolean mNoResponseFromUser = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700117 protected boolean launchBrowser = false;
118 protected BrowserSettings mBrowserSettings = null;
119 protected LinkedList<DelayedCmd> mCmdsQ = null;
120 protected boolean mCmdInProgress = false;
121 protected int mStkServiceState = STATE_UNKNOWN;
122 protected int mSetupMenuState = STATE_UNKNOWN;
123 protected int mMenuState = StkMenuActivity.STATE_INIT;
124 protected int mOpCode = -1;
125 private Activity mActivityInstance = null;
126 private Activity mDialogInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700127 private int mSlotId = 0;
Preeti Ahuja95919342013-10-01 18:18:55 -0700128 private SetupEventListSettings mSetupEventListSettings = null;
129 private boolean mClearSelectItem = false;
130 private boolean mDisplayTextDlgIsVisibile = false;
131 private CatCmdMessage mCurrentSetupEventCmd = null;
Preeti Ahuja560be362014-11-25 19:38:24 -0800132 private CatCmdMessage mIdleModeTextCmd = null;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900133 private boolean mIdleModeTextVisible = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700134 final synchronized void setPendingActivityInstance(Activity act) {
135 CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act);
136 callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
137 }
138 final synchronized Activity getPendingActivityInstance() {
139 CatLog.d(this, "getPendingActivityInstance act : " + mSlotId + ", " +
140 mActivityInstance);
141 return mActivityInstance;
142 }
143 final synchronized void setPendingDialogInstance(Activity act) {
144 CatLog.d(this, "setPendingDialogInstance act : " + mSlotId + ", " + act);
145 callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act);
146 }
147 final synchronized Activity getPendingDialogInstance() {
148 CatLog.d(this, "getPendingDialogInstance act : " + mSlotId + ", " +
149 mDialogInstance);
150 return mDialogInstance;
151 }
Wink Savillee68857d2014-10-17 15:23:05 -0700152 }
153
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800154 private volatile Looper mServiceLooper;
155 private volatile ServiceHandler mServiceHandler;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800156 private Context mContext = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800157 private NotificationManager mNotificationManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800158 static StkAppService sInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700159 private AppInterface[] mStkService = null;
160 private StkContext[] mStkContext = null;
161 private int mSimCount = 0;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900162 private IProcessObserver.Stub mProcessObserver = null;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530163 private TonePlayer mTonePlayer = null;
164 private Vibrator mVibrator = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700165
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800166 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
167 // creating an intent.
168 private enum InitiatedByUserAction {
169 yes, // The action was started via a user initiated action
170 unknown, // Not known for sure if user initated the action
171 }
172
173 // constants
174 static final String OPCODE = "op";
175 static final String CMD_MSG = "cmd message";
176 static final String RES_ID = "response id";
177 static final String MENU_SELECTION = "menu selection";
178 static final String INPUT = "input";
179 static final String HELP = "help";
180 static final String CONFIRMATION = "confirm";
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500181 static final String CHOICE = "choice";
Wink Savillee68857d2014-10-17 15:23:05 -0700182 static final String SLOT_ID = "SLOT_ID";
183 static final String STK_CMD = "STK CMD";
184 static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/";
185 static final String STK_MENU_URI = "stk://com.android.stk/menu/";
186 static final String STK_INPUT_URI = "stk://com.android.stk/input/";
187 static final String STK_TONE_URI = "stk://com.android.stk/tone/";
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530188 static final String FINISH_TONE_ACTIVITY_ACTION =
189 "android.intent.action.stk.finish_activity";
Preeti Ahuja95919342013-10-01 18:18:55 -0700190
191 // These below constants are used for SETUP_EVENT_LIST
192 static final String SETUP_EVENT_TYPE = "event";
193 static final String SETUP_EVENT_CAUSE = "cause";
194
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800195 // operations ids for different service functionality.
196 static final int OP_CMD = 1;
197 static final int OP_RESPONSE = 2;
198 static final int OP_LAUNCH_APP = 3;
199 static final int OP_END_SESSION = 4;
200 static final int OP_BOOT_COMPLETED = 5;
201 private static final int OP_DELAYED_MSG = 6;
Wink Saville94e982b2014-07-11 07:38:14 -0700202 static final int OP_CARD_STATUS_CHANGED = 7;
Wink Savillee68857d2014-10-17 15:23:05 -0700203 static final int OP_SET_ACT_INST = 8;
204 static final int OP_SET_DAL_INST = 9;
Ryuto Sawada08c821c2016-08-08 18:29:02 +0900205 static final int OP_LOCALE_CHANGED = 10;
206 static final int OP_ALPHA_NOTIFY = 11;
207 static final int OP_IDLE_SCREEN = 12;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800208
Preeti Ahuja95919342013-10-01 18:18:55 -0700209 //Invalid SetupEvent
210 static final int INVALID_SETUP_EVENT = 0xFF;
211
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530212 // Message id to signal stop tone due to play tone timeout.
213 private static final int OP_STOP_TONE = 16;
214
215 // Message id to signal stop tone on user keyback.
216 static final int OP_STOP_TONE_USER = 17;
217
218 // Message id to remove stop tone message from queue.
219 private static final int STOP_TONE_WHAT = 100;
220
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800221 // Response ids
222 static final int RES_ID_MENU_SELECTION = 11;
223 static final int RES_ID_INPUT = 12;
224 static final int RES_ID_CONFIRM = 13;
225 static final int RES_ID_DONE = 14;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500226 static final int RES_ID_CHOICE = 15;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800227
228 static final int RES_ID_TIMEOUT = 20;
229 static final int RES_ID_BACKWARD = 21;
230 static final int RES_ID_END_SESSION = 22;
231 static final int RES_ID_EXIT = 23;
Srikanth Chintalaba103002015-11-30 10:49:52 -0800232 static final int RES_ID_ERROR = 24;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800233
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500234 static final int YES = 1;
235 static final int NO = 0;
236
Wink Savillee68857d2014-10-17 15:23:05 -0700237 static final int STATE_UNKNOWN = -1;
238 static final int STATE_NOT_EXIST = 0;
239 static final int STATE_EXIST = 1;
Wink Saville79085fc2009-06-09 10:27:23 -0700240
Wink Savillee68857d2014-10-17 15:23:05 -0700241 private static final String PACKAGE_NAME = "com.android.stk";
242 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
243 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
244 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800245 // Notification id used to display Idle Mode text in NotificationManager.
246 private static final int STK_NOTIFICATION_ID = 333;
fionaxu2c91c752017-04-21 18:11:57 -0700247 // Notification channel containing all mobile service messages notifications.
248 private static final String STK_NOTIFICATION_CHANNEL_ID = "mobileServiceMessages";
249
Wink Savillee68857d2014-10-17 15:23:05 -0700250 private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
Wink Saville79085fc2009-06-09 10:27:23 -0700251
Takanori Nakano3776e2c2016-10-14 16:54:28 +0900252 static final String SESSION_ENDED = "session_ended";
253
Wink Saville79085fc2009-06-09 10:27:23 -0700254 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800255 // session end) while the service is busy processing a previous message.
256 private class DelayedCmd {
257 // members
258 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700259 CatCmdMessage msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700260 int slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800261
Wink Savillee68857d2014-10-17 15:23:05 -0700262 DelayedCmd(int id, CatCmdMessage msg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800263 this.id = id;
264 this.msg = msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700265 this.slotId = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800266 }
267 }
268
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700269 // system property to set the STK specific default url for launch browser proactive cmds
270 private static final String STK_BROWSER_DEFAULT_URL_SYSPROP = "persist.radio.stk.default_url";
271
Yuta Uife965802017-11-07 20:12:37 +0900272 private static final int NOTIFICATION_ON_KEYGUARD = 1;
273 private static final long[] VIBRATION_PATTERN = new long[] { 0, 350, 250, 350 };
274 private BroadcastReceiver mUserPresentReceiver = null;
275
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800276 @Override
277 public void onCreate() {
Wink Savillee68857d2014-10-17 15:23:05 -0700278 CatLog.d(LOG_TAG, "onCreate()+");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800279 // Initialize members
Wink Savillee68857d2014-10-17 15:23:05 -0700280 int i = 0;
281 mContext = getBaseContext();
282 mSimCount = TelephonyManager.from(mContext).getSimCount();
283 CatLog.d(LOG_TAG, "simCount: " + mSimCount);
284 mStkService = new AppInterface[mSimCount];
285 mStkContext = new StkContext[mSimCount];
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900286
Wink Savillee68857d2014-10-17 15:23:05 -0700287 for (i = 0; i < mSimCount; i++) {
288 CatLog.d(LOG_TAG, "slotId: " + i);
Legler Wuaeefef52014-10-27 00:57:18 +0800289 mStkService[i] = CatService.getInstance(i);
Wink Savillee68857d2014-10-17 15:23:05 -0700290 mStkContext[i] = new StkContext();
291 mStkContext[i].mSlotId = i;
292 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
293 }
294
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800295 Thread serviceThread = new Thread(null, this, "Stk App Service");
296 serviceThread.start();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800297 mNotificationManager = (NotificationManager) mContext
298 .getSystemService(Context.NOTIFICATION_SERVICE);
299 sInstance = this;
300 }
301
302 @Override
303 public void onStart(Intent intent, int startId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700304 if (intent == null) {
305 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530306 return;
307 }
308
Wink Savillee68857d2014-10-17 15:23:05 -0700309 Bundle args = intent.getExtras();
310 if (args == null) {
311 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
312 return;
313 }
314
315 int op = args.getInt(OPCODE);
316 int slotId = 0;
317 int i = 0;
318 if (op != OP_BOOT_COMPLETED) {
319 slotId = args.getInt(SLOT_ID);
320 }
Cuihtlauac ALVARADObde7f032015-05-29 16:25:12 +0200321 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", *****");
Wink Savillee68857d2014-10-17 15:23:05 -0700322 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +0800323 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -0700324 if (mStkService[slotId] == null) {
325 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
326 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
327 //Check other StkService state.
328 //If all StkServices are not available, stop itself and uninstall apk.
329 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
330 if (i != slotId
Tsukasa Goto029332b2016-10-05 17:12:06 +0900331 && (mStkService[i] != null)
Wink Savillee68857d2014-10-17 15:23:05 -0700332 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
333 || mStkContext[i].mStkServiceState == STATE_EXIST)) {
334 break;
335 }
336 }
337 } else {
338 mStkContext[slotId].mStkServiceState = STATE_EXIST;
339 }
340 if (i == mSimCount) {
341 stopSelf();
342 StkAppInstaller.unInstall(mContext);
343 return;
344 }
345 }
346
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530347 waitForLooper();
John Wang62acae42009-10-08 11:20:23 -0700348
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800349 Message msg = mServiceHandler.obtainMessage();
Wink Savillee68857d2014-10-17 15:23:05 -0700350 msg.arg1 = op;
351 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800352 switch(msg.arg1) {
353 case OP_CMD:
354 msg.obj = args.getParcelable(CMD_MSG);
355 break;
356 case OP_RESPONSE:
Wink Saville94e982b2014-07-11 07:38:14 -0700357 case OP_CARD_STATUS_CHANGED:
Preeti Ahuja95919342013-10-01 18:18:55 -0700358 case OP_LOCALE_CHANGED:
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530359 case OP_ALPHA_NOTIFY:
Preeti Ahuja560be362014-11-25 19:38:24 -0800360 case OP_IDLE_SCREEN:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800361 msg.obj = args;
362 /* falls through */
363 case OP_LAUNCH_APP:
364 case OP_END_SESSION:
365 case OP_BOOT_COMPLETED:
366 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530367 case OP_STOP_TONE_USER:
368 msg.obj = args;
369 msg.what = STOP_TONE_WHAT;
370 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800371 default:
372 return;
373 }
374 mServiceHandler.sendMessage(msg);
375 }
376
377 @Override
378 public void onDestroy() {
Wink Savillee68857d2014-10-17 15:23:05 -0700379 CatLog.d(LOG_TAG, "onDestroy()");
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900380 unregisterProcessObserver();
Tsukasa Gotou54afbdd2016-01-07 16:30:20 +0900381 sInstance = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800382 waitForLooper();
383 mServiceLooper.quit();
384 }
385
386 @Override
387 public IBinder onBind(Intent intent) {
388 return null;
389 }
390
391 public void run() {
392 Looper.prepare();
393
394 mServiceLooper = Looper.myLooper();
395 mServiceHandler = new ServiceHandler();
396
397 Looper.loop();
398 }
399
400 /*
401 * Package api used by StkMenuActivity to indicate if its on the foreground.
402 */
Wink Savillee68857d2014-10-17 15:23:05 -0700403 void indicateMenuVisibility(boolean visibility, int slotId) {
404 if (slotId >= 0 && slotId < mSimCount) {
405 mStkContext[slotId].mMenuIsVisible = visibility;
406 }
407 }
408
Preeti Ahuja95919342013-10-01 18:18:55 -0700409 /*
410 * Package api used by StkDialogActivity to indicate if its on the foreground.
411 */
412 void setDisplayTextDlgVisibility(boolean visibility, int slotId) {
413 if (slotId >= 0 && slotId < mSimCount) {
414 mStkContext[slotId].mDisplayTextDlgIsVisibile = visibility;
415 }
416 }
417
Wink Savillee68857d2014-10-17 15:23:05 -0700418 boolean isInputPending(int slotId) {
419 if (slotId >= 0 && slotId < mSimCount) {
420 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
421 return mStkContext[slotId].mIsInputPending;
422 }
423 return false;
424 }
425
426 boolean isMenuPending(int slotId) {
427 if (slotId >= 0 && slotId < mSimCount) {
428 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
429 return mStkContext[slotId].mIsMenuPending;
430 }
431 return false;
432 }
433
434 boolean isDialogPending(int slotId) {
435 if (slotId >= 0 && slotId < mSimCount) {
436 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
437 return mStkContext[slotId].mIsDialogPending;
438 }
439 return false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800440 }
441
Takanori Nakano3776e2c2016-10-14 16:54:28 +0900442 boolean isMainMenuAvailable(int slotId) {
443 if (slotId >= 0 && slotId < mSimCount) {
444 // The main menu can handle the next user operation if the previous session finished.
445 return (mStkContext[slotId].lastSelectedItem == null) ? true : false;
446 }
447 return false;
448 }
449
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800450 /*
451 * Package api used by StkMenuActivity to get its Menu parameter.
452 */
Wink Savillee68857d2014-10-17 15:23:05 -0700453 Menu getMenu(int slotId) {
454 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
455 if (slotId >=0 && slotId < mSimCount) {
456 return mStkContext[slotId].mCurrentMenu;
457 } else {
458 return null;
459 }
460 }
461
462 /*
463 * Package api used by StkMenuActivity to get its Main Menu parameter.
464 */
465 Menu getMainMenu(int slotId) {
466 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
w30234a08cffe2015-02-04 15:13:25 -0800467 if (slotId >=0 && slotId < mSimCount && (mStkContext[slotId].mMainCmd != null)) {
Takanori Nakanoc8054ba2016-08-15 19:18:16 +0900468 Menu menu = mStkContext[slotId].mMainCmd.getMenu();
469 if (menu != null && mSimCount > PhoneConstants.MAX_PHONE_COUNT_SINGLE_SIM) {
470 // If alpha identifier or icon identifier with the self-explanatory qualifier is
471 // specified in SET-UP MENU command, it should be more prioritized than preset ones.
472 if (menu.title == null
473 && (menu.titleIcon == null || !menu.titleIconSelfExplanatory)) {
474 StkMenuConfig config = StkMenuConfig.getInstance(getApplicationContext());
475 String label = config.getLabel(slotId);
476 Bitmap icon = config.getIcon(slotId);
477 if (label != null || icon != null) {
478 Parcel parcel = Parcel.obtain();
479 menu.writeToParcel(parcel, 0);
480 parcel.setDataPosition(0);
481 menu = Menu.CREATOR.createFromParcel(parcel);
482 parcel.recycle();
483 menu.title = label;
484 menu.titleIcon = icon;
485 menu.titleIconSelfExplanatory = false;
486 }
487 }
488 }
489 return menu;
Wink Savillee68857d2014-10-17 15:23:05 -0700490 } else {
491 return null;
492 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800493 }
494
495 /*
496 * Package api used by UI Activities and Dialogs to communicate directly
497 * with the service to deliver state information and parameters.
498 */
499 static StkAppService getInstance() {
500 return sInstance;
501 }
502
503 private void waitForLooper() {
504 while (mServiceHandler == null) {
505 synchronized (this) {
506 try {
507 wait(100);
508 } catch (InterruptedException e) {
509 }
510 }
511 }
512 }
513
514 private final class ServiceHandler extends Handler {
515 @Override
516 public void handleMessage(Message msg) {
Wink Savillee68857d2014-10-17 15:23:05 -0700517 if(null == msg) {
518 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
519 return;
520 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800521 int opcode = msg.arg1;
Wink Savillee68857d2014-10-17 15:23:05 -0700522 int slotId = msg.arg2;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800523
Wink Savillee68857d2014-10-17 15:23:05 -0700524 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
525 if (opcode == OP_CMD && msg.obj != null &&
526 ((CatCmdMessage)msg.obj).getCmdType()!= null) {
527 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
528 }
529 mStkContext[slotId].mOpCode = opcode;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800530 switch (opcode) {
531 case OP_LAUNCH_APP:
Wink Savillee68857d2014-10-17 15:23:05 -0700532 if (mStkContext[slotId].mMainCmd == null) {
533 CatLog.d(LOG_TAG, "mMainCmd is null");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800534 // nothing todo when no SET UP MENU command didn't arrive.
535 return;
536 }
Wink Savillee68857d2014-10-17 15:23:05 -0700537 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
538 mStkContext[slotId].mCmdInProgress + "]");
539
540 //If there is a pending activity for the slot id,
541 //just finish it and create a new one to handle the pending command.
542 cleanUpInstanceStackBySlot(slotId);
543
Wink Savillee68857d2014-10-17 15:23:05 -0700544 CatLog.d(LOG_TAG, "Current cmd type: " +
545 mStkContext[slotId].mCurrentCmd.getCmdType());
546 //Restore the last command from stack by slot id.
547 restoreInstanceFromStackBySlot(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800548 break;
549 case OP_CMD:
Wink Savillee68857d2014-10-17 15:23:05 -0700550 CatLog.d(LOG_TAG, "[OP_CMD]");
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700551 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800552 // There are two types of commands:
553 // 1. Interactive - user's response is required.
554 // 2. Informative - display a message, no interaction with the user.
555 //
Wink Saville79085fc2009-06-09 10:27:23 -0700556 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800557 // Interactive commands can't override each other. So if a command
558 // is already in progress, we need to queue the next command until
559 // the user has responded or a timeout expired.
560 if (!isCmdInteractive(cmdMsg)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700561 handleCmd(cmdMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800562 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700563 if (!mStkContext[slotId].mCmdInProgress) {
564 mStkContext[slotId].mCmdInProgress = true;
565 handleCmd((CatCmdMessage) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800566 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700567 CatLog.d(LOG_TAG, "[Interactive][in progress]");
568 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
569 (CatCmdMessage) msg.obj, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800570 }
571 }
572 break;
573 case OP_RESPONSE:
Preeti Ahuja414bc412013-06-25 19:31:49 -0700574 handleCmdResponse((Bundle) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800575 // call delayed commands if needed.
Wink Savillee68857d2014-10-17 15:23:05 -0700576 if (mStkContext[slotId].mCmdsQ.size() != 0) {
577 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800578 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700579 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800580 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800581 break;
582 case OP_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700583 if (!mStkContext[slotId].mCmdInProgress) {
584 mStkContext[slotId].mCmdInProgress = true;
585 handleSessionEnd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800586 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700587 mStkContext[slotId].mCmdsQ.addLast(
588 new DelayedCmd(OP_END_SESSION, null, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800589 }
590 break;
591 case OP_BOOT_COMPLETED:
Wink Savillee68857d2014-10-17 15:23:05 -0700592 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
593 int i = 0;
594 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
595 if (mStkContext[i].mMainCmd != null) {
596 break;
597 }
598 }
599 if (i == mSimCount) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800600 StkAppInstaller.unInstall(mContext);
601 }
602 break;
603 case OP_DELAYED_MSG:
Wink Savillee68857d2014-10-17 15:23:05 -0700604 handleDelayedCmd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800605 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700606 case OP_CARD_STATUS_CHANGED:
Wink Savillee68857d2014-10-17 15:23:05 -0700607 CatLog.d(LOG_TAG, "Card/Icc Status change received");
608 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
609 break;
610 case OP_SET_ACT_INST:
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900611 Activity act = (Activity) msg.obj;
612 if (mStkContext[slotId].mActivityInstance != act) {
613 CatLog.d(LOG_TAG, "Set activity instance - " + act);
614 Activity previous = mStkContext[slotId].mActivityInstance;
615 mStkContext[slotId].mActivityInstance = act;
616 // Finish the previous one if it has not been finished yet somehow.
617 if (previous != null && !previous.isDestroyed() && !previous.isFinishing()) {
618 CatLog.d(LOG_TAG, "Finish the previous pending activity - " + previous);
619 previous.finish();
620 }
621 }
Wink Savillee68857d2014-10-17 15:23:05 -0700622 break;
623 case OP_SET_DAL_INST:
624 Activity dal = new Activity();
625 CatLog.d(LOG_TAG, "Set dialog instance. " + dal);
626 dal = (Activity) msg.obj;
627 mStkContext[slotId].mDialogInstance = dal;
628 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700629 case OP_LOCALE_CHANGED:
630 CatLog.d(this, "Locale Changed");
Yuta Ui1481b172016-02-03 15:34:31 +0900631 for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
632 checkForSetupEvent(LANGUAGE_SELECTION_EVENT, (Bundle) msg.obj, slot);
633 }
fionaxu805eb572017-05-02 10:57:30 -0700634 // rename all registered notification channels on locale change
635 createAllChannels();
Preeti Ahuja95919342013-10-01 18:18:55 -0700636 break;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530637 case OP_ALPHA_NOTIFY:
638 handleAlphaNotify((Bundle) msg.obj);
639 break;
Preeti Ahuja560be362014-11-25 19:38:24 -0800640 case OP_IDLE_SCREEN:
641 for (int slot = 0; slot < mSimCount; slot++) {
642 if (mStkContext[slot] != null) {
643 handleIdleScreen(slot);
644 }
645 }
646 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530647 case OP_STOP_TONE_USER:
648 case OP_STOP_TONE:
649 CatLog.d(this, "Stop tone");
650 handleStopTone(msg, slotId);
651 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700652 }
653 }
654
Wink Savillee68857d2014-10-17 15:23:05 -0700655 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
Wink Saville94e982b2014-07-11 07:38:14 -0700656 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
657
Wink Savillee68857d2014-10-17 15:23:05 -0700658 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
Wink Saville94e982b2014-07-11 07:38:14 -0700659 if (cardStatus == false) {
Wink Savillee68857d2014-10-17 15:23:05 -0700660 CatLog.d(LOG_TAG, "CARD is ABSENT");
Wink Saville94e982b2014-07-11 07:38:14 -0700661 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900662 cancelIdleText(slotId);
Srikanth Chintala7c5a04c2016-09-22 19:05:01 +0530663 mStkContext[slotId].mCurrentMenu = null;
664 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700665 if (isAllOtherCardsAbsent(slotId)) {
666 CatLog.d(LOG_TAG, "All CARDs are ABSENT");
667 StkAppInstaller.unInstall(mContext);
668 stopSelf();
669 }
Wink Saville94e982b2014-07-11 07:38:14 -0700670 } else {
671 IccRefreshResponse state = new IccRefreshResponse();
672 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
673
Wink Savillee68857d2014-10-17 15:23:05 -0700674 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
Wink Saville94e982b2014-07-11 07:38:14 -0700675 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
676 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
677 // Clear Idle Text
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900678 cancelIdleText(slotId);
Wink Saville94e982b2014-07-11 07:38:14 -0700679 }
680
681 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
682 // Uninstall STkmenu
Wink Savillee68857d2014-10-17 15:23:05 -0700683 if (isAllOtherCardsAbsent(slotId)) {
684 StkAppInstaller.unInstall(mContext);
685 }
686 mStkContext[slotId].mCurrentMenu = null;
687 mStkContext[slotId].mMainCmd = null;
Wink Saville94e982b2014-07-11 07:38:14 -0700688 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800689 }
690 }
691 }
Wink Savillee68857d2014-10-17 15:23:05 -0700692 /*
693 * Check if all SIMs are absent except the id of slot equals "slotId".
694 */
695 private boolean isAllOtherCardsAbsent(int slotId) {
696 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
697 Context.TELEPHONY_SERVICE);
698 int i = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800699
Wink Savillee68857d2014-10-17 15:23:05 -0700700 for (i = 0; i < mSimCount; i++) {
701 if (i != slotId && mTm.hasIccCard(i)) {
702 break;
703 }
704 }
705 if (i == mSimCount) {
706 return true;
707 } else {
708 return false;
709 }
710 }
Preeti Ahuja95919342013-10-01 18:18:55 -0700711
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900712 /* package */ boolean isScreenIdle() {
713 ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
714 List<RunningTaskInfo> tasks = am.getRunningTasks(1);
715 if (tasks == null || tasks.isEmpty()) {
716 return false;
717 }
718
719 String top = tasks.get(0).topActivity.getPackageName();
720 if (top == null) {
721 return false;
722 }
723
724 // We can assume that the screen is idle if the home application is in the foreground.
725 final Intent intent = new Intent(Intent.ACTION_MAIN, null);
726 intent.addCategory(Intent.CATEGORY_HOME);
727
728 ResolveInfo info = getPackageManager().resolveActivity(intent,
729 PackageManager.MATCH_DEFAULT_ONLY);
730 if (info != null) {
731 if (top.equals(info.activityInfo.packageName)) {
732 return true;
733 }
734 }
735
736 return false;
Preeti Ahuja560be362014-11-25 19:38:24 -0800737 }
738
739 private void handleIdleScreen(int slotId) {
740
741 // If the idle screen event is present in the list need to send the
742 // response to SIM.
743 CatLog.d(this, "Need to send IDLE SCREEN Available event to SIM");
744 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
745
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900746 if (mStkContext[slotId].mIdleModeTextCmd != null
747 && !mStkContext[slotId].mIdleModeTextVisible) {
748 launchIdleText(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -0800749 }
750 }
751
752 private void sendScreenBusyResponse(int slotId) {
753 if (mStkContext[slotId].mCurrentCmd == null) {
754 return;
755 }
756 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
757 CatLog.d(this, "SCREEN_BUSY");
758 resMsg.setResultCode(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS);
759 mStkService[slotId].onCmdResponse(resMsg);
760 if (mStkContext[slotId].mCmdsQ.size() != 0) {
761 callDelayedMsg(slotId);
762 } else {
763 mStkContext[slotId].mCmdInProgress = false;
764 }
765 }
766
Preeti Ahuja95919342013-10-01 18:18:55 -0700767 private void sendResponse(int resId, int slotId, boolean confirm) {
768 Message msg = mServiceHandler.obtainMessage();
769 msg.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +0900770 msg.arg2 = slotId;
Preeti Ahuja95919342013-10-01 18:18:55 -0700771 Bundle args = new Bundle();
772 args.putInt(StkAppService.RES_ID, resId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700773 args.putBoolean(StkAppService.CONFIRMATION, confirm);
774 msg.obj = args;
775 mServiceHandler.sendMessage(msg);
776 }
777
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700778 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800779 switch (cmd.getCmdType()) {
780 case SEND_DTMF:
781 case SEND_SMS:
782 case SEND_SS:
783 case SEND_USSD:
784 case SET_UP_IDLE_MODE_TEXT:
785 case SET_UP_MENU:
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500786 case CLOSE_CHANNEL:
787 case RECEIVE_DATA:
788 case SEND_DATA:
Preeti Ahuja95919342013-10-01 18:18:55 -0700789 case SET_UP_EVENT_LIST:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800790 return false;
791 }
792
793 return true;
794 }
795
Wink Savillee68857d2014-10-17 15:23:05 -0700796 private void handleDelayedCmd(int slotId) {
797 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
798 if (mStkContext[slotId].mCmdsQ.size() != 0) {
799 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
800 if (cmd != null) {
801 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
802 mStkContext[slotId].mCmdsQ.size() +
803 " id: " + cmd.id + "sim id: " + cmd.slotId);
804 switch (cmd.id) {
805 case OP_CMD:
806 handleCmd(cmd.msg, cmd.slotId);
807 break;
808 case OP_END_SESSION:
809 handleSessionEnd(cmd.slotId);
810 break;
811 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800812 }
813 }
814 }
815
Wink Savillee68857d2014-10-17 15:23:05 -0700816 private void callDelayedMsg(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800817 Message msg = mServiceHandler.obtainMessage();
818 msg.arg1 = OP_DELAYED_MSG;
Wink Savillee68857d2014-10-17 15:23:05 -0700819 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800820 mServiceHandler.sendMessage(msg);
821 }
822
Wink Savillee68857d2014-10-17 15:23:05 -0700823 private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) {
824 Message msg = mServiceHandler.obtainMessage();
825 msg.obj = obj;
826 msg.arg1 = inst_type;
827 msg.arg2 = slotId;
828 mServiceHandler.sendMessage(msg);
829 }
830
831 private void handleSessionEnd(int slotId) {
Legler Wuaeefef52014-10-27 00:57:18 +0800832 // We should finish all pending activity if receiving END SESSION command.
833 cleanUpInstanceStackBySlot(slotId);
834
Wink Savillee68857d2014-10-17 15:23:05 -0700835 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
836 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
837 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
838 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
839 mStkContext[slotId].mMenuState);
840
841 mStkContext[slotId].mIsInputPending = false;
842 mStkContext[slotId].mIsMenuPending = false;
843 mStkContext[slotId].mIsDialogPending = false;
Yuta Uife965802017-11-07 20:12:37 +0900844 mStkContext[slotId].mNoResponseFromUser = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700845
Wink Savillee68857d2014-10-17 15:23:05 -0700846 if (mStkContext[slotId].mMainCmd == null) {
847 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
848 }
849 mStkContext[slotId].lastSelectedItem = null;
Wink Saville79085fc2009-06-09 10:27:23 -0700850 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800851 // update the current menu member.
Wink Savillee68857d2014-10-17 15:23:05 -0700852 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
853 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800854 }
Wink Savillee68857d2014-10-17 15:23:05 -0700855 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
Ryuto Sawada08c821c2016-08-08 18:29:02 +0900856
Wink Savillee68857d2014-10-17 15:23:05 -0700857 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
Ryuto Sawada08c821c2016-08-08 18:29:02 +0900858 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800859 }
Takanori Nakano3776e2c2016-10-14 16:54:28 +0900860
861 // Send a local broadcast as a notice that this service handled the session end event.
862 Intent intent = new Intent(SESSION_ENDED);
863 intent.putExtra(SLOT_ID, slotId);
864 LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
865
Wink Savillee68857d2014-10-17 15:23:05 -0700866 if (mStkContext[slotId].mCmdsQ.size() != 0) {
867 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800868 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700869 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800870 }
871 // In case a launch browser command was just confirmed, launch that url.
Wink Savillee68857d2014-10-17 15:23:05 -0700872 if (mStkContext[slotId].launchBrowser) {
873 mStkContext[slotId].launchBrowser = false;
874 launchBrowser(mStkContext[slotId].mBrowserSettings);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800875 }
876 }
877
Preeti Ahuja560be362014-11-25 19:38:24 -0800878 // returns true if any Stk related activity already has focus on the screen
Yoshiaki Nakacec55b82017-10-20 15:53:43 +0900879 boolean isTopOfStack() {
pkanwareab12f32017-02-06 08:35:03 -0800880 ActivityManager mActivityManager = (ActivityManager) mContext
Preeti Ahuja560be362014-11-25 19:38:24 -0800881 .getSystemService(ACTIVITY_SERVICE);
pkanwareab12f32017-02-06 08:35:03 -0800882 String currentPackageName = null;
883 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
884 if (tasks == null || tasks.get(0).topActivity == null) {
885 return false;
886 }
887 currentPackageName = tasks.get(0).topActivity.getPackageName();
Preeti Ahuja560be362014-11-25 19:38:24 -0800888 if (null != currentPackageName) {
889 return currentPackageName.equals(PACKAGE_NAME);
890 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800891 return false;
892 }
893
Sooraj Sasindrana4160472016-10-12 16:28:25 -0700894 /**
895 * Get the boolean config from carrier config manager.
896 *
897 * @param context the context to get carrier service
898 * @param key config key defined in CarrierConfigManager
899 * @return boolean value of corresponding key.
900 */
901 private static boolean getBooleanCarrierConfig(Context context, String key) {
902 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
903 Context.CARRIER_CONFIG_SERVICE);
904 PersistableBundle b = null;
905 if (configManager != null) {
906 b = configManager.getConfig();
907 }
908 if (b != null) {
909 return b.getBoolean(key);
910 } else {
911 // Return static default defined in CarrierConfigManager.
912 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
913 }
914 }
915
Wink Savillee68857d2014-10-17 15:23:05 -0700916 private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700917
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800918 if (cmdMsg == null) {
919 return;
920 }
921 // save local reference for state tracking.
Wink Savillee68857d2014-10-17 15:23:05 -0700922 mStkContext[slotId].mCurrentCmd = cmdMsg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800923 boolean waitForUsersResponse = true;
924
Wink Savillee68857d2014-10-17 15:23:05 -0700925 mStkContext[slotId].mIsInputPending = false;
926 mStkContext[slotId].mIsMenuPending = false;
927 mStkContext[slotId].mIsDialogPending = false;
928
929 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800930 switch (cmdMsg.getCmdType()) {
931 case DISPLAY_TEXT:
932 TextMessage msg = cmdMsg.geTextMessage();
Jeevaka Badrappan854a25c2012-12-01 16:32:03 +0200933 waitForUsersResponse = msg.responseNeeded;
Wink Savillee68857d2014-10-17 15:23:05 -0700934 if (mStkContext[slotId].lastSelectedItem != null) {
935 msg.title = mStkContext[slotId].lastSelectedItem;
936 } else if (mStkContext[slotId].mMainCmd != null){
Yoshiaki Naka28313ba2017-08-04 12:20:53 +0900937 if (!getResources().getBoolean(R.bool.show_menu_title_only_on_menu)) {
938 msg.title = mStkContext[slotId].mMainCmd.getMenu().title;
939 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800940 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800941 //If we receive a low priority Display Text and the device is
942 // not displaying any STK related activity and the screen is not idle
943 // ( that is, device is in an interactive state), then send a screen busy
944 // terminal response. Otherwise display the message. The existing
945 // displayed message shall be updated with the new display text
946 // proactive command (Refer to ETSI TS 102 384 section 27.22.4.1.4.4.2).
947 if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible
948 || mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) {
949 if(!isScreenIdle()) {
950 CatLog.d(LOG_TAG, "Screen is not idle");
951 sendScreenBusyResponse(slotId);
952 } else {
953 launchTextDialog(slotId);
954 }
955 } else {
956 launchTextDialog(slotId);
957 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800958 break;
959 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700960 CatLog.d(LOG_TAG, "SELECT_ITEM +");
961 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
962 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
963 launchMenuActivity(cmdMsg.getMenu(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800964 break;
965 case SET_UP_MENU:
Wink Savillee68857d2014-10-17 15:23:05 -0700966 mStkContext[slotId].mCmdInProgress = false;
967 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
968 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
969 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
970 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
971
972 if (removeMenu(slotId)) {
973 int i = 0;
974 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App");
975 mStkContext[slotId].mCurrentMenu = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700976 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700977 //Check other setup menu state. If all setup menu are removed, uninstall apk.
978 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
979 if (i != slotId
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +0900980 && (mStkContext[i].mSetupMenuState == STATE_UNKNOWN
981 || mStkContext[i].mSetupMenuState == STATE_EXIST)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700982 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +0900983 + mStkContext[i].mSetupMenuState);
Wink Savillee68857d2014-10-17 15:23:05 -0700984 break;
985 }
986 }
987 if (i == mSimCount) {
988 StkAppInstaller.unInstall(mContext);
989 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800990 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700991 CatLog.d(LOG_TAG, "install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800992 StkAppInstaller.install(mContext);
993 }
Wink Savillee68857d2014-10-17 15:23:05 -0700994 if (mStkContext[slotId].mMenuIsVisible) {
995 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800996 }
997 break;
998 case GET_INPUT:
999 case GET_INKEY:
Wink Savillee68857d2014-10-17 15:23:05 -07001000 launchInputActivity(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001001 break;
1002 case SET_UP_IDLE_MODE_TEXT:
1003 waitForUsersResponse = false;
Preeti Ahuja560be362014-11-25 19:38:24 -08001004 mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd;
1005 TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001006 if (idleModeText == null || TextUtils.isEmpty(idleModeText.text)) {
1007 cancelIdleText(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -08001008 }
1009 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001010 if (mStkContext[slotId].mIdleModeTextCmd != null) {
1011 if (mStkContext[slotId].mIdleModeTextVisible || isScreenIdle()) {
1012 CatLog.d(this, "set up idle mode");
1013 launchIdleText(slotId);
1014 } else {
1015 registerProcessObserver();
1016 }
Preeti Ahuja560be362014-11-25 19:38:24 -08001017 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001018 break;
1019 case SEND_DTMF:
1020 case SEND_SMS:
1021 case SEND_SS:
1022 case SEND_USSD:
Preeti Ahuja95919342013-10-01 18:18:55 -07001023 case GET_CHANNEL_STATUS:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001024 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -07001025 launchEventMessage(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001026 break;
1027 case LAUNCH_BROWSER:
Ryuto Sawada0bdc7192016-04-18 12:10:56 +09001028 // The device setup process should not be interrupted by launching browser.
1029 if (Settings.Global.getInt(mContext.getContentResolver(),
1030 Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
1031 CatLog.d(this, "The command is not performed if the setup has not been completed.");
1032 sendScreenBusyResponse(slotId);
1033 break;
1034 }
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001035
1036 /* Check if Carrier would not want to launch browser */
1037 if (getBooleanCarrierConfig(mContext,
1038 CarrierConfigManager.KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL)) {
1039 CatLog.d(this, "Browser is not launched as per carrier.");
1040 sendResponse(RES_ID_DONE, slotId, true);
1041 break;
1042 }
1043
Srikanth Chintalaba103002015-11-30 10:49:52 -08001044 mStkContext[slotId].mBrowserSettings =
1045 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
1046 if (!isUrlAvailableToLaunchBrowser(mStkContext[slotId].mBrowserSettings)) {
1047 CatLog.d(this, "Browser url property is not set - send error");
1048 sendResponse(RES_ID_ERROR, slotId, true);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001049 } else {
Srikanth Chintalaba103002015-11-30 10:49:52 -08001050 TextMessage alphaId = mStkContext[slotId].mCurrentCmd.geTextMessage();
1051 if ((alphaId == null) || TextUtils.isEmpty(alphaId.text)) {
1052 // don't need user confirmation in this case
1053 // just launch the browser or spawn a new tab
1054 CatLog.d(this, "user confirmation is not currently needed.\n" +
1055 "supressing confirmation dialogue and confirming silently...");
1056 mStkContext[slotId].launchBrowser = true;
1057 sendResponse(RES_ID_CONFIRM, slotId, true);
1058 } else {
1059 launchConfirmationDialog(alphaId, slotId);
1060 }
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001061 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001062 break;
1063 case SET_UP_CALL:
Preeti Ahujadd240102013-08-30 17:25:06 -07001064 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg;
1065 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) {
1066 mesg.text = getResources().getString(R.string.default_setup_call_msg);
1067 }
1068 CatLog.d(this, "SET_UP_CALL mesg.text " + mesg.text);
1069 launchConfirmationDialog(mesg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001070 break;
1071 case PLAY_TONE:
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301072 handlePlayTone(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001073 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001074 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -07001075 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001076 break;
1077 case CLOSE_CHANNEL:
1078 case RECEIVE_DATA:
1079 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -07001080 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001081
1082 if ((m != null) && (m.text == null)) {
1083 switch(cmdMsg.getCmdType()) {
1084 case CLOSE_CHANNEL:
1085 m.text = getResources().getString(R.string.default_close_channel_msg);
1086 break;
1087 case RECEIVE_DATA:
1088 m.text = getResources().getString(R.string.default_receive_data_msg);
1089 break;
1090 case SEND_DATA:
1091 m.text = getResources().getString(R.string.default_send_data_msg);
1092 break;
1093 }
1094 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001095 /*
1096 * Display indication in the form of a toast to the user if required.
1097 */
Wink Savillee68857d2014-10-17 15:23:05 -07001098 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001099 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001100 case SET_UP_EVENT_LIST:
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001101 replaceEventList(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -08001102 if (isScreenIdle()) {
1103 CatLog.d(this," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List");
1104 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
1105 }
Preeti Ahuja95919342013-10-01 18:18:55 -07001106 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001107 }
1108
1109 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -07001110 if (mStkContext[slotId].mCmdsQ.size() != 0) {
1111 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001112 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001113 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001114 }
1115 }
1116 }
1117
Wink Savillee68857d2014-10-17 15:23:05 -07001118 private void handleCmdResponse(Bundle args, int slotId) {
1119 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
1120 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001121 return;
1122 }
Wink Savillee68857d2014-10-17 15:23:05 -07001123
1124 if (mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +08001125 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001126 if (mStkService[slotId] == null) {
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001127 // This should never happen (we should be responding only to a message
1128 // that arrived from StkService). It has to exist by this time
Wink Savillee68857d2014-10-17 15:23:05 -07001129 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response.");
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001130 throw new RuntimeException("mStkService is null when we need to send response");
1131 }
1132 }
1133
Wink Savillee68857d2014-10-17 15:23:05 -07001134 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001135
1136 // set result code
1137 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001138 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001139
1140 switch(args.getInt(RES_ID)) {
1141 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -07001142 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
1143 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001144 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -07001145 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001146 case SET_UP_MENU:
1147 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -07001148 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001149 if (helpRequired) {
1150 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1151 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301152 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1153 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001154 }
1155 resMsg.setMenuSelection(menuSelection);
1156 break;
1157 }
1158 break;
1159 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001160 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001161 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -07001162 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
1163 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001164 boolean yesNoSelection = input
1165 .equals(StkInputActivity.YES_STR_RESPONSE);
1166 resMsg.setYesNo(yesNoSelection);
1167 } else {
1168 if (helpRequired) {
1169 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1170 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301171 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1172 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001173 resMsg.setInput(input);
1174 }
1175 }
1176 break;
1177 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -07001178 CatLog.d(this, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001179 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -07001180 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001181 case DISPLAY_TEXT:
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301182 if (confirmed) {
1183 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1184 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
1185 } else {
1186 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1187 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001188 break;
1189 case LAUNCH_BROWSER:
1190 resMsg.setResultCode(confirmed ? ResultCode.OK
1191 : ResultCode.UICC_SESSION_TERM_BY_USER);
1192 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001193 mStkContext[slotId].launchBrowser = true;
1194 mStkContext[slotId].mBrowserSettings =
1195 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001196 }
1197 break;
1198 case SET_UP_CALL:
1199 resMsg.setResultCode(ResultCode.OK);
1200 resMsg.setConfirmation(confirmed);
1201 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001202 launchEventMessage(slotId,
1203 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001204 }
1205 break;
1206 }
1207 break;
1208 case RES_ID_DONE:
1209 resMsg.setResultCode(ResultCode.OK);
1210 break;
1211 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -07001212 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001213 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
1214 break;
1215 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -07001216 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001217 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1218 break;
1219 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001220 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -08001221 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
1222 // Clear message after delay, successful) expects result code OK.
1223 // If the command qualifier specifies no user response is required
1224 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -07001225 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1226 AppInterface.CommandType.DISPLAY_TEXT.value())
1227 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -08001228 resMsg.setResultCode(ResultCode.OK);
1229 } else {
1230 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
1231 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001232 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001233 case RES_ID_CHOICE:
1234 int choice = args.getInt(CHOICE);
1235 CatLog.d(this, "User Choice=" + choice);
1236 switch (choice) {
1237 case YES:
1238 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001239 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001240 break;
1241 case NO:
1242 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
1243 break;
1244 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001245
Wink Savillee68857d2014-10-17 15:23:05 -07001246 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1247 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001248 resMsg.setConfirmation(confirmed);
1249 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001250 break;
Srikanth Chintalaba103002015-11-30 10:49:52 -08001251 case RES_ID_ERROR:
1252 CatLog.d(LOG_TAG, "RES_ID_ERROR");
1253 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
1254 case LAUNCH_BROWSER:
1255 resMsg.setResultCode(ResultCode.LAUNCH_BROWSER_ERROR);
1256 break;
1257 }
1258 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001259 default:
Wink Savillee68857d2014-10-17 15:23:05 -07001260 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001261 return;
1262 }
Wink Savillee68857d2014-10-17 15:23:05 -07001263
Yuta Uife965802017-11-07 20:12:37 +09001264 switch (args.getInt(RES_ID)) {
1265 case RES_ID_MENU_SELECTION:
1266 case RES_ID_INPUT:
1267 case RES_ID_CONFIRM:
1268 case RES_ID_CHOICE:
1269 case RES_ID_BACKWARD:
1270 case RES_ID_END_SESSION:
1271 mStkContext[slotId].mNoResponseFromUser = false;
1272 break;
1273 case RES_ID_TIMEOUT:
1274 cancelNotificationOnKeyguard(slotId);
1275 mStkContext[slotId].mNoResponseFromUser = true;
1276 break;
1277 default:
1278 // The other IDs cannot be used to judge if there is no response from user.
1279 break;
1280 }
1281
Wink Savillee68857d2014-10-17 15:23:05 -07001282 if (null != mStkContext[slotId].mCurrentCmd &&
1283 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1284 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1285 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1286 }
1287 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001288 }
1289
1290 /**
1291 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1292 *
1293 * @param userAction If the userAction is yes then we always return 0 otherwise
1294 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1295 * then we are the foreground app and we'll return 0 as from our perspective a
1296 * user action did cause. If it's false than we aren't the foreground app and
1297 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001298 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001299 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1300 */
Wink Savillee68857d2014-10-17 15:23:05 -07001301 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1302 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1303 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1304 }
1305 /**
1306 * This method is used for cleaning up pending instances in stack.
1307 */
1308 private void cleanUpInstanceStackBySlot(int slotId) {
1309 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1310 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1311 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
Legler Wuaeefef52014-10-27 00:57:18 +08001312 if (mStkContext[slotId].mCurrentCmd == null) {
1313 CatLog.d(LOG_TAG, "current cmd is null.");
1314 return;
1315 }
Wink Savillee68857d2014-10-17 15:23:05 -07001316 if (activity != null) {
1317 CatLog.d(LOG_TAG, "current cmd type: " +
1318 mStkContext[slotId].mCurrentCmd.getCmdType());
1319 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1320 AppInterface.CommandType.GET_INPUT.value() ||
1321 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1322 AppInterface.CommandType.GET_INKEY.value()) {
1323 mStkContext[slotId].mIsInputPending = true;
1324 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1325 AppInterface.CommandType.SET_UP_MENU.value() ||
1326 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1327 AppInterface.CommandType.SELECT_ITEM.value()) {
1328 mStkContext[slotId].mIsMenuPending = true;
1329 } else {
1330 }
1331 CatLog.d(LOG_TAG, "finish pending activity.");
1332 activity.finish();
1333 mStkContext[slotId].mActivityInstance = null;
1334 }
1335 if (dialog != null) {
1336 CatLog.d(LOG_TAG, "finish pending dialog.");
1337 mStkContext[slotId].mIsDialogPending = true;
1338 dialog.finish();
1339 mStkContext[slotId].mDialogInstance = null;
1340 }
1341 }
1342 /**
1343 * This method is used for restoring pending instances from stack.
1344 */
1345 private void restoreInstanceFromStackBySlot(int slotId) {
1346 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1347
1348 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1349 switch(cmdType) {
1350 case GET_INPUT:
1351 case GET_INKEY:
1352 launchInputActivity(slotId);
1353 //Set mMenuIsVisible to true for showing main menu for
1354 //following session end command.
1355 mStkContext[slotId].mMenuIsVisible = true;
1356 break;
1357 case DISPLAY_TEXT:
1358 launchTextDialog(slotId);
1359 break;
1360 case LAUNCH_BROWSER:
1361 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1362 slotId);
1363 break;
1364 case OPEN_CHANNEL:
1365 launchOpenChannelDialog(slotId);
1366 break;
1367 case SET_UP_CALL:
1368 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1369 confirmMsg, slotId);
1370 break;
1371 case SET_UP_MENU:
1372 case SELECT_ITEM:
1373 launchMenuActivity(null, slotId);
1374 break;
1375 default:
1376 break;
1377 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001378 }
1379
Wink Savillee68857d2014-10-17 15:23:05 -07001380 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001381 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001382 String targetActivity = STK_MENU_ACTIVITY_NAME;
1383 String uriString = STK_MENU_URI + System.currentTimeMillis();
1384 //Set unique URI to create a new instance of activity for different slotId.
1385 Uri uriData = Uri.parse(uriString);
1386
1387 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1388 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1389 + mStkContext[slotId].mMenuState);
1390 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1391 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1392
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001393 if (menu == null) {
1394 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001395 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001396 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1397 //Otherwise, it should be "STATE_MAIN".
1398 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1399 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1400 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1401 } else {
1402 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1403 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1404 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001405 } else {
1406 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001407 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001408 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001409 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001410 }
Wink Savillee68857d2014-10-17 15:23:05 -07001411 newIntent.putExtra(SLOT_ID, slotId);
1412 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001413 newIntent.setFlags(intentFlags);
1414 mContext.startActivity(newIntent);
1415 }
1416
Wink Savillee68857d2014-10-17 15:23:05 -07001417 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001418 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001419 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1420 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1421 //Set unique URI to create a new instance of activity for different slotId.
1422 Uri uriData = Uri.parse(uriString);
Yuta Uife965802017-11-07 20:12:37 +09001423 Input input = mStkContext[slotId].mCurrentCmd.geInput();
Wink Savillee68857d2014-10-17 15:23:05 -07001424
1425 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001426 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001427 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1428 newIntent.setClassName(PACKAGE_NAME, targetActivity);
Yuta Uife965802017-11-07 20:12:37 +09001429 newIntent.putExtra("INPUT", input);
Wink Savillee68857d2014-10-17 15:23:05 -07001430 newIntent.putExtra(SLOT_ID, slotId);
1431 newIntent.setData(uriData);
Yuta Uife965802017-11-07 20:12:37 +09001432
1433 if (input != null) {
1434 notifyUserIfNecessary(slotId, input.text);
1435 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001436 mContext.startActivity(newIntent);
1437 }
1438
Wink Savillee68857d2014-10-17 15:23:05 -07001439 private void launchTextDialog(int slotId) {
1440 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1441 Intent newIntent = new Intent();
1442 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1443 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1444 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1445 //Set unique URI to create a new instance of activity for different slotId.
1446 Uri uriData = Uri.parse(uriString);
Yuta Uife965802017-11-07 20:12:37 +09001447 TextMessage textMessage = mStkContext[slotId].mCurrentCmd.geTextMessage();
1448
1449 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1450 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1451 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1452 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1453 newIntent.setData(uriData);
1454 newIntent.putExtra("TEXT", textMessage);
1455 newIntent.putExtra(SLOT_ID, slotId);
1456
1457 if (textMessage != null) {
1458 notifyUserIfNecessary(slotId, textMessage.text);
1459 }
1460 startActivity(newIntent);
1461 // For display texts with immediate response, send the terminal response
1462 // immediately. responseNeeded will be false, if display text command has
1463 // the immediate response tlv.
1464 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
1465 sendResponse(RES_ID_CONFIRM, slotId, true);
1466 }
1467 }
1468
1469 private void notifyUserIfNecessary(int slotId, String message) {
1470 createAllChannels();
1471
1472 if (mStkContext[slotId].mNoResponseFromUser) {
1473 // No response from user was observed in the current session.
1474 // Do nothing in that case in order to avoid turning on the screen again and again
1475 // when the card repeatedly sends the same command in its retry procedure.
1476 return;
1477 }
1478
1479 PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
1480
1481 if (((KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE)).isKeyguardLocked()) {
1482 // Display the notification on the keyguard screen
1483 // if user cannot see the message from the card right now because of it.
1484 // The notification can be dismissed if user removed the keyguard screen.
1485 launchNotificationOnKeyguard(slotId, message);
1486 } else if (!(pm.isInteractive() && isTopOfStack())) {
1487 // User might be doing something but it is not related to the SIM Toolkit.
1488 // Play the tone and do vibration in order to attract user's attention.
1489 // User will see the input screen or the dialog soon in this case.
1490 NotificationChannel channel = mNotificationManager
1491 .getNotificationChannel(STK_NOTIFICATION_CHANNEL_ID);
1492 Uri uri = channel.getSound();
1493 if (uri != null && !Uri.EMPTY.equals(uri)
1494 && (NotificationManager.IMPORTANCE_LOW) < channel.getImportance()) {
1495 RingtoneManager.getRingtone(getApplicationContext(), uri).play();
1496 }
1497 long[] pattern = channel.getVibrationPattern();
1498 if (pattern != null && channel.shouldVibrate()) {
1499 ((Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE))
1500 .vibrate(pattern, -1);
Preeti Ahuja414bc412013-06-25 19:31:49 -07001501 }
Wink Savillee68857d2014-10-17 15:23:05 -07001502 }
Yuta Uife965802017-11-07 20:12:37 +09001503
1504 // Turn on the screen.
1505 PowerManager.WakeLock wakelock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
1506 | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
1507 wakelock.acquire();
1508 wakelock.release();
1509 }
1510
1511 private void launchNotificationOnKeyguard(int slotId, String message) {
1512 Notification.Builder builder = new Notification.Builder(this, STK_NOTIFICATION_CHANNEL_ID);
1513
1514 builder.setStyle(new Notification.BigTextStyle(builder).bigText(message));
1515 builder.setContentText(message);
1516
1517 Menu menu = getMainMenu(slotId);
1518 if (menu == null || TextUtils.isEmpty(menu.title)) {
1519 builder.setContentTitle(getResources().getString(R.string.app_name));
1520 } else {
1521 builder.setContentTitle(menu.title);
1522 }
1523
1524 builder.setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1525 builder.setOngoing(true);
1526 builder.setOnlyAlertOnce(true);
1527 builder.setColor(getResources().getColor(
1528 com.android.internal.R.color.system_notification_accent_color));
1529
1530 registerUserPresentReceiver();
1531 mNotificationManager.notify(getNotificationId(NOTIFICATION_ON_KEYGUARD, slotId),
1532 builder.build());
1533 mStkContext[slotId].mNotificationOnKeyguard = true;
1534 }
1535
1536 private void cancelNotificationOnKeyguard(int slotId) {
1537 mNotificationManager.cancel(getNotificationId(NOTIFICATION_ON_KEYGUARD, slotId));
1538 mStkContext[slotId].mNotificationOnKeyguard = false;
1539 unregisterUserPresentReceiver(slotId);
1540 }
1541
1542 private synchronized void registerUserPresentReceiver() {
1543 if (mUserPresentReceiver == null) {
1544 mUserPresentReceiver = new BroadcastReceiver() {
1545 @Override public void onReceive(Context context, Intent intent) {
1546 if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
1547 for (int slot = 0; slot < mSimCount; slot++) {
1548 cancelNotificationOnKeyguard(slot);
1549 }
1550 }
1551 }
1552 };
1553 registerReceiver(mUserPresentReceiver, new IntentFilter(Intent.ACTION_USER_PRESENT));
1554 }
1555 }
1556
1557 private synchronized void unregisterUserPresentReceiver(int slotId) {
1558 if (mUserPresentReceiver != null) {
1559 for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
1560 if (slot != slotId) {
1561 if (mStkContext[slot].mNotificationOnKeyguard) {
1562 // The broadcast receiver is still necessary for other SIM card.
1563 return;
1564 }
1565 }
1566 }
1567 unregisterReceiver(mUserPresentReceiver);
1568 mUserPresentReceiver = null;
1569 }
1570 }
1571
1572 private int getNotificationId(int notificationType, int slotId) {
1573 return getNotificationId(slotId) + (notificationType * mSimCount);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001574 }
1575
Wink Savillee68857d2014-10-17 15:23:05 -07001576 public boolean isStkDialogActivated(Context context) {
1577 String stkDialogActivity = "com.android.stk.StkDialogActivity";
1578 boolean activated = false;
1579 final ActivityManager am = (ActivityManager) context.getSystemService(
1580 Context.ACTIVITY_SERVICE);
1581 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName();
1582
1583 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity);
1584 if (topActivity.equals(stkDialogActivity)) {
1585 activated = true;
1586 }
1587 CatLog.d(LOG_TAG, "activated : " + activated);
1588 return activated;
Johan Hellman3aec01c2011-02-10 10:15:28 +01001589 }
1590
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001591 private void replaceEventList(int slotId) {
1592 if (mStkContext[slotId].mSetupEventListSettings != null) {
1593 for (int current : mStkContext[slotId].mSetupEventListSettings.eventList) {
1594 if (current != INVALID_SETUP_EVENT) {
1595 // Cancel the event notification if it is not listed in the new event list.
1596 if ((mStkContext[slotId].mCurrentCmd.getSetEventList() == null)
1597 || !findEvent(current, mStkContext[slotId].mCurrentCmd
1598 .getSetEventList().eventList)) {
1599 unregisterEvent(current, slotId);
1600 }
1601 }
1602 }
1603 }
1604 mStkContext[slotId].mSetupEventListSettings
1605 = mStkContext[slotId].mCurrentCmd.getSetEventList();
1606 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
1607 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
1608 registerEvents(slotId);
1609 }
1610
1611 private boolean findEvent(int event, int[] eventList) {
1612 for (int content : eventList) {
1613 if (content == event) return true;
1614 }
1615 return false;
1616 }
1617
1618 private void unregisterEvent(int event, int slotId) {
1619 switch (event) {
1620 case IDLE_SCREEN_AVAILABLE_EVENT:
1621 unregisterProcessObserver(AppInterface.CommandType.SET_UP_EVENT_LIST, slotId);
1622 break;
1623 case LANGUAGE_SELECTION_EVENT:
1624 default:
1625 break;
1626 }
1627 }
1628
1629 private void registerEvents(int slotId) {
1630 if (mStkContext[slotId].mSetupEventListSettings == null) {
1631 return;
1632 }
1633 for (int event : mStkContext[slotId].mSetupEventListSettings.eventList) {
1634 switch (event) {
1635 case IDLE_SCREEN_AVAILABLE_EVENT:
1636 registerProcessObserver();
1637 break;
1638 case LANGUAGE_SELECTION_EVENT:
1639 default:
1640 break;
1641 }
1642 }
1643 }
1644
1645 private synchronized void registerProcessObserver() {
1646 if (mProcessObserver == null) {
1647 try {
1648 IProcessObserver.Stub observer = new IProcessObserver.Stub() {
1649 @Override
1650 public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
1651 if (isScreenIdle()) {
1652 Message message = mServiceHandler.obtainMessage();
1653 message.arg1 = OP_IDLE_SCREEN;
1654 mServiceHandler.sendMessage(message);
1655 unregisterProcessObserver();
1656 }
1657 }
1658
1659 @Override
1660 public void onProcessDied(int pid, int uid) {
1661 }
1662 };
1663 ActivityManagerNative.getDefault().registerProcessObserver(observer);
1664 mProcessObserver = observer;
1665 } catch (RemoteException e) {
1666 CatLog.d(this, "Failed to register the process observer");
1667 }
1668 }
1669 }
1670
1671 private void unregisterProcessObserver(AppInterface.CommandType command, int slotId) {
1672 // Check if there is any pending command which still needs the process observer
1673 // except for the current command and slot.
1674 for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
1675 if (command != AppInterface.CommandType.SET_UP_IDLE_MODE_TEXT || slot != slotId) {
1676 if (mStkContext[slot].mIdleModeTextCmd != null
1677 && !mStkContext[slot].mIdleModeTextVisible) {
1678 // Keep the process observer registered
1679 // as there is an idle mode text which has not been visible yet.
1680 return;
1681 }
1682 }
1683 if (command != AppInterface.CommandType.SET_UP_EVENT_LIST || slot != slotId) {
1684 if (mStkContext[slot].mSetupEventListSettings != null) {
1685 if (findEvent(IDLE_SCREEN_AVAILABLE_EVENT,
1686 mStkContext[slot].mSetupEventListSettings.eventList)) {
1687 // Keep the process observer registered
1688 // as there is a SIM card which still want IDLE SCREEN AVAILABLE event.
1689 return;
1690 }
1691 }
1692 }
1693 }
1694 unregisterProcessObserver();
1695 }
1696
1697 private synchronized void unregisterProcessObserver() {
1698 if (mProcessObserver != null) {
1699 try {
1700 ActivityManagerNative.getDefault().unregisterProcessObserver(mProcessObserver);
1701 mProcessObserver = null;
1702 } catch (RemoteException e) {
1703 CatLog.d(this, "Failed to unregister the process observer");
1704 }
1705 }
1706 }
1707
Preeti Ahuja95919342013-10-01 18:18:55 -07001708 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
Preeti Ahuja414bc412013-06-25 19:31:49 -07001709 CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -07001710
1711 if (mStkContext[slotId].mCurrentSetupEventCmd == null){
1712 CatLog.e(this, "mCurrentSetupEventCmd is null");
1713 return;
1714 }
1715
1716 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd);
1717
1718 resMsg.setResultCode(ResultCode.OK);
1719 resMsg.setEventDownload(event, addedInfo);
1720
1721 mStkService[slotId].onCmdResponse(resMsg);
1722 }
1723
1724 private void checkForSetupEvent(int event, Bundle args, int slotId) {
1725 boolean eventPresent = false;
1726 byte[] addedInfo = null;
1727 CatLog.d(this, "Event :" + event);
1728
1729 if (mStkContext[slotId].mSetupEventListSettings != null) {
1730 /* Checks if the event is present in the EventList updated by last
1731 * SetupEventList Proactive Command */
1732 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) {
1733 if (event == i) {
1734 eventPresent = true;
1735 break;
1736 }
1737 }
1738
1739 /* If Event is present send the response to ICC */
1740 if (eventPresent == true) {
1741 CatLog.d(this, " Event " + event + "exists in the EventList");
1742
1743 switch (event) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001744 case IDLE_SCREEN_AVAILABLE_EVENT:
1745 sendSetUpEventResponse(event, addedInfo, slotId);
1746 removeSetUpEvent(event, slotId);
1747 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001748 case LANGUAGE_SELECTION_EVENT:
1749 String language = mContext
1750 .getResources().getConfiguration().locale.getLanguage();
1751 CatLog.d(this, "language: " + language);
1752 // Each language code is a pair of alpha-numeric characters.
1753 // Each alpha-numeric character shall be coded on one byte
1754 // using the SMS default 7-bit coded alphabet
1755 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language);
1756 sendSetUpEventResponse(event, addedInfo, slotId);
1757 break;
1758 default:
1759 break;
1760 }
1761 } else {
1762 CatLog.e(this, " Event does not exist in the EventList");
1763 }
1764 } else {
1765 CatLog.e(this, "SetupEventList is not received. Ignoring the event: " + event);
1766 }
1767 }
1768
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001769 private void removeSetUpEvent(int event, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -07001770 CatLog.d(this, "Remove Event :" + event);
1771
1772 if (mStkContext[slotId].mSetupEventListSettings != null) {
1773 /*
1774 * Make new Eventlist without the event
1775 */
1776 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
1777 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
1778 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001779
1780 switch (event) {
1781 case IDLE_SCREEN_AVAILABLE_EVENT:
1782 // The process observer can be unregistered
1783 // as the idle screen has already been available.
1784 unregisterProcessObserver();
1785 break;
1786 default:
1787 break;
1788 }
Preeti Ahuja95919342013-10-01 18:18:55 -07001789 break;
1790 }
1791 }
1792 }
1793 }
1794
1795 private void launchEventMessage(int slotId) {
1796 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
1797 }
1798
Wink Savillee68857d2014-10-17 15:23:05 -07001799 private void launchEventMessage(int slotId, TextMessage msg) {
Ryuto Sawada2ba20cc2015-12-28 17:10:35 +01001800 if (msg == null || msg.text == null || (msg.text != null && msg.text.length() == 0)) {
Wink Savillee68857d2014-10-17 15:23:05 -07001801 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001802 return;
1803 }
Wink Savillee68857d2014-10-17 15:23:05 -07001804
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001805 Toast toast = new Toast(mContext.getApplicationContext());
1806 LayoutInflater inflate = (LayoutInflater) mContext
1807 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1808 View v = inflate.inflate(R.layout.stk_event_msg, null);
1809 TextView tv = (TextView) v
1810 .findViewById(com.android.internal.R.id.message);
1811 ImageView iv = (ImageView) v
1812 .findViewById(com.android.internal.R.id.icon);
1813 if (msg.icon != null) {
1814 iv.setImageBitmap(msg.icon);
1815 } else {
1816 iv.setVisibility(View.GONE);
1817 }
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301818 /* In case of 'self explanatory' stkapp should display the specified
1819 * icon in proactive command (but not the alpha string).
1820 * If icon is non-self explanatory and if the icon could not be displayed
1821 * then alpha string or text data should be displayed
1822 * Ref: ETSI 102.223,section 6.5.4
1823 */
1824 if (mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ||
1825 msg.icon == null || !msg.iconSelfExplanatory) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001826 tv.setText(msg.text);
1827 }
1828
1829 toast.setView(v);
1830 toast.setDuration(Toast.LENGTH_LONG);
1831 toast.setGravity(Gravity.BOTTOM, 0, 0);
1832 toast.show();
1833 }
1834
Wink Savillee68857d2014-10-17 15:23:05 -07001835 private void launchConfirmationDialog(TextMessage msg, int slotId) {
1836 msg.title = mStkContext[slotId].lastSelectedItem;
1837 Intent newIntent = new Intent();
1838 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1839 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1840 //Set unique URI to create a new instance of activity for different slotId.
1841 Uri uriData = Uri.parse(uriString);
1842
Yuta Uife965802017-11-07 20:12:37 +09001843 newIntent.setClassName(this, targetActivity);
1844 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1845 | Intent.FLAG_ACTIVITY_NO_HISTORY
1846 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1847 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1848 newIntent.putExtra("TEXT", msg);
1849 newIntent.putExtra(SLOT_ID, slotId);
1850 newIntent.setData(uriData);
1851 startActivity(newIntent);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001852 }
1853
1854 private void launchBrowser(BrowserSettings settings) {
1855 if (settings == null) {
1856 return;
1857 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001858
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001859 Uri data = null;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001860 String url;
1861 if (settings.url == null) {
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001862 // if the command did not contain a URL,
1863 // launch the browser to the default homepage.
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001864 CatLog.d(this, "no url data provided by proactive command." +
1865 " launching browser with stk default URL ... ");
1866 url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP,
1867 "http://www.google.com");
1868 } else {
1869 CatLog.d(this, "launch browser command has attached url = " + settings.url);
1870 url = settings.url;
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001871 }
David Brown7c03cfe2011-10-20 15:36:12 -07001872
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001873 if (url.startsWith("http://") || url.startsWith("https://")) {
1874 data = Uri.parse(url);
1875 CatLog.d(this, "launching browser with url = " + url);
1876 } else {
1877 String modifiedUrl = "http://" + url;
1878 data = Uri.parse(modifiedUrl);
1879 CatLog.d(this, "launching browser with modified url = " + modifiedUrl);
1880 }
1881
1882 Intent intent = new Intent(Intent.ACTION_VIEW);
1883 intent.setData(data);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001884 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1885 switch (settings.mode) {
1886 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001887 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1888 break;
1889 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001890 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
1891 break;
1892 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
1893 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1894 break;
1895 }
1896 // start browser activity
1897 startActivity(intent);
1898 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07001899 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001900 // followed immediately.
1901 try {
Ryuto Sawada350aaa62016-06-13 14:47:22 +09001902 Thread.sleep(3000);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001903 } catch (InterruptedException e) {}
1904 }
1905
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001906 private void cancelIdleText(int slotId) {
1907 unregisterProcessObserver(AppInterface.CommandType.SET_UP_IDLE_MODE_TEXT, slotId);
1908 mNotificationManager.cancel(getNotificationId(slotId));
1909 mStkContext[slotId].mIdleModeTextCmd = null;
1910 mStkContext[slotId].mIdleModeTextVisible = false;
1911 }
1912
Wink Savillee68857d2014-10-17 15:23:05 -07001913 private void launchIdleText(int slotId) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001914 TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001915
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001916 if (msg != null && !TextUtils.isEmpty(msg.text)) {
Preeti Ahuja95919342013-10-01 18:18:55 -07001917 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
1918 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
1919 + "] icon[" + msg.icon + "], sim id: " + slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001920 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001921 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001922 new Intent(mContext, StkAppService.class), 0);
fionaxu805eb572017-05-02 10:57:30 -07001923 createAllChannels();
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001924 final Notification.Builder notificationBuilder = new Notification.Builder(
fionaxu2c91c752017-04-21 18:11:57 -07001925 StkAppService.this, STK_NOTIFICATION_CHANNEL_ID);
Wink Savillee68857d2014-10-17 15:23:05 -07001926 if (mStkContext[slotId].mMainCmd != null &&
1927 mStkContext[slotId].mMainCmd.getMenu() != null) {
1928 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001929 } else {
1930 notificationBuilder.setContentTitle("");
1931 }
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001932 notificationBuilder
1933 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1934 notificationBuilder.setContentIntent(pendingIntent);
1935 notificationBuilder.setOngoing(true);
Yuta Uife965802017-11-07 20:12:37 +09001936 notificationBuilder.setOnlyAlertOnce(true);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001937 // Set text and icon for the status bar and notification body.
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301938 if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() ||
1939 !msg.iconSelfExplanatory) {
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001940 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001941 notificationBuilder.setTicker(msg.text);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001942 }
1943 if (msg.icon != null) {
1944 notificationBuilder.setLargeIcon(msg.icon);
1945 } else {
1946 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
1947 .getResources().getSystem(),
1948 com.android.internal.R.drawable.stat_notify_sim_toolkit);
1949 notificationBuilder.setLargeIcon(bitmapIcon);
1950 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02001951 notificationBuilder.setColor(mContext.getResources().getColor(
1952 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07001953 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001954 mStkContext[slotId].mIdleModeTextVisible = true;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001955 }
1956 }
1957
fionaxu805eb572017-05-02 10:57:30 -07001958 /** Creates the notification channel and registers it with NotificationManager.
1959 * If a channel with the same ID is already registered, NotificationManager will
1960 * ignore this call.
1961 */
1962 private void createAllChannels() {
Yuta Uife965802017-11-07 20:12:37 +09001963 NotificationChannel notificationChannel = new NotificationChannel(
fionaxu805eb572017-05-02 10:57:30 -07001964 STK_NOTIFICATION_CHANNEL_ID,
1965 getResources().getString(R.string.stk_channel_name),
Yuta Uife965802017-11-07 20:12:37 +09001966 NotificationManager.IMPORTANCE_DEFAULT);
1967
1968 notificationChannel.enableVibration(true);
1969 notificationChannel.setVibrationPattern(VIBRATION_PATTERN);
1970
1971 mNotificationManager.createNotificationChannel(notificationChannel);
fionaxu805eb572017-05-02 10:57:30 -07001972 }
1973
Wink Savillee68857d2014-10-17 15:23:05 -07001974 private void launchToneDialog(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001975 Intent newIntent = new Intent(this, ToneDialog.class);
Wink Savillee68857d2014-10-17 15:23:05 -07001976 String uriString = STK_TONE_URI + slotId;
1977 Uri uriData = Uri.parse(uriString);
1978 //Set unique URI to create a new instance of activity for different slotId.
1979 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001980 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1981 | Intent.FLAG_ACTIVITY_NO_HISTORY
1982 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Wink Savillee68857d2014-10-17 15:23:05 -07001983 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1984 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1985 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
1986 newIntent.putExtra(SLOT_ID, slotId);
1987 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001988 startActivity(newIntent);
1989 }
1990
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301991 private void handlePlayTone(int slotId) {
1992 TextMessage toneMsg = mStkContext[slotId].mCurrentCmd.geTextMessage();
1993
1994 boolean showUser = true;
1995 boolean displayDialog = true;
1996 Resources resource = Resources.getSystem();
1997 try {
1998 displayDialog = !resource.getBoolean(
1999 com.android.internal.R.bool.config_stkNoAlphaUsrCnf);
2000 } catch (NotFoundException e) {
2001 displayDialog = true;
2002 }
2003
2004 // As per the spec 3GPP TS 11.14, 6.4.5. Play Tone.
2005 // If there is no alpha identifier tlv present, UE may show the
2006 // user information. 'config_stkNoAlphaUsrCnf' value will decide
2007 // whether to show it or not.
2008 // If alpha identifier tlv is present and its data is null, play only tone
2009 // without showing user any information.
2010 // Alpha Id is Present, but the text data is null.
2011 if ((toneMsg.text != null ) && (toneMsg.text.equals(""))) {
2012 CatLog.d(this, "Alpha identifier data is null, play only tone");
2013 showUser = false;
2014 }
2015 // Alpha Id is not present AND we need to show info to the user.
2016 if (toneMsg.text == null && displayDialog) {
2017 CatLog.d(this, "toneMsg.text " + toneMsg.text
2018 + " Starting ToneDialog activity with default message.");
2019 toneMsg.text = getResources().getString(R.string.default_tone_dialog_msg);
2020 showUser = true;
2021 }
2022 // Dont show user info, if config setting is true.
2023 if (toneMsg.text == null && !displayDialog) {
2024 CatLog.d(this, "config value stkNoAlphaUsrCnf is true");
2025 showUser = false;
2026 }
2027
2028 CatLog.d(this, "toneMsg.text: " + toneMsg.text + "showUser: " +showUser +
2029 "displayDialog: " +displayDialog);
2030 playTone(showUser, slotId);
2031 }
2032
2033 private void playTone(boolean showUserInfo, int slotId) {
2034 // Start playing tone and vibration
2035 ToneSettings settings = mStkContext[slotId].mCurrentCmd.getToneSettings();
2036 if (null == settings) {
2037 CatLog.d(this, "null settings, not playing tone.");
2038 return;
2039 }
2040
2041 mVibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
2042 mTonePlayer = new TonePlayer();
2043 mTonePlayer.play(settings.tone);
2044 int timeout = StkApp.calculateDurationInMilis(settings.duration);
2045 if (timeout == 0) {
2046 timeout = StkApp.TONE_DEFAULT_TIMEOUT;
2047 }
2048
2049 Message msg = mServiceHandler.obtainMessage();
2050 msg.arg1 = OP_STOP_TONE;
2051 msg.arg2 = slotId;
2052 msg.obj = (Integer)(showUserInfo ? 1 : 0);
2053 msg.what = STOP_TONE_WHAT;
2054 mServiceHandler.sendMessageDelayed(msg, timeout);
2055 if (settings.vibrate) {
2056 mVibrator.vibrate(timeout);
2057 }
2058
2059 // Start Tone dialog Activity to show user the information.
2060 if (showUserInfo) {
2061 Intent newIntent = new Intent(sInstance, ToneDialog.class);
2062 String uriString = STK_TONE_URI + slotId;
2063 Uri uriData = Uri.parse(uriString);
2064 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
2065 | Intent.FLAG_ACTIVITY_NO_HISTORY
2066 | Intent.FLAG_ACTIVITY_SINGLE_TOP
2067 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
2068 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
2069 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
2070 newIntent.putExtra(SLOT_ID, slotId);
2071 newIntent.setData(uriData);
2072 startActivity(newIntent);
2073 }
2074 }
2075
2076 private void finishToneDialogActivity() {
2077 Intent finishIntent = new Intent(FINISH_TONE_ACTIVITY_ACTION);
2078 sendBroadcast(finishIntent);
2079 }
2080
2081 private void handleStopTone(Message msg, int slotId) {
2082 int resId = 0;
2083
2084 // Stop the play tone in following cases:
2085 // 1.OP_STOP_TONE: play tone timer expires.
2086 // 2.STOP_TONE_USER: user pressed the back key.
2087 if (msg.arg1 == OP_STOP_TONE) {
2088 resId = RES_ID_DONE;
2089 // Dismiss Tone dialog, after finishing off playing the tone.
2090 int finishActivity = (Integer) msg.obj;
2091 if (finishActivity == 1) finishToneDialogActivity();
2092 } else if (msg.arg1 == OP_STOP_TONE_USER) {
2093 resId = RES_ID_END_SESSION;
2094 }
2095
2096 sendResponse(resId, slotId, true);
2097 mServiceHandler.removeMessages(STOP_TONE_WHAT);
2098 if (mTonePlayer != null) {
2099 mTonePlayer.stop();
2100 mTonePlayer.release();
2101 mTonePlayer = null;
2102 }
2103 if (mVibrator != null) {
2104 mVibrator.cancel();
2105 mVibrator = null;
2106 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002107 }
2108
Takanori Nakano49b12722016-02-16 14:34:14 +09002109 private void launchOpenChannelDialog(final int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -07002110 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002111 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07002112 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002113 return;
2114 }
2115
2116 msg.title = getResources().getString(R.string.stk_dialog_title);
2117 if (msg.text == null) {
2118 msg.text = getResources().getString(R.string.default_open_channel_msg);
2119 }
2120
2121 final AlertDialog dialog = new AlertDialog.Builder(mContext)
2122 .setIconAttribute(android.R.attr.alertDialogIcon)
2123 .setTitle(msg.title)
2124 .setMessage(msg.text)
2125 .setCancelable(false)
2126 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
2127 new DialogInterface.OnClickListener() {
2128 public void onClick(DialogInterface dialog, int which) {
2129 Bundle args = new Bundle();
2130 args.putInt(RES_ID, RES_ID_CHOICE);
2131 args.putInt(CHOICE, YES);
2132 Message message = mServiceHandler.obtainMessage();
2133 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09002134 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002135 message.obj = args;
2136 mServiceHandler.sendMessage(message);
2137 }
2138 })
2139 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
2140 new DialogInterface.OnClickListener() {
2141 public void onClick(DialogInterface dialog, int which) {
2142 Bundle args = new Bundle();
2143 args.putInt(RES_ID, RES_ID_CHOICE);
2144 args.putInt(CHOICE, NO);
2145 Message message = mServiceHandler.obtainMessage();
2146 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09002147 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002148 message.obj = args;
2149 mServiceHandler.sendMessage(message);
2150 }
2151 })
2152 .create();
2153
2154 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2155 if (!mContext.getResources().getBoolean(
2156 com.android.internal.R.bool.config_sf_slowBlur)) {
2157 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
2158 }
2159
2160 dialog.show();
2161 }
2162
Wink Savillee68857d2014-10-17 15:23:05 -07002163 private void launchTransientEventMessage(int slotId) {
2164 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002165 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07002166 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002167 return;
2168 }
2169
2170 msg.title = getResources().getString(R.string.stk_dialog_title);
2171
2172 final AlertDialog dialog = new AlertDialog.Builder(mContext)
2173 .setIconAttribute(android.R.attr.alertDialogIcon)
2174 .setTitle(msg.title)
2175 .setMessage(msg.text)
2176 .setCancelable(false)
2177 .setPositiveButton(getResources().getString(android.R.string.ok),
2178 new DialogInterface.OnClickListener() {
2179 public void onClick(DialogInterface dialog, int which) {
2180 }
2181 })
2182 .create();
2183
2184 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2185 if (!mContext.getResources().getBoolean(
2186 com.android.internal.R.bool.config_sf_slowBlur)) {
2187 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
2188 }
2189
2190 dialog.show();
2191 }
2192
Wink Savillee68857d2014-10-17 15:23:05 -07002193 private int getNotificationId(int slotId) {
2194 int notifyId = STK_NOTIFICATION_ID;
2195 if (slotId >= 0 && slotId < mSimCount) {
2196 notifyId += slotId;
2197 } else {
2198 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
2199 }
2200 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
2201 return notifyId;
2202 }
2203
2204 private String getItemName(int itemId, int slotId) {
2205 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002206 if (menu == null) {
2207 return null;
2208 }
2209 for (Item item : menu.items) {
2210 if (item.id == itemId) {
2211 return item.text;
2212 }
2213 }
2214 return null;
2215 }
2216
Wink Savillee68857d2014-10-17 15:23:05 -07002217 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002218 try {
Wink Savillee68857d2014-10-17 15:23:05 -07002219 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
2220 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
2221 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002222 return true;
2223 }
2224 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07002225 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
2226 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002227 return true;
2228 }
Wink Savillee68857d2014-10-17 15:23:05 -07002229 mStkContext[slotId].mSetupMenuState = STATE_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002230 return false;
2231 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05302232
Wink Savillee68857d2014-10-17 15:23:05 -07002233 StkContext getStkContext(int slotId) {
2234 if (slotId >= 0 && slotId < mSimCount) {
2235 return mStkContext[slotId];
2236 } else {
2237 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
2238 return null;
2239 }
2240 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05302241
2242 private void handleAlphaNotify(Bundle args) {
2243 String alphaString = args.getString(AppInterface.ALPHA_STRING);
2244
2245 CatLog.d(this, "Alpha string received from card: " + alphaString);
2246 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
2247 toast.setGravity(Gravity.TOP, 0, 0);
2248 toast.show();
2249 }
Srikanth Chintalaba103002015-11-30 10:49:52 -08002250
2251 private boolean isUrlAvailableToLaunchBrowser(BrowserSettings settings) {
2252 String url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP, "");
2253 if (url == "" && settings.url == null) {
2254 return false;
2255 }
2256 return true;
2257 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002258}