blob: 2aa10431f1dd36b87fc9c0974c0878e3cc534428 [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
2 * Copyright (C) 2006 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.phone;
18
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.content.ActivityNotFoundException;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.net.Uri;
Jeff Sharkey236e67c2014-04-16 17:21:29 -070026import android.provider.Settings;
27
Santos Cordon7d4ddf62013-07-10 11:58:08 -070028import com.android.internal.telephony.TelephonyIntents;
29import com.android.internal.telephony.Phone;
Jeff Sharkey236e67c2014-04-16 17:21:29 -070030
Santos Cordon7d4ddf62013-07-10 11:58:08 -070031import android.telephony.PhoneNumberUtils;
32import android.util.Log;
33import android.view.WindowManager;
34
35import com.android.internal.telephony.TelephonyCapabilities;
36
37/**
38 * Helper class to listen for some magic dialpad character sequences
39 * that are handled specially by the Phone app.
40 *
41 * Note the Contacts app also handles these sequences too, so there's a
42 * separate version of this class under apps/Contacts.
43 *
44 * In fact, the most common use case for these special sequences is typing
45 * them from the regular "Dialer" used for outgoing calls, which is part
46 * of the contacts app; see DialtactsActivity and DialpadFragment.
47 * *This* version of SpecialCharSequenceMgr is used for only a few
48 * relatively obscure places in the UI:
49 * - The "SIM network unlock" PIN entry screen (see
50 * IccNetworkDepersonalizationPanel.java)
51 * - The emergency dialer (see EmergencyDialer.java).
52 *
53 * TODO: there's lots of duplicated code between this class and the
54 * corresponding class under apps/Contacts. Let's figure out a way to
55 * unify these two classes (in the framework? in a common shared library?)
56 */
57public class SpecialCharSequenceMgr {
58 private static final String TAG = PhoneGlobals.LOG_TAG;
59 private static final boolean DBG = false;
60
61 private static final String MMI_IMEI_DISPLAY = "*#06#";
62 private static final String MMI_REGULATORY_INFO_DISPLAY = "*#07#";
63
64 /** This class is never instantiated. */
65 private SpecialCharSequenceMgr() {
66 }
67
68 /**
69 * Check for special strings of digits from an input
70 * string.
71 * @param context input Context for the events we handle.
72 * @param input the dial string to be examined.
73 */
74 static boolean handleChars(Context context, String input) {
75 return handleChars(context, input, null);
76 }
77
78 /**
79 * Generally used for the Personal Unblocking Key (PUK) unlocking
80 * case, where we want to be able to maintain a handle to the
81 * calling activity so that we can close it or otherwise display
82 * indication if the PUK code is recognized.
83 *
84 * NOTE: The counterpart to this file in Contacts does
85 * NOT contain the special PUK handling code, since it
86 * does NOT need it. When the device gets into PUK-
87 * locked state, the keyguard comes up and the only way
88 * to unlock the device is through the Emergency dialer,
89 * which is still in the Phone App.
90 *
91 * @param context input Context for the events we handle.
92 * @param input the dial string to be examined.
93 * @param pukInputActivity activity that originated this
94 * PUK call, tracked so that we can close it or otherwise
95 * indicate that special character sequence is
96 * successfully processed. Can be null.
97 * @return true if the input was a special string which has been
98 * handled.
99 */
100 static boolean handleChars(Context context,
101 String input,
102 Activity pukInputActivity) {
103
104 //get rid of the separators so that the string gets parsed correctly
105 String dialString = PhoneNumberUtils.stripSeparators(input);
106
107 if (handleIMEIDisplay(context, dialString)
108 || handleRegulatoryInfoDisplay(context, dialString)
109 || handlePinEntry(context, dialString, pukInputActivity)
110 || handleAdnEntry(context, dialString)
fionaxue559f972017-01-24 22:31:12 -0800111 || handleSecretCode(dialString)) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700112 return true;
113 }
114
115 return false;
116 }
117
118 /**
119 * Variant of handleChars() that looks for the subset of "special
120 * sequences" that are available even if the device is locked.
121 *
122 * (Specifically, these are the sequences that you're allowed to type
123 * in the Emergency Dialer, which is accessible *without* unlocking
124 * the device.)
125 */
126 static boolean handleCharsForLockedDevice(Context context,
127 String input,
128 Activity pukInputActivity) {
129 // Get rid of the separators so that the string gets parsed correctly
130 String dialString = PhoneNumberUtils.stripSeparators(input);
131
132 // The only sequences available on a locked device are the "**04"
133 // or "**05" sequences that allow you to enter PIN or PUK-related
134 // codes. (e.g. for the case where you're currently locked out of
135 // your phone, and need to change the PIN! The only way to do
136 // that is via the Emergency Dialer.)
137
138 if (handlePinEntry(context, dialString, pukInputActivity)) {
139 return true;
140 }
141
142 return false;
143 }
144
145 /**
fionaxue559f972017-01-24 22:31:12 -0800146 * Handles secret codes to launch arbitrary receivers in the form of *#*#<code>#*#*.
147 * If a secret code is encountered, an broadcast intent is sent with the
148 * android_secret_code://<code> URI.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700149 *
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700150 * @param input the text to check for a secret code in
fionaxue559f972017-01-24 22:31:12 -0800151 * @return true if a secret code was encountered and intent is sent out
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700152 */
fionaxue559f972017-01-24 22:31:12 -0800153 static private boolean handleSecretCode(String input) {
154 Phone phone = PhoneGlobals.getPhone();
155 return phone.sendDialerCode(input);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700156 }
157
158 static private boolean handleAdnEntry(Context context, String input) {
159 /* ADN entries are of the form "N(N)(N)#" */
160
161 // if the phone is keyguard-restricted, then just ignore this
162 // input. We want to make sure that sim card contacts are NOT
163 // exposed unless the phone is unlocked, and this code can be
164 // accessed from the emergency dialer.
165 if (PhoneGlobals.getInstance().getKeyguardManager().inKeyguardRestrictedInputMode()) {
166 return false;
167 }
168
169 int len = input.length();
170 if ((len > 1) && (len < 5) && (input.endsWith("#"))) {
171 try {
172 int index = Integer.parseInt(input.substring(0, len-1));
173 Intent intent = new Intent(Intent.ACTION_PICK);
174
175 intent.setClassName("com.android.phone",
176 "com.android.phone.SimContacts");
177 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
178 intent.putExtra("index", index);
179 PhoneGlobals.getInstance().startActivity(intent);
180
181 return true;
182 } catch (NumberFormatException ex) {}
183 }
184 return false;
185 }
186
187 static private boolean handlePinEntry(Context context, String input,
188 Activity pukInputActivity) {
189 // TODO: The string constants here should be removed in favor
190 // of some call to a static the MmiCode class that determines
191 // if a dialstring is an MMI code.
192 if ((input.startsWith("**04") || input.startsWith("**05"))
193 && input.endsWith("#")) {
194 PhoneGlobals app = PhoneGlobals.getInstance();
Stuart Scottdcf40a92014-12-09 10:45:01 -0800195 Phone phone = PhoneGlobals.getPhone();
196 boolean isMMIHandled = phone.handlePinMmi(input);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700197
198 // if the PUK code is recognized then indicate to the
199 // phone app that an attempt to unPUK the device was
200 // made with this activity. The PUK code may still
201 // fail though, but we won't know until the MMI code
202 // returns a result.
203 if (isMMIHandled && input.startsWith("**05")) {
204 app.setPukEntryActivity(pukInputActivity);
205 }
206 return isMMIHandled;
207 }
208 return false;
209 }
210
211 static private boolean handleIMEIDisplay(Context context,
212 String input) {
213 if (input.equals(MMI_IMEI_DISPLAY)) {
214 showDeviceIdPanel(context);
215 return true;
216 }
217
218 return false;
219 }
220
221 static private void showDeviceIdPanel(Context context) {
222 if (DBG) log("showDeviceIdPanel()...");
223
224 Phone phone = PhoneGlobals.getPhone();
225 int labelId = TelephonyCapabilities.getDeviceIdLabel(phone);
226 String deviceId = phone.getDeviceId();
227
228 AlertDialog alert = new AlertDialog.Builder(context)
229 .setTitle(labelId)
230 .setMessage(deviceId)
231 .setPositiveButton(R.string.ok, null)
232 .setCancelable(false)
233 .create();
234 alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PRIORITY_PHONE);
235 alert.show();
236 }
237
238 private static boolean handleRegulatoryInfoDisplay(Context context, String input) {
239 if (input.equals(MMI_REGULATORY_INFO_DISPLAY)) {
240 log("handleRegulatoryInfoDisplay() sending intent to settings app");
Jeff Sharkey236e67c2014-04-16 17:21:29 -0700241 Intent showRegInfoIntent = new Intent(Settings.ACTION_SHOW_REGULATORY_INFO);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700242 try {
243 context.startActivity(showRegInfoIntent);
244 } catch (ActivityNotFoundException e) {
245 Log.e(TAG, "startActivity() failed: " + e);
246 }
247 return true;
248 }
249 return false;
250 }
251
252 private static void log(String msg) {
253 Log.d(TAG, "[SpecialCharSequenceMgr] " + msg);
254 }
255}