blob: ddec79902136f0c8cad7d184dba49fc262f4fea0 [file] [log] [blame]
/*
* Copyright (C) 2010 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.quickcontact;
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.model.AccountType.EditType;
import com.android.contacts.model.DataKind;
import com.android.contacts.util.Constants;
import com.android.contacts.util.PhoneCapabilityTester;
import com.android.contacts.util.StructuredPostalUtils;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.net.WebAddress;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
import android.provider.ContactsContract.Data;
import android.text.TextUtils;
import android.util.Log;
/**
* Description of a specific {@link Data#_ID} item, with style information
* defined by a {@link DataKind}.
*/
public class DataAction implements Action {
private static final String TAG = "DataAction";
private final Context mContext;
private final DataKind mKind;
private final String mMimeType;
private CharSequence mBody;
private CharSequence mSubtitle;
private Intent mIntent;
private Intent mAlternateIntent;
private int mAlternateIconDescriptionRes;
private int mAlternateIconRes;
private int mPresence = -1;
private Uri mDataUri;
private long mDataId;
private boolean mIsPrimary;
/**
* Create an action from common {@link Data} elements.
*/
public DataAction(Context context, String mimeType, DataKind kind, long dataId,
ContentValues entryValues) {
mContext = context;
mKind = kind;
mMimeType = mimeType;
// Determine type for subtitle
mSubtitle = "";
if (kind.typeColumn != null) {
if (entryValues.containsKey(kind.typeColumn)) {
final int typeValue = entryValues.getAsInteger(kind.typeColumn);
// get type string
for (EditType type : kind.typeList) {
if (type.rawValue == typeValue) {
if (type.customColumn == null) {
// Non-custom type. Get its description from the resource
mSubtitle = context.getString(type.labelRes);
} else {
// Custom type. Read it from the database
mSubtitle = entryValues.getAsString(type.customColumn);
}
break;
}
}
}
}
final Integer superPrimary = entryValues.getAsInteger(Data.IS_SUPER_PRIMARY);
mIsPrimary = superPrimary != null && superPrimary != 0;
if (mKind.actionBody != null) {
mBody = mKind.actionBody.inflateUsing(context, entryValues);
}
mDataId = dataId;
mDataUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId);
final boolean hasPhone = PhoneCapabilityTester.isPhone(mContext);
final boolean hasSms = PhoneCapabilityTester.isSmsIntentRegistered(mContext);
// Handle well-known MIME-types with special care
if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
if (PhoneCapabilityTester.isPhone(mContext)) {
final String number = entryValues.getAsString(Phone.NUMBER);
if (!TextUtils.isEmpty(number)) {
final Intent phoneIntent = hasPhone ? ContactsUtils.getCallIntent(number)
: null;
final Intent smsIntent = hasSms ? new Intent(Intent.ACTION_SENDTO,
Uri.fromParts(Constants.SCHEME_SMSTO, number, null)) : null;
// Configure Icons and Intents. Notice actionIcon is already set to the phone
if (hasPhone && hasSms) {
mIntent = phoneIntent;
mAlternateIntent = smsIntent;
mAlternateIconRes = kind.iconAltRes;
mAlternateIconDescriptionRes = kind.iconAltDescriptionRes;
} else if (hasPhone) {
mIntent = phoneIntent;
} else if (hasSms) {
mIntent = smsIntent;
}
}
}
} else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType)) {
if (PhoneCapabilityTester.isSipPhone(mContext)) {
final String address = entryValues.getAsString(SipAddress.SIP_ADDRESS);
if (!TextUtils.isEmpty(address)) {
final Uri callUri = Uri.fromParts(Constants.SCHEME_SIP, address, null);
mIntent = ContactsUtils.getCallIntent(callUri);
// Note that this item will get a SIP-specific variant
// of the "call phone" icon, rather than the standard
// app icon for the Phone app (which we show for
// regular phone numbers.) That's because the phone
// app explicitly specifies an android:icon attribute
// for the SIP-related intent-filters in its manifest.
}
}
} else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
final String address = entryValues.getAsString(Email.DATA);
if (!TextUtils.isEmpty(address)) {
final Uri mailUri = Uri.fromParts(Constants.SCHEME_MAILTO, address, null);
mIntent = new Intent(Intent.ACTION_SENDTO, mailUri);
}
} else if (Website.CONTENT_ITEM_TYPE.equals(mimeType)) {
final String url = entryValues.getAsString(Website.URL);
if (!TextUtils.isEmpty(url)) {
WebAddress webAddress = new WebAddress(url);
mIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webAddress.toString()));
}
} else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(
entryValues.getAsString(Data.MIMETYPE));
if (isEmail || isProtocolValid(entryValues)) {
final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK :
entryValues.getAsInteger(Im.PROTOCOL);
if (isEmail) {
// Use Google Talk string when using Email, and clear data
// Uri so we don't try saving Email as primary.
mSubtitle = Im.getProtocolLabel(context.getResources(), Im.PROTOCOL_GOOGLE_TALK,
null);
mDataUri = null;
}
String host = entryValues.getAsString(Im.CUSTOM_PROTOCOL);
String data = entryValues.getAsString(isEmail ? Email.DATA : Im.DATA);
if (protocol != Im.PROTOCOL_CUSTOM) {
// Try bringing in a well-known host for specific protocols
host = ContactsUtils.lookupProviderNameFromId(protocol);
}
if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(data)) {
final String authority = host.toLowerCase();
final Uri imUri = new Uri.Builder().scheme(Constants.SCHEME_IMTO).authority(
authority).appendPath(data).build();
mIntent = new Intent(Intent.ACTION_SENDTO, imUri);
// If the address is also available for a video chat, we'll show the capability
// as a secondary action.
final Integer chatCapabilityObj = entryValues.getAsInteger(Im.CHAT_CAPABILITY);
final int chatCapability = chatCapabilityObj == null ? 0 : chatCapabilityObj;
final boolean isVideoChatCapable =
(chatCapability & Im.CAPABILITY_HAS_CAMERA) != 0;
final boolean isAudioChatCapable =
(chatCapability & Im.CAPABILITY_HAS_VOICE) != 0;
if (isVideoChatCapable || isAudioChatCapable) {
mAlternateIntent = new Intent(
Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?call"));
if (isVideoChatCapable) {
mAlternateIconRes = R.drawable.sym_action_videochat_holo_light;
mAlternateIconDescriptionRes = R.string.video_chat;
} else {
mAlternateIconRes = R.drawable.sym_action_audiochat_holo_light;
mAlternateIconDescriptionRes = R.string.audio_chat;
}
}
}
}
} else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
final String postalAddress =
entryValues.getAsString(StructuredPostal.FORMATTED_ADDRESS);
if (!TextUtils.isEmpty(postalAddress)) {
mIntent = StructuredPostalUtils.getViewPostalAddressIntent(postalAddress);
}
}
if (mIntent == null) {
// Otherwise fall back to default VIEW action
mIntent = new Intent(Intent.ACTION_VIEW);
mIntent.setDataAndType(mDataUri, mimeType);
}
mIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
}
@Override
public int getPresence() {
return mPresence;
}
public void setPresence(int presence) {
mPresence = presence;
}
private boolean isProtocolValid(ContentValues entryValues) {
final String protocol = entryValues.getAsString(Im.PROTOCOL);
if (protocol == null) {
return false;
}
try {
Integer.valueOf(protocol);
} catch (NumberFormatException e) {
return false;
}
return true;
}
@Override
public CharSequence getSubtitle() {
return mSubtitle;
}
@Override
public CharSequence getBody() {
return mBody;
}
@Override
public String getMimeType() {
return mMimeType;
}
@Override
public Uri getDataUri() {
return mDataUri;
}
@Override
public long getDataId() {
return mDataId;
}
@Override
public Boolean isPrimary() {
return mIsPrimary;
}
@Override
public Drawable getAlternateIcon() {
if (mAlternateIconRes == 0) return null;
final String resourcePackageName = mKind.resourcePackageName;
if (resourcePackageName == null) {
return mContext.getResources().getDrawable(mAlternateIconRes);
}
final PackageManager pm = mContext.getPackageManager();
return pm.getDrawable(resourcePackageName, mAlternateIconRes, null);
}
@Override
public String getAlternateIconDescription() {
if (mAlternateIconDescriptionRes == 0) return null;
return mContext.getResources().getString(mAlternateIconDescriptionRes);
}
@Override
public Intent getIntent() {
return mIntent;
}
@Override
public Intent getAlternateIntent() {
return mAlternateIntent;
}
@Override
public boolean collapseWith(Action other) {
if (!shouldCollapseWith(other)) {
return false;
}
return true;
}
@Override
public boolean shouldCollapseWith(Action t) {
if (t == null) {
return false;
}
if (!(t instanceof DataAction)) {
Log.e(TAG, "t must be DataAction");
return false;
}
DataAction that = (DataAction)t;
if (!ContactsUtils.shouldCollapse(mMimeType, mBody, that.mMimeType, that.mBody)) {
return false;
}
if (!TextUtils.equals(mMimeType, that.mMimeType)
|| !ContactsUtils.areIntentActionEqual(mIntent, that.mIntent)) {
return false;
}
return true;
}
}