Add high power whitelist for apps

- Strings not final!
 - New UX for power usage details (more preferency)
 - Add high power apps list shows on/off and screen to
   change (when possible)
 - Link from power usage summary to high power list
 - Link from advanced apps to high power list

Bug: 19991702
Change-Id: I97c927ed82d3b89041e4429b427508545763d66c
This commit is contained in:
Jason Monk
2015-04-29 12:46:42 -04:00
parent a283e6e325
commit 1eb54eb2ff
29 changed files with 952 additions and 597 deletions

View File

@@ -923,6 +923,15 @@
android:value="true" /> android:value="true" />
</activity> </activity>
<activity android:name="Settings$HighPowerApplicationsActivity"
android:label="@string/high_power_apps"
android:taskAffinity="">
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.applications.ManageApplications" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true" />
</activity>
<!-- Keep compatibility with old shortcuts. --> <!-- Keep compatibility with old shortcuts. -->
<activity-alias android:name=".applications.ManageApplications" <activity-alias android:name=".applications.ManageApplications"
android:label="@string/applications_settings" android:label="@string/applications_settings"

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="3dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<TextView
android:id="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItem"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@android:id/summary"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"
android:gravity="end" />
</LinearLayout>

View File

@@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingStart="4dip"
android:focusable="true"
android:orientation="vertical"
android:paddingEnd="?android:attr/scrollbarSize">
<TextView android:id="@+id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:paddingBottom="4dip"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- Spacer -->
<View
android:id="@+id/buttons_spacer_left"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:visibility="invisible" />
<Button
android:id="@+id/action_button"
android:layout_width="150dip"
android:paddingEnd="6dip"
android:layout_weight="0.3"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,48 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--Label for the item-->
<TextView
android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:singleLine="true"
android:ellipsize="middle"
android:layout_alignParentStart="true"
android:layout_toStartOf="@+id/value"
android:layout_marginBottom="4dip"
android:layout_marginTop="4dip"
android:layout_marginEnd="4dip"/>
<TextView
android:id="@+id/value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="normal"
android:singleLine="true"
android:layout_marginBottom="4dip"
android:layout_marginTop="4dip" />
</RelativeLayout>

View File

@@ -1,111 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:scrollbarStyle="@integer/preference_scrollbar_style">
<LinearLayout
android:id="@+id/all_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:orientation="vertical">
<include layout="@layout/app_percentage_item" />
<!-- Force stop and report buttons -->
<LinearLayout
android:id="@+id/two_buttons_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="6dip"
android:orientation="vertical">
<include
layout="@layout/two_buttons_panel"/>
</LinearLayout>
<TextView
style="?android:attr/listSeparatorTextViewStyle"
android:text="@string/details_subtitle" />
<LinearLayout
android:id="@+id/details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="6dip"
android:orientation="vertical">
<!-- Insert detail items here -->
</LinearLayout>
<LinearLayout
android:id="@+id/controls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/controls_title"
style="?android:attr/listSeparatorTextViewStyle"
android:layout_marginTop="6dip"
android:text="@string/controls_subtitle" />
<!-- Controls go here ... -->
</LinearLayout>
<LinearLayout
android:id="@+id/messages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/messages_title"
style="?android:attr/listSeparatorTextViewStyle"
android:layout_marginTop="6dip" />
<!-- Messages go here ... -->
</LinearLayout>
<TextView
android:id="@+id/packages_section_title"
style="?android:attr/listSeparatorTextViewStyle"
android:layout_marginTop="6dip"
android:text="@string/packages_subtitle" />
<LinearLayout
android:id="@+id/packages_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="6dip"
android:orientation="vertical">
<!-- Insert detail items here -->
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingStart="4dip"
android:paddingEnd="?android:attr/scrollbarSize"
android:paddingBottom="4dip"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium" />

View File

@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:minHeight="@dimen/battery_history_chart_height">
<include layout="@layout/battery_history_chart" />
<TextView android:id="@+id/labelsHeader"
android:layout_width="match_parent"
android:layout_height="48dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="14sp"
android:textColor="?android:attr/colorControlActivated"
android:gravity="start|center_vertical"
android:text="@string/power_usage_list_summary"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />
</LinearLayout>

View File

@@ -6642,4 +6642,31 @@
<!-- Label for process [CHAR LIMIT=25] --> <!-- Label for process [CHAR LIMIT=25] -->
<string name="process_format">Process <xliff:g id="count" example="3">%1$d</xliff:g></string> <string name="process_format">Process <xliff:g id="count" example="3">%1$d</xliff:g></string>
<!-- Label for whether app is allowed to use a lot ef power [CHAR LIMIT=25]-->
<string name="high_power" translatable="false">High power</string>
<!-- List of apps that are allowed to use a lot of power [CHAR LIMIT=25]-->
<string name="high_power_apps" translatable="false">High power apps</string>
<!-- Summary of app allowed to use a lot of power [CHAR LIMIT=25] -->
<string name="high_power_on">On</string>
<!-- Summary of app not allowed to use a lot of power [CHAR LIMIT=25] -->
<string name="high_power_off">Off</string>
<!-- Description of high power switch [CHAR LIMIT=NONE] -->
<string name="high_power_desc" translatable="false">High powered apps description text goes here. This is a placeholder.</string>
<!-- Description of number of apps with high power turned on [CHAR LIMIT=NONE] -->
<plurals name="high_power_count" translatable="false">
<item quantity="one">1 app is allowed to ignore restrictions like battery saver mode, sync etc.</item>
<item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> apps is allowed to ignore restrictions like battery saver mode, sync etc.</item>
</plurals>
<!-- Summary of power usage for an app [CHAR LIMIT=NONE] -->
<string name="battery_summary" translatable="false"><xliff:g id="percentage" example="2">%1$d</xliff:g>%% use since last full charge</string>
<!-- Summary for app with no battery usage [CHAR LIMIT=NONE] -->
<string name="no_battery_summary" translatable="false">No battery use since last full charge</string>
</resources> </resources>

View File

@@ -25,12 +25,6 @@
android:title="@string/default_apps_title" android:title="@string/default_apps_title"
settings:keywords="@string/keywords_default_apps" /> settings:keywords="@string/keywords_default_apps" />
<PreferenceScreen
android:key="manage_perms"
android:fragment="com.android.settings.applications.ManagePermissions"
android:title="@string/app_permissions"
settings:keywords="@string/keywords_app_permissions" />
<PreferenceScreen <PreferenceScreen
android:key="domain_urls" android:key="domain_urls"
android:title="@string/domain_urls_title" android:title="@string/domain_urls_title"
@@ -40,4 +34,19 @@
android:value="com.android.settings.Settings$DomainsURLsAppListActivity" /> android:value="com.android.settings.Settings$DomainsURLsAppListActivity" />
</PreferenceScreen> </PreferenceScreen>
<PreferenceScreen
android:key="manage_perms"
android:fragment="com.android.settings.applications.ManagePermissions"
android:title="@string/app_permissions"
settings:keywords="@string/keywords_app_permissions" />
<PreferenceScreen
android:key="high_power_apps"
android:title="@string/high_power_apps"
android:fragment="com.android.settings.applications.ManageApplications">
<extra
android:name="classname"
android:value="com.android.settings.Settings$HighPowerApplicationsActivity" />
</PreferenceScreen>
</PreferenceScreen> </PreferenceScreen>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project <!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -14,13 +14,16 @@
limitations under the License. limitations under the License.
--> -->
<TextView <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:id="@+id/label" android:title="@string/high_power">
android:layout_width="wrap_content"
android:layout_height="wrap_content" <SwitchPreference
android:textAppearance="?android:attr/textAppearanceMedium" android:key="high_power_switch"
android:singleLine="true" android:title="@string/high_power" />
android:layout_alignParentStart="true"
android:layout_marginBottom="2dip" <Preference
android:layout_marginTop="2dip" /> android:summary="@string/high_power_desc"
android:selectable="false" />
</PreferenceScreen>

View File

@@ -18,7 +18,8 @@
android:title="@string/application_info_label"> android:title="@string/application_info_label">
<com.android.settings.applications.LayoutPreference <com.android.settings.applications.LayoutPreference
android:key="header_view" android:key="header_view"
android:layout="@layout/installed_app_details" /> android:layout="@layout/installed_app_details"
android:selectable="false" />
<Preference <Preference
android:key="storage_settings" android:key="storage_settings"
@@ -44,4 +45,10 @@
android:key="preferred_settings" android:key="preferred_settings"
android:title="@string/launch_by_default" android:title="@string/launch_by_default"
android:selectable="true" /> android:selectable="true" />
<Preference
android:key="battery"
android:title="@string/power_usage_summary_title"
android:selectable="true" />
</PreferenceScreen> </PreferenceScreen>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
<com.android.settings.fuelgauge.BatteryHistoryPreference
android:key="battery_history" />
<com.android.settings.applications.LayoutPreference
android:key="two_buttons"
android:layout="@layout/two_buttons_panel"
android:selectable="false" />
<Preference
android:key="high_power"
android:title="@string/high_power" />
<PreferenceCategory
android:key="details_parent"
android:title="@string/details_subtitle" />
<PreferenceCategory
android:key="controls_parent"
android:title="@string/controls_subtitle" />
<PreferenceCategory
android:key="messages_parent" />
<PreferenceCategory
android:key="packages_parent"
android:title="@string/packages_subtitle" />
</PreferenceScreen>

View File

@@ -17,6 +17,13 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings" xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:title="@string/power_usage_summary_title" android:title="@string/power_usage_summary_title"
settings:keywords="@string/keywords_battery" settings:keywords="@string/keywords_battery">
android:key="app_list">
<com.android.settings.fuelgauge.BatteryHistoryPreference
android:key="battery_history" />
<PreferenceCategory
android:key="app_list"
android:title="@string/power_usage_list_summary" />
</PreferenceScreen> </PreferenceScreen>

View File

@@ -18,6 +18,7 @@ package com.android.settings;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
@@ -29,6 +30,11 @@ public class AppHeader {
public static void createAppHeader(final Activity activity, Drawable icon, CharSequence label, public static void createAppHeader(final Activity activity, Drawable icon, CharSequence label,
final Intent settingsIntent) { 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 View content = activity.findViewById(R.id.main_content);
final ViewGroup contentParent = (ViewGroup) content.getParent(); final ViewGroup contentParent = (ViewGroup) content.getParent();
final View bar = activity.getLayoutInflater().inflate(R.layout.app_header, 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); final ImageView appIcon = (ImageView) bar.findViewById(R.id.app_icon);
appIcon.setImageDrawable(icon); appIcon.setImageDrawable(icon);
if (tintColorRes != 0) {
appIcon.setImageTintList(ColorStateList.valueOf(activity.getColor(tintColorRes)));
}
final TextView appName = (TextView) bar.findViewById(R.id.app_name); final TextView appName = (TextView) bar.findViewById(R.id.app_name);
appName.setText(label); appName.setText(label);

View File

@@ -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_DEFAULT_APPS = VIEW_CATEGORY_UNDECLARED + 1;
public static final int VIEW_CATEGORY_STORAGE_APPS = VIEW_CATEGORY_UNDECLARED + 2; 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_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. * Declare the view of this category.

View File

@@ -51,6 +51,7 @@ public class Settings extends SettingsActivity {
public static class ApplicationSettingsActivity extends SettingsActivity { /* empty */ } public static class ApplicationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ManageApplicationsActivity extends SettingsActivity { /* empty */ } public static class ManageApplicationsActivity extends SettingsActivity { /* empty */ }
public static class AllApplicationsActivity extends SettingsActivity { /* empty */ } public static class AllApplicationsActivity extends SettingsActivity { /* empty */ }
public static class HighPowerApplicationsActivity extends SettingsActivity { /* empty */ }
public static class AppOpsSummaryActivity extends SettingsActivity { public static class AppOpsSummaryActivity extends SettingsActivity {
@Override @Override
public boolean isValidFragment(String className) { public boolean isValidFragment(String className) {

View File

@@ -89,6 +89,7 @@ import com.android.settings.deviceinfo.PublicVolumeSettings;
import com.android.settings.deviceinfo.StorageSettings; import com.android.settings.deviceinfo.StorageSettings;
import com.android.settings.deviceinfo.UsbSettings; import com.android.settings.deviceinfo.UsbSettings;
import com.android.settings.fuelgauge.BatterySaverSettings; import com.android.settings.fuelgauge.BatterySaverSettings;
import com.android.settings.fuelgauge.PowerUsageDetail;
import com.android.settings.fuelgauge.PowerUsageSummary; import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.inputmethod.InputMethodAndLanguageSettings; import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
import com.android.settings.inputmethod.KeyboardLayoutPickerFragment; import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
@@ -347,6 +348,7 @@ public class SettingsActivity extends Activity
ZenModeEventRuleSettings.class.getName(), ZenModeEventRuleSettings.class.getName(),
ZenModeExternalRuleSettings.class.getName(), ZenModeExternalRuleSettings.class.getName(),
ProcessStatsUi.class.getName(), ProcessStatsUi.class.getName(),
PowerUsageDetail.class.getName(),
}; };

View File

@@ -26,6 +26,7 @@ import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment; import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.ApplicationsState.AppEntry; import com.android.settings.applications.ApplicationsState.AppEntry;
import com.android.settings.applications.ApplicationsState.Session; import com.android.settings.applications.ApplicationsState.Session;
import com.android.settings.fuelgauge.PowerWhitelistBackend;
import com.android.settingslib.applications.PermissionsInfo; import com.android.settingslib.applications.PermissionsInfo;
import java.util.ArrayList; 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_PERM = "manage_perms";
private static final String KEY_APP_DOMAIN_URLS = "domain_urls"; 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 ApplicationsState mApplicationsState;
private Session mSession; private Session mSession;
private Preference mAppPermsPreference; private Preference mAppPermsPreference;
private Preference mAppDomainURLsPreference; private Preference mAppDomainURLsPreference;
private Preference mHighPowerPreference;
private PermissionsInfo mPermissionsInfo; private PermissionsInfo mPermissionsInfo;
@Override @Override
@@ -55,6 +58,7 @@ public class AdvancedAppSettings extends SettingsPreferenceFragment implements
mAppPermsPreference = findPreference(KEY_APP_PERM); mAppPermsPreference = findPreference(KEY_APP_PERM);
mAppDomainURLsPreference = findPreference(KEY_APP_DOMAIN_URLS); mAppDomainURLsPreference = findPreference(KEY_APP_DOMAIN_URLS);
mHighPowerPreference = findPreference(KEY_HIGH_POWER_APPS);
updateUI(); updateUI();
} }
@@ -70,6 +74,10 @@ public class AdvancedAppSettings extends SettingsPreferenceFragment implements
String summary = getResources().getQuantityString( String summary = getResources().getQuantityString(
R.plurals.domain_urls_apps_summary, countAppWithDomainURLs, countAppWithDomainURLs); R.plurals.domain_urls_apps_summary, countAppWithDomainURLs, countAppWithDomainURLs);
mAppDomainURLsPreference.setSummary(summary); mAppDomainURLsPreference.setSummary(summary);
int highPowerCount = PowerWhitelistBackend.getInstance().getWhitelistSize();
mHighPowerPreference.setSummary(getResources().getQuantityString(R.plurals.high_power_count,
highPowerCount, highPowerCount));
} }
@Override @Override

View File

@@ -20,6 +20,7 @@ import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.app.DialogFragment; import android.app.DialogFragment;
import android.app.Fragment;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -36,6 +37,7 @@ import android.util.Log;
import com.android.settings.InstrumentedPreferenceFragment; import com.android.settings.InstrumentedPreferenceFragment;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.applications.ApplicationsState.AppEntry; import com.android.settings.applications.ApplicationsState.AppEntry;
import java.util.ArrayList; import java.util.ArrayList;
@@ -194,6 +196,17 @@ public abstract class AppInfoBase extends InstrumentedPreferenceFragment
refreshUi(); 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 class MyAlertDialogFragment extends DialogFragment {
public MyAlertDialogFragment(int id, int errorCode) { public MyAlertDialogFragment(int id, int errorCode) {
Bundle args = new Bundle(); Bundle args = new Bundle();

View File

@@ -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<AppEntry> 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;
}
};
}

View File

@@ -38,6 +38,7 @@ import android.net.NetworkTemplate;
import android.net.TrafficStats; import android.net.TrafficStats;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.BatteryStats;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
@@ -57,12 +58,16 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.android.internal.logging.MetricsLogger; 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;
import com.android.settings.DataUsageSummary.AppItem; import com.android.settings.DataUsageSummary.AppItem;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.applications.ApplicationsState.AppEntry; 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.ChartData;
import com.android.settings.net.ChartDataLoader; import com.android.settings.net.ChartDataLoader;
import com.android.settings.notification.NotificationBackend; 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_PERMISSION = "permission_settings";
private static final String KEY_DATA = "data_settings"; private static final String KEY_DATA = "data_settings";
private static final String KEY_LAUNCH = "preferred_settings"; private static final String KEY_LAUNCH = "preferred_settings";
private static final String KEY_BATTERY = "battery";
private final HashSet<String> mHomePackages = new HashSet<String>(); private final HashSet<String> mHomePackages = new HashSet<String>();
@@ -131,6 +137,11 @@ public class InstalledAppDetails extends AppInfoBase
private ChartData mChartData; private ChartData mChartData;
private INetworkStatsSession mStatsSession; private INetworkStatsSession mStatsSession;
private Preference mBatteryPreference;
private BatteryStatsHelper mBatteryHelper;
private BatterySipper mSipper;
private boolean handleDisableable(Button button) { private boolean handleDisableable(Button button) {
boolean disableable = false; boolean disableable = false;
// Try to prevent the user from bricking their phone // Try to prevent the user from bricking their phone
@@ -221,6 +232,7 @@ public class InstalledAppDetails extends AppInfoBase
} catch (RemoteException e) { } catch (RemoteException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
mBatteryHelper = new BatteryStatsHelper(getActivity(), true);
} }
@Override @Override
@@ -236,6 +248,7 @@ public class InstalledAppDetails extends AppInfoBase
getLoaderManager().restartLoader(LOADER_CHART_DATA, getLoaderManager().restartLoader(LOADER_CHART_DATA,
ChartDataLoader.buildArgs(NetworkTemplate.buildTemplateMobileWildcard(), app), ChartDataLoader.buildArgs(NetworkTemplate.buildTemplateMobileWildcard(), app),
mDataCallbacks); mDataCallbacks);
new BatteryUpdater().execute();
} }
@Override @Override
@@ -263,6 +276,9 @@ public class InstalledAppDetails extends AppInfoBase
mPermissionsPreference.setOnPreferenceClickListener(this); mPermissionsPreference.setOnPreferenceClickListener(this);
mDataPreference = findPreference(KEY_DATA); mDataPreference = findPreference(KEY_DATA);
mDataPreference.setOnPreferenceClickListener(this); mDataPreference.setOnPreferenceClickListener(this);
mBatteryPreference = findPreference(KEY_BATTERY);
mBatteryPreference.setEnabled(false);
mBatteryPreference.setOnPreferenceClickListener(this);
mLaunchPreference = findPreference(KEY_LAUNCH); mLaunchPreference = findPreference(KEY_LAUNCH);
if ((mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { if ((mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
@@ -434,6 +450,8 @@ public class InstalledAppDetails extends AppInfoBase
mBackend)); mBackend));
mDataPreference.setSummary(getDataSummary()); mDataPreference.setSummary(getDataSummary());
updateBattery();
if (!mInitialized) { if (!mInitialized) {
// First time init: are we displaying an uninstalled app? // First time init: are we displaying an uninstalled app?
mInitialized = true; mInitialized = true;
@@ -459,6 +477,20 @@ public class InstalledAppDetails extends AppInfoBase
return true; 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() { private CharSequence getDataSummary() {
if (mChartData != null) { if (mChartData != null) {
long totalBytes = mChartData.detail.getTotalBytes(); long totalBytes = mChartData.detail.getTotalBytes();
@@ -656,6 +688,10 @@ public class InstalledAppDetails extends AppInfoBase
SettingsActivity sa = (SettingsActivity) getActivity(); SettingsActivity sa = (SettingsActivity) getActivity();
sa.startPreferencePanel(DataUsageSummary.class.getName(), args, -1, sa.startPreferencePanel(DataUsageSummary.class.getName(), args, -1,
getString(R.string.app_data_usage), this, SUB_INFO_FRAGMENT); 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 { } else {
return false; return false;
} }
@@ -700,7 +736,31 @@ public class InstalledAppDetails extends AppInfoBase
} }
} }
static class DisableChanger extends AsyncTask<Object, Object, Object> { private class BatteryUpdater extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
mBatteryHelper.create((Bundle) null);
mBatteryHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
mUserManager.getUserProfiles());
List<BatterySipper> usageList = mBatteryHelper.getUsageList();
final int N = usageList.size();
for (int i = 0; i < N; i++) {
BatterySipper sipper = usageList.get(i);
if (sipper.getUid() == mPackageInfo.applicationInfo.uid) {
mSipper = sipper;
break;
}
}
return null;
}
@Override
protected void onPostExecute(Void result) {
refreshUi();
}
}
private static class DisableChanger extends AsyncTask<Object, Object, Object> {
final PackageManager mPm; final PackageManager mPm;
final WeakReference<InstalledAppDetails> mActivity; final WeakReference<InstalledAppDetails> mActivity;
final ApplicationInfo mInfo; final ApplicationInfo mInfo;

View File

@@ -45,7 +45,9 @@ public class LayoutPreference extends Preference {
.inflate(layoutResource, null, false); .inflate(layoutResource, null, false);
final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details); final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details);
if (allDetails != null) {
Utils.forceCustomPadding(allDetails, true /* additive padding */); Utils.forceCustomPadding(allDetails, true /* additive padding */);
}
mRootView = view; mRootView = view;
setShouldDisableView(false); setShouldDisableView(false);
} }

View File

@@ -55,6 +55,7 @@ import com.android.settings.InstrumentedFragment;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Settings.AllApplicationsActivity; import com.android.settings.Settings.AllApplicationsActivity;
import com.android.settings.Settings.DomainsURLsAppListActivity; import com.android.settings.Settings.DomainsURLsAppListActivity;
import com.android.settings.Settings.HighPowerApplicationsActivity;
import com.android.settings.Settings.NotificationAppListActivity; import com.android.settings.Settings.NotificationAppListActivity;
import com.android.settings.Settings.StorageUseActivity; import com.android.settings.Settings.StorageUseActivity;
import com.android.settings.Settings.UsageAccessSettingsActivity; import com.android.settings.Settings.UsageAccessSettingsActivity;
@@ -65,6 +66,7 @@ import com.android.settings.applications.ApplicationsState.AppEntry;
import com.android.settings.applications.ApplicationsState.AppFilter; import com.android.settings.applications.ApplicationsState.AppFilter;
import com.android.settings.applications.ApplicationsState.CompoundFilter; import com.android.settings.applications.ApplicationsState.CompoundFilter;
import com.android.settings.applications.ApplicationsState.VolumeFilter; import com.android.settings.applications.ApplicationsState.VolumeFilter;
import com.android.settings.fuelgauge.HighPowerDetail;
import com.android.settings.notification.NotificationBackend; import com.android.settings.notification.NotificationBackend;
import com.android.settings.notification.NotificationBackend.AppRow; import com.android.settings.notification.NotificationBackend.AppRow;
@@ -117,6 +119,8 @@ public class ManageApplications extends InstrumentedFragment
public static final int FILTER_APPS_WORK = 8; public static final int FILTER_APPS_WORK = 8;
public static final int FILTER_APPS_WITH_DOMAIN_URLS = 9; public static final int FILTER_APPS_WITH_DOMAIN_URLS = 9;
public static final int FILTER_APPS_USAGE_ACCESS = 10; public static final int FILTER_APPS_USAGE_ACCESS = 10;
public static final int FILTER_APPS_POWER_WHITELIST = 11;
public static final int FILTER_APPS_POWER_NO_WHITELIST = 12;
// This is the string labels for the filter modes above, the order must be kept in sync. // This is the string labels for the filter modes above, the order must be kept in sync.
public static final int[] FILTER_LABELS = new int[] { public static final int[] FILTER_LABELS = new int[] {
@@ -131,6 +135,8 @@ public class ManageApplications extends InstrumentedFragment
R.string.filter_work_apps, // Work R.string.filter_work_apps, // Work
R.string.filter_with_domain_urls_apps, // Domain URLs R.string.filter_with_domain_urls_apps, // Domain URLs
R.string.filter_all_apps, // Usage access screen, never displayed R.string.filter_all_apps, // Usage access screen, never displayed
R.string.high_power_on, // High power whitelist, on
R.string.high_power_off, // High power whitelist, off
}; };
// This is the actual mapping to filters from FILTER_ constants above, the order must // This is the actual mapping to filters from FILTER_ constants above, the order must
// be kept in sync. // be kept in sync.
@@ -146,6 +152,8 @@ public class ManageApplications extends InstrumentedFragment
ApplicationsState.FILTER_WORK, // Work ApplicationsState.FILTER_WORK, // Work
ApplicationsState.FILTER_WITH_DOMAIN_URLS, // Apps with Domain URLs ApplicationsState.FILTER_WITH_DOMAIN_URLS, // Apps with Domain URLs
AppStateUsageBridge.FILTER_APP_USAGE, // Apps with Domain URLs AppStateUsageBridge.FILTER_APP_USAGE, // Apps with Domain URLs
AppStatePowerBridge.FILTER_POWER_WHITELISTED, // High power whitelist, on
AppStatePowerBridge.FILTER_POWER_NOT_WHITELISTED, // High power whitelist, off
}; };
// sort order // sort order
@@ -185,6 +193,7 @@ public class ManageApplications extends InstrumentedFragment
public static final int LIST_TYPE_DOMAINS_URLS = 2; public static final int LIST_TYPE_DOMAINS_URLS = 2;
public static final int LIST_TYPE_STORAGE = 3; public static final int LIST_TYPE_STORAGE = 3;
public static final int LIST_TYPE_USAGE_ACCESS = 4; public static final int LIST_TYPE_USAGE_ACCESS = 4;
public static final int LIST_TYPE_HIGH_POWER = 5;
private View mRootView; private View mRootView;
@@ -228,6 +237,8 @@ public class ManageApplications extends InstrumentedFragment
} else if (className.equals(UsageAccessSettingsActivity.class.getName())) { } else if (className.equals(UsageAccessSettingsActivity.class.getName())) {
mListType = LIST_TYPE_USAGE_ACCESS; mListType = LIST_TYPE_USAGE_ACCESS;
getActivity().getActionBar().setTitle(R.string.usage_access_title); getActivity().getActionBar().setTitle(R.string.usage_access_title);
} else if (className.equals(HighPowerApplicationsActivity.class.getName())) {
mListType = LIST_TYPE_HIGH_POWER;
} else { } else {
mListType = LIST_TYPE_MAIN; mListType = LIST_TYPE_MAIN;
} }
@@ -310,6 +321,9 @@ public class ManageApplications extends InstrumentedFragment
mFilterAdapter.enableFilter(FILTER_APPS_SENSITIVE); mFilterAdapter.enableFilter(FILTER_APPS_SENSITIVE);
mFilterAdapter.enableFilter(FILTER_APPS_NO_PEEKING); mFilterAdapter.enableFilter(FILTER_APPS_NO_PEEKING);
} }
if (mListType == LIST_TYPE_HIGH_POWER) {
mFilterAdapter.enableFilter(FILTER_APPS_POWER_NO_WHITELIST);
}
if (mListType == LIST_TYPE_STORAGE) { if (mListType == LIST_TYPE_STORAGE) {
mApplications.setOverrideFilter(new VolumeFilter(mVolumeUuid)); mApplications.setOverrideFilter(new VolumeFilter(mVolumeUuid));
} }
@@ -325,12 +339,12 @@ public class ManageApplications extends InstrumentedFragment
private int getDefaultFilter() { private int getDefaultFilter() {
switch (mListType) { switch (mListType) {
case LIST_TYPE_MAIN:
return FILTER_APPS_ALL;
case LIST_TYPE_DOMAINS_URLS: case LIST_TYPE_DOMAINS_URLS:
return FILTER_APPS_WITH_DOMAIN_URLS; return FILTER_APPS_WITH_DOMAIN_URLS;
case LIST_TYPE_USAGE_ACCESS: case LIST_TYPE_USAGE_ACCESS:
return FILTER_APPS_USAGE_ACCESS; return FILTER_APPS_USAGE_ACCESS;
case LIST_TYPE_HIGH_POWER:
return FILTER_APPS_POWER_WHITELIST;
default: default:
return FILTER_APPS_ALL; return FILTER_APPS_ALL;
} }
@@ -349,6 +363,8 @@ public class ManageApplications extends InstrumentedFragment
return InstrumentedFragment.VIEW_CATEGORY_STORAGE_APPS; return InstrumentedFragment.VIEW_CATEGORY_STORAGE_APPS;
case LIST_TYPE_USAGE_ACCESS: case LIST_TYPE_USAGE_ACCESS:
return MetricsLogger.USAGE_ACCESS; return MetricsLogger.USAGE_ACCESS;
case LIST_TYPE_HIGH_POWER:
return InstrumentedFragment.VIEW_CATEGORY_HIGH_POWER_APPS;
default: default:
return MetricsLogger.VIEW_UNKNOWN; return MetricsLogger.VIEW_UNKNOWN;
} }
@@ -426,6 +442,9 @@ public class ManageApplications extends InstrumentedFragment
case LIST_TYPE_STORAGE: case LIST_TYPE_STORAGE:
startAppInfoFragment(AppStorageSettings.class, R.string.storage_settings); startAppInfoFragment(AppStorageSettings.class, R.string.storage_settings);
break; break;
case LIST_TYPE_HIGH_POWER:
startAppInfoFragment(HighPowerDetail.class, R.string.high_power);
break;
// TODO: Figure out if there is a way where we can spin up the profile's settings // TODO: Figure out if there is a way where we can spin up the profile's settings
// process ahead of time, to avoid a long load of data when user clicks on a managed app. // process ahead of time, to avoid a long load of data when user clicks on a managed app.
// Maybe when they load the list of apps that contains managed profile apps. // Maybe when they load the list of apps that contains managed profile apps.
@@ -436,13 +455,8 @@ public class ManageApplications extends InstrumentedFragment
} }
private void startAppInfoFragment(Class<? extends AppInfoBase> fragment, int titleRes) { private void startAppInfoFragment(Class<? extends AppInfoBase> fragment, int titleRes) {
Bundle args = new Bundle(); AppInfoBase.startAppInfoFragment(fragment, titleRes, mCurrentPkgName, mCurrentUid, this,
args.putString(AppInfoBase.ARG_PACKAGE_NAME, mCurrentPkgName); INSTALLED_APP_DETAILS);
Intent intent = Utils.onBuildStartFragmentIntent(getActivity(), fragment.getName(), args,
null, titleRes, null, false);
getActivity().startActivityForResultAsUser(intent, INSTALLED_APP_DETAILS,
new UserHandle(UserHandle.getUserId(mCurrentUid)));
} }
@Override @Override
@@ -685,6 +699,8 @@ public class ManageApplications extends InstrumentedFragment
mState, this, manageApplications.mNotifBackend); mState, this, manageApplications.mNotifBackend);
} else if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) { } else if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) {
mExtraInfoBridge = new AppStateUsageBridge(mContext, mState, this); mExtraInfoBridge = new AppStateUsageBridge(mContext, mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_HIGH_POWER) {
mExtraInfoBridge = new AppStatePowerBridge(mState, this);
} else { } else {
mExtraInfoBridge = null; mExtraInfoBridge = null;
} }
@@ -994,6 +1010,10 @@ public class ManageApplications extends InstrumentedFragment
} }
break; break;
case LIST_TYPE_HIGH_POWER:
holder.summary.setText(HighPowerDetail.getSummary(mContext, holder.entry));
break;
default: default:
holder.updateSizeText(mManageApplications.mInvalidSizeStr, mWhichSize); holder.updateSizeText(mManageApplications.mInvalidSizeStr, mWhichSize);
break; break;

View File

@@ -19,10 +19,16 @@ package com.android.settings.fuelgauge;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.Bundle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity;
/** /**
* Custom preference for displaying power consumption as a bar and an icon on the left for the * Custom preference for displaying power consumption as a bar and an icon on the left for the
@@ -31,38 +37,60 @@ import com.android.settings.R;
*/ */
public class BatteryHistoryPreference extends Preference { public class BatteryHistoryPreference extends Preference {
final private BatteryStats mStats; protected static final String BATTERY_HISTORY_FILE = "tmp_bat_history.bin";
final private Intent mBatteryBroadcast;
private BatteryStats mStats;
private Intent mBatteryBroadcast;
private boolean mHideLabels;
private View mLabelHeader;
private BatteryHistoryChart mChart; private BatteryHistoryChart mChart;
private BatteryStatsHelper mHelper;
public BatteryHistoryPreference(Context context, BatteryStats stats, Intent batteryBroadcast) { public BatteryHistoryPreference(Context context, AttributeSet attrs) {
super(context); super(context, attrs);
setLayoutResource(R.layout.preference_batteryhistory); }
mStats = stats;
mBatteryBroadcast = batteryBroadcast; @Override
public void performClick(PreferenceScreen preferenceScreen) {
if (!isEnabled()) {
return;
}
mHelper.storeStatsHistoryInFile(BATTERY_HISTORY_FILE);
Bundle args = new Bundle();
args.putString(BatteryHistoryDetail.EXTRA_STATS, BATTERY_HISTORY_FILE);
args.putParcelable(BatteryHistoryDetail.EXTRA_BROADCAST,
mHelper.getBatteryBroadcast());
if (getContext() instanceof SettingsActivity) {
SettingsActivity sa = (SettingsActivity) getContext();
sa.startPreferencePanel(BatteryHistoryDetail.class.getName(), args,
R.string.history_details_title, null, null, 0);
}
}
public void setStats(BatteryStatsHelper batteryStats) {
// Clear out the chart to receive new data.
mChart = null;
mHelper = batteryStats;
mStats = batteryStats.getStats();
mBatteryBroadcast = batteryStats.getBatteryBroadcast();
if (getLayoutResource() != R.layout.battery_history_chart) {
// Now we should have some data, set the layout we want.
setLayoutResource(R.layout.battery_history_chart);
}
notifyChanged();
} }
BatteryStats getStats() { BatteryStats getStats() {
return mStats; return mStats;
} }
public void setHideLabels(boolean hide) {
if (mHideLabels != hide) {
mHideLabels = hide;
if (mLabelHeader != null) {
mLabelHeader.setVisibility(hide ? View.GONE : View.VISIBLE);
}
}
}
@Override @Override
protected void onBindView(View view) { protected void onBindView(View view) {
super.onBindView(view); super.onBindView(view);
BatteryHistoryChart chart = (BatteryHistoryChart)view.findViewById( if (mStats == null) {
return;
}
BatteryHistoryChart chart = (BatteryHistoryChart) view.findViewById(
R.id.battery_history_chart); R.id.battery_history_chart);
if (mChart == null) { if (mChart == null) {
// First time: use and initialize this chart. // First time: use and initialize this chart.
@@ -71,15 +99,13 @@ public class BatteryHistoryPreference extends Preference {
} else { } else {
// All future times: forget the newly inflated chart, re-use the // All future times: forget the newly inflated chart, re-use the
// already initialized chart from last time. // already initialized chart from last time.
ViewGroup parent = (ViewGroup)chart.getParent(); ViewGroup parent = (ViewGroup) chart.getParent();
int index = parent.indexOfChild(chart); int index = parent.indexOfChild(chart);
parent.removeViewAt(index); parent.removeViewAt(index);
if (mChart.getParent() != null) { if (mChart.getParent() != null) {
((ViewGroup)mChart.getParent()).removeView(mChart); ((ViewGroup) mChart.getParent()).removeView(mChart);
} }
parent.addView(mChart, index); parent.addView(mChart, index);
} }
mLabelHeader = view.findViewById(R.id.labelsHeader);
mLabelHeader.setVisibility(mHideLabels ? View.GONE : View.VISIBLE);
} }
} }

View File

@@ -0,0 +1,84 @@
/*
* 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.fuelgauge;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.SwitchPreference;
import com.android.settings.InstrumentedFragment;
import com.android.settings.R;
import com.android.settings.applications.AppInfoWithHeader;
import com.android.settings.applications.ApplicationsState.AppEntry;
public class HighPowerDetail extends AppInfoWithHeader implements OnPreferenceChangeListener {
private static final String KEY_HIGH_POWER_SWITCH = "high_power_switch";
private final PowerWhitelistBackend mBackend = PowerWhitelistBackend.getInstance();
private SwitchPreference mUsageSwitch;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.high_power_details);
mUsageSwitch = (SwitchPreference) findPreference(KEY_HIGH_POWER_SWITCH);
mUsageSwitch.setOnPreferenceChangeListener(this);
}
@Override
protected boolean refreshUi() {
mUsageSwitch.setEnabled(!mBackend.isSysWhitelisted(mPackageName));
mUsageSwitch.setChecked(mBackend.isWhitelisted(mPackageName));
return true;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (newValue == Boolean.TRUE) {
mBackend.addApp(mPackageName);
} else {
mBackend.removeApp(mPackageName);
}
return true;
}
@Override
protected AlertDialog createDialog(int id, int errorCode) {
return null;
}
@Override
protected int getMetricsCategory() {
return InstrumentedFragment.VIEW_CATEGORY_HIGH_POWER_DETAILS;
}
public static CharSequence getSummary(Context context, AppEntry entry) {
return getSummary(context, entry.info.packageName);
}
public static CharSequence getSummary(Context context, String pkg) {
return context.getString(PowerWhitelistBackend.getInstance().isWhitelisted(pkg)
? R.string.high_power_on : R.string.high_power_off);
}
}

View File

@@ -0,0 +1,172 @@
/*
* 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.fuelgauge;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryStats;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.UserManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
/**
* Common base class for things that need to show the battery usage graph.
*/
public abstract class PowerUsageBase extends SettingsPreferenceFragment {
// +1 to allow ordering for PowerUsageSummary.
private static final int MENU_STATS_REFRESH = Menu.FIRST + 1;
protected BatteryStatsHelper mStatsHelper;
protected UserManager mUm;
private String mBatteryLevel;
private String mBatteryStatus;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE);
mStatsHelper = new BatteryStatsHelper(activity, true);
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mStatsHelper.create(icicle);
setHasOptionsMenu(true);
}
@Override
public void onStart() {
super.onStart();
mStatsHelper.clearStats();
}
@Override
public void onResume() {
super.onResume();
BatteryStatsHelper.dropFile(getActivity(), BatteryHistoryPreference.BATTERY_HISTORY_FILE);
updateBatteryStatus(getActivity().registerReceiver(mBatteryInfoReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED)));
if (mHandler.hasMessages(MSG_REFRESH_STATS)) {
mHandler.removeMessages(MSG_REFRESH_STATS);
mStatsHelper.clearStats();
}
}
@Override
public void onPause() {
super.onPause();
getActivity().unregisterReceiver(mBatteryInfoReceiver);
}
@Override
public void onStop() {
super.onStop();
mHandler.removeMessages(MSG_REFRESH_STATS);
}
@Override
public void onDestroy() {
super.onDestroy();
if (getActivity().isChangingConfigurations()) {
mStatsHelper.storeState();
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
MenuItem refresh = menu.add(0, MENU_STATS_REFRESH, 0, R.string.menu_stats_refresh)
.setIcon(com.android.internal.R.drawable.ic_menu_refresh)
.setAlphabeticShortcut('r');
refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
MenuItem.SHOW_AS_ACTION_WITH_TEXT);
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_STATS_REFRESH:
mStatsHelper.clearStats();
refreshStats();
mHandler.removeMessages(MSG_REFRESH_STATS);
return true;
}
return super.onOptionsItemSelected(item);
}
protected void refreshStats() {
mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, mUm.getUserProfiles());
}
protected void updatePreference(BatteryHistoryPreference historyPref) {
historyPref.setStats(mStatsHelper);
}
private boolean updateBatteryStatus(Intent intent) {
if (intent != null) {
String batteryLevel = com.android.settings.Utils.getBatteryPercentage(intent);
String batteryStatus = com.android.settings.Utils.getBatteryStatus(getResources(),
intent);
if (!batteryLevel.equals(mBatteryLevel) || !batteryStatus.equals(mBatteryStatus)) {
mBatteryLevel = batteryLevel;
mBatteryStatus = batteryStatus;
return true;
}
}
return false;
}
static final int MSG_REFRESH_STATS = 100;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REFRESH_STATS:
mStatsHelper.clearStats();
refreshStats();
break;
}
}
};
private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_BATTERY_CHANGED.equals(action)
&& updateBatteryStatus(intent)) {
if (!mHandler.hasMessages(MSG_REFRESH_STATS)) {
mHandler.sendEmptyMessageDelayed(MSG_REFRESH_STATS, 500);
}
}
}
};
}

View File

@@ -16,8 +16,6 @@
package com.android.settings.fuelgauge; package com.android.settings.fuelgauge;
import static com.android.settings.Utils.prepareCustomPreferencesList;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.ApplicationErrorReport; import android.app.ApplicationErrorReport;
@@ -30,33 +28,34 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.Bundle; import android.os.Bundle;
import android.os.Process; import android.os.Process;
import android.os.UserHandle; import android.os.UserHandle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceCategory;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.LayoutInflater; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BatterySipper; import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatterySipper.DrainType;
import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastPrintWriter;
import com.android.settings.AppHeader;
import com.android.settings.DisplaySettings; import com.android.settings.DisplaySettings;
import com.android.settings.InstrumentedFragment;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.WirelessSettings; import com.android.settings.WirelessSettings;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.InstalledAppDetails; import com.android.settings.applications.InstalledAppDetails;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.bluetooth.BluetoothSettings; import com.android.settings.bluetooth.BluetoothSettings;
import com.android.settings.location.LocationSettings; import com.android.settings.location.LocationSettings;
import com.android.settings.wifi.WifiSettings; import com.android.settings.wifi.WifiSettings;
@@ -65,7 +64,7 @@ import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
public class PowerUsageDetail extends InstrumentedFragment implements Button.OnClickListener { public class PowerUsageDetail extends PowerUsageBase implements Button.OnClickListener {
// Note: Must match the sequence of the DrainType // Note: Must match the sequence of the DrainType
private static int[] sDrainTypeDesciptions = new int[] { private static int[] sDrainTypeDesciptions = new int[] {
@@ -292,51 +291,57 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC
public static final String EXTRA_ICON_ID = "iconId"; // Int public static final String EXTRA_ICON_ID = "iconId"; // Int
public static final String EXTRA_SHOW_LOCATION_BUTTON = "showLocationButton"; // Boolean public static final String EXTRA_SHOW_LOCATION_BUTTON = "showLocationButton"; // Boolean
private static final String TAG = "PowerUsageDetail";
private static final String KEY_DETAILS_PARENT = "details_parent";
private static final String KEY_CONTROLS_PARENT = "controls_parent";
private static final String KEY_MESSAGES_PARENT = "messages_parent";
private static final String KEY_PACKAGES_PARENT = "packages_parent";
private static final String KEY_BATTERY_HISTORY = "battery_history";
private static final String KEY_TWO_BUTTONS = "two_buttons";
private static final String KEY_HIGH_POWER = "high_power";
private PackageManager mPm; private PackageManager mPm;
private DevicePolicyManager mDpm; private DevicePolicyManager mDpm;
private String mTitle;
private int mUsageSince; private int mUsageSince;
private int[] mTypes; private int[] mTypes;
private int mUid; private int mUid;
private double[] mValues; private double[] mValues;
private View mRootView;
private TextView mTitleView;
private ViewGroup mTwoButtonsPanel;
private Button mForceStopButton; private Button mForceStopButton;
private Button mReportButton; private Button mReportButton;
private ViewGroup mDetailsParent;
private ViewGroup mControlsParent;
private ViewGroup mMessagesParent;
private long mStartTime; private long mStartTime;
private BatterySipper.DrainType mDrainType; private BatterySipper.DrainType mDrainType;
private Drawable mAppIcon;
private double mNoCoverage; // Percentage of time that there was no coverage private double mNoCoverage; // Percentage of time that there was no coverage
private BatteryHistoryPreference mHistPref;
private PreferenceCategory mDetailsParent;
private PreferenceCategory mControlsParent;
private PreferenceCategory mMessagesParent;
private PreferenceCategory mPackagesParent;
private boolean mUsesGps; private boolean mUsesGps;
private boolean mShowLocationButton; private boolean mShowLocationButton;
private static final String TAG = "PowerUsageDetail";
private String[] mPackages; private String[] mPackages;
ApplicationInfo mApp; ApplicationInfo mApp;
ComponentName mInstaller; ComponentName mInstaller;
private Preference mHighPower;
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
mPm = getActivity().getPackageManager(); mPm = getActivity().getPackageManager();
mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE); mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
}
@Override addPreferencesFromResource(R.xml.power_usage_details);
public View onCreateView( mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_HISTORY);
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mDetailsParent = (PreferenceCategory) findPreference(KEY_DETAILS_PARENT);
final View view = inflater.inflate(R.layout.power_usage_details, container, false); mControlsParent = (PreferenceCategory) findPreference(KEY_CONTROLS_PARENT);
prepareCustomPreferencesList(container, view, view, false); mMessagesParent = (PreferenceCategory) findPreference(KEY_MESSAGES_PARENT);
mPackagesParent = (PreferenceCategory) findPreference(KEY_PACKAGES_PARENT);
mRootView = view;
createDetails(); createDetails();
return view;
} }
@Override @Override
@@ -349,76 +354,31 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC
super.onResume(); super.onResume();
mStartTime = android.os.Process.getElapsedCpuTime(); mStartTime = android.os.Process.getElapsedCpuTime();
checkForceStop(); checkForceStop();
if (mHighPower != null) {
mHighPower.setSummary(HighPowerDetail.getSummary(getActivity(), mApp.packageName));
} }
@Override
public void onPause() {
super.onPause();
} }
private void createDetails() { private void createDetails() {
final Bundle args = getArguments(); final Bundle args = getArguments();
mTitle = args.getString(EXTRA_TITLE); Context context = getActivity();
final int percentage = args.getInt(EXTRA_PERCENT, 1);
final int gaugeValue = args.getInt(EXTRA_GAUGE, 1);
mUsageSince = args.getInt(EXTRA_USAGE_SINCE, USAGE_SINCE_UNPLUGGED); mUsageSince = args.getInt(EXTRA_USAGE_SINCE, USAGE_SINCE_UNPLUGGED);
mUid = args.getInt(EXTRA_UID, 0); mUid = args.getInt(EXTRA_UID, 0);
mPackages = context.getPackageManager().getPackagesForUid(mUid);
mDrainType = (BatterySipper.DrainType) args.getSerializable(EXTRA_DRAIN_TYPE); mDrainType = (BatterySipper.DrainType) args.getSerializable(EXTRA_DRAIN_TYPE);
mNoCoverage = args.getDouble(EXTRA_NO_COVERAGE, 0); mNoCoverage = args.getDouble(EXTRA_NO_COVERAGE, 0);
String iconPackage = args.getString(EXTRA_ICON_PACKAGE);
int iconId = args.getInt(EXTRA_ICON_ID, 0);
mShowLocationButton = args.getBoolean(EXTRA_SHOW_LOCATION_BUTTON); mShowLocationButton = args.getBoolean(EXTRA_SHOW_LOCATION_BUTTON);
if (!TextUtils.isEmpty(iconPackage)) {
try {
final PackageManager pm = getActivity().getPackageManager();
ApplicationInfo ai = pm.getPackageInfo(iconPackage, 0).applicationInfo;
if (ai != null) {
mAppIcon = ai.loadIcon(pm);
}
} catch (NameNotFoundException nnfe) {
// Use default icon
}
} else if (iconId != 0) {
mAppIcon = getActivity().getDrawable(iconId);
}
if (mAppIcon == null) {
mAppIcon = getActivity().getPackageManager().getDefaultActivityIcon();
}
// Set the description setupHeader();
final TextView summary = (TextView) mRootView.findViewById(android.R.id.summary);
summary.setText(getDescriptionForDrainType());
summary.setVisibility(View.VISIBLE);
mTypes = args.getIntArray(EXTRA_DETAIL_TYPES); mTypes = args.getIntArray(EXTRA_DETAIL_TYPES);
mValues = args.getDoubleArray(EXTRA_DETAIL_VALUES); mValues = args.getDoubleArray(EXTRA_DETAIL_VALUES);
mTitleView = (TextView) mRootView.findViewById(android.R.id.title); LayoutPreference twoButtons = (LayoutPreference) findPreference(KEY_TWO_BUTTONS);
mTitleView.setText(mTitle); mForceStopButton = (Button) twoButtons.findViewById(R.id.left_button);
mReportButton = (Button) twoButtons.findViewById(R.id.right_button);
final TextView text1 = (TextView)mRootView.findViewById(android.R.id.text1);
text1.setText(Utils.formatPercentage(percentage));
mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel);
mForceStopButton = (Button)mRootView.findViewById(R.id.left_button);
mReportButton = (Button)mRootView.findViewById(R.id.right_button);
mForceStopButton.setEnabled(false); mForceStopButton.setEnabled(false);
final ProgressBar progress = (ProgressBar) mRootView.findViewById(android.R.id.progress);
progress.setProgress(gaugeValue);
final ImageView icon = (ImageView) mRootView.findViewById(android.R.id.icon);
icon.setImageDrawable(mAppIcon);
mDetailsParent = (ViewGroup)mRootView.findViewById(R.id.details);
mControlsParent = (ViewGroup)mRootView.findViewById(R.id.controls);
mMessagesParent = (ViewGroup)mRootView.findViewById(R.id.messages);
fillDetailsSection();
fillPackagesSection(mUid);
fillControlsSection(mUid);
fillMessagesSection(mUid);
if (mUid >= Process.FIRST_APPLICATION_UID) { if (mUid >= Process.FIRST_APPLICATION_UID) {
mForceStopButton.setText(R.string.force_stop); mForceStopButton.setText(R.string.force_stop);
mForceStopButton.setTag(ACTION_FORCE_STOP); mForceStopButton.setTag(ACTION_FORCE_STOP);
@@ -427,26 +387,85 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC
mReportButton.setTag(ACTION_REPORT); mReportButton.setTag(ACTION_REPORT);
mReportButton.setOnClickListener(this); mReportButton.setOnClickListener(this);
// check if error reporting is enabled in secure settings
int enabled = android.provider.Settings.Global.getInt(getActivity().getContentResolver(),
android.provider.Settings.Global.SEND_ACTION_APP_ERROR, 0);
if (enabled != 0) {
if (mPackages != null && mPackages.length > 0) { if (mPackages != null && mPackages.length > 0) {
try { try {
mApp = getActivity().getPackageManager().getApplicationInfo( mApp = context.getPackageManager().getApplicationInfo(
mPackages[0], 0); mPackages[0], 0);
mInstaller = ApplicationErrorReport.getErrorReportReceiver(
getActivity(), mPackages[0], mApp.flags);
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
} }
} else {
Log.d(TAG, "No packages!!");
}
// check if error reporting is enabled in secure settings
int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
android.provider.Settings.Global.SEND_ACTION_APP_ERROR, 0);
if (enabled != 0) {
if (mApp != null) {
mInstaller = ApplicationErrorReport.getErrorReportReceiver(
context, mPackages[0], mApp.flags);
} }
mReportButton.setEnabled(mInstaller != null); mReportButton.setEnabled(mInstaller != null);
} else { } else {
mTwoButtonsPanel.setVisibility(View.GONE); removePreference(KEY_TWO_BUTTONS);
}
if (mApp != null) {
mHighPower = findPreference(KEY_HIGH_POWER);
mHighPower.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
AppInfoBase.startAppInfoFragment(HighPowerDetail.class, R.string.high_power,
mApp.packageName, mApp.uid, PowerUsageDetail.this, 0);
return true;
}
});
} else {
removePreference(KEY_HIGH_POWER);
} }
} else { } else {
mTwoButtonsPanel.setVisibility(View.GONE); removePreference(KEY_TWO_BUTTONS);
removePreference(KEY_HIGH_POWER);
} }
refreshStats();
fillDetailsSection();
fillPackagesSection(mUid);
fillControlsSection(mUid);
fillMessagesSection(mUid);
}
@Override
protected void refreshStats() {
super.refreshStats();
updatePreference(mHistPref);
}
private void setupHeader() {
final Bundle args = getArguments();
String title = args.getString(EXTRA_TITLE);
String iconPackage = args.getString(EXTRA_ICON_PACKAGE);
int iconId = args.getInt(EXTRA_ICON_ID, 0);
Drawable appIcon = null;
if (!TextUtils.isEmpty(iconPackage)) {
try {
final PackageManager pm = getActivity().getPackageManager();
ApplicationInfo ai = pm.getPackageInfo(iconPackage, 0).applicationInfo;
if (ai != null) {
appIcon = ai.loadIcon(pm);
}
} catch (NameNotFoundException nnfe) {
// Use default icon
}
} else if (iconId != 0) {
appIcon = getActivity().getDrawable(iconId);
}
if (appIcon == null) {
appIcon = getActivity().getPackageManager().getDefaultActivityIcon();
}
AppHeader.createAppHeader(getActivity(), appIcon, title, null,
mDrainType != DrainType.APP ? android.R.color.white : 0);
} }
public void onClick(View v) { public void onClick(View v) {
@@ -500,7 +519,6 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC
} }
private void fillDetailsSection() { private void fillDetailsSection() {
LayoutInflater inflater = getActivity().getLayoutInflater();
if (mTypes != null && mValues != null) { if (mTypes != null && mValues != null) {
for (int i = 0; i < mTypes.length; i++) { for (int i = 0; i < mTypes.length; i++) {
// Only add an item if the time is greater than zero // Only add an item if the time is greater than zero
@@ -530,17 +548,21 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC
default: default:
value = Utils.formatElapsedTime(getActivity(), mValues[i], true); value = Utils.formatElapsedTime(getActivity(), mValues[i], true);
} }
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text, addHorizontalPreference(mDetailsParent, label, value);
null);
mDetailsParent.addView(item);
TextView labelView = (TextView) item.findViewById(R.id.label);
TextView valueView = (TextView) item.findViewById(R.id.value);
labelView.setText(label);
valueView.setText(value);
} }
} }
} }
private void addHorizontalPreference(PreferenceCategory parent, CharSequence title,
CharSequence summary) {
Preference pref = new Preference(getActivity());
pref.setLayoutResource(R.layout.horizontal_preference);
pref.setTitle(title);
pref.setSummary(summary);
pref.setSelectable(false);
parent.addPreference(pref);
}
private void fillControlsSection(int uid) { private void fillControlsSection(int uid) {
PackageManager pm = getActivity().getPackageManager(); PackageManager pm = getActivity().getPackageManager();
String[] packages = pm.getPackagesForUid(uid); String[] packages = pm.getPackagesForUid(uid);
@@ -597,21 +619,22 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC
break; break;
} }
if (removeHeader) { if (removeHeader) {
mControlsParent.setVisibility(View.GONE); mControlsParent.setTitle(null);
} }
} }
private void addControl(int title, int summary, int action) { private void addControl(int pageSummary, int actionTitle, final int action) {
final Resources res = getResources(); Preference pref = new Preference(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater(); pref.setTitle(actionTitle);
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_action_item,null); pref.setSummary(pageSummary);
mControlsParent.addView(item); pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
Button actionButton = (Button) item.findViewById(R.id.action_button); @Override
TextView summaryView = (TextView) item.findViewById(R.id.summary); public boolean onPreferenceClick(Preference preference) {
actionButton.setText(res.getString(title)); doAction(action);
summaryView.setText(res.getString(summary)); return true;
actionButton.setOnClickListener(this); }
actionButton.setTag(new Integer(action)); });
mControlsParent.addPreference(pref);
} }
private void fillMessagesSection(int uid) { private void fillMessagesSection(int uid) {
@@ -623,27 +646,16 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC
break; break;
} }
if (removeHeader) { if (removeHeader) {
mMessagesParent.setVisibility(View.GONE); mMessagesParent.setTitle(null);
} }
} }
private void addMessage(int message) { private void addMessage(int message) {
final Resources res = getResources(); addHorizontalPreference(mMessagesParent, getString(message), null);
LayoutInflater inflater = getActivity().getLayoutInflater();
View item = inflater.inflate(R.layout.power_usage_message_item, null);
mMessagesParent.addView(item);
TextView messageView = (TextView) item.findViewById(R.id.message);
messageView.setText(res.getText(message));
} }
private void removePackagesSection() { private void removePackagesSection() {
View view; getPreferenceScreen().removePreference(mPackagesParent);
if ((view = mRootView.findViewById(R.id.packages_section_title)) != null) {
view.setVisibility(View.GONE);
}
if ((view = mRootView.findViewById(R.id.packages_section)) != null) {
view.setVisibility(View.GONE);
}
} }
private void killProcesses() { private void killProcesses() {
@@ -725,40 +737,23 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC
removePackagesSection(); removePackagesSection();
return; return;
} }
ViewGroup packagesParent = (ViewGroup)mRootView.findViewById(R.id.packages_section);
if (packagesParent == null) return;
LayoutInflater inflater = getActivity().getLayoutInflater();
PackageManager pm = getActivity().getPackageManager();
//final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
mPackages = pm.getPackagesForUid(uid);
if (mPackages == null || mPackages.length < 2) { if (mPackages == null || mPackages.length < 2) {
removePackagesSection(); removePackagesSection();
return; return;
} }
PackageManager pm = getPackageManager();
// Convert package names to user-facing labels where possible // Convert package names to user-facing labels where possible
for (int i = 0; i < mPackages.length; i++) { for (int i = 0; i < mPackages.length; i++) {
try { try {
ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0); ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0);
CharSequence label = ai.loadLabel(pm); CharSequence label = ai.loadLabel(pm);
//Drawable icon = defaultActivityIcon;
if (label != null) { if (label != null) {
mPackages[i] = label.toString(); mPackages[i] = label.toString();
} }
//if (ai.icon != 0) { addHorizontalPreference(mPackagesParent, mPackages[i], null);
// icon = ai.loadIcon(pm);
//}
View item = inflater.inflate(R.layout.power_usage_package_item, null);
packagesParent.addView(item);
TextView labelView = (TextView) item.findViewById(R.id.label);
labelView.setText(mPackages[i]);
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
} }
} }
} }
private String getDescriptionForDrainType() {
return getResources().getString(sDrainTypeDesciptions[mDrainType.ordinal()]);
}
} }

View File

@@ -17,10 +17,6 @@
package com.android.settings.fuelgauge; package com.android.settings.fuelgauge;
import android.app.Activity; import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.Build; import android.os.Build;
@@ -28,7 +24,6 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceGroup; import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
@@ -39,12 +34,12 @@ import android.view.MenuItem;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BatterySipper; import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.PowerProfile; import com.android.internal.os.PowerProfile;
import com.android.settings.HelpUtils; import com.android.settings.HelpUtils;
import com.android.settings.InstrumentedPreferenceFragment;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Settings.HighPowerApplicationsActivity;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.applications.ManageApplications;
import java.util.List; import java.util.List;
@@ -52,27 +47,22 @@ import java.util.List;
* Displays a list of apps and subsystems that consume power, ordered by how much power was * Displays a list of apps and subsystems that consume power, ordered by how much power was
* consumed since the last time it was unplugged. * consumed since the last time it was unplugged.
*/ */
public class PowerUsageSummary extends InstrumentedPreferenceFragment { public class PowerUsageSummary extends PowerUsageBase {
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
static final String TAG = "PowerUsageSummary"; static final String TAG = "PowerUsageSummary";
private static final String KEY_APP_LIST = "app_list"; private static final String KEY_APP_LIST = "app_list";
private static final String KEY_BATTERY_HISTORY = "battery_history";
private static final String BATTERY_HISTORY_FILE = "tmp_bat_history.bin";
private static final int MENU_STATS_TYPE = Menu.FIRST; private static final int MENU_STATS_TYPE = Menu.FIRST;
private static final int MENU_STATS_REFRESH = Menu.FIRST + 1;
private static final int MENU_BATTERY_SAVER = Menu.FIRST + 2; private static final int MENU_BATTERY_SAVER = Menu.FIRST + 2;
private static final int MENU_HELP = Menu.FIRST + 3; private static final int MENU_HIGH_POWER_APPS = Menu.FIRST + 3;
private static final int MENU_HELP = Menu.FIRST + 4;
private UserManager mUm;
private BatteryHistoryPreference mHistPref; private BatteryHistoryPreference mHistPref;
private PreferenceGroup mAppListGroup; private PreferenceGroup mAppListGroup;
private String mBatteryLevel;
private String mBatteryStatus;
private int mStatsType = BatteryStats.STATS_SINCE_CHARGED; private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
@@ -81,43 +71,13 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment {
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10; private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
private static final int SECONDS_IN_HOUR = 60 * 60; private static final int SECONDS_IN_HOUR = 60 * 60;
private BatteryStatsHelper mStatsHelper;
private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_BATTERY_CHANGED.equals(action)
&& updateBatteryStatus(intent)) {
if (!mHandler.hasMessages(MSG_REFRESH_STATS)) {
mHandler.sendEmptyMessageDelayed(MSG_REFRESH_STATS, 500);
}
}
}
};
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE);
mStatsHelper = new BatteryStatsHelper(activity, true);
}
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
mStatsHelper.create(icicle);
addPreferencesFromResource(R.xml.power_usage_summary); addPreferencesFromResource(R.xml.power_usage_summary);
mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_HISTORY);
mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST); mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
setHasOptionsMenu(true);
}
@Override
public void onStart() {
super.onStart();
mStatsHelper.clearStats();
} }
@Override @Override
@@ -128,13 +88,6 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment {
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
BatteryStatsHelper.dropFile(getActivity(), BATTERY_HISTORY_FILE);
updateBatteryStatus(getActivity().registerReceiver(mBatteryInfoReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED)));
if (mHandler.hasMessages(MSG_REFRESH_STATS)) {
mHandler.removeMessages(MSG_REFRESH_STATS);
mStatsHelper.clearStats();
}
refreshStats(); refreshStats();
} }
@@ -142,38 +95,19 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment {
public void onPause() { public void onPause() {
BatteryEntry.stopRequestQueue(); BatteryEntry.stopRequestQueue();
mHandler.removeMessages(BatteryEntry.MSG_UPDATE_NAME_ICON); mHandler.removeMessages(BatteryEntry.MSG_UPDATE_NAME_ICON);
getActivity().unregisterReceiver(mBatteryInfoReceiver);
super.onPause(); super.onPause();
} }
@Override
public void onStop() {
super.onStop();
mHandler.removeMessages(MSG_REFRESH_STATS);
}
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
if (getActivity().isChangingConfigurations()) { if (getActivity().isChangingConfigurations()) {
mStatsHelper.storeState();
BatteryEntry.clearUidCache(); BatteryEntry.clearUidCache();
} }
} }
@Override @Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference instanceof BatteryHistoryPreference) {
mStatsHelper.storeStatsHistoryInFile(BATTERY_HISTORY_FILE);
Bundle args = new Bundle();
args.putString(BatteryHistoryDetail.EXTRA_STATS, BATTERY_HISTORY_FILE);
args.putParcelable(BatteryHistoryDetail.EXTRA_BROADCAST,
mStatsHelper.getBatteryBroadcast());
SettingsActivity sa = (SettingsActivity) getActivity();
sa.startPreferencePanel(BatteryHistoryDetail.class.getName(), args,
R.string.history_details_title, null, null, 0);
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
if (!(preference instanceof PowerGaugePreference)) { if (!(preference instanceof PowerGaugePreference)) {
return false; return false;
} }
@@ -186,20 +120,18 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment {
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
if (DEBUG) { if (DEBUG) {
menu.add(0, MENU_STATS_TYPE, 0, R.string.menu_stats_total) menu.add(0, MENU_STATS_TYPE, 0, R.string.menu_stats_total)
.setIcon(com.android.internal.R.drawable.ic_menu_info_details) .setIcon(com.android.internal.R.drawable.ic_menu_info_details)
.setAlphabeticShortcut('t'); .setAlphabeticShortcut('t');
} }
MenuItem refresh = menu.add(0, MENU_STATS_REFRESH, 0, R.string.menu_stats_refresh)
.setIcon(com.android.internal.R.drawable.ic_menu_refresh)
.setAlphabeticShortcut('r');
refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
MenuItem.SHOW_AS_ACTION_WITH_TEXT);
MenuItem batterySaver = menu.add(0, MENU_BATTERY_SAVER, 0, R.string.battery_saver); MenuItem batterySaver = menu.add(0, MENU_BATTERY_SAVER, 0, R.string.battery_saver);
batterySaver.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); batterySaver.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.add(0, MENU_HIGH_POWER_APPS, 0, R.string.high_power_apps);
String helpUrl; String helpUrl;
if (!TextUtils.isEmpty(helpUrl = getResources().getString(R.string.help_url_battery))) { if (!TextUtils.isEmpty(helpUrl = getResources().getString(R.string.help_url_battery))) {
final MenuItem help = menu.add(0, MENU_HELP, 0, R.string.help_label); final MenuItem help = menu.add(0, MENU_HELP, 0, R.string.help_label);
@@ -209,6 +141,7 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
final SettingsActivity sa = (SettingsActivity) getActivity();
switch (item.getItemId()) { switch (item.getItemId()) {
case MENU_STATS_TYPE: case MENU_STATS_TYPE:
if (mStatsType == BatteryStats.STATS_SINCE_CHARGED) { if (mStatsType == BatteryStats.STATS_SINCE_CHARGED) {
@@ -218,59 +151,40 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment {
} }
refreshStats(); refreshStats();
return true; return true;
case MENU_STATS_REFRESH:
mStatsHelper.clearStats();
refreshStats();
mHandler.removeMessages(MSG_REFRESH_STATS);
return true;
case MENU_BATTERY_SAVER: case MENU_BATTERY_SAVER:
final SettingsActivity sa = (SettingsActivity) getActivity();
sa.startPreferencePanel(BatterySaverSettings.class.getName(), null, sa.startPreferencePanel(BatterySaverSettings.class.getName(), null,
R.string.battery_saver, null, null, 0); R.string.battery_saver, null, null, 0);
return true; return true;
case MENU_HIGH_POWER_APPS:
Bundle args = new Bundle();
args.putString(ManageApplications.EXTRA_CLASSNAME,
HighPowerApplicationsActivity.class.getName());
sa.startPreferencePanel(ManageApplications.class.getName(), args,
R.string.high_power_apps, null, null, 0);
return true;
default: default:
return false; return super.onOptionsItemSelected(item);
} }
} }
private void addNotAvailableMessage() { private void addNotAvailableMessage() {
Preference notAvailable = new Preference(getActivity()); Preference notAvailable = new Preference(getActivity());
notAvailable.setTitle(R.string.power_usage_not_available); notAvailable.setTitle(R.string.power_usage_not_available);
mHistPref.setHideLabels(true);
mAppListGroup.addPreference(notAvailable); mAppListGroup.addPreference(notAvailable);
} }
private boolean updateBatteryStatus(Intent intent) { protected void refreshStats() {
if (intent != null) { super.refreshStats();
String batteryLevel = com.android.settings.Utils.getBatteryPercentage(intent); updatePreference(mHistPref);
String batteryStatus = com.android.settings.Utils.getBatteryStatus(getResources(),
intent);
if (!batteryLevel.equals(mBatteryLevel) || !batteryStatus.equals(mBatteryStatus)) {
mBatteryLevel = batteryLevel;
mBatteryStatus = batteryStatus;
return true;
}
}
return false;
}
private void refreshStats() {
mAppListGroup.removeAll(); mAppListGroup.removeAll();
mAppListGroup.setOrderingAsAdded(false); mAppListGroup.setOrderingAsAdded(false);
mHistPref = new BatteryHistoryPreference(getActivity(), mStatsHelper.getStats(),
mStatsHelper.getBatteryBroadcast());
mHistPref.setOrder(-1);
mAppListGroup.addPreference(mHistPref);
boolean addedSome = false; boolean addedSome = false;
final PowerProfile powerProfile = mStatsHelper.getPowerProfile(); final PowerProfile powerProfile = mStatsHelper.getPowerProfile();
final BatteryStats stats = mStatsHelper.getStats(); final BatteryStats stats = mStatsHelper.getStats();
final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL); final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP) { if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP) {
final List<UserHandle> profiles = mUm.getUserProfiles();
mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, profiles);
final List<BatterySipper> usageList = mStatsHelper.getUsageList(); final List<BatterySipper> usageList = mStatsHelper.getUsageList();
final int dischargeAmount = stats != null ? stats.getDischargeAmount(mStatsType) : 0; final int dischargeAmount = stats != null ? stats.getDischargeAmount(mStatsType) : 0;
@@ -320,7 +234,8 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment {
final PowerGaugePreference pref = new PowerGaugePreference(getActivity(), final PowerGaugePreference pref = new PowerGaugePreference(getActivity(),
badgedIcon, contentDescription, entry); badgedIcon, contentDescription, entry);
final double percentOfMax = (sipper.totalPowerMah * 100) / mStatsHelper.getMaxPower(); final double percentOfMax = (sipper.totalPowerMah * 100)
/ mStatsHelper.getMaxPower();
sipper.percent = percentOfTotal; sipper.percent = percentOfTotal;
pref.setTitle(entry.getLabel()); pref.setTitle(entry.getLabel());
pref.setOrder(i + 1); pref.setOrder(i + 1);
@@ -342,8 +257,6 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment {
BatteryEntry.startRequestQueue(); BatteryEntry.startRequestQueue();
} }
static final int MSG_REFRESH_STATS = 100;
Handler mHandler = new Handler() { Handler mHandler = new Handler() {
@Override @Override
@@ -367,9 +280,6 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment {
activity.reportFullyDrawn(); activity.reportFullyDrawn();
} }
break; break;
case MSG_REFRESH_STATS:
mStatsHelper.clearStats();
refreshStats();
} }
super.handleMessage(msg); super.handleMessage(msg);
} }

View File

@@ -0,0 +1,97 @@
/*
* 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.fuelgauge;
import android.os.IDeviceIdleController;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArraySet;
import android.util.Log;
/**
* Handles getting/changing the whitelist for the exceptions to battery saving features.
*/
public class PowerWhitelistBackend {
private static final String TAG = "PowerWhitelistBackend";
private static final String DEVICE_IDLE_SERVICE = "deviceidle";
private static final PowerWhitelistBackend INSTANCE = new PowerWhitelistBackend();
private final IDeviceIdleController mDeviceIdleService;
private final ArraySet<String> mWhitelistedApps = new ArraySet<>();
private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>();
public PowerWhitelistBackend() {
mDeviceIdleService = IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(DEVICE_IDLE_SERVICE));
refreshList();
}
public int getWhitelistSize() {
return mWhitelistedApps.size();
}
public boolean isSysWhitelisted(String pkg) {
return mSysWhitelistedApps.contains(pkg);
}
public boolean isWhitelisted(String pkg) {
return mWhitelistedApps.contains(pkg);
}
public void addApp(String pkg) {
try {
mDeviceIdleService.addPowerSaveWhitelistApp(pkg);
mWhitelistedApps.add(pkg);
} catch (RemoteException e) {
Log.w(TAG, "Unable to reach IDeviceIdleController", e);
}
}
public void removeApp(String pkg) {
try {
mDeviceIdleService.removePowerSaveWhitelistApp(pkg);
mWhitelistedApps.remove(pkg);
} catch (RemoteException e) {
Log.w(TAG, "Unable to reach IDeviceIdleController", e);
}
}
private void refreshList() {
mSysWhitelistedApps.clear();
mWhitelistedApps.clear();
try {
String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
for (String app : whitelistedApps) {
mWhitelistedApps.add(app);
}
String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist();
for (String app : sysWhitelistedApps) {
mSysWhitelistedApps.add(app);
}
} catch (RemoteException e) {
Log.w(TAG, "Unable to reach IDeviceIdleController", e);
}
}
public static PowerWhitelistBackend getInstance() {
return INSTANCE;
}
}