blob: 58ba9d85440dc2115e8d9e43824227a552c6d2ac [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 {
165 mDigits.setBackgroundDrawable(mDigitsEmptyBackground);
166 }
167
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700168 updateDialAndDeleteButtonStateEnabledAttr();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800169 }
170
171 @Override
172 protected void onCreate(Bundle icicle) {
173 super.onCreate(icicle);
174
175 // Set the content view
176 setContentView(getContentViewResource());
177
Nicolas Catania75993762009-09-21 16:42:00 -0700178 // Load up the resources for the text field.
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800179 Resources r = getResources();
180 mDigitsBackground = r.getDrawable(R.drawable.btn_dial_textfield_active);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800181 mDigitsEmptyBackground = r.getDrawable(R.drawable.btn_dial_textfield);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800182
183 mDigits = (EditText) findViewById(R.id.digits);
184 mDigits.setKeyListener(DialerKeyListener.getInstance());
185 mDigits.setOnClickListener(this);
186 mDigits.setOnKeyListener(this);
187 maybeAddNumberFormatting();
188
189 // Check for the presence of the keypad
190 View view = findViewById(R.id.one);
191 if (view != null) {
192 setupKeypad();
193 }
194
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700195 mVoicemailDialAndDeleteRow = findViewById(R.id.voicemailAndDialAndDelete);
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700196
Nicolas Catania80bda0f2009-09-19 09:17:14 -0700197 initVoicemailButton();
198
David Brown3d07e6d2009-08-04 20:30:09 -0700199 // Check whether we should show the onscreen "Dial" button.
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700200 mDialButton = mVoicemailDialAndDeleteRow.findViewById(R.id.dialButton);
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700201
David Brown3d07e6d2009-08-04 20:30:09 -0700202 if (r.getBoolean(R.bool.config_show_onscreen_dial_button)) {
David Brown3d07e6d2009-08-04 20:30:09 -0700203 mDialButton.setOnClickListener(this);
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700204 } else {
205 mDialButton.setVisibility(View.GONE); // It's VISIBLE by default
206 mDialButton = null;
David Brown3d07e6d2009-08-04 20:30:09 -0700207 }
208
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700209 view = mVoicemailDialAndDeleteRow.findViewById(R.id.deleteButton);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800210 view.setOnClickListener(this);
211 view.setOnLongClickListener(this);
212 mDelete = view;
213
Dmitri Plotnikov032bb362009-05-06 17:05:39 -0700214 mDialpad = findViewById(R.id.dialpad); // This is null in landscape mode
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800215
216 // Set up the "dialpad chooser" UI; see showDialpadChooser().
217 mDialpadChooser = (ListView) findViewById(R.id.dialpadChooser);
218 mDialpadChooser.setOnItemClickListener(this);
219
220 if (!resolveIntent() && icicle != null) {
221 super.onRestoreInstanceState(icicle);
222 }
223
David Brownc29c7ab2009-07-07 16:00:18 -0700224 // TODO: We might eventually need to make mVibrateOn come from a
225 // user preference rather than a per-platform resource, in which
226 // case we would need to update it in onResume() rather than here.
Nicolas Catania4c0704a2009-09-23 11:42:00 -0700227 initVibrationPattern(r);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800228 }
229
230 @Override
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800231 protected void onRestoreInstanceState(Bundle icicle) {
232 // Do nothing, state is restored in onCreate() if needed
233 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700234
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800235 protected void maybeAddNumberFormatting() {
236 mDigits.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
237 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700238
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800239 /**
Eric Laurentd9efc872009-07-17 11:52:06 -0700240 * Overridden by subclasses to control the resource used by the content view.
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800241 */
242 protected int getContentViewResource() {
243 return R.layout.twelve_key_dialer;
244 }
245
246 private boolean resolveIntent() {
247 boolean ignoreState = false;
248
249 // Find the proper intent
250 final Intent intent;
251 if (isChild()) {
252 intent = getParent().getIntent();
253 ignoreState = intent.getBooleanExtra(DialtactsActivity.EXTRA_IGNORE_STATE, false);
254 } else {
255 intent = getIntent();
256 }
257 // Log.i(TAG, "==> resolveIntent(): intent: " + intent);
258
259 // by default we are not adding a call.
260 mIsAddCallMode = false;
261
262 // By default we don't show the "dialpad chooser" UI.
263 boolean needToShowDialpadChooser = false;
264
265 // Resolve the intent
266 final String action = intent.getAction();
267 if (Intent.ACTION_DIAL.equals(action) || Intent.ACTION_VIEW.equals(action)) {
268 // see if we are "adding a call" from the InCallScreen; false by default.
269 mIsAddCallMode = intent.getBooleanExtra(ADD_CALL_MODE_KEY, false);
270 Uri uri = intent.getData();
271 if (uri != null) {
272 if ("tel".equals(uri.getScheme())) {
273 // Put the requested number into the input area
274 String data = uri.getSchemeSpecificPart();
275 setFormattedDigits(data);
276 } else {
277 String type = intent.getType();
278 if (People.CONTENT_ITEM_TYPE.equals(type)
279 || Phones.CONTENT_ITEM_TYPE.equals(type)) {
280 // Query the phone number
281 Cursor c = getContentResolver().query(intent.getData(),
282 new String[] {PhonesColumns.NUMBER}, null, null, null);
283 if (c != null) {
284 if (c.moveToFirst()) {
285 // Put the number into the input area
286 setFormattedDigits(c.getString(0));
287 }
288 c.close();
289 }
290 }
291 }
292 }
293 } else if (Intent.ACTION_MAIN.equals(action)) {
294 // The MAIN action means we're bringing up a blank dialer
295 // (e.g. by selecting the Home shortcut, or tabbing over from
296 // Contacts or Call log.)
297 //
298 // At this point, IF there's already an active call, there's a
299 // good chance that the user got here accidentally (but really
300 // wanted the in-call dialpad instead). So we bring up an
301 // intermediate UI to make the user confirm what they really
302 // want to do.
303 if (phoneIsInUse()) {
304 // Log.i(TAG, "resolveIntent(): phone is in use; showing dialpad chooser!");
305 needToShowDialpadChooser = true;
306 }
307 }
308
309 // Bring up the "dialpad chooser" IFF we need to make the user
310 // confirm which dialpad they really want.
311 showDialpadChooser(needToShowDialpadChooser);
312
313 return ignoreState;
314 }
315
316 protected void setFormattedDigits(String data) {
317 // strip the non-dialable numbers out of the data string.
318 String dialString = PhoneNumberUtils.extractNetworkPortion(data);
319 dialString = PhoneNumberUtils.formatNumber(dialString);
320 if (!TextUtils.isEmpty(dialString)) {
321 Editable digits = mDigits.getText();
322 digits.replace(0, digits.length(), dialString);
Karl Rosaenf46bc312009-03-24 18:20:48 -0700323 // for some reason this isn't getting called in the digits.replace call above..
324 // but in any case, this will make sure the background drawable looks right
325 afterTextChanged(digits);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800326 }
327 }
328
329 @Override
330 protected void onNewIntent(Intent newIntent) {
331 setIntent(newIntent);
332 resolveIntent();
333 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700334
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800335 @Override
336 protected void onPostCreate(Bundle savedInstanceState) {
337 super.onPostCreate(savedInstanceState);
338
339 // This can't be done in onCreate(), since the auto-restoring of the digits
340 // will play DTMF tones for all the old digits if it is when onRestoreSavedInstanceState()
341 // is called. This method will be called every time the activity is created, and
342 // will always happen after onRestoreSavedInstanceState().
343 mDigits.addTextChangedListener(this);
344 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700345
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800346 private void setupKeypad() {
347 // Setup the listeners for the buttons
348 View view = findViewById(R.id.one);
349 view.setOnClickListener(this);
350 view.setOnLongClickListener(this);
351
352 findViewById(R.id.two).setOnClickListener(this);
353 findViewById(R.id.three).setOnClickListener(this);
354 findViewById(R.id.four).setOnClickListener(this);
355 findViewById(R.id.five).setOnClickListener(this);
356 findViewById(R.id.six).setOnClickListener(this);
357 findViewById(R.id.seven).setOnClickListener(this);
358 findViewById(R.id.eight).setOnClickListener(this);
359 findViewById(R.id.nine).setOnClickListener(this);
360 findViewById(R.id.star).setOnClickListener(this);
361
362 view = findViewById(R.id.zero);
363 view.setOnClickListener(this);
364 view.setOnLongClickListener(this);
365
366 findViewById(R.id.pound).setOnClickListener(this);
367 }
368
369 @Override
370 protected void onResume() {
371 super.onResume();
David Brownc29c7ab2009-07-07 16:00:18 -0700372
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800373 // retrieve the DTMF tone play back setting.
374 mDTMFToneEnabled = Settings.System.getInt(getContentResolver(),
375 Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
376
Eric Laurentd9efc872009-07-17 11:52:06 -0700377 // if the mToneGenerator creation fails, just continue without it. It is
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800378 // a local audio signal, and is not as important as the dtmf tone itself.
379 synchronized(mToneGeneratorLock) {
380 if (mToneGenerator == null) {
381 try {
Eric Laurentd9efc872009-07-17 11:52:06 -0700382 mToneGenerator = new ToneGenerator(AudioManager.STREAM_DTMF,
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800383 TONE_RELATIVE_VOLUME);
384 } catch (RuntimeException e) {
385 Log.w(TAG, "Exception caught while creating local tone generator: " + e);
386 mToneGenerator = null;
387 }
388 }
389 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700390
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800391 Activity parent = getParent();
392 // See if we were invoked with a DIAL intent. If we were, fill in the appropriate
393 // digits in the dialer field.
394 if (parent != null && parent instanceof DialtactsActivity) {
395 Uri dialUri = ((DialtactsActivity) parent).getAndClearDialUri();
396 if (dialUri != null) {
397 resolveIntent();
398 }
399 }
400
401 // While we're in the foreground, listen for phone state changes,
402 // purely so that we can take down the "dialpad chooser" if the
403 // phone becomes idle while the chooser UI is visible.
404 TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
405 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
406
407 // Potentially show hint text in the mDigits field when the user
408 // hasn't typed any digits yet. (If there's already an active call,
409 // this hint text will remind the user that he's about to add a new
410 // call.)
411 //
412 // TODO: consider adding better UI for the case where *both* lines
413 // are currently in use. (Right now we let the user try to add
414 // another call, but that call is guaranteed to fail. Perhaps the
415 // entire dialer UI should be disabled instead.)
416 if (phoneIsInUse()) {
417 mDigits.setHint(R.string.dialerDialpadHintText);
418 } else {
419 // Common case; no hint necessary.
420 mDigits.setHint(null);
421
422 // Also, a sanity-check: the "dialpad chooser" UI should NEVER
423 // be visible if the phone is idle!
424 showDialpadChooser(false);
425 }
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700426
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700427 updateDialAndDeleteButtonStateEnabledAttr();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800428 }
429
430 @Override
Karl Rosaenf46bc312009-03-24 18:20:48 -0700431 public void onWindowFocusChanged(boolean hasFocus) {
432 if (hasFocus) {
433 // Hide soft keyboard, if visible (it's fugly over button dialer).
434 // The only known case where this will be true is when launching the dialer with
435 // ACTION_DIAL via a soft keyboard. we dismiss it here because we don't
436 // have a window token yet in onCreate / onNewIntent
437 InputMethodManager inputMethodManager = (InputMethodManager)
438 getSystemService(Context.INPUT_METHOD_SERVICE);
Eric Laurentd9efc872009-07-17 11:52:06 -0700439 inputMethodManager.hideSoftInputFromWindow(mDigits.getWindowToken(), 0);
Karl Rosaenf46bc312009-03-24 18:20:48 -0700440 }
441 }
442
443 @Override
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800444 protected void onPause() {
445 super.onPause();
446
447 // Stop listening for phone state changes.
448 TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
449 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
450
451 synchronized(mToneGeneratorLock) {
452 if (mToneGenerator != null) {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800453 mToneGenerator.release();
454 mToneGenerator = null;
455 }
456 }
457 }
458
459 @Override
460 public boolean onCreateOptionsMenu(Menu menu) {
Reli Talc2a2a512009-06-10 16:48:00 -0400461 mAddToContactMenuItem = menu.add(0, MENU_ADD_CONTACTS, 0, R.string.recentCalls_addToContact)
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800462 .setIcon(android.R.drawable.ic_menu_add);
Reli Talc2a2a512009-06-10 16:48:00 -0400463 m2SecPauseMenuItem = menu.add(0, MENU_2S_PAUSE, 0, R.string.add_2sec_pause)
464 .setIcon(R.drawable.ic_menu_2sec_pause);
465 mWaitMenuItem = menu.add(0, MENU_WAIT, 0, R.string.add_wait)
466 .setIcon(R.drawable.ic_menu_wait);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800467 return true;
468 }
469
470 @Override
471 public boolean onPrepareOptionsMenu(Menu menu) {
472 // We never show a menu if the "choose dialpad" UI is up.
473 if (dialpadChooserVisible()) {
474 return false;
475 }
476
477 CharSequence digits = mDigits.getText();
478 if (digits == null || !TextUtils.isGraphic(digits)) {
479 mAddToContactMenuItem.setVisible(false);
Reli Talc2a2a512009-06-10 16:48:00 -0400480 m2SecPauseMenuItem.setVisible(false);
481 mWaitMenuItem.setVisible(false);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800482 } else {
483 // Put the current digits string into an intent
484 Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
485 intent.putExtra(Insert.PHONE, mDigits.getText());
486 intent.setType(People.CONTENT_ITEM_TYPE);
487 mAddToContactMenuItem.setIntent(intent);
488 mAddToContactMenuItem.setVisible(true);
Reli Talc2a2a512009-06-10 16:48:00 -0400489
490 // Check out whether to show Pause & Wait option menu items
491 int selectionStart;
492 int selectionEnd;
493 String strDigits = digits.toString();
494
495 selectionStart = mDigits.getSelectionStart();
496 selectionEnd = mDigits.getSelectionEnd();
497
498 if (selectionStart != -1) {
499 if (selectionStart > selectionEnd) {
500 // swap it as we want start to be less then end
501 int tmp = selectionStart;
502 selectionStart = selectionEnd;
503 selectionEnd = tmp;
504 }
505
506 if (selectionStart != 0) {
507 // Pause can be visible if cursor is not in the begining
508 m2SecPauseMenuItem.setVisible(true);
509
510 // For Wait to be visible set of condition to meet
511 mWaitMenuItem.setVisible(showWait(selectionStart,
512 selectionEnd, strDigits));
513 } else {
514 // cursor in the beginning both pause and wait to be invisible
515 m2SecPauseMenuItem.setVisible(false);
516 mWaitMenuItem.setVisible(false);
517 }
518 } else {
519 // cursor is not selected so assume new digit is added to the end
520 int strLength = strDigits.length();
521 mWaitMenuItem.setVisible(showWait(strLength,
522 strLength, strDigits));
523 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800524 }
525 return true;
526 }
527
528 @Override
529 public boolean onKeyDown(int keyCode, KeyEvent event) {
530 switch (keyCode) {
531 case KeyEvent.KEYCODE_CALL: {
532 long callPressDiff = SystemClock.uptimeMillis() - event.getDownTime();
533 if (callPressDiff >= ViewConfiguration.getLongPressTimeout()) {
534 // Launch voice dialer
535 Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
536 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
537 try {
538 startActivity(intent);
539 } catch (ActivityNotFoundException e) {
540 }
541 }
542 return true;
543 }
544 case KeyEvent.KEYCODE_1: {
Eric Laurentd9efc872009-07-17 11:52:06 -0700545 long timeDiff = SystemClock.uptimeMillis() - event.getDownTime();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800546 if (timeDiff >= ViewConfiguration.getLongPressTimeout()) {
547 // Long press detected, call voice mail
548 callVoicemail();
549 }
550 return true;
551 }
552 }
553 return super.onKeyDown(keyCode, event);
554 }
555
556 @Override
557 public boolean onKeyUp(int keyCode, KeyEvent event) {
558 switch (keyCode) {
559 case KeyEvent.KEYCODE_CALL: {
560 if (mIsAddCallMode && (TextUtils.isEmpty(mDigits.getText().toString()))) {
561 // if we are adding a call from the InCallScreen and the phone
562 // number entered is empty, we just close the dialer to expose
563 // the InCallScreen under it.
564 finish();
565 } else {
566 // otherwise, we place the call.
567 placeCall();
568 }
569 return true;
570 }
571 }
572 return super.onKeyUp(keyCode, event);
573 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700574
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800575 private void keyPressed(int keyCode) {
David Brownc29c7ab2009-07-07 16:00:18 -0700576 vibrate();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800577 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
578 mDigits.onKeyDown(keyCode, event);
579 }
580
581 public boolean onKey(View view, int keyCode, KeyEvent event) {
582 switch (view.getId()) {
583 case R.id.digits:
584 if (keyCode == KeyEvent.KEYCODE_ENTER) {
585 placeCall();
586 return true;
587 }
588 break;
589 }
590 return false;
591 }
592
593 public void onClick(View view) {
594 switch (view.getId()) {
595 case R.id.one: {
596 playTone(ToneGenerator.TONE_DTMF_1);
597 keyPressed(KeyEvent.KEYCODE_1);
598 return;
599 }
600 case R.id.two: {
601 playTone(ToneGenerator.TONE_DTMF_2);
602 keyPressed(KeyEvent.KEYCODE_2);
603 return;
604 }
605 case R.id.three: {
606 playTone(ToneGenerator.TONE_DTMF_3);
607 keyPressed(KeyEvent.KEYCODE_3);
608 return;
609 }
610 case R.id.four: {
611 playTone(ToneGenerator.TONE_DTMF_4);
612 keyPressed(KeyEvent.KEYCODE_4);
613 return;
614 }
615 case R.id.five: {
616 playTone(ToneGenerator.TONE_DTMF_5);
617 keyPressed(KeyEvent.KEYCODE_5);
618 return;
619 }
620 case R.id.six: {
621 playTone(ToneGenerator.TONE_DTMF_6);
622 keyPressed(KeyEvent.KEYCODE_6);
623 return;
624 }
625 case R.id.seven: {
626 playTone(ToneGenerator.TONE_DTMF_7);
627 keyPressed(KeyEvent.KEYCODE_7);
628 return;
629 }
630 case R.id.eight: {
631 playTone(ToneGenerator.TONE_DTMF_8);
632 keyPressed(KeyEvent.KEYCODE_8);
633 return;
634 }
635 case R.id.nine: {
636 playTone(ToneGenerator.TONE_DTMF_9);
637 keyPressed(KeyEvent.KEYCODE_9);
638 return;
639 }
640 case R.id.zero: {
641 playTone(ToneGenerator.TONE_DTMF_0);
642 keyPressed(KeyEvent.KEYCODE_0);
643 return;
644 }
645 case R.id.pound: {
646 playTone(ToneGenerator.TONE_DTMF_P);
647 keyPressed(KeyEvent.KEYCODE_POUND);
648 return;
649 }
650 case R.id.star: {
651 playTone(ToneGenerator.TONE_DTMF_S);
652 keyPressed(KeyEvent.KEYCODE_STAR);
653 return;
654 }
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700655 case R.id.deleteButton: {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800656 keyPressed(KeyEvent.KEYCODE_DEL);
657 return;
658 }
David Brown3d07e6d2009-08-04 20:30:09 -0700659 case R.id.dialButton:
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800660 case R.id.digits: {
David Brownc29c7ab2009-07-07 16:00:18 -0700661 vibrate(); // Vibrate here too, just like we do for the regular keys
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800662 placeCall();
663 return;
664 }
Nicolas Catania80bda0f2009-09-19 09:17:14 -0700665 case R.id.voicemailButton: {
666 callVoicemail();
667 vibrate();
668 return;
669 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800670 }
671 }
672
673 public boolean onLongClick(View view) {
674 final Editable digits = mDigits.getText();
675 int id = view.getId();
676 switch (id) {
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700677 case R.id.deleteButton: {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800678 digits.clear();
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700679 // TODO: The framework forgets to clear the pressed
680 // status of disabled button. Until this is fixed,
681 // clear manually the pressed status. b/2133127
682 mDelete.setPressed(false);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800683 return true;
684 }
685 case R.id.one: {
686 if (digits.length() == 0) {
687 callVoicemail();
688 return true;
689 }
690 return false;
691 }
692 case R.id.zero: {
693 keyPressed(KeyEvent.KEYCODE_PLUS);
694 return true;
695 }
696 }
697 return false;
698 }
699
700 void callVoicemail() {
701 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
702 Uri.fromParts("voicemail", "", null));
703 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
704 startActivity(intent);
705 mDigits.getText().clear();
706 finish();
707 }
708
709 void placeCall() {
710 final String number = mDigits.getText().toString();
711 if (number == null || !TextUtils.isGraphic(number)) {
712 // There is no number entered.
713 playTone(ToneGenerator.TONE_PROP_NACK);
714 return;
715 }
716 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
717 Uri.fromParts("tel", number, null));
718 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
719 startActivity(intent);
720 mDigits.getText().clear();
721 finish();
722 }
723
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800724
725 /**
David Brown22f615f2009-06-25 16:19:19 -0700726 * Plays the specified tone for TONE_LENGTH_MS milliseconds.
727 *
728 * The tone is played locally, using the audio stream for phone calls.
729 * Tones are played only if the "Audible touch tones" user preference
730 * is checked, and are NOT played if the device is in silent mode.
731 *
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800732 * @param tone a tone code from {@link ToneGenerator}
733 */
734 void playTone(int tone) {
735 // if local tone playback is disabled, just return.
736 if (!mDTMFToneEnabled) {
737 return;
738 }
David Brown22f615f2009-06-25 16:19:19 -0700739
740 // Also do nothing if the phone is in silent mode.
741 // We need to re-check the ringer mode for *every* playTone()
742 // call, rather than keeping a local flag that's updated in
743 // onResume(), since it's possible to toggle silent mode without
744 // leaving the current activity (via the ENDCALL-longpress menu.)
745 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
David Brownd5a15302009-07-20 16:39:47 -0700746 int ringerMode = audioManager.getRingerMode();
747 if ((ringerMode == AudioManager.RINGER_MODE_SILENT)
748 || (ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
David Brown22f615f2009-06-25 16:19:19 -0700749 return;
750 }
751
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800752 synchronized(mToneGeneratorLock) {
753 if (mToneGenerator == null) {
754 Log.w(TAG, "playTone: mToneGenerator == null, tone: "+tone);
755 return;
756 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700757
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800758 // Start the new tone (will stop any playing tone)
Eric Laurent8487fed2009-09-07 08:45:14 -0700759 mToneGenerator.startTone(tone, TONE_LENGTH_MS);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800760 }
761 }
762
763 /**
764 * Brings up the "dialpad chooser" UI in place of the usual Dialer
765 * elements (the textfield/button and the dialpad underneath).
766 *
767 * We show this UI if the user brings up the Dialer while a call is
768 * already in progress, since there's a good chance we got here
769 * accidentally (and the user really wanted the in-call dialpad instead).
770 * So in this situation we display an intermediate UI that lets the user
771 * explicitly choose between the in-call dialpad ("Use touch tone
772 * keypad") and the regular Dialer ("Add call"). (Or, the option "Return
773 * to call in progress" just goes back to the in-call UI with no dialpad
774 * at all.)
775 *
776 * @param enabled If true, show the "dialpad chooser" instead
777 * of the regular Dialer UI
778 */
779 private void showDialpadChooser(boolean enabled) {
780 if (enabled) {
781 // Log.i(TAG, "Showing dialpad chooser!");
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700782 mDigits.setVisibility(View.GONE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800783 if (mDialpad != null) mDialpad.setVisibility(View.GONE);
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700784 mVoicemailDialAndDeleteRow.setVisibility(View.GONE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800785 mDialpadChooser.setVisibility(View.VISIBLE);
786
787 // Instantiate the DialpadChooserAdapter and hook it up to the
788 // ListView. We do this only once.
789 if (mDialpadChooserAdapter == null) {
790 mDialpadChooserAdapter = new DialpadChooserAdapter(this);
791 mDialpadChooser.setAdapter(mDialpadChooserAdapter);
792 }
793 } else {
794 // Log.i(TAG, "Displaying normal Dialer UI.");
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700795 mDigits.setVisibility(View.VISIBLE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800796 if (mDialpad != null) mDialpad.setVisibility(View.VISIBLE);
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700797 mVoicemailDialAndDeleteRow.setVisibility(View.VISIBLE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800798 mDialpadChooser.setVisibility(View.GONE);
799 }
800 }
801
802 /**
803 * @return true if we're currently showing the "dialpad chooser" UI.
804 */
805 private boolean dialpadChooserVisible() {
806 return mDialpadChooser.getVisibility() == View.VISIBLE;
807 }
808
809 /**
810 * Simple list adapter, binding to an icon + text label
811 * for each item in the "dialpad chooser" list.
812 */
813 private static class DialpadChooserAdapter extends BaseAdapter {
814 private LayoutInflater mInflater;
815
816 // Simple struct for a single "choice" item.
817 static class ChoiceItem {
818 String text;
819 Bitmap icon;
820 int id;
821
822 public ChoiceItem(String s, Bitmap b, int i) {
823 text = s;
824 icon = b;
825 id = i;
826 }
827 }
828
829 // IDs for the possible "choices":
830 static final int DIALPAD_CHOICE_USE_DTMF_DIALPAD = 101;
831 static final int DIALPAD_CHOICE_RETURN_TO_CALL = 102;
832 static final int DIALPAD_CHOICE_ADD_NEW_CALL = 103;
833
834 private static final int NUM_ITEMS = 3;
835 private ChoiceItem mChoiceItems[] = new ChoiceItem[NUM_ITEMS];
836
837 public DialpadChooserAdapter(Context context) {
838 // Cache the LayoutInflate to avoid asking for a new one each time.
839 mInflater = LayoutInflater.from(context);
840
841 // Initialize the possible choices.
842 // TODO: could this be specified entirely in XML?
843
844 // - "Use touch tone keypad"
845 mChoiceItems[0] = new ChoiceItem(
846 context.getString(R.string.dialer_useDtmfDialpad),
847 BitmapFactory.decodeResource(context.getResources(),
848 R.drawable.ic_dialer_fork_tt_keypad),
849 DIALPAD_CHOICE_USE_DTMF_DIALPAD);
850
851 // - "Return to call in progress"
852 mChoiceItems[1] = new ChoiceItem(
853 context.getString(R.string.dialer_returnToInCallScreen),
854 BitmapFactory.decodeResource(context.getResources(),
855 R.drawable.ic_dialer_fork_current_call),
856 DIALPAD_CHOICE_RETURN_TO_CALL);
857
858 // - "Add call"
859 mChoiceItems[2] = new ChoiceItem(
860 context.getString(R.string.dialer_addAnotherCall),
861 BitmapFactory.decodeResource(context.getResources(),
862 R.drawable.ic_dialer_fork_add_call),
863 DIALPAD_CHOICE_ADD_NEW_CALL);
864 }
865
866 public int getCount() {
867 return NUM_ITEMS;
868 }
869
870 /**
871 * Return the ChoiceItem for a given position.
872 */
873 public Object getItem(int position) {
874 return mChoiceItems[position];
875 }
876
877 /**
878 * Return a unique ID for each possible choice.
879 */
880 public long getItemId(int position) {
881 return position;
882 }
883
884 /**
885 * Make a view for each row.
886 */
887 public View getView(int position, View convertView, ViewGroup parent) {
888 // When convertView is non-null, we can reuse it (there's no need
889 // to reinflate it.)
890 if (convertView == null) {
891 convertView = mInflater.inflate(R.layout.dialpad_chooser_list_item, null);
892 }
893
894 TextView text = (TextView) convertView.findViewById(R.id.text);
895 text.setText(mChoiceItems[position].text);
896
897 ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
898 icon.setImageBitmap(mChoiceItems[position].icon);
899
900 return convertView;
901 }
902 }
903
904 /**
905 * Handle clicks from the dialpad chooser.
906 */
907 public void onItemClick(AdapterView parent, View v, int position, long id) {
908 DialpadChooserAdapter.ChoiceItem item =
909 (DialpadChooserAdapter.ChoiceItem) parent.getItemAtPosition(position);
910 int itemId = item.id;
911 switch (itemId) {
912 case DialpadChooserAdapter.DIALPAD_CHOICE_USE_DTMF_DIALPAD:
913 // Log.i(TAG, "DIALPAD_CHOICE_USE_DTMF_DIALPAD");
914 // Fire off an intent to go back to the in-call UI
915 // with the dialpad visible.
916 returnToInCallScreen(true);
917 break;
918
919 case DialpadChooserAdapter.DIALPAD_CHOICE_RETURN_TO_CALL:
920 // Log.i(TAG, "DIALPAD_CHOICE_RETURN_TO_CALL");
921 // Fire off an intent to go back to the in-call UI
922 // (with the dialpad hidden).
923 returnToInCallScreen(false);
924 break;
925
926 case DialpadChooserAdapter.DIALPAD_CHOICE_ADD_NEW_CALL:
927 // Log.i(TAG, "DIALPAD_CHOICE_ADD_NEW_CALL");
928 // Ok, guess the user really did want to be here (in the
929 // regular Dialer) after all. Bring back the normal Dialer UI.
930 showDialpadChooser(false);
931 break;
932
933 default:
934 Log.w(TAG, "onItemClick: unexpected itemId: " + itemId);
935 break;
936 }
937 }
938
939 /**
940 * Returns to the in-call UI (where there's presumably a call in
941 * progress) in response to the user selecting "use touch tone keypad"
942 * or "return to call" from the dialpad chooser.
943 */
944 private void returnToInCallScreen(boolean showDialpad) {
945 try {
946 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
947 if (phone != null) phone.showCallScreenWithDialpad(showDialpad);
948 } catch (RemoteException e) {
949 Log.w(TAG, "phone.showCallScreenWithDialpad() failed", e);
950 }
951
952 // Finally, finish() ourselves so that we don't stay on the
953 // activity stack.
954 // Note that we do this whether or not the showCallScreenWithDialpad()
955 // call above had any effect or not! (That call is a no-op if the
956 // phone is idle, which can happen if the current call ends while
957 // the dialpad chooser is up. In this case we can't show the
958 // InCallScreen, and there's no point staying here in the Dialer,
959 // so we just take the user back where he came from...)
960 finish();
961 }
962
963 /**
964 * @return true if the phone is "in use", meaning that at least one line
965 * is active (ie. off hook or ringing or dialing).
966 */
967 private boolean phoneIsInUse() {
968 boolean phoneInUse = false;
969 try {
970 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
971 if (phone != null) phoneInUse = !phone.isIdle();
972 } catch (RemoteException e) {
973 Log.w(TAG, "phone.isIdle() failed", e);
974 }
975 return phoneInUse;
976 }
David Brownc29c7ab2009-07-07 16:00:18 -0700977
978 /**
979 * Triggers haptic feedback (if enabled) for dialer key presses.
980 */
981 private synchronized void vibrate() {
982 if (!mVibrateOn) {
983 return;
984 }
985 if (mVibrator == null) {
986 mVibrator = new Vibrator();
987 }
Nicolas Catania4c0704a2009-09-23 11:42:00 -0700988 mVibrator.vibrate(mVibratePattern, VIBRATE_NO_REPEAT);
David Brownc29c7ab2009-07-07 16:00:18 -0700989 }
Reli Talc2a2a512009-06-10 16:48:00 -0400990
991 /**
992 * Returns true whenever any one of the options from the menu is selected.
993 * Code changes to support dialpad options
994 */
995 @Override
996 public boolean onOptionsItemSelected(MenuItem item) {
997 switch (item.getItemId()) {
998 case MENU_2S_PAUSE:
999 updateDialString(",");
1000 return true;
1001 case MENU_WAIT:
1002 updateDialString(";");
1003 return true;
1004 }
1005 return false;
1006 }
1007
1008 /**
1009 * Updates the dial string (mDigits) after inserting a Pause character (,)
1010 * or Wait character (;).
1011 */
1012 private void updateDialString(String newDigits) {
1013 int selectionStart;
1014 int selectionEnd;
1015
1016 // SpannableStringBuilder editable_text = new SpannableStringBuilder(mDigits.getText());
Eric Fischer686782e2009-09-10 17:57:45 -07001017 int anchor = mDigits.getSelectionStart();
1018 int point = mDigits.getSelectionEnd();
1019
1020 selectionStart = Math.min(anchor, point);
1021 selectionEnd = Math.max(anchor, point);
Reli Talc2a2a512009-06-10 16:48:00 -04001022
1023 Editable digits = mDigits.getText();
1024 if (selectionStart != -1 ) {
1025 if (selectionStart == selectionEnd) {
1026 // then there is no selection. So insert the pause at this
1027 // position and update the mDigits.
1028 digits.replace(selectionStart, selectionStart, newDigits);
1029 } else {
Eric Fischer1e2d3a22009-09-17 10:53:10 -07001030 digits.replace(selectionStart, selectionEnd, newDigits);
Nicolas Catania7edbd0c2009-09-28 20:37:33 -07001031 // Unselect: back to a regular cursor, just pass the character inserted.
1032 mDigits.setSelection(selectionStart + 1);
Reli Talc2a2a512009-06-10 16:48:00 -04001033 }
1034 } else {
1035 int len = mDigits.length();
1036 digits.replace(len, len, newDigits);
1037 }
1038 }
1039
1040 /**
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001041 * Update the enabledness of the "Dial" and "Backspace" buttons if applicable.
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001042 */
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001043 private void updateDialAndDeleteButtonStateEnabledAttr() {
1044 final boolean notEmpty = mDigits.length() != 0;
1045
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001046 if (mDialButton != null) {
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001047 mDialButton.setEnabled(notEmpty);
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001048 }
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001049 mDelete.setEnabled(notEmpty);
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001050 }
1051
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001052
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001053 /**
Nicolas Catania80bda0f2009-09-19 09:17:14 -07001054 * Check if voicemail is enabled/accessible.
1055 */
1056 private void initVoicemailButton() {
1057 boolean hasVoicemail = false;
1058 try {
1059 hasVoicemail = TelephonyManager.getDefault().getVoiceMailNumber() != null;
1060 } catch (SecurityException se) {
1061 // Possibly no READ_PHONE_STATE privilege.
1062 }
1063
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001064 mVoicemailButton = mVoicemailDialAndDeleteRow.findViewById(R.id.voicemailButton);
Nicolas Catania80bda0f2009-09-19 09:17:14 -07001065 if (hasVoicemail) {
1066 mVoicemailButton.setOnClickListener(this);
1067 } else {
1068 mVoicemailButton.setEnabled(false);
1069 }
1070 }
1071
1072 /**
Nicolas Catania4c0704a2009-09-23 11:42:00 -07001073 * Initialize the vibration parameters.
1074 * @param r The Resources with the vibration parameters.
1075 */
1076 private void initVibrationPattern(Resources r) {
1077 int[] pattern = null;
1078 try {
1079 mVibrateOn = r.getBoolean(R.bool.config_enable_dialer_key_vibration);
1080 pattern = r.getIntArray(com.android.internal.R.array.config_virtualKeyVibePattern);
1081 if (null == pattern) {
1082 Log.e(TAG, "Vibrate pattern is null.");
1083 mVibrateOn = false;
1084 }
1085 } catch (Resources.NotFoundException nfe) {
1086 Log.e(TAG, "Vibrate control bool or pattern missing.", nfe);
1087 mVibrateOn = false;
1088 }
1089
1090 if (!mVibrateOn) {
1091 return;
1092 }
1093
1094 // int[] to long[] conversion.
1095 mVibratePattern = new long[pattern.length];
1096 for (int i = 0; i < pattern.length; i++) {
1097 mVibratePattern[i] = pattern[i];
1098 }
1099 }
1100
1101 /**
Reli Talc2a2a512009-06-10 16:48:00 -04001102 * This function return true if Wait menu item can be shown
1103 * otherwise returns false. Assumes the passed string is non-empty
1104 * and the 0th index check is not required.
1105 */
1106 private boolean showWait(int start, int end, String digits) {
1107 if (start == end) {
1108 // visible false in this case
1109 if (start > digits.length()) return false;
1110
1111 // preceding char is ';', so visible should be false
1112 if (digits.charAt(start-1) == ';') return false;
1113
1114 // next char is ';', so visible should be false
1115 if ((digits.length() > start) && (digits.charAt(start) == ';')) return false;
1116 } else {
1117 // visible false in this case
1118 if (start > digits.length() || end > digits.length()) return false;
1119
1120 // In this case we need to just check for ';' preceding to start
1121 // or next to end
1122 if (digits.charAt(start-1) == ';') return false;
1123 }
1124 return true;
1125 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001126}