Show history of battery level.

Also clean up to remove dead code for running services and old
battery usage UI.

Finally some string improvements from Roy.

Change-Id: I8765a4c744b92edd1505f14c47fea57b918e5d7b
This commit is contained in:
Dianne Hackborn
2010-06-11 10:25:54 -07:00
parent a316d99b34
commit ea38e67853
18 changed files with 597 additions and 2675 deletions

View File

@@ -712,13 +712,6 @@
</intent-filter>
</activity>
<activity android:name=".battery_history.BatteryHistory" android:label="@string/battery_history_label">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEVELOPMENT_PREFERENCE" />
</intent-filter>
</activity>
<activity android:name="Display" android:label="@string/display_label"
android:configChanges="fontScale">
<intent-filter>
@@ -788,6 +781,7 @@
</activity>
<activity android:name=".fuelgauge.PowerUsageSummary"
android:theme="@android:style/Theme.NoTitleBar"
android:label="@string/power_usage_summary_title"
android:clearTaskOnLaunch="true"
>

View File

@@ -1,144 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/topLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/graphLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Spinner
android:id="@+id/typeSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@array/battery_history_type_spinner" />
<Spinner
android:id="@+id/whichSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@array/battery_history_which_spinner" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/messageText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="17dp"
android:visibility="gone" />
<com.android.settings.battery_history.GraphableButton
android:id="@+id/button0"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:layout_weight="1" />
<com.android.settings.battery_history.GraphableButton
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:layout_weight="1" />
<com.android.settings.battery_history.GraphableButton
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:layout_weight="1" />
<com.android.settings.battery_history.GraphableButton
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:layout_weight="1" />
<com.android.settings.battery_history.GraphableButton
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:layout_weight="1" />
<com.android.settings.battery_history.GraphableButton
android:id="@+id/button5"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:layout_weight="1" />
<com.android.settings.battery_history.GraphableButton
android:id="@+id/button6"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:layout_weight="1" />
<com.android.settings.battery_history.GraphableButton
android:id="@+id/button7"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:layout_weight="1" />
</LinearLayout>
</ScrollView>
</LinearLayout>
<LinearLayout
android:id="@+id/textLayout"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/detailsText"
android:layout_width="match_parent"
android:textSize="17dp"
android:layout_height="1000dp"/>
</ScrollView>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 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.
-->
<com.android.settings.fuelgauge.BatteryHistoryChart
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:id="@+android:id/battery_history_chart"
android:paddingRight="?android:attr/scrollbarSize"
android:textAppearance="?android:attr/textAppearanceMedium"
android:shadowRadius="4"
android:shadowColor="?android:attr/colorBackground"
android:shadowDx="2"
android:shadowDy="2">
</com.android.settings.fuelgauge.BatteryHistoryChart>

View File

@@ -1,60 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* Copyright (C) 2008 Google Inc.
*
* 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="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1">
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false"
android:fastScrollEnabled="true" />
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/no_running_services"
android:textAppearance="?android:attr/textAppearanceLarge" />
</FrameLayout>
<view class="com.android.settings.applications.RunningServices$LinearColorBar"
android:id="@+id/color_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="4dp">
<TextView android:id="@+id/foregroundText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceSmallInverse"
android:color="?android:attr/textColorPrimaryInverse"
android:singleLine="true" />
<TextView android:id="@+id/backgroundText"
android:layout_gravity="center_vertical|right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:textAppearance="?android:attr/textAppearanceSmallInverse"
android:color="?android:attr/textColorPrimaryInverse"
android:singleLine="true" />
</view>
</LinearLayout>

View File

@@ -1,86 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2008, 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:orientation="vertical"
android:gravity="fill" >
<ImageView android:id="@+id/separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="?android:attr/listDivider"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingRight="6dip"
android:paddingLeft="6dip"
android:gravity="center_vertical" >
<ImageView android:id="@+id/icon"
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
android:layout_marginLeft="5dip"
android:layout_marginRight="11dip"
android:layout_gravity="center_vertical"
android:scaleType="fitCenter"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:orientation="horizontal"
android:baselineAlignedChildIndex="0"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:singleLine="true"
android:ellipsize="marquee"
android:layout_marginBottom="2dip" />
<TextView android:id="@+id/size"
android:layout_gravity="center_vertical|right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<TextView android:id="@+id/description"
android:layout_marginTop="-4dip"
android:layout_gravity="center_vertical|left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="4dip"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -285,23 +285,6 @@
<item>2</item>
</string-array>
<!-- Match with constants in BatteryHistory class -->
<string-array name="battery_history_type_spinner">
<item>CPU usage</item>
<item>Network usage</item>
<item>GPS usage</item>
<item>Sensor usage</item>
<item>Partial wake usage</item>
<item>Other usage</item>
</string-array>
<!-- Match with constants in BatteryStats class -->
<string-array name="battery_history_which_spinner">
<item>Since last unplugged</item>
<item>Total since boot</item>
<item>Total in all time</item>
</string-array>
<!-- Display options for UsageStats class -->
<string-array name="usage_stats_display_order_types">
<item>Usage Time</item>

View File

@@ -21,4 +21,25 @@
<declare-styleable name="IconPreferenceScreen">
<attr name="icon" format="reference" />
</declare-styleable>
<declare-styleable name="BatteryHistoryChart">
<!-- Base text color, typeface, size, and style. -->
<attr name="android:textAppearance" />
<!-- Text color. -->
<attr name="android:textColor" />
<!-- Size of the text. Recommended dimension type for text is "sp" for scaled-pixels (example: 15sp). -->
<attr name="android:textSize" />
<!-- Typeface (normal, sans, serif, monospace) for the text. -->
<attr name="android:typeface" />
<!-- Style (bold, italic, bolditalic) for the text. -->
<attr name="android:textStyle" />
<!-- Place a shadow of the specified color behind the text. -->
<attr name="android:shadowColor" />
<!-- Horizontal offset of the shadow. -->
<attr name="android:shadowDx" />
<!-- Vertical offset of the shadow. -->
<attr name="android:shadowDy" />
<!-- Radius of the shadow. -->
<attr name="android:shadowRadius" />
</declare-styleable>
</resources>

View File

@@ -431,8 +431,6 @@
<string name="device_info_label">Device info</string>
<!-- The title of the activity to see battery info. -->
<string name="battery_info_label">Battery info</string>
<!-- The title of the activity to see battery history. -->
<string name="battery_history_label">Battery history</string>
<!-- The title of the activity to adjust display settings -->
<string name="display_label">Display</string>
<!-- The title of the activity to see phone info -->
@@ -1752,19 +1750,6 @@ found in the list of installed applications.</string>
<string name="runningservices_settings_summary">View and control currently running services</string>
<!-- Label for a service item when it is restarting -->
<string name="service_restarting">Restarting</string>
<!-- Running services, body text when there are no services to show -->
<string name="no_running_services">No running services</string>
<!-- Running services, title of dialog to stop a service -->
<string name="confirm_stop_service">Stop service?</string>
<!-- Running services, message of dialog to stop a service -->
<string name="confirm_stop_service_msg">The service will no longer run until
started again. This may have undesirable
consequences on the application
<xliff:g id="application">%1$s</xliff:g>.</string>
<!-- Running services, button to stop a service -->
<string name="confirm_stop_stop">Stop</string>
<!-- Running services, button to cancel stopping of a service -->
<string name="confirm_stop_cancel">Cancel</string>
<!-- Running services, description for a service in the started state -->
<string name="service_started_by_app">Started by application.</string>
<!-- Running services, description for a service in the started state -->
@@ -1799,13 +1784,13 @@ found in the list of installed applications.</string>
<!-- Running service details, stop a service that has started itself. -->
<string name="service_stop">Stop</string>
<!-- Running service details, manage a service that is running for some other reason. -->
<string name="service_manage">Manage</string>
<string name="service_manage">Settings</string>
<!-- Running service details, default description for services that are started. -->
<string name="service_stop_description">This service was started by its
application. Stopping it may cause the application to misbehave.</string>
application. Stopping it may cause the application to fail.</string>
<!-- Running service details, default description for services that are managed. -->
<string name="service_manage_description"><xliff:g id="client_name">%1$s</xliff:g>:
currently in use. You can manage your settings to stop it.</string>
currently in use. Touch Settings to control it.</string>
<!-- Description of the main process in the details. -->
<string name="main_running_process_description">Main process that is in use.</string>
<!-- Message that a process's service is in use. -->
@@ -1953,39 +1938,6 @@ found in the list of installed applications.</string>
the final name for Gadgets/Widgets, so please translate both for now. -->
<string name="widget_picker_title">Choose widget</string>
<!-- Used to display "Details for UID 1234" in BatteryHistory -->
<string name="battery_history_details_for">Details for UID <xliff:g id="number" example="1234">%d</xliff:g></string>
<!-- Used to name a set of apps that share a user id in BatteryHistory -->
<string name="battery_history_uid">UID <xliff:g id="user_id">%1$d</xliff:g></string>
<!-- Used as a title for the network usage details screen in BatteryHistory -->
<string name="battery_history_network_usage">Network usage details for <xliff:g id="app_name">%1$s</xliff:g>:</string>
<!-- Used to show the number of bytes received by an app over the network in BatteryHistory -->
<string name="battery_history_bytes_received">Bytes received: <xliff:g id="bytes">%1$d</xliff:g></string>
<!-- Used to show the number of bytes sent by an app over the network in BatteryHistory -->
<string name="battery_history_bytes_sent">Bytes sent: <xliff:g id="bytes">%1$d</xliff:g></string>
<!-- Used to show the number of bytes sent and received by an app over the network in BatteryHistory -->
<string name="battery_history_bytes_total">Total bytes: <xliff:g id="bytes">%1$d</xliff:g></string>
<!-- Used as a title for the cpu usage details screen in BatteryHistory -->
<string name="battery_history_cpu_usage">CPU usage details for <xliff:g id="app_name">%1$s</xliff:g>:</string>
<!-- Used to show the time spent in user code for a given app in BatteryHistory -->
<string name="battery_history_user_time">User time: </string>
<!-- Used to show the time spent in system code for a given app in BatteryHistory -->
<string name="battery_history_system_time">System time: </string>
<!-- Used to show the time spent in user or system code for a given app in BatteryHistory -->
<string name="battery_history_total_time">Total time: </string>
<!-- Used to show the number of times an app has been started in BatteryHistory -->
<string name="battery_history_starts">Starts: <xliff:g id="starts">%1$d</xliff:g></string>
<!-- Used to show an amount of time in the form "d days, h hours, m minutes, s seconds" in BatteryHistory -->
<string name="battery_history_days"><xliff:g id="days">%1$d</xliff:g>d <xliff:g id="hours">%2$d</xliff:g>h <xliff:g id="minutes">%3$d</xliff:g>m <xliff:g id="seconds">%4$d</xliff:g>s</string>
@@ -1997,52 +1949,7 @@ found in the list of installed applications.</string>
<!-- Used to show an amount of time in the form "s seconds" in BatteryHistory -->
<string name="battery_history_seconds"><xliff:g id="seconds">%1$d</xliff:g>s</string>
<!-- Used to head a list of packages that share a given user id BatteryHistory -->
<string name="battery_history_packages_sharing_this_uid">Packages sharing this UID:</string>
<!-- Used when no battery data available in BatteryHistory -->
<string name="battery_history_no_data">No battery usage data available</string>
<!-- Used for Sensor detail screen in BatteryHistory -->
<string name="battery_history_sensor">Sensor:</string>
<!-- Used for Wakelock detail screen in BatteryHistory -->
<string name="battery_history_wakelock">Partial Wakelock:</string>
<!-- Used for Sensor detail screen in BatteryHistory -->
<string name="battery_history_used_by_packages">Sensor used by packages:</string>
<!-- Used for Sensor detail screen in BatteryHistory -->
<string name="battery_history_sensor_usage">Used <xliff:g id="count">%1$d</xliff:g> times by <xliff:g id="package">%2$s</xliff:g></string>
<!-- Used for Sensor detail screen in BatteryHistory -->
<string name="battery_history_sensor_usage_multi">Used <xliff:g id="count">%1$d</xliff:g> times by one of:</string>
<!-- Used for label of awake bar in BatteryHistory -->
<string name="battery_history_awake_label">Running</string>
<!-- Used for label of screen on bar in BatteryHistory -->
<string name="battery_history_screen_on_label">Screen on</string>
<!-- Used for label of phone on bar in BatteryHistory -->
<string name="battery_history_phone_on_label">Phone on</string>
<!-- Used for awake time message in BatteryHistory -->
<string name="battery_history_awake">Time spent without sleeping:</string>
<!-- Used for Screen on time message in BatteryHistory -->
<string name="battery_history_screen_on">Time spent with screen on:</string>
<!-- Used for Phone on time message in BatteryHistory -->
<string name="battery_history_phone_on">Time spent with phone on:</string>
<!-- Used for Screen on time message in BatteryHistory -->
<string name="battery_history_screen_on_battery">On battery:</string>
<!-- XXX remove? Used for Screen on time message in BatteryHistory -->
<string name="battery_history_screen_on_plugged">Plugged in:</string>
<!-- XXX remove? Strings used for displaying usage statistics -->
<string name="usage_stats_label">Usage statistics</string>
@@ -2109,6 +2016,8 @@ found in the list of installed applications.</string>
<string name="battery_since_unplugged">Battery use since unplugged</string>
<!-- Battery usage since user reset the stats -->
<string name="battery_since_reset">Battery use since reset</string>
<!-- Battery usage on battery duration -->
<string name="battery_stats_on_battery"><xliff:g id="time">%1$s</xliff:g> on battery</string>
<!-- Battery usage duration -->
<string name="battery_stats_duration"><xliff:g id="time">%1$s</xliff:g> since unplugged</string>
<!-- Battery usage during last unplugged period -->

View File

@@ -1,538 +0,0 @@
/*
* Copyright (C) 2010 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.R;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.format.DateUtils;
import android.text.format.Formatter;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
public class RunningProcessesViewOld extends FrameLayout
implements AdapterView.OnItemClickListener {
static final String TAG = "RunningServices";
/** Maximum number of services to retrieve */
static final int MAX_SERVICES = 100;
static final int MSG_UPDATE_TIMES = 1;
static final int MSG_UPDATE_CONTENTS = 2;
static final int MSG_REFRESH_UI = 3;
static final long TIME_UPDATE_DELAY = 1000;
static final long CONTENTS_UPDATE_DELAY = 2000;
// Memory pages are 4K.
static final long PAGE_SIZE = 4*1024;
long SECONDARY_SERVER_MEM;
final HashMap<View, ActiveItem> mActiveItems = new HashMap<View, ActiveItem>();
ActivityManager mAm;
RunningState mState;
StringBuilder mBuilder = new StringBuilder(128);
RunningState.BaseItem mCurSelected;
int mProcessBgColor;
ListView mListView;
LinearColorBar mColorBar;
TextView mBackgroundProcessText;
TextView mForegroundProcessText;
int mLastNumBackgroundProcesses = -1;
int mLastNumForegroundProcesses = -1;
int mLastNumServiceProcesses = -1;
long mLastBackgroundProcessMemory = -1;
long mLastForegroundProcessMemory = -1;
long mLastServiceProcessMemory = -1;
long mLastAvailMemory = -1;
Dialog mCurDialog;
byte[] mBuffer = new byte[1024];
class ActiveItem {
View mRootView;
RunningState.BaseItem mItem;
ActivityManager.RunningServiceInfo mService;
ViewHolder mHolder;
long mFirstRunTime;
void updateTime(Context context) {
if (mItem.mIsProcess) {
String size = mItem.mSizeStr != null ? mItem.mSizeStr : "";
if (!size.equals(mItem.mCurSizeStr)) {
mItem.mCurSizeStr = size;
mHolder.size.setText(size);
}
} else {
if (mItem.mActiveSince >= 0) {
mHolder.size.setText(DateUtils.formatElapsedTime(mBuilder,
(SystemClock.uptimeMillis()-mFirstRunTime)/1000));
} else {
mHolder.size.setText(context.getResources().getText(
R.string.service_restarting));
}
}
}
}
static class ViewHolder {
ImageView separator;
ImageView icon;
TextView name;
TextView description;
TextView size;
}
static class TimeTicker extends TextView {
public TimeTicker(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
class ServiceListAdapter extends BaseAdapter {
final RunningState mState;
final LayoutInflater mInflater;
ArrayList<RunningState.BaseItem> mItems;
ServiceListAdapter(RunningState state) {
mState = state;
mInflater = (LayoutInflater)getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
refreshItems();
}
void refreshItems() {
ArrayList<RunningState.BaseItem> newItems = mState.getCurrentItems();
if (mItems != newItems) {
mItems = newItems;
}
if (mItems == null) {
mItems = new ArrayList<RunningState.BaseItem>();
}
}
public boolean hasStableIds() {
return true;
}
public int getCount() {
return mItems.size();
}
public Object getItem(int position) {
return mItems.get(position);
}
public long getItemId(int position) {
return mItems.get(position).hashCode();
}
public boolean areAllItemsEnabled() {
return false;
}
public boolean isEnabled(int position) {
return !mItems.get(position).mIsProcess;
}
public View getView(int position, View convertView, ViewGroup parent) {
View v;
if (convertView == null) {
v = newView(parent);
} else {
v = convertView;
}
bindView(v, position);
return v;
}
public View newView(ViewGroup parent) {
View v = mInflater.inflate(R.layout.running_services_item, parent, false);
ViewHolder h = new ViewHolder();
h.separator = (ImageView)v.findViewById(R.id.separator);
h.icon = (ImageView)v.findViewById(R.id.icon);
h.name = (TextView)v.findViewById(R.id.name);
h.description = (TextView)v.findViewById(R.id.description);
h.size = (TextView)v.findViewById(R.id.size);
v.setTag(h);
return v;
}
public void bindView(View view, int position) {
synchronized (mState.mLock) {
ViewHolder vh = (ViewHolder) view.getTag();
if (position >= mItems.size()) {
// List must have changed since we last reported its
// size... ignore here, we will be doing a data changed
// to refresh the entire list.
return;
}
RunningState.BaseItem item = mItems.get(position);
vh.name.setText(item.mDisplayLabel);
vh.separator.setVisibility(item.mNeedDivider
? View.VISIBLE : View.INVISIBLE);
ActiveItem ai = new ActiveItem();
ai.mRootView = view;
ai.mItem = item;
ai.mHolder = vh;
ai.mFirstRunTime = item.mActiveSince;
vh.description.setText(item.mDescription);
if (item.mIsProcess) {
view.setBackgroundColor(mProcessBgColor);
vh.icon.setImageDrawable(null);
vh.icon.setVisibility(View.GONE);
vh.description.setText(item.mDescription);
item.mCurSizeStr = null;
} else {
view.setBackgroundDrawable(null);
vh.icon.setImageDrawable(item.mPackageInfo.loadIcon(
getContext().getPackageManager()));
vh.icon.setVisibility(View.VISIBLE);
vh.description.setText(item.mDescription);
ai.mFirstRunTime = item.mActiveSince;
}
ai.updateTime(getContext());
mActiveItems.put(view, ai);
}
}
}
public static class LinearColorBar extends LinearLayout {
private float mRedRatio;
private float mYellowRatio;
private float mGreenRatio;
final Rect mRect = new Rect();
final Paint mPaint = new Paint();
public LinearColorBar(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
mPaint.setStyle(Paint.Style.FILL);
}
public void setRatios(float red, float yellow, float green) {
mRedRatio = red;
mYellowRatio = yellow;
mGreenRatio = green;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
mRect.top = 0;
mRect.bottom = getHeight();
int left = 0;
int right = left + (int)(width*mRedRatio);
if (left < right) {
mRect.left = left;
mRect.right = right;
mPaint.setColor(0xffff8080);
canvas.drawRect(mRect, mPaint);
width -= (right-left);
left = right;
}
right = left + (int)(width*mYellowRatio);
if (left < right) {
mRect.left = left;
mRect.right = right;
mPaint.setColor(0xffffff00);
canvas.drawRect(mRect, mPaint);
width -= (right-left);
left = right;
}
right = left + width;
if (left < right) {
mRect.left = left;
mRect.right = right;
mPaint.setColor(0xff80ff80);
canvas.drawRect(mRect, mPaint);
}
}
}
HandlerThread mBackgroundThread;
final class BackgroundHandler extends Handler {
public BackgroundHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_CONTENTS:
Message cmd = mHandler.obtainMessage(MSG_REFRESH_UI);
cmd.arg1 = mState.update(getContext(), mAm) ? 1 : 0;
mHandler.sendMessage(cmd);
removeMessages(MSG_UPDATE_CONTENTS);
msg = obtainMessage(MSG_UPDATE_CONTENTS);
sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
break;
}
}
};
BackgroundHandler mBackgroundHandler;
final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_TIMES:
Iterator<ActiveItem> it = mActiveItems.values().iterator();
while (it.hasNext()) {
ActiveItem ai = it.next();
if (ai.mRootView.getWindowToken() == null) {
// Clean out any dead views, just in case.
it.remove();
continue;
}
ai.updateTime(getContext());
}
removeMessages(MSG_UPDATE_TIMES);
msg = obtainMessage(MSG_UPDATE_TIMES);
sendMessageDelayed(msg, TIME_UPDATE_DELAY);
break;
case MSG_REFRESH_UI:
refreshUi(msg.arg1 != 0);
break;
}
}
};
private boolean matchText(byte[] buffer, int index, String text) {
int N = text.length();
if ((index+N) >= buffer.length) {
return false;
}
for (int i=0; i<N; i++) {
if (buffer[index+i] != text.charAt(i)) {
return false;
}
}
return true;
}
private long extractMemValue(byte[] buffer, int index) {
while (index < buffer.length && buffer[index] != '\n') {
if (buffer[index] >= '0' && buffer[index] <= '9') {
int start = index;
index++;
while (index < buffer.length && buffer[index] >= '0'
&& buffer[index] <= '9') {
index++;
}
String str = new String(buffer, 0, start, index-start);
return ((long)Integer.parseInt(str)) * 1024;
}
index++;
}
return 0;
}
private long readAvailMem() {
try {
long memFree = 0;
long memCached = 0;
FileInputStream is = new FileInputStream("/proc/meminfo");
int len = is.read(mBuffer);
is.close();
final int BUFLEN = mBuffer.length;
for (int i=0; i<len && (memFree == 0 || memCached == 0); i++) {
if (matchText(mBuffer, i, "MemFree")) {
i += 7;
memFree = extractMemValue(mBuffer, i);
} else if (matchText(mBuffer, i, "Cached")) {
i += 6;
memCached = extractMemValue(mBuffer, i);
}
while (i < BUFLEN && mBuffer[i] != '\n') {
i++;
}
}
return memFree + memCached;
} catch (java.io.FileNotFoundException e) {
} catch (java.io.IOException e) {
}
return 0;
}
void refreshUi(boolean dataChanged) {
if (dataChanged) {
ServiceListAdapter adapter = (ServiceListAdapter)(mListView.getAdapter());
adapter.refreshItems();
adapter.notifyDataSetChanged();
}
// This is the amount of available memory until we start killing
// background services.
long availMem = readAvailMem() - SECONDARY_SERVER_MEM;
if (availMem < 0) {
availMem = 0;
}
synchronized (mState.mLock) {
if (mLastNumBackgroundProcesses != mState.mNumBackgroundProcesses
|| mLastBackgroundProcessMemory != mState.mBackgroundProcessMemory
|| mLastAvailMemory != availMem) {
mLastNumBackgroundProcesses = mState.mNumBackgroundProcesses;
mLastBackgroundProcessMemory = mState.mBackgroundProcessMemory;
mLastAvailMemory = availMem;
String sizeStr = Formatter.formatShortFileSize(getContext(),
mLastAvailMemory + mLastBackgroundProcessMemory);
mBackgroundProcessText.setText(getResources().getString(
R.string.service_background_processes, sizeStr));
}
if (mLastNumForegroundProcesses != mState.mNumForegroundProcesses
|| mLastForegroundProcessMemory != mState.mForegroundProcessMemory) {
mLastNumForegroundProcesses = mState.mNumForegroundProcesses;
mLastForegroundProcessMemory = mState.mForegroundProcessMemory;
String sizeStr = Formatter.formatShortFileSize(getContext(),
mLastForegroundProcessMemory);
mForegroundProcessText.setText(getResources().getString(
R.string.service_foreground_processes, sizeStr));
}
mLastNumServiceProcesses = mState.mNumServiceProcesses;
mLastServiceProcessMemory = mState.mServiceProcessMemory;
float totalMem = availMem + mLastBackgroundProcessMemory
+ mLastForegroundProcessMemory + mLastServiceProcessMemory;
mColorBar.setRatios(mLastForegroundProcessMemory/totalMem,
mLastServiceProcessMemory/totalMem,
(availMem+mLastBackgroundProcessMemory)/totalMem);
}
}
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
ListView l = (ListView)parent;
RunningState.BaseItem bi = (RunningState.BaseItem)l.getAdapter().getItem(position);
mCurSelected = bi;
}
public void onMovedToScrapHeap(View view) {
mActiveItems.remove(view);
}
public RunningProcessesViewOld(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void doCreate(Bundle savedInstanceState, Object nonConfigurationInstace) {
mAm = (ActivityManager)getContext().getSystemService(Context.ACTIVITY_SERVICE);
mState = (RunningState)nonConfigurationInstace;
if (mState == null) {
mState = new RunningState();
}
mProcessBgColor = 0xff505050;
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.running_processes_view, this);
mListView = (ListView)findViewById(android.R.id.list);
View emptyView = findViewById(com.android.internal.R.id.empty);
if (emptyView != null) {
mListView.setEmptyView(emptyView);
}
mListView.setOnItemClickListener(this);
mListView.setDivider(null);
mListView.setAdapter(new ServiceListAdapter(mState));
mColorBar = (LinearColorBar)findViewById(R.id.color_bar);
mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
// Magic! Implementation detail! Don't count on this!
SECONDARY_SERVER_MEM =
Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
}
public void doPause() {
mHandler.removeMessages(MSG_UPDATE_TIMES);
if (mBackgroundThread != null) {
mBackgroundThread.quit();
mBackgroundThread = null;
mBackgroundHandler = null;
}
}
public void doResume() {
refreshUi(mState.update(getContext(), mAm));
mBackgroundThread = new HandlerThread("RunningServices");
mBackgroundThread.start();
mBackgroundHandler = new BackgroundHandler(mBackgroundThread.getLooper());
mHandler.removeMessages(MSG_UPDATE_TIMES);
Message msg = mHandler.obtainMessage(MSG_UPDATE_TIMES);
mHandler.sendMessageDelayed(msg, TIME_UPDATE_DELAY);
mBackgroundHandler.removeMessages(MSG_UPDATE_CONTENTS);
msg = mBackgroundHandler.obtainMessage(MSG_UPDATE_CONTENTS);
mBackgroundHandler.sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
}
public Object doRetainNonConfigurationInstance() {
return mState;
}
}

View File

@@ -1,582 +0,0 @@
/*
* Copyright (C) 2006 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.R;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.format.DateUtils;
import android.text.format.Formatter;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
public class RunningServices extends ListActivity
implements AbsListView.RecyclerListener,
DialogInterface.OnClickListener {
static final String TAG = "RunningServices";
/** Maximum number of services to retrieve */
static final int MAX_SERVICES = 100;
static final int MSG_UPDATE_TIMES = 1;
static final int MSG_UPDATE_CONTENTS = 2;
static final int MSG_REFRESH_UI = 3;
static final long TIME_UPDATE_DELAY = 1000;
static final long CONTENTS_UPDATE_DELAY = 2000;
// Memory pages are 4K.
static final long PAGE_SIZE = 4*1024;
long SECONDARY_SERVER_MEM;
final HashMap<View, ActiveItem> mActiveItems = new HashMap<View, ActiveItem>();
ActivityManager mAm;
RunningState mState;
StringBuilder mBuilder = new StringBuilder(128);
RunningState.BaseItem mCurSelected;
int mProcessBgColor;
LinearColorBar mColorBar;
TextView mBackgroundProcessText;
TextView mForegroundProcessText;
int mLastNumBackgroundProcesses = -1;
int mLastNumForegroundProcesses = -1;
int mLastNumServiceProcesses = -1;
long mLastBackgroundProcessMemory = -1;
long mLastForegroundProcessMemory = -1;
long mLastServiceProcessMemory = -1;
long mLastAvailMemory = -1;
Dialog mCurDialog;
byte[] mBuffer = new byte[1024];
class ActiveItem {
View mRootView;
RunningState.BaseItem mItem;
ActivityManager.RunningServiceInfo mService;
ViewHolder mHolder;
long mFirstRunTime;
void updateTime(Context context) {
if (mItem.mIsProcess) {
String size = mItem.mSizeStr != null ? mItem.mSizeStr : "";
if (!size.equals(mItem.mCurSizeStr)) {
mItem.mCurSizeStr = size;
mHolder.size.setText(size);
}
} else {
if (mItem.mActiveSince >= 0) {
mHolder.size.setText(DateUtils.formatElapsedTime(mBuilder,
(SystemClock.uptimeMillis()-mFirstRunTime)/1000));
} else {
mHolder.size.setText(context.getResources().getText(
R.string.service_restarting));
}
}
}
}
static class ViewHolder {
ImageView separator;
ImageView icon;
TextView name;
TextView description;
TextView size;
}
static class TimeTicker extends TextView {
public TimeTicker(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
class ServiceListAdapter extends BaseAdapter {
final RunningState mState;
final LayoutInflater mInflater;
ArrayList<RunningState.BaseItem> mItems;
ServiceListAdapter(RunningState state) {
mState = state;
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
refreshItems();
}
void refreshItems() {
ArrayList<RunningState.BaseItem> newItems = mState.getCurrentItems();
if (mItems != newItems) {
mItems = newItems;
}
if (mItems == null) {
mItems = new ArrayList<RunningState.BaseItem>();
}
}
public boolean hasStableIds() {
return true;
}
public int getCount() {
return mItems.size();
}
public Object getItem(int position) {
return mItems.get(position);
}
public long getItemId(int position) {
return mItems.get(position).hashCode();
}
public boolean areAllItemsEnabled() {
return false;
}
public boolean isEnabled(int position) {
return !mItems.get(position).mIsProcess;
}
public View getView(int position, View convertView, ViewGroup parent) {
View v;
if (convertView == null) {
v = newView(parent);
} else {
v = convertView;
}
bindView(v, position);
return v;
}
public View newView(ViewGroup parent) {
View v = mInflater.inflate(R.layout.running_services_item, parent, false);
ViewHolder h = new ViewHolder();
h.separator = (ImageView)v.findViewById(R.id.separator);
h.icon = (ImageView)v.findViewById(R.id.icon);
h.name = (TextView)v.findViewById(R.id.name);
h.description = (TextView)v.findViewById(R.id.description);
h.size = (TextView)v.findViewById(R.id.size);
v.setTag(h);
return v;
}
public void bindView(View view, int position) {
synchronized (mState.mLock) {
ViewHolder vh = (ViewHolder) view.getTag();
if (position >= mItems.size()) {
// List must have changed since we last reported its
// size... ignore here, we will be doing a data changed
// to refresh the entire list.
return;
}
RunningState.BaseItem item = mItems.get(position);
vh.name.setText(item.mDisplayLabel);
vh.separator.setVisibility(item.mNeedDivider
? View.VISIBLE : View.INVISIBLE);
ActiveItem ai = new ActiveItem();
ai.mRootView = view;
ai.mItem = item;
ai.mHolder = vh;
ai.mFirstRunTime = item.mActiveSince;
vh.description.setText(item.mDescription);
if (item.mIsProcess) {
view.setBackgroundColor(mProcessBgColor);
vh.icon.setImageDrawable(null);
vh.icon.setVisibility(View.GONE);
vh.description.setText(item.mDescription);
item.mCurSizeStr = null;
} else {
view.setBackgroundDrawable(null);
vh.icon.setImageDrawable(item.mPackageInfo.loadIcon(getPackageManager()));
vh.icon.setVisibility(View.VISIBLE);
vh.description.setText(item.mDescription);
ai.mFirstRunTime = item.mActiveSince;
}
ai.updateTime(RunningServices.this);
mActiveItems.put(view, ai);
}
}
}
public static class LinearColorBar extends LinearLayout {
private float mRedRatio;
private float mYellowRatio;
private float mGreenRatio;
final Rect mRect = new Rect();
final Paint mPaint = new Paint();
public LinearColorBar(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
mPaint.setStyle(Paint.Style.FILL);
}
public void setRatios(float red, float yellow, float green) {
mRedRatio = red;
mYellowRatio = yellow;
mGreenRatio = green;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
mRect.top = 0;
mRect.bottom = getHeight();
int left = 0;
int right = left + (int)(width*mRedRatio);
if (left < right) {
mRect.left = left;
mRect.right = right;
mPaint.setColor(0xffff8080);
canvas.drawRect(mRect, mPaint);
width -= (right-left);
left = right;
}
right = left + (int)(width*mYellowRatio);
if (left < right) {
mRect.left = left;
mRect.right = right;
mPaint.setColor(0xffffff00);
canvas.drawRect(mRect, mPaint);
width -= (right-left);
left = right;
}
right = left + width;
if (left < right) {
mRect.left = left;
mRect.right = right;
mPaint.setColor(0xff80ff80);
canvas.drawRect(mRect, mPaint);
}
}
}
HandlerThread mBackgroundThread;
final class BackgroundHandler extends Handler {
public BackgroundHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_CONTENTS:
Message cmd = mHandler.obtainMessage(MSG_REFRESH_UI);
cmd.arg1 = mState.update(RunningServices.this, mAm) ? 1 : 0;
mHandler.sendMessage(cmd);
removeMessages(MSG_UPDATE_CONTENTS);
msg = obtainMessage(MSG_UPDATE_CONTENTS);
sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
break;
}
}
};
BackgroundHandler mBackgroundHandler;
final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_TIMES:
Iterator<ActiveItem> it = mActiveItems.values().iterator();
while (it.hasNext()) {
ActiveItem ai = it.next();
if (ai.mRootView.getWindowToken() == null) {
// Clean out any dead views, just in case.
it.remove();
continue;
}
ai.updateTime(RunningServices.this);
}
removeMessages(MSG_UPDATE_TIMES);
msg = obtainMessage(MSG_UPDATE_TIMES);
sendMessageDelayed(msg, TIME_UPDATE_DELAY);
break;
case MSG_REFRESH_UI:
refreshUi(msg.arg1 != 0);
break;
}
}
};
private boolean matchText(byte[] buffer, int index, String text) {
int N = text.length();
if ((index+N) >= buffer.length) {
return false;
}
for (int i=0; i<N; i++) {
if (buffer[index+i] != text.charAt(i)) {
return false;
}
}
return true;
}
private long extractMemValue(byte[] buffer, int index) {
while (index < buffer.length && buffer[index] != '\n') {
if (buffer[index] >= '0' && buffer[index] <= '9') {
int start = index;
index++;
while (index < buffer.length && buffer[index] >= '0'
&& buffer[index] <= '9') {
index++;
}
String str = new String(buffer, 0, start, index-start);
return ((long)Integer.parseInt(str)) * 1024;
}
index++;
}
return 0;
}
private long readAvailMem() {
try {
long memFree = 0;
long memCached = 0;
FileInputStream is = new FileInputStream("/proc/meminfo");
int len = is.read(mBuffer);
is.close();
final int BUFLEN = mBuffer.length;
for (int i=0; i<len && (memFree == 0 || memCached == 0); i++) {
if (matchText(mBuffer, i, "MemFree")) {
i += 7;
memFree = extractMemValue(mBuffer, i);
} else if (matchText(mBuffer, i, "Cached")) {
i += 6;
memCached = extractMemValue(mBuffer, i);
}
while (i < BUFLEN && mBuffer[i] != '\n') {
i++;
}
}
return memFree + memCached;
} catch (java.io.FileNotFoundException e) {
} catch (java.io.IOException e) {
}
return 0;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAm = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
mState = (RunningState)getLastNonConfigurationInstance();
if (mState == null) {
mState = new RunningState();
}
mProcessBgColor = 0xff505050;
setContentView(R.layout.running_services);
getListView().setDivider(null);
getListView().setAdapter(new ServiceListAdapter(mState));
mColorBar = (LinearColorBar)findViewById(R.id.color_bar);
mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
// Magic! Implementation detail! Don't count on this!
SECONDARY_SERVER_MEM =
Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
}
void refreshUi(boolean dataChanged) {
if (dataChanged) {
ServiceListAdapter adapter = (ServiceListAdapter)(getListView().getAdapter());
adapter.refreshItems();
adapter.notifyDataSetChanged();
}
// This is the amount of available memory until we start killing
// background services.
long availMem = readAvailMem() - SECONDARY_SERVER_MEM;
if (availMem < 0) {
availMem = 0;
}
synchronized (mState.mLock) {
if (mLastNumBackgroundProcesses != mState.mNumBackgroundProcesses
|| mLastBackgroundProcessMemory != mState.mBackgroundProcessMemory
|| mLastAvailMemory != availMem) {
mLastNumBackgroundProcesses = mState.mNumBackgroundProcesses;
mLastBackgroundProcessMemory = mState.mBackgroundProcessMemory;
mLastAvailMemory = availMem;
String availStr = availMem != 0
? Formatter.formatShortFileSize(this, availMem) : "0";
String sizeStr = Formatter.formatShortFileSize(this, mLastBackgroundProcessMemory);
mBackgroundProcessText.setText(getResources().getString(
R.string.service_background_processes,
mLastNumBackgroundProcesses, availStr, sizeStr));
}
if (mLastNumForegroundProcesses != mState.mNumForegroundProcesses
|| mLastForegroundProcessMemory != mState.mForegroundProcessMemory) {
mLastNumForegroundProcesses = mState.mNumForegroundProcesses;
mLastForegroundProcessMemory = mState.mForegroundProcessMemory;
String sizeStr = Formatter.formatShortFileSize(this, mLastForegroundProcessMemory);
mForegroundProcessText.setText(getResources().getString(
R.string.service_foreground_processes, mLastNumForegroundProcesses, sizeStr));
}
mLastNumServiceProcesses = mState.mNumServiceProcesses;
mLastServiceProcessMemory = mState.mServiceProcessMemory;
float totalMem = availMem + mLastBackgroundProcessMemory
+ mLastForegroundProcessMemory + mLastServiceProcessMemory;
mColorBar.setRatios(mLastForegroundProcessMemory/totalMem,
mLastServiceProcessMemory/totalMem,
(availMem+mLastBackgroundProcessMemory)/totalMem);
}
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
RunningState.BaseItem bi = (RunningState.BaseItem)l.getAdapter().getItem(position);
if (!bi.mIsProcess) {
RunningState.ServiceItem si = (RunningState.ServiceItem)bi;
if (si.mRunningService.clientLabel != 0) {
mCurSelected = null;
PendingIntent pi = mAm.getRunningServiceControlPanel(
si.mRunningService.service);
if (pi != null) {
try {
this.startIntentSender(pi.getIntentSender(), null,
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET, 0);
} catch (IntentSender.SendIntentException e) {
Log.w(TAG, e);
} catch (IllegalArgumentException e) {
Log.w(TAG, e);
} catch (ActivityNotFoundException e) {
Log.w(TAG, e);
}
}
} else {
mCurSelected = bi;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.confirm_stop_service);
String msg = getResources().getString(
R.string.confirm_stop_service_msg,
si.mPackageInfo.loadLabel(getPackageManager()));
builder.setMessage(msg);
builder.setPositiveButton(R.string.confirm_stop_stop, this);
builder.setNegativeButton(R.string.confirm_stop_cancel, null);
builder.setCancelable(true);
mCurDialog = builder.show();
}
} else {
mCurSelected = null;
}
}
public void onClick(DialogInterface dialog, int which) {
if (mCurSelected != null) {
stopService(new Intent().setComponent(
((RunningState.ServiceItem)mCurSelected).mRunningService.service));
if (mBackgroundHandler != null) {
mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS);
}
}
}
@Override
protected void onPause() {
super.onPause();
mHandler.removeMessages(MSG_UPDATE_TIMES);
if (mBackgroundThread != null) {
mBackgroundThread.quit();
mBackgroundThread = null;
mBackgroundHandler = null;
}
}
@Override
protected void onResume() {
super.onResume();
refreshUi(mState.update(this, mAm));
mBackgroundThread = new HandlerThread("RunningServices");
mBackgroundThread.start();
mBackgroundHandler = new BackgroundHandler(mBackgroundThread.getLooper());
mHandler.removeMessages(MSG_UPDATE_TIMES);
Message msg = mHandler.obtainMessage(MSG_UPDATE_TIMES);
mHandler.sendMessageDelayed(msg, TIME_UPDATE_DELAY);
mBackgroundHandler.removeMessages(MSG_UPDATE_CONTENTS);
msg = mBackgroundHandler.obtainMessage(MSG_UPDATE_CONTENTS);
mBackgroundHandler.sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
}
@Override
public Object onRetainNonConfigurationInstance() {
return mState;
}
public void onMovedToScrapHeap(View view) {
mActiveItems.remove(view);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mCurDialog != null) {
mCurDialog.dismiss();
}
}
}

View File

@@ -418,7 +418,7 @@ public class RunningState {
boolean changed = false;
List<ActivityManager.RunningServiceInfo> services
= am.getRunningServices(RunningServices.MAX_SERVICES);
= am.getRunningServices(RunningProcessesView.MAX_SERVICES);
final int NS = services != null ? services.size() : 0;
for (int i=0; i<NS; i++) {
ActivityManager.RunningServiceInfo si = services.get(i);
@@ -671,7 +671,7 @@ public class RunningState {
numForegroundProcesses++;
mAllProcessItems.add(proc);
} else {
Log.i(RunningServices.TAG, "Unknown non-service process: "
Log.i("RunningState", "Unknown non-service process: "
+ proc.mProcessName + " #" + proc.mPid);
}
} else {

View File

@@ -1,916 +0,0 @@
/*
* Copyright (C) 2006 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.battery_history;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Formatter;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import com.android.internal.app.IBatteryStats;
import com.android.settings.R;
import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.BatteryStats;
import android.os.Bundle;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.BatteryStats.Timer;
import android.os.BatteryStats.Uid;
import android.util.Log;
import android.util.LogPrinter;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;
public class BatteryHistory extends Activity implements OnClickListener, OnItemSelectedListener {
private static final String TAG = "BatteryHistory";
private static final int SECONDS_PER_MINUTE = 60;
private static final int SECONDS_PER_HOUR = 60 * 60;
private static final int SECONDS_PER_DAY = 24 * 60 * 60;
// Must be in sync with the values in res/values/array.xml (id battery_history_type_spinner)
private static final int CPU_USAGE = 0;
private static final int NETWORK_USAGE = 1;
private static final int GPS_USAGE = 2;
private static final int SENSOR_USAGE = 3;
private static final int WAKELOCK_USAGE = 4;
private static final int MISC_USAGE = 5;
// Must be in sync with the values in res/values/array.xml (id battery_history_which_spinner)
private static final int UNPLUGGED = 0;
private static final int CURRENT = 1;
private static final int TOTAL = 2;
private BatteryStats mStats;
private int mWhich = BatteryStats.STATS_UNPLUGGED;
private int mType = MISC_USAGE;
private GraphableButton[] mButtons;
IBatteryStats mBatteryInfo;
private List<CpuUsage> mCpuUsage = new ArrayList<CpuUsage>();
private List<NetworkUsage> mNetworkUsage = new ArrayList<NetworkUsage>();
private List<SensorUsage> mSensorUsage = new ArrayList<SensorUsage>();
private List<SensorUsage> mGpsUsage = new ArrayList<SensorUsage>();
private List<WakelockUsage> mWakelockUsage = new ArrayList<WakelockUsage>();
private List<MiscUsage> mMiscUsage = new ArrayList<MiscUsage>();
private boolean mHaveCpuUsage, mHaveNetworkUsage, mHaveSensorUsage,
mHaveWakelockUsage, mHaveMiscUsage;
private LinearLayout mGraphLayout;
private LinearLayout mTextLayout;
private TextView mMessageText;
private TextView mDetailsText;
private Button mDetailsBackButton;
private Spinner mTypeSpinner;
private Spinner mWhichSpinner;
private boolean mDetailsShown = false;
private static String getLabel(String packageName, PackageManager pm) {
try {
ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
CharSequence label = ai.loadLabel(pm);
if (label != null) {
return label.toString();
}
} catch (NameNotFoundException e) {
return packageName;
}
return "";
}
void formatTime(double millis, StringBuilder sb) {
int seconds = (int) Math.floor(millis / 1000);
int days = 0, hours = 0, minutes = 0;
if (seconds > SECONDS_PER_DAY) {
days = seconds / SECONDS_PER_DAY;
seconds -= days * SECONDS_PER_DAY;
}
if (seconds > SECONDS_PER_HOUR) {
hours = seconds / SECONDS_PER_HOUR;
seconds -= hours * SECONDS_PER_HOUR;
}
if (seconds > SECONDS_PER_MINUTE) {
minutes = seconds / SECONDS_PER_MINUTE;
seconds -= minutes * SECONDS_PER_MINUTE;
}
if (days > 0) {
sb.append(getString(R.string.battery_history_days, days, hours, minutes, seconds));
} else if (hours > 0) {
sb.append(getString(R.string.battery_history_hours, hours, minutes, seconds));
} else if (minutes > 0) {
sb.append(getString(R.string.battery_history_minutes, minutes, seconds));
} else {
sb.append(getString(R.string.battery_history_seconds, seconds));
}
}
abstract class Graphable implements Comparable<Graphable> {
protected String mName;
protected String mNamePackage;
protected boolean mUniqueName;
protected String[] mPackages;
protected String[] mPackageNames;
public abstract String getLabel();
public abstract double getSortValue();
public abstract double[] getValues();
public abstract void getInfo(StringBuilder info);
public double getMaxValue() {
return -Double.MAX_VALUE;
}
public int compareTo(Graphable o) {
double t = getSortValue();
double ot = o.getSortValue();
if (t < ot) {
// Largest first
return 1;
} else if (t > ot) {
return -1;
} else {
return 0;
}
}
// Side effects: sets mName and mUniqueName
void getNameForUid(int uid) {
PackageManager pm = getPackageManager();
mPackages = pm.getPackagesForUid(uid);
if (mPackages == null) {
mName = Integer.toString(uid);
mNamePackage = null;
return;
}
mPackageNames = new String[mPackages.length];
System.arraycopy(mPackages, 0, mPackageNames, 0, mPackages.length);
// Convert package names to user-facing labels where possible
for (int i = 0; i < mPackageNames.length; i++) {
mPackageNames[i] = BatteryHistory.getLabel(mPackageNames[i], pm);
}
if (mPackageNames.length == 1) {
mNamePackage = mPackages[0];
mName = mPackageNames[0];
mUniqueName = true;
} else {
mName = getString(R.string.battery_history_uid, uid); // Default name
// Look for an official name for this UID.
for (String name : mPackages) {
try {
PackageInfo pi = pm.getPackageInfo(name, 0);
if (pi.sharedUserLabel != 0) {
CharSequence nm = pm.getText(name,
pi.sharedUserLabel, pi.applicationInfo);
if (nm != null) {
mName = nm.toString();
break;
}
}
} catch (PackageManager.NameNotFoundException e) {
}
}
}
}
}
class CpuUsage extends Graphable {
String mProcess;
double[] mUsage;
double mTotalRuntime;
long mStarts;
public CpuUsage(int uid, String process, long userTime, long systemTime,
long starts, long totalRuntime) {
getNameForUid(uid);
mProcess = process;
PackageManager pm = BatteryHistory.this.getPackageManager();
mName = BatteryHistory.getLabel(process, pm);
mUsage = new double[2];
mUsage[0] = userTime;
mUsage[1] = userTime + systemTime;
mTotalRuntime = totalRuntime;
mStarts = starts;
}
public String getLabel() {
return mName;
}
public double getSortValue() {
return mUsage[1];
}
public double[] getValues() {
return mUsage;
}
public double getMaxValue() {
return mTotalRuntime;
}
public void getInfo(StringBuilder info) {
info.append(getString(R.string.battery_history_cpu_usage, mProcess));
info.append("\n\n");
info.append(getString(R.string.battery_history_user_time));
formatTime(mUsage[0] * 10, info);
info.append('\n');
info.append(getString(R.string.battery_history_system_time));
formatTime((mUsage[1] - mUsage[0]) * 10, info);
info.append('\n');
info.append(getString(R.string.battery_history_total_time));
formatTime((mUsage[1]) * 10, info);
info.append('\n');
info.append(getString(R.string.battery_history_starts, mStarts));
}
}
class NetworkUsage extends Graphable {
double[] mUsage;
public NetworkUsage(int uid, long received, long sent) {
getNameForUid(uid);
mUsage = new double[2];
mUsage[0] = received;
mUsage[1] = received + sent;
}
public String getLabel() {
return mName;
}
public double getSortValue() {
return mUsage[1];
}
public double[] getValues() {
return mUsage;
}
public void getInfo(StringBuilder info) {
info.append(getString(R.string.battery_history_network_usage, mName));
info.append("\n\n");
info.append(getString(R.string.battery_history_bytes_received, (long) mUsage[0]));
info.append('\n');
info.append(getString(R.string.battery_history_bytes_sent,
(long) mUsage[1] - (long) mUsage[0]));
info.append('\n');
info.append(getString(R.string.battery_history_bytes_total, (long) mUsage[1]));
if (!mUniqueName) {
info.append("\n\n");
info.append(getString(R.string.battery_history_packages_sharing_this_uid));
info.append('\n');
PackageManager pm = BatteryHistory.this.getPackageManager();
List<String> names = new ArrayList<String>();
for (String name : mPackageNames) {
names.add(BatteryHistory.getLabel(name, pm));
}
Collections.sort(names);
for (String name : names) {
info.append(" ");
info.append(name);
info.append('\n');
}
}
}
}
class SensorUsage extends Graphable {
double[] mUsage;
double mTotalRealtime;
int mCount;
public SensorUsage(int uid, long time, int count, long totalRealtime) {
getNameForUid(uid);
mUsage = new double[1];
mUsage[0] = time;
mTotalRealtime = totalRealtime;
mCount = count;
}
public String getLabel() {
return mName;
}
public double getSortValue() {
return mUsage[0];
}
public double[] getValues() {
return mUsage;
}
public double getMaxValue() {
return mTotalRealtime;
}
public void getInfo(StringBuilder info) {
info.append(getString(R.string.battery_history_sensor));
info.append(mName);
info.append("\n\n");
info.append(getString(R.string.battery_history_total_time));
formatTime(mUsage[0], info);
info.append("\n\n");
}
}
class WakelockUsage extends Graphable {
double[] mUsage;
double mTotalRealtime;
int mCount;
public WakelockUsage(int uid, long time, int count, long totalRealtime) {
getNameForUid(uid);
mUsage = new double[1];
mUsage[0] = time;
mTotalRealtime = totalRealtime;
mCount = count;
}
public String getLabel() {
return mName;
}
public double getSortValue() {
return mUsage[0];
}
public double[] getValues() {
return mUsage;
}
public double getMaxValue() {
return mTotalRealtime;
}
public void getInfo(StringBuilder info) {
info.append(getString(R.string.battery_history_wakelock));
info.append(mName);
info.append("\n\n");
info.append(getString(R.string.battery_history_total_time));
formatTime(mUsage[0], info);
info.append("\n\n");
}
}
class MiscUsage extends Graphable {
int mInfoLabelRes;
String mInfoLabel;
double[] mUsage;
double mTotalRealtime;
public MiscUsage(String name, int infoLabelRes, long value,
long totalRealtime) {
mName = name;
mInfoLabelRes = infoLabelRes;
mUsage = new double[2];
mUsage[0] = value;
mTotalRealtime = totalRealtime;
}
public MiscUsage(String name, String infoLabel, long value,
long totalRealtime) {
mName = name;
mInfoLabel = infoLabel;
mUsage = new double[2];
mUsage[0] = value;
mTotalRealtime = totalRealtime;
}
public String getLabel() {
return mName;
}
public double getSortValue() {
return mUsage[1];
}
public double[] getValues() {
return mUsage;
}
public double getMaxValue() {
return mTotalRealtime;
}
public void getInfo(StringBuilder info) {
info.append(mInfoLabel != null ? mInfoLabel : getString(mInfoLabelRes));
info.append(' ');
formatTime(mUsage[0], info);
info.append(" (");
info.append((mUsage[0]*100)/mTotalRealtime);
info.append("%)");
}
}
private List<? extends Graphable> getGraphRecords() {
switch (mType) {
case CPU_USAGE: return mCpuUsage;
case NETWORK_USAGE : return mNetworkUsage;
case SENSOR_USAGE: return mSensorUsage;
case GPS_USAGE: return mGpsUsage;
case WAKELOCK_USAGE: return mWakelockUsage;
case MISC_USAGE: return mMiscUsage;
default:
return (List<? extends Graphable>) null; // TODO
}
}
private void displayGraph() {
Log.i(TAG, "displayGraph");
collectStatistics();
// Hide the UI and selectively enable it below
mMessageText.setVisibility(View.GONE);
for (int i = 0; i < mButtons.length; i++) {
mButtons[i].setVisibility(View.INVISIBLE);
}
double maxValue = -Double.MAX_VALUE;
List<? extends Graphable> records = getGraphRecords();
for (Graphable g : records) {
double[] values = g.getValues();
maxValue = Math.max(maxValue, values[values.length - 1]);
maxValue = Math.max(maxValue, g.getMaxValue());
}
int[] colors = new int[2];
colors[0] = 0xff0000ff;
colors[1] = 0xffff0000;
for (int i = 0; i < mButtons.length; i++) {
mButtons[i].setVisibility(View.INVISIBLE);
}
int numRecords = Math.min(records.size(), mButtons.length);
if (numRecords == 0) {
mMessageText.setVisibility(View.VISIBLE);
mMessageText.setText(R.string.battery_history_no_data);
} else {
for (int i = 0; i < numRecords; i++) {
Graphable r = records.get(i);
mButtons[i].setText(r.getLabel());
mButtons[i].setValues(r.getValues(), maxValue);
mButtons[i].setVisibility(View.VISIBLE);
}
}
}
private void hideDetails() {
mTextLayout.setVisibility(View.GONE);
mGraphLayout.setVisibility(View.VISIBLE);
mDetailsShown = false;
}
private void showDetails(int id) {
mGraphLayout.setVisibility(View.GONE);
mTextLayout.setVisibility(View.VISIBLE);
StringBuilder info = new StringBuilder();
List<? extends Graphable> records = getGraphRecords();
if (id < records.size()) {
Graphable record = records.get(id);
record.getInfo(info);
} else {
info.append(getString(R.string.battery_history_details_for, id));
}
mDetailsText.setText(info.toString());
mDetailsShown = true;
}
private void processCpuUsage() {
mCpuUsage.clear();
long uSecTime = SystemClock.uptimeMillis() * 1000;
final long uSecNow = mStats.computeBatteryUptime(uSecTime, mWhich) / 1000;
SparseArray<? extends Uid> uidStats = mStats.getUidStats();
final int NU = uidStats.size();
for (int iu = 0; iu < NU; iu++) {
Uid u = uidStats.valueAt(iu);
Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
if (processStats.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
: processStats.entrySet()) {
Uid.Proc ps = ent.getValue();
long userTime = ps.getUserTime(mWhich);
long systemTime = ps.getSystemTime(mWhich);
long starts = ps.getStarts(mWhich);
if (userTime != 0 || systemTime != 0) {
mCpuUsage.add(new CpuUsage(u.getUid(), ent.getKey(),
userTime, systemTime, starts, uSecNow));
}
}
}
}
Collections.sort(mCpuUsage);
}
private void processNetworkUsage() {
mNetworkUsage.clear();
SparseArray<? extends Uid> uidStats = mStats.getUidStats();
final int NU = uidStats.size();
for (int iu = 0; iu < NU; iu++) {
Uid u = uidStats.valueAt(iu);
long received = u.getTcpBytesReceived(mWhich);
long sent = u.getTcpBytesSent(mWhich);
if (received + sent > 0) {
mNetworkUsage.add(new NetworkUsage(u.getUid(), received, sent));
}
}
Collections.sort(mNetworkUsage);
}
private void processSensorUsage() {
mGpsUsage.clear();
mSensorUsage.clear();
long uSecTime = SystemClock.elapsedRealtime() * 1000;
final long uSecNow = mStats.computeBatteryRealtime(uSecTime, mWhich) / 1000;
SparseArray<? extends Uid> uidStats = mStats.getUidStats();
final int NU = uidStats.size();
for (int iu = 0; iu < NU; iu++) {
Uid u = uidStats.valueAt(iu);
int uid = u.getUid();
Map<Integer, ? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
long timeGps = 0;
int countGps = 0;
long timeOther = 0;
int countOther = 0;
if (sensorStats.size() > 0) {
for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
: sensorStats.entrySet()) {
Uid.Sensor se = ent.getValue();
int handle = se.getHandle();
Timer timer = se.getSensorTime();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
long totalTime = (timer.getTotalTimeLocked(uSecNow, mWhich) + 500) / 1000;
int count = timer.getCountLocked(mWhich);
if (handle == BatteryStats.Uid.Sensor.GPS) {
timeGps += totalTime;
countGps += count;
} else {
timeOther += totalTime;
countOther += count;
}
}
}
}
if (timeGps > 0) {
mGpsUsage.add(new SensorUsage(uid, timeGps, countGps, uSecNow));
}
if (timeOther > 0) {
mSensorUsage.add(new SensorUsage(uid, timeOther, countOther, uSecNow));
}
}
Collections.sort(mGpsUsage);
Collections.sort(mSensorUsage);
}
private void processWakelockUsage() {
mWakelockUsage.clear();
long uSecTime = SystemClock.elapsedRealtime() * 1000;
final long uSecNow = mStats.computeBatteryRealtime(uSecTime, mWhich) / 1000;
SparseArray<? extends Uid> uidStats = mStats.getUidStats();
final int NU = uidStats.size();
for (int iu = 0; iu < NU; iu++) {
Uid u = uidStats.valueAt(iu);
int uid = u.getUid();
Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = u.getWakelockStats();
long time = 0;
int count = 0;
if (wakelockStats.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
: wakelockStats.entrySet()) {
Uid.Wakelock wl = ent.getValue();
Timer timer = wl.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
time += (timer.getTotalTimeLocked(uSecNow, mWhich) + 500) / 1000;
count += timer.getCountLocked(mWhich);
}
}
}
if (time > 0) {
mWakelockUsage.add(new WakelockUsage(uid, time, count, uSecNow));
}
}
Collections.sort(mWakelockUsage);
}
private final StringBuilder mFormatBuilder = new StringBuilder(8);
private final Formatter mFormatter = new Formatter(mFormatBuilder);
private final String formatRatio(long num, long den) {
if (den == 0L) {
return "---%";
}
float perc = ((float)num) / ((float)den) * 100;
mFormatBuilder.setLength(0);
mFormatter.format("%.1f%%", perc);
return mFormatBuilder.toString();
}
private void processMiscUsage() {
mMiscUsage.clear();
long rawRealtime = SystemClock.elapsedRealtime() * 1000;
final long batteryRealtime = mStats.getBatteryRealtime(rawRealtime);
final long whichRealtime = mStats.computeBatteryRealtime(rawRealtime, mWhich) / 1000;
long time = mStats.computeBatteryUptime(SystemClock.uptimeMillis() * 1000, mWhich) / 1000;
if (time > 0) {
mMiscUsage.add(new MiscUsage(getString(
R.string.battery_history_awake_label)
+ " (" + formatRatio(time, whichRealtime) + ")",
R.string.battery_history_awake,
time, whichRealtime));
}
time = mStats.getScreenOnTime(batteryRealtime, mWhich) / 1000;
if (time > 0) {
mMiscUsage.add(new MiscUsage(getString(
R.string.battery_history_screen_on_label)
+ " (" + formatRatio(time, whichRealtime) + ")",
R.string.battery_history_screen_on,
time, whichRealtime));
}
time = mStats.getPhoneOnTime(batteryRealtime, mWhich) / 1000;
if (time > 0) {
mMiscUsage.add(new MiscUsage(getString(
R.string.battery_history_phone_on_label)
+ " (" + formatRatio(time, whichRealtime) + ")",
R.string.battery_history_phone_on,
time, whichRealtime));
}
time = mStats.getWifiOnTime(batteryRealtime, mWhich) / 1000;
if (time > 0) {
mMiscUsage.add(new MiscUsage("Wifi On ("
+ formatRatio(time, whichRealtime) + ")",
"Time spent with Wifi on:",
time, whichRealtime));
}
time = mStats.getWifiRunningTime(batteryRealtime, mWhich) / 1000;
if (time > 0) {
mMiscUsage.add(new MiscUsage("Wifi Running ("
+ formatRatio(time, whichRealtime) + ")",
"Time spent with Wifi running:",
time, whichRealtime));
}
time = mStats.getBluetoothOnTime(batteryRealtime, mWhich) / 1000;
if (time > 0) {
mMiscUsage.add(new MiscUsage("Bluetooth On ("
+ formatRatio(time, whichRealtime) + ")",
"Time spent with Bluetooth on:",
time, whichRealtime));
}
Collections.sort(mMiscUsage);
}
private void collectStatistics() {
if (mType == CPU_USAGE) {
if (!mHaveCpuUsage) {
mHaveCpuUsage = true;
processCpuUsage();
}
}
if (mType == NETWORK_USAGE) {
if (!mHaveNetworkUsage) {
mHaveNetworkUsage = true;
processNetworkUsage();
}
}
if (mType == GPS_USAGE || mType == SENSOR_USAGE) {
if (!mHaveSensorUsage) {
mHaveSensorUsage = true;
processSensorUsage();
}
}
if (mType == WAKELOCK_USAGE) {
if (!mHaveWakelockUsage) {
mHaveWakelockUsage = true;
processWakelockUsage();
}
}
if (mType == MISC_USAGE) {
if (!mHaveMiscUsage) {
mHaveMiscUsage = true;
processMiscUsage();
}
}
}
private void load() {
try {
byte[] data = mBatteryInfo.getStatistics();
Parcel parcel = Parcel.obtain();
//Log.i(TAG, "Got data: " + data.length + " bytes");
parcel.unmarshall(data, 0, data.length);
parcel.setDataPosition(0);
mStats = com.android.internal.os.BatteryStatsImpl.CREATOR
.createFromParcel(parcel);
//Log.i(TAG, "RECEIVED BATTERY INFO:");
//mStats.dumpLocked(new LogPrinter(Log.INFO, TAG));
mHaveCpuUsage = mHaveNetworkUsage = mHaveSensorUsage
= mHaveWakelockUsage = mHaveMiscUsage = false;
} catch (RemoteException e) {
Log.e(TAG, "RemoteException:", e);
}
}
public void onClick(View v) {
if (v == mDetailsBackButton) {
hideDetails();
return;
}
int id = ((Integer) v.getTag()).intValue();
showDetails(id);
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && mDetailsShown) {
hideDetails();
return true;
}
return super.onKeyDown(keyCode, event);
}
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
int oldWhich = mWhich;
if (parent.equals(mTypeSpinner)) {
mType = position;
} else if (parent.equals(mWhichSpinner)) {
switch (position) {
case UNPLUGGED:
mWhich = BatteryStats.STATS_UNPLUGGED;
break;
case CURRENT:
mWhich = BatteryStats.STATS_CURRENT;
break;
case TOTAL:
mWhich = BatteryStats.STATS_TOTAL;
break;
}
}
if (oldWhich != mWhich) {
mHaveCpuUsage = mHaveNetworkUsage = mHaveSensorUsage
= mHaveWakelockUsage = mHaveMiscUsage = false;
}
displayGraph();
}
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing
}
@Override
public Object onRetainNonConfigurationInstance() {
BatteryStats stats = mStats;
mStats = null;
return stats;
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mStats != null) {
outState.putParcelable("stats", mStats);
}
outState.putInt("type", mType);
outState.putInt("which", mWhich);
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Log.i(TAG, "onCreate");
setContentView(R.layout.battery_history);
mStats = (BatteryStats)getLastNonConfigurationInstance();
if (icicle != null) {
if (mStats == null) {
mStats = (BatteryStats)icicle.getParcelable("stats");
}
mType = icicle.getInt("type");
mWhich = icicle.getInt("which");
}
mGraphLayout = (LinearLayout) findViewById(R.id.graphLayout);
mTextLayout = (LinearLayout) findViewById(R.id.textLayout);
mDetailsText = (TextView) findViewById(R.id.detailsText);
mMessageText = (TextView) findViewById(R.id.messageText);
mTypeSpinner = (Spinner) findViewById(R.id.typeSpinner);
mTypeSpinner.setSelection(mType);
mTypeSpinner.setOnItemSelectedListener(this);
mWhichSpinner = (Spinner) findViewById(R.id.whichSpinner);
mWhichSpinner.setOnItemSelectedListener(this);
mWhichSpinner.setEnabled(true);
mButtons = new GraphableButton[8];
mButtons[0] = (GraphableButton) findViewById(R.id.button0);
mButtons[1] = (GraphableButton) findViewById(R.id.button1);
mButtons[2] = (GraphableButton) findViewById(R.id.button2);
mButtons[3] = (GraphableButton) findViewById(R.id.button3);
mButtons[4] = (GraphableButton) findViewById(R.id.button4);
mButtons[5] = (GraphableButton) findViewById(R.id.button5);
mButtons[6] = (GraphableButton) findViewById(R.id.button6);
mButtons[7] = (GraphableButton) findViewById(R.id.button7);
for (int i = 0; i < mButtons.length; i++) {
mButtons[i].setTag(i);
mButtons[i].setOnClickListener(this);
}
mBatteryInfo = IBatteryStats.Stub.asInterface(
ServiceManager.getService("batteryinfo"));
if (mStats == null) {
load();
}
displayGraph();
}
}

View File

@@ -1,55 +0,0 @@
package com.android.settings.battery_history;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Button;
public class GraphableButton extends Button {
private static final String TAG = "GraphableButton";
static Paint[] sPaint = new Paint[2];
static {
sPaint[0] = new Paint();
sPaint[0].setStyle(Paint.Style.FILL);
sPaint[0].setColor(0xFF0080FF);
sPaint[1] = new Paint();
sPaint[1].setStyle(Paint.Style.FILL);
sPaint[1].setColor(0xFFFF6060);
}
double[] mValues;
public GraphableButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setValues(double[] values, double maxValue) {
mValues = values.clone();
for (int i = 0; i < values.length; i++) {
mValues[i] /= maxValue;
}
}
@Override
public void onDraw(Canvas canvas) {
Log.i(TAG, "onDraw: w = " + getWidth() + ", h = " + getHeight());
int xmin = getPaddingLeft();
int xmax = getWidth() - getPaddingRight();
int ymin = getPaddingTop();
int ymax = getHeight() - getPaddingBottom();
int startx = xmin;
for (int i = 0; i < mValues.length; i++) {
int endx = xmin + (int) (mValues[i] * (xmax - xmin));
canvas.drawRect(startx, ymin, endx, ymax, sPaint[i]);
startx = endx;
}
super.onDraw(canvas);
}
}

View File

@@ -0,0 +1,275 @@
/*
* Copyright (C) 2010 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 com.android.settings.R;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.BatteryStats;
import android.os.SystemClock;
import android.os.BatteryStats.BatteryHistoryRecord;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
public class BatteryHistoryChart extends View {
private static final int SANS = 1;
private static final int SERIF = 2;
private static final int MONOSPACE = 3;
final Paint mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
final TextPaint mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
int mFontSize;
BatteryStats mStats;
long mStatsPeriod;
String mDurationString;
int mTextAscent;
int mTextDescent;
int mDurationStringWidth;
int mNumHist;
long mHistStart;
long mHistEnd;
int mBatLow;
int mBatHigh;
public BatteryHistoryChart(Context context, AttributeSet attrs) {
super(context, attrs);
mBatteryPaint.setARGB(255, 255, 128, 128);
mTextPaint.density = getResources().getDisplayMetrics().density;
mTextPaint.setCompatibilityScaling(
getResources().getCompatibilityInfo().applicationScale);
TypedArray a =
context.obtainStyledAttributes(
attrs, R.styleable.BatteryHistoryChart, 0, 0);
ColorStateList textColor = null;
int textSize = 15;
int typefaceIndex = -1;
int styleIndex = -1;
TypedArray appearance = null;
int ap = a.getResourceId(R.styleable.BatteryHistoryChart_android_textAppearance, -1);
if (ap != -1) {
appearance = context.obtainStyledAttributes(ap,
com.android.internal.R.styleable.
TextAppearance);
}
if (appearance != null) {
int n = appearance.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = appearance.getIndex(i);
switch (attr) {
case com.android.internal.R.styleable.TextAppearance_textColor:
textColor = appearance.getColorStateList(attr);
break;
case com.android.internal.R.styleable.TextAppearance_textSize:
textSize = appearance.getDimensionPixelSize(attr, textSize);
break;
case com.android.internal.R.styleable.TextAppearance_typeface:
typefaceIndex = appearance.getInt(attr, -1);
break;
case com.android.internal.R.styleable.TextAppearance_textStyle:
styleIndex = appearance.getInt(attr, -1);
break;
}
}
appearance.recycle();
}
int shadowcolor = 0;
float dx=0, dy=0, r=0;
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.BatteryHistoryChart_android_shadowColor:
shadowcolor = a.getInt(attr, 0);
break;
case R.styleable.BatteryHistoryChart_android_shadowDx:
dx = a.getFloat(attr, 0);
break;
case R.styleable.BatteryHistoryChart_android_shadowDy:
dy = a.getFloat(attr, 0);
break;
case R.styleable.BatteryHistoryChart_android_shadowRadius:
r = a.getFloat(attr, 0);
break;
case R.styleable.BatteryHistoryChart_android_textColor:
textColor = a.getColorStateList(attr);
break;
case R.styleable.BatteryHistoryChart_android_textSize:
textSize = a.getDimensionPixelSize(attr, textSize);
break;
case R.styleable.BatteryHistoryChart_android_typeface:
typefaceIndex = a.getInt(attr, typefaceIndex);
break;
case R.styleable.BatteryHistoryChart_android_textStyle:
styleIndex = a.getInt(attr, styleIndex);
break;
}
}
mTextPaint.setColor(textColor.getDefaultColor());
mTextPaint.setTextSize(textSize);
Typeface tf = null;
switch (typefaceIndex) {
case SANS:
tf = Typeface.SANS_SERIF;
break;
case SERIF:
tf = Typeface.SERIF;
break;
case MONOSPACE:
tf = Typeface.MONOSPACE;
break;
}
setTypeface(tf, styleIndex);
if (shadowcolor != 0) {
mTextPaint.setShadowLayer(r, dx, dy, shadowcolor);
}
}
public void setTypeface(Typeface tf, int style) {
if (style > 0) {
if (tf == null) {
tf = Typeface.defaultFromStyle(style);
} else {
tf = Typeface.create(tf, style);
}
mTextPaint.setTypeface(tf);
// now compute what (if any) algorithmic styling is needed
int typefaceStyle = tf != null ? tf.getStyle() : 0;
int need = style & ~typefaceStyle;
mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
} else {
mTextPaint.setFakeBoldText(false);
mTextPaint.setTextSkewX(0);
mTextPaint.setTypeface(tf);
}
}
void setStats(BatteryStats stats) {
mStats = stats;
long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000,
BatteryStats.STATS_UNPLUGGED);
mStatsPeriod = uSecTime;
String durationString = Utils.formatElapsedTime(getContext(), mStatsPeriod / 1000);
mDurationString = getContext().getString(R.string.battery_stats_on_battery,
durationString);
BatteryStats.BatteryHistoryRecord rec = stats.getHistory();
if (rec != null) {
mHistStart = rec.time;
mBatLow = mBatHigh = rec.batteryLevel;
}
int pos = 0;
int lastUnplugged = 0;
mBatLow = 0;
mBatHigh = 100;
while (rec != null) {
pos++;
if ((rec.states&BatteryHistoryRecord.STATE_BATTERY_PLUGGED_FLAG) == 0) {
lastUnplugged = pos;
mHistEnd = rec.time;
}
rec = rec.next;
}
mNumHist = lastUnplugged;
if (mHistEnd <= mHistStart) mHistEnd = mHistStart+1;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mDurationStringWidth = (int)mTextPaint.measureText(mDurationString);
mTextAscent = (int)mTextPaint.ascent();
mTextDescent = (int)mTextPaint.descent();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int width = getWidth();
final int height = getHeight();
final long timeStart = mHistStart;
final long timeChange = mHistEnd-mHistStart;
final int batLow = mBatLow;
final int batChange = mBatHigh-mBatLow;
BatteryStats.BatteryHistoryRecord rec = mStats.getHistory();
int lastX=-1, lastY=-1;
int pos = 0;
final int N = mNumHist;
while (rec != null && pos < N) {
int x = (int)(((rec.time-timeStart)*width)/timeChange);
int y = height-1 - ((rec.batteryLevel-batLow)*height)/batChange;
if (lastX >= 0) {
canvas.drawLine(lastX, lastY, x, y, mBatteryPaint);
}
lastX = x;
lastY = y;
rec = rec.next;
pos++;
}
canvas.drawText(mDurationString, (width/2) - (mDurationStringWidth/2),
(height/2) - ((mTextDescent-mTextAscent)/2) - mTextAscent, mTextPaint);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.BatteryStats;
import android.preference.Preference;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.settings.R;
/**
* Custom preference for displaying power consumption as a bar and an icon on the left for the
* subsystem/app type.
*
*/
public class BatteryHistoryPreference extends Preference {
private BatteryStats mStats;
public BatteryHistoryPreference(Context context, BatteryStats stats) {
super(context);
setLayoutResource(R.layout.preference_batteryhistory);
mStats = stats;
}
BatteryStats getStats() {
return mStats;
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
BatteryHistoryChart chart = (BatteryHistoryChart)view.findViewById(
R.id.battery_history_chart);
chart.setStats(mStats);
}
}

View File

@@ -0,0 +1,196 @@
/*
* 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.
*/
package com.android.settings.fuelgauge;
import com.android.settings.R;
import com.android.settings.fuelgauge.PowerUsageDetail.DrainType;
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.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.BatteryStats.Uid;
import java.util.ArrayList;
import java.util.HashMap;
class BatterySipper implements Comparable<BatterySipper> {
final Context mContext;
final HashMap<String,UidToDetail> mUidCache = 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 cpuFgTime;
double percent;
double noCoveragePercent;
String defaultPackageName;
static class UidToDetail {
String name;
String packageName;
Drawable icon;
}
BatterySipper(Context context, ArrayList<BatterySipper> requestQueue,
Handler handler, String label, DrainType drainType,
int iconId, Uid uid, double[] values) {
mContext = context;
mRequestQueue = requestQueue;
mHandler = handler;
this.values = values;
name = label;
this.drainType = drainType;
if (iconId > 0) {
icon = mContext.getResources().getDrawable(iconId);
}
if (values != null) value = values[0];
if ((label == null || iconId == 0) && uid != null) {
getQuickNameIconForUid(uid);
}
uidObj = uid;
}
double getSortValue() {
return value;
}
double[] getValues() {
return values;
}
Drawable getIcon() {
return icon;
}
public int compareTo(BatterySipper other) {
// Return the flipped value because we want the items in descending order
return (int) (other.getSortValue() - getSortValue());
}
void getQuickNameIconForUid(Uid uidObj) {
final int uid = uidObj.getUid();
final String uidString = Integer.toString(uid);
if (mUidCache.containsKey(uidString)) {
UidToDetail utd = mUidCache.get(uidString);
defaultPackageName = utd.packageName;
name = utd.name;
icon = utd.icon;
return;
}
PackageManager pm = mContext.getPackageManager();
final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
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);
} else if ("mediaserver".equals(name)) {
name = mContext.getResources().getString(R.string.process_mediaserver_label);
}
iconId = R.drawable.ic_power_system;
icon = mContext.getResources().getDrawable(iconId);
return;
} else {
//name = packages[0];
}
synchronized (mRequestQueue) {
mRequestQueue.add(this);
}
}
/**
* Sets name and icon
* @param uid Uid of the application
*/
void getNameIcon() {
PackageManager pm = mContext.getPackageManager();
final int uid = uidObj.getUid();
final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
String[] packages = pm.getPackagesForUid(uid);
if (packages == null) {
name = Integer.toString(uid);
return;
}
String[] packageLabels = new String[packages.length];
System.arraycopy(packages, 0, packageLabels, 0, packages.length);
int preferredIndex = -1;
// Convert package names to user-facing labels where possible
for (int i = 0; i < packageLabels.length; i++) {
// Check if package matches preferred package
if (packageLabels[i].equals(name)) preferredIndex = i;
try {
ApplicationInfo ai = pm.getApplicationInfo(packageLabels[i], 0);
CharSequence label = ai.loadLabel(pm);
if (label != null) {
packageLabels[i] = label.toString();
}
if (ai.icon != 0) {
defaultPackageName = packages[i];
icon = ai.loadIcon(pm);
break;
}
} catch (NameNotFoundException e) {
}
}
if (icon == null) icon = defaultActivityIcon;
if (packageLabels.length == 1) {
name = packageLabels[0];
} else {
// Look for an official name for this UID.
for (String pkgName : packages) {
try {
final PackageInfo pi = pm.getPackageInfo(pkgName, 0);
if (pi.sharedUserLabel != 0) {
final CharSequence nm = pm.getText(pkgName,
pi.sharedUserLabel, pi.applicationInfo);
if (nm != null) {
name = nm.toString();
if (pi.applicationInfo.icon != 0) {
defaultPackageName = pkgName;
icon = pi.applicationInfo.loadIcon(pm);
}
break;
}
}
} catch (PackageManager.NameNotFoundException e) {
}
}
}
final String uidString = Integer.toString(uidObj.getUid());
UidToDetail utd = new UidToDetail();
utd.name = name;
utd.icon = icon;
utd.packageName = defaultPackageName;
mUidCache.put(uidString, utd);
mHandler.sendMessage(mHandler.obtainMessage(PowerUsageSummary.MSG_UPDATE_NAME_ICON, this));
}
}

View File

@@ -17,9 +17,6 @@
package com.android.settings.fuelgauge;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.preference.Preference;
import android.view.View;
@@ -27,7 +24,6 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.fuelgauge.PowerUsageSummary.BatterySipper;
/**
* Custom preference for displaying power consumption as a bar and an icon on the left for the

View File

@@ -18,10 +18,6 @@ package com.android.settings.fuelgauge;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import android.hardware.SensorManager;
import android.os.BatteryStats;
@@ -53,7 +49,6 @@ import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -86,19 +81,11 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
private double mTotalPower;
private PowerProfile mPowerProfile;
private HashMap<String,UidToDetail> mUidCache = new HashMap<String,UidToDetail>();
/** Queue for fetching name and icon for an application */
private ArrayList<BatterySipper> mRequestQueue = new ArrayList<BatterySipper>();
private Thread mRequestThread;
private boolean mAbort;
static class UidToDetail {
String name;
String packageName;
Drawable icon;
}
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -267,6 +254,10 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
mAppListGroup.setOrderingAsAdded(false);
BatteryHistoryPreference hist = new BatteryHistoryPreference(this, mStats);
hist.setOrder(-1);
mAppListGroup.addPreference(hist);
Collections.sort(mUsageList);
for (BatterySipper sipper : mUsageList) {
if (sipper.getSortValue() < MIN_POWER_THRESHOLD) continue;
@@ -283,7 +274,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
pref.setKey(Integer.toString(sipper.uidObj.getUid()));
}
mAppListGroup.addPreference(pref);
if (mAppListGroup.getPreferenceCount() > MAX_ITEMS_TO_LIST) break;
if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) break;
}
if (DEBUG) setTitle("Battery total uAh = " + ((mTotalPower * 1000) / 3600));
synchronized (mRequestQueue) {
@@ -408,7 +399,8 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
// Add the app to the list if it is consuming power
if (power != 0) {
BatterySipper app = new BatterySipper(packageWithHighestDrain, DrainType.APP, 0, u,
BatterySipper app = new BatterySipper(this, mRequestQueue, mHandler,
packageWithHighestDrain, DrainType.APP, 0, u,
new double[] {power});
app.cpuTime = cpuTime;
app.gpsTime = gpsTime;
@@ -549,7 +541,8 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
double power) {
if (power > mMaxPower) mMaxPower = power;
mTotalPower += power;
BatterySipper bs = new BatterySipper(label, drainType, iconId, null, new double[] {power});
BatterySipper bs = new BatterySipper(this, mRequestQueue, mHandler,
label, drainType, iconId, null, new double[] {power});
bs.usageTime = time;
bs.iconId = iconId;
mUsageList.add(bs);
@@ -569,156 +562,6 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
}
}
class BatterySipper implements Comparable<BatterySipper> {
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 cpuFgTime;
double percent;
double noCoveragePercent;
String defaultPackageName;
BatterySipper(String label, DrainType drainType, int iconId, Uid uid, double[] values) {
this.values = values;
name = label;
this.drainType = drainType;
if (iconId > 0) {
icon = getResources().getDrawable(iconId);
}
if (values != null) value = values[0];
if ((label == null || iconId == 0) && uid != null) {
getQuickNameIconForUid(uid);
}
uidObj = uid;
}
double getSortValue() {
return value;
}
double[] getValues() {
return values;
}
Drawable getIcon() {
return icon;
}
public int compareTo(BatterySipper other) {
// Return the flipped value because we want the items in descending order
return (int) (other.getSortValue() - getSortValue());
}
void getQuickNameIconForUid(Uid uidObj) {
final int uid = uidObj.getUid();
final String uidString = Integer.toString(uid);
if (mUidCache.containsKey(uidString)) {
UidToDetail utd = mUidCache.get(uidString);
defaultPackageName = utd.packageName;
name = utd.name;
icon = utd.icon;
return;
}
PackageManager pm = getPackageManager();
final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
String[] packages = pm.getPackagesForUid(uid);
icon = pm.getDefaultActivityIcon();
if (packages == null) {
//name = Integer.toString(uid);
if (uid == 0) {
name = getResources().getString(R.string.process_kernel_label);
} else if ("mediaserver".equals(name)) {
name = getResources().getString(R.string.process_mediaserver_label);
}
iconId = R.drawable.ic_power_system;
icon = getResources().getDrawable(iconId);
return;
} else {
//name = packages[0];
}
synchronized (mRequestQueue) {
mRequestQueue.add(this);
}
}
/**
* Sets name and icon
* @param uid Uid of the application
*/
void getNameIcon() {
PackageManager pm = getPackageManager();
final int uid = uidObj.getUid();
final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
String[] packages = pm.getPackagesForUid(uid);
if (packages == null) {
name = Integer.toString(uid);
return;
}
String[] packageLabels = new String[packages.length];
System.arraycopy(packages, 0, packageLabels, 0, packages.length);
int preferredIndex = -1;
// Convert package names to user-facing labels where possible
for (int i = 0; i < packageLabels.length; i++) {
// Check if package matches preferred package
if (packageLabels[i].equals(name)) preferredIndex = i;
try {
ApplicationInfo ai = pm.getApplicationInfo(packageLabels[i], 0);
CharSequence label = ai.loadLabel(pm);
if (label != null) {
packageLabels[i] = label.toString();
}
if (ai.icon != 0) {
defaultPackageName = packages[i];
icon = ai.loadIcon(pm);
break;
}
} catch (NameNotFoundException e) {
}
}
if (icon == null) icon = defaultActivityIcon;
if (packageLabels.length == 1) {
name = packageLabels[0];
} else {
// Look for an official name for this UID.
for (String pkgName : packages) {
try {
final PackageInfo pi = pm.getPackageInfo(pkgName, 0);
if (pi.sharedUserLabel != 0) {
final CharSequence nm = pm.getText(pkgName,
pi.sharedUserLabel, pi.applicationInfo);
if (nm != null) {
name = nm.toString();
if (pi.applicationInfo.icon != 0) {
defaultPackageName = pkgName;
icon = pi.applicationInfo.loadIcon(pm);
}
break;
}
}
} catch (PackageManager.NameNotFoundException e) {
}
}
}
final String uidString = Integer.toString(uidObj.getUid());
UidToDetail utd = new UidToDetail();
utd.name = name;
utd.icon = icon;
utd.packageName = defaultPackageName;
mUidCache.put(uidString, utd);
mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_NAME_ICON, this));
}
}
public void run() {
while (true) {
BatterySipper bs;
@@ -733,7 +576,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
}
}
private static final int MSG_UPDATE_NAME_ICON = 1;
static final int MSG_UPDATE_NAME_ICON = 1;
Handler mHandler = new Handler() {