Merge "Improve Contacts' permission handling" into mnc-dev
diff --git a/src/com/android/contacts/common/list/ContactEntryListFragment.java b/src/com/android/contacts/common/list/ContactEntryListFragment.java
index 8689874..8d1cede 100644
--- a/src/com/android/contacts/common/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/common/list/ContactEntryListFragment.java
@@ -31,6 +31,7 @@
 import android.os.Parcelable;
 import android.provider.ContactsContract.Directory;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -346,7 +347,19 @@
     }
 
     public CursorLoader createCursorLoader(Context context) {
-        return new CursorLoader(context, null, null, null, null, null);
+        return new CursorLoader(context, null, null, null, null, null) {
+            @Override
+            protected Cursor onLoadInBackground() {
+                try {
+                    return super.onLoadInBackground();
+                } catch (RuntimeException e) {
+                    // We don't even know what the projection should be, so no point trying to
+                    // return an empty MatrixCursor with the correct projection here.
+                    Log.w(TAG, "RuntimeException while trying to query ContactsProvider.");
+                    return null;
+                }
+            }
+        };
     }
 
     private void startLoadingDirectoryPartition(int partitionIndex) {
diff --git a/src/com/android/contacts/common/list/DirectoryListLoader.java b/src/com/android/contacts/common/list/DirectoryListLoader.java
index dedd62e..b327361 100644
--- a/src/com/android/contacts/common/list/DirectoryListLoader.java
+++ b/src/com/android/contacts/common/list/DirectoryListLoader.java
@@ -144,13 +144,15 @@
                 throw new RuntimeException(
                         "Unsupported directory search mode: " + mDirectorySearchMode);
         }
-
-        Cursor cursor = context.getContentResolver().query(DirectoryQuery.URI,
-                DirectoryQuery.PROJECTION, selection, null, DirectoryQuery.ORDER_BY);
-        if (cursor == null) {
-            return result;
-        }
+        Cursor cursor = null;
         try {
+            cursor = context.getContentResolver().query(DirectoryQuery.URI,
+                    DirectoryQuery.PROJECTION, selection, null, DirectoryQuery.ORDER_BY);
+
+            if (cursor == null) {
+                return result;
+            }
+
             while(cursor.moveToNext()) {
                 long directoryId = cursor.getLong(DirectoryQuery.ID);
                 String directoryType = null;
@@ -169,8 +171,12 @@
                 int photoSupport = cursor.getInt(DirectoryQuery.PHOTO_SUPPORT);
                 result.addRow(new Object[]{directoryId, directoryType, displayName, photoSupport});
             }
+        } catch (RuntimeException e) {
+            Log.w(TAG, "Runtime Exception when querying directory");
         } finally {
-            cursor.close();
+            if (cursor != null) {
+                cursor.close();
+            }
         }
 
         return result;
diff --git a/src/com/android/contacts/common/list/ShortcutIntentBuilder.java b/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
index cc306f1..9e6b5e9 100644
--- a/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
+++ b/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
@@ -316,7 +316,7 @@
         } else {
             phoneUri = Uri.fromParts(ContactsUtils.SCHEME_SMSTO, phoneNumber, null);
             bitmap = generatePhoneNumberIcon(drawable, phoneType, phoneLabel,
-                    R.drawable.ic_textsms_24dp);
+                    R.drawable.ic_message_24dp);
         }
 
         Intent shortcutIntent = new Intent(shortcutAction, phoneUri);
diff --git a/src/com/android/contacts/common/model/account/BaseAccountType.java b/src/com/android/contacts/common/model/account/BaseAccountType.java
index c176a87..262a939 100644
--- a/src/com/android/contacts/common/model/account/BaseAccountType.java
+++ b/src/com/android/contacts/common/model/account/BaseAccountType.java
@@ -256,7 +256,7 @@
     protected DataKind addDataKindPhone(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(Phone.CONTENT_ITEM_TYPE, R.string.phoneLabelsGroup,
                 Weight.PHONE, true));
-        kind.iconAltRes = R.drawable.ic_text_holo_light;
+        kind.iconAltRes = R.drawable.ic_message_24dp;
         kind.iconAltDescriptionRes = R.string.sms;
         kind.actionHeader = new PhoneActionInflater();
         kind.actionAltHeader = new PhoneActionAltInflater();
@@ -1044,7 +1044,7 @@
                     Phone.CONTENT_ITEM_TYPE, Phone.TYPE, R.string.phoneLabelsGroup, Weight.PHONE,
                     new PhoneActionInflater(), new SimpleInflater(Phone.NUMBER));
 
-            kind.iconAltRes = R.drawable.ic_text_holo_light;
+            kind.iconAltRes = R.drawable.ic_message_24dp;
             kind.iconAltDescriptionRes = R.string.sms;
             kind.actionAltHeader = new PhoneActionAltInflater();
 
diff --git a/src/com/android/contacts/common/widget/FloatingActionButtonController.java b/src/com/android/contacts/common/widget/FloatingActionButtonController.java
index 1cfb89c..31f44af 100644
--- a/src/com/android/contacts/common/widget/FloatingActionButtonController.java
+++ b/src/com/android/contacts/common/widget/FloatingActionButtonController.java
@@ -82,6 +82,10 @@
         mFloatingActionButtonContainer.setVisibility(visible ? View.VISIBLE : View.GONE);
     }
 
+    private boolean isVisible() {
+        return mFloatingActionButtonContainer.getVisibility() == View.VISIBLE;
+    }
+
     public void changeIcon(Drawable icon, String description) {
         if (mFloatingActionButton.getDrawable() != icon
                 || !mFloatingActionButton.getContentDescription().equals(description)) {
@@ -104,10 +108,21 @@
     }
 
     /**
+     * Aligns the FAB to the described location
+     *
+     * @param align One of ALIGN_MIDDLE, ALIGN_QUARTER_RIGHT, or ALIGN_RIGHT.
+     * @param animate Whether or not to animate the transition.
+     */
+    public void align(int align, boolean animate) {
+        align(align, 0 /*offsetX */, 0 /* offsetY */, animate);
+    }
+
+    /**
      * Aligns the FAB to the described location plus specified additional offsets.
      *
      * @param align One of ALIGN_MIDDLE, ALIGN_QUARTER_RIGHT, or ALIGN_RIGHT.
      * @param offsetX Additional offsetX to translate by.
+     * @param offsetY Additional offsetY to translate by.
      * @param animate Whether or not to animate the transition.
      */
     public void align(int align, int offsetX, int offsetY, boolean animate) {
@@ -152,6 +167,12 @@
      * @param delayMs The delay for the effect, in milliseconds.
      */
     public void scaleIn(int delayMs) {
+        if (isVisible()) {
+            mFloatingActionButtonContainer.setScaleX(1);
+            mFloatingActionButtonContainer.setScaleY(1);
+            return;
+        }
+
         setVisible(true);
         AnimUtils.scaleIn(mFloatingActionButtonContainer, FAB_SCALE_IN_DURATION, delayMs);
         AnimUtils.fadeIn(mFloatingActionButton, FAB_SCALE_IN_DURATION,