blob: 0eb9c9439795da28eaa922ca7e84d352f2a92191 [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
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800189 maybeAddNumberFormatting();
190
191 // Check for the presence of the keypad
192 View view = findViewById(R.id.one);
193 if (view != null) {
194 setupKeypad();
195 }
196
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700197 mVoicemailDialAndDeleteRow = findViewById(R.id.voicemailAndDialAndDelete);
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700198
Nicolas Catania80bda0f2009-09-19 09:17:14 -0700199 initVoicemailButton();
200
David Brown3d07e6d2009-08-04 20:30:09 -0700201 // Check whether we should show the onscreen "Dial" button.
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700202 mDialButton = mVoicemailDialAndDeleteRow.findViewById(R.id.dialButton);
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700203
David Brown3d07e6d2009-08-04 20:30:09 -0700204 if (r.getBoolean(R.bool.config_show_onscreen_dial_button)) {
David Brown3d07e6d2009-08-04 20:30:09 -0700205 mDialButton.setOnClickListener(this);
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700206 } else {
207 mDialButton.setVisibility(View.GONE); // It's VISIBLE by default
208 mDialButton = null;
David Brown3d07e6d2009-08-04 20:30:09 -0700209 }
210
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700211 view = mVoicemailDialAndDeleteRow.findViewById(R.id.deleteButton);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800212 view.setOnClickListener(this);
213 view.setOnLongClickListener(this);
214 mDelete = view;
215
Nicolas Catania901f8562009-10-09 11:09:45 -0700216 mDialpad = findViewById(R.id.dialpad); // This is null in landscape mode.
217
218 // In landscape we put the keyboard in phone mode.
219 // In portrait we prevent the soft keyboard to show since the
220 // dialpad acts as one already.
221 if (null == mDialpad) {
222 mDigits.setInputType(android.text.InputType.TYPE_CLASS_PHONE);
223 } else {
224 mDigits.setInputType(android.text.InputType.TYPE_NULL);
225 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800226
227 // Set up the "dialpad chooser" UI; see showDialpadChooser().
228 mDialpadChooser = (ListView) findViewById(R.id.dialpadChooser);
229 mDialpadChooser.setOnItemClickListener(this);
230
231 if (!resolveIntent() && icicle != null) {
232 super.onRestoreInstanceState(icicle);
233 }
234
David Brownc29c7ab2009-07-07 16:00:18 -0700235 // TODO: We might eventually need to make mVibrateOn come from a
236 // user preference rather than a per-platform resource, in which
237 // case we would need to update it in onResume() rather than here.
Nicolas Catania4c0704a2009-09-23 11:42:00 -0700238 initVibrationPattern(r);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800239 }
240
241 @Override
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800242 protected void onRestoreInstanceState(Bundle icicle) {
243 // Do nothing, state is restored in onCreate() if needed
244 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700245
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800246 protected void maybeAddNumberFormatting() {
247 mDigits.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
248 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700249
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800250 /**
Eric Laurentd9efc872009-07-17 11:52:06 -0700251 * Overridden by subclasses to control the resource used by the content view.
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800252 */
253 protected int getContentViewResource() {
254 return R.layout.twelve_key_dialer;
255 }
256
257 private boolean resolveIntent() {
258 boolean ignoreState = false;
259
260 // Find the proper intent
261 final Intent intent;
262 if (isChild()) {
263 intent = getParent().getIntent();
264 ignoreState = intent.getBooleanExtra(DialtactsActivity.EXTRA_IGNORE_STATE, false);
265 } else {
266 intent = getIntent();
267 }
268 // Log.i(TAG, "==> resolveIntent(): intent: " + intent);
269
270 // by default we are not adding a call.
271 mIsAddCallMode = false;
272
273 // By default we don't show the "dialpad chooser" UI.
274 boolean needToShowDialpadChooser = false;
275
276 // Resolve the intent
277 final String action = intent.getAction();
278 if (Intent.ACTION_DIAL.equals(action) || Intent.ACTION_VIEW.equals(action)) {
279 // see if we are "adding a call" from the InCallScreen; false by default.
280 mIsAddCallMode = intent.getBooleanExtra(ADD_CALL_MODE_KEY, false);
281 Uri uri = intent.getData();
282 if (uri != null) {
283 if ("tel".equals(uri.getScheme())) {
284 // Put the requested number into the input area
285 String data = uri.getSchemeSpecificPart();
286 setFormattedDigits(data);
287 } else {
288 String type = intent.getType();
289 if (People.CONTENT_ITEM_TYPE.equals(type)
290 || Phones.CONTENT_ITEM_TYPE.equals(type)) {
291 // Query the phone number
292 Cursor c = getContentResolver().query(intent.getData(),
293 new String[] {PhonesColumns.NUMBER}, null, null, null);
294 if (c != null) {
295 if (c.moveToFirst()) {
296 // Put the number into the input area
297 setFormattedDigits(c.getString(0));
298 }
299 c.close();
300 }
301 }
302 }
303 }
304 } else if (Intent.ACTION_MAIN.equals(action)) {
305 // The MAIN action means we're bringing up a blank dialer
306 // (e.g. by selecting the Home shortcut, or tabbing over from
307 // Contacts or Call log.)
308 //
309 // At this point, IF there's already an active call, there's a
310 // good chance that the user got here accidentally (but really
311 // wanted the in-call dialpad instead). So we bring up an
312 // intermediate UI to make the user confirm what they really
313 // want to do.
314 if (phoneIsInUse()) {
315 // Log.i(TAG, "resolveIntent(): phone is in use; showing dialpad chooser!");
316 needToShowDialpadChooser = true;
317 }
318 }
319
320 // Bring up the "dialpad chooser" IFF we need to make the user
321 // confirm which dialpad they really want.
322 showDialpadChooser(needToShowDialpadChooser);
323
324 return ignoreState;
325 }
326
327 protected void setFormattedDigits(String data) {
328 // strip the non-dialable numbers out of the data string.
329 String dialString = PhoneNumberUtils.extractNetworkPortion(data);
330 dialString = PhoneNumberUtils.formatNumber(dialString);
331 if (!TextUtils.isEmpty(dialString)) {
332 Editable digits = mDigits.getText();
333 digits.replace(0, digits.length(), dialString);
Karl Rosaenf46bc312009-03-24 18:20:48 -0700334 // for some reason this isn't getting called in the digits.replace call above..
335 // but in any case, this will make sure the background drawable looks right
336 afterTextChanged(digits);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800337 }
338 }
339
340 @Override
341 protected void onNewIntent(Intent newIntent) {
342 setIntent(newIntent);
343 resolveIntent();
344 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700345
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800346 @Override
347 protected void onPostCreate(Bundle savedInstanceState) {
348 super.onPostCreate(savedInstanceState);
349
350 // This can't be done in onCreate(), since the auto-restoring of the digits
351 // will play DTMF tones for all the old digits if it is when onRestoreSavedInstanceState()
352 // is called. This method will be called every time the activity is created, and
353 // will always happen after onRestoreSavedInstanceState().
354 mDigits.addTextChangedListener(this);
355 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700356
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800357 private void setupKeypad() {
358 // Setup the listeners for the buttons
359 View view = findViewById(R.id.one);
360 view.setOnClickListener(this);
361 view.setOnLongClickListener(this);
362
363 findViewById(R.id.two).setOnClickListener(this);
364 findViewById(R.id.three).setOnClickListener(this);
365 findViewById(R.id.four).setOnClickListener(this);
366 findViewById(R.id.five).setOnClickListener(this);
367 findViewById(R.id.six).setOnClickListener(this);
368 findViewById(R.id.seven).setOnClickListener(this);
369 findViewById(R.id.eight).setOnClickListener(this);
370 findViewById(R.id.nine).setOnClickListener(this);
371 findViewById(R.id.star).setOnClickListener(this);
372
373 view = findViewById(R.id.zero);
374 view.setOnClickListener(this);
375 view.setOnLongClickListener(this);
376
377 findViewById(R.id.pound).setOnClickListener(this);
378 }
379
380 @Override
381 protected void onResume() {
382 super.onResume();
David Brownc29c7ab2009-07-07 16:00:18 -0700383
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800384 // retrieve the DTMF tone play back setting.
385 mDTMFToneEnabled = Settings.System.getInt(getContentResolver(),
386 Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
387
Eric Laurentd9efc872009-07-17 11:52:06 -0700388 // if the mToneGenerator creation fails, just continue without it. It is
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800389 // a local audio signal, and is not as important as the dtmf tone itself.
390 synchronized(mToneGeneratorLock) {
391 if (mToneGenerator == null) {
392 try {
Eric Laurentd9efc872009-07-17 11:52:06 -0700393 mToneGenerator = new ToneGenerator(AudioManager.STREAM_DTMF,
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800394 TONE_RELATIVE_VOLUME);
395 } catch (RuntimeException e) {
396 Log.w(TAG, "Exception caught while creating local tone generator: " + e);
397 mToneGenerator = null;
398 }
399 }
400 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700401
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800402 Activity parent = getParent();
403 // See if we were invoked with a DIAL intent. If we were, fill in the appropriate
404 // digits in the dialer field.
405 if (parent != null && parent instanceof DialtactsActivity) {
406 Uri dialUri = ((DialtactsActivity) parent).getAndClearDialUri();
407 if (dialUri != null) {
408 resolveIntent();
409 }
410 }
411
412 // While we're in the foreground, listen for phone state changes,
413 // purely so that we can take down the "dialpad chooser" if the
414 // phone becomes idle while the chooser UI is visible.
415 TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
416 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
417
418 // Potentially show hint text in the mDigits field when the user
419 // hasn't typed any digits yet. (If there's already an active call,
420 // this hint text will remind the user that he's about to add a new
421 // call.)
422 //
423 // TODO: consider adding better UI for the case where *both* lines
424 // are currently in use. (Right now we let the user try to add
425 // another call, but that call is guaranteed to fail. Perhaps the
426 // entire dialer UI should be disabled instead.)
427 if (phoneIsInUse()) {
428 mDigits.setHint(R.string.dialerDialpadHintText);
429 } else {
430 // Common case; no hint necessary.
431 mDigits.setHint(null);
432
433 // Also, a sanity-check: the "dialpad chooser" UI should NEVER
434 // be visible if the phone is idle!
435 showDialpadChooser(false);
436 }
Nicolas Cataniadea164e2009-09-18 06:26:16 -0700437
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700438 updateDialAndDeleteButtonStateEnabledAttr();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800439 }
440
441 @Override
Karl Rosaenf46bc312009-03-24 18:20:48 -0700442 public void onWindowFocusChanged(boolean hasFocus) {
443 if (hasFocus) {
444 // Hide soft keyboard, if visible (it's fugly over button dialer).
445 // The only known case where this will be true is when launching the dialer with
446 // ACTION_DIAL via a soft keyboard. we dismiss it here because we don't
447 // have a window token yet in onCreate / onNewIntent
448 InputMethodManager inputMethodManager = (InputMethodManager)
449 getSystemService(Context.INPUT_METHOD_SERVICE);
Eric Laurentd9efc872009-07-17 11:52:06 -0700450 inputMethodManager.hideSoftInputFromWindow(mDigits.getWindowToken(), 0);
Karl Rosaenf46bc312009-03-24 18:20:48 -0700451 }
452 }
453
454 @Override
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800455 protected void onPause() {
456 super.onPause();
457
458 // Stop listening for phone state changes.
459 TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
460 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
461
462 synchronized(mToneGeneratorLock) {
463 if (mToneGenerator != null) {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800464 mToneGenerator.release();
465 mToneGenerator = null;
466 }
467 }
468 }
469
470 @Override
471 public boolean onCreateOptionsMenu(Menu menu) {
Reli Talc2a2a512009-06-10 16:48:00 -0400472 mAddToContactMenuItem = menu.add(0, MENU_ADD_CONTACTS, 0, R.string.recentCalls_addToContact)
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800473 .setIcon(android.R.drawable.ic_menu_add);
Reli Talc2a2a512009-06-10 16:48:00 -0400474 m2SecPauseMenuItem = menu.add(0, MENU_2S_PAUSE, 0, R.string.add_2sec_pause)
475 .setIcon(R.drawable.ic_menu_2sec_pause);
476 mWaitMenuItem = menu.add(0, MENU_WAIT, 0, R.string.add_wait)
477 .setIcon(R.drawable.ic_menu_wait);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800478 return true;
479 }
480
481 @Override
482 public boolean onPrepareOptionsMenu(Menu menu) {
483 // We never show a menu if the "choose dialpad" UI is up.
484 if (dialpadChooserVisible()) {
485 return false;
486 }
487
488 CharSequence digits = mDigits.getText();
489 if (digits == null || !TextUtils.isGraphic(digits)) {
490 mAddToContactMenuItem.setVisible(false);
Reli Talc2a2a512009-06-10 16:48:00 -0400491 m2SecPauseMenuItem.setVisible(false);
492 mWaitMenuItem.setVisible(false);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800493 } else {
494 // Put the current digits string into an intent
495 Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
496 intent.putExtra(Insert.PHONE, mDigits.getText());
497 intent.setType(People.CONTENT_ITEM_TYPE);
498 mAddToContactMenuItem.setIntent(intent);
499 mAddToContactMenuItem.setVisible(true);
Reli Talc2a2a512009-06-10 16:48:00 -0400500
501 // Check out whether to show Pause & Wait option menu items
502 int selectionStart;
503 int selectionEnd;
504 String strDigits = digits.toString();
505
506 selectionStart = mDigits.getSelectionStart();
507 selectionEnd = mDigits.getSelectionEnd();
508
509 if (selectionStart != -1) {
510 if (selectionStart > selectionEnd) {
511 // swap it as we want start to be less then end
512 int tmp = selectionStart;
513 selectionStart = selectionEnd;
514 selectionEnd = tmp;
515 }
516
517 if (selectionStart != 0) {
518 // Pause can be visible if cursor is not in the begining
519 m2SecPauseMenuItem.setVisible(true);
520
521 // For Wait to be visible set of condition to meet
522 mWaitMenuItem.setVisible(showWait(selectionStart,
523 selectionEnd, strDigits));
524 } else {
525 // cursor in the beginning both pause and wait to be invisible
526 m2SecPauseMenuItem.setVisible(false);
527 mWaitMenuItem.setVisible(false);
528 }
529 } else {
530 // cursor is not selected so assume new digit is added to the end
531 int strLength = strDigits.length();
532 mWaitMenuItem.setVisible(showWait(strLength,
533 strLength, strDigits));
534 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800535 }
536 return true;
537 }
538
539 @Override
540 public boolean onKeyDown(int keyCode, KeyEvent event) {
541 switch (keyCode) {
542 case KeyEvent.KEYCODE_CALL: {
543 long callPressDiff = SystemClock.uptimeMillis() - event.getDownTime();
544 if (callPressDiff >= ViewConfiguration.getLongPressTimeout()) {
545 // Launch voice dialer
546 Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
547 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
548 try {
549 startActivity(intent);
550 } catch (ActivityNotFoundException e) {
551 }
552 }
553 return true;
554 }
555 case KeyEvent.KEYCODE_1: {
Eric Laurentd9efc872009-07-17 11:52:06 -0700556 long timeDiff = SystemClock.uptimeMillis() - event.getDownTime();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800557 if (timeDiff >= ViewConfiguration.getLongPressTimeout()) {
558 // Long press detected, call voice mail
559 callVoicemail();
560 }
561 return true;
562 }
563 }
564 return super.onKeyDown(keyCode, event);
565 }
566
567 @Override
568 public boolean onKeyUp(int keyCode, KeyEvent event) {
569 switch (keyCode) {
570 case KeyEvent.KEYCODE_CALL: {
571 if (mIsAddCallMode && (TextUtils.isEmpty(mDigits.getText().toString()))) {
572 // if we are adding a call from the InCallScreen and the phone
573 // number entered is empty, we just close the dialer to expose
574 // the InCallScreen under it.
575 finish();
576 } else {
577 // otherwise, we place the call.
578 placeCall();
579 }
580 return true;
581 }
582 }
583 return super.onKeyUp(keyCode, event);
584 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700585
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800586 private void keyPressed(int keyCode) {
David Brownc29c7ab2009-07-07 16:00:18 -0700587 vibrate();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800588 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
589 mDigits.onKeyDown(keyCode, event);
590 }
591
592 public boolean onKey(View view, int keyCode, KeyEvent event) {
593 switch (view.getId()) {
594 case R.id.digits:
595 if (keyCode == KeyEvent.KEYCODE_ENTER) {
596 placeCall();
597 return true;
598 }
599 break;
600 }
601 return false;
602 }
603
604 public void onClick(View view) {
605 switch (view.getId()) {
606 case R.id.one: {
607 playTone(ToneGenerator.TONE_DTMF_1);
608 keyPressed(KeyEvent.KEYCODE_1);
609 return;
610 }
611 case R.id.two: {
612 playTone(ToneGenerator.TONE_DTMF_2);
613 keyPressed(KeyEvent.KEYCODE_2);
614 return;
615 }
616 case R.id.three: {
617 playTone(ToneGenerator.TONE_DTMF_3);
618 keyPressed(KeyEvent.KEYCODE_3);
619 return;
620 }
621 case R.id.four: {
622 playTone(ToneGenerator.TONE_DTMF_4);
623 keyPressed(KeyEvent.KEYCODE_4);
624 return;
625 }
626 case R.id.five: {
627 playTone(ToneGenerator.TONE_DTMF_5);
628 keyPressed(KeyEvent.KEYCODE_5);
629 return;
630 }
631 case R.id.six: {
632 playTone(ToneGenerator.TONE_DTMF_6);
633 keyPressed(KeyEvent.KEYCODE_6);
634 return;
635 }
636 case R.id.seven: {
637 playTone(ToneGenerator.TONE_DTMF_7);
638 keyPressed(KeyEvent.KEYCODE_7);
639 return;
640 }
641 case R.id.eight: {
642 playTone(ToneGenerator.TONE_DTMF_8);
643 keyPressed(KeyEvent.KEYCODE_8);
644 return;
645 }
646 case R.id.nine: {
647 playTone(ToneGenerator.TONE_DTMF_9);
648 keyPressed(KeyEvent.KEYCODE_9);
649 return;
650 }
651 case R.id.zero: {
652 playTone(ToneGenerator.TONE_DTMF_0);
653 keyPressed(KeyEvent.KEYCODE_0);
654 return;
655 }
656 case R.id.pound: {
657 playTone(ToneGenerator.TONE_DTMF_P);
658 keyPressed(KeyEvent.KEYCODE_POUND);
659 return;
660 }
661 case R.id.star: {
662 playTone(ToneGenerator.TONE_DTMF_S);
663 keyPressed(KeyEvent.KEYCODE_STAR);
664 return;
665 }
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700666 case R.id.deleteButton: {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800667 keyPressed(KeyEvent.KEYCODE_DEL);
668 return;
669 }
Nicolas Catania3040fa32009-10-01 13:00:53 -0700670 case R.id.dialButton: {
David Brownc29c7ab2009-07-07 16:00:18 -0700671 vibrate(); // Vibrate here too, just like we do for the regular keys
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800672 placeCall();
673 return;
674 }
Nicolas Catania80bda0f2009-09-19 09:17:14 -0700675 case R.id.voicemailButton: {
676 callVoicemail();
677 vibrate();
678 return;
679 }
Nicolas Catania3040fa32009-10-01 13:00:53 -0700680 case R.id.digits: {
681 if (mDigits.length() != 0) {
682 mDigits.setCursorVisible(true);
683 }
684 return;
685 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800686 }
687 }
688
689 public boolean onLongClick(View view) {
690 final Editable digits = mDigits.getText();
691 int id = view.getId();
692 switch (id) {
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700693 case R.id.deleteButton: {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800694 digits.clear();
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700695 // TODO: The framework forgets to clear the pressed
696 // status of disabled button. Until this is fixed,
697 // clear manually the pressed status. b/2133127
698 mDelete.setPressed(false);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800699 return true;
700 }
701 case R.id.one: {
702 if (digits.length() == 0) {
703 callVoicemail();
704 return true;
705 }
706 return false;
707 }
708 case R.id.zero: {
709 keyPressed(KeyEvent.KEYCODE_PLUS);
710 return true;
711 }
712 }
713 return false;
714 }
715
716 void callVoicemail() {
717 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
718 Uri.fromParts("voicemail", "", null));
719 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
720 startActivity(intent);
721 mDigits.getText().clear();
722 finish();
723 }
724
725 void placeCall() {
726 final String number = mDigits.getText().toString();
727 if (number == null || !TextUtils.isGraphic(number)) {
728 // There is no number entered.
729 playTone(ToneGenerator.TONE_PROP_NACK);
730 return;
731 }
732 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
733 Uri.fromParts("tel", number, null));
734 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
735 startActivity(intent);
736 mDigits.getText().clear();
737 finish();
738 }
739
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800740
741 /**
David Brown22f615f2009-06-25 16:19:19 -0700742 * Plays the specified tone for TONE_LENGTH_MS milliseconds.
743 *
744 * The tone is played locally, using the audio stream for phone calls.
745 * Tones are played only if the "Audible touch tones" user preference
746 * is checked, and are NOT played if the device is in silent mode.
747 *
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800748 * @param tone a tone code from {@link ToneGenerator}
749 */
750 void playTone(int tone) {
751 // if local tone playback is disabled, just return.
752 if (!mDTMFToneEnabled) {
753 return;
754 }
David Brown22f615f2009-06-25 16:19:19 -0700755
756 // Also do nothing if the phone is in silent mode.
757 // We need to re-check the ringer mode for *every* playTone()
758 // call, rather than keeping a local flag that's updated in
759 // onResume(), since it's possible to toggle silent mode without
760 // leaving the current activity (via the ENDCALL-longpress menu.)
761 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
David Brownd5a15302009-07-20 16:39:47 -0700762 int ringerMode = audioManager.getRingerMode();
763 if ((ringerMode == AudioManager.RINGER_MODE_SILENT)
764 || (ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
David Brown22f615f2009-06-25 16:19:19 -0700765 return;
766 }
767
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800768 synchronized(mToneGeneratorLock) {
769 if (mToneGenerator == null) {
770 Log.w(TAG, "playTone: mToneGenerator == null, tone: "+tone);
771 return;
772 }
Eric Laurentd9efc872009-07-17 11:52:06 -0700773
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800774 // Start the new tone (will stop any playing tone)
Eric Laurent8487fed2009-09-07 08:45:14 -0700775 mToneGenerator.startTone(tone, TONE_LENGTH_MS);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800776 }
777 }
778
779 /**
780 * Brings up the "dialpad chooser" UI in place of the usual Dialer
781 * elements (the textfield/button and the dialpad underneath).
782 *
783 * We show this UI if the user brings up the Dialer while a call is
784 * already in progress, since there's a good chance we got here
785 * accidentally (and the user really wanted the in-call dialpad instead).
786 * So in this situation we display an intermediate UI that lets the user
787 * explicitly choose between the in-call dialpad ("Use touch tone
788 * keypad") and the regular Dialer ("Add call"). (Or, the option "Return
789 * to call in progress" just goes back to the in-call UI with no dialpad
790 * at all.)
791 *
792 * @param enabled If true, show the "dialpad chooser" instead
793 * of the regular Dialer UI
794 */
795 private void showDialpadChooser(boolean enabled) {
796 if (enabled) {
797 // Log.i(TAG, "Showing dialpad chooser!");
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700798 mDigits.setVisibility(View.GONE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800799 if (mDialpad != null) mDialpad.setVisibility(View.GONE);
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700800 mVoicemailDialAndDeleteRow.setVisibility(View.GONE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800801 mDialpadChooser.setVisibility(View.VISIBLE);
802
803 // Instantiate the DialpadChooserAdapter and hook it up to the
804 // ListView. We do this only once.
805 if (mDialpadChooserAdapter == null) {
806 mDialpadChooserAdapter = new DialpadChooserAdapter(this);
807 mDialpadChooser.setAdapter(mDialpadChooserAdapter);
808 }
809 } else {
810 // Log.i(TAG, "Displaying normal Dialer UI.");
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700811 mDigits.setVisibility(View.VISIBLE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800812 if (mDialpad != null) mDialpad.setVisibility(View.VISIBLE);
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -0700813 mVoicemailDialAndDeleteRow.setVisibility(View.VISIBLE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800814 mDialpadChooser.setVisibility(View.GONE);
815 }
816 }
817
818 /**
819 * @return true if we're currently showing the "dialpad chooser" UI.
820 */
821 private boolean dialpadChooserVisible() {
822 return mDialpadChooser.getVisibility() == View.VISIBLE;
823 }
824
825 /**
826 * Simple list adapter, binding to an icon + text label
827 * for each item in the "dialpad chooser" list.
828 */
829 private static class DialpadChooserAdapter extends BaseAdapter {
830 private LayoutInflater mInflater;
831
832 // Simple struct for a single "choice" item.
833 static class ChoiceItem {
834 String text;
835 Bitmap icon;
836 int id;
837
838 public ChoiceItem(String s, Bitmap b, int i) {
839 text = s;
840 icon = b;
841 id = i;
842 }
843 }
844
845 // IDs for the possible "choices":
846 static final int DIALPAD_CHOICE_USE_DTMF_DIALPAD = 101;
847 static final int DIALPAD_CHOICE_RETURN_TO_CALL = 102;
848 static final int DIALPAD_CHOICE_ADD_NEW_CALL = 103;
849
850 private static final int NUM_ITEMS = 3;
851 private ChoiceItem mChoiceItems[] = new ChoiceItem[NUM_ITEMS];
852
853 public DialpadChooserAdapter(Context context) {
854 // Cache the LayoutInflate to avoid asking for a new one each time.
855 mInflater = LayoutInflater.from(context);
856
857 // Initialize the possible choices.
858 // TODO: could this be specified entirely in XML?
859
860 // - "Use touch tone keypad"
861 mChoiceItems[0] = new ChoiceItem(
862 context.getString(R.string.dialer_useDtmfDialpad),
863 BitmapFactory.decodeResource(context.getResources(),
864 R.drawable.ic_dialer_fork_tt_keypad),
865 DIALPAD_CHOICE_USE_DTMF_DIALPAD);
866
867 // - "Return to call in progress"
868 mChoiceItems[1] = new ChoiceItem(
869 context.getString(R.string.dialer_returnToInCallScreen),
870 BitmapFactory.decodeResource(context.getResources(),
871 R.drawable.ic_dialer_fork_current_call),
872 DIALPAD_CHOICE_RETURN_TO_CALL);
873
874 // - "Add call"
875 mChoiceItems[2] = new ChoiceItem(
876 context.getString(R.string.dialer_addAnotherCall),
877 BitmapFactory.decodeResource(context.getResources(),
878 R.drawable.ic_dialer_fork_add_call),
879 DIALPAD_CHOICE_ADD_NEW_CALL);
880 }
881
882 public int getCount() {
883 return NUM_ITEMS;
884 }
885
886 /**
887 * Return the ChoiceItem for a given position.
888 */
889 public Object getItem(int position) {
890 return mChoiceItems[position];
891 }
892
893 /**
894 * Return a unique ID for each possible choice.
895 */
896 public long getItemId(int position) {
897 return position;
898 }
899
900 /**
901 * Make a view for each row.
902 */
903 public View getView(int position, View convertView, ViewGroup parent) {
904 // When convertView is non-null, we can reuse it (there's no need
905 // to reinflate it.)
906 if (convertView == null) {
907 convertView = mInflater.inflate(R.layout.dialpad_chooser_list_item, null);
908 }
909
910 TextView text = (TextView) convertView.findViewById(R.id.text);
911 text.setText(mChoiceItems[position].text);
912
913 ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
914 icon.setImageBitmap(mChoiceItems[position].icon);
915
916 return convertView;
917 }
918 }
919
920 /**
921 * Handle clicks from the dialpad chooser.
922 */
923 public void onItemClick(AdapterView parent, View v, int position, long id) {
924 DialpadChooserAdapter.ChoiceItem item =
925 (DialpadChooserAdapter.ChoiceItem) parent.getItemAtPosition(position);
926 int itemId = item.id;
927 switch (itemId) {
928 case DialpadChooserAdapter.DIALPAD_CHOICE_USE_DTMF_DIALPAD:
929 // Log.i(TAG, "DIALPAD_CHOICE_USE_DTMF_DIALPAD");
930 // Fire off an intent to go back to the in-call UI
931 // with the dialpad visible.
932 returnToInCallScreen(true);
933 break;
934
935 case DialpadChooserAdapter.DIALPAD_CHOICE_RETURN_TO_CALL:
936 // Log.i(TAG, "DIALPAD_CHOICE_RETURN_TO_CALL");
937 // Fire off an intent to go back to the in-call UI
938 // (with the dialpad hidden).
939 returnToInCallScreen(false);
940 break;
941
942 case DialpadChooserAdapter.DIALPAD_CHOICE_ADD_NEW_CALL:
943 // Log.i(TAG, "DIALPAD_CHOICE_ADD_NEW_CALL");
944 // Ok, guess the user really did want to be here (in the
945 // regular Dialer) after all. Bring back the normal Dialer UI.
946 showDialpadChooser(false);
947 break;
948
949 default:
950 Log.w(TAG, "onItemClick: unexpected itemId: " + itemId);
951 break;
952 }
953 }
954
955 /**
956 * Returns to the in-call UI (where there's presumably a call in
957 * progress) in response to the user selecting "use touch tone keypad"
958 * or "return to call" from the dialpad chooser.
959 */
960 private void returnToInCallScreen(boolean showDialpad) {
961 try {
962 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
963 if (phone != null) phone.showCallScreenWithDialpad(showDialpad);
964 } catch (RemoteException e) {
965 Log.w(TAG, "phone.showCallScreenWithDialpad() failed", e);
966 }
967
968 // Finally, finish() ourselves so that we don't stay on the
969 // activity stack.
970 // Note that we do this whether or not the showCallScreenWithDialpad()
971 // call above had any effect or not! (That call is a no-op if the
972 // phone is idle, which can happen if the current call ends while
973 // the dialpad chooser is up. In this case we can't show the
974 // InCallScreen, and there's no point staying here in the Dialer,
975 // so we just take the user back where he came from...)
976 finish();
977 }
978
979 /**
980 * @return true if the phone is "in use", meaning that at least one line
981 * is active (ie. off hook or ringing or dialing).
982 */
983 private boolean phoneIsInUse() {
984 boolean phoneInUse = false;
985 try {
986 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
987 if (phone != null) phoneInUse = !phone.isIdle();
988 } catch (RemoteException e) {
989 Log.w(TAG, "phone.isIdle() failed", e);
990 }
991 return phoneInUse;
992 }
David Brownc29c7ab2009-07-07 16:00:18 -0700993
994 /**
995 * Triggers haptic feedback (if enabled) for dialer key presses.
996 */
997 private synchronized void vibrate() {
998 if (!mVibrateOn) {
999 return;
1000 }
1001 if (mVibrator == null) {
1002 mVibrator = new Vibrator();
1003 }
Nicolas Catania4c0704a2009-09-23 11:42:00 -07001004 mVibrator.vibrate(mVibratePattern, VIBRATE_NO_REPEAT);
David Brownc29c7ab2009-07-07 16:00:18 -07001005 }
Reli Talc2a2a512009-06-10 16:48:00 -04001006
1007 /**
1008 * Returns true whenever any one of the options from the menu is selected.
1009 * Code changes to support dialpad options
1010 */
1011 @Override
1012 public boolean onOptionsItemSelected(MenuItem item) {
1013 switch (item.getItemId()) {
1014 case MENU_2S_PAUSE:
1015 updateDialString(",");
1016 return true;
1017 case MENU_WAIT:
1018 updateDialString(";");
1019 return true;
1020 }
1021 return false;
1022 }
1023
1024 /**
1025 * Updates the dial string (mDigits) after inserting a Pause character (,)
1026 * or Wait character (;).
1027 */
1028 private void updateDialString(String newDigits) {
1029 int selectionStart;
1030 int selectionEnd;
1031
1032 // SpannableStringBuilder editable_text = new SpannableStringBuilder(mDigits.getText());
Eric Fischer686782e2009-09-10 17:57:45 -07001033 int anchor = mDigits.getSelectionStart();
1034 int point = mDigits.getSelectionEnd();
1035
1036 selectionStart = Math.min(anchor, point);
1037 selectionEnd = Math.max(anchor, point);
Reli Talc2a2a512009-06-10 16:48:00 -04001038
1039 Editable digits = mDigits.getText();
1040 if (selectionStart != -1 ) {
1041 if (selectionStart == selectionEnd) {
1042 // then there is no selection. So insert the pause at this
1043 // position and update the mDigits.
1044 digits.replace(selectionStart, selectionStart, newDigits);
1045 } else {
Eric Fischer1e2d3a22009-09-17 10:53:10 -07001046 digits.replace(selectionStart, selectionEnd, newDigits);
Nicolas Catania7edbd0c2009-09-28 20:37:33 -07001047 // Unselect: back to a regular cursor, just pass the character inserted.
1048 mDigits.setSelection(selectionStart + 1);
Reli Talc2a2a512009-06-10 16:48:00 -04001049 }
1050 } else {
1051 int len = mDigits.length();
1052 digits.replace(len, len, newDigits);
1053 }
1054 }
1055
1056 /**
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001057 * Update the enabledness of the "Dial" and "Backspace" buttons if applicable.
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001058 */
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001059 private void updateDialAndDeleteButtonStateEnabledAttr() {
1060 final boolean notEmpty = mDigits.length() != 0;
1061
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001062 if (mDialButton != null) {
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001063 mDialButton.setEnabled(notEmpty);
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001064 }
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001065 mDelete.setEnabled(notEmpty);
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001066 }
1067
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001068
Nicolas Cataniadea164e2009-09-18 06:26:16 -07001069 /**
Nicolas Catania80bda0f2009-09-19 09:17:14 -07001070 * Check if voicemail is enabled/accessible.
1071 */
1072 private void initVoicemailButton() {
1073 boolean hasVoicemail = false;
1074 try {
1075 hasVoicemail = TelephonyManager.getDefault().getVoiceMailNumber() != null;
1076 } catch (SecurityException se) {
1077 // Possibly no READ_PHONE_STATE privilege.
1078 }
1079
Nicolas Cataniaa7e5a5b2009-09-20 10:56:40 -07001080 mVoicemailButton = mVoicemailDialAndDeleteRow.findViewById(R.id.voicemailButton);
Nicolas Catania80bda0f2009-09-19 09:17:14 -07001081 if (hasVoicemail) {
1082 mVoicemailButton.setOnClickListener(this);
1083 } else {
1084 mVoicemailButton.setEnabled(false);
1085 }
1086 }
1087
1088 /**
Nicolas Catania4c0704a2009-09-23 11:42:00 -07001089 * Initialize the vibration parameters.
1090 * @param r The Resources with the vibration parameters.
1091 */
1092 private void initVibrationPattern(Resources r) {
1093 int[] pattern = null;
1094 try {
1095 mVibrateOn = r.getBoolean(R.bool.config_enable_dialer_key_vibration);
1096 pattern = r.getIntArray(com.android.internal.R.array.config_virtualKeyVibePattern);
1097 if (null == pattern) {
1098 Log.e(TAG, "Vibrate pattern is null.");
1099 mVibrateOn = false;
1100 }
1101 } catch (Resources.NotFoundException nfe) {
1102 Log.e(TAG, "Vibrate control bool or pattern missing.", nfe);
1103 mVibrateOn = false;
1104 }
1105
1106 if (!mVibrateOn) {
1107 return;
1108 }
1109
1110 // int[] to long[] conversion.
1111 mVibratePattern = new long[pattern.length];
1112 for (int i = 0; i < pattern.length; i++) {
1113 mVibratePattern[i] = pattern[i];
1114 }
1115 }
1116
1117 /**
Reli Talc2a2a512009-06-10 16:48:00 -04001118 * This function return true if Wait menu item can be shown
1119 * otherwise returns false. Assumes the passed string is non-empty
1120 * and the 0th index check is not required.
1121 */
1122 private boolean showWait(int start, int end, String digits) {
1123 if (start == end) {
1124 // visible false in this case
1125 if (start > digits.length()) return false;
1126
1127 // preceding char is ';', so visible should be false
1128 if (digits.charAt(start-1) == ';') return false;
1129
1130 // next char is ';', so visible should be false
1131 if ((digits.length() > start) && (digits.charAt(start) == ';')) return false;
1132 } else {
1133 // visible false in this case
1134 if (start > digits.length() || end > digits.length()) return false;
1135
1136 // In this case we need to just check for ';' preceding to start
1137 // or next to end
1138 if (digits.charAt(start-1) == ';') return false;
1139 }
1140 return true;
1141 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001142}