Merge "Fix alarm expanding issues." into ics-ub-clock-amazon
diff --git a/res/drawable-hdpi/ic_plusone_disabled.png b/res/drawable-hdpi/ic_plusone_disabled.png
index 61b69e1..73af697 100644
--- a/res/drawable-hdpi/ic_plusone_disabled.png
+++ b/res/drawable-hdpi/ic_plusone_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/stat_notify_timer.png b/res/drawable-hdpi/stat_notify_timer.png
index 9b6143c..ed39528 100644
--- a/res/drawable-hdpi/stat_notify_timer.png
+++ b/res/drawable-hdpi/stat_notify_timer.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_plusone_disabled.png b/res/drawable-mdpi/ic_plusone_disabled.png
index 9531596..52dd356 100644
--- a/res/drawable-mdpi/ic_plusone_disabled.png
+++ b/res/drawable-mdpi/ic_plusone_disabled.png
Binary files differ
diff --git a/res/drawable-mdpi/stat_notify_timer.png b/res/drawable-mdpi/stat_notify_timer.png
index 05842b0..e75a12d 100644
--- a/res/drawable-mdpi/stat_notify_timer.png
+++ b/res/drawable-mdpi/stat_notify_timer.png
Binary files differ
diff --git a/res/drawable-sw600dp-hdpi/ic_plusone_disabled.png b/res/drawable-sw600dp-hdpi/ic_plusone_disabled.png
new file mode 100644
index 0000000..25e75e8
--- /dev/null
+++ b/res/drawable-sw600dp-hdpi/ic_plusone_disabled.png
Binary files differ
diff --git a/res/drawable-sw600dp-mdpi/ic_plusone_disabled.png b/res/drawable-sw600dp-mdpi/ic_plusone_disabled.png
new file mode 100644
index 0000000..134e4c8
--- /dev/null
+++ b/res/drawable-sw600dp-mdpi/ic_plusone_disabled.png
Binary files differ
diff --git a/res/drawable-sw600dp-xhdpi/ic_plusone_disabled.png b/res/drawable-sw600dp-xhdpi/ic_plusone_disabled.png
new file mode 100644
index 0000000..934e9e8
--- /dev/null
+++ b/res/drawable-sw600dp-xhdpi/ic_plusone_disabled.png
Binary files differ
diff --git a/res/drawable-sw600dp-xxhdpi/ic_plusone_disabled.png b/res/drawable-sw600dp-xxhdpi/ic_plusone_disabled.png
new file mode 100644
index 0000000..b324edd
--- /dev/null
+++ b/res/drawable-sw600dp-xxhdpi/ic_plusone_disabled.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_plusone_disabled.png b/res/drawable-xhdpi/ic_plusone_disabled.png
index 707843f..3207f2b 100644
--- a/res/drawable-xhdpi/ic_plusone_disabled.png
+++ b/res/drawable-xhdpi/ic_plusone_disabled.png
Binary files differ
diff --git a/res/drawable-xhdpi/stat_notify_timer.png b/res/drawable-xhdpi/stat_notify_timer.png
index b0b974a..c52629c 100644
--- a/res/drawable-xhdpi/stat_notify_timer.png
+++ b/res/drawable-xhdpi/stat_notify_timer.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_plusone_disabled.png b/res/drawable-xxhdpi/ic_plusone_disabled.png
index 0bf3fb5..95b47b7 100644
--- a/res/drawable-xxhdpi/ic_plusone_disabled.png
+++ b/res/drawable-xxhdpi/ic_plusone_disabled.png
Binary files differ
diff --git a/res/drawable-xxhdpi/stat_notify_timer.png b/res/drawable-xxhdpi/stat_notify_timer.png
index af3c7f9..6150379 100644
--- a/res/drawable-xxhdpi/stat_notify_timer.png
+++ b/res/drawable-xxhdpi/stat_notify_timer.png
Binary files differ
diff --git a/src/com/android/deskclock/timer/CountingTimerView.java b/src/com/android/deskclock/timer/CountingTimerView.java
index 4f0c41f..9dbe549 100644
--- a/src/com/android/deskclock/timer/CountingTimerView.java
+++ b/src/com/android/deskclock/timer/CountingTimerView.java
@@ -60,7 +60,6 @@
     private boolean mShowTimeStr = true;
     private final Paint mPaintBigThin = new Paint();
     private final Paint mPaintMed = new Paint();
-    private final Paint mPaintLabel = new Paint();
     private final float mBigFontSize, mSmallFontSize;
     // Hours and minutes are signed for when a timer goes past the set time and thus negative
     private final SignedTime mBigHours, mBigMinutes;
@@ -289,13 +288,6 @@
         mPaintMed.setTextAlign(Paint.Align.CENTER);
         mPaintMed.setTypeface(androidClockMonoLight);
 
-        Typeface robotoLabel = Typeface.create("sans-serif-condensed", Typeface.BOLD);
-        mPaintLabel.setAntiAlias(true);
-        mPaintLabel.setStyle(Paint.Style.STROKE);
-        mPaintLabel.setTextAlign(Paint.Align.LEFT);
-        mPaintLabel.setTypeface(robotoLabel);
-        mPaintLabel.setTextSize(r.getDimension(R.dimen.label_font_size));
-
         resetTextSize();
         setTextColor(mDefaultColor);
 
@@ -318,7 +310,6 @@
     protected void setTextColor(int textColor) {
         mPaintBigThin.setColor(textColor);
         mPaintMed.setColor(textColor);
-        mPaintLabel.setColor(textColor);
     }
 
     /**
@@ -644,7 +635,6 @@
             textColor = mDefaultColor;
         }
         mPaintBigThin.setColor(textColor);
-        mPaintLabel.setColor(textColor);
         mPaintMed.setColor(textColor);
 
         if (mHours != null) {
@@ -665,6 +655,7 @@
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
         mRemeasureText = true;
+        resetTextSize();
     }
 
     public void registerStopTextView(TextView stopStartTextView) {
diff --git a/src/com/android/deskclock/timer/TimerReceiver.java b/src/com/android/deskclock/timer/TimerReceiver.java
index e22a827..c2e74a8 100644
--- a/src/com/android/deskclock/timer/TimerReceiver.java
+++ b/src/com/android/deskclock/timer/TimerReceiver.java
@@ -184,8 +184,6 @@
                 cancelTimesUpNotification(context, t);
                 showTimesUpNotification(context, t);
             }
-            // Unlike the actions above, there is nothing else to do
-            return;
         }
         // Update the next "Times up" alarm
         updateNextTimesup(context);
diff --git a/src/com/android/deskclock/widget/EllipsizeLayout.java b/src/com/android/deskclock/widget/EllipsizeLayout.java
index 2976f82..6c5dd33 100644
--- a/src/com/android/deskclock/widget/EllipsizeLayout.java
+++ b/src/com/android/deskclock/widget/EllipsizeLayout.java
@@ -7,13 +7,33 @@
 import android.widget.TextView;
 
 /**
- * When this layout is in the Horizontal orientation and one and only one child
- * is a TextView with a non-null android:ellipsize, this layout will reduce
- * android:maxWidth of that TextView to ensure the other children are within the
- * layout. This layout has no effect if the children have weights.
+ * When this layout is in the Horizontal orientation and one and only one child is a TextView with a
+ * non-null android:ellipsize, this layout will reduce android:maxWidth of that TextView to ensure
+ * the siblings are not truncated. This class is useful when that ellipsize-text-view "starts"
+ * before other children of this view group. This layout has no effect if:
+ * <ul>
+ *     <li>the orientation is not horizontal</li>
+ *     <li>any child has weights.</li>
+ *     <li>more than one child has a non-null android:ellipsize.</li>
+ * </ul>
+ *
+ * <p>The purpose of this horizontal-linear-layout is to ensure that when the sum of widths of the
+ * children are greater than this parent, the maximum width of the ellipsize-text-view, is reduced
+ * so that no siblings are truncated.</p>
+ *
+ * <p>For example: Given Text1 has android:ellipsize="end" and Text2 has android:ellipsize="none",
+ * as Text1 and/or Text2 grow in width, both will consume more width until Text2 hits the end
+ * margin, then Text1 will cease to grow and instead shrink to accommodate any further growth in
+ * Text2.</p>
+ * <ul>
+ * <li>|[text1]|[text2]              |</li>
+ * <li>|[text1 text1]|[text2 text2]  |</li>
+ * <li>|[text...]|[text2 text2 text2]|</li>
+ * </ul>
  */
 public class EllipsizeLayout extends LinearLayout {
 
+    @SuppressWarnings("unused")
     public EllipsizeLayout(Context context) {
         this(context, null);
     }
@@ -22,49 +42,80 @@
         super(context, attrs);
     }
 
+    /**
+     * This override only acts when the LinearLayout is in the Horizontal orientation and is in it's
+     * final measurement pass(MeasureSpec.EXACTLY). In this case only, this class
+     * <ul>
+     *     <li>Identifies the one TextView child with the non-null android:ellipsize.</li>
+     *     <li>Re-measures the needed width of all children (by calling measureChildWithMargins with
+     *     the width measure specification to MeasureSpec.UNSPECIFIED.)</li>
+     *     <li>Sums the children's widths.</li>
+     *     <li>Whenever the sum of the children's widths is greater than this parent was allocated,
+     *     the maximum width of the one TextView child with the non-null android:ellipsize is
+     *     reduced.</li>
+     * </ul>
+     *
+     * @param widthMeasureSpec horizontal space requirements as imposed by the parent
+     * @param heightMeasureSpec vertical space requirements as imposed by the parent
+     */
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         if (getOrientation() == HORIZONTAL
                 && (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY)) {
             int totalLength = 0;
+            // If any of the constraints of this class are exceeded, outOfSpec becomes true
+            // and the no alterations are made to the ellipsize-text-view.
             boolean outOfSpec = false;
-            TextView ellipView = null;
+            TextView ellipsizeView = null;
             final int count = getChildCount();
+            final int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
+            final int queryWidthMeasureSpec = MeasureSpec.
+                    makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED);
 
             for (int ii = 0; ii < count && !outOfSpec; ++ii) {
                 final View child = getChildAt(ii);
                 if (child != null && child.getVisibility() != GONE) {
+                    // Identify the ellipsize view
                     if (child instanceof TextView) {
                         final TextView tv = (TextView) child;
                         if (tv.getEllipsize() != null) {
-                            if (ellipView == null) {
-                                ellipView = tv;
-                                // clear maxWidth on mEllipView before measure
-                                ellipView.setMaxWidth(Integer.MAX_VALUE);
+                            if (ellipsizeView == null) {
+                                ellipsizeView = tv;
+                                // Clear the maximum width on ellipsizeView before measurement
+                                ellipsizeView.setMaxWidth(Integer.MAX_VALUE);
                             } else {
                                 // TODO: support multiple android:ellipsize
                                 outOfSpec = true;
                             }
                         }
                     }
-                    final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child
-                            .getLayoutParams();
-                    outOfSpec |= (lp.weight > 0f);
-                    measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
-                    totalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
+                    // Ask the child to measure itself
+                    measureChildWithMargins(child, queryWidthMeasureSpec, 0, heightMeasureSpec, 0);
+
+                    // Get the layout parameters to check for a weighted width and to add the
+                    // child's margins to the total length.
+                    final LinearLayout.LayoutParams layoutParams =
+                            (LinearLayout.LayoutParams) child.getLayoutParams();
+                    if (layoutParams != null) {
+                        outOfSpec |= (layoutParams.weight > 0f);
+                        totalLength += child.getMeasuredWidth()
+                                + layoutParams.leftMargin + layoutParams.rightMargin;
+                    } else {
+                        outOfSpec = true;
+                    }
                 }
             }
-            outOfSpec |= (ellipView == null) || (totalLength == 0);
-            final int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
+            // Last constraint test
+            outOfSpec |= (ellipsizeView == null) || (totalLength == 0);
 
             if (!outOfSpec && totalLength > parentWidth) {
-                int maxWidth = ellipView.getMeasuredWidth() - (totalLength - parentWidth);
+                int maxWidth = ellipsizeView.getMeasuredWidth() - (totalLength - parentWidth);
                 // TODO: Respect android:minWidth (easy with @TargetApi(16))
-                int minWidth = 0;
+                final int minWidth = 0;
                 if (maxWidth < minWidth) {
                     maxWidth = minWidth;
                 }
-                ellipView.setMaxWidth(maxWidth);
+                ellipsizeView.setMaxWidth(maxWidth);
             }
         }
 
diff --git a/src/com/android/deskclock/worldclock/CitiesActivity.java b/src/com/android/deskclock/worldclock/CitiesActivity.java
index 22daa0b..f8f11f3 100644
--- a/src/com/android/deskclock/worldclock/CitiesActivity.java
+++ b/src/com/android/deskclock/worldclock/CitiesActivity.java
@@ -121,6 +121,12 @@
 
         private int mLayoutDirection;
 
+        // A map that caches names of cities in local memory.  The names in this map are
+        // preferred over the names of the selected cities stored in SharedPreferences, which could
+        // be in a different language.  This map gets reloaded on a locale change, when the new
+        // language's city strings are read from the xml file.
+        private HashMap<String, String> mCityNameMap = new HashMap<String, String>();
+
         private String[] mSectionHeaders;
         private Integer[] mSectionPositions;
 
@@ -130,7 +136,7 @@
         private final LayoutInflater mInflater;
         private boolean mIs24HoursMode; // AM/PM or 24 hours mode
 
-        private int mSelectedEndPosition;
+        private int mSelectedEndPosition = 0;
 
         private Filter mFilter = new Filter() {
 
@@ -227,12 +233,35 @@
         public CityAdapter(
                 Context context, LayoutInflater factory) {
             super();
-            loadCities(context);
-            mInflater = factory;
             mCalendar = Calendar.getInstance();
             mCalendar.setTimeInMillis(System.currentTimeMillis());
+            mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
+            mInflater = factory;
+
+            // Load the cities from xml.
+            mCities = Utils.loadCitiesFromXml(context);
+
+            // Reload the city name map with the recently parsed city names of the currently
+            // selected language for use with selected cities.
+            mCityNameMap.clear();
+            for (CityObj city : mCities) {
+                mCityNameMap.put(city.mCityId, city.mCityName);
+            }
+
+            // Re-organize the selected cities into an array.
             Collection<CityObj> selectedCities = mUserSelectedCities.values();
             mSelectedCities = selectedCities.toArray(new CityObj[selectedCities.size()]);
+
+            // Override the selected city names in the shared preferences with the
+            // city names in the updated city name map, which will always reflect the
+            // current language.
+            for (CityObj city : mSelectedCities) {
+                String newCityName = mCityNameMap.get(city.mCityId);
+                if (newCityName != null) {
+                    city.mCityName = newCityName;
+                }
+            }
+
             sortCities(mSortType);
             set24HoursMode(context);
         }
@@ -243,14 +272,6 @@
             sortCities(mSortType);
         }
 
-        private void loadCities(Context c) {
-            mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
-            mCities = Utils.loadCitiesFromXml(c);
-            if (mCities == null) {
-                return;
-            }
-        }
-
         public void toggleSort() {
             if (mSortType == SORT_BY_NAME) {
                 sortCities(SORT_BY_GMT_OFFSET);
@@ -333,6 +354,7 @@
                 }
                 view.setOnClickListener(CitiesActivity.this);
                 CityViewHolder holder = (CityViewHolder) view.getTag();
+
                 if (position < mSelectedEndPosition) {
                     holder.selected.setVisibility(View.GONE);
                     holder.time.setVisibility(View.GONE);