diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f01110ad79e..6c04af25aff 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -923,6 +923,15 @@
android:value="true" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/power_usage_action_item.xml b/res/layout/power_usage_action_item.xml
deleted file mode 100644
index 9e8551eb7d5..00000000000
--- a/res/layout/power_usage_action_item.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout/power_usage_detail_item_text.xml b/res/layout/power_usage_detail_item_text.xml
deleted file mode 100644
index 04b48b86de0..00000000000
--- a/res/layout/power_usage_detail_item_text.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout/power_usage_details.xml b/res/layout/power_usage_details.xml
deleted file mode 100644
index f711d9a348b..00000000000
--- a/res/layout/power_usage_details.xml
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout/power_usage_message_item.xml b/res/layout/power_usage_message_item.xml
deleted file mode 100644
index 6f9e6190219..00000000000
--- a/res/layout/power_usage_message_item.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
diff --git a/res/layout/preference_batteryhistory.xml b/res/layout/preference_batteryhistory.xml
deleted file mode 100644
index 86970598c98..00000000000
--- a/res/layout/preference_batteryhistory.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3da13e72ff0..7e520367b8a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6642,4 +6642,31 @@
Process %1$d
+
+ High power
+
+
+ High power apps
+
+
+ On
+
+
+ Off
+
+
+ High powered apps description text goes here. This is a placeholder.
+
+
+
+ - 1 app is allowed to ignore restrictions like battery saver mode, sync etc.
+ - %d apps is allowed to ignore restrictions like battery saver mode, sync etc.
+
+
+
+ %1$d%% use since last full charge
+
+
+ No battery use since last full charge
+
diff --git a/res/xml/advanced_apps.xml b/res/xml/advanced_apps.xml
index e8082108803..62431c30c4a 100644
--- a/res/xml/advanced_apps.xml
+++ b/res/xml/advanced_apps.xml
@@ -25,12 +25,6 @@
android:title="@string/default_apps_title"
settings:keywords="@string/keywords_default_apps" />
-
-
+
+
+
+
+
+
diff --git a/res/layout/power_usage_package_item.xml b/res/xml/high_power_details.xml
similarity index 55%
rename from res/layout/power_usage_package_item.xml
rename to res/xml/high_power_details.xml
index 6c3179283c9..81f780618c0 100644
--- a/res/layout/power_usage_package_item.xml
+++ b/res/xml/high_power_details.xml
@@ -1,5 +1,5 @@
-
-
+
+
+
+
+
+
+
diff --git a/res/xml/installed_app_details.xml b/res/xml/installed_app_details.xml
index 233331d0610..deab13b7f31 100644
--- a/res/xml/installed_app_details.xml
+++ b/res/xml/installed_app_details.xml
@@ -18,7 +18,8 @@
android:title="@string/application_info_label">
+ android:layout="@layout/installed_app_details"
+ android:selectable="false" />
+
+
+
diff --git a/res/xml/power_usage_details.xml b/res/xml/power_usage_details.xml
new file mode 100644
index 00000000000..ca84e897e23
--- /dev/null
+++ b/res/xml/power_usage_details.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml
index 062251383c5..3f39d472d9f 100644
--- a/res/xml/power_usage_summary.xml
+++ b/res/xml/power_usage_summary.xml
@@ -17,6 +17,13 @@
+ settings:keywords="@string/keywords_battery">
+
+
+
+
+
diff --git a/src/com/android/settings/AppHeader.java b/src/com/android/settings/AppHeader.java
index cd76e80355b..2f3678b942c 100644
--- a/src/com/android/settings/AppHeader.java
+++ b/src/com/android/settings/AppHeader.java
@@ -18,6 +18,7 @@ package com.android.settings;
import android.app.Activity;
import android.content.Intent;
+import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.View.OnClickListener;
@@ -29,6 +30,11 @@ public class AppHeader {
public static void createAppHeader(final Activity activity, Drawable icon, CharSequence label,
final Intent settingsIntent) {
+ createAppHeader(activity, icon, label, settingsIntent, 0);
+ }
+
+ public static void createAppHeader(final Activity activity, Drawable icon, CharSequence label,
+ final Intent settingsIntent, int tintColorRes) {
final View content = activity.findViewById(R.id.main_content);
final ViewGroup contentParent = (ViewGroup) content.getParent();
final View bar = activity.getLayoutInflater().inflate(R.layout.app_header,
@@ -36,6 +42,9 @@ public class AppHeader {
final ImageView appIcon = (ImageView) bar.findViewById(R.id.app_icon);
appIcon.setImageDrawable(icon);
+ if (tintColorRes != 0) {
+ appIcon.setImageTintList(ColorStateList.valueOf(activity.getColor(tintColorRes)));
+ }
final TextView appName = (TextView) bar.findViewById(R.id.app_name);
appName.setText(label);
diff --git a/src/com/android/settings/InstrumentedFragment.java b/src/com/android/settings/InstrumentedFragment.java
index d239d4e1ca0..1ee7e730ae2 100644
--- a/src/com/android/settings/InstrumentedFragment.java
+++ b/src/com/android/settings/InstrumentedFragment.java
@@ -29,6 +29,8 @@ public abstract class InstrumentedFragment extends PreferenceFragment {
public static final int VIEW_CATEGORY_DEFAULT_APPS = VIEW_CATEGORY_UNDECLARED + 1;
public static final int VIEW_CATEGORY_STORAGE_APPS = VIEW_CATEGORY_UNDECLARED + 2;
public static final int VIEW_CATEGORY_USAGE_ACCESS_DETAIL = VIEW_CATEGORY_UNDECLARED + 3;
+ public static final int VIEW_CATEGORY_HIGH_POWER_DETAILS = VIEW_CATEGORY_UNDECLARED + 4;
+ public static final int VIEW_CATEGORY_HIGH_POWER_APPS = VIEW_CATEGORY_UNDECLARED + 5;
/**
* Declare the view of this category.
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 6723839944f..b91275a542d 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -51,6 +51,7 @@ public class Settings extends SettingsActivity {
public static class ApplicationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ManageApplicationsActivity extends SettingsActivity { /* empty */ }
public static class AllApplicationsActivity extends SettingsActivity { /* empty */ }
+ public static class HighPowerApplicationsActivity extends SettingsActivity { /* empty */ }
public static class AppOpsSummaryActivity extends SettingsActivity {
@Override
public boolean isValidFragment(String className) {
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index fcbb5129d4b..89dbc99d1ae 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -89,6 +89,7 @@ import com.android.settings.deviceinfo.PublicVolumeSettings;
import com.android.settings.deviceinfo.StorageSettings;
import com.android.settings.deviceinfo.UsbSettings;
import com.android.settings.fuelgauge.BatterySaverSettings;
+import com.android.settings.fuelgauge.PowerUsageDetail;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
@@ -347,6 +348,7 @@ public class SettingsActivity extends Activity
ZenModeEventRuleSettings.class.getName(),
ZenModeExternalRuleSettings.class.getName(),
ProcessStatsUi.class.getName(),
+ PowerUsageDetail.class.getName(),
};
diff --git a/src/com/android/settings/applications/AdvancedAppSettings.java b/src/com/android/settings/applications/AdvancedAppSettings.java
index 52a8b8562f1..5e8d2f4a6ab 100644
--- a/src/com/android/settings/applications/AdvancedAppSettings.java
+++ b/src/com/android/settings/applications/AdvancedAppSettings.java
@@ -26,6 +26,7 @@ import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.ApplicationsState.AppEntry;
import com.android.settings.applications.ApplicationsState.Session;
+import com.android.settings.fuelgauge.PowerWhitelistBackend;
import com.android.settingslib.applications.PermissionsInfo;
import java.util.ArrayList;
@@ -38,11 +39,13 @@ public class AdvancedAppSettings extends SettingsPreferenceFragment implements
private static final String KEY_APP_PERM = "manage_perms";
private static final String KEY_APP_DOMAIN_URLS = "domain_urls";
+ private static final String KEY_HIGH_POWER_APPS = "high_power_apps";
private ApplicationsState mApplicationsState;
private Session mSession;
private Preference mAppPermsPreference;
private Preference mAppDomainURLsPreference;
+ private Preference mHighPowerPreference;
private PermissionsInfo mPermissionsInfo;
@Override
@@ -55,6 +58,7 @@ public class AdvancedAppSettings extends SettingsPreferenceFragment implements
mAppPermsPreference = findPreference(KEY_APP_PERM);
mAppDomainURLsPreference = findPreference(KEY_APP_DOMAIN_URLS);
+ mHighPowerPreference = findPreference(KEY_HIGH_POWER_APPS);
updateUI();
}
@@ -70,6 +74,10 @@ public class AdvancedAppSettings extends SettingsPreferenceFragment implements
String summary = getResources().getQuantityString(
R.plurals.domain_urls_apps_summary, countAppWithDomainURLs, countAppWithDomainURLs);
mAppDomainURLsPreference.setSummary(summary);
+
+ int highPowerCount = PowerWhitelistBackend.getInstance().getWhitelistSize();
+ mHighPowerPreference.setSummary(getResources().getQuantityString(R.plurals.high_power_count,
+ highPowerCount, highPowerCount));
}
@Override
diff --git a/src/com/android/settings/applications/AppInfoBase.java b/src/com/android/settings/applications/AppInfoBase.java
index 56fe885461e..2d402e53a49 100644
--- a/src/com/android/settings/applications/AppInfoBase.java
+++ b/src/com/android/settings/applications/AppInfoBase.java
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
+import android.app.Fragment;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
@@ -36,6 +37,7 @@ import android.util.Log;
import com.android.settings.InstrumentedPreferenceFragment;
import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
import com.android.settings.applications.ApplicationsState.AppEntry;
import java.util.ArrayList;
@@ -194,6 +196,17 @@ public abstract class AppInfoBase extends InstrumentedPreferenceFragment
refreshUi();
}
+ public static void startAppInfoFragment(Class extends AppInfoBase> fragment, int titleRes,
+ String pkg, int uid, Fragment source, int request) {
+ Bundle args = new Bundle();
+ args.putString(AppInfoBase.ARG_PACKAGE_NAME, pkg);
+
+ Intent intent = Utils.onBuildStartFragmentIntent(source.getActivity(), fragment.getName(),
+ args, null, titleRes, null, false);
+ source.getActivity().startActivityForResultAsUser(intent, request,
+ new UserHandle(UserHandle.getUserId(uid)));
+ }
+
public class MyAlertDialogFragment extends DialogFragment {
public MyAlertDialogFragment(int id, int errorCode) {
Bundle args = new Bundle();
diff --git a/src/com/android/settings/applications/AppStatePowerBridge.java b/src/com/android/settings/applications/AppStatePowerBridge.java
new file mode 100644
index 00000000000..40163cb2b2e
--- /dev/null
+++ b/src/com/android/settings/applications/AppStatePowerBridge.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 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.applications;
+
+import com.android.settings.applications.ApplicationsState.AppEntry;
+import com.android.settings.applications.ApplicationsState.AppFilter;
+import com.android.settings.fuelgauge.PowerWhitelistBackend;
+
+import java.util.ArrayList;
+
+/**
+ * Connects data from the PowerWhitelistBackend to ApplicationsState.
+ */
+public class AppStatePowerBridge extends AppStateBaseBridge {
+
+ private final PowerWhitelistBackend mBackend = PowerWhitelistBackend.getInstance();
+
+ public AppStatePowerBridge(ApplicationsState appState, Callback callback) {
+ super(appState, callback);
+ }
+
+ @Override
+ protected void loadAllExtraInfo() {
+ ArrayList apps = mAppSession.getAllApps();
+ final int N = apps.size();
+ for (int i = 0; i < N; i++) {
+ AppEntry app = apps.get(i);
+ app.extraInfo = mBackend.isWhitelisted(app.info.packageName)
+ ? Boolean.TRUE : Boolean.FALSE;
+ }
+ }
+
+ @Override
+ protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+ app.extraInfo = mBackend.isWhitelisted(pkg) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public static class HighPowerState {
+ public boolean isHighPower;
+ public boolean isSystemHighPower;
+ }
+
+ public static final AppFilter FILTER_POWER_WHITELISTED = new AppFilter() {
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(AppEntry info) {
+ return info.extraInfo == Boolean.TRUE;
+ }
+ };
+
+ public static final AppFilter FILTER_POWER_NOT_WHITELISTED = new AppFilter() {
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(AppEntry info) {
+ return info.extraInfo == Boolean.FALSE;
+ }
+ };
+
+}
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index ffd4959abf9..a6fee90a9dc 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -38,6 +38,7 @@ import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.BatteryStats;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -57,12 +58,16 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.os.BatterySipper;
+import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.DataUsageSummary;
import com.android.settings.DataUsageSummary.AppItem;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.applications.ApplicationsState.AppEntry;
+import com.android.settings.fuelgauge.BatteryEntry;
+import com.android.settings.fuelgauge.PowerUsageDetail;
import com.android.settings.net.ChartData;
import com.android.settings.net.ChartDataLoader;
import com.android.settings.notification.NotificationBackend;
@@ -108,6 +113,7 @@ public class InstalledAppDetails extends AppInfoBase
private static final String KEY_PERMISSION = "permission_settings";
private static final String KEY_DATA = "data_settings";
private static final String KEY_LAUNCH = "preferred_settings";
+ private static final String KEY_BATTERY = "battery";
private final HashSet mHomePackages = new HashSet();
@@ -131,6 +137,11 @@ public class InstalledAppDetails extends AppInfoBase
private ChartData mChartData;
private INetworkStatsSession mStatsSession;
+ private Preference mBatteryPreference;
+
+ private BatteryStatsHelper mBatteryHelper;
+ private BatterySipper mSipper;
+
private boolean handleDisableable(Button button) {
boolean disableable = false;
// Try to prevent the user from bricking their phone
@@ -221,6 +232,7 @@ public class InstalledAppDetails extends AppInfoBase
} catch (RemoteException e) {
throw new RuntimeException(e);
}
+ mBatteryHelper = new BatteryStatsHelper(getActivity(), true);
}
@Override
@@ -236,6 +248,7 @@ public class InstalledAppDetails extends AppInfoBase
getLoaderManager().restartLoader(LOADER_CHART_DATA,
ChartDataLoader.buildArgs(NetworkTemplate.buildTemplateMobileWildcard(), app),
mDataCallbacks);
+ new BatteryUpdater().execute();
}
@Override
@@ -263,6 +276,9 @@ public class InstalledAppDetails extends AppInfoBase
mPermissionsPreference.setOnPreferenceClickListener(this);
mDataPreference = findPreference(KEY_DATA);
mDataPreference.setOnPreferenceClickListener(this);
+ mBatteryPreference = findPreference(KEY_BATTERY);
+ mBatteryPreference.setEnabled(false);
+ mBatteryPreference.setOnPreferenceClickListener(this);
mLaunchPreference = findPreference(KEY_LAUNCH);
if ((mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
@@ -434,6 +450,8 @@ public class InstalledAppDetails extends AppInfoBase
mBackend));
mDataPreference.setSummary(getDataSummary());
+ updateBattery();
+
if (!mInitialized) {
// First time init: are we displaying an uninstalled app?
mInitialized = true;
@@ -459,6 +477,20 @@ public class InstalledAppDetails extends AppInfoBase
return true;
}
+ private void updateBattery() {
+ if (mSipper != null) {
+ mBatteryPreference.setEnabled(true);
+ int dischargeAmount = mBatteryHelper.getStats().getDischargeAmount(
+ BatteryStats.STATS_SINCE_CHARGED);
+ final int percentOfMax = (int) ((mSipper.totalPowerMah)
+ / mBatteryHelper.getTotalPower() * dischargeAmount + .5f);
+ mBatteryPreference.setSummary(getString(R.string.battery_summary, percentOfMax));
+ } else {
+ mBatteryPreference.setEnabled(false);
+ mBatteryPreference.setSummary(getString(R.string.no_battery_summary));
+ }
+ }
+
private CharSequence getDataSummary() {
if (mChartData != null) {
long totalBytes = mChartData.detail.getTotalBytes();
@@ -656,6 +688,10 @@ public class InstalledAppDetails extends AppInfoBase
SettingsActivity sa = (SettingsActivity) getActivity();
sa.startPreferencePanel(DataUsageSummary.class.getName(), args, -1,
getString(R.string.app_data_usage), this, SUB_INFO_FRAGMENT);
+ } else if (preference == mBatteryPreference) {
+ BatteryEntry entry = new BatteryEntry(getActivity(), null, mUserManager, mSipper);
+ PowerUsageDetail.startBatteryDetailPage((SettingsActivity) getActivity(),
+ mBatteryHelper, BatteryStats.STATS_SINCE_CHARGED, entry, true);
} else {
return false;
}
@@ -700,7 +736,31 @@ public class InstalledAppDetails extends AppInfoBase
}
}
- static class DisableChanger extends AsyncTask