Add Emergency Calls Only and Charging State to Status Bar Header

Bug: 15393101
Change-Id: If1dc300d843fb5f694ef57714225f43924dbb2b8
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 693d8c3..d24d21e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -35,12 +35,65 @@
         android:background="@drawable/notification_header_bg"
         android:clickable="true"
         />
+
+    <View android:id="@+id/header_spacer"
+        android:layout_height="8dp"
+        android:layout_width="0dp" />
+
+    <TextView
+        android:id="@+id/header_emergency_calls_only"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_below="@id/header_spacer"
+        android:paddingTop="12dp"
+        android:paddingStart="16dp"
+        android:paddingEnd="16dp"
+        android:visibility="gone"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
+        android:text="@*android:string/emergency_calls_only" />
+
+    <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
+        android:layout_width="40dp"
+        android:layout_height="@dimen/status_bar_header_height"
+        android:layout_alignParentEnd="true"
+        android:background="@null"
+        android:scaleType="centerInside"
+        android:padding="8dp" />
+
+    <ImageButton android:id="@+id/settings_button"
+        style="@android:style/Widget.Material.Button.Borderless"
+        android:layout_toStartOf="@id/multi_user_switch"
+        android:layout_width="56dp"
+        android:layout_height="@dimen/status_bar_header_height"
+        android:src="@drawable/ic_settings_24dp"
+        android:contentDescription="@string/accessibility_desc_quick_settings"/>
+
+    <FrameLayout android:id="@+id/system_icons_container"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/status_bar_header_height"
+        android:layout_toStartOf="@id/multi_user_switch"
+        android:layout_marginEnd="4dp"
+        android:layout_marginStart="16dp"
+        />
+
+    <TextView
+        android:id="@+id/header_charging_info"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toEndOf="@id/system_icons_container"
+        android:layout_below="@id/header_spacer"
+        android:paddingTop="12dp"
+        android:paddingEnd="16dp"
+        android:paddingStart="4dp"
+        style="@style/TextAppearance.StatusBar.Expanded.ChargingInfo"/>
+
     <RelativeLayout
         android:id="@+id/datetime"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="start"
-        android:paddingTop="16dp"
+        android:layout_below="@id/header_emergency_calls_only"
+        android:paddingTop="8dp"
         android:paddingBottom="16dp"
         android:paddingStart="16dp"
         android:paddingEnd="16dp"
@@ -65,30 +118,6 @@
             />
     </RelativeLayout>
 
-    <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
-        android:layout_width="40dp"
-        android:layout_height="@dimen/status_bar_header_height"
-        android:layout_alignParentEnd="true"
-        android:background="@null"
-        android:scaleType="centerInside"
-        android:padding="8dp"
-        />
-
-    <ImageButton android:id="@+id/settings_button"
-        style="@android:style/Widget.Material.Button.Borderless"
-        android:layout_toStartOf="@id/multi_user_switch"
-        android:layout_width="56dp"
-        android:layout_height="@dimen/status_bar_header_height"
-        android:src="@drawable/ic_settings_24dp"
-        android:contentDescription="@string/accessibility_desc_quick_settings"/>
-
-    <FrameLayout android:id="@+id/system_icons_container"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/status_bar_header_height"
-        android:layout_toStartOf="@id/multi_user_switch"
-        android:layout_marginEnd="4dp"
-        />
-
     <com.android.keyguard.CarrierText
         android:id="@+id/keyguard_carrier_text"
         android:layout_width="match_parent"
@@ -105,6 +134,8 @@
         layout="@layout/quick_settings_brightness_dialog"
         android:id="@+id/brightness_container"
         android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
         />
 
     <TextView
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index de297e5..ed32795 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -531,6 +531,18 @@
     <string name="recents_search_bar_label">search</string>
 
 
+    <!-- Expanded Status Bar Header: Battery Charged [CHAR LIMIT=40] -->
+    <string name="expanded_header_battery_charged">Charged</string>
+
+    <!-- Expanded Status Bar Header: Charging, no known time [CHAR LIMIT=40] -->
+    <string name="expanded_header_battery_charging">Charging</string>
+
+    <!-- Expanded Status Bar Header: Charging, showing time left until charged [CHAR LIMIT=40] -->
+    <string name="expanded_header_battery_charging_with_time"><xliff:g id="charging_time" example="2 hrs 25 min">%s</xliff:g> until full</string>
+
+    <!-- Expanded Status Bar Header: Not charging [CHAR LIMIT=40] -->
+    <string name="expanded_header_battery_not_charging">Not charging</string>
+
     <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
     <string name="battery_meter_very_low_overlay_symbol">!</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b0b018d..43560a3 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -70,17 +70,29 @@
     <style name="TextAppearance.StatusBar.Expanded" parent="@*android:style/TextAppearance.StatusBar" />
 
     <style name="TextAppearance.StatusBar.Expanded.Clock">
-        <item name="android:textSize">18dp</item>
+        <item name="android:textSize">16dp</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">#ffffff</item>
     </style>
 
     <style name="TextAppearance.StatusBar.Expanded.Date">
+        <item name="android:textSize">14dp</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#99ffffff</item>
+    </style>
+
+    <style name="TextAppearance.StatusBar.Expanded.AboveDateTime">
         <item name="android:textSize">12dp</item>
         <item name="android:textStyle">normal</item>
-        <item name="android:textColor">#afb3b6</item>
+        <item name="android:textColor">#99ffffff</item>
     </style>
 
+    <style name="TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
+           parent="TextAppearance.StatusBar.Expanded.AboveDateTime" />
+
+    <style name="TextAppearance.StatusBar.Expanded.ChargingInfo"
+            parent="TextAppearance.StatusBar.Expanded.AboveDateTime" />
+
     <style name="TextAppearance.StatusBar.Expanded.Network" parent="@style/TextAppearance.StatusBar.Expanded.Date">
         <item name="android:textColor">#999999</item>
 	</style>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 4749b9c..f86572d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -266,7 +266,6 @@
     private TextView mCarrierLabel;
     private boolean mCarrierLabelVisible = false;
     private int mCarrierLabelHeight;
-    private TextView mEmergencyCallLabel;
     private int mStatusBarHeaderHeight;
 
     private boolean mShowCarrierInPanel = false;
@@ -720,23 +719,9 @@
 
         mNetworkController.addSignalCluster(signalCluster);
         signalCluster.setNetworkController(mNetworkController);
-
         final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
         if (isAPhone) {
-            mEmergencyCallLabel =
-                    (TextView) mStatusBarWindow.findViewById(R.id.emergency_calls_only);
-            // TODO: Uncomment when correctly positioned
-//            if (mEmergencyCallLabel != null) {
-//                mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
-//                mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
-//                    public void onClick(View v) { }});
-//                mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
-//                    @Override
-//                    public void onLayoutChange(View v, int left, int top, int right, int bottom,
-//                            int oldLeft, int oldTop, int oldRight, int oldBottom) {
-//                        updateCarrierLabelVisibility(false);
-//                    }});
-//            }
+            mNetworkController.addEmergencyLabelView(mHeader);
         }
 
         mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
@@ -762,6 +747,8 @@
 //                    updateCarrierLabelVisibility(false);
         }
 
+        mBatteryController.setStatusBarHeaderView(mHeader);
+
         // Set up the quick settings tile panel
         mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
         if (mQSPanel != null) {
@@ -1351,7 +1338,8 @@
                     mCarrierLabelHeight));
         }
 
-        final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null;
+        // Emergency calls only is shown in the expanded header now.
+        final boolean emergencyCallsShownElsewhere = true;
         final boolean makeVisible =
             !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
             && mStackScroller.getHeight() < (mNotificationPanel.getHeight()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 13d3291..1916f13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -26,6 +26,7 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
@@ -57,6 +58,11 @@
     private View mSignalCluster;
     private View mSettingsButton;
     private View mBrightnessContainer;
+    private View mEmergencyCallsOnly;
+    private TextView mChargingInfo;
+
+    private boolean mShowEmergencyCallsOnly;
+    private boolean mShowChargingInfo;
 
     private int mCollapsedHeight;
     private int mExpandedHeight;
@@ -91,6 +97,8 @@
         mBrightnessController = new BrightnessController(getContext(),
                 (ImageView) findViewById(R.id.brightness_icon),
                 (ToggleSlider) findViewById(R.id.brightness_slider));
+        mEmergencyCallsOnly = findViewById(R.id.header_emergency_calls_only);
+        mChargingInfo = (TextView) findViewById(R.id.header_charging_info);
         loadDimens();
         updateVisibilities();
         addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@@ -195,13 +203,32 @@
         if (mSignalCluster != null) {
             mSignalCluster.setVisibility(!mExpanded || mOverscrolled ? View.VISIBLE : View.GONE);
         }
+        mEmergencyCallsOnly.setVisibility(mExpanded && !mOverscrolled && mShowEmergencyCallsOnly
+                ? VISIBLE : GONE);
+        mChargingInfo.setVisibility(mExpanded && !mOverscrolled && mShowChargingInfo
+                && !mShowEmergencyCallsOnly ? VISIBLE : GONE);
     }
 
     private void updateSystemIconsLayoutParams() {
         RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsContainer.getLayoutParams();
-        lp.addRule(RelativeLayout.START_OF, mExpanded
-                ? mSettingsButton.getId()
-                : mMultiUserSwitch.getId());
+        boolean systemIconsAboveClock = mExpanded && !mOverscrolled
+                && mShowChargingInfo && !mShowEmergencyCallsOnly;
+        if (systemIconsAboveClock) {
+            lp.addRule(ALIGN_PARENT_START);
+            lp.removeRule(START_OF);
+        } else {
+            lp.addRule(RelativeLayout.START_OF, mExpanded
+                    ? mSettingsButton.getId()
+                    : mMultiUserSwitch.getId());
+            lp.removeRule(ALIGN_PARENT_START);
+        }
+
+        RelativeLayout.LayoutParams clockLp = (LayoutParams) mDateTime.getLayoutParams();
+        if (systemIconsAboveClock) {
+            clockLp.addRule(BELOW, mChargingInfo.getId());
+        } else {
+            clockLp.addRule(BELOW, mEmergencyCallsOnly.getId());
+        }
     }
 
     private void updateBrightnessControllerState() {
@@ -307,4 +334,24 @@
             mBrightnessContainer.animate().alpha(showingDetail ? 0 : 1).withLayer().start();
         }
     };
+
+    public void setShowEmergencyCallsOnly(boolean show) {
+        mShowEmergencyCallsOnly = show;
+        if (mExpanded) {
+            updateVisibilities();
+            updateSystemIconsLayoutParams();
+        }
+    }
+
+    public void setShowChargingInfo(boolean showChargingInfo) {
+        mShowChargingInfo = showChargingInfo;
+        if (mExpanded) {
+            updateVisibilities();
+            updateSystemIconsLayoutParams();
+        }
+    }
+
+    public void setChargingInfo(CharSequence chargingInfo) {
+        mChargingInfo.setText(chargingInfo);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 6db9bc3..4cf66a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -16,26 +16,49 @@
 
 package com.android.systemui.statusbar.policy;
 
+import com.android.internal.app.IBatteryStats;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarHeaderView;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.format.Formatter;
+import android.util.Log;
 
 import java.util.ArrayList;
 
 public class BatteryController extends BroadcastReceiver {
     private static final String TAG = "StatusBar.BatteryController";
 
-
     private ArrayList<BatteryStateChangeCallback> mChangeCallbacks =
             new ArrayList<BatteryStateChangeCallback>();
 
+    private Context mContext;
+    private StatusBarHeaderView mStatusBarHeaderView;
+    private IBatteryStats mBatteryInfo;
+
+    private int mLevel;
+    private boolean mPluggedIn;
+    private boolean mCharging;
+    private boolean mCharged;
+
+
     public interface BatteryStateChangeCallback {
-        public void onBatteryLevelChanged(int level, boolean pluggedIn);
+        public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging);
     }
 
     public BatteryController(Context context) {
+        mContext = context;
+
+        mBatteryInfo = IBatteryStats.Stub.asInterface(
+                ServiceManager.getService(BatteryStats.SERVICE_NAME));
+
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
         context.registerReceiver(this, filter);
@@ -45,24 +68,59 @@
         mChangeCallbacks.add(cb);
     }
 
+    public void setStatusBarHeaderView(StatusBarHeaderView statusBarHeaderView) {
+        mStatusBarHeaderView = statusBarHeaderView;
+        updateStatusBarHeaderView();
+    }
+
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
         if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
-            final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
+            mLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
+            mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
+
             final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
                     BatteryManager.BATTERY_STATUS_UNKNOWN);
+            mCharged = status == BatteryManager.BATTERY_STATUS_FULL;
+            mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING;
 
-            boolean plugged = false;
-            switch (status) {
-                case BatteryManager.BATTERY_STATUS_CHARGING:
-                case BatteryManager.BATTERY_STATUS_FULL:
-                    plugged = true;
-                    break;
-            }
-
+            updateStatusBarHeaderView();
             for (BatteryStateChangeCallback cb : mChangeCallbacks) {
-                cb.onBatteryLevelChanged(level, plugged);
+                cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
             }
         }
     }
+
+    private void updateStatusBarHeaderView() {
+        if (mStatusBarHeaderView != null) {
+            mStatusBarHeaderView.setShowChargingInfo(mPluggedIn);
+            mStatusBarHeaderView.setChargingInfo(computeChargingInfo());
+        }
+    }
+
+    private String computeChargingInfo() {
+        if (!mPluggedIn || !mCharged && !mCharging) {
+            return mContext.getResources().getString(R.string.expanded_header_battery_not_charging);
+        }
+
+        if (mCharged) {
+            return mContext.getResources().getString(R.string.expanded_header_battery_charged);
+        }
+
+        // Try fetching charging time from battery stats.
+        try {
+            long chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
+            if (chargingTimeRemaining > 0) {
+                String chargingTimeFormatted =
+                        Formatter.formatShortElapsedTime(mContext, chargingTimeRemaining);
+                return mContext.getResources().getString(
+                        R.string.expanded_header_battery_charging_with_time, chargingTimeFormatted);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IBatteryStats: ", e);
+        }
+
+        // Fall back to simple charging label.
+        return mContext.getResources().getString(R.string.expanded_header_battery_charging);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 56402a5..bf908fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -47,6 +47,7 @@
 import com.android.internal.util.AsyncChannel;
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarHeaderView;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -143,7 +144,7 @@
     ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
     ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
     ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
-    ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
+    ArrayList<StatusBarHeaderView> mEmergencyViews = new ArrayList<>();
     ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
     ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
             new ArrayList<NetworkSignalChangedCallback>();
@@ -261,8 +262,8 @@
         mWifiLabelViews.add(v);
     }
 
-    public void addEmergencyLabelView(TextView v) {
-        mEmergencyLabelViews.add(v);
+    public void addEmergencyLabelView(StatusBarHeaderView v) {
+        mEmergencyViews.add(v);
     }
 
     public void addSignalCluster(SignalCluster cluster) {
@@ -1251,15 +1252,10 @@
         }
 
         // e-call label
-        N = mEmergencyLabelViews.size();
+        N = mEmergencyViews.size();
         for (int i=0; i<N; i++) {
-            TextView v = mEmergencyLabelViews.get(i);
-            if (!emergencyOnly) {
-                v.setVisibility(View.GONE);
-            } else {
-                v.setText(mobileLabel); // comes from the telephony stack
-                v.setVisibility(View.VISIBLE);
-            }
+            StatusBarHeaderView v = mEmergencyViews.get(i);
+            v.setShowEmergencyCallsOnly(emergencyOnly);
         }
     }