OSDN Git Service

Implement call and SMS shortcuts.
authorDianne Hackborn <hackbod@google.com>
Tue, 26 May 2009 19:46:23 +0000 (12:46 -0700)
committerDianne Hackborn <hackbod@google.com>
Tue, 26 May 2009 19:49:28 +0000 (12:49 -0700)
This is basically the code from AnyCut integrated into the contacts app.
It doesn't yet let you change the shortcut name before it is added, but that
would be nice to do.

AndroidManifest.xml
res/drawable-finger/badge_action_call.png [new file with mode: 0644]
res/drawable-finger/badge_action_sms.png [new file with mode: 0644]
res/values/colors.xml [new file with mode: 0644]
res/values/strings.xml
src/com/android/contacts/ContactsListActivity.java

index f515434..33d8168 100644 (file)
 
         </activity-alias>
 
+        <activity-alias android:name="alias.DialShortcut"
+            android:targetActivity="ContactsListActivity"
+            android:label="@string/shortcutDialContact"
+            android:icon="@drawable/ic_launcher_shortcut_contact">
+
+            <intent-filter>
+                <action android:name="android.intent.action.CREATE_SHORTCUT" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+
+        </activity-alias>
+
+        <activity-alias android:name="alias.MessageShortcut"
+            android:targetActivity="ContactsListActivity"
+            android:label="@string/shortcutMessageContact"
+            android:icon="@drawable/ic_launcher_shortcut_contact">
+
+            <intent-filter>
+                <action android:name="android.intent.action.CREATE_SHORTCUT" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+
+        </activity-alias>
+
         <activity android:name="CallDetailActivity"
             android:label="@string/callDetailTitle"
             android:theme="@style/TallTitleBarTheme"
diff --git a/res/drawable-finger/badge_action_call.png b/res/drawable-finger/badge_action_call.png
new file mode 100644 (file)
index 0000000..3bc88a3
Binary files /dev/null and b/res/drawable-finger/badge_action_call.png differ
diff --git a/res/drawable-finger/badge_action_sms.png b/res/drawable-finger/badge_action_sms.png
new file mode 100644 (file)
index 0000000..bbcfb59
Binary files /dev/null and b/res/drawable-finger/badge_action_sms.png differ
diff --git a/res/values/colors.xml b/res/values/colors.xml
new file mode 100644 (file)
index 0000000..fb4019d
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+    <color name="textColorIconOverlay">#fff</color>
+    <color name="textColorIconOverlayShadow">#000</color>
+</resources>
index c147479..fe866f7 100644 (file)
          This shows up in a list of things like bookmark, folder, music playlist, etc -->
     <string name="shortcutContact">Contact</string>
 
+    <!-- Name of activity that allows users to create shortcuts on the home screen to dial a contact.
+         This shows up in a list of things like bookmark, folder, music playlist, etc -->
+    <string name="shortcutDialContact">Direct Dial</string>
+
+    <!-- Name of activity that allows users to create shortcuts on the home screen to message (SMS) a contact.
+         This shows up in a list of things like bookmark, folder, music playlist, etc -->
+    <string name="shortcutMessageContact">Direct Message</string>
+
+    <!-- Activity title when the user is selecting a contact for a shortcut. -->
+    <string name="shortcutActivityTitle">Choose a contact shortcut</string>
+    
+    <!-- Activity title when the user is selecting a contact for a direct dial shortcut. -->
+    <string name="callShortcutActivityTitle">Choose a number to call</string>
+    
+    <!-- Activity title when the user is selecting a contact for a direct message shortcut. -->
+    <string name="messageShortcutActivityTitle">Choose a number to message</string>
+        
     <!-- Title for the activity that shows only starred contacts -->
     <string name="starredList">Starred</string>
 
index 041d61d..0ddb608 100644 (file)
@@ -30,10 +30,17 @@ import android.content.IContentProvider;
 import android.content.ISyncAdapter;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.res.Resources;
 import android.database.CharArrayBuffer;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -83,6 +90,8 @@ public final class ContactsListActivity extends ListActivity
         implements View.OnCreateContextMenuListener, DialogInterface.OnClickListener {
     private static final String TAG = "ContactsListActivity";
 
+    private static final boolean ENABLE_ACTION_ICON_OVERLAYS = false;
+
     private static final String LIST_STATE_KEY = "liststate";
     private static final String FOCUS_KEY = "focused";
     
@@ -291,7 +300,7 @@ public final class ContactsListActivity extends ListActivity
     private Parcelable mListState = null;
     private boolean mListHasFocus;
 
-    private boolean mCreateShortcut;
+    private String mShortcutAction;
     private boolean mDefaultMode = false;
     
     /**
@@ -401,8 +410,19 @@ public final class ContactsListActivity extends ListActivity
                 mMode = MODE_PICK_POSTAL;
             }
         } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
-            mMode = MODE_PICK_OR_CREATE_CONTACT;
-            mCreateShortcut = true;
+            if (intent.getComponent().getClassName().equals("alias.DialShortcut")) {
+                mMode = MODE_PICK_PHONE;
+                mShortcutAction = Intent.ACTION_CALL;
+                setTitle(R.string.callShortcutActivityTitle);
+            } else if (intent.getComponent().getClassName().equals("alias.MessageShortcut")) {
+                mMode = MODE_PICK_PHONE;
+                mShortcutAction = Intent.ACTION_SENDTO;
+                setTitle(R.string.messageShortcutActivityTitle);
+            } else {
+                mMode = MODE_PICK_OR_CREATE_CONTACT;
+                mShortcutAction = Intent.ACTION_VIEW;
+                setTitle(R.string.shortcutActivityTitle);
+            }
         } else if (Intent.ACTION_GET_CONTENT.equals(action)) {
             final String type = intent.resolveType(this);
             if (People.CONTENT_ITEM_TYPE.equals(type)) {
@@ -879,8 +899,8 @@ public final class ContactsListActivity extends ListActivity
             case SUBACTIVITY_NEW_CONTACT:
                 if (resultCode == RESULT_OK) {
                     // Contact was created, pass it back
-                    returnPickerResult(data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME),
-                            data.getData());
+                    returnPickerResult(null, data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME),
+                            data.getData(), 0);
                 }
         }
     }
@@ -1064,18 +1084,22 @@ public final class ContactsListActivity extends ListActivity
             } else if (mMode == MODE_PICK_CONTACT 
                     || mMode == MODE_PICK_OR_CREATE_CONTACT) {
                 Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, id);
-                if (mCreateShortcut) {
+                if (mShortcutAction != null) {
                     // Subtract one if we have Create Contact at the top
                     Cursor c = (Cursor) mAdapter.getItem(position
                             - (mMode == MODE_PICK_OR_CREATE_CONTACT? 1:0));
-                    returnPickerResult(c.getString(NAME_COLUMN_INDEX), uri);
+                    returnPickerResult(c, c.getString(NAME_COLUMN_INDEX), uri, id);
                 } else {
-                    returnPickerResult(null, uri);
+                    returnPickerResult(null, null, uri, id);
                 }
             } else if (mMode == MODE_PICK_PHONE) {
-                setResult(RESULT_OK, new Intent().setData(
-                        ContentUris.withAppendedId(Phones.CONTENT_URI, id)));
-                finish();
+                Uri uri = ContentUris.withAppendedId(Phones.CONTENT_URI, id);
+                if (mShortcutAction != null) {
+                    Cursor c = (Cursor) mAdapter.getItem(position);
+                    returnPickerResult(c, c.getString(NAME_COLUMN_INDEX), uri, id);
+                } else {
+                    returnPickerResult(null, null, uri, id);
+                }
             } else if (mMode == MODE_PICK_POSTAL) {
                 setResult(RESULT_OK, new Intent().setData(
                         ContentUris.withAppendedId(ContactMethods.CONTENT_URI, id)));
@@ -1090,22 +1114,47 @@ public final class ContactsListActivity extends ListActivity
         }
     }
 
-    private void returnPickerResult(String name, Uri uri) {
+    private void returnPickerResult(Cursor c, String name, Uri uri, long id) {
         final Intent intent = new Intent();
     
-        if (mCreateShortcut) {
-            Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, uri);
+        if (mShortcutAction != null) {
+            Intent shortcutIntent;
+            if (Intent.ACTION_VIEW.equals(mShortcutAction)) {
+                // This is a simple shortcut to view a contact.
+                shortcutIntent = new Intent(mShortcutAction, uri);
+                final Bitmap icon = People.loadContactPhoto(this, uri, 0, null);
+                if (icon != null) {
+                    intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);
+                } else {
+                    intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
+                            Intent.ShortcutIconResource.fromContext(this,
+                                    R.drawable.ic_launcher_shortcut_contact));
+                }
+            } else {
+                // This is a direct dial or sms shortcut.
+                String number = c.getString(DATA_COLUMN_INDEX);
+                int type = c.getInt(TYPE_COLUMN_INDEX);
+                String scheme;
+                int resid;
+                if (Intent.ACTION_CALL.equals(mShortcutAction)) {
+                    scheme = "tel";
+                    resid = R.drawable.badge_action_call;
+                } else {
+                    scheme = "smsto";
+                    resid = R.drawable.badge_action_sms;
+                }
+                // Make the URI a direct tel: URI so that it will always continue to work
+                Uri phoneUri = Uri.fromParts(scheme, number, null);
+                shortcutIntent = new Intent(mShortcutAction, phoneUri);
+                
+                Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, id);
+                intent.putExtra(Intent.EXTRA_SHORTCUT_ICON,
+                        generatePhoneNumberIcon(personUri, type, resid));
+                
+            }
             shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
             intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
             intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
-            final Bitmap icon = People.loadContactPhoto(this, uri, 0, null);
-            if (icon != null) {
-                intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);
-            } else {
-                intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
-                        Intent.ShortcutIconResource.fromContext(this,
-                                R.drawable.ic_launcher_shortcut_contact));
-            }
             setResult(RESULT_OK, intent);
         } else {
             setResult(RESULT_OK, intent.setData(uri));
@@ -1113,6 +1162,107 @@ public final class ContactsListActivity extends ListActivity
         finish();
     }
 
+    /**
+     * Generates a phone number shortcut icon. Adds an overlay describing the type of the phone
+     * number, and if there is a photo also adds the call action icon.
+     *
+     * @param personUri The person the phone number belongs to
+     * @param type The type of the phone number
+     * @param actionResId The ID for the action resource
+     * @return The bitmap for the icon
+     */
+    private Bitmap generatePhoneNumberIcon(Uri personUri, int type, int actionResId) {
+        final Resources r = getResources();
+        boolean drawPhoneOverlay = true;
+
+        Bitmap photo = People.loadContactPhoto(this, personUri, 0, null);
+        if (photo == null) {
+            // If there isn't a photo use the generic phone action icon instead
+            Bitmap phoneIcon = getPhoneActionIcon(r, actionResId);
+            if (phoneIcon != null) {
+                photo = phoneIcon;
+                drawPhoneOverlay = false;
+            } else {
+                return null;
+            }
+        }
+
+        // Setup the drawing classes
+        int iconSize = (int) r.getDimension(android.R.dimen.app_icon_size);
+        Bitmap icon = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(icon);
+
+        // Copy in the photo
+        Paint photoPaint = new Paint();
+        photoPaint.setDither(true);
+        photoPaint.setFilterBitmap(true);
+        Rect src = new Rect(0,0, photo.getWidth(),photo.getHeight());
+        Rect dst = new Rect(0,0, iconSize,iconSize);
+        canvas.drawBitmap(photo, src, dst, photoPaint);
+
+        // Create an overlay for the phone number type
+        String overlay = null;
+        switch (type) {
+            case Phones.TYPE_HOME:
+                overlay = "H";
+                break;
+
+            case Phones.TYPE_MOBILE:
+                overlay = "M";
+                break;
+
+            case Phones.TYPE_WORK:
+                overlay = "W";
+                break;
+
+            case Phones.TYPE_PAGER:
+                overlay = "P";
+                break;
+
+            case Phones.TYPE_OTHER:
+                overlay = "O";
+                break;
+        }
+        if (overlay != null) {
+            Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
+            textPaint.setTextSize(20.0f);
+            textPaint.setTypeface(Typeface.DEFAULT_BOLD);
+            textPaint.setColor(r.getColor(R.color.textColorIconOverlay));
+            textPaint.setShadowLayer(3f, 1, 1, r.getColor(R.color.textColorIconOverlayShadow));
+            canvas.drawText(overlay, 2, 16, textPaint);
+        }
+
+        // Draw the phone action icon as an overlay
+        if (ENABLE_ACTION_ICON_OVERLAYS && drawPhoneOverlay) {
+            Bitmap phoneIcon = getPhoneActionIcon(r, actionResId);
+            if (phoneIcon != null) {
+                src.set(0,0, phoneIcon.getWidth(),phoneIcon.getHeight());
+                int iconWidth = icon.getWidth();
+                dst.set(iconWidth - 20, -1, iconWidth, 19);
+                canvas.drawBitmap(phoneIcon, src, dst, photoPaint);
+            }
+        }
+
+        return icon;
+    }
+
+    /**
+     * Returns the icon for the phone call action.
+     *
+     * @param r The resources to load the icon from
+     * @param resId The resource ID to load
+     * @return the icon for the phone call action
+     */
+    private Bitmap getPhoneActionIcon(Resources r, int resId) {
+        Drawable phoneIcon = r.getDrawable(resId);
+        if (phoneIcon instanceof BitmapDrawable) {
+            BitmapDrawable bd = (BitmapDrawable) phoneIcon;
+            return bd.getBitmap();
+        } else {
+            return null;
+        }
+    }
+    
     String[] getProjection() {
         switch (mMode) {
             case MODE_GROUP: