Merge "Move blue fab out of Dialer" into lmp-dev
diff --git a/src/com/android/dialer/SpecialCharSequenceMgr.java b/src/com/android/dialer/SpecialCharSequenceMgr.java
index 0b6e881..37c0383 100644
--- a/src/com/android/dialer/SpecialCharSequenceMgr.java
+++ b/src/com/android/dialer/SpecialCharSequenceMgr.java
@@ -36,6 +36,7 @@
 import android.widget.EditText;
 import android.widget.Toast;
 
+import com.android.common.io.MoreCloseables;
 import com.android.contacts.common.database.NoNullCursorAsyncQueryHandler;
 
 /**
@@ -377,34 +378,38 @@
          */
         @Override
         protected void onNotNullableQueryComplete(int token, Object cookie, Cursor c) {
-            sPreviousAdnQueryHandler = null;
-            if (mCanceled) {
-                return;
-            }
+            try {
+                sPreviousAdnQueryHandler = null;
+                if (mCanceled) {
+                    return;
+                }
 
-            SimContactQueryCookie sc = (SimContactQueryCookie) cookie;
+                SimContactQueryCookie sc = (SimContactQueryCookie) cookie;
 
-            // close the progress dialog.
-            sc.progressDialog.dismiss();
+                // close the progress dialog.
+                sc.progressDialog.dismiss();
 
-            // get the EditText to update or see if the request was cancelled.
-            EditText text = sc.getTextField();
+                // get the EditText to update or see if the request was cancelled.
+                EditText text = sc.getTextField();
 
-            // if the textview is valid, and the cursor is valid and postionable
-            // on the Nth number, then we update the text field and display a
-            // toast indicating the caller name.
-            if ((c != null) && (text != null) && (c.moveToPosition(sc.contactNum))) {
-                String name = c.getString(c.getColumnIndexOrThrow(ADN_NAME_COLUMN_NAME));
-                String number = c.getString(c.getColumnIndexOrThrow(ADN_PHONE_NUMBER_COLUMN_NAME));
+                // if the textview is valid, and the cursor is valid and postionable
+                // on the Nth number, then we update the text field and display a
+                // toast indicating the caller name.
+                if ((c != null) && (text != null) && (c.moveToPosition(sc.contactNum))) {
+                    String name = c.getString(c.getColumnIndexOrThrow(ADN_NAME_COLUMN_NAME));
+                    String number = c.getString(c.getColumnIndexOrThrow(ADN_PHONE_NUMBER_COLUMN_NAME));
 
-                // fill the text in.
-                text.getText().replace(0, 0, number);
+                    // fill the text in.
+                    text.getText().replace(0, 0, number);
 
-                // display the name as a toast
-                Context context = sc.progressDialog.getContext();
-                name = context.getString(R.string.menu_callNumber, name);
-                Toast.makeText(context, name, Toast.LENGTH_SHORT)
-                    .show();
+                    // display the name as a toast
+                    Context context = sc.progressDialog.getContext();
+                    name = context.getString(R.string.menu_callNumber, name);
+                    Toast.makeText(context, name, Toast.LENGTH_SHORT)
+                        .show();
+                }
+            } finally {
+                MoreCloseables.closeQuietly(c);
             }
         }
 
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 921a1c4..a90fc55 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -1299,10 +1299,13 @@
                         Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
                         PhoneQuery._PROJECTION, null, null, null);
                 if (phonesCursor != null) {
-                    if (phonesCursor.moveToFirst()) {
-                        matchingNumber = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER);
+                    try {
+                        if (phonesCursor.moveToFirst()) {
+                            matchingNumber = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER);
+                        }
+                    } finally {
+                        phonesCursor.close();
                     }
-                    phonesCursor.close();
                 }
             } catch (Exception e) {
                 // Use the number from the call log
diff --git a/src/com/android/dialer/database/DialerDatabaseHelper.java b/src/com/android/dialer/database/DialerDatabaseHelper.java
index 95249a6..511c2a7 100644
--- a/src/com/android/dialer/database/DialerDatabaseHelper.java
+++ b/src/com/android/dialer/database/DialerDatabaseHelper.java
@@ -441,17 +441,19 @@
 
     public String getProperty(SQLiteDatabase db, String key, String defaultValue) {
         try {
+            String value = null;
             final Cursor cursor = db.query(Tables.PROPERTIES,
                     new String[] {PropertiesColumns.PROPERTY_VALUE},
                             PropertiesColumns.PROPERTY_KEY + "=?",
                     new String[] {key}, null, null, null);
-            String value = null;
-            try {
-                if (cursor.moveToFirst()) {
-                    value = cursor.getString(0);
+            if (cursor != null) {
+                try {
+                    if (cursor.moveToFirst()) {
+                        value = cursor.getString(0);
+                    }
+                } finally {
+                    cursor.close();
                 }
-            } finally {
-                cursor.close();
             }
             return value != null ? value : defaultValue;
         } catch (SQLiteException e) {
@@ -770,14 +772,6 @@
             final Cursor updatedContactCursor = mContext.getContentResolver().query(PhoneQuery.URI,
                     PhoneQuery.PROJECTION, PhoneQuery.SELECTION,
                     new String[]{lastUpdateMillis}, null);
-
-            /** Sets the time after querying the database as the current update time. */
-            final Long currentMillis = System.currentTimeMillis();
-
-            if (DEBUG) {
-                stopWatch.lap("Queried the Contacts database");
-            }
-
             if (updatedContactCursor == null) {
                 if (DEBUG) {
                     Log.e(TAG, "SmartDial query received null for cursor");
@@ -785,18 +779,25 @@
                 return;
             }
 
-            /** Prevents the app from reading the dialer database when updating. */
-            sInUpdate.getAndSet(true);
-
-            /** Removes contacts that have been deleted. */
-            removeDeletedContacts(db, lastUpdateMillis);
-            removePotentiallyCorruptedContacts(db, lastUpdateMillis);
-
-            if (DEBUG) {
-                stopWatch.lap("Finished deleting deleted entries");
-            }
+            /** Sets the time after querying the database as the current update time. */
+            final Long currentMillis = System.currentTimeMillis();
 
             try {
+                if (DEBUG) {
+                    stopWatch.lap("Queried the Contacts database");
+                }
+
+                /** Prevents the app from reading the dialer database when updating. */
+                sInUpdate.getAndSet(true);
+
+                /** Removes contacts that have been deleted. */
+                removeDeletedContacts(db, lastUpdateMillis);
+                removePotentiallyCorruptedContacts(db, lastUpdateMillis);
+
+                if (DEBUG) {
+                    stopWatch.lap("Finished deleting deleted entries");
+                }
+
                 /** If the database did not exist before, jump through deletion as there is nothing
                  * to delete.
                  */
@@ -830,12 +831,12 @@
                     " WHERE " + SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME +
                     " = " + Long.toString(currentMillis),
                     new String[] {});
-            if (DEBUG) {
-                stopWatch.lap("Queried the smart dial table for contact names");
-            }
-
             if (nameCursor != null) {
                 try {
+                    if (DEBUG) {
+                        stopWatch.lap("Queried the smart dial table for contact names");
+                    }
+
                     /** Inserts prefixes of names into the prefix table.*/
                     insertNamePrefixes(db, nameCursor);
                     if (DEBUG) {
@@ -936,26 +937,28 @@
                     " LIKE '" + looseQuery + "')" +
                 " ORDER BY " + SmartDialSortingOrder.SORT_ORDER,
                 new String[] {currentTimeStamp});
-
-        if (DEBUG) {
-            stopWatch.lap("Prefix query completed");
+        if (cursor == null) {
+            return result;
         }
-
-        /** Gets the column ID from the cursor.*/
-        final int columnDataId = 0;
-        final int columnDisplayNamePrimary = 1;
-        final int columnPhotoId = 2;
-        final int columnNumber = 3;
-        final int columnId = 4;
-        final int columnLookupKey = 5;
-        if (DEBUG) {
-            stopWatch.lap("Found column IDs");
-        }
-
-        final Set<ContactMatch> duplicates = new HashSet<ContactMatch>();
-        int counter = 0;
         try {
             if (DEBUG) {
+                stopWatch.lap("Prefix query completed");
+            }
+
+            /** Gets the column ID from the cursor.*/
+            final int columnDataId = 0;
+            final int columnDisplayNamePrimary = 1;
+            final int columnPhotoId = 2;
+            final int columnNumber = 3;
+            final int columnId = 4;
+            final int columnLookupKey = 5;
+            if (DEBUG) {
+                stopWatch.lap("Found column IDs");
+            }
+
+            final Set<ContactMatch> duplicates = new HashSet<ContactMatch>();
+            int counter = 0;
+            if (DEBUG) {
                 stopWatch.lap("Moved cursor to start");
             }
             /** Iterates the cursor to find top contact suggestions without duplication.*/
diff --git a/src/com/android/dialer/interactions/PhoneNumberInteraction.java b/src/com/android/dialer/interactions/PhoneNumberInteraction.java
index dc35b06..b61a496 100644
--- a/src/com/android/dialer/interactions/PhoneNumberInteraction.java
+++ b/src/com/android/dialer/interactions/PhoneNumberInteraction.java
@@ -380,13 +380,17 @@
 
     @Override
     public void onLoadComplete(Loader<Cursor> loader, Cursor cursor) {
-        if (cursor == null || !isSafeToCommitTransactions()) {
+        if (cursor == null) {
             onDismiss();
             return;
         }
-        ArrayList<PhoneItem> phoneList = new ArrayList<PhoneItem>();
-        String primaryPhone = null;
         try {
+            ArrayList<PhoneItem> phoneList = new ArrayList<PhoneItem>();
+            String primaryPhone = null;
+            if (!isSafeToCommitTransactions()) {
+                onDismiss();
+                return;
+            }
             while (cursor.moveToNext()) {
                 if (mContactId == UNKNOWN_CONTACT_ID) {
                     mContactId = cursor.getLong(CONTACT_ID);
@@ -408,28 +412,27 @@
 
                 phoneList.add(item);
             }
+
+            if (mUseDefault && primaryPhone != null) {
+                performAction(primaryPhone);
+                onDismiss();
+                return;
+            }
+
+            Collapser.collapseList(phoneList, mContext);
+            if (phoneList.size() == 0) {
+                onDismiss();
+            } else if (phoneList.size() == 1) {
+                PhoneItem item = phoneList.get(0);
+                onDismiss();
+                performAction(item.phoneNumber);
+            } else {
+                // There are multiple candidates. Let the user choose one.
+                showDisambiguationDialog(phoneList);
+            }
         } finally {
             cursor.close();
         }
-
-        if (mUseDefault && primaryPhone != null) {
-            performAction(primaryPhone);
-            onDismiss();
-            return;
-        }
-
-        Collapser.collapseList(phoneList, mContext);
-
-        if (phoneList.size() == 0) {
-            onDismiss();
-        } else if (phoneList.size() == 1) {
-            PhoneItem item = phoneList.get(0);
-            onDismiss();
-            performAction(item.phoneNumber);
-        } else {
-            // There are multiple candidates. Let the user choose one.
-            showDisambiguationDialog(phoneList);
-        }
     }
 
     private boolean isSafeToCommitTransactions() {
diff --git a/src/com/android/dialer/list/ListsFragment.java b/src/com/android/dialer/list/ListsFragment.java
index ed95dc2..5246b55 100644
--- a/src/com/android/dialer/list/ListsFragment.java
+++ b/src/com/android/dialer/list/ListsFragment.java
@@ -111,12 +111,11 @@
     private PanelSlideListener mPanelSlideListener = new PanelSlideListener() {
         @Override
         public void onPanelSlide(View panel, float slideOffset) {
-            // For every 1 percent that the panel is slid upwards, clip 1.5 percent from each edge
-            // of the shortcut card, to achieve the animated effect of the shortcut card
-            // rapidly shrinking and disappearing from view when the panel is slid upwards.
-            // slideOffset is 1 when the shortcut card is fully exposed, and 0 when completely
-            // hidden.
-            float ratioCardHidden = (1 - slideOffset) * 1.5f;
+            // For every 1 percent that the panel is slid upwards, clip 1 percent off the top
+            // edge of the shortcut card, to achieve the animated effect of the shortcut card
+            // being pushed out of view when the panel is slid upwards. slideOffset is 1 when
+            // the shortcut card is fully exposed, and 0 when completely hidden.
+            float ratioCardHidden = (1 - slideOffset);
             if (mShortcutCardsListView.getChildCount() > 0) {
                 final SwipeableShortcutCard v =
                         (SwipeableShortcutCard) mShortcutCardsListView.getChildAt(0);
diff --git a/src/com/android/dialer/list/ShortcutCardsAdapter.java b/src/com/android/dialer/list/ShortcutCardsAdapter.java
index 4bd914f..d1ffa79 100644
--- a/src/com/android/dialer/list/ShortcutCardsAdapter.java
+++ b/src/com/android/dialer/list/ShortcutCardsAdapter.java
@@ -52,6 +52,10 @@
     }
 
     private static final String TAG = ShortcutCardsAdapter.class.getSimpleName();
+    private static final float CLIP_CARD_BARELY_HIDDEN_RATIO = 0.001f;
+    private static final float CLIP_CARD_MOSTLY_HIDDEN_RATIO = 0.9f;
+    // Fade out 5x faster than the hidden ratio.
+    private static final float CLIP_CARD_OPACITY_RATIO = 5f;
 
     private final CallLogAdapter mCallLogAdapter;
 
@@ -339,34 +343,31 @@
             int width = viewToClip.getWidth();
             int height = viewToClip.getHeight();
 
-            if (ratioHidden <= 0.001f) {
+            if (ratioHidden <= CLIP_CARD_BARELY_HIDDEN_RATIO) {
                 viewToClip.setTranslationZ(mPreviousTranslationZ);
             } else if (viewToClip.getTranslationZ() != 0){
                 mPreviousTranslationZ = viewToClip.getTranslationZ();
                 viewToClip.setTranslationZ(0);
             }
 
-            if (ratioHidden > 0.5f) {
+            if (ratioHidden > CLIP_CARD_MOSTLY_HIDDEN_RATIO) {
                 mClipRect.set(0, 0 , 0, 0);
                 setVisibility(View.INVISIBLE);
             } else {
                 setVisibility(View.VISIBLE);
-                int newLeft = (int) (ratioHidden * mCardMaxHorizontalClip);
-                int newRight = width - newLeft;
                 int newTop = (int) (ratioHidden * height);
-                int newBottom = (height - newTop);
-                mClipRect.set(newLeft, newTop, newRight, newBottom);
+                mClipRect.set(0, newTop, width, height);
 
                 // Since the pane will be overlapping with the action bar, apply a vertical offset
-                // to visually center the clipped card in the viewable area;
-                int verticalOffset = -newTop / 2;
-                viewToClip.setTranslationY(verticalOffset);
+                // to top align the clipped card in the viewable area;
+                viewToClip.setTranslationY(-newTop);
             }
             viewToClip.setClipBounds(mClipRect);
 
             // If the view has any children, fade them out of view.
             final ViewGroup viewGroup = (ViewGroup) viewToClip;
-            setChildrenOpacity(viewGroup, Math.max(0, 1 - 4.5f * ratioHidden));
+            setChildrenOpacity(
+                    viewGroup, Math.max(0, 1 - (CLIP_CARD_OPACITY_RATIO  * ratioHidden)));
         }
 
         private void setChildrenOpacity(ViewGroup viewGroup, float alpha) {