Data usage axis grow/shrink, other fixes.

When dragging vertical sweeps near edges, grow or shrink axis scale
to give users access to larger limits.  Triggers 10% for each 250ms
that user continues holding.  Change axis math to support arbitrary
ranges beyond [0,5GB].

Show "empty" message when no application details found.  Added strings
that didn't appear in default language.  Better sweep margins using
dip instead of scale units.  Format time ranges in local time instead
of UTC.  Only show dashed estimate when it would reach near warning
or limit.  Extend app usage series until "now" when buckets missing.

Bug: 5096685, 5092538, 5058158, 5058114, 5058024, 4643457
Change-Id: I45cf33f7f3baeba1bfa5b21f31cb0a12006f62fa
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index d87080f..8581421 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -182,6 +182,7 @@
 
     private DataUsageChartView mChart;
     private TextView mUsageSummary;
+    private TextView mEmpty;
 
     private View mAppDetail;
     private TextView mAppTitle;
@@ -305,6 +306,7 @@
         }
 
         mUsageSummary = (TextView) mHeader.findViewById(R.id.usage_summary);
+        mEmpty = (TextView) mHeader.findViewById(android.R.id.empty);
 
         // only assign layout transitions once first layout is finished
         mListView.getViewTreeObserver().addOnGlobalLayoutListener(mFirstLayoutListener);
@@ -986,7 +988,7 @@
 
         final long totalBytes = entry != null ? entry.rxBytes + entry.txBytes : 0;
         final String totalPhrase = Formatter.formatFileSize(context, totalBytes);
-        final String rangePhrase = formatDateRangeUtc(context, start, end);
+        final String rangePhrase = formatDateRange(context, start, end, null);
 
         mUsageSummary.setText(
                 getString(R.string.data_usage_total_during_range, totalPhrase, rangePhrase));
@@ -1002,11 +1004,18 @@
         /** {@inheritDoc} */
         public void onLoadFinished(Loader<NetworkStats> loader, NetworkStats data) {
             mAdapter.bindStats(data);
+            updateEmptyVisible();
         }
 
         /** {@inheritDoc} */
         public void onLoaderReset(Loader<NetworkStats> loader) {
             mAdapter.bindStats(null);
+            updateEmptyVisible();
+        }
+
+        private void updateEmptyVisible() {
+            final boolean isEmpty = mAdapter.isEmpty() && !isAppDetailMode();
+            mEmpty.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
         }
     };
 
@@ -1063,7 +1072,7 @@
         }
 
         public CycleItem(Context context, long start, long end) {
-            this.label = formatDateRangeUtc(context, start, end);
+            this.label = formatDateRange(context, start, end, Time.TIMEZONE_UTC);
             this.start = start;
             this.end = end;
         }
@@ -1078,7 +1087,7 @@
     private static final java.util.Formatter sFormatter = new java.util.Formatter(
             sBuilder, Locale.getDefault());
 
-    private static String formatDateRangeUtc(Context context, long start, long end) {
+    private static String formatDateRange(Context context, long start, long end, String timezone) {
         synchronized (sBuilder) {
             int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH;
             if (Time.getJulianDay(start, 0) == Time.getJulianDay(end, 0)) {
@@ -1087,8 +1096,8 @@
             }
 
             sBuilder.setLength(0);
-            return DateUtils.formatDateRange(
-                    context, sFormatter, start, end, flags, Time.TIMEZONE_UTC).toString();
+            return DateUtils
+                    .formatDateRange(context, sFormatter, start, end, flags, timezone).toString();
         }
     }
 
@@ -1197,7 +1206,7 @@
 
         @Override
         public long getItemId(int position) {
-            return position;
+            return mItems.get(position).uid;
         }
 
         @Override