Start cleaning up percentage formatting in Settings.

This fixes some of the percentage formatting issues, but there are
still about ten strings with hard-coded %%s in them.

Bug: 15476051
Change-Id: I668b6b16e598425f6006f6de0005c980f613f5b2
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 47ff6af..6adea9c 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -61,6 +61,8 @@
 import android.provider.ContactsContract.RawContacts;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.telephony.TelephonyManager;
+import android.text.BidiFormatter;
+import android.text.TextDirectionHeuristics;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
@@ -76,6 +78,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.InetAddress;
+import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -123,6 +126,10 @@
 
     private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
 
+    private static final int SECONDS_PER_MINUTE = 60;
+    private static final int SECONDS_PER_HOUR = 60 * 60;
+    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
+
     /**
      * Finds a matching activity for a preference's intent. If a matching
      * activity is not found, it will remove the preference.
@@ -314,12 +321,28 @@
         }
     }
 
+    /** Formats the ratio of amount/total as a percentage. */
+    public static String formatPercentage(long amount, long total) {
+        return formatPercentage(((double) amount) / total);
+    }
+
+    /** Formats an integer from 0..100 as a percentage. */
+    public static String formatPercentage(int percentage) {
+        return formatPercentage(((double) percentage) / 100.0);
+    }
+
+    /** Formats a double from 0.0..1.0 as a percentage. */
+    private static String formatPercentage(double percentage) {
+      BidiFormatter bf = BidiFormatter.getInstance();
+      return bf.unicodeWrap(NumberFormat.getPercentInstance().format(percentage));
+    }
+
     public static boolean isBatteryPresent(Intent batteryChangedIntent) {
         return batteryChangedIntent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
     }
 
     public static String getBatteryPercentage(Intent batteryChangedIntent) {
-        return String.valueOf(getBatteryLevel(batteryChangedIntent)) + "%";
+        return formatPercentage(getBatteryLevel(batteryChangedIntent));
     }
 
     public static int getBatteryLevel(Intent batteryChangedIntent) {
@@ -871,4 +894,58 @@
         return null;
     }
 
+    /**
+     * Returns elapsed time for the given millis, in the following format:
+     * 2d 5h 40m 29s
+     * @param context the application context
+     * @param millis the elapsed time in milli seconds
+     * @param withSeconds include seconds?
+     * @return the formatted elapsed time
+     */
+    public static String formatElapsedTime(Context context, double millis, boolean withSeconds) {
+        StringBuilder sb = new StringBuilder();
+        int seconds = (int) Math.floor(millis / 1000);
+        if (!withSeconds) {
+            // Round up.
+            seconds += 30;
+        }
+
+        int days = 0, hours = 0, minutes = 0;
+        if (seconds >= SECONDS_PER_DAY) {
+            days = seconds / SECONDS_PER_DAY;
+            seconds -= days * SECONDS_PER_DAY;
+        }
+        if (seconds >= SECONDS_PER_HOUR) {
+            hours = seconds / SECONDS_PER_HOUR;
+            seconds -= hours * SECONDS_PER_HOUR;
+        }
+        if (seconds >= SECONDS_PER_MINUTE) {
+            minutes = seconds / SECONDS_PER_MINUTE;
+            seconds -= minutes * SECONDS_PER_MINUTE;
+        }
+        if (withSeconds) {
+            if (days > 0) {
+                sb.append(context.getString(R.string.battery_history_days,
+                        days, hours, minutes, seconds));
+            } else if (hours > 0) {
+                sb.append(context.getString(R.string.battery_history_hours,
+                        hours, minutes, seconds));
+            } else if (minutes > 0) {
+                sb.append(context.getString(R.string.battery_history_minutes, minutes, seconds));
+            } else {
+                sb.append(context.getString(R.string.battery_history_seconds, seconds));
+            }
+        } else {
+            if (days > 0) {
+                sb.append(context.getString(R.string.battery_history_days_no_seconds,
+                        days, hours, minutes));
+            } else if (hours > 0) {
+                sb.append(context.getString(R.string.battery_history_hours_no_seconds,
+                        hours, minutes));
+            } else {
+                sb.append(context.getString(R.string.battery_history_minutes_no_seconds, minutes));
+            }
+        }
+        return sb.toString();
+    }
 }
diff --git a/src/com/android/settings/applications/ProcessStatsDetail.java b/src/com/android/settings/applications/ProcessStatsDetail.java
index 5d0660a..30f6b52 100644
--- a/src/com/android/settings/applications/ProcessStatsDetail.java
+++ b/src/com/android/settings/applications/ProcessStatsDetail.java
@@ -39,6 +39,7 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 import com.android.settings.R;
+import com.android.settings.Utils;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -72,11 +73,6 @@
     private ViewGroup mDetailsParent;
     private ViewGroup mServicesParent;
 
-    public static String makePercentString(Resources res, long amount, long total) {
-        final double percent = (((double)amount) / total) * 100;
-        return res.getString(R.string.percentage, (int) Math.round(percent));
-    }
-
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -116,7 +112,7 @@
         final double percentOfWeight = (((double)mEntry.mWeight) / mMaxWeight) * 100;
 
         int appLevel = (int) Math.ceil(percentOfWeight);
-        String appLevelText = makePercentString(getResources(), mEntry.mDuration, mTotalTime);
+        String appLevelText = Utils.formatPercentage(mEntry.mDuration, mTotalTime);
 
         // Set all values in the header.
         final TextView summary = (TextView) mRootView.findViewById(android.R.id.summary);
@@ -203,7 +199,7 @@
                 Formatter.formatShortFileSize(getActivity(),
                         (mUseUss ? mEntry.mMaxUss : mEntry.mMaxPss) * 1024));
         addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_run_time),
-                makePercentString(getResources(), mEntry.mDuration, mTotalTime));
+                Utils.formatPercentage(mEntry.mDuration, mTotalTime));
     }
 
     final static Comparator<ProcStatsEntry.Service> sServiceCompare
@@ -265,10 +261,8 @@
                     if (tail >= 0 && tail < (label.length()-1)) {
                         label = label.substring(tail+1);
                     }
-                    long duration = service.mDuration;
-                    final double percentOfTime = (((double)duration) / mTotalTime) * 100;
-                    addDetailsItem(mServicesParent, label, getActivity().getResources().getString(
-                            R.string.percentage, (int) Math.ceil(percentOfTime)));
+                    String percentage = Utils.formatPercentage(service.mDuration, mTotalTime);
+                    addDetailsItem(mServicesParent, label, percentage);
                 }
             }
         }
diff --git a/src/com/android/settings/applications/ProcessStatsPreference.java b/src/com/android/settings/applications/ProcessStatsPreference.java
index 197f00a..adf80e5 100644
--- a/src/com/android/settings/applications/ProcessStatsPreference.java
+++ b/src/com/android/settings/applications/ProcessStatsPreference.java
@@ -26,6 +26,7 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 import com.android.settings.R;
+import com.android.settings.Utils;
 
 public class ProcessStatsPreference extends Preference {
     private ProcStatsEntry mEntry;
@@ -61,8 +62,7 @@
 
     public void setPercent(double percentOfWeight, double percentOfTime) {
         mProgress = (int) Math.ceil(percentOfWeight);
-        mProgressText = getContext().getResources().getString(
-                R.string.percentage, (int) Math.round(percentOfTime));
+        mProgressText = Utils.formatPercentage((int) percentOfTime);
         notifyChanged();
     }
 
diff --git a/src/com/android/settings/applications/ProcessStatsUi.java b/src/com/android/settings/applications/ProcessStatsUi.java
index 269ff39..03e4b75 100644
--- a/src/com/android/settings/applications/ProcessStatsUi.java
+++ b/src/com/android/settings/applications/ProcessStatsUi.java
@@ -43,7 +43,7 @@
 import com.android.internal.util.MemInfoReader;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
-import com.android.settings.fuelgauge.Utils;
+import com.android.settings.Utils;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryChart.java b/src/com/android/settings/fuelgauge/BatteryHistoryChart.java
index 9d3edd5..7aebb17 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistoryChart.java
+++ b/src/com/android/settings/fuelgauge/BatteryHistoryChart.java
@@ -26,6 +26,7 @@
 import android.util.Log;
 import android.util.TimeUtils;
 import com.android.settings.R;
+import com.android.settings.Utils;
 
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -489,10 +490,8 @@
         mCpuRunningLabel = getContext().getString(R.string.battery_stats_wake_lock_label);
         mPhoneSignalLabel = getContext().getString(R.string.battery_stats_phone_signal_label);
 
-        mMaxPercentLabelString = getContext().getResources().getString(
-                R.string.percentage, 100);
-        mMinPercentLabelString = getContext().getResources().getString(
-                R.string.percentage, 0);
+        mMaxPercentLabelString = Utils.formatPercentage(100);
+        mMinPercentLabelString = Utils.formatPercentage(0);
 
         mBatteryLevel = com.android.settings.Utils.getBatteryLevel(mBatteryBroadcast);
         long remainingTimeUs = 0;
@@ -506,8 +505,7 @@
                 mChargeLabelString = getContext().getResources().getString(
                         R.string.power_discharging_duration, mBatteryLevel, timeString);
             } else {
-                mChargeLabelString = getContext().getResources().getString(
-                        R.string.power_discharging, mBatteryLevel);
+                mChargeLabelString = Utils.formatPercentage(mBatteryLevel);
             }
         } else {
             final long chargeTime = mStats.computeChargeTimeRemaining(elapsedRealtimeUs);
diff --git a/src/com/android/settings/fuelgauge/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
index a558533..97012e4 100644
--- a/src/com/android/settings/fuelgauge/PowerGaugePreference.java
+++ b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
@@ -25,6 +25,7 @@
 import android.widget.TextView;
 
 import com.android.settings.R;
+import com.android.settings.Utils;
 
 /**
  * Custom preference for displaying power consumption as a bar and an icon on
@@ -47,8 +48,7 @@
 
     public void setPercent(double percentOfMax, double percentOfTotal) {
         mProgress = (int) Math.ceil(percentOfMax);
-        mProgressText = getContext().getResources().getString(
-                R.string.percentage, (int) (percentOfTotal+.5));
+        mProgressText = Utils.formatPercentage((int) (percentOfTotal + 0.5));
         notifyChanged();
     }
 
diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
index fe4fd81..b745c9d 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
@@ -53,6 +53,7 @@
 import com.android.settings.DisplaySettings;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
 import com.android.settings.WirelessSettings;
 import com.android.settings.applications.InstalledAppDetails;
 import com.android.settings.bluetooth.BluetoothSettings;
@@ -387,7 +388,7 @@
         mTitleView.setText(mTitle);
 
         final TextView text1 = (TextView)mRootView.findViewById(android.R.id.text1);
-        text1.setText(getString(R.string.percentage, percentage));
+        text1.setText(Utils.formatPercentage(percentage));
 
         mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel);
         mForceStopButton = (Button)mRootView.findViewById(R.id.left_button);
@@ -507,7 +508,7 @@
                         break;
                     case R.string.usage_type_no_coverage:
                         final int percentage = (int) Math.floor(mValues[i]);
-                        value = getActivity().getString(R.string.percentage, percentage);
+                        value = Utils.formatPercentage(percentage);
                         break;
                     case R.string.usage_type_total_battery_capacity:
                     case R.string.usage_type_computed_power:
diff --git a/src/com/android/settings/fuelgauge/Utils.java b/src/com/android/settings/fuelgauge/Utils.java
deleted file mode 100644
index 9a06c9f..0000000
--- a/src/com/android/settings/fuelgauge/Utils.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-import android.content.Context;
-
-import com.android.settings.R;
-
-/**
- * Contains utility functions for formatting elapsed time and consumed bytes
- */
-public class Utils {
-    private static final int SECONDS_PER_MINUTE = 60;
-    private static final int SECONDS_PER_HOUR = 60 * 60;
-    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
-
-    /**
-     * Returns elapsed time for the given millis, in the following format:
-     * 2d 5h 40m 29s
-     * @param context the application context
-     * @param millis the elapsed time in milli seconds
-     * @return the formatted elapsed time
-     */
-    public static String formatElapsedTime(Context context, double millis, boolean inclSeconds) {
-        StringBuilder sb = new StringBuilder();
-        int seconds = (int) Math.floor(millis / 1000);
-        if (!inclSeconds) {
-            // Round up.
-            seconds += 30;
-        }
-
-        int days = 0, hours = 0, minutes = 0;
-        if (seconds >= SECONDS_PER_DAY) {
-            days = seconds / SECONDS_PER_DAY;
-            seconds -= days * SECONDS_PER_DAY;
-        }
-        if (seconds >= SECONDS_PER_HOUR) {
-            hours = seconds / SECONDS_PER_HOUR;
-            seconds -= hours * SECONDS_PER_HOUR;
-        }
-        if (seconds >= SECONDS_PER_MINUTE) {
-            minutes = seconds / SECONDS_PER_MINUTE;
-            seconds -= minutes * SECONDS_PER_MINUTE;
-        }
-        if (inclSeconds) {
-            if (days > 0) {
-                sb.append(context.getString(R.string.battery_history_days,
-                        days, hours, minutes, seconds));
-            } else if (hours > 0) {
-                sb.append(context.getString(R.string.battery_history_hours,
-                        hours, minutes, seconds));
-            } else if (minutes > 0) {
-                sb.append(context.getString(R.string.battery_history_minutes, minutes, seconds));
-            } else {
-                sb.append(context.getString(R.string.battery_history_seconds, seconds));
-            }
-        } else {
-            if (days > 0) {
-                sb.append(context.getString(R.string.battery_history_days_no_seconds,
-                        days, hours, minutes));
-            } else if (hours > 0) {
-                sb.append(context.getString(R.string.battery_history_hours_no_seconds,
-                        hours, minutes));
-            } else {
-                sb.append(context.getString(R.string.battery_history_minutes_no_seconds, minutes));
-            }
-        }
-        return sb.toString();
-    }
-}