Merge "Hide "Use network recommendations" in Settings."
diff --git a/res/drawable/ic_battery_circle.xml b/res/drawable/ic_battery_circle.xml
new file mode 100644
index 0000000..5c736fd
--- /dev/null
+++ b/res/drawable/ic_battery_circle.xml
@@ -0,0 +1,24 @@
+<!--
+     Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorControlNormal">
+    <path android:fillColor="#FF000000"
+          android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout/app_details.xml b/res/layout/app_details.xml
index 7994a4c..9f349de 100644
--- a/res/layout/app_details.xml
+++ b/res/layout/app_details.xml
@@ -24,36 +24,56 @@
     android:layout_gravity="center_horizontal|top"
     android:orientation="vertical"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingTop="24dp"
+    android:paddingBottom="24dp" >
 
     <!-- App snippet with buttons -->
-    <ImageView
-        android:id="@android:id/icon"
-        android:layout_width="80dp"
-        android:layout_height="80dp"
-        android:scaleType="fitXY"
-        android:layout_gravity="center_horizontal"
-        android:antialias="true"/>
-
-    <TextView
-        android:id="@android:id/title"
-        style="@style/TextAppearance.EntityHeaderTitle"
+    <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:gravity="center_horizontal"
-        android:paddingTop="8dp"/>
+        android:paddingStart="8dp"
+        android:paddingEnd="8dp"
+        android:orientation="horizontal">
 
-    <TextView
-        android:id="@android:id/summary"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:textAppearance="@android:style/TextAppearance.Material.Body1"
-        android:textColor="?android:attr/textColorSecondary"/>
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="80dp"
+            android:layout_height="80dp"
+            android:scaleType="fitXY"
+            android:layout_gravity="center_horizontal"
+            android:antialias="true"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingStart="24dp"
+            android:paddingEnd="24dp"
+            android:orientation="vertical">
+
+            <TextView
+                android:id="@android:id/title"
+                style="@style/TextAppearance.EntityHeaderTitle"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:gravity="start"
+                android:paddingTop="8dp"/>
+
+            <TextView
+                android:id="@android:id/summary"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="start"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textColor="?android:attr/textColorSecondary"/>
+
+        </LinearLayout>
+
+    </LinearLayout>
 
     <LinearLayout
         android:id="@+id/app_detail_links"
diff --git a/res/layout/preference_category_material_settings.xml b/res/layout/preference_category_material_settings.xml
index e9ce9b5..de53ce2 100644
--- a/res/layout/preference_category_material_settings.xml
+++ b/res/layout/preference_category_material_settings.xml
@@ -21,9 +21,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_marginBottom="16dp"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingTop="16dp">
+    android:layout_marginTop="8dp"
+    android:layout_marginBottom="8dp"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart" >
 
     <LinearLayout
         android:id="@+id/icon_container"
@@ -47,6 +47,7 @@
         android:orientation="vertical">
         <TextView
             android:id="@android:id/title"
+            android:layout_marginTop="16dp"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:textAppearance="@android:style/TextAppearance.Material.Body2"
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 7d9ab4a..d099cdc 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -153,4 +153,8 @@
         <attr name="aspectRatio" format="float" />
     </declare-styleable>
 
+    <declare-styleable name="TintablePreference">
+        <attr name="android:tint" format="color|reference"/>
+    </declare-styleable>
+
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 776a510..b74ad5d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4312,7 +4312,9 @@
     <!-- Bluetooth on time -->
     <string name="bluetooth_on_time">Wi\u2011Fi on time</string>
 
-    <!-- Activity title for battery usage history details -->
+    <!-- Activity title for advanced battery usage page [CHAR LIMIT=60] -->
+    <string name="advanced_battery_title">Advanced battery usage</string>
+    <!-- Activity title for battery usage history details [CHAR LIMIT=60] -->
     <string name="history_details_title">History details</string>
 
     <!-- Activity title for battery usage details for an app. or power consumer -->
@@ -4346,6 +4348,14 @@
     <string name="power_unaccounted">Miscellaneous</string>
     <!-- Label for power that we computed too much for -->
     <string name="power_overcounted">Over-counted</string>
+    <!-- Label for power consumed by apps [CHAR LIMIT=30] -->
+    <string name="power_apps">Apps</string>
+    <!-- Label for power consumed by services [CHAR LIMIT=30] -->
+    <string name="power_service">Services</string>
+    <!-- Label for power consumed by system [CHAR LIMIT=30] -->
+    <string name="power_system">System</string>
+    <!-- Label for power consumed by user [CHAR LIMIT=30] -->
+    <string name="power_user">User</string>
 
     <!-- Label for CPU usage time -->
     <string name="usage_type_cpu">CPU total</string>
@@ -4465,6 +4475,8 @@
 
     <!-- Description for battery usage time for an app, i.e. Used for 30min. [CHAR LIMIT=60] -->
     <string name="battery_used_for">Used for %1$s</string>
+    <!-- Description for battery usage detail information since last full charge. [CHAR LIMIT=120] -->
+    <string name="battery_detail_since_full_charge">Usage breakdown since last full charge</string>
 
     <!-- Menu label for viewing battery usage since unplugged -->
     <string name="menu_stats_unplugged"><xliff:g id="unplugged">%1$s</xliff:g> since unplugged</string>
@@ -6369,7 +6381,10 @@
     <string name="loading_notification_apps">Loading apps...</string>
 
     <!-- [CHAR LIMIT=NONE] App notification settings: channels title -->
-    <string name="notification_channels">Channels</string>
+    <string name="notification_channels">Categories</string>
+
+    <!-- [CHAR LIMIT=NONE] App notification settings: non-grouped-channels title -->
+    <string name="notification_channels_other">Other</string>
 
     <!-- [CHAR LIMIT=NONE] App notification settings: no channels -->
     <string name="no_channels">This app has not posted any notifications</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 092d997..2f6f120 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -433,5 +433,4 @@
     </style>
 
     <style name="AppActionPrimaryButton" parent="android:Widget.Material.Button.Colored"/>
-
 </resources>
diff --git a/res/xml/app_default_settings.xml b/res/xml/app_default_settings.xml
index 404fb82..b99051d 100644
--- a/res/xml/app_default_settings.xml
+++ b/res/xml/app_default_settings.xml
@@ -94,8 +94,8 @@
         </Preference>
 
         <Preference
-            android:key="work_default_phone_app_new"
-            android:title="new phone pref work"
+            android:key="work_default_phone_app"
+            android:title="@string/default_phone_title"
             android:fragment="com.android.settings.applications.defaultapps.DefaultPhonePicker"
             settings:keywords="@string/keywords_default_phone_app">
             <extra android:name="for_work" android:value="true"/>
diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml
index c68e456..ef8a45c 100644
--- a/res/xml/app_notification_settings.xml
+++ b/res/xml/app_notification_settings.xml
@@ -34,8 +34,4 @@
         settings:useAdditionalSummary="true"
         settings:restrictedSwitchSummary="@string/enabled_by_admin" />
 
-    <PreferenceCategory
-            android:key="channels"
-            android:title="@string/notification_channels" />
-
 </PreferenceScreen>
diff --git a/res/xml/installed_app_details_ia.xml b/res/xml/installed_app_details_ia.xml
index f4603ed..e72384a 100644
--- a/res/xml/installed_app_details_ia.xml
+++ b/res/xml/installed_app_details_ia.xml
@@ -23,6 +23,16 @@
         android:selectable="false"/>
 
     <Preference
+        android:key="notification_settings"
+        android:title="@string/notifications_label"
+        android:selectable="true"/>
+
+    <Preference
+        android:key="permission_settings"
+        android:title="@string/permissions_label"
+        android:selectable="true"/>
+
+    <Preference
         android:key="storage_settings"
         android:title="@string/storage_settings"
         android:selectable="true"/>
@@ -33,13 +43,8 @@
         android:selectable="true"/>
 
     <Preference
-        android:key="permission_settings"
-        android:title="@string/permissions_label"
-        android:selectable="true"/>
-
-    <Preference
-        android:key="notification_settings"
-        android:title="@string/notifications_label"
+        android:key="battery"
+        android:title="@string/power_usage_summary_title"
         android:selectable="true"/>
 
     <Preference
@@ -48,11 +53,6 @@
         android:selectable="true"/>
 
     <Preference
-        android:key="battery"
-        android:title="@string/power_usage_summary_title"
-        android:selectable="true"/>
-
-    <Preference
         android:key="memory"
         android:title="@string/memory_settings_title"
         android:enabled="false"
diff --git a/res/xml/power_usage_advanced.xml b/res/xml/power_usage_advanced.xml
new file mode 100644
index 0000000..6422a75
--- /dev/null
+++ b/res/xml/power_usage_advanced.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
+    android:title="@string/advanced_battery_title"
+    settings:keywords="@string/keywords_battery">
+
+    <com.android.settings.fuelgauge.BatteryHistoryPreference
+        android:key="battery_graph"/>
+
+    <PreferenceCategory
+        android:key="battery_usage_list"
+        android:title="@string/battery_detail_since_full_charge">
+
+        <com.android.settings.fuelgauge.PowerGaugePreference
+            android:key="battery_apps"
+            android:title="@string/power_apps"/>
+
+        <com.android.settings.fuelgauge.PowerGaugePreference
+            android:key="battery_wifi"
+            android:title="@string/power_wifi"/>
+
+        <com.android.settings.fuelgauge.PowerGaugePreference
+            android:key="battery_cell"
+            android:title="@string/power_cell"/>
+
+        <com.android.settings.fuelgauge.PowerGaugePreference
+            android:key="battery_service"
+            android:title="@string/power_service"/>
+
+        <com.android.settings.fuelgauge.PowerGaugePreference
+            android:key="battery_system"
+            android:title="@string/power_system"/>
+
+        <com.android.settings.fuelgauge.PowerGaugePreference
+            android:key="battery_bluetooth"
+            android:title="@string/power_bluetooth"/>
+
+        <com.android.settings.fuelgauge.PowerGaugePreference
+            android:key="battery_idle"
+            android:title="@string/power_idle"/>
+
+        <com.android.settings.fuelgauge.PowerGaugePreference
+            android:key="battery_user"
+            android:title="@string/power_user"/>
+
+    </PreferenceCategory>
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/TintablePreference.java b/src/com/android/settings/TintablePreference.java
index 45f43fb..2e1fd3d 100644
--- a/src/com/android/settings/TintablePreference.java
+++ b/src/com/android/settings/TintablePreference.java
@@ -17,17 +17,23 @@
 
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.support.annotation.ColorInt;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.util.AttributeSet;
 import android.widget.ImageView;
 
 public class TintablePreference extends Preference {
-
+    @ColorInt
     private int mTintColor;
 
     public TintablePreference(Context context, AttributeSet attrs) {
         super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TintablePreference);
+        mTintColor = a.getColor(R.styleable.TintablePreference_android_tint, 0);
+        a.recycle();
     }
 
     public void setTint(int color) {
diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
index ea196ad..6ec1b73 100644
--- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
@@ -17,9 +17,7 @@
 package com.android.settings.deviceinfo;
 
 import android.content.Context;
-import android.content.Loader;
 import android.os.Bundle;
-import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 import android.provider.SearchIndexableResource;
@@ -29,7 +27,6 @@
 import com.android.settings.R;
 import com.android.settings.core.PreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.deviceinfo.storage.AppsAsyncLoader;
 import com.android.settings.deviceinfo.storage.StorageItemPreferenceController;
 import com.android.settings.deviceinfo.storage.StorageSummaryDonutPreferenceController;
 import com.android.settings.overlay.FeatureFactory;
@@ -37,7 +34,6 @@
 import com.android.settings.search.Indexable;
 import com.android.settings.widget.FooterPreference;
 import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
-import com.android.settingslib.drawer.CategoryKey;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -88,7 +84,6 @@
         mSummaryController.updateBytes(usedBytes, totalSize);
         mPreferenceController.setVolume(mVolume);
         mPreferenceController.setSystemSize(systemSize);
-        mPreferenceController.startMeasurement();
 
         // Initialize the footer preference to go to the smart storage management.
         final FooterPreference pref = mFooterPreferenceMixin.createFooterPreference();
@@ -120,7 +115,7 @@
         controllers.add(mSummaryController);
 
         StorageManager sm = context.getSystemService(StorageManager.class);
-        mPreferenceController = new StorageItemPreferenceController(context, getLifecycle(), this,
+        mPreferenceController = new StorageItemPreferenceController(context, this,
                 mVolume, new StorageManagerVolumeProvider(sm));
         controllers.add(mPreferenceController);
         controllers.add(new ManageStoragePreferenceController(context));
diff --git a/src/com/android/settings/deviceinfo/UsbBackend.java b/src/com/android/settings/deviceinfo/UsbBackend.java
index e648b39..2011638 100644
--- a/src/com/android/settings/deviceinfo/UsbBackend.java
+++ b/src/com/android/settings/deviceinfo/UsbBackend.java
@@ -24,6 +24,7 @@
 import android.hardware.usb.UsbPortStatus;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
 
 public class UsbBackend {
 
@@ -41,7 +42,6 @@
     private final boolean mRestrictedBySystem;
     private final boolean mMidi;
 
-    private UserManager mUserManager;
     private UsbManager mUsbManager;
     private UsbPort mPort;
     private UsbPortStatus mPortStatus;
@@ -49,20 +49,26 @@
     private boolean mIsUnlocked;
 
     public UsbBackend(Context context) {
+        this(context, new UserRestrictionUtil(context));
+    }
+
+    @VisibleForTesting
+    UsbBackend(Context context, UserRestrictionUtil userRestrictionUtil) {
         Intent intent = context.registerReceiver(null,
                 new IntentFilter(UsbManager.ACTION_USB_STATE));
         mIsUnlocked = intent == null ?
                 false : intent.getBooleanExtra(UsbManager.USB_DATA_UNLOCKED, false);
 
-        mUserManager = UserManager.get(context);
         mUsbManager = context.getSystemService(UsbManager.class);
 
-        mRestricted = mUserManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
-        mRestrictedBySystem = mUserManager.hasBaseUserRestriction(
-                UserManager.DISALLOW_USB_FILE_TRANSFER, UserHandle.of(UserHandle.myUserId()));
+        mRestricted = userRestrictionUtil.isUsbFileTransferRestricted();
+        mRestrictedBySystem = userRestrictionUtil.isUsbFileTransferRestrictedBySystem();
         mMidi = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI);
 
         UsbPort[] ports = mUsbManager.getPorts();
+        if (ports == null) {
+            return;
+        }
         // For now look for a connected port, in the future we should identify port in the
         // notification and pick based on that.
         final int N = ports.length;
@@ -172,4 +178,22 @@
         // No port, support sink modes only.
         return (mode & MODE_POWER_MASK) != MODE_POWER_SOURCE;
     }
+
+    // Wrapper class to enable testing with UserManager APIs
+    public static class UserRestrictionUtil {
+        private UserManager mUserManager;
+
+        public UserRestrictionUtil(Context context) {
+            mUserManager = UserManager.get(context);
+        }
+
+        public boolean isUsbFileTransferRestricted() {
+            return mUserManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
+        }
+
+        public boolean isUsbFileTransferRestrictedBySystem() {
+            return mUserManager.hasBaseUserRestriction(
+                UserManager.DISALLOW_USB_FILE_TRANSFER, UserHandle.of(UserHandle.myUserId()));
+        }
+    }
 }
diff --git a/src/com/android/settings/deviceinfo/storage/AppsAsyncLoader.java b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java
similarity index 73%
rename from src/com/android/settings/deviceinfo/storage/AppsAsyncLoader.java
rename to src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java
index cbedb08..b16590e 100644
--- a/src/com/android/settings/deviceinfo/storage/AppsAsyncLoader.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java
@@ -16,8 +16,12 @@
 
 package com.android.settings.deviceinfo.storage;
 
+import static android.content.pm.ApplicationInfo.CATEGORY_AUDIO;
+import static android.content.pm.ApplicationInfo.CATEGORY_GAME;
+
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.os.UserHandle;
 import android.util.ArraySet;
 
 import com.android.settings.applications.PackageManagerWrapper;
@@ -29,13 +33,13 @@
  * AppsAsyncLoader is a Loader which loads app storage information and categories it by the app's
  * specified categorization.
  */
-public class AppsAsyncLoader extends AsyncLoader<AppsAsyncLoader.AppsStorageResult> {
+public class StorageAsyncLoader extends AsyncLoader<StorageAsyncLoader.AppsStorageResult> {
     private int mUserId;
     private String mUuid;
     private StorageStatsSource mStatsManager;
     private PackageManagerWrapper mPackageManager;
 
-    public AppsAsyncLoader(Context context, int userId, String uuid, StorageStatsSource source,
+    public StorageAsyncLoader(Context context, int userId, String uuid, StorageStatsSource source,
             PackageManagerWrapper pm) {
         super(context);
         mUserId = userId;
@@ -66,12 +70,20 @@
             StorageStatsSource.AppStorageStats stats = mStatsManager.getStatsForUid(mUuid, app.uid);
             // Note: This omits cache intentionally -- we are not attributing it to the apps.
             long appSize = stats.getCodeBytes() + stats.getDataBytes();
-            if (app.category == ApplicationInfo.CATEGORY_GAME) {
-                result.gamesSize += appSize;
-            } else {
-                result.otherAppsSize += appSize;
+            switch (app.category) {
+                case CATEGORY_GAME:
+                    result.gamesSize += appSize;
+                    break;
+                case CATEGORY_AUDIO:
+                    result.musicAppsSize += appSize;
+                    break;
+                default:
+                    result.otherAppsSize += appSize;
+                    break;
             }
         }
+
+        result.externalStats = mStatsManager.getExternalStorageStats(mUuid, UserHandle.of(mUserId));
         return result;
     }
 
@@ -81,6 +93,8 @@
 
     public static class AppsStorageResult {
         public long gamesSize;
+        public long musicAppsSize;
         public long otherAppsSize;
+        public StorageStatsSource.ExternalStorageStats externalStats;
     }
 }
diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
index 5437dcb..627b877 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
@@ -18,13 +18,11 @@
 
 import android.app.Fragment;
 import android.app.LoaderManager;
-import android.app.usage.StorageStatsManager;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.content.Loader;
 import android.os.Bundle;
-import android.os.Environment;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.VolumeInfo;
@@ -40,23 +38,17 @@
 import com.android.settings.applications.ManageApplications;
 import com.android.settings.applications.PackageManagerWrapperImpl;
 import com.android.settings.core.PreferenceController;
-import com.android.settings.core.lifecycle.Lifecycle;
-import com.android.settings.core.lifecycle.LifecycleObserver;
-import com.android.settings.core.lifecycle.events.OnDestroy;
-import com.android.settings.deviceinfo.StorageItemPreference;
 import com.android.settingslib.deviceinfo.StorageMeasurement;
 import com.android.settingslib.deviceinfo.StorageVolumeProvider;
 
 import java.util.HashMap;
 
-
 /**
  * StorageItemPreferenceController handles the storage line items which summarize the storage
  * categorization breakdown.
  */
 public class StorageItemPreferenceController extends PreferenceController
-        implements StorageMeasurement.MeasurementReceiver, LifecycleObserver, OnDestroy,
-        LoaderManager.LoaderCallbacks<AppsAsyncLoader.AppsStorageResult> {
+        implements LoaderManager.LoaderCallbacks<StorageAsyncLoader.AppsStorageResult> {
     private static final String TAG = "StorageItemPreference";
 
     private static final String IMAGE_MIME_TYPE = "image/*";
@@ -78,9 +70,7 @@
     private final StorageVolumeProvider mSvp;
     private VolumeInfo mVolume;
     private final int mUserId;
-    private StorageMeasurement mMeasure;
     private long mSystemSize;
-    private long mUsedSize;
 
     private StorageItemPreferenceAlternate mPhotoPreference;
     private StorageItemPreferenceAlternate mAudioPreference;
@@ -91,8 +81,8 @@
 
     private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents";
 
-    public StorageItemPreferenceController(Context context, Lifecycle lifecycle,
-            Fragment hostFragment, VolumeInfo volume, StorageVolumeProvider svp) {
+    public StorageItemPreferenceController(
+            Context context, Fragment hostFragment, VolumeInfo volume, StorageVolumeProvider svp) {
         super(context);
         mFragment = hostFragment;
         mVolume = volume;
@@ -100,10 +90,6 @@
 
         UserManager um = mContext.getSystemService(UserManager.class);
         mUserId = um.getUserHandle();
-
-        if (lifecycle != null) {
-            lifecycle.addObserver(this);
-        }
     }
 
     @Override
@@ -166,44 +152,6 @@
     }
 
     @Override
-    public void onDetailsChanged(StorageMeasurement.MeasurementDetails details) {
-        final long imagesSize = totalValues(details, mUserId,
-                Environment.DIRECTORY_DCIM,
-                Environment.DIRECTORY_PICTURES,
-                Environment.DIRECTORY_MOVIES);
-        if (mPhotoPreference != null) {
-            mPhotoPreference.setStorageSize(imagesSize);
-        }
-
-        final long audioSize = totalValues(details, mUserId,
-                Environment.DIRECTORY_MUSIC,
-                Environment.DIRECTORY_ALARMS,
-                Environment.DIRECTORY_NOTIFICATIONS,
-                Environment.DIRECTORY_RINGTONES,
-                Environment.DIRECTORY_PODCASTS);
-        if (mAudioPreference != null) {
-            mAudioPreference.setStorageSize(audioSize);
-        }
-
-        if (mSystemPreference != null) {
-            mSystemPreference.setStorageSize(mSystemSize);
-        }
-
-        final long downloadsSize = totalValues(details, mUserId, Environment.DIRECTORY_DOWNLOADS);
-        final long miscSize = details.miscSize.get(mUserId);
-        if (mFilePreference != null) {
-            mFilePreference.setStorageSize(downloadsSize + miscSize);
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        if (mMeasure != null) {
-            mMeasure.onDestroy();
-        }
-    }
-
-    @Override
     public void displayPreference(PreferenceScreen screen) {
         mPhotoPreference = (StorageItemPreferenceAlternate) screen.findPreference(PHOTO_KEY);
         mAudioPreference = (StorageItemPreferenceAlternate) screen.findPreference(AUDIO_KEY);
@@ -214,32 +162,30 @@
     }
 
     @Override
-    public Loader<AppsAsyncLoader.AppsStorageResult> onCreateLoader(int id,
+    public Loader<StorageAsyncLoader.AppsStorageResult> onCreateLoader(int id,
             Bundle args) {
-        return new AppsAsyncLoader(mContext, UserHandle.myUserId(), mVolume.fsUuid,
+        return new StorageAsyncLoader(mContext, UserHandle.myUserId(), mVolume.fsUuid,
                 new StorageStatsSource(mContext),
                 new PackageManagerWrapperImpl(mContext.getPackageManager()));
     }
 
     @Override
-    public void onLoadFinished(Loader<AppsAsyncLoader.AppsStorageResult> loader,
-            AppsAsyncLoader.AppsStorageResult data) {
+    public void onLoadFinished(Loader<StorageAsyncLoader.AppsStorageResult> loader,
+            StorageAsyncLoader.AppsStorageResult data) {
+        mPhotoPreference.setStorageSize(
+                data.externalStats.imageBytes + data.externalStats.videoBytes);
+        mAudioPreference.setStorageSize(data.musicAppsSize + data.externalStats.audioBytes);
         mGamePreference.setStorageSize(data.gamesSize);
         mAppPreference.setStorageSize(data.otherAppsSize);
+        mSystemPreference.setStorageSize(mSystemSize);
+
+        long unattributedBytes = data.externalStats.totalBytes - data.externalStats.audioBytes
+                - data.externalStats.videoBytes - data.externalStats.imageBytes;
+        mFilePreference.setStorageSize(unattributedBytes);
     }
 
     @Override
-    public void onLoaderReset(Loader<AppsAsyncLoader.AppsStorageResult> loader) {
-    }
-
-    /**
-     * Begins an asynchronous storage measurement task for the preferences.
-     */
-    public void startMeasurement() {
-        //TODO: When the GID-based measurement system is completed, swap in the GID impl.
-        mMeasure = new StorageMeasurement(mContext, mVolume, mSvp.findEmulatedForPrivate(mVolume));
-        mMeasure.setReceiver(this);
-        mMeasure.forceMeasure();
+    public void onLoaderReset(Loader<StorageAsyncLoader.AppsStorageResult> loader) {
     }
 
     /**
diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java
index 0f36ab1..7cf0780 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java
+++ b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java
@@ -26,6 +26,7 @@
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.settings.R;
 import com.android.settings.Utils;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.BatteryInfo;
 import com.android.settingslib.graph.UsageView;
 
@@ -49,12 +50,22 @@
 
     @Override
     public void performClick() {
-        mHelper.storeStatsHistoryInFile(BATTERY_HISTORY_FILE);
-        Bundle args = new Bundle();
-        args.putString(BatteryHistoryDetail.EXTRA_STATS, BATTERY_HISTORY_FILE);
-        args.putParcelable(BatteryHistoryDetail.EXTRA_BROADCAST, mHelper.getBatteryBroadcast());
-        Utils.startWithFragment(getContext(), BatteryHistoryDetail.class.getName(), args,
-                null, 0, R.string.history_details_title, null);
+        // TODO(b/34890746): remove this since history graph is not clickable
+        final Context context = getContext();
+        final PowerUsageFeatureProvider featureProvider = FeatureFactory.getFactory(context)
+                .getPowerUsageFeatureProvider(context);
+
+        if (featureProvider.isAdvancedUiEnabled()) {
+            Utils.startWithFragment(getContext(), PowerUsageAdvanced.class.getName(), null,
+                    null, 0, R.string.advanced_battery_title, null);
+        } else {
+            mHelper.storeStatsHistoryInFile(BATTERY_HISTORY_FILE);
+            Bundle args = new Bundle();
+            args.putString(BatteryHistoryDetail.EXTRA_STATS, BATTERY_HISTORY_FILE);
+            args.putParcelable(BatteryHistoryDetail.EXTRA_BROADCAST, mHelper.getBatteryBroadcast());
+            Utils.startWithFragment(getContext(), BatteryHistoryDetail.class.getName(), args,
+                    null, 0, R.string.history_details_title, null);
+        }
     }
 
     public void setStats(BatteryStatsHelper batteryStats) {
diff --git a/src/com/android/settings/fuelgauge/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
index 9371a19..1d3d62b 100644
--- a/src/com/android/settings/fuelgauge/PowerGaugePreference.java
+++ b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
@@ -20,6 +20,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -48,12 +49,21 @@
         mIconSize = context.getResources().getDimensionPixelSize(R.dimen.app_icon_size);
     }
 
+    public PowerGaugePreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        final Drawable icon = context.getDrawable(R.drawable.ic_battery_circle);
+
+        setIcon(icon);
+        setWidgetLayoutResource(R.layout.preference_widget_summary);
+        mIconSize = icon.getIntrinsicWidth();
+    }
+
     public void setContentDescription(String name) {
         mContentDescription = name;
         notifyChanged();
     }
 
-    public void setPercent(double percentOfMax, double percentOfTotal) {
+    public void setPercent(double percentOfTotal) {
         mProgress = Utils.formatPercentage((int) (percentOfTotal + 0.5));
         notifyChanged();
     }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
new file mode 100644
index 0000000..4ccf9f7
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 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 android.os.Bundle;
+import android.os.Process;
+import android.provider.SearchIndexableResource;
+import android.support.annotation.ColorInt;
+import android.support.annotation.IntDef;
+import android.support.annotation.VisibleForTesting;
+import android.util.SparseArray;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.os.BatterySipper;
+import com.android.internal.os.BatterySipper.DrainType;
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.R;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.fuelgauge.PowerUsageAdvanced.PowerUsageData.UsageType;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.search.BaseSearchIndexProvider;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class PowerUsageAdvanced extends PowerUsageBase {
+    private static final String TAG = "AdvancedBatteryUsage";
+    private static final String KEY_BATTERY_GRAPH = "battery_graph";
+    private static final String KEY_BATTERY_APPS = "battery_apps";
+    private static final String KEY_BATTERY_WIFI = "battery_wifi";
+    private static final String KEY_BATTERY_CELL = "battery_cell";
+    private static final String KEY_BATTERY_BLUETOOTH = "battery_bluetooth";
+    private static final String KEY_BATTERY_IDLE = "battery_idle";
+    private static final String KEY_BATTERY_SERVICE = "battery_service";
+    private static final String KEY_BATTERY_SYSTEM = "battery_system";
+    private static final String KEY_BATTERY_USER = "battery_user";
+
+    private BatteryHistoryPreference mHistPref;
+    @VisibleForTesting
+    SparseArray<String> mUsageTypeMap;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_GRAPH);
+        init();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        refreshStats();
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.FUELGAUGE_BATTERY_HISTORY_DETAIL;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.power_usage_advanced;
+    }
+
+    @Override
+    protected List<PreferenceController> getPreferenceControllers(Context context) {
+        return null;
+    }
+
+    @Override
+    protected void refreshStats() {
+        super.refreshStats();
+
+        updatePreference(mHistPref);
+
+        List<PowerUsageData> dataList = parsePowerUsageData(mStatsHelper);
+        for (int i = 0, size = dataList.size(); i < size; i++) {
+            final PowerUsageData data = dataList.get(i);
+            final String key = mUsageTypeMap.get(data.usageType);
+            if (key != null) {
+                bindData(key, data);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    @UsageType int extractUsageType(BatterySipper sipper) {
+        final DrainType drainType = sipper.drainType;
+        final int uid = sipper.getUid();
+
+        // TODO(b/34385770): add logic to extract type service
+        if (drainType == DrainType.WIFI) {
+            return UsageType.WIFI;
+        } else if (drainType == DrainType.BLUETOOTH) {
+            return UsageType.BLUETOOTH;
+        } else if (drainType == DrainType.IDLE) {
+            return UsageType.IDLE;
+        } else if (drainType == DrainType.USER) {
+            return UsageType.USER;
+        } else if (drainType == DrainType.CELL) {
+            return UsageType.CELL;
+        } else if (uid == Process.SYSTEM_UID || uid == Process.ROOT_UID) {
+            return UsageType.SYSTEM;
+        } else {
+            return UsageType.APP;
+        }
+    }
+
+    @VisibleForTesting
+    void init() {
+        // Store projection from UsageType to preference key
+        mUsageTypeMap = new SparseArray<>();
+        mUsageTypeMap.put(UsageType.APP, KEY_BATTERY_APPS);
+        mUsageTypeMap.put(UsageType.WIFI, KEY_BATTERY_WIFI);
+        mUsageTypeMap.put(UsageType.CELL, KEY_BATTERY_CELL);
+        mUsageTypeMap.put(UsageType.BLUETOOTH, KEY_BATTERY_BLUETOOTH);
+        mUsageTypeMap.put(UsageType.IDLE, KEY_BATTERY_IDLE);
+        mUsageTypeMap.put(UsageType.SERVICE, KEY_BATTERY_SERVICE);
+        mUsageTypeMap.put(UsageType.USER, KEY_BATTERY_USER);
+        mUsageTypeMap.put(UsageType.SYSTEM, KEY_BATTERY_SYSTEM);
+    }
+
+    @VisibleForTesting
+    List<PowerUsageData> parsePowerUsageData(BatteryStatsHelper statusHelper) {
+        final List<BatterySipper> batterySippers = statusHelper.getUsageList();
+        final Map<Integer, PowerUsageData> batteryDataMap = new HashMap<>();
+
+        for (int i = 0, size = mUsageTypeMap.size(); i < size; i++) {
+            @UsageType final int type = mUsageTypeMap.keyAt(i);
+            batteryDataMap.put(type, PowerUsageData.createBatteryUsageData(type));
+        }
+
+        // Accumulate power usage based on usage type
+        for (final BatterySipper sipper : batterySippers) {
+            final PowerUsageData usageData = batteryDataMap.get(extractUsageType(sipper));
+            usageData.totalPowerMah += sipper.totalPowerMah;
+        }
+
+        // TODO(b/34385770): add logic to extract the summary
+        final List<PowerUsageData> batteryDataList = new ArrayList<>(batteryDataMap.values());
+        final double totalPower = statusHelper.getTotalPower();
+        for (final PowerUsageData usageData : batteryDataList) {
+            usageData.percentage = (usageData.totalPowerMah / totalPower) * 100;
+        }
+
+        return batteryDataList;
+    }
+
+    private void bindData(String key, PowerUsageData batteryData) {
+        final PowerGaugePreference pref = (PowerGaugePreference) findPreference(key);
+
+        pref.setSummary(batteryData.summary);
+        pref.setPercent(batteryData.percentage);
+    }
+
+    /**
+     * Class that contains data used in {@link PowerGaugePreference}.
+     */
+    @VisibleForTesting
+    static class PowerUsageData {
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef({UsageType.APP,
+                UsageType.WIFI,
+                UsageType.CELL,
+                UsageType.SERVICE,
+                UsageType.SYSTEM,
+                UsageType.BLUETOOTH,
+                UsageType.USER,
+                UsageType.IDLE})
+        public @interface UsageType {
+            int APP = 0;
+            int WIFI = 1;
+            int CELL = 2;
+            int SERVICE = 3;
+            int SYSTEM = 4;
+            int BLUETOOTH = 5;
+            int USER = 6;
+            int IDLE = 7;
+        }
+
+        public String summary;
+        public double percentage;
+        public double totalPowerMah;
+        @ColorInt
+        public int iconColor;
+        @UsageType
+        public int usageType;
+
+        private PowerUsageData(@UsageType int usageType) {
+            this.usageType = usageType;
+            totalPowerMah = 0;
+        }
+
+        public static PowerUsageData createBatteryUsageData(@UsageType int usageType) {
+            // TODO(b/34385770): add color logic in this part
+            return new PowerUsageData(usageType);
+        }
+    }
+
+    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableResource> getXmlResourcesToIndex(
+                        Context context, boolean enabled) {
+                    if (!FeatureFactory.getFactory(context).getDashboardFeatureProvider(context)
+                            .isEnabled()) {
+                        return null;
+                    }
+                    final SearchIndexableResource sir = new SearchIndexableResource(context);
+                    sir.xmlResId = R.xml.power_usage_advanced;
+                    return Arrays.asList(sir);
+                }
+            };
+
+}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index de16fe5..3c1b197 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -36,4 +36,9 @@
    * Gets an {@link Intent} to show additional battery info.
    */
   Intent getAdditionalBatteryInfoIntent();
+
+  /**
+   * Check whether advanced ui is enabled
+   */
+  boolean isAdvancedUiEnabled();
 }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
new file mode 100644
index 0000000..b29900e
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 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.Intent;
+
+public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider {
+    @Override
+    public boolean isLocationSettingEnabled(String[] packages) {
+        return false;
+    }
+
+    @Override
+    public boolean isAdditionalBatteryInfoEnabled() {
+        return false;
+    }
+
+    @Override
+    public Intent getAdditionalBatteryInfoIntent() {
+        return null;
+    }
+
+    @Override
+    public boolean isAdvancedUiEnabled() {
+        return false;
+    }
+}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 2745292..c0c92f0 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -413,7 +413,7 @@
                 sipper.percent = percentOfTotal;
                 pref.setTitle(entry.getLabel());
                 pref.setOrder(i + 1);
-                pref.setPercent(percentOfMax, percentOfTotal);
+                pref.setPercent(percentOfTotal);
                 setUsageSummary(pref, usedTime, sipper.usageTimeMs);
                 if ((sipper.drainType != DrainType.APP
                         || sipper.uidObj.getUid() == Process.ROOT_UID)
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index ef62fbb..d6b60fd 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.notification;
 
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
 import android.app.Activity;
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -24,6 +27,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.support.v7.preference.Preference;
@@ -41,10 +45,12 @@
 import com.android.settings.dashboard.DashboardFeatureProvider;
 import com.android.settings.notification.NotificationBackend.AppRow;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.MasterSwitchPreference;
 import com.android.settingslib.RestrictedPreference;
 import com.android.settingslib.RestrictedSwitchPreference;
 
 import java.text.Collator;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -63,8 +69,8 @@
     private static final String KEY_BLOCK = "block";
 
     private DashboardFeatureProvider mDashboardFeatureProvider;
-    private PreferenceCategory mChannels;
     private List<NotificationChannelGroup> mChannelGroupList;
+    private List<PreferenceCategory> mChannelGroups = new ArrayList();
 
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
@@ -98,7 +104,6 @@
 
         mBlock = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BLOCK);
         mBadge = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BADGE);
-        mChannels = (PreferenceCategory) findPreference(KEY_CHANNELS);
 
         if (mPkgInfo != null) {
             setupBlock();
@@ -107,60 +112,19 @@
             ArrayMap<String, AppRow> rows = new ArrayMap<String, AppRow>();
             rows.put(mAppRow.pkg, mAppRow);
             collectConfigActivities(rows);
-            // TODO: load channels in asynctask?
-            mChannelGroupList = mBackend.getChannelGroups(mPkg, mUid).getList();
-            Collections.sort(mChannelGroupList, mChannelGroupComparator);
-
-            if (mChannelGroupList.isEmpty()) {
-                Preference empty = new Preference(getPrefContext());
-                empty.setTitle(R.string.no_channels);
-                empty.setEnabled(false);
-                mChannels.addPreference(empty);
-            } else {
-                for (NotificationChannelGroup group : mChannelGroupList) {
-                    PreferenceCategory groupCategory = null;
-                    if (group.getId() != null && group.getName() != null) {
-                        groupCategory = new PreferenceCategory(getPrefContext());
-                        groupCategory.setTitle(group.getName());
-                        groupCategory.setKey(group.getId());
-                        groupCategory.setOrderingAsAdded(true);
-                        getPreferenceScreen().addPreference(groupCategory);
-                    }
-                    final List<NotificationChannel> channels = group.getChannels();
-                    Collections.sort(channels, mChannelComparator);
-                    int N = channels.size();
-                    for (int i = 0; i < N; i++) {
-                        final NotificationChannel channel = channels.get(i);
-                        RestrictedPreference channelPref = new RestrictedPreference(
-                                getPrefContext());
-                        channelPref.setDisabledByAdmin(mSuspendedAppsAdmin);
-                        channelPref.setKey(channel.getId());
-                        channelPref.setTitle(channel.getName());
-
-                        if (channel.isDeleted()) {
-                            channelPref.setTitle(
-                                    getString(R.string.deleted_channel_name, channel.getName()));
-                            channelPref.setEnabled(false);
-                        } else {
-                            Bundle channelArgs = new Bundle();
-                            channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
-                            channelArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
-                            channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
-                            channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
-                            Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
-                                    ChannelNotificationSettings.class.getName(),
-                                    channelArgs, null, 0, null, false);
-                            channelPref.setIntent(channelIntent);
-                        }
-                        if (groupCategory != null) {
-                            groupCategory.addPreference(channelPref);
-                        } else {
-                            mChannels.addPreference(channelPref);
-                        }
-                    }
+            new AsyncTask<Void, Void, Void>() {
+                @Override
+                protected Void doInBackground(Void... unused) {
+                    mChannelGroupList = mBackend.getChannelGroups(mPkg, mUid).getList();
+                    Collections.sort(mChannelGroupList, mChannelGroupComparator);
+                    return null;
                 }
-            }
-            updateDependents(mAppRow.banned);
+
+                @Override
+                protected void onPostExecute(Void unused) {
+                    populateChannelList();
+                }
+            }.execute();
         }
         if (mDashboardFeatureProvider.isEnabled()) {
             final Preference pref = FeatureFactory.getFactory(activity)
@@ -188,6 +152,83 @@
         }
     }
 
+    private void populateChannelList() {
+        if (mChannelGroupList.isEmpty()) {
+            PreferenceCategory groupCategory = new PreferenceCategory(getPrefContext());
+            groupCategory.setTitle(R.string.notification_channels);
+            getPreferenceScreen().addPreference(groupCategory);
+            mChannelGroups.add(groupCategory);
+
+            Preference empty = new Preference(getPrefContext());
+            empty.setTitle(R.string.no_channels);
+            empty.setEnabled(false);
+            groupCategory.addPreference(empty);
+        } else {
+            for (NotificationChannelGroup group : mChannelGroupList) {
+                PreferenceCategory groupCategory = new PreferenceCategory(getPrefContext());
+                if (group.getName() == null) {
+                    groupCategory.setTitle(mChannelGroupList.size() > 1
+                            ? R.string.notification_channels_other
+                            : R.string.notification_channels);
+                } else {
+                    groupCategory.setTitle(group.getName());
+                }
+                groupCategory.setKey(group.getId());
+                groupCategory.setOrderingAsAdded(true);
+                getPreferenceScreen().addPreference(groupCategory);
+                mChannelGroups.add(groupCategory);
+
+                final List<NotificationChannel> channels = group.getChannels();
+                Collections.sort(channels, mChannelComparator);
+                int N = channels.size();
+                for (int i = 0; i < N; i++) {
+                    final NotificationChannel channel = channels.get(i);
+                    MasterSwitchPreference channelPref = new MasterSwitchPreference(
+                            getPrefContext());
+                    channelPref.setDisabledByAdmin(mSuspendedAppsAdmin);
+                    channelPref.setKey(channel.getId());
+                    channelPref.setTitle(channel.getName());
+                    channelPref.setChecked(channel.getImportance() != IMPORTANCE_NONE);
+
+                    if (channel.isDeleted()) {
+                        channelPref.setTitle(
+                                getString(R.string.deleted_channel_name, channel.getName()));
+                        channelPref.setEnabled(false);
+                    } else {
+                        channelPref.setSummary(getImportanceSummary(channel.getImportance()));
+                        Bundle channelArgs = new Bundle();
+                        channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
+                        channelArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
+                        channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
+                        channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
+                        Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
+                                ChannelNotificationSettings.class.getName(),
+                                channelArgs, null, 0, null, false);
+                        channelPref.setIntent(channelIntent);
+
+                        channelPref.setOnPreferenceChangeListener(
+                                new Preference.OnPreferenceChangeListener() {
+                                    @Override
+                                    public boolean onPreferenceChange(Preference preference,
+                                            Object o) {
+                                        boolean value = (Boolean) o;
+                                        int importance = value ?  IMPORTANCE_LOW : IMPORTANCE_NONE;
+                                        channel.setImportance(importance);
+                                        channel.lockFields(
+                                                NotificationChannel.USER_LOCKED_IMPORTANCE);
+                                        mBackend.updateChannel(mPkg, mUid, channel);
+
+                                        return true;
+                                    }
+                                });
+                    }
+                    groupCategory.addPreference(channelPref);
+                }
+            }
+        }
+        updateDependents(mAppRow.banned);
+    }
+
     private void setupBadge() {
         mBadge.setDisabledByAdmin(mSuspendedAppsAdmin);
         mBadge.setChecked(mAppRow.showBadge);
@@ -223,7 +264,9 @@
     }
 
     private void updateDependents(boolean banned) {
-        setVisible(mChannels, !banned);
+        for (PreferenceCategory category : mChannelGroups) {
+            setVisible(category, !banned);
+        }
         setVisible(mBadge, !banned);
     }
 
@@ -289,7 +332,7 @@
 
                 @Override
                 public int compare(NotificationChannelGroup left, NotificationChannelGroup right) {
-                    // Non-groups channels (in placeholder group with a null id) come first
+                    // Non-grouped channels (in placeholder group with a null id) come last
                     if (left.getId() == null && right.getId() != null) {
                         return 1;
                     } else if (right.getId() == null && left.getId() != null) {
diff --git a/src/com/android/settings/notification/ChannelNotificationSettings.java b/src/com/android/settings/notification/ChannelNotificationSettings.java
index f35794e..b6923dc 100644
--- a/src/com/android/settings/notification/ChannelNotificationSettings.java
+++ b/src/com/android/settings/notification/ChannelNotificationSettings.java
@@ -230,12 +230,12 @@
         List<String> values = new ArrayList<>();;
         for (int i = 0; i < numImportances; i++) {
             int importance = i + 1;
-            summaries.add(getSummary(importance));
+            summaries.add(getImportanceSummary(importance));
             values.add(String.valueOf(importance));
         }
         if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId())) {
             // Add option to reset to letting the app decide
-            summaries.add(getSummary(NotificationManager.IMPORTANCE_UNSPECIFIED));
+            summaries.add(getImportanceSummary(NotificationManager.IMPORTANCE_UNSPECIFIED));
             values.add(String.valueOf(NotificationManager.IMPORTANCE_UNSPECIFIED));
         }
         mImportance.setEntryValues(values.toArray(new String[0]));
@@ -256,25 +256,6 @@
         });
     }
 
-    private String getSummary(int importance) {
-        switch (importance) {
-            case NotificationManager.IMPORTANCE_UNSPECIFIED:
-                return getContext().getString(R.string.notification_importance_unspecified);
-            case NotificationManager.IMPORTANCE_NONE:
-                return getContext().getString(R.string.notification_importance_blocked);
-            case NotificationManager.IMPORTANCE_MIN:
-                return getContext().getString(R.string.notification_importance_min);
-            case NotificationManager.IMPORTANCE_LOW:
-                return getContext().getString(R.string.notification_importance_low);
-            case NotificationManager.IMPORTANCE_DEFAULT:
-                return getContext().getString(R.string.notification_importance_default);
-            case NotificationManager.IMPORTANCE_HIGH:
-            case NotificationManager.IMPORTANCE_MAX:
-            default:
-                return getContext().getString(R.string.notification_importance_high);
-        }
-    }
-
     protected void setupPriorityPref(boolean priority) {
         mPriority.setDisabledByAdmin(mSuspendedAppsAdmin);
         mPriority.setChecked(priority);
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index f6c6591..b5c52a1 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -176,15 +176,22 @@
         return null;
     }
 
-    private PackageInfo findPackageInfo(String pkg) {
-        if (pkg == null) {
-            return null;
+    protected String getImportanceSummary(int importance) {
+        switch (importance) {
+            case NotificationManager.IMPORTANCE_UNSPECIFIED:
+                return getContext().getString(R.string.notification_importance_unspecified);
+            case NotificationManager.IMPORTANCE_NONE:
+                return getContext().getString(R.string.notification_importance_blocked);
+            case NotificationManager.IMPORTANCE_MIN:
+                return getContext().getString(R.string.notification_importance_min);
+            case NotificationManager.IMPORTANCE_LOW:
+                return getContext().getString(R.string.notification_importance_low);
+            case NotificationManager.IMPORTANCE_DEFAULT:
+                return getContext().getString(R.string.notification_importance_default);
+            case NotificationManager.IMPORTANCE_HIGH:
+            case NotificationManager.IMPORTANCE_MAX:
+            default:
+                return getContext().getString(R.string.notification_importance_high);
         }
-        try {
-            return mPm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
-        } catch (NameNotFoundException e) {
-            Log.w(TAG, "Failed to load package " + pkg, e);
-        }
-        return null;
     }
 }
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index c45bf0e..4c81e30 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -37,6 +37,7 @@
 import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
 import com.android.settings.enterprise.EnterprisePrivacyFeatureProviderImpl;
 import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.fuelgauge.PowerUsageFeatureProviderImpl;
 import com.android.settings.localepicker.LocaleFeatureProvider;
 import com.android.settings.localepicker.LocaleFeatureProviderImpl;
 import com.android.settings.search2.SearchFeatureProvider;
@@ -59,6 +60,7 @@
     private SearchFeatureProvider mSearchFeatureProvider;
     private SecurityFeatureProvider mSecurityFeatureProvider;
     private SuggestionFeatureProvider mSuggestionFeatureProvider;
+    private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
 
     @Override
     public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -75,7 +77,10 @@
 
     @Override
     public PowerUsageFeatureProvider getPowerUsageFeatureProvider(Context context) {
-        return null;
+        if (mPowerUsageFeatureProvider == null) {
+            mPowerUsageFeatureProvider = new PowerUsageFeatureProviderImpl();
+        }
+        return mPowerUsageFeatureProvider;
     }
 
     @Override
diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java
index 68a50f0..ada8200 100644
--- a/src/com/android/settings/search/SearchIndexableResources.java
+++ b/src/com/android/settings/search/SearchIndexableResources.java
@@ -47,6 +47,7 @@
 import com.android.settings.display.ScreenZoomSettings;
 import com.android.settings.enterprise.EnterprisePrivacySettings;
 import com.android.settings.fuelgauge.BatterySaverSettings;
+import com.android.settings.fuelgauge.PowerUsageAdvanced;
 import com.android.settings.fuelgauge.PowerUsageDetail;
 import com.android.settings.fuelgauge.PowerUsageSummary;
 import com.android.settings.gestures.DoubleTapPowerSettings;
@@ -127,6 +128,7 @@
         addIndex(PowerUsageSummary.class,
                 R.xml.power_usage_summary, R.drawable.ic_settings_battery);
         addIndex(PowerUsageDetail.class, NO_DATA_RES_ID, R.drawable.ic_settings_battery);
+        addIndex(PowerUsageAdvanced.class, NO_DATA_RES_ID, R.drawable.ic_settings_battery);
         addIndex(BatterySaverSettings.class,
                 R.xml.battery_saver_settings, R.drawable.ic_settings_battery);
         addIndex(AdvancedAppSettings.class, NO_DATA_RES_ID, R.drawable.ic_settings_applications);
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/UsbBackendTest.java b/tests/robotests/src/com/android/settings/deviceinfo/UsbBackendTest.java
new file mode 100644
index 0000000..99c37ef
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/UsbBackendTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 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.deviceinfo;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.usb.UsbManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class UsbBackendTest {
+
+    @Mock(answer = RETURNS_DEEP_STUBS)
+    private Context mContext;
+    @Mock
+    private UsbManager mUsbManager;
+    @Mock
+    private UsbBackend.UserRestrictionUtil mUserRestrictionUtil;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI))
+            .thenReturn(true);
+        when((Object)mContext.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
+    }
+
+    @Test
+    public void constructor_noUsbPort_shouldNotCrash() {
+        UsbBackend usbBackend = new UsbBackend(mContext, mUserRestrictionUtil);
+        // Should not crash
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
index cfec382..4851b5e 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -25,7 +25,6 @@
 import android.app.Fragment;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Environment;
 import android.os.UserHandle;
 import android.os.storage.VolumeInfo;
 import android.provider.DocumentsContract;
@@ -41,7 +40,6 @@
 import com.android.settings.SubSettings;
 import com.android.settings.TestConfig;
 import com.android.settings.applications.ManageApplications;
-import com.android.settingslib.deviceinfo.StorageMeasurement;
 import com.android.settingslib.deviceinfo.StorageVolumeProvider;
 
 import org.junit.Before;
@@ -55,8 +53,6 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
-import java.util.HashMap;
-
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class StorageItemPreferenceControllerTest {
@@ -82,7 +78,7 @@
         mContext = RuntimeEnvironment.application;
         // Note: null is passed as the Lifecycle because we are handling it outside of the normal
         //       Settings fragment lifecycle for test purposes.
-        mController = new StorageItemPreferenceController(mContext, null, mFragment, mVolume, mSvp);
+        mController = new StorageItemPreferenceController(mContext, mFragment, mVolume, mSvp);
         mPreference = new StorageItemPreferenceAlternate(mContext);
 
         // Inflate the preference and the widget.
@@ -205,23 +201,23 @@
                 Mockito.eq(StorageItemPreferenceController.FILES_KEY))).thenReturn(files);
         mController.displayPreference(screen);
 
-        StorageMeasurement.MeasurementDetails details = new StorageMeasurement.MeasurementDetails();
-        details.appsSize.put(0, KILOBYTE);
-        HashMap<String, Long> mediaSizes = new HashMap<>();
-        mediaSizes.put(Environment.DIRECTORY_PICTURES, KILOBYTE * 2);
-        mediaSizes.put(Environment.DIRECTORY_MOVIES, KILOBYTE * 3);
-        mediaSizes.put(Environment.DIRECTORY_MUSIC, KILOBYTE * 4);
-        mediaSizes.put(Environment.DIRECTORY_DOWNLOADS, KILOBYTE * 5);
-        details.mediaSize.put(0, mediaSizes);
         mController.setSystemSize(KILOBYTE * 6);
-        mController.onDetailsChanged(details);
-        AppsAsyncLoader.AppsStorageResult result = new AppsAsyncLoader.AppsStorageResult();
+        StorageAsyncLoader.AppsStorageResult result = new StorageAsyncLoader.AppsStorageResult();
+        result.gamesSize = KILOBYTE * 8;
+        result.musicAppsSize = KILOBYTE * 4;
+        result.otherAppsSize = KILOBYTE * 9;
+        result.externalStats = new StorageStatsSource.ExternalStorageStats(
+                KILOBYTE * 50, // total
+                KILOBYTE * 10, // audio
+                KILOBYTE * 15, // video
+                KILOBYTE * 20); // image
+
         result.gamesSize = KILOBYTE * 8;
         result.otherAppsSize = KILOBYTE * 9;
         mController.onLoadFinished(null, result);
 
-        assertThat(audio.getSummary().toString()).isEqualTo("4.00KB");
-        assertThat(image.getSummary().toString()).isEqualTo("5.00KB");
+        assertThat(audio.getSummary().toString()).isEqualTo("14.00KB"); // 4KB apps + 10KB files
+        assertThat(image.getSummary().toString()).isEqualTo("35.00KB"); // 15KB video + 20KB images
         assertThat(games.getSummary().toString()).isEqualTo("8.00KB");
         assertThat(apps.getSummary().toString()).isEqualTo("9.00KB");
         assertThat(system.getSummary().toString()).isEqualTo("6.00KB");
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java
new file mode 100644
index 0000000..17cd223
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java
@@ -0,0 +1,137 @@
+package com.android.settings.fuelgauge;
+
+import android.os.Process;
+import android.util.SparseArray;
+import com.android.internal.os.BatterySipper;
+import com.android.internal.os.BatterySipper.DrainType;
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.fuelgauge.PowerUsageAdvanced.PowerUsageData;
+import com.android.settings.fuelgauge.PowerUsageAdvanced.PowerUsageData.UsageType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class PowerUsageAdvancedTest {
+    private static final int FAKE_UID_1 = 50;
+    private static final int FAKE_UID_2 = 100;
+    private static final double TYPE_APP_USAGE = 80;
+    private static final double TYPE_BLUETOOTH_USAGE = 50;
+    private static final double TYPE_WIFI_USAGE = 0;
+    private static final double TOTAL_USAGE = TYPE_APP_USAGE * 2 + TYPE_BLUETOOTH_USAGE
+            + TYPE_WIFI_USAGE;
+    private static final double PRECISION = 0.001;
+    private static final String STRING_NOT_FOUND = "not_found";
+    @Mock
+    private BatterySipper mBatterySipper;
+    @Mock
+    private BatteryStatsHelper mBatteryStatsHelper;
+    private PowerUsageAdvanced mPowerUsageAdvanced;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mPowerUsageAdvanced = new PowerUsageAdvanced();
+
+        List<BatterySipper> batterySippers = new ArrayList<>();
+        batterySippers.add(new BatterySipper(DrainType.APP,
+                new FakeUid(FAKE_UID_1), TYPE_APP_USAGE));
+        batterySippers.add(new BatterySipper(DrainType.APP,
+                new FakeUid(FAKE_UID_2), TYPE_APP_USAGE));
+        batterySippers.add(new BatterySipper(DrainType.BLUETOOTH, new FakeUid(FAKE_UID_1),
+                TYPE_BLUETOOTH_USAGE));
+        batterySippers.add(new BatterySipper(DrainType.WIFI, new FakeUid(FAKE_UID_1),
+                TYPE_WIFI_USAGE));
+
+        when(mBatteryStatsHelper.getUsageList()).thenReturn(batterySippers);
+        when(mBatteryStatsHelper.getTotalPower()).thenReturn(TOTAL_USAGE);
+    }
+
+    @Test
+    public void testExtractUsageType_TypeSystem_ReturnSystem() {
+        mBatterySipper.drainType = DrainType.APP;
+        final int uids[] = {Process.SYSTEM_UID, Process.ROOT_UID};
+
+        for (int uid : uids) {
+            when(mBatterySipper.getUid()).thenReturn(uid);
+            assertThat(mPowerUsageAdvanced.extractUsageType(mBatterySipper))
+                    .isEqualTo(UsageType.SYSTEM);
+        }
+    }
+
+    @Test
+    public void testExtractUsageType_TypeEqualsToDrainType_ReturnRelevantType() {
+        final DrainType drainTypes[] = {DrainType.WIFI, DrainType.BLUETOOTH, DrainType.IDLE,
+                DrainType.USER, DrainType.CELL};
+        final int usageTypes[] = {UsageType.WIFI, UsageType.BLUETOOTH, UsageType.IDLE,
+                UsageType.USER, UsageType.CELL};
+
+        assertThat(drainTypes.length).isEqualTo(usageTypes.length);
+        for (int i = 0, size = drainTypes.length; i < size; i++) {
+            mBatterySipper.drainType = drainTypes[i];
+            assertThat(mPowerUsageAdvanced.extractUsageType(mBatterySipper))
+                    .isEqualTo(usageTypes[i]);
+        }
+    }
+
+    @Test
+    public void testParsePowerUsageData_PercentageCalculatedCorrectly() {
+        final double percentApp = TYPE_APP_USAGE * 2 / TOTAL_USAGE * 100;
+        final double percentWifi = TYPE_WIFI_USAGE / TOTAL_USAGE * 100;
+        final double percentBluetooth = TYPE_BLUETOOTH_USAGE / TOTAL_USAGE * 100;
+
+        mPowerUsageAdvanced.init();
+        List<PowerUsageData> batteryData =
+                mPowerUsageAdvanced.parsePowerUsageData(mBatteryStatsHelper);
+        for (PowerUsageData data : batteryData) {
+            switch (data.usageType) {
+                case UsageType.WIFI:
+                    assertThat(data.percentage).isWithin(PRECISION).of(percentWifi);
+                    break;
+                case UsageType.APP:
+                    assertThat(data.percentage).isWithin(PRECISION).of(percentApp);
+                    break;
+                case UsageType.BLUETOOTH:
+                    assertThat(data.percentage).isWithin(PRECISION).of(percentBluetooth);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    @Test
+    public void testInit_ContainsAllUsageType() {
+        mPowerUsageAdvanced.init();
+        final SparseArray<String> array = mPowerUsageAdvanced.mUsageTypeMap;
+
+        assertThat(array.get(UsageType.APP, STRING_NOT_FOUND))
+                .isNotEqualTo(STRING_NOT_FOUND);
+        assertThat(array.get(UsageType.WIFI, STRING_NOT_FOUND))
+                .isNotEqualTo(STRING_NOT_FOUND);
+        assertThat(array.get(UsageType.CELL, STRING_NOT_FOUND))
+                .isNotEqualTo(STRING_NOT_FOUND);
+        assertThat(array.get(UsageType.BLUETOOTH, STRING_NOT_FOUND))
+                .isNotEqualTo(STRING_NOT_FOUND);
+        assertThat(array.get(UsageType.IDLE, STRING_NOT_FOUND))
+                .isNotEqualTo(STRING_NOT_FOUND);
+        assertThat(array.get(UsageType.SERVICE, STRING_NOT_FOUND))
+                .isNotEqualTo(STRING_NOT_FOUND);
+        assertThat(array.get(UsageType.USER, STRING_NOT_FOUND))
+                .isNotEqualTo(STRING_NOT_FOUND);
+        assertThat(array.get(UsageType.SYSTEM, STRING_NOT_FOUND))
+                .isNotEqualTo(STRING_NOT_FOUND);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/AppAsyncLoaderTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java
similarity index 87%
rename from tests/unit/src/com/android/settings/deviceinfo/storage/AppAsyncLoaderTest.java
rename to tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java
index 8d4dd2e..71a1590 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/storage/AppAsyncLoaderTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java
@@ -42,7 +42,7 @@
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-public class AppAsyncLoaderTest {
+public class StorageAsyncLoaderTest {
     @Mock
     private StorageStatsSource mSource;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -51,13 +51,13 @@
     private PackageManagerWrapper mPackageManager;
     ArrayList<ApplicationInfo> mInfo = new ArrayList<>();
 
-    private AppsAsyncLoader mLoader;
+    private StorageAsyncLoader mLoader;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mInfo = new ArrayList<>();
-        mLoader = new AppsAsyncLoader(mContext, 1, "id", mSource, mPackageManager);
+        mLoader = new StorageAsyncLoader(mContext, 1, "id", mSource, mPackageManager);
         when(mPackageManager.getInstalledApplicationsAsUser(anyInt(), anyInt())).thenReturn(mInfo);
     }
 
@@ -66,7 +66,7 @@
         addPackage(1001, 0, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED);
         addPackage(1002, 0, 100, 1000, ApplicationInfo.CATEGORY_UNDEFINED);
 
-        AppsAsyncLoader.AppsStorageResult result = mLoader.loadInBackground();
+        StorageAsyncLoader.AppsStorageResult result = mLoader.loadInBackground();
 
         assertThat(result.gamesSize).isEqualTo(0L);
         assertThat(result.otherAppsSize).isEqualTo(1111L);
@@ -76,7 +76,7 @@
     public void testGamesAreFiltered() throws Exception {
         addPackage(1001, 0, 1, 10, ApplicationInfo.CATEGORY_GAME);
 
-        AppsAsyncLoader.AppsStorageResult result = mLoader.loadInBackground();
+        StorageAsyncLoader.AppsStorageResult result = mLoader.loadInBackground();
 
         assertThat(result.gamesSize).isEqualTo(11L);
         assertThat(result.otherAppsSize).isEqualTo(0);
@@ -87,7 +87,7 @@
         addPackage(1001, 0, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED);
         addPackage(1001, 0, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED);
 
-        AppsAsyncLoader.AppsStorageResult result = mLoader.loadInBackground();
+        StorageAsyncLoader.AppsStorageResult result = mLoader.loadInBackground();
 
         assertThat(result.otherAppsSize).isEqualTo(11L);
     }
@@ -96,7 +96,7 @@
     public void testCacheIsIgnored() throws Exception {
         addPackage(1001, 100, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED);
 
-        AppsAsyncLoader.AppsStorageResult result = mLoader.loadInBackground();
+        StorageAsyncLoader.AppsStorageResult result = mLoader.loadInBackground();
 
         assertThat(result.otherAppsSize).isEqualTo(11L);
     }