blob: 176997a2b08d51a4d5f3294a3a6a4c2bb5c9a11e [file] [log] [blame]
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -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.contacts;
18
19import android.app.Activity;
20import android.content.ActivityNotFoundException;
21import android.content.Context;
22import android.content.Intent;
23import android.content.res.Resources;
24import android.database.Cursor;
25import android.graphics.Bitmap;
26import android.graphics.BitmapFactory;
27import android.graphics.drawable.Drawable;
28import android.media.AudioManager;
29import android.media.ToneGenerator;
30import android.net.Uri;
31import android.os.Bundle;
32import android.os.Handler;
33import android.os.Message;
34import android.os.RemoteException;
35import android.os.ServiceManager;
36import android.os.SystemClock;
David Brownc29c7ab2009-07-07 16:00:18 -070037import android.os.Vibrator;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080038import android.provider.Contacts.Intents.Insert;
39import android.provider.Contacts.People;
40import android.provider.Contacts.Phones;
41import android.provider.Contacts.PhonesColumns;
42import android.provider.Settings;
43import android.telephony.PhoneNumberFormattingTextWatcher;
44import android.telephony.PhoneNumberUtils;
45import android.telephony.PhoneStateListener;
46import android.telephony.TelephonyManager;
47import android.text.Editable;
Reli Talc2a2a512009-06-10 16:48:00 -040048import android.text.SpannableStringBuilder;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080049import android.text.TextUtils;
50import android.text.TextWatcher;
51import android.text.method.DialerKeyListener;
52import android.util.Log;
53import android.view.KeyEvent;
54import android.view.LayoutInflater;
55import android.view.Menu;
56import android.view.MenuItem;
57import android.view.View;
58import android.view.ViewConfiguration;
59import android.view.ViewGroup;
Karl Rosaenf46bc312009-03-24 18:20:48 -070060import android.view.inputmethod.InputMethodManager;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080061import android.widget.AdapterView;
62import android.widget.BaseAdapter;
63import android.widget.EditText;
64import android.widget.ImageView;
65import android.widget.ListView;
66import android.widget.TextView;
67
68import com.android.internal.telephony.ITelephony;
69
70/**
71 * Dialer activity that displays the typical twelve key interface.
72 */
73public class TwelveKeyDialer extends Activity implements View.OnClickListener,
74 View.OnLongClickListener, View.OnKeyListener,
75 AdapterView.OnItemClickListener, TextWatcher {
76
77 private static final String TAG = "TwelveKeyDialer";
Eric Laurentd9efc872009-07-17 11:52:06 -070078
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080079 /** The length of DTMF tones in milliseconds */
80 private static final int TONE_LENGTH_MS = 150;
Eric Laurentd9efc872009-07-17 11:52:06 -070081
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080082 /** The DTMF tone volume relative to other sounds in the stream */
83 private static final int TONE_RELATIVE_VOLUME = 50;
84
Nicolas Catania4c0704a2009-09-23 11:42:00 -070085 /** Play the vibrate pattern only once. */
86 private static final int VIBRATE_NO_REPEAT = -1;
87
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080088 private EditText mDigits;
89 private View mDelete;
90 private MenuItem mAddToContactMenuItem;
91 private ToneGenerator mToneGenerator;
92 private Object mToneGeneratorLock = new Object();
93 private Drawable mDigitsBackground;
94 private Drawable mDigitsEmptyBackground;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080095 private View mDialpad;
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -070096 private View mVoicemailDialAndDeleteRow;
Nicolas Catania80bda0f2009-09-19 09:17:14 -070097 private View mVoicemailButton;
98 private View mDialButton;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080099 private ListView mDialpadChooser;
100 private DialpadChooserAdapter mDialpadChooserAdapter;
Reli Talc2a2a512009-06-10 16:48:00 -0400101 //Member variables for dialpad options
102 private MenuItem m2SecPauseMenuItem;
103 private MenuItem mWaitMenuItem;
104 private static final int MENU_ADD_CONTACTS = 1;
105 private static final int MENU_2S_PAUSE = 2;
106 private static final int MENU_WAIT = 3;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800107
108 // determines if we want to playback local DTMF tones.
109 private boolean mDTMFToneEnabled;
David Brownc29c7ab2009-07-07 16:00:18 -0700110
111 // Vibration (haptic feedback) for dialer key presses.
112 private Vibrator mVibrator;
113 private boolean mVibrateOn;
Nicolas Catania4c0704a2009-09-23 11:42:00 -0700114 private long[] mVibratePattern;
David Brownc29c7ab2009-07-07 16:00:18 -0700115
Eric Laurentd9efc872009-07-17 11:52:06 -0700116
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800117 /** Identifier for the "Add Call" intent extra. */
118 static final String ADD_CALL_MODE_KEY = "add_call_mode";
119 /** Indicates if we are opening this dialer to add a call from the InCallScreen. */
120 private boolean mIsAddCallMode;
121
122 PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
123 /**
124 * Listen for phone state changes so that we can take down the
125 * "dialpad chooser" if the phone becomes idle while the
126 * chooser UI is visible.
127 */
128 @Override
129 public void onCallStateChanged(int state, String incomingNumber) {
130 // Log.i(TAG, "PhoneStateListener.onCallStateChanged: "
131 // + state + ", '" + incomingNumber + "'");
132 if ((state == TelephonyManager.CALL_STATE_IDLE) && dialpadChooserVisible()) {
133 // Log.i(TAG, "Call ended with dialpad chooser visible! Taking it down...");
134 // Note there's a race condition in the UI here: the
135 // dialpad chooser could conceivably disappear (on its
136 // own) at the exact moment the user was trying to select
137 // one of the choices, which would be confusing. (But at
138 // least that's better than leaving the dialpad chooser
139 // onscreen, but useless...)
140 showDialpadChooser(false);
141 }
142 }
143 };
144
145 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
146 // Do nothing
147 }
148
149 public void onTextChanged(CharSequence input, int start, int before, int changeCount) {
150 // Do nothing
Eric Laurentd9efc872009-07-17 11:52:06 -0700151 // DTMF Tones do not need to be played here any longer -
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800152 // the DTMF dialer handles that functionality now.
153 }
154
155 public void afterTextChanged(Editable input) {
156 if (SpecialCharSequenceMgr.handleChars(this, input.toString(), mDigits)) {
157 // A special sequence was entered, clear the digits
158 mDigits.getText().clear();
159 }
160
Nicolas Catania75993762009-09-21 16:42:00 -0700161 final boolean notEmpty = mDigits.length() != 0;
162 if (notEmpty) {
163 mDigits.setBackgroundDrawable(mDigitsBackground);
164 } else {
Nicolas Catania3040fa32009-10-01 13:00:53 -0700165 mDigits.setCursorVisible(false);
Nicolas Catania75993762009-09-21 16:42:00 -0700166 mDigits.setBackgroundDrawable(mDigitsEmptyBackground);
167 }
168
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700169 updateDialAndDeleteButtonStateEnabledAttr();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800170 }
171
172 @Override
173 protected void onCreate(Bundle icicle) {
174 super.onCreate(icicle);
175
176 // Set the content view
177 setContentView(getContentViewResource());
178
Nicolas Catania75993762009-09-21 16:42:00 -0700179 // Load up the resources for the text field.
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800180 Resources r = getResources();
181 mDigitsBackground = r.getDrawable(R.drawable.btn_dial_textfield_active);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800182 mDigitsEmptyBackground = r.getDrawable(R.drawable.btn_dial_textfield);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800183
184 mDigits = (EditText) findViewById(R.id.digits);
185 mDigits.setKeyListener(DialerKeyListener.getInstance());
186 mDigits.setOnClickListener(this);
187 mDigits.setOnKeyListener(this);
Nicolas Catania3040fa32009-10-01 13:00:53 -0700188 mDigits.setInputType(android.text.InputType.TYPE_NULL); // Don't show IME when focused.
189
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800190 maybeAddNumberFormatting();
191
192 // Check for the presence of the keypad
193 View view = findViewById(R.id.one);
194 if (view != null) {
195 setupKeypad();
196 }
197
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700198 mVoicemailDialAndDeleteRow = findViewById(R.id.voicemailAndDialAndDelete);
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700199
Nicolas Catania80bda0f2009-09-19 09:17:14 -0700200 initVoicemailButton();
201
David Brown3d07e6d2009-08-04 20:30:09 -0700202 // Check whether we should show the onscreen "Dial" button.
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700203 mDialButton = mVoicemailDialAndDeleteRow.findViewById(R.id.dialButton);
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700204
David Brown3d07e6d2009-08-04 20:30:09 -0700205 if (r.getBoolean(R.bool.config_show_onscreen_dial_button)) {
David Brown3d07e6d2009-08-04 20:30:09 -0700206 mDialButton.setOnClickListener(this);
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700207 } else {
208 mDialButton.setVisibility(View.GONE); // It's VISIBLE by default
209 mDialButton = null;
David Brown3d07e6d2009-08-04 20:30:09 -0700210 }
211
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700212 view = mVoicemailDialAndDeleteRow.findViewById(R.id.deleteButton);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800213 view.setOnClickListener(this);
214 view.setOnLongClickListener(this);
215 mDelete = view;
216
Dmitri Plotnikov032bb362009-05-06 17:05:39 -0700217 mDialpad = findViewById(R.id.dialpad); // This is null in landscape mode
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800218
219 // Set up the "dialpad chooser" UI; see showDialpadChooser().
220 mDialpadChooser = (ListView) findViewById(R.id.dialpadChooser);
221 mDialpadChooser.setOnItemClickListener(this);
222
223 if (!resolveIntent() && icicle != null) {
224 super.onRestoreInstanceState(icicle);
225 }
226
David Brownc29c7ab2009-07-07 16:00:18 -0700227 // TODO: We might eventually need to make mVibrateOn come from a
228 // user preference rather than a per-platform resource, in which
229 // case we would need to update it in onResume() rather than here.
Nicolas Catania4c0704a2009-09-23 11:42:00 -0700230 initVibrationPattern(r);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800231 }
232
233 @Override
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800234 protected void onRestoreInstanceState(Bundle icicle) {
235 // Do nothing, state is restored in onCreate() if needed
236 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700237
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800238 protected void maybeAddNumberFormatting() {
239 mDigits.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
240 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700241
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800242 /**
Eric Laurentd9efc872009-07-17 11:52:06 -0700243 * Overridden by subclasses to control the resource used by the content view.
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800244 */
245 protected int getContentViewResource() {
246 return R.layout.twelve_key_dialer;
247 }
248
249 private boolean resolveIntent() {
250 boolean ignoreState = false;
251
252 // Find the proper intent
253 final Intent intent;
254 if (isChild()) {
255 intent = getParent().getIntent();
256 ignoreState = intent.getBooleanExtra(DialtactsActivity.EXTRA_IGNORE_STATE, false);
257 } else {
258 intent = getIntent();
259 }
260 // Log.i(TAG, "==> resolveIntent(): intent: " + intent);
261
262 // by default we are not adding a call.
263 mIsAddCallMode = false;
264
265 // By default we don't show the "dialpad chooser" UI.
266 boolean needToShowDialpadChooser = false;
267
268 // Resolve the intent
269 final String action = intent.getAction();
270 if (Intent.ACTION_DIAL.equals(action) || Intent.ACTION_VIEW.equals(action)) {
271 // see if we are "adding a call" from the InCallScreen; false by default.
272 mIsAddCallMode = intent.getBooleanExtra(ADD_CALL_MODE_KEY, false);
273 Uri uri = intent.getData();
274 if (uri != null) {
275 if ("tel".equals(uri.getScheme())) {
276 // Put the requested number into the input area
277 String data = uri.getSchemeSpecificPart();
278 setFormattedDigits(data);
279 } else {
280 String type = intent.getType();
281 if (People.CONTENT_ITEM_TYPE.equals(type)
282 || Phones.CONTENT_ITEM_TYPE.equals(type)) {
283 // Query the phone number
284 Cursor c = getContentResolver().query(intent.getData(),
285 new String[] {PhonesColumns.NUMBER}, null, null, null);
286 if (c != null) {
287 if (c.moveToFirst()) {
288 // Put the number into the input area
289 setFormattedDigits(c.getString(0));
290 }
291 c.close();
292 }
293 }
294 }
295 }
296 } else if (Intent.ACTION_MAIN.equals(action)) {
297 // The MAIN action means we're bringing up a blank dialer
298 // (e.g. by selecting the Home shortcut, or tabbing over from
299 // Contacts or Call log.)
300 //
301 // At this point, IF there's already an active call, there's a
302 // good chance that the user got here accidentally (but really
303 // wanted the in-call dialpad instead). So we bring up an
304 // intermediate UI to make the user confirm what they really
305 // want to do.
306 if (phoneIsInUse()) {
307 // Log.i(TAG, "resolveIntent(): phone is in use; showing dialpad chooser!");
308 needToShowDialpadChooser = true;
309 }
310 }
311
312 // Bring up the "dialpad chooser" IFF we need to make the user
313 // confirm which dialpad they really want.
314 showDialpadChooser(needToShowDialpadChooser);
315
316 return ignoreState;
317 }
318
319 protected void setFormattedDigits(String data) {
320 // strip the non-dialable numbers out of the data string.
321 String dialString = PhoneNumberUtils.extractNetworkPortion(data);
322 dialString = PhoneNumberUtils.formatNumber(dialString);
323 if (!TextUtils.isEmpty(dialString)) {
324 Editable digits = mDigits.getText();
325 digits.replace(0, digits.length(), dialString);
Karl Rosaenf46bc312009-03-24 18:20:48 -0700326 // for some reason this isn't getting called in the digits.replace call above..
327 // but in any case, this will make sure the background drawable looks right
328 afterTextChanged(digits);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800329 }
330 }
331
332 @Override
333 protected void onNewIntent(Intent newIntent) {
334 setIntent(newIntent);
335 resolveIntent();
336 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700337
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800338 @Override
339 protected void onPostCreate(Bundle savedInstanceState) {
340 super.onPostCreate(savedInstanceState);
341
342 // This can't be done in onCreate(), since the auto-restoring of the digits
343 // will play DTMF tones for all the old digits if it is when onRestoreSavedInstanceState()
344 // is called. This method will be called every time the activity is created, and
345 // will always happen after onRestoreSavedInstanceState().
346 mDigits.addTextChangedListener(this);
347 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700348
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800349 private void setupKeypad() {
350 // Setup the listeners for the buttons
351 View view = findViewById(R.id.one);
352 view.setOnClickListener(this);
353 view.setOnLongClickListener(this);
354
355 findViewById(R.id.two).setOnClickListener(this);
356 findViewById(R.id.three).setOnClickListener(this);
357 findViewById(R.id.four).setOnClickListener(this);
358 findViewById(R.id.five).setOnClickListener(this);
359 findViewById(R.id.six).setOnClickListener(this);
360 findViewById(R.id.seven).setOnClickListener(this);
361 findViewById(R.id.eight).setOnClickListener(this);
362 findViewById(R.id.nine).setOnClickListener(this);
363 findViewById(R.id.star).setOnClickListener(this);
364
365 view = findViewById(R.id.zero);
366 view.setOnClickListener(this);
367 view.setOnLongClickListener(this);
368
369 findViewById(R.id.pound).setOnClickListener(this);
370 }
371
372 @Override
373 protected void onResume() {
374 super.onResume();
David Brownc29c7ab2009-07-07 16:00:18 -0700375
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800376 // retrieve the DTMF tone play back setting.
377 mDTMFToneEnabled = Settings.System.getInt(getContentResolver(),
378 Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
379
Eric Laurentd9efc872009-07-17 11:52:06 -0700380 // if the mToneGenerator creation fails, just continue without it. It is
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800381 // a local audio signal, and is not as important as the dtmf tone itself.
382 synchronized(mToneGeneratorLock) {
383 if (mToneGenerator == null) {
384 try {
Eric Laurentd9efc872009-07-17 11:52:06 -0700385 mToneGenerator = new ToneGenerator(AudioManager.STREAM_DTMF,
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800386 TONE_RELATIVE_VOLUME);
387 } catch (RuntimeException e) {
388 Log.w(TAG, "Exception caught while creating local tone generator: " + e);
389 mToneGenerator = null;
390 }
391 }
392 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700393
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800394 Activity parent = getParent();
395 // See if we were invoked with a DIAL intent. If we were, fill in the appropriate
396 // digits in the dialer field.
397 if (parent != null && parent instanceof DialtactsActivity) {
398 Uri dialUri = ((DialtactsActivity) parent).getAndClearDialUri();
399 if (dialUri != null) {
400 resolveIntent();
401 }
402 }
403
404 // While we're in the foreground, listen for phone state changes,
405 // purely so that we can take down the "dialpad chooser" if the
406 // phone becomes idle while the chooser UI is visible.
407 TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
408 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
409
410 // Potentially show hint text in the mDigits field when the user
411 // hasn't typed any digits yet. (If there's already an active call,
412 // this hint text will remind the user that he's about to add a new
413 // call.)
414 //
415 // TODO: consider adding better UI for the case where *both* lines
416 // are currently in use. (Right now we let the user try to add
417 // another call, but that call is guaranteed to fail. Perhaps the
418 // entire dialer UI should be disabled instead.)
419 if (phoneIsInUse()) {
420 mDigits.setHint(R.string.dialerDialpadHintText);
421 } else {
422 // Common case; no hint necessary.
423 mDigits.setHint(null);
424
425 // Also, a sanity-check: the "dialpad chooser" UI should NEVER
426 // be visible if the phone is idle!
427 showDialpadChooser(false);
428 }
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700429
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700430 updateDialAndDeleteButtonStateEnabledAttr();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800431 }
432
433 @Override
Karl Rosaenf46bc312009-03-24 18:20:48 -0700434 public void onWindowFocusChanged(boolean hasFocus) {
435 if (hasFocus) {
436 // Hide soft keyboard, if visible (it's fugly over button dialer).
437 // The only known case where this will be true is when launching the dialer with
438 // ACTION_DIAL via a soft keyboard. we dismiss it here because we don't
439 // have a window token yet in onCreate / onNewIntent
440 InputMethodManager inputMethodManager = (InputMethodManager)
441 getSystemService(Context.INPUT_METHOD_SERVICE);
Eric Laurentd9efc872009-07-17 11:52:06 -0700442 inputMethodManager.hideSoftInputFromWindow(mDigits.getWindowToken(), 0);
Karl Rosaenf46bc312009-03-24 18:20:48 -0700443 }
444 }
445
446 @Override
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800447 protected void onPause() {
448 super.onPause();
449
450 // Stop listening for phone state changes.
451 TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
452 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
453
454 synchronized(mToneGeneratorLock) {
455 if (mToneGenerator != null) {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800456 mToneGenerator.release();
457 mToneGenerator = null;
458 }
459 }
460 }
461
462 @Override
463 public boolean onCreateOptionsMenu(Menu menu) {
Reli Talc2a2a512009-06-10 16:48:00 -0400464 mAddToContactMenuItem = menu.add(0, MENU_ADD_CONTACTS, 0, R.string.recentCalls_addToContact)
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800465 .setIcon(android.R.drawable.ic_menu_add);
Reli Talc2a2a512009-06-10 16:48:00 -0400466 m2SecPauseMenuItem = menu.add(0, MENU_2S_PAUSE, 0, R.string.add_2sec_pause)
467 .setIcon(R.drawable.ic_menu_2sec_pause);
468 mWaitMenuItem = menu.add(0, MENU_WAIT, 0, R.string.add_wait)
469 .setIcon(R.drawable.ic_menu_wait);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800470 return true;
471 }
472
473 @Override
474 public boolean onPrepareOptionsMenu(Menu menu) {
475 // We never show a menu if the "choose dialpad" UI is up.
476 if (dialpadChooserVisible()) {
477 return false;
478 }
479
480 CharSequence digits = mDigits.getText();
481 if (digits == null || !TextUtils.isGraphic(digits)) {
482 mAddToContactMenuItem.setVisible(false);
Reli Talc2a2a512009-06-10 16:48:00 -0400483 m2SecPauseMenuItem.setVisible(false);
484 mWaitMenuItem.setVisible(false);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800485 } else {
486 // Put the current digits string into an intent
487 Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
488 intent.putExtra(Insert.PHONE, mDigits.getText());
489 intent.setType(People.CONTENT_ITEM_TYPE);
490 mAddToContactMenuItem.setIntent(intent);
491 mAddToContactMenuItem.setVisible(true);
Reli Talc2a2a512009-06-10 16:48:00 -0400492
493 // Check out whether to show Pause & Wait option menu items
494 int selectionStart;
495 int selectionEnd;
496 String strDigits = digits.toString();
497
498 selectionStart = mDigits.getSelectionStart();
499 selectionEnd = mDigits.getSelectionEnd();
500
501 if (selectionStart != -1) {
502 if (selectionStart > selectionEnd) {
503 // swap it as we want start to be less then end
504 int tmp = selectionStart;
505 selectionStart = selectionEnd;
506 selectionEnd = tmp;
507 }
508
509 if (selectionStart != 0) {
510 // Pause can be visible if cursor is not in the begining
511 m2SecPauseMenuItem.setVisible(true);
512
513 // For Wait to be visible set of condition to meet
514 mWaitMenuItem.setVisible(showWait(selectionStart,
515 selectionEnd, strDigits));
516 } else {
517 // cursor in the beginning both pause and wait to be invisible
518 m2SecPauseMenuItem.setVisible(false);
519 mWaitMenuItem.setVisible(false);
520 }
521 } else {
522 // cursor is not selected so assume new digit is added to the end
523 int strLength = strDigits.length();
524 mWaitMenuItem.setVisible(showWait(strLength,
525 strLength, strDigits));
526 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800527 }
528 return true;
529 }
530
531 @Override
532 public boolean onKeyDown(int keyCode, KeyEvent event) {
533 switch (keyCode) {
534 case KeyEvent.KEYCODE_CALL: {
535 long callPressDiff = SystemClock.uptimeMillis() - event.getDownTime();
536 if (callPressDiff >= ViewConfiguration.getLongPressTimeout()) {
537 // Launch voice dialer
538 Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
539 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
540 try {
541 startActivity(intent);
542 } catch (ActivityNotFoundException e) {
543 }
544 }
545 return true;
546 }
547 case KeyEvent.KEYCODE_1: {
Eric Laurentd9efc872009-07-17 11:52:06 -0700548 long timeDiff = SystemClock.uptimeMillis() - event.getDownTime();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800549 if (timeDiff >= ViewConfiguration.getLongPressTimeout()) {
550 // Long press detected, call voice mail
551 callVoicemail();
552 }
553 return true;
554 }
555 }
556 return super.onKeyDown(keyCode, event);
557 }
558
559 @Override
560 public boolean onKeyUp(int keyCode, KeyEvent event) {
561 switch (keyCode) {
562 case KeyEvent.KEYCODE_CALL: {
563 if (mIsAddCallMode && (TextUtils.isEmpty(mDigits.getText().toString()))) {
564 // if we are adding a call from the InCallScreen and the phone
565 // number entered is empty, we just close the dialer to expose
566 // the InCallScreen under it.
567 finish();
568 } else {
569 // otherwise, we place the call.
570 placeCall();
571 }
572 return true;
573 }
574 }
575 return super.onKeyUp(keyCode, event);
576 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700577
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800578 private void keyPressed(int keyCode) {
David Brownc29c7ab2009-07-07 16:00:18 -0700579 vibrate();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800580 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
581 mDigits.onKeyDown(keyCode, event);
582 }
583
584 public boolean onKey(View view, int keyCode, KeyEvent event) {
585 switch (view.getId()) {
586 case R.id.digits:
587 if (keyCode == KeyEvent.KEYCODE_ENTER) {
588 placeCall();
589 return true;
590 }
591 break;
592 }
593 return false;
594 }
595
596 public void onClick(View view) {
597 switch (view.getId()) {
598 case R.id.one: {
599 playTone(ToneGenerator.TONE_DTMF_1);
600 keyPressed(KeyEvent.KEYCODE_1);
601 return;
602 }
603 case R.id.two: {
604 playTone(ToneGenerator.TONE_DTMF_2);
605 keyPressed(KeyEvent.KEYCODE_2);
606 return;
607 }
608 case R.id.three: {
609 playTone(ToneGenerator.TONE_DTMF_3);
610 keyPressed(KeyEvent.KEYCODE_3);
611 return;
612 }
613 case R.id.four: {
614 playTone(ToneGenerator.TONE_DTMF_4);
615 keyPressed(KeyEvent.KEYCODE_4);
616 return;
617 }
618 case R.id.five: {
619 playTone(ToneGenerator.TONE_DTMF_5);
620 keyPressed(KeyEvent.KEYCODE_5);
621 return;
622 }
623 case R.id.six: {
624 playTone(ToneGenerator.TONE_DTMF_6);
625 keyPressed(KeyEvent.KEYCODE_6);
626 return;
627 }
628 case R.id.seven: {
629 playTone(ToneGenerator.TONE_DTMF_7);
630 keyPressed(KeyEvent.KEYCODE_7);
631 return;
632 }
633 case R.id.eight: {
634 playTone(ToneGenerator.TONE_DTMF_8);
635 keyPressed(KeyEvent.KEYCODE_8);
636 return;
637 }
638 case R.id.nine: {
639 playTone(ToneGenerator.TONE_DTMF_9);
640 keyPressed(KeyEvent.KEYCODE_9);
641 return;
642 }
643 case R.id.zero: {
644 playTone(ToneGenerator.TONE_DTMF_0);
645 keyPressed(KeyEvent.KEYCODE_0);
646 return;
647 }
648 case R.id.pound: {
649 playTone(ToneGenerator.TONE_DTMF_P);
650 keyPressed(KeyEvent.KEYCODE_POUND);
651 return;
652 }
653 case R.id.star: {
654 playTone(ToneGenerator.TONE_DTMF_S);
655 keyPressed(KeyEvent.KEYCODE_STAR);
656 return;
657 }
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700658 case R.id.deleteButton: {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800659 keyPressed(KeyEvent.KEYCODE_DEL);
660 return;
661 }
Nicolas Catania3040fa32009-10-01 13:00:53 -0700662 case R.id.dialButton: {
David Brownc29c7ab2009-07-07 16:00:18 -0700663 vibrate(); // Vibrate here too, just like we do for the regular keys
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800664 placeCall();
665 return;
666 }
Nicolas Catania80bda0f2009-09-19 09:17:14 -0700667 case R.id.voicemailButton: {
668 callVoicemail();
669 vibrate();
670 return;
671 }
Nicolas Catania3040fa32009-10-01 13:00:53 -0700672 case R.id.digits: {
673 if (mDigits.length() != 0) {
674 mDigits.setCursorVisible(true);
675 }
676 return;
677 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800678 }
679 }
680
681 public boolean onLongClick(View view) {
682 final Editable digits = mDigits.getText();
683 int id = view.getId();
684 switch (id) {
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700685 case R.id.deleteButton: {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800686 digits.clear();
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700687 // TODO: The framework forgets to clear the pressed
688 // status of disabled button. Until this is fixed,
689 // clear manually the pressed status. b/2133127
690 mDelete.setPressed(false);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800691 return true;
692 }
693 case R.id.one: {
694 if (digits.length() == 0) {
695 callVoicemail();
696 return true;
697 }
698 return false;
699 }
700 case R.id.zero: {
701 keyPressed(KeyEvent.KEYCODE_PLUS);
702 return true;
703 }
704 }
705 return false;
706 }
707
708 void callVoicemail() {
709 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
710 Uri.fromParts("voicemail", "", null));
711 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
712 startActivity(intent);
713 mDigits.getText().clear();
714 finish();
715 }
716
717 void placeCall() {
718 final String number = mDigits.getText().toString();
719 if (number == null || !TextUtils.isGraphic(number)) {
720 // There is no number entered.
721 playTone(ToneGenerator.TONE_PROP_NACK);
722 return;
723 }
724 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
725 Uri.fromParts("tel", number, null));
726 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
727 startActivity(intent);
728 mDigits.getText().clear();
729 finish();
730 }
731
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800732
733 /**
David Brown22f615f2009-06-25 16:19:19 -0700734 * Plays the specified tone for TONE_LENGTH_MS milliseconds.
735 *
736 * The tone is played locally, using the audio stream for phone calls.
737 * Tones are played only if the "Audible touch tones" user preference
738 * is checked, and are NOT played if the device is in silent mode.
739 *
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800740 * @param tone a tone code from {@link ToneGenerator}
741 */
742 void playTone(int tone) {
743 // if local tone playback is disabled, just return.
744 if (!mDTMFToneEnabled) {
745 return;
746 }
David Brown22f615f2009-06-25 16:19:19 -0700747
748 // Also do nothing if the phone is in silent mode.
749 // We need to re-check the ringer mode for *every* playTone()
750 // call, rather than keeping a local flag that's updated in
751 // onResume(), since it's possible to toggle silent mode without
752 // leaving the current activity (via the ENDCALL-longpress menu.)
753 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
David Brownd5a15302009-07-20 16:39:47 -0700754 int ringerMode = audioManager.getRingerMode();
755 if ((ringerMode == AudioManager.RINGER_MODE_SILENT)
756 || (ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
David Brown22f615f2009-06-25 16:19:19 -0700757 return;
758 }
759
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800760 synchronized(mToneGeneratorLock) {
761 if (mToneGenerator == null) {
762 Log.w(TAG, "playTone: mToneGenerator == null, tone: "+tone);
763 return;
764 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700765
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800766 // Start the new tone (will stop any playing tone)
Eric Laurent8487fed2009-09-07 08:45:14 -0700767 mToneGenerator.startTone(tone, TONE_LENGTH_MS);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800768 }
769 }
770
771 /**
772 * Brings up the "dialpad chooser" UI in place of the usual Dialer
773 * elements (the textfield/button and the dialpad underneath).
774 *
775 * We show this UI if the user brings up the Dialer while a call is
776 * already in progress, since there's a good chance we got here
777 * accidentally (and the user really wanted the in-call dialpad instead).
778 * So in this situation we display an intermediate UI that lets the user
779 * explicitly choose between the in-call dialpad ("Use touch tone
780 * keypad") and the regular Dialer ("Add call"). (Or, the option "Return
781 * to call in progress" just goes back to the in-call UI with no dialpad
782 * at all.)
783 *
784 * @param enabled If true, show the "dialpad chooser" instead
785 * of the regular Dialer UI
786 */
787 private void showDialpadChooser(boolean enabled) {
788 if (enabled) {
789 // Log.i(TAG, "Showing dialpad chooser!");
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700790 mDigits.setVisibility(View.GONE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800791 if (mDialpad != null) mDialpad.setVisibility(View.GONE);
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700792 mVoicemailDialAndDeleteRow.setVisibility(View.GONE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800793 mDialpadChooser.setVisibility(View.VISIBLE);
794
795 // Instantiate the DialpadChooserAdapter and hook it up to the
796 // ListView. We do this only once.
797 if (mDialpadChooserAdapter == null) {
798 mDialpadChooserAdapter = new DialpadChooserAdapter(this);
799 mDialpadChooser.setAdapter(mDialpadChooserAdapter);
800 }
801 } else {
802 // Log.i(TAG, "Displaying normal Dialer UI.");
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700803 mDigits.setVisibility(View.VISIBLE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800804 if (mDialpad != null) mDialpad.setVisibility(View.VISIBLE);
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700805 mVoicemailDialAndDeleteRow.setVisibility(View.VISIBLE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800806 mDialpadChooser.setVisibility(View.GONE);
807 }
808 }
809
810 /**
811 * @return true if we're currently showing the "dialpad chooser" UI.
812 */
813 private boolean dialpadChooserVisible() {
814 return mDialpadChooser.getVisibility() == View.VISIBLE;
815 }
816
817 /**
818 * Simple list adapter, binding to an icon + text label
819 * for each item in the "dialpad chooser" list.
820 */
821 private static class DialpadChooserAdapter extends BaseAdapter {
822 private LayoutInflater mInflater;
823
824 // Simple struct for a single "choice" item.
825 static class ChoiceItem {
826 String text;
827 Bitmap icon;
828 int id;
829
830 public ChoiceItem(String s, Bitmap b, int i) {
831 text = s;
832 icon = b;
833 id = i;
834 }
835 }
836
837 // IDs for the possible "choices":
838 static final int DIALPAD_CHOICE_USE_DTMF_DIALPAD = 101;
839 static final int DIALPAD_CHOICE_RETURN_TO_CALL = 102;
840 static final int DIALPAD_CHOICE_ADD_NEW_CALL = 103;
841
842 private static final int NUM_ITEMS = 3;
843 private ChoiceItem mChoiceItems[] = new ChoiceItem[NUM_ITEMS];
844
845 public DialpadChooserAdapter(Context context) {
846 // Cache the LayoutInflate to avoid asking for a new one each time.
847 mInflater = LayoutInflater.from(context);
848
849 // Initialize the possible choices.
850 // TODO: could this be specified entirely in XML?
851
852 // - "Use touch tone keypad"
853 mChoiceItems[0] = new ChoiceItem(
854 context.getString(R.string.dialer_useDtmfDialpad),
855 BitmapFactory.decodeResource(context.getResources(),
856 R.drawable.ic_dialer_fork_tt_keypad),
857 DIALPAD_CHOICE_USE_DTMF_DIALPAD);
858
859 // - "Return to call in progress"
860 mChoiceItems[1] = new ChoiceItem(
861 context.getString(R.string.dialer_returnToInCallScreen),
862 BitmapFactory.decodeResource(context.getResources(),
863 R.drawable.ic_dialer_fork_current_call),
864 DIALPAD_CHOICE_RETURN_TO_CALL);
865
866 // - "Add call"
867 mChoiceItems[2] = new ChoiceItem(
868 context.getString(R.string.dialer_addAnotherCall),
869 BitmapFactory.decodeResource(context.getResources(),
870 R.drawable.ic_dialer_fork_add_call),
871 DIALPAD_CHOICE_ADD_NEW_CALL);
872 }
873
874 public int getCount() {
875 return NUM_ITEMS;
876 }
877
878 /**
879 * Return the ChoiceItem for a given position.
880 */
881 public Object getItem(int position) {
882 return mChoiceItems[position];
883 }
884
885 /**
886 * Return a unique ID for each possible choice.
887 */
888 public long getItemId(int position) {
889 return position;
890 }
891
892 /**
893 * Make a view for each row.
894 */
895 public View getView(int position, View convertView, ViewGroup parent) {
896 // When convertView is non-null, we can reuse it (there's no need
897 // to reinflate it.)
898 if (convertView == null) {
899 convertView = mInflater.inflate(R.layout.dialpad_chooser_list_item, null);
900 }
901
902 TextView text = (TextView) convertView.findViewById(R.id.text);
903 text.setText(mChoiceItems[position].text);
904
905 ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
906 icon.setImageBitmap(mChoiceItems[position].icon);
907
908 return convertView;
909 }
910 }
911
912 /**
913 * Handle clicks from the dialpad chooser.
914 */
915 public void onItemClick(AdapterView parent, View v, int position, long id) {
916 DialpadChooserAdapter.ChoiceItem item =
917 (DialpadChooserAdapter.ChoiceItem) parent.getItemAtPosition(position);
918 int itemId = item.id;
919 switch (itemId) {
920 case DialpadChooserAdapter.DIALPAD_CHOICE_USE_DTMF_DIALPAD:
921 // Log.i(TAG, "DIALPAD_CHOICE_USE_DTMF_DIALPAD");
922 // Fire off an intent to go back to the in-call UI
923 // with the dialpad visible.
924 returnToInCallScreen(true);
925 break;
926
927 case DialpadChooserAdapter.DIALPAD_CHOICE_RETURN_TO_CALL:
928 // Log.i(TAG, "DIALPAD_CHOICE_RETURN_TO_CALL");
929 // Fire off an intent to go back to the in-call UI
930 // (with the dialpad hidden).
931 returnToInCallScreen(false);
932 break;
933
934 case DialpadChooserAdapter.DIALPAD_CHOICE_ADD_NEW_CALL:
935 // Log.i(TAG, "DIALPAD_CHOICE_ADD_NEW_CALL");
936 // Ok, guess the user really did want to be here (in the
937 // regular Dialer) after all. Bring back the normal Dialer UI.
938 showDialpadChooser(false);
939 break;
940
941 default:
942 Log.w(TAG, "onItemClick: unexpected itemId: " + itemId);
943 break;
944 }
945 }
946
947 /**
948 * Returns to the in-call UI (where there's presumably a call in
949 * progress) in response to the user selecting "use touch tone keypad"
950 * or "return to call" from the dialpad chooser.
951 */
952 private void returnToInCallScreen(boolean showDialpad) {
953 try {
954 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
955 if (phone != null) phone.showCallScreenWithDialpad(showDialpad);
956 } catch (RemoteException e) {
957 Log.w(TAG, "phone.showCallScreenWithDialpad() failed", e);
958 }
959
960 // Finally, finish() ourselves so that we don't stay on the
961 // activity stack.
962 // Note that we do this whether or not the showCallScreenWithDialpad()
963 // call above had any effect or not! (That call is a no-op if the
964 // phone is idle, which can happen if the current call ends while
965 // the dialpad chooser is up. In this case we can't show the
966 // InCallScreen, and there's no point staying here in the Dialer,
967 // so we just take the user back where he came from...)
968 finish();
969 }
970
971 /**
972 * @return true if the phone is "in use", meaning that at least one line
973 * is active (ie. off hook or ringing or dialing).
974 */
975 private boolean phoneIsInUse() {
976 boolean phoneInUse = false;
977 try {
978 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
979 if (phone != null) phoneInUse = !phone.isIdle();
980 } catch (RemoteException e) {
981 Log.w(TAG, "phone.isIdle() failed", e);
982 }
983 return phoneInUse;
984 }
David Brownc29c7ab2009-07-07 16:00:18 -0700985
986 /**
987 * Triggers haptic feedback (if enabled) for dialer key presses.
988 */
989 private synchronized void vibrate() {
990 if (!mVibrateOn) {
991 return;
992 }
993 if (mVibrator == null) {
994 mVibrator = new Vibrator();
995 }
Nicolas Catania4c0704a2009-09-23 11:42:00 -0700996 mVibrator.vibrate(mVibratePattern, VIBRATE_NO_REPEAT);
David Brownc29c7ab2009-07-07 16:00:18 -0700997 }
Reli Talc2a2a512009-06-10 16:48:00 -0400998
999 /**
1000 * Returns true whenever any one of the options from the menu is selected.
1001 * Code changes to support dialpad options
1002 */
1003 @Override
1004 public boolean onOptionsItemSelected(MenuItem item) {
1005 switch (item.getItemId()) {
1006 case MENU_2S_PAUSE:
1007 updateDialString(",");
1008 return true;
1009 case MENU_WAIT:
1010 updateDialString(";");
1011 return true;
1012 }
1013 return false;
1014 }
1015
1016 /**
1017 * Updates the dial string (mDigits) after inserting a Pause character (,)
1018 * or Wait character (;).
1019 */
1020 private void updateDialString(String newDigits) {
1021 int selectionStart;
1022 int selectionEnd;
1023
1024 // SpannableStringBuilder editable_text = new SpannableStringBuilder(mDigits.getText());
Eric Fischer686782e2009-09-10 17:57:45 -07001025 int anchor = mDigits.getSelectionStart();
1026 int point = mDigits.getSelectionEnd();
1027
1028 selectionStart = Math.min(anchor, point);
1029 selectionEnd = Math.max(anchor, point);
Reli Talc2a2a512009-06-10 16:48:00 -04001030
1031 Editable digits = mDigits.getText();
1032 if (selectionStart != -1 ) {
1033 if (selectionStart == selectionEnd) {
1034 // then there is no selection. So insert the pause at this
1035 // position and update the mDigits.
1036 digits.replace(selectionStart, selectionStart, newDigits);
1037 } else {
Eric Fischer1e2d3a22009-09-17 10:53:10 -07001038 digits.replace(selectionStart, selectionEnd, newDigits);
Nicolas Catania7edbd0c2009-09-28 20:37:33 -07001039 // Unselect: back to a regular cursor, just pass the character inserted.
1040 mDigits.setSelection(selectionStart + 1);
Reli Talc2a2a512009-06-10 16:48:00 -04001041 }
1042 } else {
1043 int len = mDigits.length();
1044 digits.replace(len, len, newDigits);
1045 }
1046 }
1047
1048 /**
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001049 * Update the enabledness of the "Dial" and "Backspace" buttons if applicable.
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001050 */
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001051 private void updateDialAndDeleteButtonStateEnabledAttr() {
1052 final boolean notEmpty = mDigits.length() != 0;
1053
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001054 if (mDialButton != null) {
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001055 mDialButton.setEnabled(notEmpty);
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001056 }
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001057 mDelete.setEnabled(notEmpty);
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001058 }
1059
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001060
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001061 /**
Nicolas Catania80bda0f2009-09-19 09:17:14 -07001062 * Check if voicemail is enabled/accessible.
1063 */
1064 private void initVoicemailButton() {
1065 boolean hasVoicemail = false;
1066 try {
1067 hasVoicemail = TelephonyManager.getDefault().getVoiceMailNumber() != null;
1068 } catch (SecurityException se) {
1069 // Possibly no READ_PHONE_STATE privilege.
1070 }
1071
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001072 mVoicemailButton = mVoicemailDialAndDeleteRow.findViewById(R.id.voicemailButton);
Nicolas Catania80bda0f2009-09-19 09:17:14 -07001073 if (hasVoicemail) {
1074 mVoicemailButton.setOnClickListener(this);
1075 } else {
1076 mVoicemailButton.setEnabled(false);
1077 }
1078 }
1079
1080 /**
Nicolas Catania4c0704a2009-09-23 11:42:00 -07001081 * Initialize the vibration parameters.
1082 * @param r The Resources with the vibration parameters.
1083 */
1084 private void initVibrationPattern(Resources r) {
1085 int[] pattern = null;
1086 try {
1087 mVibrateOn = r.getBoolean(R.bool.config_enable_dialer_key_vibration);
1088 pattern = r.getIntArray(com.android.internal.R.array.config_virtualKeyVibePattern);
1089 if (null == pattern) {
1090 Log.e(TAG, "Vibrate pattern is null.");
1091 mVibrateOn = false;
1092 }
1093 } catch (Resources.NotFoundException nfe) {
1094 Log.e(TAG, "Vibrate control bool or pattern missing.", nfe);
1095 mVibrateOn = false;
1096 }
1097
1098 if (!mVibrateOn) {
1099 return;
1100 }
1101
1102 // int[] to long[] conversion.
1103 mVibratePattern = new long[pattern.length];
1104 for (int i = 0; i < pattern.length; i++) {
1105 mVibratePattern[i] = pattern[i];
1106 }
1107 }
1108
1109 /**
Reli Talc2a2a512009-06-10 16:48:00 -04001110 * This function return true if Wait menu item can be shown
1111 * otherwise returns false. Assumes the passed string is non-empty
1112 * and the 0th index check is not required.
1113 */
1114 private boolean showWait(int start, int end, String digits) {
1115 if (start == end) {
1116 // visible false in this case
1117 if (start > digits.length()) return false;
1118
1119 // preceding char is ';', so visible should be false
1120 if (digits.charAt(start-1) == ';') return false;
1121
1122 // next char is ';', so visible should be false
1123 if ((digits.length() > start) && (digits.charAt(start) == ';')) return false;
1124 } else {
1125 // visible false in this case
1126 if (start > digits.length() || end > digits.length()) return false;
1127
1128 // In this case we need to just check for ';' preceding to start
1129 // or next to end
1130 if (digits.charAt(start-1) == ';') return false;
1131 }
1132 return true;
1133 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001134}