blob: 0543a24efcfefa0c6546772ba2b9b3148cb8e4a4 [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;
Malcolm Chen8c72f2f2020-01-10 15:57:10 -080022import android.app.HomeVisibilityObserver;
Yuta Uife965802017-11-07 20:12:37 +090023import android.app.KeyguardManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080024import android.app.Notification;
fionaxu2c91c752017-04-21 18:11:57 -070025import android.app.NotificationChannel;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080026import android.app.NotificationManager;
27import android.app.PendingIntent;
28import android.app.Service;
Wink Savillee68857d2014-10-17 15:23:05 -070029import android.app.Activity;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +090030import android.app.IProcessObserver;
Yuta Uife965802017-11-07 20:12:37 +090031import android.content.BroadcastReceiver;
Yoshiaki Naka43afa362018-08-15 17:25:34 +090032import android.content.ComponentName;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080033import android.content.Context;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050034import android.content.DialogInterface;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080035import android.content.Intent;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +090036import android.content.pm.PackageManager;
37import android.content.pm.ResolveInfo;
Preeti Ahuja95919342013-10-01 18:18:55 -070038import android.content.res.Configuration;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053039import android.content.res.Resources;
40import android.content.res.Resources.NotFoundException;
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +010041import android.graphics.Bitmap;
42import android.graphics.BitmapFactory;
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;
Yoshiaki Nakafb997252017-09-19 20:14:58 +090053import android.os.ServiceManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070054import android.os.SystemProperties;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053055import android.os.Vibrator;
Preeti Ahuja95919342013-10-01 18:18:55 -070056import android.provider.Settings;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070057import android.telephony.CarrierConfigManager;
Yoshiaki Naka30d5a812018-11-12 12:43:34 +090058import android.telephony.SubscriptionInfo;
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +090059import android.telephony.SubscriptionManager;
Wink Saville56469d52009-04-02 01:37:03 -070060import android.telephony.TelephonyManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070061import android.text.TextUtils;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080062import android.view.Gravity;
Yoshiaki Nakafb997252017-09-19 20:14:58 +090063import android.view.IWindowManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080064import android.view.LayoutInflater;
65import android.view.View;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050066import android.view.WindowManager;
Yoshiaki Nakafb997252017-09-19 20:14:58 +090067import android.view.WindowManagerPolicyConstants;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080068import android.widget.ImageView;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080069import android.widget.TextView;
70import android.widget.Toast;
Wink Savillee68857d2014-10-17 15:23:05 -070071import android.content.IntentFilter;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080072
Malcolm Chen616ea282019-10-24 19:53:48 -070073import com.android.internal.telephony.PhoneConfigurationManager;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070074import com.android.internal.telephony.cat.AppInterface;
Yuta Uife965802017-11-07 20:12:37 +090075import com.android.internal.telephony.cat.Input;
Preeti Ahuja95919342013-10-01 18:18:55 -070076import com.android.internal.telephony.cat.LaunchBrowserMode;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070077import com.android.internal.telephony.cat.Menu;
78import com.android.internal.telephony.cat.Item;
79import com.android.internal.telephony.cat.ResultCode;
80import com.android.internal.telephony.cat.CatCmdMessage;
81import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
Preeti Ahuja95919342013-10-01 18:18:55 -070082import com.android.internal.telephony.cat.CatCmdMessage.SetupEventListSettings;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070083import com.android.internal.telephony.cat.CatLog;
84import com.android.internal.telephony.cat.CatResponseMessage;
85import com.android.internal.telephony.cat.TextMessage;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053086import com.android.internal.telephony.cat.ToneSettings;
Wink Saville94e982b2014-07-11 07:38:14 -070087import com.android.internal.telephony.uicc.IccRefreshResponse;
Wink Savillee68857d2014-10-17 15:23:05 -070088import com.android.internal.telephony.PhoneConstants;
Preeti Ahuja95919342013-10-01 18:18:55 -070089import com.android.internal.telephony.GsmAlphabet;
Legler Wuaeefef52014-10-27 00:57:18 +080090import com.android.internal.telephony.cat.CatService;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080091
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070092import java.util.Iterator;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080093import java.util.LinkedList;
Wink Savillee68857d2014-10-17 15:23:05 -070094import java.util.List;
Yoshiaki Naka43afa362018-08-15 17:25:34 +090095import java.util.regex.Pattern;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080096
Preeti Ahuja95919342013-10-01 18:18:55 -070097import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja560be362014-11-25 19:38:24 -080098 SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
99import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja95919342013-10-01 18:18:55 -0700100 SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900101import static com.android.internal.telephony.cat.CatCmdMessage.
102 SetupEventListConstants.USER_ACTIVITY_EVENT;
Preeti Ahuja95919342013-10-01 18:18:55 -0700103
Malcolm Chen8c72f2f2020-01-10 15:57:10 -0800104import androidx.localbroadcastmanager.content.LocalBroadcastManager;
105
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800106/**
107 * SIM toolkit application level service. Interacts with Telephopny messages,
108 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -0700109 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800110 */
111public class StkAppService extends Service implements Runnable {
112
113 // members
Wink Savillee68857d2014-10-17 15:23:05 -0700114 protected class StkContext {
115 protected CatCmdMessage mMainCmd = null;
116 protected CatCmdMessage mCurrentCmd = null;
117 protected CatCmdMessage mCurrentMenuCmd = null;
118 protected Menu mCurrentMenu = null;
119 protected String lastSelectedItem = null;
120 protected boolean mMenuIsVisible = false;
121 protected boolean mIsInputPending = false;
122 protected boolean mIsMenuPending = false;
123 protected boolean mIsDialogPending = false;
Yuta Uife965802017-11-07 20:12:37 +0900124 protected boolean mNotificationOnKeyguard = false;
125 protected boolean mNoResponseFromUser = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700126 protected boolean launchBrowser = false;
127 protected BrowserSettings mBrowserSettings = null;
128 protected LinkedList<DelayedCmd> mCmdsQ = null;
129 protected boolean mCmdInProgress = false;
130 protected int mStkServiceState = STATE_UNKNOWN;
Yoshiaki Naka3c423002018-08-28 15:17:49 +0900131 protected int mSetupMenuState = STATE_NOT_EXIST;
Wink Savillee68857d2014-10-17 15:23:05 -0700132 protected int mMenuState = StkMenuActivity.STATE_INIT;
133 protected int mOpCode = -1;
134 private Activity mActivityInstance = null;
135 private Activity mDialogInstance = null;
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900136 private Activity mImmediateDialogInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700137 private int mSlotId = 0;
Preeti Ahuja95919342013-10-01 18:18:55 -0700138 private SetupEventListSettings mSetupEventListSettings = null;
139 private boolean mClearSelectItem = false;
140 private boolean mDisplayTextDlgIsVisibile = false;
141 private CatCmdMessage mCurrentSetupEventCmd = null;
Preeti Ahuja560be362014-11-25 19:38:24 -0800142 private CatCmdMessage mIdleModeTextCmd = null;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900143 private boolean mIdleModeTextVisible = false;
Takanori Nakano43dacc02018-07-26 11:27:39 +0900144 // Determins whether the current session was initiated by user operation.
145 protected boolean mIsSessionFromUser = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700146 final synchronized void setPendingActivityInstance(Activity act) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900147 CatLog.d(LOG_TAG, "setPendingActivityInstance act : " + mSlotId + ", " + act);
Wink Savillee68857d2014-10-17 15:23:05 -0700148 callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
149 }
150 final synchronized Activity getPendingActivityInstance() {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900151 CatLog.d(LOG_TAG, "getPendingActivityInstance act : " + mSlotId + ", " +
Wink Savillee68857d2014-10-17 15:23:05 -0700152 mActivityInstance);
153 return mActivityInstance;
154 }
155 final synchronized void setPendingDialogInstance(Activity act) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900156 CatLog.d(LOG_TAG, "setPendingDialogInstance act : " + mSlotId + ", " + act);
Wink Savillee68857d2014-10-17 15:23:05 -0700157 callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act);
158 }
159 final synchronized Activity getPendingDialogInstance() {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900160 CatLog.d(LOG_TAG, "getPendingDialogInstance act : " + mSlotId + ", " +
Wink Savillee68857d2014-10-17 15:23:05 -0700161 mDialogInstance);
162 return mDialogInstance;
163 }
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900164 final synchronized void setImmediateDialogInstance(Activity act) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900165 CatLog.d(LOG_TAG, "setImmediateDialogInstance act : " + mSlotId + ", " + act);
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900166 callSetActivityInstMsg(OP_SET_IMMED_DAL_INST, mSlotId, act);
167 }
168 final synchronized Activity getImmediateDialogInstance() {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900169 CatLog.d(LOG_TAG, "getImmediateDialogInstance act : " + mSlotId + ", " +
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900170 mImmediateDialogInstance);
171 return mImmediateDialogInstance;
172 }
Wink Savillee68857d2014-10-17 15:23:05 -0700173 }
174
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800175 private volatile Looper mServiceLooper;
176 private volatile ServiceHandler mServiceHandler;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800177 private Context mContext = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800178 private NotificationManager mNotificationManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800179 static StkAppService sInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700180 private AppInterface[] mStkService = null;
181 private StkContext[] mStkContext = null;
182 private int mSimCount = 0;
Malcolm Chen8c72f2f2020-01-10 15:57:10 -0800183 private HomeVisibilityObserver mHomeVisibilityObserver = null;
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +0900184 private BroadcastReceiver mLocaleChangeReceiver = null;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530185 private TonePlayer mTonePlayer = null;
186 private Vibrator mVibrator = null;
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900187 private BroadcastReceiver mUserActivityReceiver = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700188
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800189 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
190 // creating an intent.
191 private enum InitiatedByUserAction {
192 yes, // The action was started via a user initiated action
193 unknown, // Not known for sure if user initated the action
194 }
195
196 // constants
197 static final String OPCODE = "op";
198 static final String CMD_MSG = "cmd message";
199 static final String RES_ID = "response id";
200 static final String MENU_SELECTION = "menu selection";
201 static final String INPUT = "input";
202 static final String HELP = "help";
203 static final String CONFIRMATION = "confirm";
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500204 static final String CHOICE = "choice";
Wink Savillee68857d2014-10-17 15:23:05 -0700205 static final String SLOT_ID = "SLOT_ID";
206 static final String STK_CMD = "STK CMD";
207 static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/";
208 static final String STK_MENU_URI = "stk://com.android.stk/menu/";
209 static final String STK_INPUT_URI = "stk://com.android.stk/input/";
210 static final String STK_TONE_URI = "stk://com.android.stk/tone/";
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530211 static final String FINISH_TONE_ACTIVITY_ACTION =
212 "android.intent.action.stk.finish_activity";
Preeti Ahuja95919342013-10-01 18:18:55 -0700213
214 // These below constants are used for SETUP_EVENT_LIST
215 static final String SETUP_EVENT_TYPE = "event";
216 static final String SETUP_EVENT_CAUSE = "cause";
217
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800218 // operations ids for different service functionality.
219 static final int OP_CMD = 1;
220 static final int OP_RESPONSE = 2;
221 static final int OP_LAUNCH_APP = 3;
222 static final int OP_END_SESSION = 4;
223 static final int OP_BOOT_COMPLETED = 5;
224 private static final int OP_DELAYED_MSG = 6;
Wink Saville94e982b2014-07-11 07:38:14 -0700225 static final int OP_CARD_STATUS_CHANGED = 7;
Wink Savillee68857d2014-10-17 15:23:05 -0700226 static final int OP_SET_ACT_INST = 8;
227 static final int OP_SET_DAL_INST = 9;
Ryuto Sawada08c821c2016-08-08 18:29:02 +0900228 static final int OP_LOCALE_CHANGED = 10;
229 static final int OP_ALPHA_NOTIFY = 11;
230 static final int OP_IDLE_SCREEN = 12;
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900231 static final int OP_SET_IMMED_DAL_INST = 13;
Anna Suzukib1cee232019-02-21 12:52:27 +0900232 static final int OP_HOME_KEY_PRESSED = 14;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800233
Preeti Ahuja95919342013-10-01 18:18:55 -0700234 //Invalid SetupEvent
235 static final int INVALID_SETUP_EVENT = 0xFF;
236
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530237 // Message id to signal stop tone due to play tone timeout.
238 private static final int OP_STOP_TONE = 16;
239
240 // Message id to signal stop tone on user keyback.
241 static final int OP_STOP_TONE_USER = 17;
242
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900243 // Message id to send user activity event to card.
244 private static final int OP_USER_ACTIVITY = 20;
245
Malcolm Chen616ea282019-10-24 19:53:48 -0700246 // Message id that multi-SIM config has changed (ss <-> ds).
247 private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 21;
248
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800249 // Response ids
250 static final int RES_ID_MENU_SELECTION = 11;
251 static final int RES_ID_INPUT = 12;
252 static final int RES_ID_CONFIRM = 13;
253 static final int RES_ID_DONE = 14;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500254 static final int RES_ID_CHOICE = 15;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800255
256 static final int RES_ID_TIMEOUT = 20;
257 static final int RES_ID_BACKWARD = 21;
258 static final int RES_ID_END_SESSION = 22;
259 static final int RES_ID_EXIT = 23;
Srikanth Chintalaba103002015-11-30 10:49:52 -0800260 static final int RES_ID_ERROR = 24;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800261
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500262 static final int YES = 1;
263 static final int NO = 0;
264
Wink Savillee68857d2014-10-17 15:23:05 -0700265 static final int STATE_UNKNOWN = -1;
266 static final int STATE_NOT_EXIST = 0;
267 static final int STATE_EXIST = 1;
Wink Saville79085fc2009-06-09 10:27:23 -0700268
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900269 private static final Integer PLAY_TONE_ONLY = 0;
270 private static final Integer PLAY_TONE_WITH_DIALOG = 1;
271
Wink Savillee68857d2014-10-17 15:23:05 -0700272 private static final String PACKAGE_NAME = "com.android.stk";
273 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
274 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
275 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800276 // Notification id used to display Idle Mode text in NotificationManager.
277 private static final int STK_NOTIFICATION_ID = 333;
fionaxu2c91c752017-04-21 18:11:57 -0700278 // Notification channel containing all mobile service messages notifications.
279 private static final String STK_NOTIFICATION_CHANNEL_ID = "mobileServiceMessages";
280
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900281 private static final String LOG_TAG =
282 new Object(){}.getClass().getEnclosingClass().getSimpleName();
Wink Saville79085fc2009-06-09 10:27:23 -0700283
Takanori Nakano3776e2c2016-10-14 16:54:28 +0900284 static final String SESSION_ENDED = "session_ended";
285
Wink Saville79085fc2009-06-09 10:27:23 -0700286 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800287 // session end) while the service is busy processing a previous message.
288 private class DelayedCmd {
289 // members
290 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700291 CatCmdMessage msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700292 int slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800293
Wink Savillee68857d2014-10-17 15:23:05 -0700294 DelayedCmd(int id, CatCmdMessage msg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800295 this.id = id;
296 this.msg = msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700297 this.slotId = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800298 }
299 }
300
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700301 // system property to set the STK specific default url for launch browser proactive cmds
302 private static final String STK_BROWSER_DEFAULT_URL_SYSPROP = "persist.radio.stk.default_url";
303
Yuta Uife965802017-11-07 20:12:37 +0900304 private static final int NOTIFICATION_ON_KEYGUARD = 1;
305 private static final long[] VIBRATION_PATTERN = new long[] { 0, 350, 250, 350 };
306 private BroadcastReceiver mUserPresentReceiver = null;
307
Anna Suzukib1cee232019-02-21 12:52:27 +0900308 // The reason based on Intent.ACTION_CLOSE_SYSTEM_DIALOGS.
309 private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
310 private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
311 private BroadcastReceiver mHomeKeyEventReceiver = null;
312
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800313 @Override
314 public void onCreate() {
Wink Savillee68857d2014-10-17 15:23:05 -0700315 CatLog.d(LOG_TAG, "onCreate()+");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800316 // Initialize members
Wink Savillee68857d2014-10-17 15:23:05 -0700317 int i = 0;
318 mContext = getBaseContext();
Malcolm Chen616ea282019-10-24 19:53:48 -0700319 mSimCount = TelephonyManager.from(mContext).getActiveModemCount();
320 int maxSimCount = TelephonyManager.from(mContext).getSupportedModemCount();
Wink Savillee68857d2014-10-17 15:23:05 -0700321 CatLog.d(LOG_TAG, "simCount: " + mSimCount);
Malcolm Chen616ea282019-10-24 19:53:48 -0700322 mStkService = new AppInterface[maxSimCount];
323 mStkContext = new StkContext[maxSimCount];
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900324
Wink Savillee68857d2014-10-17 15:23:05 -0700325 for (i = 0; i < mSimCount; i++) {
326 CatLog.d(LOG_TAG, "slotId: " + i);
Legler Wuaeefef52014-10-27 00:57:18 +0800327 mStkService[i] = CatService.getInstance(i);
Wink Savillee68857d2014-10-17 15:23:05 -0700328 mStkContext[i] = new StkContext();
329 mStkContext[i].mSlotId = i;
330 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
331 }
332
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800333 Thread serviceThread = new Thread(null, this, "Stk App Service");
334 serviceThread.start();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800335 mNotificationManager = (NotificationManager) mContext
336 .getSystemService(Context.NOTIFICATION_SERVICE);
337 sInstance = this;
338 }
339
340 @Override
341 public void onStart(Intent intent, int startId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700342 if (intent == null) {
343 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530344 return;
345 }
346
Wink Savillee68857d2014-10-17 15:23:05 -0700347 Bundle args = intent.getExtras();
348 if (args == null) {
349 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
350 return;
351 }
352
353 int op = args.getInt(OPCODE);
354 int slotId = 0;
355 int i = 0;
356 if (op != OP_BOOT_COMPLETED) {
357 slotId = args.getInt(SLOT_ID);
358 }
Cuihtlauac ALVARADObde7f032015-05-29 16:25:12 +0200359 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", *****");
Wink Savillee68857d2014-10-17 15:23:05 -0700360 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +0800361 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -0700362 if (mStkService[slotId] == null) {
363 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
364 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
365 //Check other StkService state.
366 //If all StkServices are not available, stop itself and uninstall apk.
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +0900367 for (i = 0; i < mSimCount; i++) {
Wink Savillee68857d2014-10-17 15:23:05 -0700368 if (i != slotId
Tsukasa Goto029332b2016-10-05 17:12:06 +0900369 && (mStkService[i] != null)
Wink Savillee68857d2014-10-17 15:23:05 -0700370 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
371 || mStkContext[i].mStkServiceState == STATE_EXIST)) {
372 break;
373 }
374 }
375 } else {
376 mStkContext[slotId].mStkServiceState = STATE_EXIST;
377 }
378 if (i == mSimCount) {
379 stopSelf();
380 StkAppInstaller.unInstall(mContext);
381 return;
382 }
383 }
384
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530385 waitForLooper();
John Wang62acae42009-10-08 11:20:23 -0700386
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900387 Message msg = mServiceHandler.obtainMessage(op, 0, slotId);
388 switch (op) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800389 case OP_CMD:
390 msg.obj = args.getParcelable(CMD_MSG);
391 break;
392 case OP_RESPONSE:
Wink Saville94e982b2014-07-11 07:38:14 -0700393 case OP_CARD_STATUS_CHANGED:
Preeti Ahuja95919342013-10-01 18:18:55 -0700394 case OP_LOCALE_CHANGED:
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530395 case OP_ALPHA_NOTIFY:
Preeti Ahuja560be362014-11-25 19:38:24 -0800396 case OP_IDLE_SCREEN:
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900397 case OP_STOP_TONE_USER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800398 msg.obj = args;
399 /* falls through */
400 case OP_LAUNCH_APP:
401 case OP_END_SESSION:
402 case OP_BOOT_COMPLETED:
403 break;
404 default:
405 return;
406 }
407 mServiceHandler.sendMessage(msg);
408 }
409
410 @Override
411 public void onDestroy() {
Wink Savillee68857d2014-10-17 15:23:05 -0700412 CatLog.d(LOG_TAG, "onDestroy()");
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900413 unregisterUserActivityReceiver();
Malcolm Chen8c72f2f2020-01-10 15:57:10 -0800414 unregisterHomeVisibilityObserver();
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +0900415 unregisterLocaleChangeReceiver();
Anna Suzukib1cee232019-02-21 12:52:27 +0900416 unregisterHomeKeyEventReceiver();
Tsukasa Gotou54afbdd2016-01-07 16:30:20 +0900417 sInstance = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800418 waitForLooper();
Yoshiaki Nakaf70e3732020-01-24 18:57:22 +0900419 PhoneConfigurationManager.unregisterForMultiSimConfigChange(mServiceHandler);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800420 mServiceLooper.quit();
421 }
422
423 @Override
424 public IBinder onBind(Intent intent) {
425 return null;
426 }
427
428 public void run() {
429 Looper.prepare();
430
431 mServiceLooper = Looper.myLooper();
432 mServiceHandler = new ServiceHandler();
433
Yoshiaki Nakaf70e3732020-01-24 18:57:22 +0900434 PhoneConfigurationManager.registerForMultiSimConfigChange(mServiceHandler,
435 EVENT_MULTI_SIM_CONFIG_CHANGED, null);
436
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800437 Looper.loop();
438 }
439
440 /*
441 * Package api used by StkMenuActivity to indicate if its on the foreground.
442 */
Malcolm Chen616ea282019-10-24 19:53:48 -0700443 synchronized void indicateMenuVisibility(boolean visibility, int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700444 if (slotId >= 0 && slotId < mSimCount) {
445 mStkContext[slotId].mMenuIsVisible = visibility;
446 }
447 }
448
Preeti Ahuja95919342013-10-01 18:18:55 -0700449 /*
450 * Package api used by StkDialogActivity to indicate if its on the foreground.
451 */
Malcolm Chen616ea282019-10-24 19:53:48 -0700452 synchronized void setDisplayTextDlgVisibility(boolean visibility, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700453 if (slotId >= 0 && slotId < mSimCount) {
454 mStkContext[slotId].mDisplayTextDlgIsVisibile = visibility;
455 }
456 }
457
Malcolm Chen616ea282019-10-24 19:53:48 -0700458 synchronized boolean isInputPending(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700459 if (slotId >= 0 && slotId < mSimCount) {
460 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
461 return mStkContext[slotId].mIsInputPending;
462 }
463 return false;
464 }
465
Malcolm Chen616ea282019-10-24 19:53:48 -0700466 synchronized boolean isMenuPending(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700467 if (slotId >= 0 && slotId < mSimCount) {
468 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
469 return mStkContext[slotId].mIsMenuPending;
470 }
471 return false;
472 }
473
Malcolm Chen616ea282019-10-24 19:53:48 -0700474 synchronized boolean isDialogPending(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700475 if (slotId >= 0 && slotId < mSimCount) {
476 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
477 return mStkContext[slotId].mIsDialogPending;
478 }
479 return false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800480 }
481
Malcolm Chen616ea282019-10-24 19:53:48 -0700482 synchronized boolean isMainMenuAvailable(int slotId) {
Takanori Nakano3776e2c2016-10-14 16:54:28 +0900483 if (slotId >= 0 && slotId < mSimCount) {
484 // The main menu can handle the next user operation if the previous session finished.
485 return (mStkContext[slotId].lastSelectedItem == null) ? true : false;
486 }
487 return false;
488 }
489
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800490 /*
491 * Package api used by StkMenuActivity to get its Menu parameter.
492 */
Malcolm Chen616ea282019-10-24 19:53:48 -0700493 synchronized Menu getMenu(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700494 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
495 if (slotId >=0 && slotId < mSimCount) {
496 return mStkContext[slotId].mCurrentMenu;
497 } else {
498 return null;
499 }
500 }
501
502 /*
503 * Package api used by StkMenuActivity to get its Main Menu parameter.
504 */
Malcolm Chen616ea282019-10-24 19:53:48 -0700505 synchronized Menu getMainMenu(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700506 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
w30234a08cffe2015-02-04 15:13:25 -0800507 if (slotId >=0 && slotId < mSimCount && (mStkContext[slotId].mMainCmd != null)) {
Takanori Nakanoc8054ba2016-08-15 19:18:16 +0900508 Menu menu = mStkContext[slotId].mMainCmd.getMenu();
509 if (menu != null && mSimCount > PhoneConstants.MAX_PHONE_COUNT_SINGLE_SIM) {
510 // If alpha identifier or icon identifier with the self-explanatory qualifier is
511 // specified in SET-UP MENU command, it should be more prioritized than preset ones.
512 if (menu.title == null
513 && (menu.titleIcon == null || !menu.titleIconSelfExplanatory)) {
514 StkMenuConfig config = StkMenuConfig.getInstance(getApplicationContext());
515 String label = config.getLabel(slotId);
516 Bitmap icon = config.getIcon(slotId);
517 if (label != null || icon != null) {
518 Parcel parcel = Parcel.obtain();
519 menu.writeToParcel(parcel, 0);
520 parcel.setDataPosition(0);
521 menu = Menu.CREATOR.createFromParcel(parcel);
522 parcel.recycle();
523 menu.title = label;
524 menu.titleIcon = icon;
525 menu.titleIconSelfExplanatory = false;
526 }
527 }
528 }
529 return menu;
Wink Savillee68857d2014-10-17 15:23:05 -0700530 } else {
531 return null;
532 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800533 }
534
535 /*
536 * Package api used by UI Activities and Dialogs to communicate directly
537 * with the service to deliver state information and parameters.
538 */
539 static StkAppService getInstance() {
540 return sInstance;
541 }
542
543 private void waitForLooper() {
544 while (mServiceHandler == null) {
545 synchronized (this) {
546 try {
547 wait(100);
548 } catch (InterruptedException e) {
549 }
550 }
551 }
552 }
553
554 private final class ServiceHandler extends Handler {
555 @Override
556 public void handleMessage(Message msg) {
Wink Savillee68857d2014-10-17 15:23:05 -0700557 if(null == msg) {
558 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
559 return;
560 }
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900561 int opcode = msg.what;
Wink Savillee68857d2014-10-17 15:23:05 -0700562 int slotId = msg.arg2;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800563
Wink Savillee68857d2014-10-17 15:23:05 -0700564 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
565 if (opcode == OP_CMD && msg.obj != null &&
566 ((CatCmdMessage)msg.obj).getCmdType()!= null) {
567 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
568 }
Malcolm Chen7a9f2ad2019-11-06 11:07:09 -0800569 if (slotId >= mStkContext.length || mStkContext[slotId] == null) {
570 CatLog.d(LOG_TAG, "invalid slotId " + slotId);
571 return;
572 }
Malcolm Chen5e576402019-11-05 16:09:18 -0800573
Wink Savillee68857d2014-10-17 15:23:05 -0700574 mStkContext[slotId].mOpCode = opcode;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800575 switch (opcode) {
576 case OP_LAUNCH_APP:
Wink Savillee68857d2014-10-17 15:23:05 -0700577 if (mStkContext[slotId].mMainCmd == null) {
578 CatLog.d(LOG_TAG, "mMainCmd is null");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800579 // nothing todo when no SET UP MENU command didn't arrive.
580 return;
581 }
Wink Savillee68857d2014-10-17 15:23:05 -0700582 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
583 mStkContext[slotId].mCmdInProgress + "]");
584
585 //If there is a pending activity for the slot id,
586 //just finish it and create a new one to handle the pending command.
587 cleanUpInstanceStackBySlot(slotId);
588
Wink Savillee68857d2014-10-17 15:23:05 -0700589 CatLog.d(LOG_TAG, "Current cmd type: " +
590 mStkContext[slotId].mCurrentCmd.getCmdType());
591 //Restore the last command from stack by slot id.
592 restoreInstanceFromStackBySlot(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800593 break;
594 case OP_CMD:
Wink Savillee68857d2014-10-17 15:23:05 -0700595 CatLog.d(LOG_TAG, "[OP_CMD]");
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700596 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800597 // There are two types of commands:
598 // 1. Interactive - user's response is required.
599 // 2. Informative - display a message, no interaction with the user.
600 //
Wink Saville79085fc2009-06-09 10:27:23 -0700601 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800602 // Interactive commands can't override each other. So if a command
603 // is already in progress, we need to queue the next command until
604 // the user has responded or a timeout expired.
605 if (!isCmdInteractive(cmdMsg)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700606 handleCmd(cmdMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800607 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700608 if (!mStkContext[slotId].mCmdInProgress) {
609 mStkContext[slotId].mCmdInProgress = true;
610 handleCmd((CatCmdMessage) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800611 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700612 CatLog.d(LOG_TAG, "[Interactive][in progress]");
613 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
614 (CatCmdMessage) msg.obj, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800615 }
616 }
617 break;
618 case OP_RESPONSE:
Preeti Ahuja414bc412013-06-25 19:31:49 -0700619 handleCmdResponse((Bundle) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800620 // call delayed commands if needed.
Wink Savillee68857d2014-10-17 15:23:05 -0700621 if (mStkContext[slotId].mCmdsQ.size() != 0) {
622 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800623 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700624 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800625 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800626 break;
627 case OP_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700628 if (!mStkContext[slotId].mCmdInProgress) {
629 mStkContext[slotId].mCmdInProgress = true;
630 handleSessionEnd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800631 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700632 mStkContext[slotId].mCmdsQ.addLast(
633 new DelayedCmd(OP_END_SESSION, null, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800634 }
635 break;
636 case OP_BOOT_COMPLETED:
Wink Savillee68857d2014-10-17 15:23:05 -0700637 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
638 int i = 0;
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +0900639 for (i = 0; i < mSimCount; i++) {
Wink Savillee68857d2014-10-17 15:23:05 -0700640 if (mStkContext[i].mMainCmd != null) {
641 break;
642 }
643 }
644 if (i == mSimCount) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800645 StkAppInstaller.unInstall(mContext);
646 }
647 break;
648 case OP_DELAYED_MSG:
Wink Savillee68857d2014-10-17 15:23:05 -0700649 handleDelayedCmd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800650 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700651 case OP_CARD_STATUS_CHANGED:
Wink Savillee68857d2014-10-17 15:23:05 -0700652 CatLog.d(LOG_TAG, "Card/Icc Status change received");
653 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
654 break;
655 case OP_SET_ACT_INST:
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900656 Activity act = (Activity) msg.obj;
657 if (mStkContext[slotId].mActivityInstance != act) {
Yoshiaki Naka03a79d92018-08-09 18:41:31 +0900658 CatLog.d(LOG_TAG, "Set pending activity instance - " + act);
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900659 Activity previous = mStkContext[slotId].mActivityInstance;
660 mStkContext[slotId].mActivityInstance = act;
Yoshiaki Naka03a79d92018-08-09 18:41:31 +0900661 // Finish the previous one if it was replaced with new one
662 // but it has not been finished yet somehow.
663 if (act != null && previous != null && !previous.isDestroyed()
664 && !previous.isFinishing()) {
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900665 CatLog.d(LOG_TAG, "Finish the previous pending activity - " + previous);
666 previous.finish();
667 }
Anna Suzuki35309b02019-02-15 16:24:59 +0900668 }
669 // Clear pending dialog instance if it has not been cleared yet.
670 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
671 if (dialog != null && (dialog.isDestroyed() || dialog.isFinishing())) {
672 CatLog.d(LOG_TAG, "Clear pending dialog instance - " + dialog);
673 mStkContext[slotId].mDialogInstance = null;
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900674 }
Wink Savillee68857d2014-10-17 15:23:05 -0700675 break;
676 case OP_SET_DAL_INST:
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900677 Activity dal = (Activity) msg.obj;
Yoshiaki Nakaa1cea462018-08-09 20:33:36 +0900678 if (mStkContext[slotId].mDialogInstance != dal) {
679 CatLog.d(LOG_TAG, "Set pending dialog instance - " + dal);
680 mStkContext[slotId].mDialogInstance = dal;
681 }
Wink Savillee68857d2014-10-17 15:23:05 -0700682 break;
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900683 case OP_SET_IMMED_DAL_INST:
684 Activity immedDal = (Activity) msg.obj;
685 CatLog.d(LOG_TAG, "Set dialog instance for immediate response. " + immedDal);
686 mStkContext[slotId].mImmediateDialogInstance = immedDal;
687 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700688 case OP_LOCALE_CHANGED:
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900689 CatLog.d(LOG_TAG, "Locale Changed");
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +0900690 for (int slot = 0; slot < mSimCount; slot++) {
Yuta Ui1481b172016-02-03 15:34:31 +0900691 checkForSetupEvent(LANGUAGE_SELECTION_EVENT, (Bundle) msg.obj, slot);
692 }
fionaxu805eb572017-05-02 10:57:30 -0700693 // rename all registered notification channels on locale change
694 createAllChannels();
Preeti Ahuja95919342013-10-01 18:18:55 -0700695 break;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530696 case OP_ALPHA_NOTIFY:
697 handleAlphaNotify((Bundle) msg.obj);
698 break;
Preeti Ahuja560be362014-11-25 19:38:24 -0800699 case OP_IDLE_SCREEN:
700 for (int slot = 0; slot < mSimCount; slot++) {
701 if (mStkContext[slot] != null) {
702 handleIdleScreen(slot);
703 }
704 }
705 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530706 case OP_STOP_TONE_USER:
707 case OP_STOP_TONE:
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900708 CatLog.d(LOG_TAG, "Stop tone");
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530709 handleStopTone(msg, slotId);
710 break;
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900711 case OP_USER_ACTIVITY:
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +0900712 for (int slot = 0; slot < mSimCount; slot++) {
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900713 checkForSetupEvent(USER_ACTIVITY_EVENT, null, slot);
714 }
715 break;
Malcolm Chen616ea282019-10-24 19:53:48 -0700716 case EVENT_MULTI_SIM_CONFIG_CHANGED:
717 handleMultiSimConfigChanged();
718 break;
Anna Suzukib1cee232019-02-21 12:52:27 +0900719 case OP_HOME_KEY_PRESSED:
720 CatLog.d(LOG_TAG, "Process the home key pressed event");
721 for (int slot = 0; slot < mSimCount; slot++) {
722 if (mStkContext[slot] != null) {
723 handleHomeKeyPressed(slot);
724 }
725 }
726 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700727 }
728 }
729
Wink Savillee68857d2014-10-17 15:23:05 -0700730 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
Wink Saville94e982b2014-07-11 07:38:14 -0700731 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
732
Wink Savillee68857d2014-10-17 15:23:05 -0700733 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
Wink Saville94e982b2014-07-11 07:38:14 -0700734 if (cardStatus == false) {
Wink Savillee68857d2014-10-17 15:23:05 -0700735 CatLog.d(LOG_TAG, "CARD is ABSENT");
Wink Saville94e982b2014-07-11 07:38:14 -0700736 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900737 cancelIdleText(slotId);
Srikanth Chintala7c5a04c2016-09-22 19:05:01 +0530738 mStkContext[slotId].mCurrentMenu = null;
739 mStkContext[slotId].mMainCmd = null;
Sandeep Gutta670b7a92018-09-17 18:55:34 +0530740 mStkService[slotId] = null;
Takanori Nakanob82c8752019-04-01 14:47:07 +0900741 // Stop the tone currently being played if the relevant SIM is removed or disabled.
742 if (mStkContext[slotId].mCurrentCmd != null
743 && mStkContext[slotId].mCurrentCmd.getCmdType().value()
744 == AppInterface.CommandType.PLAY_TONE.value()) {
745 terminateTone(slotId);
746 }
Wink Savillee68857d2014-10-17 15:23:05 -0700747 if (isAllOtherCardsAbsent(slotId)) {
748 CatLog.d(LOG_TAG, "All CARDs are ABSENT");
749 StkAppInstaller.unInstall(mContext);
750 stopSelf();
751 }
Wink Saville94e982b2014-07-11 07:38:14 -0700752 } else {
753 IccRefreshResponse state = new IccRefreshResponse();
754 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
755
Wink Savillee68857d2014-10-17 15:23:05 -0700756 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
Wink Saville94e982b2014-07-11 07:38:14 -0700757 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
758 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
759 // Clear Idle Text
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900760 cancelIdleText(slotId);
Wink Saville94e982b2014-07-11 07:38:14 -0700761 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800762 }
763 }
764 }
Malcolm Chen616ea282019-10-24 19:53:48 -0700765
766 private synchronized void handleMultiSimConfigChanged() {
767 int oldSimCount = mSimCount;
768 mSimCount = TelephonyManager.from(mContext).getActiveModemCount();
769 for (int i = oldSimCount; i < mSimCount; i++) {
770 CatLog.d(LOG_TAG, "slotId: " + i);
771 mStkService[i] = CatService.getInstance(i);
772 mStkContext[i] = new StkContext();
773 mStkContext[i].mSlotId = i;
774 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
775 }
776
777 for (int i = mSimCount; i < oldSimCount; i++) {
778 CatLog.d(LOG_TAG, "slotId: " + i);
779 if (mStkService[i] != null) {
780 mStkService[i].dispose();
781 mStkService[i] = null;
782 }
783 mStkContext[i] = null;
784 }
785 }
786
Wink Savillee68857d2014-10-17 15:23:05 -0700787 /*
788 * Check if all SIMs are absent except the id of slot equals "slotId".
789 */
790 private boolean isAllOtherCardsAbsent(int slotId) {
791 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
792 Context.TELEPHONY_SERVICE);
793 int i = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800794
Wink Savillee68857d2014-10-17 15:23:05 -0700795 for (i = 0; i < mSimCount; i++) {
796 if (i != slotId && mTm.hasIccCard(i)) {
797 break;
798 }
799 }
800 if (i == mSimCount) {
801 return true;
802 } else {
803 return false;
804 }
805 }
Preeti Ahuja95919342013-10-01 18:18:55 -0700806
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900807 /* package */ boolean isScreenIdle() {
808 ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
809 List<RunningTaskInfo> tasks = am.getRunningTasks(1);
810 if (tasks == null || tasks.isEmpty()) {
811 return false;
812 }
813
814 String top = tasks.get(0).topActivity.getPackageName();
815 if (top == null) {
816 return false;
817 }
818
819 // We can assume that the screen is idle if the home application is in the foreground.
820 final Intent intent = new Intent(Intent.ACTION_MAIN, null);
821 intent.addCategory(Intent.CATEGORY_HOME);
822
823 ResolveInfo info = getPackageManager().resolveActivity(intent,
824 PackageManager.MATCH_DEFAULT_ONLY);
825 if (info != null) {
826 if (top.equals(info.activityInfo.packageName)) {
827 return true;
828 }
829 }
830
831 return false;
Preeti Ahuja560be362014-11-25 19:38:24 -0800832 }
833
Anna Suzukib1cee232019-02-21 12:52:27 +0900834 private synchronized void startToObserveHomeKeyEvent(int slotId) {
835 if (mStkContext[slotId].mIsSessionFromUser || mHomeKeyEventReceiver != null) {
836 return;
837 }
838 mHomeKeyEventReceiver = new BroadcastReceiver() {
839 @Override public void onReceive(Context context, Intent intent) {
840 if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(
841 intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY))) {
842 Message message = mServiceHandler.obtainMessage();
843 message.arg1 = OP_HOME_KEY_PRESSED;
844 mServiceHandler.sendMessage(message);
Takanori Nakano43dacc02018-07-26 11:27:39 +0900845 }
Anna Suzukib1cee232019-02-21 12:52:27 +0900846 }
847 };
848 CatLog.d(LOG_TAG, "Started to observe home key event");
849 registerReceiver(mHomeKeyEventReceiver,
850 new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
851 }
852
853 private synchronized void unregisterHomeKeyEventReceiver() {
854 if (mHomeKeyEventReceiver != null) {
855 CatLog.d(LOG_TAG, "Stopped to observe home key event");
856 unregisterReceiver(mHomeKeyEventReceiver);
857 mHomeKeyEventReceiver = null;
858 }
859 if (mServiceHandler != null) {
860 mServiceHandler.removeMessages(OP_HOME_KEY_PRESSED);
861 }
862 }
863
864 private void handleHomeKeyPressed(int slotId) {
865 // It might be hard for user to recognize that the dialog or screens belong to SIM Toolkit
866 // application if the current session was not initiated by user but by the SIM card,
867 // so it is recommended to send TERMINAL RESPONSE if user press the home key.
868 if (!mStkContext[slotId].mIsSessionFromUser) {
869 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
870 Activity activity = mStkContext[slotId].getPendingActivityInstance();
871 if (dialog != null) {
872 dialog.finish();
873 mStkContext[slotId].mDialogInstance = null;
874 } else if (activity != null) {
875 activity.finish();
876 mStkContext[slotId].mActivityInstance = null;
Takanori Nakano43dacc02018-07-26 11:27:39 +0900877 }
878 }
879 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800880
Takanori Nakano43dacc02018-07-26 11:27:39 +0900881 private void handleIdleScreen(int slotId) {
Preeti Ahuja560be362014-11-25 19:38:24 -0800882 // If the idle screen event is present in the list need to send the
883 // response to SIM.
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900884 CatLog.d(LOG_TAG, "Need to send IDLE SCREEN Available event to SIM");
Preeti Ahuja560be362014-11-25 19:38:24 -0800885 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
886
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900887 if (mStkContext[slotId].mIdleModeTextCmd != null
888 && !mStkContext[slotId].mIdleModeTextVisible) {
889 launchIdleText(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -0800890 }
891 }
892
893 private void sendScreenBusyResponse(int slotId) {
894 if (mStkContext[slotId].mCurrentCmd == null) {
895 return;
896 }
897 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900898 CatLog.d(LOG_TAG, "SCREEN_BUSY");
Preeti Ahuja560be362014-11-25 19:38:24 -0800899 resMsg.setResultCode(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS);
900 mStkService[slotId].onCmdResponse(resMsg);
901 if (mStkContext[slotId].mCmdsQ.size() != 0) {
902 callDelayedMsg(slotId);
903 } else {
904 mStkContext[slotId].mCmdInProgress = false;
905 }
906 }
907
Takanori Nakano43dacc02018-07-26 11:27:39 +0900908 /**
909 * Sends TERMINAL RESPONSE or ENVELOPE
910 *
911 * @param args detailed parameters of the response
912 * @param slotId slot identifier
913 */
914 public void sendResponse(Bundle args, int slotId) {
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900915 Message msg = mServiceHandler.obtainMessage(OP_RESPONSE, 0, slotId, args);
Takanori Nakano43dacc02018-07-26 11:27:39 +0900916 mServiceHandler.sendMessage(msg);
917 }
918
Preeti Ahuja95919342013-10-01 18:18:55 -0700919 private void sendResponse(int resId, int slotId, boolean confirm) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700920 Bundle args = new Bundle();
921 args.putInt(StkAppService.RES_ID, resId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700922 args.putBoolean(StkAppService.CONFIRMATION, confirm);
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900923 sendResponse(args, slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700924 }
925
Takanori Nakanob82c8752019-04-01 14:47:07 +0900926 private void terminateTone(int slotId) {
927 Message msg = new Message();
928 msg.what = OP_STOP_TONE;
929 msg.obj = mServiceHandler.hasMessages(OP_STOP_TONE, PLAY_TONE_WITH_DIALOG)
930 ? PLAY_TONE_WITH_DIALOG : PLAY_TONE_ONLY;
931 handleStopTone(msg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800932 }
933
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700934 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800935 switch (cmd.getCmdType()) {
936 case SEND_DTMF:
937 case SEND_SMS:
Yoshiaki.Naka7f74e022017-11-25 16:42:39 +0900938 case REFRESH:
Avinash Nalluri3fcea522017-10-18 16:20:49 -0700939 case RUN_AT:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800940 case SEND_SS:
941 case SEND_USSD:
942 case SET_UP_IDLE_MODE_TEXT:
943 case SET_UP_MENU:
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500944 case CLOSE_CHANNEL:
945 case RECEIVE_DATA:
946 case SEND_DATA:
Preeti Ahuja95919342013-10-01 18:18:55 -0700947 case SET_UP_EVENT_LIST:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800948 return false;
949 }
950
951 return true;
952 }
953
Wink Savillee68857d2014-10-17 15:23:05 -0700954 private void handleDelayedCmd(int slotId) {
955 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
956 if (mStkContext[slotId].mCmdsQ.size() != 0) {
957 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
958 if (cmd != null) {
959 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
960 mStkContext[slotId].mCmdsQ.size() +
961 " id: " + cmd.id + "sim id: " + cmd.slotId);
962 switch (cmd.id) {
963 case OP_CMD:
964 handleCmd(cmd.msg, cmd.slotId);
965 break;
966 case OP_END_SESSION:
967 handleSessionEnd(cmd.slotId);
968 break;
969 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800970 }
971 }
972 }
973
Wink Savillee68857d2014-10-17 15:23:05 -0700974 private void callDelayedMsg(int slotId) {
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900975 Message msg = mServiceHandler.obtainMessage(OP_DELAYED_MSG, 0, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800976 mServiceHandler.sendMessage(msg);
977 }
978
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900979 private void callSetActivityInstMsg(int opcode, int slotId, Object obj) {
980 Message msg = mServiceHandler.obtainMessage(opcode, 0, slotId, obj);
Wink Savillee68857d2014-10-17 15:23:05 -0700981 mServiceHandler.sendMessage(msg);
982 }
983
984 private void handleSessionEnd(int slotId) {
Legler Wuaeefef52014-10-27 00:57:18 +0800985 // We should finish all pending activity if receiving END SESSION command.
986 cleanUpInstanceStackBySlot(slotId);
987
Wink Savillee68857d2014-10-17 15:23:05 -0700988 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
989 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
990 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
991 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
992 mStkContext[slotId].mMenuState);
993
994 mStkContext[slotId].mIsInputPending = false;
995 mStkContext[slotId].mIsMenuPending = false;
996 mStkContext[slotId].mIsDialogPending = false;
Yuta Uife965802017-11-07 20:12:37 +0900997 mStkContext[slotId].mNoResponseFromUser = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700998
Wink Savillee68857d2014-10-17 15:23:05 -0700999 if (mStkContext[slotId].mMainCmd == null) {
1000 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
1001 }
1002 mStkContext[slotId].lastSelectedItem = null;
Takanori Nakano43dacc02018-07-26 11:27:39 +09001003 mStkContext[slotId].mIsSessionFromUser = false;
Wink Saville79085fc2009-06-09 10:27:23 -07001004 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001005 // update the current menu member.
Wink Savillee68857d2014-10-17 15:23:05 -07001006 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
1007 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001008 }
Wink Savillee68857d2014-10-17 15:23:05 -07001009 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
Ryuto Sawada08c821c2016-08-08 18:29:02 +09001010
Wink Savillee68857d2014-10-17 15:23:05 -07001011 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
Ryuto Sawada08c821c2016-08-08 18:29:02 +09001012 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001013 }
Takanori Nakano3776e2c2016-10-14 16:54:28 +09001014
1015 // Send a local broadcast as a notice that this service handled the session end event.
1016 Intent intent = new Intent(SESSION_ENDED);
1017 intent.putExtra(SLOT_ID, slotId);
1018 LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
1019
Wink Savillee68857d2014-10-17 15:23:05 -07001020 if (mStkContext[slotId].mCmdsQ.size() != 0) {
1021 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001022 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001023 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001024 }
1025 // In case a launch browser command was just confirmed, launch that url.
Wink Savillee68857d2014-10-17 15:23:05 -07001026 if (mStkContext[slotId].launchBrowser) {
1027 mStkContext[slotId].launchBrowser = false;
1028 launchBrowser(mStkContext[slotId].mBrowserSettings);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001029 }
1030 }
1031
Preeti Ahuja560be362014-11-25 19:38:24 -08001032 // returns true if any Stk related activity already has focus on the screen
Yoshiaki Nakacec55b82017-10-20 15:53:43 +09001033 boolean isTopOfStack() {
pkanwareab12f32017-02-06 08:35:03 -08001034 ActivityManager mActivityManager = (ActivityManager) mContext
Preeti Ahuja560be362014-11-25 19:38:24 -08001035 .getSystemService(ACTIVITY_SERVICE);
pkanwareab12f32017-02-06 08:35:03 -08001036 String currentPackageName = null;
1037 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
1038 if (tasks == null || tasks.get(0).topActivity == null) {
1039 return false;
1040 }
1041 currentPackageName = tasks.get(0).topActivity.getPackageName();
Preeti Ahuja560be362014-11-25 19:38:24 -08001042 if (null != currentPackageName) {
1043 return currentPackageName.equals(PACKAGE_NAME);
1044 }
Preeti Ahuja560be362014-11-25 19:38:24 -08001045 return false;
1046 }
1047
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001048 /**
1049 * Get the boolean config from carrier config manager.
1050 *
Yukiko Fujimura913c1432019-02-21 17:14:30 +09001051 * @param context the context to get carrier service
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001052 * @param key config key defined in CarrierConfigManager
Yoshiaki Naka028bb092018-08-30 16:57:47 +09001053 * @param slotId slot ID.
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001054 * @return boolean value of corresponding key.
1055 */
Yukiko Fujimura913c1432019-02-21 17:14:30 +09001056 /* package */ static boolean getBooleanCarrierConfig(Context context, String key, int slotId) {
1057 CarrierConfigManager ccm = (CarrierConfigManager) context.getSystemService(
1058 Context.CARRIER_CONFIG_SERVICE);
1059 SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
Yoshiaki Naka30d5a812018-11-12 12:43:34 +09001060 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001061 PersistableBundle b = null;
Yoshiaki Naka30d5a812018-11-12 12:43:34 +09001062 if (ccm != null && sm != null) {
1063 SubscriptionInfo info = sm.getActiveSubscriptionInfoForSimSlotIndex(slotId);
1064 if (info != null) {
1065 b = ccm.getConfigForSubId(info.getSubscriptionId());
1066 }
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001067 }
1068 if (b != null) {
1069 return b.getBoolean(key);
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001070 }
Yoshiaki Naka028bb092018-08-30 16:57:47 +09001071 // Return static default defined in CarrierConfigManager.
1072 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001073 }
1074
Yukiko Fujimura913c1432019-02-21 17:14:30 +09001075 private boolean getBooleanCarrierConfig(String key, int slotId) {
1076 return getBooleanCarrierConfig(this, key, slotId);
1077 }
1078
Wink Savillee68857d2014-10-17 15:23:05 -07001079 private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -07001080
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001081 if (cmdMsg == null) {
1082 return;
1083 }
1084 // save local reference for state tracking.
Wink Savillee68857d2014-10-17 15:23:05 -07001085 mStkContext[slotId].mCurrentCmd = cmdMsg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001086 boolean waitForUsersResponse = true;
1087
Wink Savillee68857d2014-10-17 15:23:05 -07001088 mStkContext[slotId].mIsInputPending = false;
1089 mStkContext[slotId].mIsMenuPending = false;
1090 mStkContext[slotId].mIsDialogPending = false;
1091
1092 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001093 switch (cmdMsg.getCmdType()) {
1094 case DISPLAY_TEXT:
1095 TextMessage msg = cmdMsg.geTextMessage();
Jeevaka Badrappan854a25c2012-12-01 16:32:03 +02001096 waitForUsersResponse = msg.responseNeeded;
Wink Savillee68857d2014-10-17 15:23:05 -07001097 if (mStkContext[slotId].lastSelectedItem != null) {
1098 msg.title = mStkContext[slotId].lastSelectedItem;
1099 } else if (mStkContext[slotId].mMainCmd != null){
Yoshiaki Naka28313ba2017-08-04 12:20:53 +09001100 if (!getResources().getBoolean(R.bool.show_menu_title_only_on_menu)) {
1101 msg.title = mStkContext[slotId].mMainCmd.getMenu().title;
1102 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001103 }
Preeti Ahuja560be362014-11-25 19:38:24 -08001104 //If we receive a low priority Display Text and the device is
1105 // not displaying any STK related activity and the screen is not idle
1106 // ( that is, device is in an interactive state), then send a screen busy
1107 // terminal response. Otherwise display the message. The existing
1108 // displayed message shall be updated with the new display text
1109 // proactive command (Refer to ETSI TS 102 384 section 27.22.4.1.4.4.2).
1110 if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible
1111 || mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) {
1112 if(!isScreenIdle()) {
1113 CatLog.d(LOG_TAG, "Screen is not idle");
1114 sendScreenBusyResponse(slotId);
1115 } else {
1116 launchTextDialog(slotId);
1117 }
1118 } else {
1119 launchTextDialog(slotId);
1120 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001121 break;
1122 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -07001123 CatLog.d(LOG_TAG, "SELECT_ITEM +");
1124 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
1125 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
1126 launchMenuActivity(cmdMsg.getMenu(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001127 break;
1128 case SET_UP_MENU:
Wink Savillee68857d2014-10-17 15:23:05 -07001129 mStkContext[slotId].mCmdInProgress = false;
1130 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
1131 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
1132 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
1133 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
1134
1135 if (removeMenu(slotId)) {
1136 int i = 0;
1137 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App");
1138 mStkContext[slotId].mCurrentMenu = null;
Preeti Ahuja95919342013-10-01 18:18:55 -07001139 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -07001140 //Check other setup menu state. If all setup menu are removed, uninstall apk.
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +09001141 for (i = 0; i < mSimCount; i++) {
Yoshiaki Naka3c423002018-08-28 15:17:49 +09001142 if (i != slotId && mStkContext[i].mSetupMenuState != STATE_NOT_EXIST) {
Wink Savillee68857d2014-10-17 15:23:05 -07001143 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +09001144 + mStkContext[i].mSetupMenuState);
Wink Savillee68857d2014-10-17 15:23:05 -07001145 break;
1146 }
1147 }
1148 if (i == mSimCount) {
1149 StkAppInstaller.unInstall(mContext);
1150 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001151 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001152 CatLog.d(LOG_TAG, "install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001153 StkAppInstaller.install(mContext);
1154 }
Wink Savillee68857d2014-10-17 15:23:05 -07001155 if (mStkContext[slotId].mMenuIsVisible) {
1156 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001157 }
1158 break;
1159 case GET_INPUT:
1160 case GET_INKEY:
Wink Savillee68857d2014-10-17 15:23:05 -07001161 launchInputActivity(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001162 break;
1163 case SET_UP_IDLE_MODE_TEXT:
1164 waitForUsersResponse = false;
Preeti Ahuja560be362014-11-25 19:38:24 -08001165 mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd;
1166 TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001167 if (idleModeText == null || TextUtils.isEmpty(idleModeText.text)) {
1168 cancelIdleText(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -08001169 }
1170 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001171 if (mStkContext[slotId].mIdleModeTextCmd != null) {
1172 if (mStkContext[slotId].mIdleModeTextVisible || isScreenIdle()) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001173 CatLog.d(LOG_TAG, "set up idle mode");
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001174 launchIdleText(slotId);
1175 } else {
Malcolm Chen8c72f2f2020-01-10 15:57:10 -08001176 registerHomeVisibilityObserver();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001177 }
Preeti Ahuja560be362014-11-25 19:38:24 -08001178 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001179 break;
1180 case SEND_DTMF:
1181 case SEND_SMS:
Yoshiaki.Naka7f74e022017-11-25 16:42:39 +09001182 case REFRESH:
Avinash Nalluri3fcea522017-10-18 16:20:49 -07001183 case RUN_AT:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001184 case SEND_SS:
1185 case SEND_USSD:
Preeti Ahuja95919342013-10-01 18:18:55 -07001186 case GET_CHANNEL_STATUS:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001187 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -07001188 launchEventMessage(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001189 break;
1190 case LAUNCH_BROWSER:
Ryuto Sawada0bdc7192016-04-18 12:10:56 +09001191 // The device setup process should not be interrupted by launching browser.
1192 if (Settings.Global.getInt(mContext.getContentResolver(),
1193 Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001194 CatLog.d(LOG_TAG, "Not perform if the setup process has not been completed.");
Ryuto Sawada0bdc7192016-04-18 12:10:56 +09001195 sendScreenBusyResponse(slotId);
1196 break;
1197 }
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001198
1199 /* Check if Carrier would not want to launch browser */
Yoshiaki Naka028bb092018-08-30 16:57:47 +09001200 if (getBooleanCarrierConfig(CarrierConfigManager.KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL,
1201 slotId)) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001202 CatLog.d(LOG_TAG, "Browser is not launched as per carrier.");
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001203 sendResponse(RES_ID_DONE, slotId, true);
1204 break;
1205 }
1206
Srikanth Chintalaba103002015-11-30 10:49:52 -08001207 mStkContext[slotId].mBrowserSettings =
1208 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
1209 if (!isUrlAvailableToLaunchBrowser(mStkContext[slotId].mBrowserSettings)) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001210 CatLog.d(LOG_TAG, "Browser url property is not set - send error");
Srikanth Chintalaba103002015-11-30 10:49:52 -08001211 sendResponse(RES_ID_ERROR, slotId, true);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001212 } else {
Srikanth Chintalaba103002015-11-30 10:49:52 -08001213 TextMessage alphaId = mStkContext[slotId].mCurrentCmd.geTextMessage();
1214 if ((alphaId == null) || TextUtils.isEmpty(alphaId.text)) {
1215 // don't need user confirmation in this case
1216 // just launch the browser or spawn a new tab
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001217 CatLog.d(LOG_TAG, "user confirmation is not currently needed.\n" +
Srikanth Chintalaba103002015-11-30 10:49:52 -08001218 "supressing confirmation dialogue and confirming silently...");
1219 mStkContext[slotId].launchBrowser = true;
1220 sendResponse(RES_ID_CONFIRM, slotId, true);
1221 } else {
1222 launchConfirmationDialog(alphaId, slotId);
1223 }
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001224 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001225 break;
1226 case SET_UP_CALL:
Preeti Ahujadd240102013-08-30 17:25:06 -07001227 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg;
1228 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) {
1229 mesg.text = getResources().getString(R.string.default_setup_call_msg);
1230 }
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001231 CatLog.d(LOG_TAG, "SET_UP_CALL mesg.text " + mesg.text);
Preeti Ahujadd240102013-08-30 17:25:06 -07001232 launchConfirmationDialog(mesg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001233 break;
1234 case PLAY_TONE:
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301235 handlePlayTone(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001236 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001237 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -07001238 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001239 break;
1240 case CLOSE_CHANNEL:
1241 case RECEIVE_DATA:
1242 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -07001243 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001244
1245 if ((m != null) && (m.text == null)) {
1246 switch(cmdMsg.getCmdType()) {
1247 case CLOSE_CHANNEL:
1248 m.text = getResources().getString(R.string.default_close_channel_msg);
1249 break;
1250 case RECEIVE_DATA:
1251 m.text = getResources().getString(R.string.default_receive_data_msg);
1252 break;
1253 case SEND_DATA:
1254 m.text = getResources().getString(R.string.default_send_data_msg);
1255 break;
1256 }
1257 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001258 /*
1259 * Display indication in the form of a toast to the user if required.
1260 */
Wink Savillee68857d2014-10-17 15:23:05 -07001261 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001262 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001263 case SET_UP_EVENT_LIST:
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001264 replaceEventList(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -08001265 if (isScreenIdle()) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001266 CatLog.d(LOG_TAG," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List");
Preeti Ahuja560be362014-11-25 19:38:24 -08001267 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
1268 }
Preeti Ahuja95919342013-10-01 18:18:55 -07001269 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001270 }
1271
1272 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -07001273 if (mStkContext[slotId].mCmdsQ.size() != 0) {
1274 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001275 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001276 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001277 }
1278 }
1279 }
1280
Takanori Nakano43dacc02018-07-26 11:27:39 +09001281 @SuppressWarnings("FallThrough")
Wink Savillee68857d2014-10-17 15:23:05 -07001282 private void handleCmdResponse(Bundle args, int slotId) {
1283 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
Anna Suzukib1cee232019-02-21 12:52:27 +09001284 unregisterHomeKeyEventReceiver();
Wink Savillee68857d2014-10-17 15:23:05 -07001285 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001286 return;
1287 }
Wink Savillee68857d2014-10-17 15:23:05 -07001288
1289 if (mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +08001290 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001291 if (mStkService[slotId] == null) {
Takanori Nakanoeeed5db2019-04-08 12:21:29 +09001292 // CatService is disposed when the relevant SIM is removed or disabled.
1293 // StkAppService can also be stopped when the absent state is notified,
1294 // so this situation can happen.
1295 CatLog.d(LOG_TAG, "No response is sent back to the missing CatService.");
1296 return;
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001297 }
1298 }
1299
Wink Savillee68857d2014-10-17 15:23:05 -07001300 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001301
1302 // set result code
1303 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001304 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001305
1306 switch(args.getInt(RES_ID)) {
1307 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -07001308 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
1309 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001310 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -07001311 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001312 case SET_UP_MENU:
Takanori Nakano43dacc02018-07-26 11:27:39 +09001313 mStkContext[slotId].mIsSessionFromUser = true;
1314 // Fall through
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001315 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -07001316 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001317 if (helpRequired) {
1318 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1319 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301320 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1321 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001322 }
1323 resMsg.setMenuSelection(menuSelection);
1324 break;
1325 }
1326 break;
1327 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001328 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001329 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -07001330 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
1331 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001332 boolean yesNoSelection = input
1333 .equals(StkInputActivity.YES_STR_RESPONSE);
1334 resMsg.setYesNo(yesNoSelection);
1335 } else {
1336 if (helpRequired) {
1337 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1338 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301339 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1340 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001341 resMsg.setInput(input);
1342 }
1343 }
1344 break;
1345 case RES_ID_CONFIRM:
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001346 CatLog.d(LOG_TAG, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001347 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -07001348 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001349 case DISPLAY_TEXT:
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301350 if (confirmed) {
1351 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1352 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
1353 } else {
1354 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1355 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001356 break;
1357 case LAUNCH_BROWSER:
1358 resMsg.setResultCode(confirmed ? ResultCode.OK
1359 : ResultCode.UICC_SESSION_TERM_BY_USER);
1360 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001361 mStkContext[slotId].launchBrowser = true;
1362 mStkContext[slotId].mBrowserSettings =
1363 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001364 }
1365 break;
1366 case SET_UP_CALL:
1367 resMsg.setResultCode(ResultCode.OK);
1368 resMsg.setConfirmation(confirmed);
1369 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001370 launchEventMessage(slotId,
1371 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001372 }
1373 break;
1374 }
1375 break;
1376 case RES_ID_DONE:
1377 resMsg.setResultCode(ResultCode.OK);
1378 break;
1379 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -07001380 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001381 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
1382 break;
1383 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -07001384 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001385 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1386 break;
1387 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001388 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -08001389 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
1390 // Clear message after delay, successful) expects result code OK.
1391 // If the command qualifier specifies no user response is required
1392 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -07001393 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1394 AppInterface.CommandType.DISPLAY_TEXT.value())
1395 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -08001396 resMsg.setResultCode(ResultCode.OK);
1397 } else {
1398 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
1399 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001400 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001401 case RES_ID_CHOICE:
1402 int choice = args.getInt(CHOICE);
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001403 CatLog.d(LOG_TAG, "User Choice=" + choice);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001404 switch (choice) {
1405 case YES:
1406 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001407 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001408 break;
1409 case NO:
1410 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
1411 break;
1412 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001413
Wink Savillee68857d2014-10-17 15:23:05 -07001414 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1415 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001416 resMsg.setConfirmation(confirmed);
1417 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001418 break;
Srikanth Chintalaba103002015-11-30 10:49:52 -08001419 case RES_ID_ERROR:
1420 CatLog.d(LOG_TAG, "RES_ID_ERROR");
1421 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
1422 case LAUNCH_BROWSER:
1423 resMsg.setResultCode(ResultCode.LAUNCH_BROWSER_ERROR);
1424 break;
1425 }
1426 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001427 default:
Wink Savillee68857d2014-10-17 15:23:05 -07001428 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001429 return;
1430 }
Wink Savillee68857d2014-10-17 15:23:05 -07001431
Yuta Uife965802017-11-07 20:12:37 +09001432 switch (args.getInt(RES_ID)) {
1433 case RES_ID_MENU_SELECTION:
1434 case RES_ID_INPUT:
1435 case RES_ID_CONFIRM:
1436 case RES_ID_CHOICE:
1437 case RES_ID_BACKWARD:
1438 case RES_ID_END_SESSION:
1439 mStkContext[slotId].mNoResponseFromUser = false;
1440 break;
1441 case RES_ID_TIMEOUT:
1442 cancelNotificationOnKeyguard(slotId);
1443 mStkContext[slotId].mNoResponseFromUser = true;
1444 break;
1445 default:
1446 // The other IDs cannot be used to judge if there is no response from user.
1447 break;
1448 }
1449
Wink Savillee68857d2014-10-17 15:23:05 -07001450 if (null != mStkContext[slotId].mCurrentCmd &&
1451 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1452 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1453 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1454 }
1455 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001456 }
1457
1458 /**
1459 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1460 *
1461 * @param userAction If the userAction is yes then we always return 0 otherwise
1462 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1463 * then we are the foreground app and we'll return 0 as from our perspective a
1464 * user action did cause. If it's false than we aren't the foreground app and
1465 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001466 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001467 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1468 */
Wink Savillee68857d2014-10-17 15:23:05 -07001469 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1470 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1471 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1472 }
1473 /**
1474 * This method is used for cleaning up pending instances in stack.
Takanori Nakano28ce8b62018-02-22 12:10:44 +09001475 * No terminal response will be sent for pending instances.
Wink Savillee68857d2014-10-17 15:23:05 -07001476 */
1477 private void cleanUpInstanceStackBySlot(int slotId) {
1478 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1479 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1480 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
1481 if (activity != null) {
Takanori Nakano28ce8b62018-02-22 12:10:44 +09001482 if (mStkContext[slotId].mCurrentCmd != null) {
1483 CatLog.d(LOG_TAG, "current cmd type: " +
1484 mStkContext[slotId].mCurrentCmd.getCmdType());
1485 if (mStkContext[slotId].mCurrentCmd.getCmdType().value()
1486 == AppInterface.CommandType.GET_INPUT.value()
1487 || mStkContext[slotId].mCurrentCmd.getCmdType().value()
1488 == AppInterface.CommandType.GET_INKEY.value()) {
1489 mStkContext[slotId].mIsInputPending = true;
1490 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value()
1491 == AppInterface.CommandType.SET_UP_MENU.value()
1492 || mStkContext[slotId].mCurrentCmd.getCmdType().value()
1493 == AppInterface.CommandType.SELECT_ITEM.value()) {
1494 mStkContext[slotId].mIsMenuPending = true;
1495 }
Wink Savillee68857d2014-10-17 15:23:05 -07001496 }
1497 CatLog.d(LOG_TAG, "finish pending activity.");
1498 activity.finish();
1499 mStkContext[slotId].mActivityInstance = null;
1500 }
1501 if (dialog != null) {
1502 CatLog.d(LOG_TAG, "finish pending dialog.");
1503 mStkContext[slotId].mIsDialogPending = true;
1504 dialog.finish();
1505 mStkContext[slotId].mDialogInstance = null;
1506 }
1507 }
1508 /**
1509 * This method is used for restoring pending instances from stack.
1510 */
1511 private void restoreInstanceFromStackBySlot(int slotId) {
1512 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1513
1514 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1515 switch(cmdType) {
1516 case GET_INPUT:
1517 case GET_INKEY:
1518 launchInputActivity(slotId);
1519 //Set mMenuIsVisible to true for showing main menu for
1520 //following session end command.
1521 mStkContext[slotId].mMenuIsVisible = true;
1522 break;
1523 case DISPLAY_TEXT:
1524 launchTextDialog(slotId);
1525 break;
1526 case LAUNCH_BROWSER:
1527 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1528 slotId);
1529 break;
1530 case OPEN_CHANNEL:
1531 launchOpenChannelDialog(slotId);
1532 break;
1533 case SET_UP_CALL:
1534 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1535 confirmMsg, slotId);
1536 break;
1537 case SET_UP_MENU:
1538 case SELECT_ITEM:
1539 launchMenuActivity(null, slotId);
1540 break;
1541 default:
1542 break;
1543 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001544 }
1545
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +09001546 @Override
1547 public void startActivity(Intent intent) {
1548 int slotId = intent.getIntExtra(SLOT_ID, SubscriptionManager.INVALID_SIM_SLOT_INDEX);
1549 // Close the dialog displayed for DISPLAY TEXT command with an immediate response object
1550 // before new dialog is displayed.
1551 if (SubscriptionManager.isValidSlotIndex(slotId)) {
1552 Activity dialog = mStkContext[slotId].getImmediateDialogInstance();
1553 if (dialog != null) {
1554 CatLog.d(LOG_TAG, "finish dialog for immediate response.");
1555 dialog.finish();
1556 }
1557 }
1558 super.startActivity(intent);
1559 }
1560
Wink Savillee68857d2014-10-17 15:23:05 -07001561 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001562 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001563 String targetActivity = STK_MENU_ACTIVITY_NAME;
1564 String uriString = STK_MENU_URI + System.currentTimeMillis();
1565 //Set unique URI to create a new instance of activity for different slotId.
1566 Uri uriData = Uri.parse(uriString);
1567
1568 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1569 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1570 + mStkContext[slotId].mMenuState);
1571 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1572 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1573
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001574 if (menu == null) {
1575 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001576 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001577 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1578 //Otherwise, it should be "STATE_MAIN".
1579 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1580 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1581 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1582 } else {
1583 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1584 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1585 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001586 } else {
1587 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001588 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001589 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001590 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001591 }
Anna Suzuki35309b02019-02-15 16:24:59 +09001592 if (mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
Anna Suzukib1cee232019-02-21 12:52:27 +09001593 startToObserveHomeKeyEvent(slotId);
Anna Suzuki35309b02019-02-15 16:24:59 +09001594 }
Wink Savillee68857d2014-10-17 15:23:05 -07001595 newIntent.putExtra(SLOT_ID, slotId);
1596 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001597 newIntent.setFlags(intentFlags);
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +09001598 startActivity(newIntent);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001599 }
1600
Wink Savillee68857d2014-10-17 15:23:05 -07001601 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001602 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001603 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1604 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1605 //Set unique URI to create a new instance of activity for different slotId.
1606 Uri uriData = Uri.parse(uriString);
Yuta Uife965802017-11-07 20:12:37 +09001607 Input input = mStkContext[slotId].mCurrentCmd.geInput();
Wink Savillee68857d2014-10-17 15:23:05 -07001608
1609 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001610 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001611 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1612 newIntent.setClassName(PACKAGE_NAME, targetActivity);
Yuta Uife965802017-11-07 20:12:37 +09001613 newIntent.putExtra("INPUT", input);
Wink Savillee68857d2014-10-17 15:23:05 -07001614 newIntent.putExtra(SLOT_ID, slotId);
1615 newIntent.setData(uriData);
Yuta Uife965802017-11-07 20:12:37 +09001616
1617 if (input != null) {
1618 notifyUserIfNecessary(slotId, input.text);
1619 }
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +09001620 startActivity(newIntent);
Anna Suzukib1cee232019-02-21 12:52:27 +09001621 startToObserveHomeKeyEvent(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001622 }
1623
Wink Savillee68857d2014-10-17 15:23:05 -07001624 private void launchTextDialog(int slotId) {
1625 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1626 Intent newIntent = new Intent();
1627 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1628 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1629 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1630 //Set unique URI to create a new instance of activity for different slotId.
1631 Uri uriData = Uri.parse(uriString);
Yuta Uife965802017-11-07 20:12:37 +09001632 TextMessage textMessage = mStkContext[slotId].mCurrentCmd.geTextMessage();
1633
1634 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1635 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Yuta Uife965802017-11-07 20:12:37 +09001636 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1637 newIntent.setData(uriData);
1638 newIntent.putExtra("TEXT", textMessage);
1639 newIntent.putExtra(SLOT_ID, slotId);
1640
1641 if (textMessage != null) {
1642 notifyUserIfNecessary(slotId, textMessage.text);
1643 }
1644 startActivity(newIntent);
1645 // For display texts with immediate response, send the terminal response
1646 // immediately. responseNeeded will be false, if display text command has
1647 // the immediate response tlv.
1648 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
1649 sendResponse(RES_ID_CONFIRM, slotId, true);
Anna Suzuki35309b02019-02-15 16:24:59 +09001650 } else {
Anna Suzukib1cee232019-02-21 12:52:27 +09001651 startToObserveHomeKeyEvent(slotId);
Yuta Uife965802017-11-07 20:12:37 +09001652 }
1653 }
1654
1655 private void notifyUserIfNecessary(int slotId, String message) {
1656 createAllChannels();
1657
1658 if (mStkContext[slotId].mNoResponseFromUser) {
1659 // No response from user was observed in the current session.
1660 // Do nothing in that case in order to avoid turning on the screen again and again
1661 // when the card repeatedly sends the same command in its retry procedure.
1662 return;
1663 }
1664
1665 PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
1666
1667 if (((KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE)).isKeyguardLocked()) {
1668 // Display the notification on the keyguard screen
1669 // if user cannot see the message from the card right now because of it.
1670 // The notification can be dismissed if user removed the keyguard screen.
1671 launchNotificationOnKeyguard(slotId, message);
Wink Savillee68857d2014-10-17 15:23:05 -07001672 }
Yuta Uife965802017-11-07 20:12:37 +09001673
1674 // Turn on the screen.
1675 PowerManager.WakeLock wakelock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
1676 | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
1677 wakelock.acquire();
1678 wakelock.release();
1679 }
1680
1681 private void launchNotificationOnKeyguard(int slotId, String message) {
1682 Notification.Builder builder = new Notification.Builder(this, STK_NOTIFICATION_CHANNEL_ID);
1683
1684 builder.setStyle(new Notification.BigTextStyle(builder).bigText(message));
1685 builder.setContentText(message);
1686
1687 Menu menu = getMainMenu(slotId);
1688 if (menu == null || TextUtils.isEmpty(menu.title)) {
1689 builder.setContentTitle(getResources().getString(R.string.app_name));
1690 } else {
1691 builder.setContentTitle(menu.title);
1692 }
1693
1694 builder.setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1695 builder.setOngoing(true);
1696 builder.setOnlyAlertOnce(true);
1697 builder.setColor(getResources().getColor(
1698 com.android.internal.R.color.system_notification_accent_color));
1699
1700 registerUserPresentReceiver();
1701 mNotificationManager.notify(getNotificationId(NOTIFICATION_ON_KEYGUARD, slotId),
1702 builder.build());
1703 mStkContext[slotId].mNotificationOnKeyguard = true;
1704 }
1705
1706 private void cancelNotificationOnKeyguard(int slotId) {
1707 mNotificationManager.cancel(getNotificationId(NOTIFICATION_ON_KEYGUARD, slotId));
1708 mStkContext[slotId].mNotificationOnKeyguard = false;
1709 unregisterUserPresentReceiver(slotId);
1710 }
1711
1712 private synchronized void registerUserPresentReceiver() {
1713 if (mUserPresentReceiver == null) {
1714 mUserPresentReceiver = new BroadcastReceiver() {
1715 @Override public void onReceive(Context context, Intent intent) {
1716 if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
1717 for (int slot = 0; slot < mSimCount; slot++) {
1718 cancelNotificationOnKeyguard(slot);
1719 }
1720 }
1721 }
1722 };
1723 registerReceiver(mUserPresentReceiver, new IntentFilter(Intent.ACTION_USER_PRESENT));
1724 }
1725 }
1726
1727 private synchronized void unregisterUserPresentReceiver(int slotId) {
1728 if (mUserPresentReceiver != null) {
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +09001729 for (int slot = 0; slot < mSimCount; slot++) {
Yuta Uife965802017-11-07 20:12:37 +09001730 if (slot != slotId) {
1731 if (mStkContext[slot].mNotificationOnKeyguard) {
1732 // The broadcast receiver is still necessary for other SIM card.
1733 return;
1734 }
1735 }
1736 }
1737 unregisterReceiver(mUserPresentReceiver);
1738 mUserPresentReceiver = null;
1739 }
1740 }
1741
1742 private int getNotificationId(int notificationType, int slotId) {
1743 return getNotificationId(slotId) + (notificationType * mSimCount);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001744 }
1745
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001746 private void replaceEventList(int slotId) {
1747 if (mStkContext[slotId].mSetupEventListSettings != null) {
1748 for (int current : mStkContext[slotId].mSetupEventListSettings.eventList) {
1749 if (current != INVALID_SETUP_EVENT) {
1750 // Cancel the event notification if it is not listed in the new event list.
1751 if ((mStkContext[slotId].mCurrentCmd.getSetEventList() == null)
1752 || !findEvent(current, mStkContext[slotId].mCurrentCmd
1753 .getSetEventList().eventList)) {
1754 unregisterEvent(current, slotId);
1755 }
1756 }
1757 }
1758 }
1759 mStkContext[slotId].mSetupEventListSettings
1760 = mStkContext[slotId].mCurrentCmd.getSetEventList();
1761 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
1762 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
1763 registerEvents(slotId);
1764 }
1765
1766 private boolean findEvent(int event, int[] eventList) {
1767 for (int content : eventList) {
1768 if (content == event) return true;
1769 }
1770 return false;
1771 }
1772
1773 private void unregisterEvent(int event, int slotId) {
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +09001774 for (int slot = 0; slot < mSimCount; slot++) {
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +09001775 if (slot != slotId) {
1776 if (mStkContext[slot].mSetupEventListSettings != null) {
1777 if (findEvent(event, mStkContext[slot].mSetupEventListSettings.eventList)) {
1778 // The specified event shall never be canceled
1779 // if there is any other SIM card which requests the event.
1780 return;
1781 }
1782 }
1783 }
1784 }
1785
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001786 switch (event) {
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001787 case USER_ACTIVITY_EVENT:
1788 unregisterUserActivityReceiver();
1789 break;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001790 case IDLE_SCREEN_AVAILABLE_EVENT:
Malcolm Chen8c72f2f2020-01-10 15:57:10 -08001791 unregisterHomeVisibilityObserver(AppInterface.CommandType.SET_UP_EVENT_LIST, slotId);
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001792 break;
1793 case LANGUAGE_SELECTION_EVENT:
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +09001794 unregisterLocaleChangeReceiver();
1795 break;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001796 default:
1797 break;
1798 }
1799 }
1800
1801 private void registerEvents(int slotId) {
1802 if (mStkContext[slotId].mSetupEventListSettings == null) {
1803 return;
1804 }
1805 for (int event : mStkContext[slotId].mSetupEventListSettings.eventList) {
1806 switch (event) {
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001807 case USER_ACTIVITY_EVENT:
1808 registerUserActivityReceiver();
1809 break;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001810 case IDLE_SCREEN_AVAILABLE_EVENT:
Malcolm Chen8c72f2f2020-01-10 15:57:10 -08001811 registerHomeVisibilityObserver();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001812 break;
1813 case LANGUAGE_SELECTION_EVENT:
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +09001814 registerLocaleChangeReceiver();
1815 break;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001816 default:
1817 break;
1818 }
1819 }
1820 }
1821
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001822 private synchronized void registerUserActivityReceiver() {
1823 if (mUserActivityReceiver == null) {
1824 mUserActivityReceiver = new BroadcastReceiver() {
1825 @Override public void onReceive(Context context, Intent intent) {
1826 if (WindowManagerPolicyConstants.ACTION_USER_ACTIVITY_NOTIFICATION.equals(
1827 intent.getAction())) {
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09001828 Message message = mServiceHandler.obtainMessage(OP_USER_ACTIVITY);
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001829 mServiceHandler.sendMessage(message);
1830 unregisterUserActivityReceiver();
1831 }
1832 }
1833 };
1834 registerReceiver(mUserActivityReceiver, new IntentFilter(
1835 WindowManagerPolicyConstants.ACTION_USER_ACTIVITY_NOTIFICATION));
1836 try {
1837 IWindowManager wm = IWindowManager.Stub.asInterface(
1838 ServiceManager.getService(Context.WINDOW_SERVICE));
1839 wm.requestUserActivityNotification();
1840 } catch (RemoteException e) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001841 CatLog.e(LOG_TAG, "failed to init WindowManager:" + e);
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001842 }
1843 }
1844 }
1845
1846 private synchronized void unregisterUserActivityReceiver() {
1847 if (mUserActivityReceiver != null) {
1848 unregisterReceiver(mUserActivityReceiver);
1849 mUserActivityReceiver = null;
1850 }
1851 }
1852
Malcolm Chen8c72f2f2020-01-10 15:57:10 -08001853 private synchronized void registerHomeVisibilityObserver() {
1854 if (mHomeVisibilityObserver == null) {
1855 mHomeVisibilityObserver = new HomeVisibilityObserver() {
1856 @Override
1857 public void onHomeVisibilityChanged(boolean isHomeActivityVisible) {
1858 if (isHomeActivityVisible) {
1859 Message message = mServiceHandler.obtainMessage(OP_IDLE_SCREEN);
1860 mServiceHandler.sendMessage(message);
1861 unregisterHomeVisibilityObserver();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001862 }
Malcolm Chen8c72f2f2020-01-10 15:57:10 -08001863 }
1864 };
1865 ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
1866 am.registerHomeVisibilityObserver(mHomeVisibilityObserver);
1867 CatLog.d(LOG_TAG, "Started to observe the foreground activity");
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001868 }
1869 }
1870
Malcolm Chen8c72f2f2020-01-10 15:57:10 -08001871 private void unregisterHomeVisibilityObserver(AppInterface.CommandType command, int slotId) {
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001872 // Check if there is any pending command which still needs the process observer
1873 // except for the current command and slot.
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +09001874 for (int slot = 0; slot < mSimCount; slot++) {
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001875 if (command != AppInterface.CommandType.SET_UP_IDLE_MODE_TEXT || slot != slotId) {
1876 if (mStkContext[slot].mIdleModeTextCmd != null
1877 && !mStkContext[slot].mIdleModeTextVisible) {
1878 // Keep the process observer registered
1879 // as there is an idle mode text which has not been visible yet.
1880 return;
1881 }
1882 }
1883 if (command != AppInterface.CommandType.SET_UP_EVENT_LIST || slot != slotId) {
1884 if (mStkContext[slot].mSetupEventListSettings != null) {
1885 if (findEvent(IDLE_SCREEN_AVAILABLE_EVENT,
1886 mStkContext[slot].mSetupEventListSettings.eventList)) {
1887 // Keep the process observer registered
1888 // as there is a SIM card which still want IDLE SCREEN AVAILABLE event.
1889 return;
1890 }
1891 }
1892 }
1893 }
Malcolm Chen8c72f2f2020-01-10 15:57:10 -08001894 unregisterHomeVisibilityObserver();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001895 }
1896
Malcolm Chen8c72f2f2020-01-10 15:57:10 -08001897 private synchronized void unregisterHomeVisibilityObserver() {
1898 if (mHomeVisibilityObserver != null) {
1899 ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
1900 am.unregisterHomeVisibilityObserver(mHomeVisibilityObserver);
1901 CatLog.d(LOG_TAG, "Stopped to observe the foreground activity");
1902 mHomeVisibilityObserver = null;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001903 }
1904 }
1905
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +09001906 private synchronized void registerLocaleChangeReceiver() {
1907 if (mLocaleChangeReceiver == null) {
1908 mLocaleChangeReceiver = new BroadcastReceiver() {
1909 @Override public void onReceive(Context context, Intent intent) {
1910 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09001911 Message message = mServiceHandler.obtainMessage(OP_LOCALE_CHANGED);
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +09001912 mServiceHandler.sendMessage(message);
1913 }
1914 }
1915 };
1916 registerReceiver(mLocaleChangeReceiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
1917 }
1918 }
1919
1920 private synchronized void unregisterLocaleChangeReceiver() {
1921 if (mLocaleChangeReceiver != null) {
1922 unregisterReceiver(mLocaleChangeReceiver);
1923 mLocaleChangeReceiver = null;
1924 }
1925 }
1926
Preeti Ahuja95919342013-10-01 18:18:55 -07001927 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001928 CatLog.d(LOG_TAG, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -07001929
1930 if (mStkContext[slotId].mCurrentSetupEventCmd == null){
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001931 CatLog.e(LOG_TAG, "mCurrentSetupEventCmd is null");
Preeti Ahuja95919342013-10-01 18:18:55 -07001932 return;
1933 }
1934
1935 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd);
1936
1937 resMsg.setResultCode(ResultCode.OK);
1938 resMsg.setEventDownload(event, addedInfo);
1939
1940 mStkService[slotId].onCmdResponse(resMsg);
1941 }
1942
1943 private void checkForSetupEvent(int event, Bundle args, int slotId) {
1944 boolean eventPresent = false;
1945 byte[] addedInfo = null;
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001946 CatLog.d(LOG_TAG, "Event :" + event);
Preeti Ahuja95919342013-10-01 18:18:55 -07001947
1948 if (mStkContext[slotId].mSetupEventListSettings != null) {
1949 /* Checks if the event is present in the EventList updated by last
1950 * SetupEventList Proactive Command */
1951 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) {
1952 if (event == i) {
1953 eventPresent = true;
1954 break;
1955 }
1956 }
1957
1958 /* If Event is present send the response to ICC */
1959 if (eventPresent == true) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001960 CatLog.d(LOG_TAG, " Event " + event + "exists in the EventList");
Preeti Ahuja95919342013-10-01 18:18:55 -07001961
1962 switch (event) {
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001963 case USER_ACTIVITY_EVENT:
Preeti Ahuja560be362014-11-25 19:38:24 -08001964 case IDLE_SCREEN_AVAILABLE_EVENT:
1965 sendSetUpEventResponse(event, addedInfo, slotId);
1966 removeSetUpEvent(event, slotId);
1967 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001968 case LANGUAGE_SELECTION_EVENT:
1969 String language = mContext
1970 .getResources().getConfiguration().locale.getLanguage();
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001971 CatLog.d(LOG_TAG, "language: " + language);
Preeti Ahuja95919342013-10-01 18:18:55 -07001972 // Each language code is a pair of alpha-numeric characters.
1973 // Each alpha-numeric character shall be coded on one byte
1974 // using the SMS default 7-bit coded alphabet
1975 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language);
1976 sendSetUpEventResponse(event, addedInfo, slotId);
1977 break;
1978 default:
1979 break;
1980 }
1981 } else {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001982 CatLog.e(LOG_TAG, " Event does not exist in the EventList");
Preeti Ahuja95919342013-10-01 18:18:55 -07001983 }
1984 } else {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001985 CatLog.e(LOG_TAG, "SetupEventList is not received. Ignoring the event: " + event);
Preeti Ahuja95919342013-10-01 18:18:55 -07001986 }
1987 }
1988
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001989 private void removeSetUpEvent(int event, int slotId) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001990 CatLog.d(LOG_TAG, "Remove Event :" + event);
Preeti Ahuja95919342013-10-01 18:18:55 -07001991
1992 if (mStkContext[slotId].mSetupEventListSettings != null) {
1993 /*
1994 * Make new Eventlist without the event
1995 */
1996 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
1997 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
1998 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001999
2000 switch (event) {
Yoshiaki Nakafb997252017-09-19 20:14:58 +09002001 case USER_ACTIVITY_EVENT:
2002 // The broadcast receiver can be unregistered
2003 // as the event has already been sent to the card.
2004 unregisterUserActivityReceiver();
2005 break;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002006 case IDLE_SCREEN_AVAILABLE_EVENT:
2007 // The process observer can be unregistered
2008 // as the idle screen has already been available.
Malcolm Chen8c72f2f2020-01-10 15:57:10 -08002009 unregisterHomeVisibilityObserver();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002010 break;
2011 default:
2012 break;
2013 }
Preeti Ahuja95919342013-10-01 18:18:55 -07002014 break;
2015 }
2016 }
2017 }
2018 }
2019
2020 private void launchEventMessage(int slotId) {
2021 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
2022 }
2023
Wink Savillee68857d2014-10-17 15:23:05 -07002024 private void launchEventMessage(int slotId, TextMessage msg) {
Ryuto Sawada2ba20cc2015-12-28 17:10:35 +01002025 if (msg == null || msg.text == null || (msg.text != null && msg.text.length() == 0)) {
Wink Savillee68857d2014-10-17 15:23:05 -07002026 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002027 return;
2028 }
Wink Savillee68857d2014-10-17 15:23:05 -07002029
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002030 Toast toast = new Toast(mContext.getApplicationContext());
2031 LayoutInflater inflate = (LayoutInflater) mContext
2032 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
2033 View v = inflate.inflate(R.layout.stk_event_msg, null);
2034 TextView tv = (TextView) v
2035 .findViewById(com.android.internal.R.id.message);
2036 ImageView iv = (ImageView) v
2037 .findViewById(com.android.internal.R.id.icon);
2038 if (msg.icon != null) {
2039 iv.setImageBitmap(msg.icon);
2040 } else {
2041 iv.setVisibility(View.GONE);
2042 }
Preeti Ahujaf33bf392013-09-28 19:11:31 +05302043 /* In case of 'self explanatory' stkapp should display the specified
2044 * icon in proactive command (but not the alpha string).
2045 * If icon is non-self explanatory and if the icon could not be displayed
2046 * then alpha string or text data should be displayed
2047 * Ref: ETSI 102.223,section 6.5.4
2048 */
2049 if (mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ||
2050 msg.icon == null || !msg.iconSelfExplanatory) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002051 tv.setText(msg.text);
2052 }
2053
2054 toast.setView(v);
2055 toast.setDuration(Toast.LENGTH_LONG);
2056 toast.setGravity(Gravity.BOTTOM, 0, 0);
2057 toast.show();
2058 }
2059
Wink Savillee68857d2014-10-17 15:23:05 -07002060 private void launchConfirmationDialog(TextMessage msg, int slotId) {
2061 msg.title = mStkContext[slotId].lastSelectedItem;
2062 Intent newIntent = new Intent();
2063 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
2064 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
2065 //Set unique URI to create a new instance of activity for different slotId.
2066 Uri uriData = Uri.parse(uriString);
2067
Yuta Uife965802017-11-07 20:12:37 +09002068 newIntent.setClassName(this, targetActivity);
2069 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
2070 | Intent.FLAG_ACTIVITY_NO_HISTORY
2071 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
2072 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
2073 newIntent.putExtra("TEXT", msg);
2074 newIntent.putExtra(SLOT_ID, slotId);
2075 newIntent.setData(uriData);
2076 startActivity(newIntent);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002077 }
2078
2079 private void launchBrowser(BrowserSettings settings) {
2080 if (settings == null) {
2081 return;
2082 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002083
Abhishek Adappa840c82f2013-02-26 10:19:49 -08002084 Uri data = null;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002085 String url;
2086 if (settings.url == null) {
Abhishek Adappa840c82f2013-02-26 10:19:49 -08002087 // if the command did not contain a URL,
2088 // launch the browser to the default homepage.
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002089 CatLog.d(LOG_TAG, "no url data provided by proactive command." +
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002090 " launching browser with stk default URL ... ");
2091 url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP,
2092 "http://www.google.com");
2093 } else {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002094 CatLog.d(LOG_TAG, "launch browser command has attached url = " + settings.url);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002095 url = settings.url;
Abhishek Adappa840c82f2013-02-26 10:19:49 -08002096 }
David Brown7c03cfe2011-10-20 15:36:12 -07002097
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002098 if (url.startsWith("http://") || url.startsWith("https://")) {
2099 data = Uri.parse(url);
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002100 CatLog.d(LOG_TAG, "launching browser with url = " + url);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002101 } else {
2102 String modifiedUrl = "http://" + url;
2103 data = Uri.parse(modifiedUrl);
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002104 CatLog.d(LOG_TAG, "launching browser with modified url = " + modifiedUrl);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002105 }
2106
2107 Intent intent = new Intent(Intent.ACTION_VIEW);
2108 intent.setData(data);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002109 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2110 switch (settings.mode) {
2111 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002112 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
2113 break;
2114 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002115 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
2116 break;
2117 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
2118 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
2119 break;
2120 }
2121 // start browser activity
2122 startActivity(intent);
2123 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07002124 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002125 // followed immediately.
2126 try {
Ryuto Sawada350aaa62016-06-13 14:47:22 +09002127 Thread.sleep(3000);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002128 } catch (InterruptedException e) {}
2129 }
2130
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002131 private void cancelIdleText(int slotId) {
Malcolm Chen8c72f2f2020-01-10 15:57:10 -08002132 unregisterHomeVisibilityObserver(AppInterface.CommandType.SET_UP_IDLE_MODE_TEXT, slotId);
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002133 mNotificationManager.cancel(getNotificationId(slotId));
2134 mStkContext[slotId].mIdleModeTextCmd = null;
2135 mStkContext[slotId].mIdleModeTextVisible = false;
2136 }
2137
Wink Savillee68857d2014-10-17 15:23:05 -07002138 private void launchIdleText(int slotId) {
Preeti Ahuja560be362014-11-25 19:38:24 -08002139 TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09002140
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002141 if (msg != null && !TextUtils.isEmpty(msg.text)) {
Preeti Ahuja95919342013-10-01 18:18:55 -07002142 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
2143 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
2144 + "] icon[" + msg.icon + "], sim id: " + slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07002145 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002146 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002147 new Intent(mContext, StkAppService.class), 0);
fionaxu805eb572017-05-02 10:57:30 -07002148 createAllChannels();
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002149 final Notification.Builder notificationBuilder = new Notification.Builder(
fionaxu2c91c752017-04-21 18:11:57 -07002150 StkAppService.this, STK_NOTIFICATION_CHANNEL_ID);
Wink Savillee68857d2014-10-17 15:23:05 -07002151 if (mStkContext[slotId].mMainCmd != null &&
2152 mStkContext[slotId].mMainCmd.getMenu() != null) {
2153 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02002154 } else {
2155 notificationBuilder.setContentTitle("");
2156 }
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002157 notificationBuilder
2158 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
2159 notificationBuilder.setContentIntent(pendingIntent);
2160 notificationBuilder.setOngoing(true);
Yuta Uife965802017-11-07 20:12:37 +09002161 notificationBuilder.setOnlyAlertOnce(true);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002162 // Set text and icon for the status bar and notification body.
Preeti Ahujaf33bf392013-09-28 19:11:31 +05302163 if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() ||
2164 !msg.iconSelfExplanatory) {
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002165 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02002166 notificationBuilder.setTicker(msg.text);
samalinc7f3bdf2018-04-26 15:04:31 +08002167 notificationBuilder.setStyle(new Notification.BigTextStyle(notificationBuilder)
2168 .bigText(msg.text));
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002169 }
2170 if (msg.icon != null) {
2171 notificationBuilder.setLargeIcon(msg.icon);
2172 } else {
2173 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
2174 .getResources().getSystem(),
2175 com.android.internal.R.drawable.stat_notify_sim_toolkit);
2176 notificationBuilder.setLargeIcon(bitmapIcon);
2177 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02002178 notificationBuilder.setColor(mContext.getResources().getColor(
2179 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07002180 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002181 mStkContext[slotId].mIdleModeTextVisible = true;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002182 }
2183 }
2184
fionaxu805eb572017-05-02 10:57:30 -07002185 /** Creates the notification channel and registers it with NotificationManager.
2186 * If a channel with the same ID is already registered, NotificationManager will
2187 * ignore this call.
2188 */
2189 private void createAllChannels() {
Yuta Uife965802017-11-07 20:12:37 +09002190 NotificationChannel notificationChannel = new NotificationChannel(
fionaxu805eb572017-05-02 10:57:30 -07002191 STK_NOTIFICATION_CHANNEL_ID,
2192 getResources().getString(R.string.stk_channel_name),
Yuta Uife965802017-11-07 20:12:37 +09002193 NotificationManager.IMPORTANCE_DEFAULT);
2194
2195 notificationChannel.enableVibration(true);
2196 notificationChannel.setVibrationPattern(VIBRATION_PATTERN);
2197
2198 mNotificationManager.createNotificationChannel(notificationChannel);
fionaxu805eb572017-05-02 10:57:30 -07002199 }
2200
Wink Savillee68857d2014-10-17 15:23:05 -07002201 private void launchToneDialog(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002202 Intent newIntent = new Intent(this, ToneDialog.class);
Wink Savillee68857d2014-10-17 15:23:05 -07002203 String uriString = STK_TONE_URI + slotId;
2204 Uri uriData = Uri.parse(uriString);
2205 //Set unique URI to create a new instance of activity for different slotId.
2206 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002207 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
2208 | Intent.FLAG_ACTIVITY_NO_HISTORY
2209 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Wink Savillee68857d2014-10-17 15:23:05 -07002210 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
2211 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
2212 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
2213 newIntent.putExtra(SLOT_ID, slotId);
2214 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002215 startActivity(newIntent);
2216 }
2217
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302218 private void handlePlayTone(int slotId) {
2219 TextMessage toneMsg = mStkContext[slotId].mCurrentCmd.geTextMessage();
2220
2221 boolean showUser = true;
2222 boolean displayDialog = true;
2223 Resources resource = Resources.getSystem();
2224 try {
2225 displayDialog = !resource.getBoolean(
2226 com.android.internal.R.bool.config_stkNoAlphaUsrCnf);
2227 } catch (NotFoundException e) {
2228 displayDialog = true;
2229 }
2230
2231 // As per the spec 3GPP TS 11.14, 6.4.5. Play Tone.
2232 // If there is no alpha identifier tlv present, UE may show the
2233 // user information. 'config_stkNoAlphaUsrCnf' value will decide
2234 // whether to show it or not.
2235 // If alpha identifier tlv is present and its data is null, play only tone
2236 // without showing user any information.
2237 // Alpha Id is Present, but the text data is null.
2238 if ((toneMsg.text != null ) && (toneMsg.text.equals(""))) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002239 CatLog.d(LOG_TAG, "Alpha identifier data is null, play only tone");
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302240 showUser = false;
2241 }
2242 // Alpha Id is not present AND we need to show info to the user.
2243 if (toneMsg.text == null && displayDialog) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002244 CatLog.d(LOG_TAG, "toneMsg.text " + toneMsg.text
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302245 + " Starting ToneDialog activity with default message.");
2246 toneMsg.text = getResources().getString(R.string.default_tone_dialog_msg);
2247 showUser = true;
2248 }
2249 // Dont show user info, if config setting is true.
2250 if (toneMsg.text == null && !displayDialog) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002251 CatLog.d(LOG_TAG, "config value stkNoAlphaUsrCnf is true");
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302252 showUser = false;
2253 }
2254
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002255 CatLog.d(LOG_TAG, "toneMsg.text: " + toneMsg.text + "showUser: " +showUser +
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302256 "displayDialog: " +displayDialog);
2257 playTone(showUser, slotId);
2258 }
2259
2260 private void playTone(boolean showUserInfo, int slotId) {
2261 // Start playing tone and vibration
2262 ToneSettings settings = mStkContext[slotId].mCurrentCmd.getToneSettings();
2263 if (null == settings) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002264 CatLog.d(LOG_TAG, "null settings, not playing tone.");
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302265 return;
2266 }
2267
2268 mVibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
2269 mTonePlayer = new TonePlayer();
2270 mTonePlayer.play(settings.tone);
2271 int timeout = StkApp.calculateDurationInMilis(settings.duration);
2272 if (timeout == 0) {
2273 timeout = StkApp.TONE_DEFAULT_TIMEOUT;
2274 }
2275
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002276 Message msg = mServiceHandler.obtainMessage(OP_STOP_TONE, 0, slotId,
2277 (showUserInfo ? PLAY_TONE_WITH_DIALOG : PLAY_TONE_ONLY));
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302278 mServiceHandler.sendMessageDelayed(msg, timeout);
2279 if (settings.vibrate) {
2280 mVibrator.vibrate(timeout);
2281 }
2282
2283 // Start Tone dialog Activity to show user the information.
2284 if (showUserInfo) {
2285 Intent newIntent = new Intent(sInstance, ToneDialog.class);
2286 String uriString = STK_TONE_URI + slotId;
2287 Uri uriData = Uri.parse(uriString);
2288 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302289 | Intent.FLAG_ACTIVITY_SINGLE_TOP
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302290 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
2291 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
2292 newIntent.putExtra(SLOT_ID, slotId);
2293 newIntent.setData(uriData);
2294 startActivity(newIntent);
2295 }
2296 }
2297
2298 private void finishToneDialogActivity() {
2299 Intent finishIntent = new Intent(FINISH_TONE_ACTIVITY_ACTION);
2300 sendBroadcast(finishIntent);
2301 }
2302
2303 private void handleStopTone(Message msg, int slotId) {
2304 int resId = 0;
2305
2306 // Stop the play tone in following cases:
2307 // 1.OP_STOP_TONE: play tone timer expires.
2308 // 2.STOP_TONE_USER: user pressed the back key.
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002309 if (msg.what == OP_STOP_TONE) {
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302310 resId = RES_ID_DONE;
2311 // Dismiss Tone dialog, after finishing off playing the tone.
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002312 if (PLAY_TONE_WITH_DIALOG.equals((Integer) msg.obj)) finishToneDialogActivity();
2313 } else if (msg.what == OP_STOP_TONE_USER) {
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302314 resId = RES_ID_END_SESSION;
2315 }
2316
2317 sendResponse(resId, slotId, true);
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002318
2319 mServiceHandler.removeMessages(OP_STOP_TONE);
2320 mServiceHandler.removeMessages(OP_STOP_TONE_USER);
2321
Takanori Nakanob82c8752019-04-01 14:47:07 +09002322 if (mTonePlayer != null) {
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302323 mTonePlayer.stop();
2324 mTonePlayer.release();
2325 mTonePlayer = null;
2326 }
2327 if (mVibrator != null) {
2328 mVibrator.cancel();
2329 mVibrator = null;
2330 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002331 }
2332
Takanori Nakano49b12722016-02-16 14:34:14 +09002333 private void launchOpenChannelDialog(final int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -07002334 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002335 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07002336 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002337 return;
2338 }
2339
2340 msg.title = getResources().getString(R.string.stk_dialog_title);
2341 if (msg.text == null) {
2342 msg.text = getResources().getString(R.string.default_open_channel_msg);
2343 }
2344
2345 final AlertDialog dialog = new AlertDialog.Builder(mContext)
2346 .setIconAttribute(android.R.attr.alertDialogIcon)
2347 .setTitle(msg.title)
2348 .setMessage(msg.text)
2349 .setCancelable(false)
2350 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
2351 new DialogInterface.OnClickListener() {
2352 public void onClick(DialogInterface dialog, int which) {
2353 Bundle args = new Bundle();
2354 args.putInt(RES_ID, RES_ID_CHOICE);
2355 args.putInt(CHOICE, YES);
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002356 sendResponse(args, slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002357 }
2358 })
2359 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
2360 new DialogInterface.OnClickListener() {
2361 public void onClick(DialogInterface dialog, int which) {
2362 Bundle args = new Bundle();
2363 args.putInt(RES_ID, RES_ID_CHOICE);
2364 args.putInt(CHOICE, NO);
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002365 sendResponse(args, slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002366 }
2367 })
2368 .create();
2369
2370 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2371 if (!mContext.getResources().getBoolean(
2372 com.android.internal.R.bool.config_sf_slowBlur)) {
2373 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
2374 }
2375
2376 dialog.show();
2377 }
2378
Wink Savillee68857d2014-10-17 15:23:05 -07002379 private void launchTransientEventMessage(int slotId) {
2380 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002381 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07002382 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002383 return;
2384 }
2385
2386 msg.title = getResources().getString(R.string.stk_dialog_title);
2387
2388 final AlertDialog dialog = new AlertDialog.Builder(mContext)
2389 .setIconAttribute(android.R.attr.alertDialogIcon)
2390 .setTitle(msg.title)
2391 .setMessage(msg.text)
2392 .setCancelable(false)
2393 .setPositiveButton(getResources().getString(android.R.string.ok),
2394 new DialogInterface.OnClickListener() {
2395 public void onClick(DialogInterface dialog, int which) {
2396 }
2397 })
2398 .create();
2399
2400 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2401 if (!mContext.getResources().getBoolean(
2402 com.android.internal.R.bool.config_sf_slowBlur)) {
2403 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
2404 }
2405
2406 dialog.show();
2407 }
2408
Wink Savillee68857d2014-10-17 15:23:05 -07002409 private int getNotificationId(int slotId) {
2410 int notifyId = STK_NOTIFICATION_ID;
2411 if (slotId >= 0 && slotId < mSimCount) {
2412 notifyId += slotId;
2413 } else {
2414 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
2415 }
2416 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
2417 return notifyId;
2418 }
2419
2420 private String getItemName(int itemId, int slotId) {
2421 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002422 if (menu == null) {
2423 return null;
2424 }
2425 for (Item item : menu.items) {
2426 if (item.id == itemId) {
2427 return item.text;
2428 }
2429 }
2430 return null;
2431 }
2432
Wink Savillee68857d2014-10-17 15:23:05 -07002433 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002434 try {
Wink Savillee68857d2014-10-17 15:23:05 -07002435 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
2436 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
2437 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002438 return true;
2439 }
2440 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07002441 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
2442 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002443 return true;
2444 }
Wink Savillee68857d2014-10-17 15:23:05 -07002445 mStkContext[slotId].mSetupMenuState = STATE_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002446 return false;
2447 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05302448
Malcolm Chen616ea282019-10-24 19:53:48 -07002449 synchronized StkContext getStkContext(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -07002450 if (slotId >= 0 && slotId < mSimCount) {
2451 return mStkContext[slotId];
2452 } else {
2453 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
2454 return null;
2455 }
2456 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05302457
2458 private void handleAlphaNotify(Bundle args) {
2459 String alphaString = args.getString(AppInterface.ALPHA_STRING);
2460
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002461 CatLog.d(LOG_TAG, "Alpha string received from card: " + alphaString);
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05302462 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
2463 toast.setGravity(Gravity.TOP, 0, 0);
2464 toast.show();
2465 }
Srikanth Chintalaba103002015-11-30 10:49:52 -08002466
2467 private boolean isUrlAvailableToLaunchBrowser(BrowserSettings settings) {
2468 String url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP, "");
2469 if (url == "" && settings.url == null) {
2470 return false;
2471 }
2472 return true;
2473 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002474}