FileDocCategorySizeDatePackage
ViewContactActivity.javaAPI DocAndroid 1.5 API42762Wed May 06 22:42:44 BST 2009com.android.contacts

ViewContactActivity

public class ViewContactActivity extends android.app.ListActivity implements View.OnCreateContextMenuListener, DialogInterface.OnClickListener, View.OnClickListener
Displays the details of a specific contact.

Fields Summary
private static final String
TAG
private static final String
SHOW_BARCODE_INTENT
private static final boolean
SHOW_SEPARATORS
private static final String[]
PHONE_KEYS
private static final String[]
EMAIL_KEYS
private static final int
DIALOG_CONFIRM_DELETE
public static final int
MENU_ITEM_DELETE
public static final int
MENU_ITEM_MAKE_DEFAULT
public static final int
MENU_ITEM_SHOW_BARCODE
private android.net.Uri
mUri
private android.content.ContentResolver
mResolver
private ViewAdapter
mAdapter
private int
mNumPhoneNumbers
ArrayList
mPhoneEntries
ArrayList
mSmsEntries
ArrayList
mEmailEntries
ArrayList
mPostalEntries
ArrayList
mImEntries
ArrayList
mOrganizationEntries
ArrayList
mOtherEntries
ArrayList
mSections
private android.database.Cursor
mCursor
private boolean
mObserverRegistered
private android.database.ContentObserver
mObserver
private android.widget.TextView
mNameView
private android.widget.TextView
mPhoneticNameView
private android.widget.ImageView
mPhotoView
private int
mNoPhotoResource
private android.widget.CheckBox
mStarView
private boolean
mShowSmsLinksForAllPhones
Constructors Summary
Methods Summary
java.lang.StringbuildActionString(int actionResId, java.lang.CharSequence type, boolean lowerCase)

        // If there is no type just display an empty string
        if (type == null) {
            type = "";
        }

        if (lowerCase) {
            return getString(actionResId, type.toString().toLowerCase());
        } else {
            return getString(actionResId, type.toString());
        }
    
private final voidbuildEntries(android.database.Cursor personCursor)
Build up the entries to display on the screen.

param
personCursor the URI for the contact being displayed

        // Clear out the old entries
        final int numSections = mSections.size();
        for (int i = 0; i < numSections; i++) {
            mSections.get(i).clear();
        }

        if (SHOW_SEPARATORS) {
            buildSeparators();
        }

        // Build up the phone entries
        final Uri phonesUri = Uri.withAppendedPath(mUri, People.Phones.CONTENT_DIRECTORY);
        final Cursor phonesCursor = mResolver.query(phonesUri, PHONES_PROJECTION, null, null,
                Phones.ISPRIMARY + " DESC");

        if (phonesCursor != null) {
            while (phonesCursor.moveToNext()) {
                final int type = phonesCursor.getInt(PHONES_TYPE_COLUMN);
                final String number = phonesCursor.getString(PHONES_NUMBER_COLUMN);
                final String label = phonesCursor.getString(PHONES_LABEL_COLUMN);
                final boolean isPrimary = phonesCursor.getInt(PHONES_ISPRIMARY_COLUMN) == 1;
                final long id = phonesCursor.getLong(PHONES_ID_COLUMN);
                final Uri uri = ContentUris.withAppendedId(phonesUri, id);

                // Don't crash if the number is bogus
                if (TextUtils.isEmpty(number)) {
                    Log.w(TAG, "empty number for phone " + id);
                    continue;
                }

                mNumPhoneNumbers++;
                
                // Add a phone number entry
                final ViewEntry entry = new ViewEntry();
                final CharSequence displayLabel = Phones.getDisplayLabel(this, type, label);
                entry.label = buildActionString(R.string.actionCall, displayLabel, true);
                entry.data = number;
                entry.id = id;
                entry.uri = uri;
                entry.intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, entry.uri);
                entry.auxIntent = new Intent(Intent.ACTION_SENDTO,
                        Uri.fromParts("sms", number, null));
                entry.kind = Contacts.KIND_PHONE;
                if (isPrimary) {
                    entry.primaryIcon = R.drawable.ic_default_number;
                }
                entry.actionIcon = android.R.drawable.sym_action_call;
                mPhoneEntries.add(entry);

                if (type == Phones.TYPE_MOBILE || mShowSmsLinksForAllPhones) {
                    // Add an SMS entry
                    ViewEntry smsEntry = new ViewEntry();
                    smsEntry.label = buildActionString(R.string.actionText, displayLabel, true);
                    smsEntry.data = number;
                    smsEntry.id = id;
                    smsEntry.uri = uri;
                    smsEntry.intent = entry.auxIntent;
                    smsEntry.kind = ViewEntry.KIND_SMS;
                    smsEntry.actionIcon = R.drawable.sym_action_sms;
                    mSmsEntries.add(smsEntry);
                }
            }

            phonesCursor.close();
        }

        // Build the contact method entries
        final Uri methodsUri = Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY);
        Cursor methodsCursor = mResolver.query(
                Uri.withAppendedPath(mUri, "contact_methods_with_presence"),
                METHODS_WITH_PRESENCE_PROJECTION, null, null, null);

        if (methodsCursor != null) {
            String[] protocolStrings = getResources().getStringArray(android.R.array.imProtocols);

            while (methodsCursor.moveToNext()) {
                final int kind = methodsCursor.getInt(METHODS_KIND_COLUMN);
                final String label = methodsCursor.getString(METHODS_LABEL_COLUMN);
                final String data = methodsCursor.getString(METHODS_DATA_COLUMN);
                final int type = methodsCursor.getInt(METHODS_TYPE_COLUMN);
                final long id = methodsCursor.getLong(METHODS_ID_COLUMN);
                final Uri uri = ContentUris.withAppendedId(methodsUri, id);

                // Don't crash if the data is bogus
                if (TextUtils.isEmpty(data)) {
                    Log.w(TAG, "empty data for contact method " + id);
                    continue;
                }

                ViewEntry entry = new ViewEntry();
                entry.id = id;
                entry.uri = uri;
                entry.kind = kind;

                switch (kind) {
                    case Contacts.KIND_EMAIL:
                        entry.label = buildActionString(R.string.actionEmail,
                                ContactMethods.getDisplayLabel(this, kind, type, label), true);
                        entry.data = data;
                        entry.intent = new Intent(Intent.ACTION_SENDTO,
                                Uri.fromParts("mailto", data, null));
                        entry.actionIcon = android.R.drawable.sym_action_email;
                        mEmailEntries.add(entry);
                        break;

                    case Contacts.KIND_POSTAL:
                        entry.label = buildActionString(R.string.actionMap,
                                ContactMethods.getDisplayLabel(this, kind, type, label), true);
                        entry.data = data;
                        entry.maxLines = 4;
                        entry.intent = new Intent(Intent.ACTION_VIEW, uri);
                        entry.actionIcon = R.drawable.sym_action_map;
                        mPostalEntries.add(entry);
                        break;

                    case Contacts.KIND_IM: {
                        Object protocolObj = ContactMethods.decodeImProtocol(
                                methodsCursor.getString(METHODS_AUX_DATA_COLUMN));
                        String host;
                        if (protocolObj instanceof Number) {
                            int protocol = ((Number) protocolObj).intValue();
                            entry.label = buildActionString(R.string.actionChat,
                                    protocolStrings[protocol], false);
                            host = ContactMethods.lookupProviderNameFromId(protocol).toLowerCase();
                            if (protocol == ContactMethods.PROTOCOL_GOOGLE_TALK
                                    || protocol == ContactMethods.PROTOCOL_MSN) {
                                entry.maxLabelLines = 2;
                            }
                        } else {
                            String providerName = (String) protocolObj;
                            entry.label = buildActionString(R.string.actionChat,
                                    providerName, false);
                            host = providerName.toLowerCase();
                        }

                        // Only add the intent if there is a valid host
                        if (!TextUtils.isEmpty(host)) {
                            entry.intent = new Intent(Intent.ACTION_SENDTO,
                                    constructImToUrl(host, data));
                        }
                        entry.data = data;
                        if (!methodsCursor.isNull(METHODS_STATUS_COLUMN)) {
                            entry.presenceIcon = Presence.getPresenceIconResourceId(
                                    methodsCursor.getInt(METHODS_STATUS_COLUMN));
                        }
                        entry.actionIcon = android.R.drawable.sym_action_chat;
                        mImEntries.add(entry);
                        break;
                    }
                }
            }

            methodsCursor.close();
        }

        // Build IM entries for things we have presence info about but not explicit IM entries for
        long personId = ContentUris.parseId(mUri);
        String[] projection = new String[] {
                Presence.IM_HANDLE, // 0
                Presence.IM_PROTOCOL, // 1
                Presence.PRESENCE_STATUS, // 2
        };
        Cursor presenceCursor = mResolver.query(Presence.CONTENT_URI, projection,
                Presence.PERSON_ID + "=" + personId, null, null);
        if (presenceCursor != null) {
            try {
                while (presenceCursor.moveToNext()) {
                    // Find the display info for the provider
                    String data = presenceCursor.getString(0);
                    String label;
                    Object protocolObj = ContactMethods.decodeImProtocol(
                            presenceCursor.getString(1));
                    String host;
                    if (protocolObj instanceof Number) {
                        int protocol = ((Number) protocolObj).intValue();
                        label = getResources().getStringArray(
                                android.R.array.imProtocols)[protocol];
                        host = ContactMethods.lookupProviderNameFromId(protocol).toLowerCase();
                    } else {
                        String providerName = (String) protocolObj;
                        label = providerName;
                        host = providerName.toLowerCase();
                    }

                    if (TextUtils.isEmpty(host)) {
                        // A valid provider name is required
                        continue;
                    }


                    Intent intent = new Intent(Intent.ACTION_SENDTO, constructImToUrl(host, data));

                    // Check to see if there is already an entry for this IM account
                    boolean addEntry = true;
                    int numImEntries = mImEntries.size();
                    for (int i = 0; i < numImEntries; i++) {
                        // Check to see if the intent point to the same thing, if so we won't
                        // add this entry to the list since there is already an explict entry
                        // for the IM account
                        Intent existingIntent = mImEntries.get(i).intent;
                        if (intent.filterEquals(existingIntent)) {
                            addEntry = false;
                            break;
                        }
                    }

                    // Add the entry if an existing one wasn't found
                    if (addEntry) {
                        ViewEntry entry = new ViewEntry();
                        entry.kind = Contacts.KIND_IM;
                        entry.data = data;
                        entry.label = label;
                        entry.intent = intent;
                        entry.actionIcon = android.R.drawable.sym_action_chat;
                        entry.presenceIcon = Presence.getPresenceIconResourceId(
                                presenceCursor.getInt(2));
                        entry.maxLabelLines = 2;
                        mImEntries.add(entry);
                    }
                }
            } finally {
                presenceCursor.close();
            }
        }

        // Build the organization entries
        final Uri organizationsUri = Uri.withAppendedPath(mUri, Organizations.CONTENT_DIRECTORY);
        Cursor organizationsCursor = mResolver.query(organizationsUri, ORGANIZATIONS_PROJECTION,
                null, null, null);

        if (organizationsCursor != null) {
            while (organizationsCursor.moveToNext()) {
                ViewEntry entry = new ViewEntry();
                entry.id = organizationsCursor.getLong(ORGANIZATIONS_ID_COLUMN);
                entry.uri = ContentUris.withAppendedId(organizationsUri, entry.id);
                entry.kind = Contacts.KIND_ORGANIZATION;
                entry.label = organizationsCursor.getString(ORGANIZATIONS_COMPANY_COLUMN);
                entry.data = organizationsCursor.getString(ORGANIZATIONS_TITLE_COLUMN);
                entry.actionIcon = R.drawable.sym_action_organization;
/*
                entry.label = Organizations.getDisplayLabel(this,
                        organizationsCursor.getInt(ORGANIZATIONS_TYPE_COLUMN),
                        organizationsCursor.getString(ORGANIZATIONS_LABEL_COLUMN)).toString();
*/
                mOrganizationEntries.add(entry);
            }

            organizationsCursor.close();
        }


        // Build the other entries
        String note = personCursor.getString(CONTACT_NOTES_COLUMN);
        if (!TextUtils.isEmpty(note)) {
            ViewEntry entry = new ViewEntry();
            entry.label = getString(R.string.label_notes);
            entry.data = note;
            entry.id = 0;
            entry.kind = ViewEntry.KIND_CONTACT;
            entry.uri = null;
            entry.intent = null;
            entry.maxLines = 10;
            entry.actionIcon = R.drawable.sym_note;
            mOtherEntries.add(entry);
        }
        
        // Build the ringtone entry
        String ringtoneStr = personCursor.getString(CONTACT_CUSTOM_RINGTONE_COLUMN);
        if (!TextUtils.isEmpty(ringtoneStr)) {
            // Get the URI
            Uri ringtoneUri = Uri.parse(ringtoneStr);
            if (ringtoneUri != null) {
                Ringtone ringtone = RingtoneManager.getRingtone(this, ringtoneUri);
                if (ringtone != null) {
                    ViewEntry entry = new ViewEntry();
                    entry.label = getString(R.string.label_ringtone);
                    entry.data = ringtone.getTitle(this);
                    entry.kind = ViewEntry.KIND_CONTACT;
                    entry.uri = ringtoneUri;
                    entry.actionIcon = R.drawable.sym_ringtone;
                    mOtherEntries.add(entry);
                }
            }
        }

        // Build the send directly to voice mail entry
        boolean sendToVoicemail = personCursor.getInt(CONTACT_SEND_TO_VOICEMAIL_COLUMN) == 1;
        if (sendToVoicemail) {
            ViewEntry entry = new ViewEntry();
            entry.label = getString(R.string.actionIncomingCall);
            entry.data = getString(R.string.detailIncomingCallsGoToVoicemail);
            entry.kind = ViewEntry.KIND_CONTACT;
            entry.actionIcon = R.drawable.sym_send_to_voicemail;
            mOtherEntries.add(entry);
        }
    
private voidbuildSeparators()
Build separator entries for all of the sections.

        ViewEntry separator;
        
        separator = new ViewEntry();
        separator.kind = ViewEntry.KIND_SEPARATOR;
        separator.data = getString(R.string.listSeparatorCallNumber);
        mPhoneEntries.add(separator);

        separator = new ViewEntry();
        separator.kind = ViewEntry.KIND_SEPARATOR;
        separator.data = getString(R.string.listSeparatorSendSmsMms);
        mSmsEntries.add(separator);

        separator = new ViewEntry();
        separator.kind = ViewEntry.KIND_SEPARATOR;
        separator.data = getString(R.string.listSeparatorSendEmail);
        mEmailEntries.add(separator);

        separator = new ViewEntry();
        separator.kind = ViewEntry.KIND_SEPARATOR;
        separator.data = getString(R.string.listSeparatorSendIm);
        mImEntries.add(separator);

        separator = new ViewEntry();
        separator.kind = ViewEntry.KIND_SEPARATOR;
        separator.data = getString(R.string.listSeparatorMapAddress);
        mPostalEntries.add(separator);

        separator = new ViewEntry();
        separator.kind = ViewEntry.KIND_SEPARATOR;
        separator.data = getString(R.string.listSeparatorOrganizations);
        mOrganizationEntries.add(separator);

        separator = new ViewEntry();
        separator.kind = ViewEntry.KIND_SEPARATOR;
        separator.data = getString(R.string.listSeparatorOtherInformation);
        mOtherEntries.add(separator);
    
private android.net.UriconstructImToUrl(java.lang.String host, java.lang.String data)

	    // don't encode the url, because the Activity Manager can't find using the encoded url
        StringBuilder buf = new StringBuilder("imto://");
        buf.append(host);
        buf.append('/");
        buf.append(data);
        return Uri.parse(buf.toString());
    
private voiddataChanged()

        mCursor.requery();
        if (mCursor.moveToFirst()) {
            // Set the name
            String name = mCursor.getString(CONTACT_NAME_COLUMN);
            if (TextUtils.isEmpty(name)) {
                mNameView.setText(getText(android.R.string.unknownName));
            } else {
                mNameView.setText(name);
            }

            if (mPhoneticNameView != null) {
                String phoneticName = mCursor.getString(CONTACT_PHONETIC_NAME_COLUMN);
                mPhoneticNameView.setText(phoneticName);
            }

            // Load the photo
            mPhotoView.setImageBitmap(People.loadContactPhoto(this, mUri, mNoPhotoResource,
                    null /* use the default options */));

            // Set the star
            mStarView.setChecked(mCursor.getInt(CONTACT_STARRED_COLUMN) == 1 ? true : false);

            // Build up the contact entries
            buildEntries(mCursor);
            if (mAdapter == null) {
                mAdapter = new ViewAdapter(this, mSections);
                setListAdapter(mAdapter);
            } else {
                mAdapter.setSections(mSections, SHOW_SEPARATORS);
            }
        } else {
            Toast.makeText(this, R.string.invalidContactMessage, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "invalid contact uri: " + mUri);
            finish();
        }
    
private booleanisBarcodeScannerInstalled()

        final Intent intent = new Intent(SHOW_BARCODE_INTENT);
        ResolveInfo ri = getPackageManager().resolveActivity(intent,
                PackageManager.MATCH_DEFAULT_ONLY);
        return ri != null;
    
public voidonClick(android.content.DialogInterface dialog, int which)


          
        if (mCursor != null) {
            if (mObserverRegistered) {
                mCursor.unregisterContentObserver(mObserver);
                mObserverRegistered = false;
            }
            mCursor.close();
            mCursor = null;
        }
        getContentResolver().delete(mUri, null, null);
        finish();
    
public voidonClick(android.view.View view)

        if (!mObserverRegistered) {
            return;
        }
        switch (view.getId()) {
            case R.id.star: {
                int oldStarredState = mCursor.getInt(CONTACT_STARRED_COLUMN);
                ContentValues values = new ContentValues(1);
                values.put(People.STARRED, oldStarredState == 1 ? 0 : 1);
                getContentResolver().update(mUri, values, null, null);
                break;
            }
        }
    
public booleanonContextItemSelected(android.view.MenuItem item)

        switch (item.getItemId()) {
            case MENU_ITEM_MAKE_DEFAULT: {
                AdapterView.AdapterContextMenuInfo info;
                try {
                     info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
                } catch (ClassCastException e) {
                    Log.e(TAG, "bad menuInfo", e);
                    break;
                }

                ViewEntry entry = ContactEntryAdapter.getEntry(mSections, info.position,
                        SHOW_SEPARATORS);
                ContentValues values = new ContentValues(1);
                values.put(People.PRIMARY_PHONE_ID, entry.id);
                getContentResolver().update(mUri, values, null, null);
                dataChanged();
                return true;
            }
        }
        return super.onContextItemSelected(item);
    
protected voidonCreate(android.os.Bundle icicle)

        super.onCreate(icicle);

        setContentView(R.layout.view_contact);
        getListView().setOnCreateContextMenuListener(this);

        mNameView = (TextView) findViewById(R.id.name);
        mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name);
        mPhotoView = (ImageView) findViewById(R.id.photo);
        mStarView = (CheckBox) findViewById(R.id.star);
        mStarView.setOnClickListener(this);

        // Set the photo with a random "no contact" image
        long now = SystemClock.elapsedRealtime();
        int num = (int) now & 0xf;
        if (num < 9) {
            // Leaning in from right, common
            mNoPhotoResource = R.drawable.ic_contact_picture;
        } else if (num < 14) {
            // Leaning in from left uncommon
            mNoPhotoResource = R.drawable.ic_contact_picture_2;
        } else {
            // Coming in from the top, rare
            mNoPhotoResource = R.drawable.ic_contact_picture_3;
        }

        mUri = getIntent().getData();
        mResolver = getContentResolver();

        // Build the list of sections. The order they're added to mSections dictates the
        // order they are displayed in the list.
        mSections.add(mPhoneEntries);
        mSections.add(mSmsEntries);
        mSections.add(mEmailEntries);
        mSections.add(mImEntries);
        mSections.add(mPostalEntries);
        mSections.add(mOrganizationEntries);
        mSections.add(mOtherEntries);

        //TODO Read this value from a preference
        mShowSmsLinksForAllPhones = true;

        mCursor = mResolver.query(mUri, CONTACT_PROJECTION, null, null, null);
    
public voidonCreateContextMenu(android.view.ContextMenu menu, android.view.View view, android.view.ContextMenu.ContextMenuInfo menuInfo)

        AdapterView.AdapterContextMenuInfo info;
        try {
             info = (AdapterView.AdapterContextMenuInfo) menuInfo;
        } catch (ClassCastException e) {
            Log.e(TAG, "bad menuInfo", e);
            return;
        }

        // This can be null sometimes, don't crash...
        if (info == null) {
            Log.e(TAG, "bad menuInfo");
            return;
        }

        ViewEntry entry = ContactEntryAdapter.getEntry(mSections, info.position, SHOW_SEPARATORS);
        switch (entry.kind) {
            case Contacts.KIND_PHONE: {
                menu.add(0, 0, 0, R.string.menu_call).setIntent(entry.intent);
                menu.add(0, 0, 0, R.string.menu_sendSMS).setIntent(entry.auxIntent);
                if (entry.primaryIcon == -1) {
                    menu.add(0, MENU_ITEM_MAKE_DEFAULT, 0, R.string.menu_makeDefaultNumber);
                }
                break;
            }

            case Contacts.KIND_EMAIL: {
                menu.add(0, 0, 0, R.string.menu_sendEmail).setIntent(entry.intent);
                break;
            }

            case Contacts.KIND_POSTAL: {
                menu.add(0, 0, 0, R.string.menu_viewAddress).setIntent(entry.intent);
                break;
            }
        }
    
protected android.app.DialogonCreateDialog(int id)

        switch (id) {
            case DIALOG_CONFIRM_DELETE:
                return new AlertDialog.Builder(this)
                        .setTitle(R.string.deleteConfirmation_title)
                        .setIcon(android.R.drawable.ic_dialog_alert)
                        .setMessage(R.string.deleteConfirmation)
                        .setNegativeButton(android.R.string.cancel, null)
                        .setPositiveButton(android.R.string.ok, this)
                        .setCancelable(false)
                        .create();
        }
        return null;
    
public booleanonCreateOptionsMenu(android.view.Menu menu)

        menu.add(0, 0, 0, R.string.menu_editContact)
                .setIcon(android.R.drawable.ic_menu_edit)
                .setIntent(new Intent(Intent.ACTION_EDIT, mUri))
                .setAlphabeticShortcut('e");
        menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_deleteContact)
                .setIcon(android.R.drawable.ic_menu_delete);

        return true;
    
protected voidonDestroy()

        super.onDestroy();

        if (mCursor != null) {
            if (mObserverRegistered) {
                mCursor.unregisterContentObserver(mObserver);
                mObserverRegistered = false;
            }
            mCursor.close();
        }
    
public booleanonKeyDown(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()) {
                        // Skip out and let the key be handled at a higher level
                        break;
                    }
                } catch (RemoteException re) {
                    // Fall through and try to call the contact
                }

                int index = getListView().getSelectedItemPosition();
                if (index != -1) {
                    ViewEntry entry = ViewAdapter.getEntry(mSections, index, SHOW_SEPARATORS);
                    if (entry.kind == Contacts.KIND_PHONE) {
                        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, entry.uri);
                        startActivity(intent);
                    }
                } else if (mNumPhoneNumbers != 0) {
                    // There isn't anything selected, call the default number
                    Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, mUri);
                    startActivity(intent);
                }
                return true;
            }

            case KeyEvent.KEYCODE_DEL: {
                showDialog(DIALOG_CONFIRM_DELETE);
                return true;
            }
        }

        return super.onKeyDown(keyCode, event);
    
protected voidonListItemClick(android.widget.ListView l, android.view.View v, int position, long id)

        ViewEntry entry = ViewAdapter.getEntry(mSections, position, SHOW_SEPARATORS);
        if (entry != null) {
            Intent intent = entry.intent;
            if (intent != null) {
                try {
                    startActivity(intent);
                } catch (ActivityNotFoundException e) {
                    Log.e(TAG, "No activity found for intent: " + intent);
                    signalError();
                }
            } else {
                signalError();
            }
        } else {
            signalError();
        }
    
public booleanonOptionsItemSelected(android.view.MenuItem item)

        switch (item.getItemId()) {
            case MENU_ITEM_DELETE: {
                // Get confirmation
                showDialog(DIALOG_CONFIRM_DELETE);
                return true;
            }
            case MENU_ITEM_SHOW_BARCODE:
                if (mCursor.moveToFirst()) {
                    Intent intent = new Intent(SHOW_BARCODE_INTENT);
                    intent.putExtra("ENCODE_TYPE", "CONTACT_TYPE");
                    Bundle bundle = new Bundle();
                    String name = mCursor.getString(CONTACT_NAME_COLUMN);
                    if (!TextUtils.isEmpty(name)) {
                        // Correctly handle when section headers are hidden
                        int sepAdjust = SHOW_SEPARATORS ? 1 : 0;
                        
                        bundle.putString(Contacts.Intents.Insert.NAME, name);
                        // The 0th ViewEntry in each ArrayList below is a separator item
                        int entriesToAdd = Math.min(mPhoneEntries.size() - sepAdjust, PHONE_KEYS.length);
                        for (int x = 0; x < entriesToAdd; x++) {
                            ViewEntry entry = mPhoneEntries.get(x + sepAdjust);
                            bundle.putString(PHONE_KEYS[x], entry.data);
                        }
                        entriesToAdd = Math.min(mEmailEntries.size() - sepAdjust, EMAIL_KEYS.length);
                        for (int x = 0; x < entriesToAdd; x++) {
                            ViewEntry entry = mEmailEntries.get(x + sepAdjust);
                            bundle.putString(EMAIL_KEYS[x], entry.data);
                        }
                        if (mPostalEntries.size() >= 1 + sepAdjust) {
                            ViewEntry entry = mPostalEntries.get(sepAdjust);
                            bundle.putString(Contacts.Intents.Insert.POSTAL, entry.data);
                        }
                        intent.putExtra("ENCODE_DATA", bundle);
                        try {
                            startActivity(intent);
                        } catch (ActivityNotFoundException e) {
                            // The check in onPrepareOptionsMenu() should make this impossible, but
                            // for safety I'm catching the exception rather than crashing. Ideally
                            // I'd call Menu.removeItem() here too, but I don't see a way to get
                            // the options menu.
                            Log.e(TAG, "Show barcode menu item was clicked but Barcode Scanner " +
                                    "was not installed.");
                        }
                        return true;
                    }
                }
                break;
        }
        return super.onOptionsItemSelected(item);
    
protected voidonPause()

        super.onPause();
        if (mCursor != null) {
            if (mObserverRegistered) {
                mObserverRegistered = false;
                mCursor.unregisterContentObserver(mObserver);
            }
            mCursor.deactivate();
        }
    
public booleanonPrepareOptionsMenu(android.view.Menu menu)

        super.onPrepareOptionsMenu(menu);
        // Perform this check each time the menu is about to be shown, because the Barcode Scanner
        // could be installed or uninstalled at any time.
        if (isBarcodeScannerInstalled()) {
            if (menu.findItem(MENU_ITEM_SHOW_BARCODE) == null) {
                menu.add(0, MENU_ITEM_SHOW_BARCODE, 0, R.string.menu_showBarcode)
                        .setIcon(R.drawable.ic_menu_show_barcode);
            }
        } else {
            menu.removeItem(MENU_ITEM_SHOW_BARCODE);
        }
        return true;
    
protected voidonResume()

        super.onResume();
        mObserverRegistered = true;
        mCursor.registerContentObserver(mObserver);
        dataChanged();
    
private voidsignalError()
Signal an error to the user via a beep, or some other method.

        //TODO: implement this when we have the sonification APIs