RecentCallsListActivitypublic class RecentCallsListActivity extends android.app.ListActivity implements View.OnCreateContextMenuListenerDisplays a list of call log entries. |
Fields Summary |
---|
private static final String | TAG | static final String[] | CALL_LOG_PROJECTIONThe projection to use when querying the call log table | static final int | ID_COLUMN_INDEX | static final int | NUMBER_COLUMN_INDEX | static final int | DATE_COLUMN_INDEX | static final int | DURATION_COLUMN_INDEX | static final int | CALL_TYPE_COLUMN_INDEX | static final int | CALLER_NAME_COLUMN_INDEX | static final int | CALLER_NUMBERTYPE_COLUMN_INDEX | static final int | CALLER_NUMBERLABEL_COLUMN_INDEX | static final String[] | PHONES_PROJECTIONThe projection to use when querying the phones table | static final int | PERSON_ID_COLUMN_INDEX | static final int | NAME_COLUMN_INDEX | static final int | PHONE_TYPE_COLUMN_INDEX | static final int | LABEL_COLUMN_INDEX | static final int | MATCHED_NUMBER_COLUMN_INDEX | private static final int | MENU_ITEM_DELETE | private static final int | MENU_ITEM_DELETE_ALL | private static final int | MENU_ITEM_VIEW_CONTACTS | private static final int | QUERY_TOKEN | private static final int | UPDATE_TOKEN | RecentCallsAdapter | mAdapter | private QueryHandler | mQueryHandler | String | mVoiceMailNumber | private static final android.text.SpannableStringBuilder | sEditableShared builder used by {@link #formatPhoneNumber(String)} to minimize
allocations when formatting phone numbers. | private static final int | FORMATTING_TYPE_INVALIDInvalid formatting type constant for {@link #sFormattingType}. | private static int | sFormattingTypeCached formatting type for current {@link Locale}, as provided by
{@link PhoneNumberUtils#getFormatTypeForLocale(Locale)}. |
Methods Summary |
---|
private void | callEntry(int position)
if (position < 0) {
// In touch mode you may often not have something selected, so
// just call the first entry to make sure that [send] [send] calls the
// most recent entry.
position = 0;
}
final Cursor cursor = mAdapter.getCursor();
if (cursor != null && cursor.moveToPosition(position)) {
String number = cursor.getString(NUMBER_COLUMN_INDEX);
if (TextUtils.isEmpty(number)
|| number.equals(CallerInfo.UNKNOWN_NUMBER)
|| number.equals(CallerInfo.PRIVATE_NUMBER)
|| number.equals(CallerInfo.PAYPHONE_NUMBER)) {
// This number can't be called, do nothing
return;
}
int callType = cursor.getInt(CALL_TYPE_COLUMN_INDEX);
if (!number.startsWith("+") &&
(callType == Calls.INCOMING_TYPE
|| callType == Calls.MISSED_TYPE)) {
// If the caller-id matches a contact with a better qualified number, use it
number = getBetterNumberFromContacts(number);
}
Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
Uri.fromParts("tel", number, null));
intent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);
}
| private java.lang.String | formatPhoneNumber(java.lang.String number)Format the given phone number using
{@link PhoneNumberUtils#formatNumber(android.text.Editable, int)}. This
helper method uses {@link #sEditable} and {@link #sFormattingType} to
prevent allocations between multiple calls.
Because of the shared {@link #sEditable} builder, this method is not
thread safe, and should only be called from the GUI thread.
// Cache formatting type if not already present
if (sFormattingType == FORMATTING_TYPE_INVALID) {
sFormattingType = PhoneNumberUtils.getFormatTypeForLocale(Locale.getDefault());
}
sEditable.clear();
sEditable.append(number);
PhoneNumberUtils.formatNumber(sEditable, sFormattingType);
return sEditable.toString();
| private java.lang.String | getBetterNumberFromContacts(java.lang.String number)
String matchingNumber = null;
// Look in the cache first. If it's not found then query the Phones db
ContactInfo ci = mAdapter.mContactInfo.get(number);
if (ci != null && ci != ContactInfo.EMPTY) {
matchingNumber = ci.number;
} else {
try {
Cursor phonesCursor =
RecentCallsListActivity.this.getContentResolver().query(
Uri.withAppendedPath(Phones.CONTENT_FILTER_URL,
number),
PHONES_PROJECTION, null, null, null);
if (phonesCursor != null) {
if (phonesCursor.moveToFirst()) {
matchingNumber = phonesCursor.getString(MATCHED_NUMBER_COLUMN_INDEX);
}
phonesCursor.close();
}
} catch (Exception e) {
// Use the number from the call log
}
}
if (!TextUtils.isEmpty(matchingNumber) &&
(matchingNumber.startsWith("+")
|| matchingNumber.length() > number.length())) {
number = matchingNumber;
}
return number;
| public boolean | onContextItemSelected(android.view.MenuItem item)
// Convert the menu info to the proper type
AdapterView.AdapterContextMenuInfo menuInfo;
try {
menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
} catch (ClassCastException e) {
Log.e(TAG, "bad menuInfoIn", e);
return false;
}
switch (item.getItemId()) {
case MENU_ITEM_DELETE: {
Cursor cursor = mAdapter.getCursor();
if (cursor != null) {
cursor.moveToPosition(menuInfo.position);
cursor.deleteRow();
}
return true;
}
}
return super.onContextItemSelected(item);
| protected void | onCreate(android.os.Bundle state)
super.onCreate(state);
setContentView(R.layout.recent_calls);
// Typing here goes to the dialer
setDefaultKeyMode(DEFAULT_KEYS_DIALER);
mAdapter = new RecentCallsAdapter();
getListView().setOnCreateContextMenuListener(this);
setListAdapter(mAdapter);
mVoiceMailNumber = ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE))
.getVoiceMailNumber();
mQueryHandler = new QueryHandler(this);
// Reset locale-based formatting cache
sFormattingType = FORMATTING_TYPE_INVALID;
| public void | onCreateContextMenu(android.view.ContextMenu menu, android.view.View view, android.view.ContextMenu.ContextMenuInfo menuInfoIn)
AdapterView.AdapterContextMenuInfo menuInfo;
try {
menuInfo = (AdapterView.AdapterContextMenuInfo) menuInfoIn;
} catch (ClassCastException e) {
Log.e(TAG, "bad menuInfoIn", e);
return;
}
Cursor cursor = (Cursor) mAdapter.getItem(menuInfo.position);
String number = cursor.getString(NUMBER_COLUMN_INDEX);
Uri numberUri = null;
boolean isVoicemail = false;
if (number.equals(CallerInfo.UNKNOWN_NUMBER)) {
number = getString(R.string.unknown);
} else if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
number = getString(R.string.private_num);
} else if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
number = getString(R.string.payphone);
} else if (number.equals(mVoiceMailNumber)) {
number = getString(R.string.voicemail);
numberUri = Uri.parse("voicemail:x");
isVoicemail = true;
} else {
numberUri = Uri.fromParts("tel", number, null);
}
ContactInfo info = mAdapter.getContactInfo(number);
boolean contactInfoPresent = (info != null && info != ContactInfo.EMPTY);
if (contactInfoPresent) {
menu.setHeaderTitle(info.name);
} else {
menu.setHeaderTitle(number);
}
if (numberUri != null) {
Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, numberUri);
menu.add(0, 0, 0, getResources().getString(R.string.recentCalls_callNumber, number))
.setIntent(intent);
}
if (contactInfoPresent) {
menu.add(0, 0, 0, R.string.menu_viewContact)
.setIntent(new Intent(Intent.ACTION_VIEW,
ContentUris.withAppendedId(People.CONTENT_URI, info.personId)));
}
if (numberUri != null && !isVoicemail) {
menu.add(0, 0, 0, R.string.recentCalls_editNumberBeforeCall)
.setIntent(new Intent(Intent.ACTION_DIAL, numberUri));
menu.add(0, 0, 0, R.string.menu_sendTextMessage)
.setIntent(new Intent(Intent.ACTION_SENDTO,
Uri.fromParts("sms", number, null)));
}
if (!contactInfoPresent && numberUri != null && !isVoicemail) {
Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
intent.setType(People.CONTENT_ITEM_TYPE);
intent.putExtra(Insert.PHONE, number);
menu.add(0, 0, 0, R.string.recentCalls_addToContact)
.setIntent(intent);
}
menu.add(0, MENU_ITEM_DELETE, 0, R.string.recentCalls_removeFromRecentList);
| public boolean | onCreateOptionsMenu(android.view.Menu menu)
menu.add(0, MENU_ITEM_DELETE_ALL, 0, R.string.recentCalls_deleteAll)
.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
return true;
| protected void | onDestroy()
super.onDestroy();
mAdapter.stopRequestProcessing();
Cursor cursor = mAdapter.getCursor();
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
| public boolean | onKeyDown(int keyCode, android.view.KeyEvent event)
switch (keyCode) {
case KeyEvent.KEYCODE_CALL: {
long callPressDiff = SystemClock.uptimeMillis() - event.getDownTime();
if (callPressDiff >= ViewConfiguration.getLongPressTimeout()) {
// Launch voice dialer
Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
}
return true;
}
}
}
return super.onKeyDown(keyCode, event);
| public boolean | onKeyUp(int keyCode, android.view.KeyEvent event)
switch (keyCode) {
case KeyEvent.KEYCODE_CALL:
try {
ITelephony phone = ITelephony.Stub.asInterface(
ServiceManager.checkService("phone"));
if (phone != null && !phone.isIdle()) {
// Let the super class handle it
break;
}
} catch (RemoteException re) {
// Fall through and try to call the contact
}
callEntry(getListView().getSelectedItemPosition());
return true;
}
return super.onKeyUp(keyCode, event);
| protected void | onListItemClick(android.widget.ListView l, android.view.View v, int position, long id)
Intent intent = new Intent(this, CallDetailActivity.class);
intent.setData(ContentUris.withAppendedId(CallLog.Calls.CONTENT_URI, id));
startActivity(intent);
| public boolean | onOptionsItemSelected(android.view.MenuItem item)
switch (item.getItemId()) {
case MENU_ITEM_DELETE_ALL: {
getContentResolver().delete(Calls.CONTENT_URI, null, null);
//TODO The change notification should do this automatically, but it isn't working
// right now. Remove this when the change notification is working properly.
startQuery();
return true;
}
case MENU_ITEM_VIEW_CONTACTS: {
Intent intent = new Intent(Intent.ACTION_VIEW, People.CONTENT_URI);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
return true;
}
}
return super.onOptionsItemSelected(item);
| protected void | onPause()
super.onPause();
// Kill the requests thread
mAdapter.stopRequestProcessing();
| protected void | onResume()
// The adapter caches looked up numbers, clear it so they will get
// looked up again.
if (mAdapter != null) {
mAdapter.clearCache();
}
startQuery();
resetNewCallsFlag();
super.onResume();
mAdapter.mPreDrawListener = null; // Let it restart the thread after next draw
| public void | onWindowFocusChanged(boolean hasFocus)
super.onWindowFocusChanged(hasFocus);
// Clear notifications only when window gains focus. This activity won't
// immediately receive focus if the keyguard screen is above it.
if (hasFocus) {
try {
ITelephony iTelephony =
ITelephony.Stub.asInterface(ServiceManager.getService("phone"));
if (iTelephony != null) {
iTelephony.cancelMissedCallsNotification();
} else {
Log.w(TAG, "Telephony service is null, can't call " +
"cancelMissedCallsNotification");
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to clear missed calls notification due to remote exception");
}
}
| private void | resetNewCallsFlag()
// Mark all "new" missed calls as not new anymore
StringBuilder where = new StringBuilder("type=");
where.append(Calls.MISSED_TYPE);
where.append(" AND new=1");
ContentValues values = new ContentValues(1);
values.put(Calls.NEW, "0");
mQueryHandler.startUpdate(UPDATE_TOKEN, null, Calls.CONTENT_URI,
values, where.toString(), null);
| private void | startQuery()
mAdapter.setLoading(true);
// Cancel any pending queries
mQueryHandler.cancelOperation(QUERY_TOKEN);
mQueryHandler.startQuery(QUERY_TOKEN, null, Calls.CONTENT_URI,
CALL_LOG_PROJECTION, null, null, Calls.DEFAULT_SORT_ORDER);
|
|