Merge change I0ad3fc43 into eclair

* changes:
  Avoid IAE by only dismissing dialog when still attached.
diff --git a/res/anim/quickcontact.xml b/res/anim/quickcontact.xml
index 6fd1a27..5dd5a16 100644
--- a/res/anim/quickcontact.xml
+++ b/res/anim/quickcontact.xml
@@ -4,4 +4,4 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:fromXDelta="100%p"
     android:toXDelta="0"
-    android:duration="400" />
+    android:duration="325" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a82f5a9..25189db 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -24,4 +24,7 @@
     <!-- The height of the ScrollingTabWidget -->
     <dimen name="tab_height">40dip</dimen>
     <dimen name="account_name_height">25dip</dimen>
+    
+    <dimen name="contact_shortcut_frame_width">50dip</dimen>    
+    <dimen name="contact_shortcut_frame_height">56dip</dimen>    
 </resources>
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 5613794..24c7100 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -103,6 +103,7 @@
 import android.widget.SectionIndexer;
 import android.widget.TextView;
 import android.widget.AbsListView.OnScrollListener;
+import android.*;
 
 import java.lang.ref.SoftReference;
 import java.lang.ref.WeakReference;
@@ -111,6 +112,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Random;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -388,7 +390,7 @@
     private static final String CLAUSE_ONLY_PHONES = Contacts.HAS_PHONE_NUMBER + "=1";
 
     /**
-     * In the {@link #MODE_JOIN} determines whether we display a list item with the label
+     * In the {@link #MODE_JOIN_CONTACT} determines whether we display a list item with the label
      * "Show all contacts" or actually show all contacts
      */
     private boolean mJoinModeShowAllContacts;
@@ -1308,8 +1310,17 @@
             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 = loadContactPhoto(id, null);
+                shortcutIntent = new Intent(ContactsContract.QuickContact.ACTION_QUICK_CONTACT);
+                shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+                        Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+    
+                shortcutIntent.setData(uri);
+                shortcutIntent.putExtra(ContactsContract.QuickContact.EXTRA_MODE,
+                        ContactsContract.QuickContact.MODE_LARGE);
+                shortcutIntent.putExtra(ContactsContract.QuickContact.EXTRA_EXCLUDE_MIMES,
+                        (String[]) null);
+
+                final Bitmap icon = framePhoto(loadContactPhoto(id, null));
                 if (icon != null) {
                     intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);
                 } else {
@@ -1350,6 +1361,33 @@
         finish();
     }
 
+    private Bitmap framePhoto(Bitmap photo) {
+        final Resources r = getResources();
+        final Drawable frame = r.getDrawable(com.android.internal.R.drawable.quickcontact_badge);
+
+        final int width = r.getDimensionPixelSize(R.dimen.contact_shortcut_frame_width);
+        final int height = r.getDimensionPixelSize(R.dimen.contact_shortcut_frame_height);
+
+        frame.setBounds(0, 0, width, height);
+
+        final Rect padding = new Rect();
+        frame.getPadding(padding);
+
+        final Rect source = new Rect(0, 0, photo.getWidth(), photo.getHeight());
+        final Rect destination = new Rect(padding.left, padding.top,
+                width - padding.right, height - padding.bottom);
+
+        final int d = Math.max(width, height);
+        final Bitmap b = Bitmap.createBitmap(d, d, Bitmap.Config.ARGB_8888);
+        final Canvas c = new Canvas(b);
+
+        c.translate((d - width) / 2.0f, (d - height) / 2.0f);
+        frame.draw(c);
+        c.drawBitmap(photo, source, destination, new Paint(Paint.FILTER_BITMAP_FLAG));
+
+        return b;
+    }
+
     /**
      * 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.
@@ -1609,6 +1647,7 @@
     private Bitmap loadContactPhoto(long contactId, BitmapFactory.Options options) {
         Cursor cursor = null;
         Bitmap bm = null;
+
         try {
             Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
             Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
@@ -1622,12 +1661,23 @@
                 cursor.close();
             }
         }
+
+        if (bm == null) {
+            final int[] fallbacks = {
+                R.drawable.ic_contact_picture,
+                R.drawable.ic_contact_picture_2,
+                R.drawable.ic_contact_picture_3
+            };
+            bm = BitmapFactory.decodeResource(getResources(),
+                    fallbacks[new Random().nextInt(fallbacks.length)]);
+        }
+
         return bm;
     }
 
     /**
-     * Return the selection arguments for a default query based on
-     * {@link #mDisplayAll} and {@link #mDisplayOnlyPhones} flags.
+     * Return the selection arguments for a default query based on the
+     * {@link #mDisplayOnlyPhones} flag.
      */
     private String getContactSelection() {
         if (mDisplayOnlyPhones) {
@@ -2191,7 +2241,7 @@
                     return;
                 }
 
-                if (Thread.currentThread().interrupted()) {
+                if (Thread.interrupted()) {
                     // shutdown has been called.
                     return;
                 }
@@ -2208,7 +2258,7 @@
 
                 mBitmapCache.put(mPhotoId, new SoftReference<Bitmap>(photo));
 
-                if (Thread.currentThread().interrupted()) {
+                if (Thread.interrupted()) {
                     // shutdown has been called.
                     return;
                 }
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java
index d892def..547cd45 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/RecentCallsListActivity.java
@@ -235,6 +235,15 @@
             mLabelArray = getResources().getTextArray(com.android.internal.R.array.phoneTypes);
         }
 
+        /**
+         * Requery on background thread when {@link Cursor} changes.
+         */
+        @Override
+        protected void onContentChanged() {
+            // Start async requery
+            startQuery();
+        }
+
         void setLoading(boolean loading) {
             mLoading = loading;
         }
diff --git a/src/com/android/contacts/ui/QuickContactActivity.java b/src/com/android/contacts/ui/QuickContactActivity.java
index d17e3be..b5e445f 100644
--- a/src/com/android/contacts/ui/QuickContactActivity.java
+++ b/src/com/android/contacts/ui/QuickContactActivity.java
@@ -65,13 +65,30 @@
         final Bundle extras = intent.getExtras();
 
         // Read requested parameters for displaying
-        final Rect target = (Rect)extras.getParcelable(QuickContact.EXTRA_TARGET_RECT);
+        final Rect target = getTargetRect(intent);
         final int mode = extras.getInt(QuickContact.EXTRA_MODE, QuickContact.MODE_MEDIUM);
         final String[] excludeMimes = extras.getStringArray(QuickContact.EXTRA_EXCLUDE_MIMES);
 
         mQuickContact.show(lookupUri, target, mode, excludeMimes);
     }
 
+    private Rect getTargetRect(Intent intent) {
+        Rect target = intent.getSourceBounds();
+        if (target != null) {
+            return target;
+        }
+        final Bundle extras = intent.getExtras();
+        try {
+            target = (Rect)extras.getParcelable(QuickContact.EXTRA_TARGET_RECT);
+            if (target != null) {
+                return target;
+            }
+        } catch (ClassCastException ex) {
+            // fall through
+        }
+        return new Rect(0, 0, 0, 0);
+    }
+
     /** {@inheritDoc} */
     @Override
     public void onBackPressed() {
diff --git a/src/com/android/contacts/ui/QuickContactWindow.java b/src/com/android/contacts/ui/QuickContactWindow.java
index e787987..132b18c 100644
--- a/src/com/android/contacts/ui/QuickContactWindow.java
+++ b/src/com/android/contacts/ui/QuickContactWindow.java
@@ -28,7 +28,6 @@
 import com.android.internal.policy.PolicyManager;
 import com.google.android.collect.Sets;
 
-import android.app.Activity;
 import android.content.ActivityNotFoundException;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -56,7 +55,6 @@
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.text.TextUtils;
-import android.text.format.DateUtils;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
@@ -192,13 +190,12 @@
      * the user has not selected a default app yet, and they will still be
      * presented with the system disambiguation dialog.
      */
-    private static final HashSet<String> sPreferResolve = Sets.newHashSet(new String[] {
+    private static final HashSet<String> sPreferResolve = Sets.newHashSet(
             "com.android.email",
             "com.android.calendar",
             "com.android.contacts",
             "com.android.mms",
-            "com.android.phone",
-    });
+            "com.android.phone");
 
     private static final int TOKEN_DATA = 1;
 
@@ -285,7 +282,7 @@
             // Inflate actual header if we picked a stub
             final ViewStub stub = (ViewStub)header;
             header = stub.inflate();
-        } else {
+        } else if (header != null) {
             header.setVisibility(View.VISIBLE);
         }
 
@@ -579,11 +576,6 @@
     }
 
     /** Assign this image to the view, if found in {@link #mHeader}. */
-    private void setHeaderImage(int id, int resId) {
-        setHeaderImage(id, mContext.getResources().getDrawable(resId));
-    }
-
-    /** Assign this image to the view, if found in {@link #mHeader}. */
     private void setHeaderImage(int id, Drawable drawable) {
         final View view = mHeader.findViewById(id);
         if (view instanceof ImageView) {
@@ -620,7 +612,7 @@
      * Find the QuickContact-specific presence icon for showing in chiclets.
      */
     private Drawable getTrackPresenceIcon(int status) {
-        int resId = -1;
+        int resId;
         switch (status) {
             case StatusUpdates.AVAILABLE:
                 resId = R.drawable.quickcontact_slider_presence_active;
@@ -902,7 +894,6 @@
      * queries, keyed internally on MIME-type.
      */
     private static class ResolveCache {
-        private Context mContext;
         private PackageManager mPackageManager;
 
         /**
@@ -917,7 +908,6 @@
         private HashMap<String, Entry> mCache = new HashMap<String, Entry>();
 
         public ResolveCache(Context context) {
-            mContext = context;
             mPackageManager = context.getPackageManager();
         }
 
@@ -1092,7 +1082,6 @@
         while (cursor.moveToNext()) {
             final long dataId = cursor.getLong(DataQuery._ID);
             final String accountType = cursor.getString(DataQuery.ACCOUNT_TYPE);
-            final String resPackage = cursor.getString(DataQuery.RES_PACKAGE);
             final String mimeType = cursor.getString(DataQuery.MIMETYPE);
 
             // Handle any social status updates from this row
@@ -1353,7 +1342,6 @@
 
                     // Set action title based on summary value
                     final Action action = (Action)getItem(position);
-                    final Drawable icon = mResolveCache.getIcon(action);
 
                     TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
                     TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);