Merge "Foreground/background network stats pie chart."
This commit is contained in:
@@ -19,8 +19,13 @@
|
|||||||
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
|
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
|
||||||
android:id="@+id/chart"
|
android:id="@+id/chart"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="220dip"
|
android:layout_height="@dimen/data_usage_chart_height"
|
||||||
android:padding="16dip">
|
android:paddingLeft="@*android:dimen/preference_item_padding_side"
|
||||||
|
android:paddingRight="@*android:dimen/preference_item_padding_side"
|
||||||
|
android:paddingTop="16dip"
|
||||||
|
android:paddingBottom="16dip"
|
||||||
|
settings:optimalWidth="@dimen/data_usage_chart_optimalWidth"
|
||||||
|
settings:optimalWidthWeight="0.4">
|
||||||
|
|
||||||
<com.android.settings.widget.ChartGridView
|
<com.android.settings.widget.ChartGridView
|
||||||
android:id="@+id/grid"
|
android:id="@+id/grid"
|
||||||
@@ -48,7 +53,7 @@
|
|||||||
android:layout_gravity="left|bottom"
|
android:layout_gravity="left|bottom"
|
||||||
settings:strokeColor="#d88d3a"
|
settings:strokeColor="#d88d3a"
|
||||||
settings:fillColor="#c0ba7f3e"
|
settings:fillColor="#c0ba7f3e"
|
||||||
settings:fillColorSecondary="#0000" />
|
settings:fillColorSecondary="#60ba7f3e" />
|
||||||
|
|
||||||
<com.android.settings.widget.ChartSweepView
|
<com.android.settings.widget.ChartSweepView
|
||||||
android:id="@+id/sweep_warning"
|
android:id="@+id/sweep_warning"
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingLeft="16dip"
|
android:paddingLeft="@*android:dimen/preference_item_padding_side"
|
||||||
android:paddingRight="16dip">
|
android:paddingRight="@*android:dimen/preference_item_padding_side">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
@@ -17,29 +17,75 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/app_detail"
|
android:id="@+id/app_detail"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@*android:dimen/preference_item_padding_side"
|
||||||
|
android:layout_marginRight="@*android:dimen/preference_item_padding_side"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginRight="@*android:dimen/preference_item_padding_inner"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/app_icon"
|
android:id="@+id/app_icon"
|
||||||
android:layout_width="48dip"
|
android:layout_width="48dip"
|
||||||
android:layout_height="48dip"
|
android:layout_height="48dip"
|
||||||
android:layout_marginLeft="16dip"
|
|
||||||
android:scaleType="centerInside" />
|
android:scaleType="centerInside" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/app_titles"
|
android:id="@+id/app_titles"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="16dip"
|
|
||||||
android:layout_marginTop="8dip"
|
android:layout_marginTop="8dip"
|
||||||
android:orientation="vertical" />
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dip"
|
||||||
|
android:textColor="#d88d3a"
|
||||||
|
android:text="@string/data_usage_label_foreground" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/app_foreground"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="#d88d3a" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dip"
|
||||||
|
android:text="@string/data_usage_label_background" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/app_background"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.android.settings.widget.PieChartView
|
||||||
|
android:id="@+id/app_pie_chart"
|
||||||
|
android:layout_width="160dip"
|
||||||
|
android:layout_height="160dip" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/app_settings"
|
android:id="@+id/app_settings"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="16dip"
|
android:layout_marginLeft="@*android:dimen/preference_item_padding_side"
|
||||||
|
android:layout_marginRight="@*android:dimen/preference_item_padding_side"
|
||||||
|
android:layout_marginTop="16dip"
|
||||||
|
android:layout_marginBottom="16dip"
|
||||||
android:text="@string/data_usage_app_settings" />
|
android:text="@string/data_usage_app_settings" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -39,8 +39,8 @@
|
|||||||
android:id="@+id/usage_summary"
|
android:id="@+id/usage_summary"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="16dip"
|
android:paddingLeft="@*android:dimen/preference_item_padding_side"
|
||||||
android:paddingRight="16dip"
|
android:paddingRight="@*android:dimen/preference_item_padding_side"
|
||||||
android:paddingTop="8dip"
|
android:paddingTop="8dip"
|
||||||
android:paddingBottom="8dip"
|
android:paddingBottom="8dip"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
@@ -52,8 +52,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:paddingLeft="16dip"
|
android:paddingLeft="@*android:dimen/preference_item_padding_side"
|
||||||
android:paddingRight="16dip"
|
android:paddingRight="@*android:dimen/preference_item_padding_side"
|
||||||
android:paddingTop="8dip"
|
android:paddingTop="8dip"
|
||||||
android:paddingBottom="8dip"
|
android:paddingBottom="8dip"
|
||||||
android:text="@string/data_usage_empty"
|
android:text="@string/data_usage_empty"
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="16dip"
|
android:paddingLeft="@*android:dimen/preference_item_padding_side"
|
||||||
android:paddingRight="16dip"
|
android:paddingRight="@*android:dimen/preference_item_padding_side"
|
||||||
android:paddingTop="8dip"
|
android:paddingTop="8dip"
|
||||||
android:paddingBottom="8dip"
|
android:paddingBottom="8dip"
|
||||||
android:columnCount="3">
|
android:columnCount="3">
|
||||||
|
|||||||
@@ -25,11 +25,20 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
<TabWidget
|
<TabWidget
|
||||||
android:id="@android:id/tabs"
|
android:id="@android:id/tabs"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_width="match_parent"
|
style="?android:attr/tabWidgetStyle" />
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
<!-- give an empty content area to make tabhost happy -->
|
<!-- give an empty content area to make tabhost happy -->
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
|||||||
@@ -37,10 +37,10 @@
|
|||||||
|
|
||||||
<TabWidget
|
<TabWidget
|
||||||
android:id="@android:id/tabs"
|
android:id="@android:id/tabs"
|
||||||
android:orientation="horizontal"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
/>
|
android:orientation="horizontal"
|
||||||
|
style="?android:attr/tabWidgetStyle" />
|
||||||
|
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
|||||||
@@ -19,17 +19,16 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minHeight="48dip"
|
android:minHeight="48dip"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
android:paddingLeft="@*android:dimen/preference_item_padding_side"
|
||||||
android:paddingRight="?android:attr/scrollbarSize"
|
android:paddingRight="?android:attr/scrollbarSize"
|
||||||
android:background="?android:attr/selectableItemBackground">
|
android:background="?android:attr/selectableItemBackground">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="15dip"
|
android:layout_weight="1"
|
||||||
android:layout_marginRight="6dip"
|
android:paddingTop="6dip"
|
||||||
android:layout_marginTop="6dip"
|
android:paddingBottom="6dip">
|
||||||
android:layout_marginBottom="6dip"
|
|
||||||
android:layout_weight="1">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+android:id/title"
|
android:id="@+android:id/title"
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="@*android:drawable/tab_indicator_holo">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@android:id/title"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="marquee"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
@@ -15,11 +15,6 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item
|
|
||||||
android:id="@+id/action_settings"
|
|
||||||
android:icon="@drawable/ic_sysbar_quicksettings"
|
|
||||||
android:showAsAction="always">
|
|
||||||
<menu>
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/data_usage_menu_roaming"
|
android:id="@+id/data_usage_menu_roaming"
|
||||||
android:title="@string/data_usage_menu_roaming"
|
android:title="@string/data_usage_menu_roaming"
|
||||||
@@ -41,5 +36,3 @@
|
|||||||
android:title="@string/data_usage_menu_show_ethernet"
|
android:title="@string/data_usage_menu_show_ethernet"
|
||||||
android:checkable="true" />
|
android:checkable="true" />
|
||||||
</menu>
|
</menu>
|
||||||
</item>
|
|
||||||
</menu>
|
|
||||||
|
|||||||
@@ -50,6 +50,13 @@
|
|||||||
<attr name="minTickWidth" format="dimension" />
|
<attr name="minTickWidth" format="dimension" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
|
<declare-styleable name="ChartView">
|
||||||
|
<!-- optimal width of the chart -->
|
||||||
|
<attr name="optimalWidth" format="dimension" />
|
||||||
|
<!-- how to weight extra space beyond optimal width -->
|
||||||
|
<attr name="optimalWidthWeight" format="float" />
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
<declare-styleable name="ChartSweepView">
|
<declare-styleable name="ChartSweepView">
|
||||||
<attr name="sweepDrawable" format="reference" />
|
<attr name="sweepDrawable" format="reference" />
|
||||||
<attr name="followAxis">
|
<attr name="followAxis">
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<dimen name="device_memory_usage_button_width">16dip</dimen>
|
<dimen name="device_memory_usage_button_width">16dip</dimen>
|
||||||
<dimen name="device_memory_usage_button_height">32dip</dimen>
|
<dimen name="device_memory_usage_button_height">32dip</dimen>
|
||||||
<dimen name="data_usage_chart_height">220dip</dimen>
|
|
||||||
<dimen name="action_bar_switch_padding">16dip</dimen>
|
<dimen name="action_bar_switch_padding">16dip</dimen>
|
||||||
|
|
||||||
<dimen name="app_icon_size">56dip</dimen>
|
<dimen name="app_icon_size">56dip</dimen>
|
||||||
@@ -28,4 +27,7 @@
|
|||||||
<dimen name="content_margin_left">16dip</dimen>
|
<dimen name="content_margin_left">16dip</dimen>
|
||||||
<dimen name="description_margin_top">26dip</dimen>
|
<dimen name="description_margin_top">26dip</dimen>
|
||||||
<dimen name="description_margin_sides">40dip</dimen>
|
<dimen name="description_margin_sides">40dip</dimen>
|
||||||
|
|
||||||
|
<dimen name="data_usage_chart_height">220dip</dimen>
|
||||||
|
<dimen name="data_usage_chart_optimalWidth">440dip</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -3392,7 +3392,7 @@ found in the list of installed applications.</string>
|
|||||||
<!-- Title for checkbox menu option to restrict background data usage. [CHAR LIMIT=32] -->
|
<!-- Title for checkbox menu option to restrict background data usage. [CHAR LIMIT=32] -->
|
||||||
<string name="data_usage_menu_restrict_background">Restrict background data</string>
|
<string name="data_usage_menu_restrict_background">Restrict background data</string>
|
||||||
<!-- Title for checkbox menu option to show 4G mobile data usage separate from other mobile data usage. [CHAR LIMIT=32] -->
|
<!-- Title for checkbox menu option to show 4G mobile data usage separate from other mobile data usage. [CHAR LIMIT=32] -->
|
||||||
<string name="data_usage_menu_split_4g">Split 4G usage</string>
|
<string name="data_usage_menu_split_4g">Separate 4G usage</string>
|
||||||
<!-- Title for checkbox menu option to show Wi-Fi data usage. [CHAR LIMIT=32] -->
|
<!-- Title for checkbox menu option to show Wi-Fi data usage. [CHAR LIMIT=32] -->
|
||||||
<string name="data_usage_menu_show_wifi">Show Wi-Fi usage</string>
|
<string name="data_usage_menu_show_wifi">Show Wi-Fi usage</string>
|
||||||
<!-- Title for checkbox menu option to show Ethernet data usage. [CHAR LIMIT=32] -->
|
<!-- Title for checkbox menu option to show Ethernet data usage. [CHAR LIMIT=32] -->
|
||||||
@@ -3403,6 +3403,10 @@ found in the list of installed applications.</string>
|
|||||||
<string name="data_usage_pick_cycle_day">Day of month to reset data usage cycle:</string>
|
<string name="data_usage_pick_cycle_day">Day of month to reset data usage cycle:</string>
|
||||||
<!-- Label shown when no applications used data during selected time period. [CHAR LIMIT=48] -->
|
<!-- Label shown when no applications used data during selected time period. [CHAR LIMIT=48] -->
|
||||||
<string name="data_usage_empty">No applications used data during this period.</string>
|
<string name="data_usage_empty">No applications used data during this period.</string>
|
||||||
|
<!-- Label for data usage occuring while application in foreground. [CHAR LIMIT=48] -->
|
||||||
|
<string name="data_usage_label_foreground">Foreground</string>
|
||||||
|
<!-- Label for data usage occuring while application in background. [CHAR LIMIT=48] -->
|
||||||
|
<string name="data_usage_label_background">Background</string>
|
||||||
|
|
||||||
<!-- Checkbox label that will disable mobile network data connection when user-defined limit is reached. [CHAR LIMIT=32] -->
|
<!-- Checkbox label that will disable mobile network data connection when user-defined limit is reached. [CHAR LIMIT=32] -->
|
||||||
<string name="data_usage_disable_mobile_limit">Disable mobile data at limit</string>
|
<string name="data_usage_disable_mobile_limit">Disable mobile data at limit</string>
|
||||||
@@ -3471,7 +3475,7 @@ found in the list of installed applications.</string>
|
|||||||
<!-- Combination of total network bytes sent and received by an application. [CHAR LIMIT=NONE] -->
|
<!-- Combination of total network bytes sent and received by an application. [CHAR LIMIT=NONE] -->
|
||||||
<string name="data_usage_received_sent"><xliff:g id="received" example="128KB">%1$s</xliff:g> received, <xliff:g id="sent" example="1.3GB">%2$s</xliff:g> sent</string>
|
<string name="data_usage_received_sent"><xliff:g id="received" example="128KB">%1$s</xliff:g> received, <xliff:g id="sent" example="1.3GB">%2$s</xliff:g> sent</string>
|
||||||
<!-- Label displaying total network data transferred during a specific time period. [CHAR LIMIT=64] -->
|
<!-- Label displaying total network data transferred during a specific time period. [CHAR LIMIT=64] -->
|
||||||
<string name="data_usage_total_during_range">Data usage: <xliff:g id="total" example="128KB">%1$s</xliff:g> on <xliff:g id="range" example="Jul 1 - Jul 31">%2$s</xliff:g></string>
|
<string name="data_usage_total_during_range"><xliff:g id="range" example="Jul 1 - Jul 31">%2$s</xliff:g>: <xliff:g id="total" example="128KB">%1$s</xliff:g> used</string>
|
||||||
|
|
||||||
<!-- Button at the bottom of the CryptKeeper screen to make an emergency call. -->
|
<!-- Button at the bottom of the CryptKeeper screen to make an emergency call. -->
|
||||||
<string name="cryptkeeper_emergency_call">Emergency call</string>
|
<string name="cryptkeeper_emergency_call">Emergency call</string>
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import static android.net.NetworkPolicyManager.POLICY_NONE;
|
|||||||
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
|
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
|
||||||
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
|
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
|
||||||
import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
|
import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
|
||||||
|
import static android.net.NetworkStats.SET_DEFAULT;
|
||||||
|
import static android.net.NetworkStats.SET_FOREGROUND;
|
||||||
import static android.net.NetworkStats.TAG_NONE;
|
import static android.net.NetworkStats.TAG_NONE;
|
||||||
import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
|
import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
|
||||||
import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
|
import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
|
||||||
@@ -60,6 +62,7 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.INetworkPolicyManager;
|
import android.net.INetworkPolicyManager;
|
||||||
@@ -83,6 +86,7 @@ import android.text.TextUtils;
|
|||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.text.format.Formatter;
|
import android.text.format.Formatter;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.SparseArray;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@@ -119,6 +123,7 @@ import com.android.settings.net.NetworkPolicyEditor;
|
|||||||
import com.android.settings.net.SummaryForAllUidLoader;
|
import com.android.settings.net.SummaryForAllUidLoader;
|
||||||
import com.android.settings.widget.DataUsageChartView;
|
import com.android.settings.widget.DataUsageChartView;
|
||||||
import com.android.settings.widget.DataUsageChartView.DataUsageChartListener;
|
import com.android.settings.widget.DataUsageChartView.DataUsageChartListener;
|
||||||
|
import com.android.settings.widget.PieChartView;
|
||||||
import com.google.android.collect.Lists;
|
import com.google.android.collect.Lists;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -196,6 +201,9 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private View mAppDetail;
|
private View mAppDetail;
|
||||||
private ImageView mAppIcon;
|
private ImageView mAppIcon;
|
||||||
private ViewGroup mAppTitles;
|
private ViewGroup mAppTitles;
|
||||||
|
private PieChartView mAppPieChart;
|
||||||
|
private TextView mAppForeground;
|
||||||
|
private TextView mAppBackground;
|
||||||
private Button mAppSettings;
|
private Button mAppSettings;
|
||||||
|
|
||||||
private LinearLayout mAppSwitches;
|
private LinearLayout mAppSwitches;
|
||||||
@@ -216,6 +224,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
|
|
||||||
private NetworkStatsHistory mHistory;
|
private NetworkStatsHistory mHistory;
|
||||||
private NetworkStatsHistory mDetailHistory;
|
private NetworkStatsHistory mDetailHistory;
|
||||||
|
private NetworkStatsHistory mDetailHistoryDefault;
|
||||||
|
private NetworkStatsHistory mDetailHistoryForeground;
|
||||||
|
|
||||||
private String mCurrentTab = null;
|
private String mCurrentTab = null;
|
||||||
private String mIntentTab = null;
|
private String mIntentTab = null;
|
||||||
@@ -301,6 +311,9 @@ public class DataUsageSummary extends Fragment {
|
|||||||
mAppDetail = mHeader.findViewById(R.id.app_detail);
|
mAppDetail = mHeader.findViewById(R.id.app_detail);
|
||||||
mAppIcon = (ImageView) mAppDetail.findViewById(R.id.app_icon);
|
mAppIcon = (ImageView) mAppDetail.findViewById(R.id.app_icon);
|
||||||
mAppTitles = (ViewGroup) mAppDetail.findViewById(R.id.app_titles);
|
mAppTitles = (ViewGroup) mAppDetail.findViewById(R.id.app_titles);
|
||||||
|
mAppPieChart = (PieChartView) mAppDetail.findViewById(R.id.app_pie_chart);
|
||||||
|
mAppForeground = (TextView) mAppDetail.findViewById(R.id.app_foreground);
|
||||||
|
mAppBackground = (TextView) mAppDetail.findViewById(R.id.app_background);
|
||||||
mAppSwitches = (LinearLayout) mAppDetail.findViewById(R.id.app_switches);
|
mAppSwitches = (LinearLayout) mAppDetail.findViewById(R.id.app_switches);
|
||||||
|
|
||||||
mAppSettings = (Button) mAppDetail.findViewById(R.id.app_settings);
|
mAppSettings = (Button) mAppDetail.findViewById(R.id.app_settings);
|
||||||
@@ -539,12 +552,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
* Build {@link TabSpec} with thin indicator, and empty content.
|
* Build {@link TabSpec} with thin indicator, and empty content.
|
||||||
*/
|
*/
|
||||||
private TabSpec buildTabSpec(String tag, int titleRes) {
|
private TabSpec buildTabSpec(String tag, int titleRes) {
|
||||||
final LayoutInflater inflater = LayoutInflater.from(mTabWidget.getContext());
|
return mTabHost.newTabSpec(tag).setIndicator(getText(titleRes)).setContent(
|
||||||
final View indicator = inflater.inflate(
|
mEmptyTabContent);
|
||||||
R.layout.tab_indicator_thin_holo, mTabWidget, false);
|
|
||||||
final TextView title = (TextView) indicator.findViewById(android.R.id.title);
|
|
||||||
title.setText(titleRes);
|
|
||||||
return mTabHost.newTabSpec(tag).setIndicator(indicator).setContent(mEmptyTabContent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private OnTabChangeListener mTabListener = new OnTabChangeListener() {
|
private OnTabChangeListener mTabListener = new OnTabChangeListener() {
|
||||||
@@ -658,6 +667,10 @@ public class DataUsageSummary extends Fragment {
|
|||||||
mAppDetail.setVisibility(View.GONE);
|
mAppDetail.setVisibility(View.GONE);
|
||||||
mCycleAdapter.setChangeVisible(true);
|
mCycleAdapter.setChangeVisible(true);
|
||||||
|
|
||||||
|
mDetailHistory = null;
|
||||||
|
mDetailHistoryDefault = null;
|
||||||
|
mDetailHistoryForeground = null;
|
||||||
|
|
||||||
// hide detail stats when not in detail mode
|
// hide detail stats when not in detail mode
|
||||||
mChart.bindDetailNetworkStats(null);
|
mChart.bindDetailNetworkStats(null);
|
||||||
return;
|
return;
|
||||||
@@ -697,15 +710,20 @@ public class DataUsageSummary extends Fragment {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// load stats for current uid and template
|
// load stats for current uid and template
|
||||||
// TODO: read template from extras
|
mDetailHistoryDefault = mStatsService.getHistoryForUid(
|
||||||
mDetailHistory = mStatsService.getHistoryForUid(
|
mTemplate, mUid, SET_DEFAULT, TAG_NONE, FIELD_RX_BYTES | FIELD_TX_BYTES);
|
||||||
mTemplate, mUid, TAG_NONE, FIELD_RX_BYTES | FIELD_TX_BYTES);
|
mDetailHistoryForeground = mStatsService.getHistoryForUid(
|
||||||
|
mTemplate, mUid, SET_FOREGROUND, TAG_NONE, FIELD_RX_BYTES | FIELD_TX_BYTES);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// since we can't do much without history, and we don't want to
|
// since we can't do much without history, and we don't want to
|
||||||
// leave with half-baked UI, we bail hard.
|
// leave with half-baked UI, we bail hard.
|
||||||
throw new RuntimeException("problem reading network stats", e);
|
throw new RuntimeException("problem reading network stats", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDetailHistory = new NetworkStatsHistory(mDetailHistoryForeground.getBucketDuration());
|
||||||
|
mDetailHistory.recordEntireHistory(mDetailHistoryDefault);
|
||||||
|
mDetailHistory.recordEntireHistory(mDetailHistoryForeground);
|
||||||
|
|
||||||
// bind chart to historical stats
|
// bind chart to historical stats
|
||||||
mChart.bindDetailNetworkStats(mDetailHistory);
|
mChart.bindDetailNetworkStats(mDetailHistory);
|
||||||
|
|
||||||
@@ -1012,14 +1030,28 @@ public class DataUsageSummary extends Fragment {
|
|||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
|
|
||||||
final Context context = getActivity();
|
final Context context = getActivity();
|
||||||
final NetworkStatsHistory.Entry entry;
|
|
||||||
|
|
||||||
if (isAppDetailMode()) {
|
NetworkStatsHistory.Entry entry = null;
|
||||||
if (mDetailHistory != null) {
|
if (isAppDetailMode() && mDetailHistory != null) {
|
||||||
|
// bind foreground/background to piechart and labels
|
||||||
|
entry = mDetailHistoryDefault.getValues(start, end, now, entry);
|
||||||
|
final long defaultBytes = entry.rxBytes + entry.txBytes;
|
||||||
|
entry = mDetailHistoryForeground.getValues(start, end, now, entry);
|
||||||
|
final long foregroundBytes = entry.rxBytes + entry.txBytes;
|
||||||
|
|
||||||
|
mAppPieChart.setOriginAngle(175);
|
||||||
|
|
||||||
|
mAppPieChart.removeAllSlices();
|
||||||
|
mAppPieChart.addSlice(foregroundBytes, Color.parseColor("#d88d3a"));
|
||||||
|
mAppPieChart.addSlice(defaultBytes, Color.parseColor("#666666"));
|
||||||
|
|
||||||
|
mAppPieChart.generatePath();
|
||||||
|
|
||||||
|
mAppBackground.setText(Formatter.formatFileSize(context, defaultBytes));
|
||||||
|
mAppForeground.setText(Formatter.formatFileSize(context, foregroundBytes));
|
||||||
|
|
||||||
|
// and finally leave with summary data for label below
|
||||||
entry = mDetailHistory.getValues(start, end, now, null);
|
entry = mDetailHistory.getValues(start, end, now, null);
|
||||||
} else {
|
|
||||||
entry = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getLoaderManager().destroyLoader(LOADER_SUMMARY);
|
getLoaderManager().destroyLoader(LOADER_SUMMARY);
|
||||||
|
|
||||||
@@ -1206,21 +1238,29 @@ public class DataUsageSummary extends Fragment {
|
|||||||
public void bindStats(NetworkStats stats) {
|
public void bindStats(NetworkStats stats) {
|
||||||
mItems.clear();
|
mItems.clear();
|
||||||
|
|
||||||
if (stats != null) {
|
|
||||||
final AppUsageItem systemItem = new AppUsageItem();
|
final AppUsageItem systemItem = new AppUsageItem();
|
||||||
systemItem.uid = android.os.Process.SYSTEM_UID;
|
systemItem.uid = android.os.Process.SYSTEM_UID;
|
||||||
|
|
||||||
|
final SparseArray<AppUsageItem> knownUids = new SparseArray<AppUsageItem>();
|
||||||
|
|
||||||
NetworkStats.Entry entry = null;
|
NetworkStats.Entry entry = null;
|
||||||
for (int i = 0; i < stats.size(); i++) {
|
final int size = stats != null ? stats.size() : 0;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
entry = stats.getValues(i, entry);
|
entry = stats.getValues(i, entry);
|
||||||
|
|
||||||
final boolean isApp = entry.uid >= android.os.Process.FIRST_APPLICATION_UID
|
final int uid = entry.uid;
|
||||||
&& entry.uid <= android.os.Process.LAST_APPLICATION_UID;
|
final boolean isApp = uid >= android.os.Process.FIRST_APPLICATION_UID
|
||||||
if (isApp || entry.uid == TrafficStats.UID_REMOVED) {
|
&& uid <= android.os.Process.LAST_APPLICATION_UID;
|
||||||
final AppUsageItem item = new AppUsageItem();
|
if (isApp || uid == TrafficStats.UID_REMOVED) {
|
||||||
item.uid = entry.uid;
|
AppUsageItem item = knownUids.get(uid);
|
||||||
item.total = entry.rxBytes + entry.txBytes;
|
if (item == null) {
|
||||||
|
item = new AppUsageItem();
|
||||||
|
item.uid = uid;
|
||||||
|
knownUids.put(uid, item);
|
||||||
mItems.add(item);
|
mItems.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
item.total += entry.rxBytes + entry.txBytes;
|
||||||
} else {
|
} else {
|
||||||
systemItem.total += entry.rxBytes + entry.txBytes;
|
systemItem.total += entry.rxBytes + entry.txBytes;
|
||||||
}
|
}
|
||||||
@@ -1229,7 +1269,6 @@ public class DataUsageSummary extends Fragment {
|
|||||||
if (systemItem.total > 0) {
|
if (systemItem.total > 0) {
|
||||||
mItems.add(systemItem);
|
mItems.add(systemItem);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Collections.sort(mItems);
|
Collections.sort(mItems);
|
||||||
mLargest = (mItems.size() > 0) ? mItems.get(0).total : 0;
|
mLargest = (mItems.size() > 0) ? mItems.get(0).total : 0;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler {
|
|||||||
private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
|
private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
|
||||||
"com.android.settings.PARENT_FRAGMENT_CLASS";
|
"com.android.settings.PARENT_FRAGMENT_CLASS";
|
||||||
|
|
||||||
private static final String EXTRA_THEME = "settings:theme";
|
private static final String EXTRA_CLEAR_UI_OPTIONS = "settings:remove_ui_options";
|
||||||
|
|
||||||
private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
|
private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
|
||||||
private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
|
private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
|
||||||
@@ -82,9 +82,9 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
final int theme = getIntent().getIntExtra(
|
if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) {
|
||||||
EXTRA_THEME, android.R.style.Theme_Holo);
|
getWindow().setUiOptions(0);
|
||||||
setTheme(theme);
|
}
|
||||||
|
|
||||||
getMetaData();
|
getMetaData();
|
||||||
mInLocalHeaderSwitch = true;
|
mInLocalHeaderSwitch = true;
|
||||||
@@ -288,12 +288,12 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler {
|
|||||||
Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
|
Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
|
||||||
titleRes, shortTitleRes);
|
titleRes, shortTitleRes);
|
||||||
|
|
||||||
// some fragments would like a custom activity theme
|
// some fragments want to avoid split actionbar
|
||||||
if (DataUsageSummary.class.getName().equals(fragmentName) ||
|
if (DataUsageSummary.class.getName().equals(fragmentName) ||
|
||||||
PowerUsageSummary.class.getName().equals(fragmentName) ||
|
PowerUsageSummary.class.getName().equals(fragmentName) ||
|
||||||
AccountSyncSettings.class.getName().equals(fragmentName) ||
|
AccountSyncSettings.class.getName().equals(fragmentName) ||
|
||||||
UserDictionarySettings.class.getName().equals(fragmentName)) {
|
UserDictionarySettings.class.getName().equals(fragmentName)) {
|
||||||
intent.putExtra(EXTRA_THEME, android.R.style.Theme_Holo);
|
intent.putExtra(EXTRA_CLEAR_UI_OPTIONS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
intent.setClass(this, SubSettings.class);
|
intent.setClass(this, SubSettings.class);
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
|
|
||||||
public void setChartColor(int stroke, int fill, int fillSecondary) {
|
public void setChartColor(int stroke, int fill, int fillSecondary) {
|
||||||
mPaintStroke = new Paint();
|
mPaintStroke = new Paint();
|
||||||
mPaintStroke.setStrokeWidth(6.0f);
|
mPaintStroke.setStrokeWidth(4.0f * getResources().getDisplayMetrics().density);
|
||||||
mPaintStroke.setColor(stroke);
|
mPaintStroke.setColor(stroke);
|
||||||
mPaintStroke.setStyle(Style.STROKE);
|
mPaintStroke.setStyle(Style.STROKE);
|
||||||
mPaintStroke.setAntiAlias(true);
|
mPaintStroke.setAntiAlias(true);
|
||||||
@@ -165,7 +165,10 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
mPathEstimate.reset();
|
mPathEstimate.reset();
|
||||||
|
|
||||||
// bail when not enough stats to render
|
// bail when not enough stats to render
|
||||||
if (mStats == null || mStats.size() < 2) return;
|
if (mStats == null || mStats.size() < 2) {
|
||||||
|
invalidate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final int width = getWidth();
|
final int width = getWidth();
|
||||||
final int height = getHeight();
|
final int height = getHeight();
|
||||||
@@ -263,6 +266,8 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mMaxEstimate = totalData;
|
mMaxEstimate = totalData;
|
||||||
|
|
||||||
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEndTime(long endTime) {
|
public void setEndTime(long endTime) {
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import android.util.AttributeSet;
|
|||||||
import android.util.MathUtils;
|
import android.util.MathUtils;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
@@ -41,7 +40,7 @@ import com.google.common.base.Preconditions;
|
|||||||
* Sweep across a {@link ChartView} at a specific {@link ChartAxis} value, which
|
* Sweep across a {@link ChartView} at a specific {@link ChartAxis} value, which
|
||||||
* a user can drag.
|
* a user can drag.
|
||||||
*/
|
*/
|
||||||
public class ChartSweepView extends FrameLayout {
|
public class ChartSweepView extends View {
|
||||||
|
|
||||||
private Drawable mSweep;
|
private Drawable mSweep;
|
||||||
private Rect mSweepPadding = new Rect();
|
private Rect mSweepPadding = new Rect();
|
||||||
@@ -78,7 +77,7 @@ public class ChartSweepView extends FrameLayout {
|
|||||||
private MotionEvent mTracking;
|
private MotionEvent mTracking;
|
||||||
|
|
||||||
public ChartSweepView(Context context) {
|
public ChartSweepView(Context context) {
|
||||||
this(context, null, 0);
|
this(context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChartSweepView(Context context, AttributeSet attrs) {
|
public ChartSweepView(Context context, AttributeSet attrs) {
|
||||||
@@ -101,8 +100,6 @@ public class ChartSweepView extends FrameLayout {
|
|||||||
|
|
||||||
a.recycle();
|
a.recycle();
|
||||||
|
|
||||||
setClipToPadding(false);
|
|
||||||
setClipChildren(false);
|
|
||||||
setWillNotDraw(false);
|
setWillNotDraw(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,16 @@ package com.android.settings.widget;
|
|||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewDebug;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container for two-dimensional chart, drawn with a combination of
|
* Container for two-dimensional chart, drawn with a combination of
|
||||||
* {@link ChartGridView}, {@link ChartNetworkSeriesView} and {@link ChartSweepView}
|
* {@link ChartGridView}, {@link ChartNetworkSeriesView} and {@link ChartSweepView}
|
||||||
@@ -41,6 +45,10 @@ public class ChartView extends FrameLayout {
|
|||||||
ChartAxis mHoriz;
|
ChartAxis mHoriz;
|
||||||
ChartAxis mVert;
|
ChartAxis mVert;
|
||||||
|
|
||||||
|
@ViewDebug.ExportedProperty
|
||||||
|
private int mOptimalWidth = -1;
|
||||||
|
private float mOptimalWidthWeight = 0;
|
||||||
|
|
||||||
private Rect mContent = new Rect();
|
private Rect mContent = new Rect();
|
||||||
|
|
||||||
public ChartView(Context context) {
|
public ChartView(Context context) {
|
||||||
@@ -54,6 +62,12 @@ public class ChartView extends FrameLayout {
|
|||||||
public ChartView(Context context, AttributeSet attrs, int defStyle) {
|
public ChartView(Context context, AttributeSet attrs, int defStyle) {
|
||||||
super(context, attrs, defStyle);
|
super(context, attrs, defStyle);
|
||||||
|
|
||||||
|
final TypedArray a = context.obtainStyledAttributes(
|
||||||
|
attrs, R.styleable.ChartView, defStyle, 0);
|
||||||
|
setOptimalWidth(a.getDimensionPixelSize(R.styleable.ChartView_optimalWidth, -1),
|
||||||
|
a.getFloat(R.styleable.ChartView_optimalWidthWeight, 0));
|
||||||
|
a.recycle();
|
||||||
|
|
||||||
setClipToPadding(false);
|
setClipToPadding(false);
|
||||||
setClipChildren(false);
|
setClipChildren(false);
|
||||||
}
|
}
|
||||||
@@ -63,6 +77,24 @@ public class ChartView extends FrameLayout {
|
|||||||
mVert = checkNotNull(vert, "missing vert");
|
mVert = checkNotNull(vert, "missing vert");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOptimalWidth(int optimalWidth, float optimalWidthWeight) {
|
||||||
|
mOptimalWidth = optimalWidth;
|
||||||
|
mOptimalWidthWeight = optimalWidthWeight;
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
|
||||||
|
final int slack = getMeasuredWidth() - mOptimalWidth;
|
||||||
|
if (mOptimalWidth > 0 && slack > 0) {
|
||||||
|
final int targetWidth = (int) (mOptimalWidth + (slack * mOptimalWidthWeight));
|
||||||
|
widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY);
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||||
mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(),
|
mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(),
|
||||||
|
|||||||
@@ -226,8 +226,6 @@ public class DataUsageChartView extends ChartView {
|
|||||||
mDetailSeries.generatePath();
|
mDetailSeries.generatePath();
|
||||||
|
|
||||||
mGrid.invalidate();
|
mGrid.invalidate();
|
||||||
mSeries.invalidate();
|
|
||||||
mDetailSeries.invalidate();
|
|
||||||
|
|
||||||
// since we just changed axis, make sweep recalculate its value
|
// since we just changed axis, make sweep recalculate its value
|
||||||
if (activeSweep != null) {
|
if (activeSweep != null) {
|
||||||
@@ -362,7 +360,6 @@ public class DataUsageChartView extends ChartView {
|
|||||||
|
|
||||||
requestLayout();
|
requestLayout();
|
||||||
mSeries.generatePath();
|
mSeries.generatePath();
|
||||||
mSeries.invalidate();
|
|
||||||
|
|
||||||
updateVertAxisBounds(null);
|
updateVertAxisBounds(null);
|
||||||
updateEstimateVisible();
|
updateEstimateVisible();
|
||||||
|
|||||||
202
src/com/android/settings/widget/PieChartView.java
Normal file
202
src/com/android/settings/widget/PieChartView.java
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 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.widget;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Paint.Style;
|
||||||
|
import android.graphics.Path;
|
||||||
|
import android.graphics.Path.Direction;
|
||||||
|
import android.graphics.RadialGradient;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.graphics.Shader.TileMode;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pie chart with multiple items.
|
||||||
|
*/
|
||||||
|
public class PieChartView extends View {
|
||||||
|
public static final String TAG = "PieChartView";
|
||||||
|
public static final boolean LOGD = true;
|
||||||
|
|
||||||
|
private ArrayList<Slice> mSlices = Lists.newArrayList();
|
||||||
|
|
||||||
|
private int mOriginAngle;
|
||||||
|
|
||||||
|
private Paint mPaintPrimary = new Paint();
|
||||||
|
private Paint mPaintShadow = new Paint();
|
||||||
|
|
||||||
|
private Path mPathSide = new Path();
|
||||||
|
private Path mPathSideShadow = new Path();
|
||||||
|
|
||||||
|
private Path mPathShadow = new Path();
|
||||||
|
|
||||||
|
private int mSideWidth;
|
||||||
|
|
||||||
|
public class Slice {
|
||||||
|
public long value;
|
||||||
|
|
||||||
|
public Path pathPrimary = new Path();
|
||||||
|
public Path pathShadow = new Path();
|
||||||
|
|
||||||
|
public Paint paintPrimary;
|
||||||
|
|
||||||
|
public Slice(long value, int color) {
|
||||||
|
this.value = value;
|
||||||
|
this.paintPrimary = buildFillPaint(color, getResources());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PieChartView(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PieChartView(Context context, AttributeSet attrs) {
|
||||||
|
this(context, attrs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PieChartView(Context context, AttributeSet attrs, int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
|
||||||
|
mPaintPrimary = buildFillPaint(Color.parseColor("#666666"), getResources());
|
||||||
|
|
||||||
|
mPaintShadow.setColor(Color.BLACK);
|
||||||
|
mPaintShadow.setStyle(Style.STROKE);
|
||||||
|
mPaintShadow.setStrokeWidth(3f * getResources().getDisplayMetrics().density);
|
||||||
|
mPaintShadow.setAntiAlias(true);
|
||||||
|
|
||||||
|
mSideWidth = (int) (20 * getResources().getDisplayMetrics().density);
|
||||||
|
|
||||||
|
setWillNotDraw(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Paint buildFillPaint(int color, Resources res) {
|
||||||
|
final Paint paint = new Paint();
|
||||||
|
|
||||||
|
paint.setColor(color);
|
||||||
|
paint.setStyle(Style.FILL_AND_STROKE);
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
|
||||||
|
final int width = (int) (280 * res.getDisplayMetrics().density);
|
||||||
|
paint.setShader(new RadialGradient(0, 0, width, color, darken(color), TileMode.MIRROR));
|
||||||
|
|
||||||
|
return paint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOriginAngle(int originAngle) {
|
||||||
|
mOriginAngle = originAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSlice(long value, int color) {
|
||||||
|
mSlices.add(new Slice(value, color));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllSlices() {
|
||||||
|
mSlices.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
|
generatePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generatePath() {
|
||||||
|
if (LOGD) Log.d(TAG, "generatePath()");
|
||||||
|
|
||||||
|
long total = 0;
|
||||||
|
for (Slice slice : mSlices) {
|
||||||
|
slice.pathPrimary.reset();
|
||||||
|
slice.pathShadow.reset();
|
||||||
|
total += slice.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPathSide.reset();
|
||||||
|
mPathSideShadow.reset();
|
||||||
|
mPathShadow.reset();
|
||||||
|
|
||||||
|
// bail when not enough stats to render
|
||||||
|
if (total == 0) {
|
||||||
|
invalidate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int width = getWidth();
|
||||||
|
final int height = getHeight();
|
||||||
|
|
||||||
|
final RectF rect = new RectF(0, 0, width, height);
|
||||||
|
|
||||||
|
mPathSide.addOval(rect, Direction.CW);
|
||||||
|
mPathSideShadow.addOval(rect, Direction.CW);
|
||||||
|
mPathShadow.addOval(rect, Direction.CW);
|
||||||
|
|
||||||
|
int startAngle = mOriginAngle;
|
||||||
|
for (Slice slice : mSlices) {
|
||||||
|
final int sweepAngle = (int) (slice.value * 360 / total);
|
||||||
|
|
||||||
|
slice.pathPrimary.moveTo(rect.centerX(), rect.centerY());
|
||||||
|
slice.pathPrimary.arcTo(rect, startAngle, sweepAngle);
|
||||||
|
slice.pathPrimary.lineTo(rect.centerX(), rect.centerY());
|
||||||
|
|
||||||
|
slice.pathShadow.moveTo(rect.centerX(), rect.centerY());
|
||||||
|
slice.pathShadow.arcTo(rect, startAngle, 0);
|
||||||
|
slice.pathShadow.moveTo(rect.centerX(), rect.centerY());
|
||||||
|
slice.pathShadow.arcTo(rect, startAngle + sweepAngle, 0);
|
||||||
|
|
||||||
|
startAngle += sweepAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
|
||||||
|
canvas.translate(getWidth() * 0.25f, getHeight() * -0.05f);
|
||||||
|
canvas.rotate(-40, getWidth() * 0.5f, getHeight());
|
||||||
|
canvas.scale(0.7f, 1.0f, getWidth(), getHeight());
|
||||||
|
|
||||||
|
canvas.save();
|
||||||
|
canvas.translate(-mSideWidth, 0);
|
||||||
|
canvas.drawPath(mPathSide, mPaintPrimary);
|
||||||
|
canvas.drawPath(mPathSideShadow, mPaintShadow);
|
||||||
|
canvas.restore();
|
||||||
|
|
||||||
|
for (Slice slice : mSlices) {
|
||||||
|
canvas.drawPath(slice.pathPrimary, slice.paintPrimary);
|
||||||
|
canvas.drawPath(slice.pathShadow, mPaintShadow);
|
||||||
|
}
|
||||||
|
canvas.drawPath(mPathShadow, mPaintShadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int darken(int color) {
|
||||||
|
float[] hsv = new float[3];
|
||||||
|
Color.colorToHSV(color, hsv);
|
||||||
|
hsv[2] /= 2;
|
||||||
|
hsv[1] /= 2;
|
||||||
|
return Color.HSVToColor(hsv);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user