auto import from //depot/cupcake/@136594
diff --git a/res/drawable/gadget_date_bg.9.png b/res/drawable/gadget_date_bg.9.png
index abf4c44..236562f 100644
--- a/res/drawable/gadget_date_bg.9.png
+++ b/res/drawable/gadget_date_bg.9.png
Binary files differ
diff --git a/res/layout-land/gadget_item.xml b/res/layout-land/gadget_item.xml
index d63eb44..563a454 100644
--- a/res/layout-land/gadget_item.xml
+++ b/res/layout-land/gadget_item.xml
@@ -94,7 +94,7 @@
 
     </FrameLayout>
 
-    <RelativeLayout
+    <LinearLayout
         android:id="@+id/primary_card"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
@@ -112,7 +112,7 @@
             android:id="@+id/when"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:paddingRight="8dip"
+            android:paddingRight="48dip"
             android:paddingLeft="8dip"
             android:paddingTop="1dip"
             android:paddingBottom="1dip"
@@ -125,36 +125,10 @@
             />
 
         <TextView
-            android:id="@+id/icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/when"
-            android:layout_alignParentRight="true"
-            android:background="@drawable/gadget_date_bg"
-            android:textStyle="bold"
-            android:textSize="18sp"
-            android:gravity="center"
-            android:paddingLeft="8dip"
-            android:paddingRight="7dip"
-            android:paddingTop="3dip"
-            android:paddingBottom="3dip"
-            android:layout_marginRight="5dip"
-            android:layout_marginTop="4dip"
-            android:layout_marginBottom="4dip"
-            android:textColor="#59b4f4"
-            android:shadowColor="#ffff"
-            android:shadowRadius="2.75"
-            android:minWidth="32dip"
-            />
-
-        <TextView
             android:id="@+id/title"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:layout_alignParentLeft="true"
-            android:layout_below="@id/when"
-            android:layout_toLeftOf="@id/icon"
-            android:paddingRight="8dip"
+            android:paddingRight="48dip"
             android:paddingLeft="8dip"
             android:textStyle="bold"
             android:textSize="16sp"
@@ -166,17 +140,27 @@
             android:id="@+id/where"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:layout_below="@id/title"
-            android:layout_toLeftOf="@id/icon"
-            android:layout_alignParentLeft="true"
-            android:paddingRight="8dip"
+            android:paddingRight="48dip"
             android:paddingLeft="8dip"
             android:textSize="11sp"
             android:textColor="@color/gadget_where"
             android:singleLine="true"
             />
 
-    </RelativeLayout>
+    </LinearLayout>
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentRight="true"
+        android:background="@drawable/gadget_date_bg"
+        android:layout_marginRight="6dip"
+        android:layout_marginTop="6dip"
+        android:minWidth="32dip"
+        android:visibility="gone"
+        />
 
 </RelativeLayout>
 
diff --git a/res/layout/gadget_item.xml b/res/layout/gadget_item.xml
index e888089..f5e9a1a 100644
--- a/res/layout/gadget_item.xml
+++ b/res/layout/gadget_item.xml
@@ -101,7 +101,7 @@
 
     </LinearLayout>
 
-    <RelativeLayout
+    <LinearLayout
         android:id="@+id/primary_card"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
@@ -119,7 +119,7 @@
             android:id="@+id/when"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:paddingRight="8dip"
+            android:paddingRight="48dip"
             android:paddingLeft="8dip"
             android:paddingTop="1dip"
             android:paddingBottom="1dip"
@@ -132,36 +132,10 @@
             />
 
         <TextView
-            android:id="@+id/icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/when"
-            android:layout_alignParentRight="true"
-            android:background="@drawable/gadget_date_bg"
-            android:textStyle="bold"
-            android:textSize="18sp"
-            android:gravity="center"
-            android:paddingLeft="8dip"
-            android:paddingRight="7dip"
-            android:paddingTop="3dip"
-            android:paddingBottom="3dip"
-            android:layout_marginRight="5dip"
-            android:layout_marginTop="4dip"
-            android:layout_marginBottom="4dip"
-            android:textColor="#59b4f4"
-            android:shadowColor="#ffff"
-            android:shadowRadius="2.75"
-            android:minWidth="32dip"
-            />
-
-        <TextView
             android:id="@+id/title"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:layout_alignParentLeft="true"
-            android:layout_below="@id/when"
-            android:layout_toLeftOf="@id/icon"
-            android:paddingRight="8dip"
+            android:paddingRight="48dip"
             android:paddingLeft="8dip"
             android:textStyle="bold"
             android:textSize="16sp"
@@ -173,10 +147,7 @@
             android:id="@+id/where"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:layout_below="@id/title"
-            android:layout_toLeftOf="@id/icon"
-            android:layout_alignParentLeft="true"
-            android:paddingRight="8dip"
+            android:paddingRight="48dip"
             android:paddingLeft="8dip"
             android:textSize="11sp"
             android:textColor="@color/gadget_where"
@@ -187,8 +158,6 @@
             android:id="@+id/divider"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:layout_below="@id/icon"
-            android:layout_alignParentLeft="true"
             android:layout_marginTop="4dip"
             android:layout_marginBottom="2dip"
             android:layout_marginLeft="16dip"
@@ -200,8 +169,6 @@
             android:id="@+id/title2"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:layout_below="@id/divider"
-            android:layout_alignParentLeft="true"
             android:paddingRight="8dip"
             android:paddingLeft="8dip"
             android:textStyle="bold"
@@ -210,7 +177,20 @@
             android:singleLine="true"
             />
 
-    </RelativeLayout>
+    </LinearLayout>
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentRight="true"
+        android:background="@drawable/gadget_date_bg"
+        android:layout_marginRight="6dip"
+        android:layout_marginTop="6dip"
+        android:minWidth="32dip"
+        android:visibility="gone"
+        />
 
 </RelativeLayout>
 
diff --git a/res/values/colors.xml b/res/values/colors.xml
index f6a9f3a..da34ad1 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -20,6 +20,7 @@
     <color name="gadget_title">#ff000000</color>
     <color name="gadget_where">#ff000000</color>
     <color name="gadget_calendar">#ff000000</color>
+    <color name="gadget_date">#ff59b4f4</color>
 
     <color name="gadget_no_events">#bb000000</color>
 </resources>
diff --git a/src/com/android/providers/calendar/CalendarGadgetProvider.java b/src/com/android/providers/calendar/CalendarGadgetProvider.java
index 9afcade..2f46bee 100644
--- a/src/com/android/providers/calendar/CalendarGadgetProvider.java
+++ b/src/com/android/providers/calendar/CalendarGadgetProvider.java
@@ -20,7 +20,6 @@
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.ContentResolver;
-import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -29,10 +28,11 @@
 import android.gadget.GadgetManager;
 import android.gadget.GadgetProvider;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
+import android.graphics.Typeface;
+import android.graphics.Paint.FontMetrics;
 import android.net.Uri;
 import android.provider.Calendar.Attendees;
 import android.provider.Calendar.Calendars;
@@ -91,6 +91,17 @@
     static final ComponentName THIS_GADGET =
         new ComponentName("com.android.providers.calendar",
                 "com.android.providers.calendar.CalendarGadgetProvider");
+
+    /**
+     * Threshold to check against when building gadget updates. If system clock
+     * has changed less than this amount, we consider ignoring the request.
+     */
+    static final long UPDATE_THRESHOLD = DateUtils.MINUTE_IN_MILLIS;
+
+    /**
+     * Last gadget update, as provided by {@link System#currentTimeMillis()}
+     */
+    private static long sLastUpdate = -1;
     
     private static CalendarGadgetProvider sInstance;
     
@@ -110,7 +121,8 @@
         // coming in without extras, which GadgetProvider then blocks.
         final String action = intent.getAction();
         if (ACTION_CALENDAR_GADGET_UPDATE.equals(action)) {
-            performUpdate(context, null, -1);
+            performUpdate(context, null /* all gadgets */,
+                    -1 /* no eventId */, false /* don't ignore */);
         } else {
             super.onReceive(context, intent);
         }
@@ -152,7 +164,7 @@
      */
     @Override
     public void onUpdate(Context context, GadgetManager gadgetManager, int[] gadgetIds) {
-        performUpdate(context, gadgetIds, -1);
+        performUpdate(context, gadgetIds, -1 /* no eventId */, false /* don't ignore */);
     }
     
     /**
@@ -168,21 +180,29 @@
      * The {@link CalendarProvider} has been updated, which means we should push
      * updates to any gadgets, if they exist.
      * 
+     * @param context Context to use when creating gadget.
      * @param changedEventId Specific event known to be changed, otherwise -1.
      *            If present, we use it to decide if an update is necessary.
      */
     void providerUpdated(Context context, long changedEventId) {
         if (hasInstances(context)) {
-            performUpdate(context, null, changedEventId);
+            performUpdate(context, null /* all gadgets */,
+                    changedEventId, false /* don't ignore */);
         }
     }
-    
+
     /**
      * {@link TimeChangeReceiver} has triggered that the time changed.
+     * 
+     * @param context Context to use when creating gadget.
+     * @param considerIgnore If true, compare {@link #sLastUpdate} against
+     *            {@link #UPDATE_THRESHOLD} to consider ignoring this update
+     *            request.
      */
-    void timeUpdated(Context context) {
+    void timeUpdated(Context context, boolean considerIgnore) {
         if (hasInstances(context)) {
-            performUpdate(context, null, -1);
+            performUpdate(context, null /* all gadgets */,
+                    -1 /* no eventId */, considerIgnore);
         }
     }
 
@@ -193,18 +213,34 @@
      * @param gadgetIds List of specific gadgetIds to update, or null for all.
      * @param changedEventId Specific event known to be changed, otherwise -1.
      *            If present, we use it to decide if an update is necessary.
+     * @param considerIgnore If true, compare {@link #sLastUpdate} against
+     *            {@link #UPDATE_THRESHOLD} to consider ignoring this update
+     *            request.
      */
-    private void performUpdate(Context context, int[] gadgetIds, long changedEventId) {
+    private void performUpdate(Context context, int[] gadgetIds,
+            long changedEventId, boolean considerIgnore) {
         ContentResolver resolver = context.getContentResolver();
         
+        long now = System.currentTimeMillis();
+        
+        // Check against delta if we have a last-updated value
+        if (considerIgnore && sLastUpdate != -1) {
+            long delta = Math.abs(now - sLastUpdate);
+            if (delta < UPDATE_THRESHOLD) {
+                if (LOGD) Log.d(TAG, "Ignoring update request because delta=" + delta);
+                return;
+            }
+        }
+        sLastUpdate = now;
+        
         Cursor cursor = null;
         RemoteViews views = null;
         long triggerTime = -1;
 
         try {
-            cursor = getUpcomingInstancesCursor(resolver, SEARCH_DURATION);
+            cursor = getUpcomingInstancesCursor(resolver, SEARCH_DURATION, now);
             if (cursor != null) {
-                MarkedEvents events = buildMarkedEvents(cursor, changedEventId);
+                MarkedEvents events = buildMarkedEvents(cursor, changedEventId, now);
                 
                 boolean shouldUpdate = true;
                 if (changedEventId != -1) {
@@ -215,7 +251,7 @@
                     views = getGadgetNoEvents(context);
                 } else if (shouldUpdate) {
                     views = getGadgetUpdate(context, cursor, events);
-                    triggerTime = calculateUpdateTime(context, cursor, events);
+                    triggerTime = calculateUpdateTime(cursor, events);
                 }
             } else {
                 views = getGadgetNoEvents(context);
@@ -245,9 +281,8 @@
         
         // If no next-update calculated, or bad trigger time in past, schedule
         // update about six hours from now.
-        long now = System.currentTimeMillis();
         if (triggerTime == -1 || triggerTime < now) {
-            if (LOGD) Log.w(TAG, "Encountered bad trigger time " + formatDebugTime(triggerTime));
+            if (LOGD) Log.w(TAG, "Encountered bad trigger time " + formatDebugTime(triggerTime, now));
             triggerTime = now + UPDATE_NO_EVENTS;
         }
         
@@ -257,13 +292,15 @@
         am.cancel(pendingUpdate);
         am.set(AlarmManager.RTC, triggerTime, pendingUpdate);
 
-        if (LOGD) Log.d(TAG, "Scheduled next update at " + formatDebugTime(triggerTime));
+        if (LOGD) Log.d(TAG, "Scheduled next update at " + formatDebugTime(triggerTime, now));
     }
     
     /**
      * Build the {@link PendingIntent} used to trigger an update of all calendar
      * gadgets. Uses {@link ACTION_CALENDAR_GADGET_UPDATE} to directly target
      * all gadgets instead of using {@link GadgetManager#EXTRA_GADGET_IDS}.
+     * 
+     * @param context Context to use when building broadcast.
      */
     private PendingIntent getUpdateIntent(Context context) {
         Intent updateIntent = new Intent(ACTION_CALENDAR_GADGET_UPDATE);
@@ -271,15 +308,19 @@
         return PendingIntent.getBroadcast(context, 0 /* no requestCode */,
                 updateIntent, 0 /* no flags */);
     }
-    
+
     /**
      * Format given time for debugging output.
+     * 
+     * @param unixTime Target time to report.
+     * @param now Current system time from {@link System#currentTimeMillis()}
+     *            for calculating time difference.
      */
-    private String formatDebugTime(long unixTime) {
+    private String formatDebugTime(long unixTime, long now) {
         Time time = new Time();
         time.set(unixTime);
         
-        long delta = unixTime - System.currentTimeMillis();
+        long delta = unixTime - now;
         if (delta > DateUtils.MINUTE_IN_MILLIS) {
             delta /= DateUtils.MINUTE_IN_MILLIS;
             return String.format("[%d] %s (%+d mins)", unixTime, time.format("%H:%M:%S"), delta);
@@ -308,8 +349,11 @@
     /**
      * Figure out the next time we should push gadget updates. This is based on
      * the time calculated by {@link #getEventFlip(Cursor, int)}.
+     * 
+     * @param cursor Valid cursor on {@link Instances#CONTENT_URI}
+     * @param events {@link MarkedEvents} parsed from the cursor
      */
-    private long calculateUpdateTime(Context context, Cursor cursor, MarkedEvents events) {
+    private long calculateUpdateTime(Cursor cursor, MarkedEvents events) {
         long result = -1;
         if (events.primaryRow != -1) {
             cursor.moveToPosition(events.primaryRow);
@@ -371,7 +415,7 @@
         int dateNumber = time.monthDay;
 
         // Set calendar icon with actual date
-        views.setTextViewText(R.id.icon, Integer.toString(dateNumber));
+        views.setImageViewBitmap(R.id.icon, getDateOverlay(res, dateNumber));
         views.setViewVisibility(R.id.icon, View.VISIBLE);
         views.setViewVisibility(R.id.no_events, View.GONE);
 
@@ -518,6 +562,43 @@
         
         return views;
     }
+
+    /**
+     * Build date overlay bitmap for positioning on gadget. This is the textual
+     * number that has been corrected for font leading issues.
+     * 
+     * @param res {@link Resources} to use for paint color.
+     * @param dateNumber Numerical date to display.
+     */
+    public Bitmap getDateOverlay(Resources res, int dateNumber) {
+        String dateString = Integer.toString(dateNumber);
+        
+        Paint paint = new Paint();
+        paint.setTypeface(Typeface.DEFAULT_BOLD);
+        paint.setTextSize(18);
+        paint.setAntiAlias(true);
+        paint.setSubpixelText(true);
+        paint.setColor(res.getColor(R.color.gadget_date));
+        
+        // Calculate exact size of text
+        FontMetrics metrics = paint.getFontMetrics();
+        int width = (int) Math.ceil(paint.measureText(dateString));
+        int height = (int) Math.ceil(-metrics.top + metrics.descent);
+        
+        // Add padding to left edge based on various obscure rules
+        // to make font center correctly
+        char firstChar = dateString.charAt(0);
+        char lastChar = dateString.charAt(dateString.length() - 1);
+        int leftPadding = (dateString.length() == 1 || firstChar == '2' ||
+                lastChar == '1' || lastChar == '0') ? 1 : 0;
+        
+        Bitmap overlay = Bitmap.createBitmap(width + leftPadding,
+                height, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(overlay);
+        canvas.drawText(dateString, leftPadding, -metrics.top, paint);
+        
+        return overlay;
+    }
     
     /**
      * Build a set of {@link RemoteViews} that describes an error state.
@@ -527,6 +608,7 @@
 
         views.setViewVisibility(R.id.no_events, View.VISIBLE);
         
+        views.setViewVisibility(R.id.icon, View.GONE);
         views.setViewVisibility(R.id.primary_card, View.GONE);
         views.setViewVisibility(R.id.secondary_card, View.GONE);
         
@@ -560,10 +642,11 @@
      * @param cursor Valid cursor across {@link Instances#CONTENT_URI}.
      * @param watchEventId Specific event to watch for, setting
      *            {@link MarkedEvents#watchFound} if found during marking.
+     * @param now Current system time to use for this update, possibly from
+     *            {@link System#currentTimeMillis()}
      */
-    private MarkedEvents buildMarkedEvents(Cursor cursor, long watchEventId) {
+    private MarkedEvents buildMarkedEvents(Cursor cursor, long watchEventId, long now) {
         MarkedEvents events = new MarkedEvents();
-        long now = System.currentTimeMillis();
         final Time recycle = new Time();
         
         cursor.moveToPosition(-1);
@@ -582,7 +665,7 @@
             
             // Skip events that have already passed their flip times
             long eventFlip = getEventFlip(cursor, start, end, allDay);
-            if (LOGD) Log.d(TAG, "Calculated flip time " + formatDebugTime(eventFlip));
+            if (LOGD) Log.d(TAG, "Calculated flip time " + formatDebugTime(eventFlip, now));
             if (eventFlip < now) {
                 continue;
             }
@@ -618,21 +701,25 @@
         }
         return events;
     }
-    
+
     /**
      * Query across all calendars for upcoming event instances from now until
      * some time in the future.
      * 
+     * @param resolver {@link ContentResolver} to use when querying
+     *            {@link Instances#CONTENT_URI}.
      * @param searchDuration Distance into the future to look for event
      *            instances, in milliseconds.
+     * @param now Current system time to use for this update, possibly from
+     *            {@link System#currentTimeMillis()}.
      */
-    private Cursor getUpcomingInstancesCursor(ContentResolver resolver, long searchDuration) {
+    private Cursor getUpcomingInstancesCursor(ContentResolver resolver,
+            long searchDuration, long now) {
         // Search for events from now until some time in the future
-        long start = System.currentTimeMillis();
-        long end = start + searchDuration;
+        long end = now + searchDuration;
         
         Uri uri = Uri.withAppendedPath(Instances.CONTENT_URI,
-                String.format("%d/%d", start, end));
+                String.format("%d/%d", now, end));
 
         String selection = String.format("%s=1 AND %s!=%d",
                 Calendars.SELECTED, Instances.SELF_ATTENDEE_STATUS,
diff --git a/src/com/android/providers/calendar/TimeChangeReceiver.java b/src/com/android/providers/calendar/TimeChangeReceiver.java
index 6a7d3c6..4618c6f 100644
--- a/src/com/android/providers/calendar/TimeChangeReceiver.java
+++ b/src/com/android/providers/calendar/TimeChangeReceiver.java
@@ -31,6 +31,9 @@
     public void onReceive(Context context, Intent intent) {
         // Pass time-changed notification through to any gadgets
         if (LOGD) Log.d(TAG, "Received time changed action=" + intent.getAction());
-        mCalendarProvider.timeUpdated(context);
+        
+        // Consider ignoring this update request if only TIME_CHANGED
+        boolean considerIgnore = (Intent.ACTION_TIME_CHANGED.equals(intent.getAction()));
+        mCalendarProvider.timeUpdated(context, considerIgnore);
     }
 }