Merge "Refactorings to make code easier to navigate"
diff --git a/res/layout/status_bar_ongoing_event_progress_bar.xml b/res/layout/status_bar_ongoing_event_progress_bar.xml
index 3c7530a..e3edf95 100644
--- a/res/layout/status_bar_ongoing_event_progress_bar.xml
+++ b/res/layout/status_bar_ongoing_event_progress_bar.xml
@@ -69,7 +69,7 @@
                 <TextView android:id="@+id/status_description"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:textColor="#ff000000"
+                    android:textColor="?android:attr/textColorPrimary"
                     android:singleLine="true"
                     android:textSize="18sp"
                     android:paddingLeft="5dp" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7437427..e993a18 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -850,7 +850,7 @@
          mention it here. -->
     <string name="fail_reason_too_long_filename">Required filename is too long (\"<xliff:g id="filename">%s</xliff:g>\")</string>
 
-    <!-- The title shown when reading vCard is canceled (probably by a user) -->
+    <!-- The title shown when exporting vCard is successfuly finished [CHAR LIMIT=40] -->
     <string name="exporting_vcard_finished_title">Finished exporting vCard</string>
 
     <!-- Dialog title shown when the application is exporting contact data outside -->
diff --git a/src/com/android/contacts/vcard/ExportProcessor.java b/src/com/android/contacts/vcard/ExportProcessor.java
index 4634b40..5e0a19d 100644
--- a/src/com/android/contacts/vcard/ExportProcessor.java
+++ b/src/com/android/contacts/vcard/ExportProcessor.java
@@ -30,6 +30,7 @@
 import android.net.Uri;
 import android.text.TextUtils;
 import android.util.Log;
+import android.widget.RemoteViews;
 
 import java.io.FileNotFoundException;
 import java.io.OutputStream;
@@ -148,13 +149,19 @@
                     doFinishNotification(title, "");
                     return;
                 }
-                doProgressNotification(uri, total, current);
+
+                // vCard export is quite fast (compared to import), and frequent notifications
+                // bother notification bar too much.
+                if (current % 100 == 1) {
+                    doProgressNotification(uri, total, current);
+                }
                 current++;
             }
             Log.i(LOG_TAG, "Successfully finished exporting vCard " + request.destUri);
 
             successful = true;
-            // TODO: Show "successful"
+            final String title = mService.getString(R.string.exporting_vcard_finished_title);
+            doFinishNotification(title, "");
         } finally {
             if (composer != null) {
                 composer.terminate();
@@ -179,13 +186,13 @@
 
     private void doProgressNotification(Uri uri, int total, int current) {
         final String title = mService.getString(R.string.exporting_contact_list_title);
+        final String filename = uri.getLastPathSegment();
         final String description =
-                mService.getString(R.string.exporting_contact_list_message, uri);
+                mService.getString(R.string.exporting_contact_list_message, filename);
 
-        /* TODO: we should show more informative Notification to users.
         final RemoteViews remoteViews = new RemoteViews(mService.getPackageName(),
                 R.layout.status_bar_ongoing_event_progress_bar);
-        remoteViews.setTextViewText(R.id.status_description, message);
+        remoteViews.setTextViewText(R.id.status_description, description);
         remoteViews.setProgressBar(R.id.status_progress_bar, total, current, (total == -1));
 
         final String percentage = mService.getString(R.string.percentage,
@@ -200,21 +207,8 @@
         notification.contentView = remoteViews;
         notification.contentIntent =
                 PendingIntent.getActivity(mService, 0,
-                        new Intent(mService, ContactBrowserActivity.class), 0);*/
+                        new Intent(mService, ContactBrowserActivity.class), 0);
 
-        final long when = System.currentTimeMillis();
-        final Notification notification = new Notification(
-                android.R.drawable.stat_sys_upload,
-                description,
-                when);
-
-        final Context context = mService.getApplicationContext();
-        final PendingIntent pendingIntent =
-                PendingIntent.getActivity(context, 0,
-                        new Intent(context, ContactBrowserActivity.class),
-                        PendingIntent.FLAG_UPDATE_CURRENT);
-
-        notification.setLatestEventInfo(context, title, description, pendingIntent);
         mNotificationManager.notify(VCardService.EXPORT_NOTIFICATION_ID, notification);
     }
 
diff --git a/src/com/android/contacts/vcard/ImportProcessor.java b/src/com/android/contacts/vcard/ImportProcessor.java
index ca7223d..acb6792 100644
--- a/src/com/android/contacts/vcard/ImportProcessor.java
+++ b/src/com/android/contacts/vcard/ImportProcessor.java
@@ -115,6 +115,8 @@
         final Account account = request.account;
         final int estimatedVCardType = request.estimatedVCardType;
         final String estimatedCharset = request.estimatedCharset;
+        final int entryCount = request.entryCount;
+        mNotifier.addTotalCount(entryCount);
 
         final VCardEntryConstructor constructor =
                 new VCardEntryConstructor(estimatedVCardType, account, estimatedCharset);
diff --git a/src/com/android/contacts/vcard/ImportProgressNotifier.java b/src/com/android/contacts/vcard/ImportProgressNotifier.java
index 99a6f55..6a24bc0 100644
--- a/src/com/android/contacts/vcard/ImportProgressNotifier.java
+++ b/src/com/android/contacts/vcard/ImportProgressNotifier.java
@@ -15,6 +15,10 @@
  */
 package com.android.contacts.vcard;
 
+import com.android.contacts.R;
+import com.android.vcard.VCardEntry;
+import com.android.vcard.VCardEntryHandler;
+
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -22,15 +26,13 @@
 import android.content.Intent;
 import android.widget.RemoteViews;
 
-import com.android.contacts.R;
-import com.android.vcard.VCardEntry;
-import com.android.vcard.VCardEntryHandler;
-
 /**
  * {@link VCardEntryHandler} implementation which lets the system update
  * the current status of vCard import.
  */
 public class ImportProgressNotifier implements VCardEntryHandler {
+    private static final String LOG_TAG = "VCardImport";
+
     private Context mContext;
     private NotificationManager mNotificationManager;
 
@@ -51,7 +53,7 @@
             return;
         }
 
-        // We don't use startEntry() since:
+        // We don't use onStart() since:
         // - We cannot know name there but here.
         // - There's high probability where name comes soon after the beginning of entry, so
         //   we don't need to hurry to show something.
diff --git a/src/com/android/contacts/widget/InterpolatingLayout.java b/src/com/android/contacts/widget/InterpolatingLayout.java
index 012e5a2..5900bf1 100644
--- a/src/com/android/contacts/widget/InterpolatingLayout.java
+++ b/src/com/android/contacts/widget/InterpolatingLayout.java
@@ -20,9 +20,12 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.LinearLayout;
 
 /**
  * Layout similar to LinearLayout that allows a child to specify examples of
@@ -35,6 +38,9 @@
  */
 public class InterpolatingLayout extends ViewGroup {
 
+    private Rect mInRect = new Rect();
+    private Rect mOutRect = new Rect();
+
     public InterpolatingLayout(Context context) {
         super(context);
     }
@@ -47,7 +53,7 @@
         super(context, attrs, defStyle);
     }
 
-    public final static class LayoutParams extends ViewGroup.MarginLayoutParams {
+    public final static class LayoutParams extends LinearLayout.LayoutParams {
 
         public int narrowParentWidth;
         public int narrowWidth;
@@ -156,8 +162,8 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int mode = MeasureSpec.getMode(widthMeasureSpec);
-        int parentSize = MeasureSpec.getSize(widthMeasureSpec);
+        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
+        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
 
         int width = 0;
         int height = 0;
@@ -171,7 +177,6 @@
             }
 
             LayoutParams params = (LayoutParams) child.getLayoutParams();
-
             if (params.width == LayoutParams.MATCH_PARENT) {
                 if (fillChild != null) {
                     throw new RuntimeException(
@@ -180,20 +185,43 @@
                 }
                 fillChild = child;
             } else {
-                int childWidth = params.resolveWidth(parentSize);
-                int childMeasureSpec = (childWidth == LayoutParams.WRAP_CONTENT)
-                        ? MeasureSpec.UNSPECIFIED
-                        : MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
-                child.measure(childMeasureSpec, heightMeasureSpec);
+                int childWidth = params.resolveWidth(parentWidth);
+                int childWidthMeasureSpec;
+                switch (childWidth) {
+                    case LayoutParams.WRAP_CONTENT:
+                        childWidthMeasureSpec = MeasureSpec.UNSPECIFIED;
+                        break;
+                    default:
+                        childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                                childWidth, MeasureSpec.EXACTLY);
+                        break;
+                }
+
+                int childHeightMeasureSpec;
+                switch (params.height) {
+                    case LayoutParams.WRAP_CONTENT:
+                        childHeightMeasureSpec = MeasureSpec.UNSPECIFIED;
+                        break;
+                    case LayoutParams.MATCH_PARENT:
+                        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                                parentHeight, MeasureSpec.EXACTLY);
+                        break;
+                    default:
+                        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                                params.height, MeasureSpec.EXACTLY);
+                        break;
+                }
+
+                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
                 width += child.getMeasuredWidth();
                 height = Math.max(child.getMeasuredHeight(), height);
             }
 
-            width += params.resolveLeftMargin(parentSize) + params.resolveRightMargin(parentSize);
+            width += params.resolveLeftMargin(parentWidth) + params.resolveRightMargin(parentWidth);
         }
 
         if (fillChild != null) {
-            int remainder = parentSize - width;
+            int remainder = parentWidth - width;
             int childMeasureSpec = remainder > 0
                     ? MeasureSpec.makeMeasureSpec(remainder, MeasureSpec.EXACTLY)
                     : MeasureSpec.UNSPECIFIED;
@@ -210,18 +238,28 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         int offset = 0;
         int width = right - left;
-        int height = bottom - top;
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
             View child = getChildAt(i);
 
             LayoutParams params = (LayoutParams) child.getLayoutParams();
-            offset += params.resolveLeftMargin(width);
-            int childWidth = child.getMeasuredWidth();
-            int childTop = params.topMargin;
-            child.layout(offset, params.topMargin, offset + childWidth,
-                    params.topMargin + child.getMeasuredHeight());
-            offset += childWidth + params.resolveRightMargin(width);
+            int gravity = params.gravity;
+            if (gravity == -1) {
+                gravity = Gravity.LEFT | Gravity.TOP;
+            }
+
+            int leftMargin = params.resolveLeftMargin(width);
+            int rightMargin = params.resolveRightMargin(width);
+
+            mInRect.set(offset + leftMargin, params.topMargin,
+                    right - left - offset - rightMargin,
+                    bottom - top - params.bottomMargin);
+
+            Gravity.apply(gravity, child.getMeasuredWidth(), child.getMeasuredHeight(),
+                    mInRect, mOutRect);
+            child.layout(mOutRect.left, mOutRect.top, mOutRect.right, mOutRect.bottom);
+
+            offset = mOutRect.right + rightMargin;
         }
     }
 }