• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.phone;
18 
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.net.Uri;
24 import android.provider.Telephony.Intents;
25 import com.android.internal.telephony.Phone;
26 import android.telephony.PhoneNumberUtils;
27 import android.util.Log;
28 import android.view.WindowManager;
29 
30 /**
31  * Helper class to listen for some magic dialpad character sequences
32  * that are handled specially by the Phone app.
33  *
34  * Note the Contacts app also handles these sequences too, so there's a
35  * separate version of this class under apps/Contacts.
36  *
37  * In fact, the most common use case for these special sequences is typing
38  * them from the regular "Dialer" used for outgoing calls, which is part
39  * of the contacts app; see DialtactsActivity and DialpadFragment.
40  * *This* version of SpecialCharSequenceMgr is used for only a few
41  * relatively obscure places in the UI:
42  * - The "SIM network unlock" PIN entry screen (see
43  *   IccNetworkDepersonalizationPanel.java)
44  * - The emergency dialer (see EmergencyDialer.java).
45  *
46  * TODO: there's lots of duplicated code between this class and the
47  * corresponding class under apps/Contacts.  Let's figure out a way to
48  * unify these two classes (in the framework? in a common shared library?)
49  */
50 public class SpecialCharSequenceMgr {
51     private static final String TAG = PhoneApp.LOG_TAG;
52     private static final boolean DBG = false;
53 
54     private static final String MMI_IMEI_DISPLAY = "*#06#";
55 
56     /** This class is never instantiated. */
SpecialCharSequenceMgr()57     private SpecialCharSequenceMgr() {
58     }
59 
60     /**
61      * Check for special strings of digits from an input
62      * string.
63      * @param context input Context for the events we handle.
64      * @param input the dial string to be examined.
65      */
handleChars(Context context, String input)66     static boolean handleChars(Context context, String input) {
67         return handleChars(context, input, null);
68     }
69 
70     /**
71      * Generally used for the Personal Unblocking Key (PUK) unlocking
72      * case, where we want to be able to maintain a handle to the
73      * calling activity so that we can close it or otherwise display
74      * indication if the PUK code is recognized.
75      *
76      * NOTE: The counterpart to this file in Contacts does
77      * NOT contain the special PUK handling code, since it
78      * does NOT need it.  When the device gets into PUK-
79      * locked state, the keyguard comes up and the only way
80      * to unlock the device is through the Emergency dialer,
81      * which is still in the Phone App.
82      *
83      * @param context input Context for the events we handle.
84      * @param input the dial string to be examined.
85      * @param pukInputActivity activity that originated this
86      * PUK call, tracked so that we can close it or otherwise
87      * indicate that special character sequence is
88      * successfully processed. Can be null.
89      * @return true if the input was a special string which has been
90      * handled.
91      */
handleChars(Context context, String input, Activity pukInputActivity)92     static boolean handleChars(Context context,
93                                String input,
94                                Activity pukInputActivity) {
95 
96         //get rid of the separators so that the string gets parsed correctly
97         String dialString = PhoneNumberUtils.stripSeparators(input);
98 
99         if (handleIMEIDisplay(context, dialString)
100             || handlePinEntry(context, dialString, pukInputActivity)
101             || handleAdnEntry(context, dialString)
102             || handleSecretCode(context, dialString)) {
103             return true;
104         }
105 
106         return false;
107     }
108 
109     /**
110      * Variant of handleChars() that looks for the subset of "special
111      * sequences" that are available even if the device is locked.
112      *
113      * (Specifically, these are the sequences that you're allowed to type
114      * in the Emergency Dialer, which is accessible *without* unlocking
115      * the device.)
116      */
handleCharsForLockedDevice(Context context, String input, Activity pukInputActivity)117     static boolean handleCharsForLockedDevice(Context context,
118                                               String input,
119                                               Activity pukInputActivity) {
120         // Get rid of the separators so that the string gets parsed correctly
121         String dialString = PhoneNumberUtils.stripSeparators(input);
122 
123         // The only sequences available on a locked device are the "**04"
124         // or "**05" sequences that allow you to enter PIN or PUK-related
125         // codes.  (e.g. for the case where you're currently locked out of
126         // your phone, and need to change the PIN!  The only way to do
127         // that is via the Emergency Dialer.)
128 
129         if (handlePinEntry(context, dialString, pukInputActivity)) {
130             return true;
131         }
132 
133         return false;
134     }
135 
136     /**
137      * Handles secret codes to launch arbitrary activities in the form of *#*#<code>#*#*.
138      * If a secret code is encountered an Intent is started with the android_secret_code://<code>
139      * URI.
140      *
141      * @param context the context to use
142      * @param input the text to check for a secret code in
143      * @return true if a secret code was encountered
144      */
handleSecretCode(Context context, String input)145     static private boolean handleSecretCode(Context context, String input) {
146         // Secret codes are in the form *#*#<code>#*#*
147         int len = input.length();
148         if (len > 8 && input.startsWith("*#*#") && input.endsWith("#*#*")) {
149             Intent intent = new Intent(Intents.SECRET_CODE_ACTION,
150                     Uri.parse("android_secret_code://" + input.substring(4, len - 4)));
151             context.sendBroadcast(intent);
152             return true;
153         }
154 
155         return false;
156     }
157 
handleAdnEntry(Context context, String input)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 (PhoneApp.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                 PhoneApp.getInstance().startActivity(intent);
180 
181                 return true;
182             } catch (NumberFormatException ex) {}
183         }
184         return false;
185     }
186 
handlePinEntry(Context context, String input, Activity pukInputActivity)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             PhoneApp app = PhoneApp.getInstance();
195             boolean isMMIHandled = app.phone.handlePinMmi(input);
196 
197             // if the PUK code is recognized then indicate to the
198             // phone app that an attempt to unPUK the device was
199             // made with this activity.  The PUK code may still
200             // fail though, but we won't know until the MMI code
201             // returns a result.
202             if (isMMIHandled && input.startsWith("**05")) {
203                 app.setPukEntryActivity(pukInputActivity);
204             }
205             return isMMIHandled;
206         }
207         return false;
208     }
209 
handleIMEIDisplay(Context context, String input)210     static private boolean handleIMEIDisplay(Context context,
211                                              String input) {
212         if (input.equals(MMI_IMEI_DISPLAY)) {
213             showDeviceIdPanel(context);
214             return true;
215         }
216 
217         return false;
218     }
219 
showDeviceIdPanel(Context context)220     static private void showDeviceIdPanel(Context context) {
221         if (DBG) log("showDeviceIdPanel()...");
222 
223         Phone phone = PhoneApp.getPhone();
224         int labelId = TelephonyCapabilities.getDeviceIdLabel(phone);
225         String deviceId = phone.getDeviceId();
226 
227         AlertDialog alert = new AlertDialog.Builder(context)
228                 .setTitle(labelId)
229                 .setMessage(deviceId)
230                 .setPositiveButton(R.string.ok, null)
231                 .setCancelable(false)
232                 .create();
233         alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PRIORITY_PHONE);
234         alert.show();
235     }
236 
log(String msg)237     private static void log(String msg) {
238         Log.d(TAG, "[SpecialCharSequenceMgr] " + msg);
239     }
240 }
241