auto import from //branches/cupcake/...@126645
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
new file mode 100755
index 0000000..8b25c09
--- /dev/null
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts;
+
+import android.app.ListActivity;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.CallLog;
+import android.provider.CallLog.Calls;
+import android.provider.Contacts;
+import android.provider.Contacts.Intents.Insert;
+import android.provider.Contacts.People;
+import android.provider.Contacts.Phones;
+import android.telephony.TelephonyManager;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Displays the details of a specific call log entry.
+ */
+public class CallDetailActivity extends ListActivity implements
+ AdapterView.OnItemClickListener {
+ private static final String TAG = "CallDetail";
+
+ private Uri mUri;
+
+ private View mCallDetailItem;
+
+ private TextView mCallType;
+ private ImageView mCallTypeIcon;
+ private TextView mCallTime;
+ private View mCallDurationRow;
+ private TextView mCallDuration;
+
+ private String mNumber = null;
+
+ /* package */ LayoutInflater mInflater;
+ /* package */ Resources mResources;
+
+ static final String[] CALL_LOG_PROJECTION = new String[] {
+ CallLog.Calls.DATE,
+ CallLog.Calls.DURATION,
+ CallLog.Calls.NUMBER,
+ CallLog.Calls.TYPE,
+ };
+
+ static final int DATE_COLUMN_INDEX = 0;
+ static final int DURATION_COLUMN_INDEX = 1;
+ static final int NUMBER_COLUMN_INDEX = 2;
+ static final int CALL_TYPE_COLUMN_INDEX = 3;
+
+ static final String[] PHONES_PROJECTION = new String[] {
+ Phones.PERSON_ID,
+ };
+
+ static final int PERSON_ID_COLUMN_INDEX = 0;
+
+ private static final int INVALID_TYPE = -1;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.call_detail);
+
+ mInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
+ mResources = getResources();
+
+ mCallDetailItem = mInflater.inflate(R.layout.call_detail_item, getListView(), false);
+
+ mCallType = (TextView) mCallDetailItem.findViewById(R.id.call_type);
+ mCallTypeIcon = (ImageView) mCallDetailItem.findViewById(R.id.call_type_icon);
+ mCallTime = (TextView) mCallDetailItem.findViewById(R.id.call_time);
+ mCallDurationRow = mCallDetailItem.findViewById(R.id.call_duration_row);
+ mCallDuration = (TextView) mCallDetailItem.findViewById(R.id.call_duration);
+
+ getListView().setOnItemClickListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateData(getIntent().getData());
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_CALL: {
+ // Make sure phone isn't already busy before starting direct call
+ TelephonyManager tm = (TelephonyManager)
+ getSystemService(Context.TELEPHONY_SERVICE);
+ if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
+ Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
+ Uri.fromParts("tel", mNumber, null));
+ startActivity(callIntent);
+ return true;
+ }
+ }
+ }
+
+ return super.onKeyDown(keyCode, event);
+ }
+
+ /**
+ * Try a reverse-phonebook lookup to find the contact, if any, behind the given number.
+ *
+ * @param number Phone number to perform reverse-lookup against
+ * @return Uri into {@link Contacts.People} if found, otherwise null
+ */
+ private Uri getPersonUri(String number) {
+ Uri personUri = null;
+
+ // Perform a reverse-phonebook lookup to find the PERSON_ID
+ ContentResolver resolver = getContentResolver();
+ Uri phoneUri = Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, Uri.encode(number));
+ Cursor phonesCursor = resolver.query(phoneUri, PHONES_PROJECTION, null, null, null);
+ try {
+ if (phonesCursor != null && phonesCursor.moveToFirst()) {
+ long personId = phonesCursor.getLong(PERSON_ID_COLUMN_INDEX);
+ personUri = ContentUris.withAppendedId(Contacts.People.CONTENT_URI, personId);
+ }
+ } finally {
+ if (phonesCursor != null) {
+ phonesCursor.close();
+ }
+ }
+
+ return personUri;
+ }
+
+ /**
+ * Update user interface with details of given call.
+ *
+ * @param callUri Uri into {@link CallLog.Calls}
+ */
+ private void updateData(Uri callUri) {
+ ContentResolver resolver = getContentResolver();
+ Cursor callCursor = resolver.query(callUri, CALL_LOG_PROJECTION, null, null, null);
+ try {
+ if (callCursor != null && callCursor.moveToFirst()) {
+ // Read call log specifics
+ mNumber = callCursor.getString(NUMBER_COLUMN_INDEX);
+ long date = callCursor.getLong(DATE_COLUMN_INDEX);
+ long duration = callCursor.getLong(DURATION_COLUMN_INDEX);
+ int callType = callCursor.getInt(CALL_TYPE_COLUMN_INDEX);
+
+ // Pull out string in format [relative], [date]
+ CharSequence dateClause = DateUtils.formatDateRange(this, date, date,
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
+ DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR |
+ DateUtils.FORMAT_ABBREV_ALL);
+ long now = System.currentTimeMillis();
+ CharSequence relativeClause = DateUtils.getRelativeTimeSpanString(date, now,
+ DateUtils.SECOND_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE);
+ String dateString = getString(R.string.datetime_relative,
+ dateClause, relativeClause);
+ mCallTime.setText(dateString);
+
+ // Set the duration
+ if (callType == Calls.MISSED_TYPE) {
+ mCallDurationRow.setVisibility(View.GONE);
+ } else {
+ mCallDurationRow.setVisibility(View.VISIBLE);
+ mCallDuration.setText(DateUtils.formatElapsedTime(duration));
+ }
+
+ // Set the call type icon and caption
+ switch (callType) {
+ case Calls.INCOMING_TYPE:
+ mCallTypeIcon.setImageResource(android.R.drawable.sym_call_incoming);
+ mCallType.setText(R.string.type_incoming);
+ break;
+
+ case Calls.OUTGOING_TYPE:
+ mCallTypeIcon.setImageResource(android.R.drawable.sym_call_outgoing);
+ mCallType.setText(R.string.type_outgoing);
+ break;
+
+ case Calls.MISSED_TYPE:
+ mCallTypeIcon.setImageResource(android.R.drawable.sym_call_missed);
+ mCallType.setText(R.string.type_missed);
+ break;
+ }
+
+ // Build list of various available actions
+ List<ViewEntry> actions = new LinkedList<ViewEntry>();
+
+ Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
+ Uri.fromParts("tel", mNumber, null));
+ actions.add(new ViewEntry(R.drawable.ic_dialer_fork_current_call,
+ getString(R.string.recentCalls_callNumber, mNumber), callIntent));
+
+ Intent smsIntent = new Intent(Intent.ACTION_SENDTO,
+ Uri.fromParts("sms", mNumber, null));
+ actions.add(new ViewEntry(R.drawable.sym_action_sms,
+ getString(R.string.menu_sendTextMessage), smsIntent));
+
+ // Let user view contact details if they exist, otherwise add option
+ // to create new contact from this number.
+ Uri personUri = getPersonUri(mNumber);
+
+ if (personUri != null) {
+ Intent viewIntent = new Intent(Intent.ACTION_VIEW, personUri);
+ actions.add(new ViewEntry(R.drawable.ic_tab_unselected_contacts,
+ getString(R.string.menu_viewContact), viewIntent));
+ } else {
+ Intent createIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
+ createIntent.setType(People.CONTENT_ITEM_TYPE);
+ createIntent.putExtra(Insert.PHONE, mNumber);
+ actions.add(new ViewEntry(R.drawable.ic_dialer_fork_add_call,
+ getString(R.string.recentCalls_addToContact), createIntent));
+ }
+
+ ViewAdapter adapter = new ViewAdapter(this, mCallDetailItem, actions);
+ setListAdapter(adapter);
+ } else {
+ // Something went wrong reading in our primary data, so we're going to
+ // bail out and show error to users.
+ Toast.makeText(this, R.string.toast_call_detail_error,
+ Toast.LENGTH_SHORT).show();
+ finish();
+ }
+ } finally {
+ if (callCursor != null) {
+ callCursor.close();
+ }
+ }
+ }
+
+ static final class ViewEntry {
+ public int icon = -1;
+ public String text = null;
+ public Intent intent = null;
+
+ public ViewEntry(int icon, String text, Intent intent) {
+ this.icon = icon;
+ this.text = text;
+ this.intent = intent;
+ }
+ }
+
+ static final class ViewAdapter extends BaseAdapter {
+
+ private final View mCallDetailItem;
+ private final List<ViewEntry> mActions;
+
+ private final Context mContext;
+ private final LayoutInflater mInflater;
+
+ public ViewAdapter(Context context, View callDetailItem, List<ViewEntry> actions) {
+ mCallDetailItem = callDetailItem;
+ mActions = actions;
+
+ mContext = context;
+ mInflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ }
+
+ public int getCount() {
+ // Count is actions plus two headers and call details panel.
+ return mActions.size() + 2;
+ }
+
+ public Object getItem(int position) {
+ if (position >= POS_FIRST_ITEM) {
+ return mActions.get(position - POS_FIRST_ITEM);
+ }
+ return null;
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ private static final int TYPE_HEADER = 0;
+ private static final int TYPE_CALL_DETAILS = 1;
+ private static final int TYPE_ACTION = 2;
+
+ private static final int POS_CALL_DETAILS = 0;
+ private static final int POS_ACTIONS_HEADER = 1;
+ private static final int POS_FIRST_ITEM = 2;
+
+ public int getViewTypeCount() {
+ // Types are headers, call details panel, and actions.
+ return 3;
+ }
+
+ public int getItemViewType(int position) {
+ switch(position) {
+ case POS_CALL_DETAILS:
+ return TYPE_CALL_DETAILS;
+ case POS_ACTIONS_HEADER:
+ return TYPE_HEADER;
+ default:
+ return TYPE_ACTION;
+ }
+ }
+
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ public boolean isEnabled(int position) {
+ return (position > POS_ACTIONS_HEADER);
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ // Make sure we have a valid convertView to start with
+ if (convertView == null) {
+ switch(getItemViewType(position)) {
+ case TYPE_HEADER: {
+ convertView = mInflater.inflate(R.layout.list_separator, parent, false);
+ break;
+ }
+ case TYPE_CALL_DETAILS: {
+ convertView = mCallDetailItem;
+ break;
+ }
+ case TYPE_ACTION: {
+ convertView = mInflater.inflate(R.layout.dialpad_chooser_list_item,
+ parent, false);
+ break;
+ }
+ }
+ }
+
+ // Now fill our known-good convertView with data
+ switch(position) {
+ case POS_CALL_DETAILS: {
+ // Assume mCallDetailItem is already filled with correct data.
+ break;
+ }
+ case POS_ACTIONS_HEADER: {
+ TextView textView = (TextView) convertView;
+ textView.setText(mContext.getResources().getString(
+ R.string.header_actions));
+ break;
+ }
+ default: {
+ // Fill action with icon and text.
+ ViewEntry entry = (ViewEntry) getItem(position);
+ convertView.setTag(entry);
+
+ ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
+ TextView text = (TextView) convertView.findViewById(R.id.text);
+
+ icon.setImageResource(entry.icon);
+ text.setText(entry.text);
+
+ break;
+ }
+ }
+
+ return convertView;
+ }
+
+ }
+
+ public void onItemClick(AdapterView parent, View view, int position, long id) {
+ // Handle passing action off to correct handler.
+ if (view.getTag() instanceof ViewEntry) {
+ ViewEntry entry = (ViewEntry) view.getTag();
+ if (entry.intent != null) {
+ startActivity(entry.intent);
+ }
+ }
+ }
+}