am ea38e678
: Show history of battery level.
Merge commit 'ea38e678537cf740b5f30c1d69c7a332e98cdd2c' * commit 'ea38e678537cf740b5f30c1d69c7a332e98cdd2c': Show history of battery level.
This commit is contained in:
@@ -712,13 +712,6 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</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"
|
<activity android:name="Display" android:label="@string/display_label"
|
||||||
android:configChanges="fontScale">
|
android:configChanges="fontScale">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@@ -788,6 +781,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".fuelgauge.PowerUsageSummary"
|
<activity android:name=".fuelgauge.PowerUsageSummary"
|
||||||
|
android:theme="@android:style/Theme.NoTitleBar"
|
||||||
android:label="@string/power_usage_summary_title"
|
android:label="@string/power_usage_summary_title"
|
||||||
android:clearTaskOnLaunch="true"
|
android:clearTaskOnLaunch="true"
|
||||||
>
|
>
|
||||||
|
@@ -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>
|
|
30
res/layout/preference_batteryhistory.xml
Normal file
30
res/layout/preference_batteryhistory.xml
Normal 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>
|
@@ -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>
|
|
@@ -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>
|
|
@@ -285,23 +285,6 @@
|
|||||||
<item>2</item>
|
<item>2</item>
|
||||||
</string-array>
|
</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 -->
|
<!-- Display options for UsageStats class -->
|
||||||
<string-array name="usage_stats_display_order_types">
|
<string-array name="usage_stats_display_order_types">
|
||||||
<item>Usage Time</item>
|
<item>Usage Time</item>
|
||||||
|
@@ -21,4 +21,25 @@
|
|||||||
<declare-styleable name="IconPreferenceScreen">
|
<declare-styleable name="IconPreferenceScreen">
|
||||||
<attr name="icon" format="reference" />
|
<attr name="icon" format="reference" />
|
||||||
</declare-styleable>
|
</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>
|
</resources>
|
||||||
|
@@ -429,8 +429,6 @@
|
|||||||
<string name="device_info_label">Device info</string>
|
<string name="device_info_label">Device info</string>
|
||||||
<!-- The title of the activity to see battery info. -->
|
<!-- The title of the activity to see battery info. -->
|
||||||
<string name="battery_info_label">Battery info</string>
|
<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 -->
|
<!-- The title of the activity to adjust display settings -->
|
||||||
<string name="display_label">Display</string>
|
<string name="display_label">Display</string>
|
||||||
<!-- The title of the activity to see phone info -->
|
<!-- The title of the activity to see phone info -->
|
||||||
@@ -1792,19 +1790,6 @@ found in the list of installed applications.</string>
|
|||||||
<string name="runningservices_settings_summary">View and control currently running services</string>
|
<string name="runningservices_settings_summary">View and control currently running services</string>
|
||||||
<!-- Label for a service item when it is restarting -->
|
<!-- Label for a service item when it is restarting -->
|
||||||
<string name="service_restarting">Restarting</string>
|
<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 -->
|
<!-- Running services, description for a service in the started state -->
|
||||||
<string name="service_started_by_app">Started by application.</string>
|
<string name="service_started_by_app">Started by application.</string>
|
||||||
<!-- Running services, description for a service in the started state -->
|
<!-- Running services, description for a service in the started state -->
|
||||||
@@ -1839,13 +1824,13 @@ found in the list of installed applications.</string>
|
|||||||
<!-- Running service details, stop a service that has started itself. -->
|
<!-- Running service details, stop a service that has started itself. -->
|
||||||
<string name="service_stop">Stop</string>
|
<string name="service_stop">Stop</string>
|
||||||
<!-- Running service details, manage a service that is running for some other reason. -->
|
<!-- 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. -->
|
<!-- Running service details, default description for services that are started. -->
|
||||||
<string name="service_stop_description">This service was started by its
|
<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. -->
|
<!-- Running service details, default description for services that are managed. -->
|
||||||
<string name="service_manage_description"><xliff:g id="client_name">%1$s</xliff:g>:
|
<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. -->
|
<!-- Description of the main process in the details. -->
|
||||||
<string name="main_running_process_description">Main process that is in use.</string>
|
<string name="main_running_process_description">Main process that is in use.</string>
|
||||||
<!-- Message that a process's service is in use. -->
|
<!-- Message that a process's service is in use. -->
|
||||||
@@ -1995,39 +1980,6 @@ found in the list of installed applications.</string>
|
|||||||
the final name for Gadgets/Widgets, so please translate both for now. -->
|
the final name for Gadgets/Widgets, so please translate both for now. -->
|
||||||
<string name="widget_picker_title">Choose widget</string>
|
<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 -->
|
<!-- 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>
|
<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>
|
||||||
|
|
||||||
@@ -2039,52 +1991,7 @@ found in the list of installed applications.</string>
|
|||||||
|
|
||||||
<!-- Used to show an amount of time in the form "s seconds" in BatteryHistory -->
|
<!-- 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>
|
<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 -->
|
<!-- XXX remove? Strings used for displaying usage statistics -->
|
||||||
<string name="usage_stats_label">Usage statistics</string>
|
<string name="usage_stats_label">Usage statistics</string>
|
||||||
|
|
||||||
@@ -2151,6 +2058,8 @@ found in the list of installed applications.</string>
|
|||||||
<string name="battery_since_unplugged">Battery use since unplugged</string>
|
<string name="battery_since_unplugged">Battery use since unplugged</string>
|
||||||
<!-- Battery usage since user reset the stats -->
|
<!-- Battery usage since user reset the stats -->
|
||||||
<string name="battery_since_reset">Battery use since reset</string>
|
<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 -->
|
<!-- Battery usage duration -->
|
||||||
<string name="battery_stats_duration"><xliff:g id="time">%1$s</xliff:g> since unplugged</string>
|
<string name="battery_stats_duration"><xliff:g id="time">%1$s</xliff:g> since unplugged</string>
|
||||||
<!-- Battery usage during last unplugged period -->
|
<!-- Battery usage during last unplugged period -->
|
||||||
|
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -418,7 +418,7 @@ public class RunningState {
|
|||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
|
|
||||||
List<ActivityManager.RunningServiceInfo> services
|
List<ActivityManager.RunningServiceInfo> services
|
||||||
= am.getRunningServices(RunningServices.MAX_SERVICES);
|
= am.getRunningServices(RunningProcessesView.MAX_SERVICES);
|
||||||
final int NS = services != null ? services.size() : 0;
|
final int NS = services != null ? services.size() : 0;
|
||||||
for (int i=0; i<NS; i++) {
|
for (int i=0; i<NS; i++) {
|
||||||
ActivityManager.RunningServiceInfo si = services.get(i);
|
ActivityManager.RunningServiceInfo si = services.get(i);
|
||||||
@@ -671,7 +671,7 @@ public class RunningState {
|
|||||||
numForegroundProcesses++;
|
numForegroundProcesses++;
|
||||||
mAllProcessItems.add(proc);
|
mAllProcessItems.add(proc);
|
||||||
} else {
|
} else {
|
||||||
Log.i(RunningServices.TAG, "Unknown non-service process: "
|
Log.i("RunningState", "Unknown non-service process: "
|
||||||
+ proc.mProcessName + " #" + proc.mPid);
|
+ proc.mProcessName + " #" + proc.mPid);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
275
src/com/android/settings/fuelgauge/BatteryHistoryChart.java
Normal file
275
src/com/android/settings/fuelgauge/BatteryHistoryChart.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
196
src/com/android/settings/fuelgauge/BatterySipper.java
Normal file
196
src/com/android/settings/fuelgauge/BatterySipper.java
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
@@ -17,9 +17,6 @@
|
|||||||
package com.android.settings.fuelgauge;
|
package com.android.settings.fuelgauge;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.ColorFilter;
|
|
||||||
import android.graphics.PixelFormat;
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -27,7 +24,6 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.android.settings.R;
|
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
|
* Custom preference for displaying power consumption as a bar and an icon on the left for the
|
||||||
|
@@ -18,10 +18,6 @@ package com.android.settings.fuelgauge;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
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.graphics.drawable.Drawable;
|
||||||
import android.hardware.SensorManager;
|
import android.hardware.SensorManager;
|
||||||
import android.os.BatteryStats;
|
import android.os.BatteryStats;
|
||||||
@@ -53,7 +49,6 @@ import java.io.StringWriter;
|
|||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -86,19 +81,11 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
|
|||||||
private double mTotalPower;
|
private double mTotalPower;
|
||||||
private PowerProfile mPowerProfile;
|
private PowerProfile mPowerProfile;
|
||||||
|
|
||||||
private HashMap<String,UidToDetail> mUidCache = new HashMap<String,UidToDetail>();
|
|
||||||
|
|
||||||
/** Queue for fetching name and icon for an application */
|
/** Queue for fetching name and icon for an application */
|
||||||
private ArrayList<BatterySipper> mRequestQueue = new ArrayList<BatterySipper>();
|
private ArrayList<BatterySipper> mRequestQueue = new ArrayList<BatterySipper>();
|
||||||
private Thread mRequestThread;
|
private Thread mRequestThread;
|
||||||
private boolean mAbort;
|
private boolean mAbort;
|
||||||
|
|
||||||
static class UidToDetail {
|
|
||||||
String name;
|
|
||||||
String packageName;
|
|
||||||
Drawable icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle icicle) {
|
protected void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
@@ -267,6 +254,10 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
|
|||||||
|
|
||||||
mAppListGroup.setOrderingAsAdded(false);
|
mAppListGroup.setOrderingAsAdded(false);
|
||||||
|
|
||||||
|
BatteryHistoryPreference hist = new BatteryHistoryPreference(this, mStats);
|
||||||
|
hist.setOrder(-1);
|
||||||
|
mAppListGroup.addPreference(hist);
|
||||||
|
|
||||||
Collections.sort(mUsageList);
|
Collections.sort(mUsageList);
|
||||||
for (BatterySipper sipper : mUsageList) {
|
for (BatterySipper sipper : mUsageList) {
|
||||||
if (sipper.getSortValue() < MIN_POWER_THRESHOLD) continue;
|
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()));
|
pref.setKey(Integer.toString(sipper.uidObj.getUid()));
|
||||||
}
|
}
|
||||||
mAppListGroup.addPreference(pref);
|
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));
|
if (DEBUG) setTitle("Battery total uAh = " + ((mTotalPower * 1000) / 3600));
|
||||||
synchronized (mRequestQueue) {
|
synchronized (mRequestQueue) {
|
||||||
@@ -408,7 +399,8 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
|
|||||||
|
|
||||||
// Add the app to the list if it is consuming power
|
// Add the app to the list if it is consuming power
|
||||||
if (power != 0) {
|
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});
|
new double[] {power});
|
||||||
app.cpuTime = cpuTime;
|
app.cpuTime = cpuTime;
|
||||||
app.gpsTime = gpsTime;
|
app.gpsTime = gpsTime;
|
||||||
@@ -549,7 +541,8 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
|
|||||||
double power) {
|
double power) {
|
||||||
if (power > mMaxPower) mMaxPower = power;
|
if (power > mMaxPower) mMaxPower = power;
|
||||||
mTotalPower += 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.usageTime = time;
|
||||||
bs.iconId = iconId;
|
bs.iconId = iconId;
|
||||||
mUsageList.add(bs);
|
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() {
|
public void run() {
|
||||||
while (true) {
|
while (true) {
|
||||||
BatterySipper bs;
|
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() {
|
Handler mHandler = new Handler() {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user