Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c1405900 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android (Google) Code Review
Browse files

Merge "Switch to BatteryStatsHelper implementation in the framework."

parents df062746 7c80af41
Loading
Loading
Loading
Loading
+305 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 The Android Open Source Project
 * 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.
@@ -13,58 +13,105 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.settings.fuelgauge;

import com.android.settings.R;
import com.android.settings.fuelgauge.PowerUsageDetail.DrainType;
package com.android.settings.fuelgauge;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
import android.os.BatteryStats;
import android.os.Handler;
import android.os.BatteryStats.Uid;
import android.os.UserManager;
import com.android.internal.os.BatterySipper;
import com.android.settings.R;
import com.android.settings.users.UserUtils;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * Contains information about package name, icon image, power usage about an
 * application or a system service.
 * Wraps the power usage data of a BatterySipper with information about package name
 * and icon image.
 */
public class BatterySipper implements Comparable<BatterySipper> {
    final Context mContext;
    /* Cache cleared when PowerUsageSummary is destroyed */
public class BatteryEntry {
    public static final int MSG_UPDATE_NAME_ICON = 1;
    public static final int MSG_REPORT_FULLY_DRAWN = 2;

    static final HashMap<String,UidToDetail> sUidCache = new HashMap<String,UidToDetail>();
    final ArrayList<BatterySipper> mRequestQueue;
    final Handler mHandler;
    String name;
    Drawable icon;
    int iconId; // For passing to the detail screen.
    Uid uidObj;
    double value;
    double[] values;
    DrainType drainType;
    long usageTime;
    long cpuTime;
    long gpsTime;
    long wifiRunningTime;
    long cpuFgTime;
    long wakeLockTime;
    long mobileRxPackets;
    long mobileTxPackets;
    long wifiRxPackets;
    long wifiTxPackets;
    long mobileRxBytes;
    long mobileTxBytes;
    long wifiRxBytes;
    long wifiTxBytes;
    double percent;
    double noCoveragePercent;
    String defaultPackageName;
    String[] mPackages;

    static final ArrayList<BatteryEntry> mRequestQueue = new ArrayList<BatteryEntry>();
    static Handler mHandler;

    static private class NameAndIconLoader extends Thread {
        private boolean mAbort = false;

        public NameAndIconLoader() {
            super("BatteryUsage Icon Loader");
        }

        public void abort() {
            mAbort = true;
        }

        @Override
        public void run() {
            while (true) {
                BatteryEntry be;
                synchronized (mRequestQueue) {
                    if (mRequestQueue.isEmpty() || mAbort) {
                        mHandler.sendEmptyMessage(MSG_REPORT_FULLY_DRAWN);
                        mRequestQueue.clear();
                        return;
                    }
                    be = mRequestQueue.remove(0);
                }
                be.loadNameAndIcon();
            }
        }
    }

    private static NameAndIconLoader mRequestThread;

    public static void startRequestQueue() {
        if (mHandler != null) {
            synchronized (mRequestQueue) {
                if (!mRequestQueue.isEmpty()) {
                    if (mRequestThread != null) {
                        mRequestThread.abort();
                    }
                    mRequestThread = new NameAndIconLoader();
                    mRequestThread.setPriority(Thread.MIN_PRIORITY);
                    mRequestThread.start();
                    mRequestQueue.notify();
                }
            }
        }
    }

    public static void stopRequestQueue() {
        synchronized (mRequestQueue) {
            if (mRequestThread != null) {
                mRequestThread.abort();
                mRequestThread = null;
                mHandler = null;
            }
        }
    }

    public static void clearUidCache() {
        sUidCache.clear();
    }

    public final Context context;
    public final BatterySipper sipper;

    public String name;
    public Drawable icon;
    public int iconId; // For passing to the detail screen.
    public String defaultPackageName;

    static class UidToDetail {
        String name;
@@ -72,31 +119,69 @@ public class BatterySipper implements Comparable<BatterySipper> {
        Drawable icon;
    }

    BatterySipper(Context context, ArrayList<BatterySipper> requestQueue,
            Handler handler, String label, DrainType drainType,
            int iconId, Uid uid, double[] values) {
        mContext = context;
        mRequestQueue = requestQueue;
    public BatteryEntry(Context context, Handler handler, UserManager um, BatterySipper sipper) {
        mHandler = handler;
        this.values = values;
        name = label;
        this.drainType = drainType;
        if (iconId > 0) {
            icon = mContext.getResources().getDrawable(iconId);
        this.context = context;
        this.sipper = sipper;
        switch (sipper.drainType) {
            case IDLE:
                name = context.getResources().getString(R.string.power_idle);
                iconId = R.drawable.ic_settings_phone_idle;
                break;
            case CELL:
                name = context.getResources().getString(R.string.power_cell);
                iconId = R.drawable.ic_settings_cell_standby;
                break;
            case PHONE:
                name = context.getResources().getString(R.string.power_phone);
                iconId = R.drawable.ic_settings_voice_calls;
                break;
            case WIFI:
                name = context.getResources().getString(R.string.power_wifi);
                iconId = R.drawable.ic_settings_wifi;
                break;
            case BLUETOOTH:
                name = context.getResources().getString(R.string.power_bluetooth);
                iconId = R.drawable.ic_settings_bluetooth;
                break;
            case SCREEN:
                name = context.getResources().getString(R.string.power_screen);
                iconId = R.drawable.ic_settings_display;
                break;
            case APP:
                name = sipper.packageWithHighestDrain;
                break;
            case USER: {
                UserInfo info = um.getUserInfo(sipper.userId);
                if (info != null) {
                    icon = UserUtils.getUserIcon(context, um, info, context.getResources());
                    name = info != null ? info.name : null;
                    if (name == null) {
                        name = Integer.toString(info.id);
                    }
                    name = context.getResources().getString(
                            R.string.running_process_item_user_label, name);
                } else {
                    icon = null;
                    name = context.getResources().getString(
                            R.string.running_process_item_removed_user_label);
                }
        if (values != null) value = values[0];
        if ((label == null || iconId == 0) && uid != null) {
            getQuickNameIconForUid(uid);
            } break;
            case UNACCOUNTED:
                name = context.getResources().getString(R.string.power_unaccounted);
                iconId = R.drawable.ic_power_system;
                break;
            case OVERCOUNTED:
                name = context.getResources().getString(R.string.power_overcounted);
                iconId = R.drawable.ic_power_system;
                break;
        }
        uidObj = uid;
        if (iconId > 0) {
            icon = context.getResources().getDrawable(iconId);
        }

    double getSortValue() {
        return value;
        if ((name == null || iconId == 0) && this.sipper.uidObj != null) {
            getQuickNameIconForUid(this.sipper.uidObj);
        }

    double[] getValues() {
        return values;
    }

    public Drawable getIcon() {
@@ -110,28 +195,7 @@ public class BatterySipper implements Comparable<BatterySipper> {
        return name;
    }

    @Override
    public int compareTo(BatterySipper other) {
        // Return the flipped value because we want the items in descending order
        return Double.compare(other.getSortValue(), getSortValue());
    }

    /**
     * Gets a list of packages associated with the current user
     */
    public String[] getPackages() {
        return mPackages;
    }

    public int getUid() {
        // Bail out if the current sipper is not an App sipper.
        if (uidObj == null) {
            return 0;
        }
        return uidObj.getUid();
    }

    void getQuickNameIconForUid(Uid uidObj) {
    void getQuickNameIconForUid(BatteryStats.Uid uidObj) {
        final int uid = uidObj.getUid();
        final String uidString = Integer.toString(uid);
        if (sUidCache.containsKey(uidString)) {
@@ -141,18 +205,18 @@ public class BatterySipper implements Comparable<BatterySipper> {
            icon = utd.icon;
            return;
        }
        PackageManager pm = mContext.getPackageManager();
        PackageManager pm = context.getPackageManager();
        String[] packages = pm.getPackagesForUid(uid);
        icon = pm.getDefaultActivityIcon();
        if (packages == null) {
            //name = Integer.toString(uid);
            if (uid == 0) {
                name = mContext.getResources().getString(R.string.process_kernel_label);
                name = context.getResources().getString(R.string.process_kernel_label);
            } else if ("mediaserver".equals(name)) {
                name = mContext.getResources().getString(R.string.process_mediaserver_label);
                name = context.getResources().getString(R.string.process_mediaserver_label);
            }
            iconId = R.drawable.ic_power_system;
            icon = mContext.getResources().getDrawable(iconId);
            icon = context.getResources().getDrawable(iconId);
            return;
        } else {
            //name = packages[0];
@@ -164,29 +228,25 @@ public class BatterySipper implements Comparable<BatterySipper> {
        }
    }

    public static void clearUidCache() {
        sUidCache.clear();
    }

    /**
     * Loads the app label and icon image and stores into the cache.
     */
    public void loadNameAndIcon() {
        // Bail out if the current sipper is not an App sipper.
        if (uidObj == null) {
        if (sipper.uidObj == null) {
            return;
        }
        PackageManager pm = mContext.getPackageManager();
        final int uid = uidObj.getUid();
        PackageManager pm = context.getPackageManager();
        final int uid = sipper.uidObj.getUid();
        final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
        mPackages = pm.getPackagesForUid(uid);
        if (mPackages == null) {
        sipper.mPackages = pm.getPackagesForUid(uid);
        if (sipper.mPackages == null) {
            name = Integer.toString(uid);
            return;
        }

        String[] packageLabels = new String[mPackages.length];
        System.arraycopy(mPackages, 0, packageLabels, 0, mPackages.length);
        String[] packageLabels = new String[sipper.mPackages.length];
        System.arraycopy(sipper.mPackages, 0, packageLabels, 0, sipper.mPackages.length);

        int preferredIndex = -1;
        // Convert package names to user-facing labels where possible
@@ -200,11 +260,11 @@ public class BatterySipper implements Comparable<BatterySipper> {
                    packageLabels[i] = label.toString();
                }
                if (ai.icon != 0) {
                    defaultPackageName = mPackages[i];
                    defaultPackageName = sipper.mPackages[i];
                    icon = ai.loadIcon(pm);
                    break;
                }
            } catch (NameNotFoundException e) {
            } catch (PackageManager.NameNotFoundException e) {
            }
        }
        if (icon == null) icon = defaultActivityIcon;
@@ -213,7 +273,7 @@ public class BatterySipper implements Comparable<BatterySipper> {
            name = packageLabels[0];
        } else {
            // Look for an official name for this UID.
            for (String pkgName : mPackages) {
            for (String pkgName : sipper.mPackages) {
                try {
                    final PackageInfo pi = pm.getPackageInfo(pkgName, 0);
                    if (pi.sharedUserLabel != 0) {
@@ -232,15 +292,14 @@ public class BatterySipper implements Comparable<BatterySipper> {
                }
            }
        }
        final String uidString = Integer.toString(uidObj.getUid());
        final String uidString = Integer.toString(sipper.uidObj.getUid());
        UidToDetail utd = new UidToDetail();
        utd.name = name;
        utd.icon = icon;
        utd.packageName = defaultPackageName;
        sUidCache.put(uidString, utd);
        if (mHandler != null) {
            mHandler.sendMessage(
                    mHandler.obtainMessage(BatteryStatsHelper.MSG_UPDATE_NAME_ICON, this));
            mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_NAME_ICON, this));
        }
    }
}
+0 −907

File deleted.

Preview size limit exceeded, changes collapsed.

+4 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.android.internal.os.BatterySipper;
import com.android.settings.R;

/**
@@ -31,11 +32,11 @@ import com.android.settings.R;
 * the left for the subsystem/app type.
 */
public class PowerGaugePreference extends Preference {
    private BatterySipper mInfo;
    private BatteryEntry mInfo;
    private int mProgress;
    private CharSequence mProgressText;

    public PowerGaugePreference(Context context, Drawable icon, BatterySipper info) {
    public PowerGaugePreference(Context context, Drawable icon, BatteryEntry info) {
        super(context);
        setLayoutResource(R.layout.app_percentage_item);
        setIcon(icon != null ? icon : new ColorDrawable(0));
@@ -49,7 +50,7 @@ public class PowerGaugePreference extends Preference {
        notifyChanged();
    }

    BatterySipper getInfo() {
    BatteryEntry getInfo() {
        return mInfo;
    }

+174 −16
Original line number Diff line number Diff line
@@ -34,13 +34,13 @@ 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.PreferenceActivity;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -49,6 +49,9 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.util.FastPrintWriter;
import com.android.settings.DisplaySettings;
import com.android.settings.R;
import com.android.settings.WirelessSettings;
@@ -57,20 +60,11 @@ import com.android.settings.bluetooth.BluetoothSettings;
import com.android.settings.location.LocationSettings;
import com.android.settings.wifi.WifiSettings;

public class PowerUsageDetail extends Fragment implements Button.OnClickListener {
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;

    enum DrainType {
        IDLE,
        CELL,
        PHONE,
        WIFI,
        BLUETOOTH,
        SCREEN,
        APP,
        USER,
        UNACCOUNTED,
        OVERCOUNTED
    }
public class PowerUsageDetail extends Fragment implements Button.OnClickListener {

    // Note: Must match the sequence of the DrainType
    private static int[] sDrainTypeDesciptions = new int[] {
@@ -86,6 +80,170 @@ public class PowerUsageDetail extends Fragment implements Button.OnClickListener
        R.string.battery_desc_overcounted,
    };

    public static void startBatteryDetailPage(
            PreferenceActivity caller, BatteryStatsHelper helper, BatteryEntry entry,
            boolean showLocationButton) {
        // Initialize mStats if necessary.
        helper.getStats();

        Bundle args = new Bundle();
        args.putString(PowerUsageDetail.EXTRA_TITLE, entry.name);
        args.putInt(PowerUsageDetail.EXTRA_PERCENT, (int)
                Math.ceil(entry.sipper.value * 100 / helper.getTotalPower()));
        args.putInt(PowerUsageDetail.EXTRA_GAUGE, (int)
                Math.ceil(entry.sipper.value * 100 / helper.getMaxPower()));
        args.putLong(PowerUsageDetail.EXTRA_USAGE_DURATION, helper.getStatsPeriod());
        args.putString(PowerUsageDetail.EXTRA_ICON_PACKAGE, entry.defaultPackageName);
        args.putInt(PowerUsageDetail.EXTRA_ICON_ID, entry.iconId);
        args.putDouble(PowerUsageDetail.EXTRA_NO_COVERAGE, entry.sipper.noCoveragePercent);
        if (entry.sipper.uidObj != null) {
            args.putInt(PowerUsageDetail.EXTRA_UID, entry.sipper.uidObj.getUid());
        }
        args.putSerializable(PowerUsageDetail.EXTRA_DRAIN_TYPE, entry.sipper.drainType);
        args.putBoolean(PowerUsageDetail.EXTRA_SHOW_LOCATION_BUTTON, showLocationButton);

        int[] types;
        double[] values;
        switch (entry.sipper.drainType) {
            case APP:
            case USER:
            {
                BatteryStats.Uid uid = entry.sipper.uidObj;
                types = new int[] {
                    R.string.usage_type_cpu,
                    R.string.usage_type_cpu_foreground,
                    R.string.usage_type_wake_lock,
                    R.string.usage_type_gps,
                    R.string.usage_type_wifi_running,
                    R.string.usage_type_data_recv,
                    R.string.usage_type_data_send,
                    R.string.usage_type_data_wifi_recv,
                    R.string.usage_type_data_wifi_send,
                    R.string.usage_type_audio,
                    R.string.usage_type_video,
                };
                values = new double[] {
                    entry.sipper.cpuTime,
                    entry.sipper.cpuFgTime,
                    entry.sipper.wakeLockTime,
                    entry.sipper.gpsTime,
                    entry.sipper.wifiRunningTime,
                    entry.sipper.mobileRxPackets,
                    entry.sipper.mobileTxPackets,
                    entry.sipper.wifiRxPackets,
                    entry.sipper.wifiTxPackets,
                    0,
                    0
                };

                if (entry.sipper.drainType == BatterySipper.DrainType.APP) {
                    Writer result = new StringWriter();
                    PrintWriter printWriter = new FastPrintWriter(result, false, 1024);
                    helper.getStats().dumpLocked(caller, printWriter, "", helper.getStatsType(),
                            uid.getUid());
                    printWriter.flush();
                    args.putString(PowerUsageDetail.EXTRA_REPORT_DETAILS, result.toString());

                    result = new StringWriter();
                    printWriter = new FastPrintWriter(result, false, 1024);
                    helper.getStats().dumpCheckinLocked(caller, printWriter, helper.getStatsType(),
                            uid.getUid());
                    printWriter.flush();
                    args.putString(PowerUsageDetail.EXTRA_REPORT_CHECKIN_DETAILS,
                            result.toString());
                }
            }
            break;
            case CELL:
            {
                types = new int[] {
                    R.string.usage_type_on_time,
                    R.string.usage_type_no_coverage
                };
                values = new double[] {
                    entry.sipper.usageTime,
                    entry.sipper.noCoveragePercent
                };
            }
            break;
            case WIFI:
            {
                types = new int[] {
                    R.string.usage_type_wifi_running,
                    R.string.usage_type_cpu,
                    R.string.usage_type_cpu_foreground,
                    R.string.usage_type_wake_lock,
                    R.string.usage_type_data_recv,
                    R.string.usage_type_data_send,
                    R.string.usage_type_data_wifi_recv,
                    R.string.usage_type_data_wifi_send,
                };
                values = new double[] {
                    entry.sipper.usageTime,
                    entry.sipper.cpuTime,
                    entry.sipper.cpuFgTime,
                    entry.sipper.wakeLockTime,
                    entry.sipper.mobileRxPackets,
                    entry.sipper.mobileTxPackets,
                    entry.sipper.wifiRxPackets,
                    entry.sipper.wifiTxPackets,
                };
            } break;
            case BLUETOOTH:
            {
                types = new int[] {
                    R.string.usage_type_on_time,
                    R.string.usage_type_cpu,
                    R.string.usage_type_cpu_foreground,
                    R.string.usage_type_wake_lock,
                    R.string.usage_type_data_recv,
                    R.string.usage_type_data_send,
                    R.string.usage_type_data_wifi_recv,
                    R.string.usage_type_data_wifi_send,
                };
                values = new double[] {
                    entry.sipper.usageTime,
                    entry.sipper.cpuTime,
                    entry.sipper.cpuFgTime,
                    entry.sipper.wakeLockTime,
                    entry.sipper.mobileRxPackets,
                    entry.sipper.mobileTxPackets,
                    entry.sipper.wifiRxPackets,
                    entry.sipper.wifiTxPackets,
                };
            } break;
            case UNACCOUNTED:
            case OVERCOUNTED:
            {
                types = new int[] {
                    R.string.usage_type_total_battery_capacity,
                    R.string.usage_type_computed_power,
                    R.string.usage_type_min_actual_power,
                    R.string.usage_type_max_actual_power,
                };
                values = new double[] {
                    helper.getPowerProfile().getBatteryCapacity(),
                    helper.getTotalPower(),
                    helper.getMinDrainedPower(),
                    helper.getMaxDrainedPower(),
                };
            } break;
            default:
            {
                types = new int[] {
                    R.string.usage_type_on_time
                };
                values = new double[] {
                    entry.sipper.usageTime
                };
            }
        }
        args.putIntArray(PowerUsageDetail.EXTRA_DETAIL_TYPES, types);
        args.putDoubleArray(PowerUsageDetail.EXTRA_DETAIL_VALUES, values);
        caller.startPreferencePanel(PowerUsageDetail.class.getName(), args,
                R.string.details_title, null, null, 0);
    }

    public static final int ACTION_DISPLAY_SETTINGS = 1;
    public static final int ACTION_WIFI_SETTINGS = 2;
    public static final int ACTION_BLUETOOTH_SETTINGS = 3;
@@ -129,7 +287,7 @@ public class PowerUsageDetail extends Fragment implements Button.OnClickListener
    private ViewGroup mDetailsParent;
    private ViewGroup mControlsParent;
    private long mStartTime;
    private DrainType mDrainType;
    private BatterySipper.DrainType mDrainType;
    private Drawable mAppIcon;
    private double mNoCoverage; // Percentage of time that there was no coverage

@@ -179,7 +337,7 @@ public class PowerUsageDetail extends Fragment implements Button.OnClickListener
        final int gaugeValue = args.getInt(EXTRA_GAUGE, 1);
        mUsageSince = args.getInt(EXTRA_USAGE_SINCE, USAGE_SINCE_UNPLUGGED);
        mUid = args.getInt(EXTRA_UID, 0);
        mDrainType = (DrainType) args.getSerializable(EXTRA_DRAIN_TYPE);
        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);
+35 −20

File changed.

Preview size limit exceeded, changes collapsed.

Loading