Aligning columns in stopwatch lap times

Bug: 7282042
Bug: 7539981

margin between total and lap times
string-array format for lap# and lap,total times
lap display centered in portrait
optimized landscape layout to give more room for list
using '#' instead of 'LAP'
removed unneeded margins on world clock; new dimen for timer margins
char limit on "Lap" and the hour, minute, second abbreviations
sw list handles times up to 1k hours
circle handles times up to 1k hours

Change-Id: If4e884ffd7b87986024c6d5a5990e529b1d6d736
diff --git a/res/layout-land/stopwatch_fragment.xml b/res/layout-land/stopwatch_fragment.xml
index 7f70302..b35f6da 100644
--- a/res/layout-land/stopwatch_fragment.xml
+++ b/res/layout-land/stopwatch_fragment.xml
@@ -25,7 +25,7 @@
         android:layout_height="match_parent"
         android:layout_marginLeft="@dimen/circle_margin"
         android:layout_marginRight="@dimen/circle_margin"
-        android:layout_weight="1" >
+        android:layout_weight="0.95" >
 
         <com.android.deskclock.timer.CountingTimerView
             android:id="@+id/stopwatch_time_text"
@@ -78,8 +78,7 @@
     <ListView
         android:id="@+id/laps_list"
         android:layout_weight="1"
-        android:layout_marginLeft="@dimen/laps_margin"
-        android:layout_marginRight="@dimen/laps_margin"
+        android:layout_marginRight="@dimen/sw_right_margin"
         android:layout_gravity="center"
         android:layout_width="0dip"
         android:layout_height="wrap_content" />
diff --git a/res/layout-land/timer_list_item.xml b/res/layout-land/timer_list_item.xml
index 15ddfdf..854d19d 100644
--- a/res/layout-land/timer_list_item.xml
+++ b/res/layout-land/timer_list_item.xml
@@ -27,8 +27,8 @@
         android:id="@+id/timer_frame"
         android:layout_width="@dimen/timer_circle_width"
         android:layout_height="@dimen/timer_circle_diameter"
-        android:layout_marginLeft="@dimen/circle_margin"
-        android:layout_marginRight="@dimen/circle_margin">
+        android:layout_marginLeft="@dimen/timer_circle_margin"
+        android:layout_marginRight="@dimen/timer_circle_margin">
 
         <com.android.deskclock.CircleTimerView
             android:id="@+id/timer_time"
diff --git a/res/layout/lap_view.xml b/res/layout/lap_view.xml
index 30d8757..f4e90f8 100644
--- a/res/layout/lap_view.xml
+++ b/res/layout/lap_view.xml
@@ -18,25 +18,24 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_marginTop="4dip"
     android:layout_marginBottom="4dip"
+    android:gravity="center"
     android:paddingTop="@dimen/body_font_padding"
     android:paddingBottom="@dimen/body_font_padding"
-    android:paddingLeft="@dimen/laps_margin"
-    android:paddingRight="@dimen/laps_margin"
     android:layout_width="match_parent"
     android:layout_height="match_parent" >
     <TextView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textColor="@color/clock_gray"
-        android:layout_marginRight="8dip"
+        android:layout_marginRight="@dimen/sw_item_space"
         android:gravity="left"
         style="@style/body"
         android:textAllCaps="false"
         android:id="@+id/lap_number" />
     <TextView
-        android:layout_width="0dip"
-        android:layout_weight="1"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_marginRight="@dimen/sw_item_space"
         android:textColor="@color/clock_gray"
         android:gravity="right"
         style="@style/body"
@@ -44,8 +43,7 @@
         android:id="@+id/lap_time" />
     <TextView
         android:layout_height="wrap_content"
-        android:layout_width="0dip"
-        android:layout_weight="1"
+        android:layout_width="wrap_content"
         android:textColor="@color/clock_gray"
         android:gravity="right"
         style="@style/body"
diff --git a/res/layout/timer_list_item.xml b/res/layout/timer_list_item.xml
index 1dfc04f..f5ac851 100644
--- a/res/layout/timer_list_item.xml
+++ b/res/layout/timer_list_item.xml
@@ -27,8 +27,8 @@
         android:id="@+id/timer_frame"
         android:layout_width="match_parent"
         android:layout_height="@dimen/timer_circle_diameter"
-        android:layout_marginLeft="@dimen/circle_margin"
-        android:layout_marginRight="@dimen/circle_margin">
+        android:layout_marginLeft="@dimen/timer_circle_margin"
+        android:layout_marginRight="@dimen/timer_circle_margin">
 
         <com.android.deskclock.CircleTimerView
             android:id="@+id/timer_time"
diff --git a/res/layout/world_clock_list_item.xml b/res/layout/world_clock_list_item.xml
index 4628d9a..a832265 100644
--- a/res/layout/world_clock_list_item.xml
+++ b/res/layout/world_clock_list_item.xml
@@ -18,8 +18,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_marginRight="@dimen/circle_margin"
-    android:layout_marginLeft="@dimen/circle_margin"
+    android:layout_marginRight="@dimen/world_clock_margin"
+    android:layout_marginLeft="@dimen/world_clock_margin"
     android:orientation="horizontal">
 
 
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 7967c3f..7b75074 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -39,8 +39,11 @@
 
     <!-- Size of margin for circles. -->
     <dimen name="circle_margin">8dp</dimen>
-    <dimen name="laps_margin">16dp</dimen>
     <dimen name="analog_clock_margin">200dp</dimen>
+    <dimen name="timer_circle_margin">8dp</dimen>
+
+    <dimen name="world_clock_margin">8dp</dimen>
+    <dimen name="sw_right_margin">8dp</dimen>
 
     <!-- Extra offset for timer button paddings. Only nonzero for non-tablets. -->
     <dimen name="timer_button_extra_offset">45dip</dimen>
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
index 822e1d9..8ecb43d 100644
--- a/res/values-sw600dp-land/dimens.xml
+++ b/res/values-sw600dp-land/dimens.xml
@@ -38,8 +38,11 @@
     <!-- Size of margin for circles. -->
     <dimen name="circle_margin_top">16dp</dimen>
     <dimen name="circle_margin">48dp</dimen>
-    <dimen name="laps_margin">36dp</dimen>
     <dimen name="analog_clock_margin">48dp</dimen>
+    <dimen name="timer_circle_margin">48dp</dimen>
+
+    <dimen name="world_clock_margin">48dp</dimen>
+    <dimen name="sw_right_margin">48dp</dimen>
 
     <!-- Empty space at the edges of the +1 and reset button icons. Based off of 56dip width.-->
     <dimen name="plusone_reset_button_padding">23dip</dimen>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 1efd8ab..544aa66 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -58,14 +58,15 @@
     <!-- Size of margin for circles. -->
     <dimen name="circle_margin_top">48dp</dimen>
     <dimen name="circle_margin">96dp</dimen>
-    <dimen name="laps_margin">110dp</dimen>
     <dimen name="analog_clock_margin">96dp</dimen>
+    <dimen name="timer_circle_margin">96dp</dimen>
 
      <!-- Width of the clock, for use with alarm buttons. -->
     <dimen name="alarm_alert_display_width">550dip</dimen>
 
     <!-- Size of analog clock in world clock. -->
     <dimen name="world_clock_analog_size">200dip</dimen>
+    <dimen name="world_clock_margin">96dp</dimen>
     <!-- Empty space at the edges of the +1 and reset button icons. Based off of 56dip width.-->
     <dimen name="plusone_reset_button_padding">23dip</dimen>
     <!-- Empty space at the edges of the delete button icons. Based off of 56dip width. -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 51fd102..212dbd3 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -71,6 +71,7 @@
     <dimen name="medium_space_top">24dp</dimen>
     <dimen name="medium_space_bottom">8dp</dimen>
     <dimen name="style_label_space">4dip</dimen>
+    <dimen name="sw_item_space">16dip</dimen>
 
     <dimen name="label_margin_big">4dp</dimen>
     <dimen name="label_margin_small">2dp</dimen>
@@ -88,8 +89,10 @@
     <!-- Size of margin for circles. -->
     <dimen name="circle_margin_top">16dp</dimen>
     <dimen name="circle_margin">32dp</dimen>
-    <dimen name="laps_margin">52dp</dimen>
     <dimen name="analog_clock_margin">60dp</dimen>
+    <dimen name="timer_circle_margin">32dp</dimen>
+
+    <dimen name="sw_right_margin">32dp</dimen>
 
     <!-- The width of the big icons in notifications. -->
     <dimen name="notification_large_icon_width">64dp</dimen>
@@ -107,6 +110,7 @@
 
     <!-- Size of analog clock in world clock. -->
     <dimen name="world_clock_analog_size">100dip</dimen>
+    <dimen name="world_clock_margin">32dp</dimen>
 
     <dimen name="toast_bar_bottom_margin_in_conversation">24dip</dimen>
 
diff --git a/src/com/android/deskclock/stopwatch/StopwatchFragment.java b/src/com/android/deskclock/stopwatch/StopwatchFragment.java
index fd71f4c..6a8aa51 100644
--- a/src/com/android/deskclock/stopwatch/StopwatchFragment.java
+++ b/src/com/android/deskclock/stopwatch/StopwatchFragment.java
@@ -12,6 +12,7 @@
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.preference.PreferenceManager;
+import android.text.format.DateUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -79,10 +80,26 @@
         ArrayList<Lap> mLaps = new ArrayList<Lap>();
         private final LayoutInflater mInflater;
         private final int mBackgroundColor;
+        private final String[] mFormats;
+        private final String[] mLapFormatSet;
+        // Size of this array must match the size of formats
+        private final long[] mThresholds = {
+                10 * DateUtils.MINUTE_IN_MILLIS, // < 10 minutes
+                DateUtils.HOUR_IN_MILLIS, // < 1 hour
+                10 * DateUtils.HOUR_IN_MILLIS, // < 10 hours
+                100 * DateUtils.HOUR_IN_MILLIS, // < 100 hours
+                1000 * DateUtils.HOUR_IN_MILLIS // < 1000 hours
+        };
+        private int mLapIndex = 0;
+        private int mTotalIndex = 0;
+        private String mLapFormat;
 
         public LapsListAdapter(Context context) {
             mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             mBackgroundColor = getResources().getColor(R.color.blackish);
+            mFormats = context.getResources().getStringArray(R.array.stopwatch_format_set);
+            mLapFormatSet = context.getResources().getStringArray(R.array.sw_lap_number_set);
+            updateLapFormat();
         }
 
         @Override
@@ -104,10 +121,11 @@
             TextView count = (TextView)lapInfo.findViewById(R.id.lap_number);
             TextView lapTime = (TextView)lapInfo.findViewById(R.id.lap_time);
             TextView toalTime = (TextView)lapInfo.findViewById(R.id.lap_total);
-            lapTime.setText(Stopwatches.getTimeText(mLaps.get(position).mLapTime));
-            toalTime.setText(Stopwatches.getTimeText(mLaps.get(position).mTotalTime));
-            count.setText(getString(R.string.sw_notification_lap_number, mLaps.size() - position)
-                    .toUpperCase());
+            lapTime.setText(Stopwatches.formatTimeText(mLaps.get(position).mLapTime,
+                    mFormats[mLapIndex]));
+            toalTime.setText(Stopwatches.formatTimeText(mLaps.get(position).mTotalTime,
+                    mFormats[mTotalIndex]));
+            count.setText(String.format(mLapFormat, mLaps.size() - position).toUpperCase());
 
             lapInfo.setBackgroundColor(mBackgroundColor);
             return lapInfo;
@@ -126,13 +144,38 @@
             return mLaps.get(position);
         }
 
+        private void updateLapFormat() {
+            // Note Stopwatches.MAX_LAPS < 100
+            mLapFormat = mLapFormatSet[mLaps.size() < 10 ? 0 : 1];
+        }
+
+        private void resetTimeFormats() {
+            mLapIndex = mTotalIndex = 0;
+        }
+
+        public boolean updateTimeFormats(Lap lap) {
+            boolean formatChanged = false;
+            while (mLapIndex + 1 < mThresholds.length && lap.mLapTime >= mThresholds[mLapIndex]) {
+                mLapIndex++;
+                formatChanged = true;
+            }
+            while (mTotalIndex + 1 < mThresholds.length && 
+                lap.mTotalTime >= mThresholds[mTotalIndex]) {
+                mTotalIndex++;
+                formatChanged = true;
+            }
+            return formatChanged;
+        }
+
         public void addLap(Lap l) {
             mLaps.add(0, l);
-            notifyDataSetChanged();
+            // for efficiency caller also calls notifyDataSetChanged()
         }
 
         public void clearLaps() {
             mLaps.clear();
+            updateLapFormat();
+            resetTimeFormats();
             notifyDataSetChanged();
         }
 
@@ -164,7 +207,9 @@
             for (int i = size -1; i >= 0; i --) {
                 totalTime += laps[i];
                 mLaps.get(i).mTotalTime = totalTime;
+                updateTimeFormats(mLaps.get(i));
             }
+            updateLapFormat();
             notifyDataSetChanged();
         }
     }
@@ -568,15 +613,18 @@
         long curTime = time - mStartTime + mAccumulatedTime;
         if (size == 0) {
             // Always show the ending lap and a new one
-            mLapsAdapter.addLap(new Lap(curTime, curTime));
+            Lap firstLap = new Lap(curTime, curTime);
+            mLapsAdapter.addLap(firstLap);
             mLapsAdapter.addLap(new Lap(0, curTime));
             mTime.setIntervalTime(curTime);
+            mLapsAdapter.updateTimeFormats(firstLap);
         } else {
             long lapTime = curTime - ((Lap) mLapsAdapter.getItem(1)).mTotalTime;
             ((Lap)mLapsAdapter.getItem(0)).mLapTime = lapTime;
             ((Lap)mLapsAdapter.getItem(0)).mTotalTime = curTime;
             mLapsAdapter.addLap(new Lap(0, 0));
             mTime.setMarkerTime(lapTime);
+            mLapsAdapter.updateLapFormat();
         //    mTime.setIntervalTime(lapTime * 10);
         }
         mLapsAdapter.notifyDataSetChanged();
diff --git a/src/com/android/deskclock/stopwatch/Stopwatches.java b/src/com/android/deskclock/stopwatch/Stopwatches.java
index d8d0741..94af594 100644
--- a/src/com/android/deskclock/stopwatch/Stopwatches.java
+++ b/src/com/android/deskclock/stopwatch/Stopwatches.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 
 import com.android.deskclock.R;
-import com.android.deskclock.stopwatch.StopwatchFragment.Lap;
 
 public class Stopwatches {
     // Private actions processed by the receiver
@@ -107,4 +106,23 @@
         return timeStr;
     }
 
+    /***
+     * Sets the string of the time running on the stopwatch up to hundred of a second accuracy
+     * @param time - in hundreds of a second since the stopwatch started
+     */
+    public static String formatTimeText(long time, final String format) {
+        if (time < 0) {
+            time = 0;
+        }
+        long hundreds, seconds, minutes, hours;
+        seconds = time / 1000;
+        hundreds = (time - seconds * 1000) / 10;
+        minutes = seconds / 60;
+        seconds = seconds - minutes * 60;
+        hours = minutes / 60;
+        minutes = minutes - hours * 60;
+        String timeStr = String.format(format, hours, minutes, seconds, hundreds);
+        return timeStr;
+    }
+
 }
diff --git a/src/com/android/deskclock/timer/CountingTimerView.java b/src/com/android/deskclock/timer/CountingTimerView.java
index 6aeda39..417e9b1 100644
--- a/src/com/android/deskclock/timer/CountingTimerView.java
+++ b/src/com/android/deskclock/timer/CountingTimerView.java
@@ -315,7 +315,7 @@
         seconds = seconds - minutes * 60;
         hours = minutes / 60;
         minutes = minutes - hours * 60;
-        if (hours > 99) {
+        if (hours > 999) {
             hours = 0;
         }
         // time may less than a second below zero, since we do not show fractions of seconds