diff options
Diffstat (limited to 'src/com/android/settings/fuelgauge')
6 files changed, 571 insertions, 287 deletions
diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java index b615ffd..0bf85b5 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java +++ b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java @@ -19,10 +19,16 @@ package com.android.settings.fuelgauge; import android.content.Context; import android.content.Intent; import android.os.BatteryStats; +import android.os.Bundle; import android.preference.Preference; +import android.preference.PreferenceScreen; +import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; + +import com.android.internal.os.BatteryStatsHelper; 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 @@ -31,38 +37,60 @@ import com.android.settings.R; */ public class BatteryHistoryPreference extends Preference { - final private BatteryStats mStats; - final private Intent mBatteryBroadcast; + protected static final String BATTERY_HISTORY_FILE = "tmp_bat_history.bin"; + + private BatteryStats mStats; + private Intent mBatteryBroadcast; - private boolean mHideLabels; - private View mLabelHeader; private BatteryHistoryChart mChart; + private BatteryStatsHelper mHelper; - public BatteryHistoryPreference(Context context, BatteryStats stats, Intent batteryBroadcast) { - super(context); - setLayoutResource(R.layout.preference_batteryhistory); - mStats = stats; - mBatteryBroadcast = batteryBroadcast; + public BatteryHistoryPreference(Context context, AttributeSet attrs) { + super(context, attrs); } - BatteryStats getStats() { - return mStats; + @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 setHideLabels(boolean hide) { - if (mHideLabels != hide) { - mHideLabels = hide; - if (mLabelHeader != null) { - mLabelHeader.setVisibility(hide ? View.GONE : View.VISIBLE); - } + 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() { + return mStats; } @Override protected void onBindView(View view) { super.onBindView(view); - BatteryHistoryChart chart = (BatteryHistoryChart)view.findViewById( + if (mStats == null) { + return; + } + BatteryHistoryChart chart = (BatteryHistoryChart) view.findViewById( R.id.battery_history_chart); if (mChart == null) { // First time: use and initialize this chart. @@ -71,15 +99,13 @@ public class BatteryHistoryPreference extends Preference { } else { // All future times: forget the newly inflated chart, re-use the // already initialized chart from last time. - ViewGroup parent = (ViewGroup)chart.getParent(); + ViewGroup parent = (ViewGroup) chart.getParent(); int index = parent.indexOfChild(chart); parent.removeViewAt(index); if (mChart.getParent() != null) { - ((ViewGroup)mChart.getParent()).removeView(mChart); + ((ViewGroup) mChart.getParent()).removeView(mChart); } parent.addView(mChart, index); } - mLabelHeader = view.findViewById(R.id.labelsHeader); - mLabelHeader.setVisibility(mHideLabels ? View.GONE : View.VISIBLE); } } diff --git a/src/com/android/settings/fuelgauge/HighPowerDetail.java b/src/com/android/settings/fuelgauge/HighPowerDetail.java new file mode 100644 index 0000000..d82cb6f --- /dev/null +++ b/src/com/android/settings/fuelgauge/HighPowerDetail.java @@ -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); + } + +} diff --git a/src/com/android/settings/fuelgauge/PowerUsageBase.java b/src/com/android/settings/fuelgauge/PowerUsageBase.java new file mode 100644 index 0000000..269249a --- /dev/null +++ b/src/com/android/settings/fuelgauge/PowerUsageBase.java @@ -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); + } + } + } + }; + +} diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java index 1f13e8e..4aa935a 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageDetail.java +++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java @@ -16,8 +16,6 @@ package com.android.settings.fuelgauge; -import static com.android.settings.Utils.prepareCustomPreferencesList; - import android.app.Activity; import android.app.ActivityManager; import android.app.ApplicationErrorReport; @@ -30,33 +28,34 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.BatteryStats; import android.os.Bundle; import android.os.Process; import android.os.UserHandle; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceCategory; import android.text.TextUtils; -import android.view.LayoutInflater; +import android.util.Log; import android.view.View; -import android.view.ViewGroup; 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.os.BatterySipper; +import com.android.internal.os.BatterySipper.DrainType; import com.android.internal.os.BatteryStatsHelper; import com.android.internal.util.FastPrintWriter; +import com.android.settings.AppHeader; import com.android.settings.DisplaySettings; -import com.android.settings.InstrumentedFragment; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.WirelessSettings; +import com.android.settings.applications.AppInfoBase; import com.android.settings.applications.InstalledAppDetails; +import com.android.settings.applications.LayoutPreference; import com.android.settings.bluetooth.BluetoothSettings; import com.android.settings.location.LocationSettings; import com.android.settings.wifi.WifiSettings; @@ -65,7 +64,7 @@ import java.io.PrintWriter; import java.io.StringWriter; 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 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_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 DevicePolicyManager mDpm; - private String mTitle; private int mUsageSince; private int[] mTypes; private int mUid; private double[] mValues; - private View mRootView; - private TextView mTitleView; - private ViewGroup mTwoButtonsPanel; private Button mForceStopButton; private Button mReportButton; - private ViewGroup mDetailsParent; - private ViewGroup mControlsParent; - private ViewGroup mMessagesParent; private long mStartTime; private BatterySipper.DrainType mDrainType; - private Drawable mAppIcon; 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 mShowLocationButton; - private static final String TAG = "PowerUsageDetail"; private String[] mPackages; ApplicationInfo mApp; ComponentName mInstaller; + private Preference mHighPower; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); mPm = getActivity().getPackageManager(); mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE); - } - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - final View view = inflater.inflate(R.layout.power_usage_details, container, false); - prepareCustomPreferencesList(container, view, view, false); + addPreferencesFromResource(R.xml.power_usage_details); + mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_HISTORY); + mDetailsParent = (PreferenceCategory) findPreference(KEY_DETAILS_PARENT); + mControlsParent = (PreferenceCategory) findPreference(KEY_CONTROLS_PARENT); + mMessagesParent = (PreferenceCategory) findPreference(KEY_MESSAGES_PARENT); + mPackagesParent = (PreferenceCategory) findPreference(KEY_PACKAGES_PARENT); - mRootView = view; createDetails(); - return view; } @Override @@ -349,76 +354,31 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC super.onResume(); mStartTime = android.os.Process.getElapsedCpuTime(); checkForceStop(); - } - - @Override - public void onPause() { - super.onPause(); + if (mHighPower != null) { + mHighPower.setSummary(HighPowerDetail.getSummary(getActivity(), mApp.packageName)); + } } private void createDetails() { final Bundle args = getArguments(); - mTitle = args.getString(EXTRA_TITLE); - final int percentage = args.getInt(EXTRA_PERCENT, 1); - final int gaugeValue = args.getInt(EXTRA_GAUGE, 1); + Context context = getActivity(); mUsageSince = args.getInt(EXTRA_USAGE_SINCE, USAGE_SINCE_UNPLUGGED); mUid = args.getInt(EXTRA_UID, 0); + mPackages = context.getPackageManager().getPackagesForUid(mUid); mDrainType = (BatterySipper.DrainType) args.getSerializable(EXTRA_DRAIN_TYPE); 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); - 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 - final TextView summary = (TextView) mRootView.findViewById(android.R.id.summary); - summary.setText(getDescriptionForDrainType()); - summary.setVisibility(View.VISIBLE); + setupHeader(); mTypes = args.getIntArray(EXTRA_DETAIL_TYPES); mValues = args.getDoubleArray(EXTRA_DETAIL_VALUES); - mTitleView = (TextView) mRootView.findViewById(android.R.id.title); - mTitleView.setText(mTitle); - - 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); + LayoutPreference twoButtons = (LayoutPreference) findPreference(KEY_TWO_BUTTONS); + mForceStopButton = (Button) twoButtons.findViewById(R.id.left_button); + mReportButton = (Button) twoButtons.findViewById(R.id.right_button); 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) { mForceStopButton.setText(R.string.force_stop); mForceStopButton.setTag(ACTION_FORCE_STOP); @@ -426,27 +386,86 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC mReportButton.setText(com.android.internal.R.string.report); mReportButton.setTag(ACTION_REPORT); mReportButton.setOnClickListener(this); - + + if (mPackages != null && mPackages.length > 0) { + try { + mApp = context.getPackageManager().getApplicationInfo( + mPackages[0], 0); + } 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(getActivity().getContentResolver(), + int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(), android.provider.Settings.Global.SEND_ACTION_APP_ERROR, 0); if (enabled != 0) { - if (mPackages != null && mPackages.length > 0) { - try { - mApp = getActivity().getPackageManager().getApplicationInfo( - mPackages[0], 0); - mInstaller = ApplicationErrorReport.getErrorReportReceiver( - getActivity(), mPackages[0], mApp.flags); - } catch (NameNotFoundException e) { - } + if (mApp != null) { + mInstaller = ApplicationErrorReport.getErrorReportReceiver( + context, mPackages[0], mApp.flags); } mReportButton.setEnabled(mInstaller != null); } 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 { - 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) { @@ -500,7 +519,6 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC } private void fillDetailsSection() { - LayoutInflater inflater = getActivity().getLayoutInflater(); if (mTypes != null && mValues != null) { for (int i = 0; i < mTypes.length; i++) { // Only add an item if the time is greater than zero @@ -530,17 +548,21 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC default: value = Utils.formatElapsedTime(getActivity(), mValues[i], true); } - ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text, - 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); + addHorizontalPreference(mDetailsParent, label, 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) { PackageManager pm = getActivity().getPackageManager(); String[] packages = pm.getPackagesForUid(uid); @@ -597,21 +619,22 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC break; } if (removeHeader) { - mControlsParent.setVisibility(View.GONE); + mControlsParent.setTitle(null); } } - private void addControl(int title, int summary, int action) { - final Resources res = getResources(); - LayoutInflater inflater = getActivity().getLayoutInflater(); - ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_action_item,null); - mControlsParent.addView(item); - Button actionButton = (Button) item.findViewById(R.id.action_button); - TextView summaryView = (TextView) item.findViewById(R.id.summary); - actionButton.setText(res.getString(title)); - summaryView.setText(res.getString(summary)); - actionButton.setOnClickListener(this); - actionButton.setTag(new Integer(action)); + private void addControl(int pageSummary, int actionTitle, final int action) { + Preference pref = new Preference(getActivity()); + pref.setTitle(actionTitle); + pref.setSummary(pageSummary); + pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + doAction(action); + return true; + } + }); + mControlsParent.addPreference(pref); } private void fillMessagesSection(int uid) { @@ -623,27 +646,16 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC break; } if (removeHeader) { - mMessagesParent.setVisibility(View.GONE); + mMessagesParent.setTitle(null); } } private void addMessage(int message) { - final Resources res = getResources(); - 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)); + addHorizontalPreference(mMessagesParent, getString(message), null); } private void removePackagesSection() { - View view; - 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); - } + getPreferenceScreen().removePreference(mPackagesParent); } private void killProcesses() { @@ -663,7 +675,7 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED); } }; - + private void checkForceStop() { if (mPackages == null || mUid < Process.FIRST_APPLICATION_UID) { mForceStopButton.setEnabled(false); @@ -693,10 +705,10 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null); } - + private void reportBatteryUse() { if (mPackages == null) return; - + ApplicationErrorReport report = new ApplicationErrorReport(); report.type = ApplicationErrorReport.TYPE_BATTERY; report.packageName = mPackages[0]; @@ -719,46 +731,29 @@ public class PowerUsageDetail extends InstrumentedFragment implements Button.OnC result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(result); } - + private void fillPackagesSection(int uid) { if (uid < 1) { removePackagesSection(); 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) { removePackagesSection(); return; } + PackageManager pm = getPackageManager(); // Convert package names to user-facing labels where possible for (int i = 0; i < mPackages.length; i++) { try { ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0); CharSequence label = ai.loadLabel(pm); - //Drawable icon = defaultActivityIcon; if (label != null) { mPackages[i] = label.toString(); } - //if (ai.icon != 0) { - // 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]); + addHorizontalPreference(mPackagesParent, mPackages[i], null); } catch (NameNotFoundException e) { } } } - - private String getDescriptionForDrainType() { - return getResources().getString(sDrainTypeDesciptions[mDrainType.ordinal()]); - } } diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index 297fe1a..89a3325 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -17,10 +17,6 @@ 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.graphics.drawable.Drawable; import android.os.BatteryStats; import android.os.Build; @@ -28,7 +24,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.UserHandle; -import android.os.UserManager; import android.preference.Preference; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; @@ -39,12 +34,12 @@ import android.view.MenuItem; import com.android.internal.logging.MetricsLogger; import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.PowerProfile; import com.android.settings.HelpUtils; -import com.android.settings.InstrumentedPreferenceFragment; import com.android.settings.R; +import com.android.settings.Settings.HighPowerApplicationsActivity; import com.android.settings.SettingsActivity; +import com.android.settings.applications.ManageApplications; 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 * consumed since the last time it was unplugged. */ -public class PowerUsageSummary extends InstrumentedPreferenceFragment { +public class PowerUsageSummary extends PowerUsageBase { private static final boolean DEBUG = false; static final String TAG = "PowerUsageSummary"; private static final String KEY_APP_LIST = "app_list"; - - private static final String BATTERY_HISTORY_FILE = "tmp_bat_history.bin"; + private static final String KEY_BATTERY_HISTORY = "battery_history"; 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_HELP = Menu.FIRST + 3; - - private UserManager mUm; + private static final int MENU_HIGH_POWER_APPS = Menu.FIRST + 3; + private static final int MENU_HELP = Menu.FIRST + 4; private BatteryHistoryPreference mHistPref; private PreferenceGroup mAppListGroup; - private String mBatteryLevel; - private String mBatteryStatus; 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 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 public void onCreate(Bundle icicle) { super.onCreate(icicle); - mStatsHelper.create(icicle); addPreferencesFromResource(R.xml.power_usage_summary); + mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_HISTORY); mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST); - setHasOptionsMenu(true); - } - - @Override - public void onStart() { - super.onStart(); - mStatsHelper.clearStats(); } @Override @@ -128,13 +88,6 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment { @Override public void 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(); } @@ -142,38 +95,19 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment { public void onPause() { BatteryEntry.stopRequestQueue(); mHandler.removeMessages(BatteryEntry.MSG_UPDATE_NAME_ICON); - getActivity().unregisterReceiver(mBatteryInfoReceiver); super.onPause(); } @Override - public void onStop() { - super.onStop(); - mHandler.removeMessages(MSG_REFRESH_STATS); - } - - @Override public void onDestroy() { super.onDestroy(); if (getActivity().isChangingConfigurations()) { - mStatsHelper.storeState(); BatteryEntry.clearUidCache(); } } @Override 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)) { return false; } @@ -186,20 +120,18 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment { @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); if (DEBUG) { menu.add(0, MENU_STATS_TYPE, 0, R.string.menu_stats_total) .setIcon(com.android.internal.R.drawable.ic_menu_info_details) .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); batterySaver.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + menu.add(0, MENU_HIGH_POWER_APPS, 0, R.string.high_power_apps); + String helpUrl; if (!TextUtils.isEmpty(helpUrl = getResources().getString(R.string.help_url_battery))) { final MenuItem help = menu.add(0, MENU_HELP, 0, R.string.help_label); @@ -209,6 +141,7 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment { @Override public boolean onOptionsItemSelected(MenuItem item) { + final SettingsActivity sa = (SettingsActivity) getActivity(); switch (item.getItemId()) { case MENU_STATS_TYPE: if (mStatsType == BatteryStats.STATS_SINCE_CHARGED) { @@ -218,59 +151,40 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment { } refreshStats(); return true; - case MENU_STATS_REFRESH: - mStatsHelper.clearStats(); - refreshStats(); - mHandler.removeMessages(MSG_REFRESH_STATS); - return true; case MENU_BATTERY_SAVER: - final SettingsActivity sa = (SettingsActivity) getActivity(); sa.startPreferencePanel(BatterySaverSettings.class.getName(), null, R.string.battery_saver, null, null, 0); 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: - return false; + return super.onOptionsItemSelected(item); } } private void addNotAvailableMessage() { Preference notAvailable = new Preference(getActivity()); notAvailable.setTitle(R.string.power_usage_not_available); - mHistPref.setHideLabels(true); mAppListGroup.addPreference(notAvailable); } - 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; - } - - private void refreshStats() { + protected void refreshStats() { + super.refreshStats(); + updatePreference(mHistPref); mAppListGroup.removeAll(); mAppListGroup.setOrderingAsAdded(false); - mHistPref = new BatteryHistoryPreference(getActivity(), mStatsHelper.getStats(), - mStatsHelper.getBatteryBroadcast()); - mHistPref.setOrder(-1); - mAppListGroup.addPreference(mHistPref); boolean addedSome = false; final PowerProfile powerProfile = mStatsHelper.getPowerProfile(); final BatteryStats stats = mStatsHelper.getStats(); final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL); - if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP) { - final List<UserHandle> profiles = mUm.getUserProfiles(); - - mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, profiles); + if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP) { final List<BatterySipper> usageList = mStatsHelper.getUsageList(); final int dischargeAmount = stats != null ? stats.getDischargeAmount(mStatsType) : 0; @@ -320,7 +234,8 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment { final PowerGaugePreference pref = new PowerGaugePreference(getActivity(), badgedIcon, contentDescription, entry); - final double percentOfMax = (sipper.totalPowerMah * 100) / mStatsHelper.getMaxPower(); + final double percentOfMax = (sipper.totalPowerMah * 100) + / mStatsHelper.getMaxPower(); sipper.percent = percentOfTotal; pref.setTitle(entry.getLabel()); pref.setOrder(i + 1); @@ -342,8 +257,6 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment { BatteryEntry.startRequestQueue(); } - static final int MSG_REFRESH_STATS = 100; - Handler mHandler = new Handler() { @Override @@ -367,9 +280,6 @@ public class PowerUsageSummary extends InstrumentedPreferenceFragment { activity.reportFullyDrawn(); } break; - case MSG_REFRESH_STATS: - mStatsHelper.clearStats(); - refreshStats(); } super.handleMessage(msg); } diff --git a/src/com/android/settings/fuelgauge/PowerWhitelistBackend.java b/src/com/android/settings/fuelgauge/PowerWhitelistBackend.java new file mode 100644 index 0000000..7199af8 --- /dev/null +++ b/src/com/android/settings/fuelgauge/PowerWhitelistBackend.java @@ -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; + } + +} |