Merge "Data usage app bars, draw estimated cycle usage."
This commit is contained in:
37
res/drawable/data_usage_bar.xml
Normal file
37
res/drawable/data_usage_bar.xml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:id="@android:id/background">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="#ff28262c" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:id="@android:id/secondaryProgress">
|
||||||
|
<clip>
|
||||||
|
<shape>
|
||||||
|
<solid android:color="#c050ade5" />
|
||||||
|
</shape>
|
||||||
|
</clip>
|
||||||
|
</item>
|
||||||
|
<item android:id="@android:id/progress">
|
||||||
|
<clip>
|
||||||
|
<shape>
|
||||||
|
<solid android:color="#c050ade5" />
|
||||||
|
</shape>
|
||||||
|
</clip>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
@@ -14,26 +14,34 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<LinearLayout 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:minHeight="48dip"
|
android:padding="8dip"
|
||||||
android:orientation="vertical">
|
android:columnCount="2">
|
||||||
|
|
||||||
|
<!-- TODO: consider using canShrink -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@android:id/text1"
|
android:id="@android:id/title"
|
||||||
android:layout_width="match_parent"
|
android:singleLine="true"
|
||||||
android:layout_height="wrap_content"
|
android:ellipsize="marquee"
|
||||||
android:layout_marginLeft="6dip"
|
android:layout_columnFlexibility="canStretch"
|
||||||
android:layout_marginTop="6dip"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@android:id/text2"
|
android:id="@android:id/summary"
|
||||||
android:layout_width="match_parent"
|
android:layout_gravity="right"
|
||||||
android:layout_height="wrap_content"
|
android:layout_marginLeft="8dip"
|
||||||
android:layout_marginLeft="6dip"
|
|
||||||
android:layout_marginBottom="6dip"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
</LinearLayout>
|
<ProgressBar
|
||||||
|
android:id="@android:id/progress"
|
||||||
|
android:layout_height="12dip"
|
||||||
|
android:layout_columnSpan="2"
|
||||||
|
android:layout_gravity="fill_horizontal"
|
||||||
|
android:layout_marginTop="4dip"
|
||||||
|
android:max="100"
|
||||||
|
android:progressDrawable="@drawable/data_usage_bar"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal" />
|
||||||
|
|
||||||
|
</GridLayout>
|
||||||
|
|||||||
@@ -3475,6 +3475,8 @@ found in the list of installed applications.</string>
|
|||||||
|
|
||||||
<!-- Title of data usage item that represents all uninstalled applications. [CHAR LIMIT=48] -->
|
<!-- Title of data usage item that represents all uninstalled applications. [CHAR LIMIT=48] -->
|
||||||
<string name="data_usage_uninstalled_apps">Removed apps</string>
|
<string name="data_usage_uninstalled_apps">Removed apps</string>
|
||||||
|
<!-- 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>
|
||||||
|
|
||||||
<!-- 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>
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
|
|||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.NumberPicker;
|
import android.widget.NumberPicker;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.Switch;
|
import android.widget.Switch;
|
||||||
import android.widget.TabHost;
|
import android.widget.TabHost;
|
||||||
@@ -946,8 +947,11 @@ public class DataUsageSummary extends Fragment {
|
|||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
final NetworkStatsHistory.Entry entry = mDetailHistory.getValues(
|
final NetworkStatsHistory.Entry entry = mDetailHistory.getValues(
|
||||||
start, end, now, null);
|
start, end, now, null);
|
||||||
final long total = entry.rxBytes + entry.txBytes;
|
|
||||||
mAppSubtitle.setText(Formatter.formatFileSize(context, total));
|
mAppSubtitle.setText(
|
||||||
|
getString(R.string.data_usage_received_sent,
|
||||||
|
Formatter.formatFileSize(context, entry.rxBytes),
|
||||||
|
Formatter.formatFileSize(context, entry.txBytes)));
|
||||||
}
|
}
|
||||||
|
|
||||||
getLoaderManager().destroyLoader(LOADER_SUMMARY);
|
getLoaderManager().destroyLoader(LOADER_SUMMARY);
|
||||||
@@ -1110,6 +1114,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
*/
|
*/
|
||||||
public static class DataUsageAdapter extends BaseAdapter {
|
public static class DataUsageAdapter extends BaseAdapter {
|
||||||
private ArrayList<AppUsageItem> mItems = Lists.newArrayList();
|
private ArrayList<AppUsageItem> mItems = Lists.newArrayList();
|
||||||
|
private long mLargest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind the given {@link NetworkStats}, or {@code null} to clear list.
|
* Bind the given {@link NetworkStats}, or {@code null} to clear list.
|
||||||
@@ -1143,6 +1148,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(mItems);
|
Collections.sort(mItems);
|
||||||
|
mLargest = (mItems.size() > 0) ? mItems.get(0).total : 0;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1170,12 +1176,17 @@ public class DataUsageSummary extends Fragment {
|
|||||||
|
|
||||||
final Context context = parent.getContext();
|
final Context context = parent.getContext();
|
||||||
|
|
||||||
final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1);
|
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
|
||||||
final TextView text2 = (TextView) convertView.findViewById(android.R.id.text2);
|
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
|
||||||
|
final ProgressBar progress = (ProgressBar) convertView.findViewById(
|
||||||
|
android.R.id.progress);
|
||||||
|
|
||||||
final AppUsageItem item = mItems.get(position);
|
final AppUsageItem item = mItems.get(position);
|
||||||
text1.setText(resolveLabelForUid(context, item.uid));
|
title.setText(resolveLabelForUid(context, item.uid));
|
||||||
text2.setText(Formatter.formatFileSize(context, item.total));
|
summary.setText(Formatter.formatFileSize(context, item.total));
|
||||||
|
|
||||||
|
final int percentTotal = mLargest != 0 ? (int) (item.total * 100 / mLargest) : 0;
|
||||||
|
progress.setProgress(percentTotal);
|
||||||
|
|
||||||
return convertView;
|
return convertView;
|
||||||
}
|
}
|
||||||
@@ -1187,7 +1198,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
* {@link DataUsageSummary}.
|
* {@link DataUsageSummary}.
|
||||||
*/
|
*/
|
||||||
public static class AppDetailsFragment extends Fragment {
|
public static class AppDetailsFragment extends Fragment {
|
||||||
public static final String EXTRA_UID = "uid";
|
private static final String EXTRA_UID = "uid";
|
||||||
|
|
||||||
public static void show(DataUsageSummary parent, int uid) {
|
public static void show(DataUsageSummary parent, int uid) {
|
||||||
final Bundle args = new Bundle();
|
final Bundle args = new Bundle();
|
||||||
@@ -1225,8 +1236,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
* {@link NetworkPolicy#limitBytes}.
|
* {@link NetworkPolicy#limitBytes}.
|
||||||
*/
|
*/
|
||||||
public static class ConfirmLimitFragment extends DialogFragment {
|
public static class ConfirmLimitFragment extends DialogFragment {
|
||||||
public static final String EXTRA_MESSAGE_ID = "messageId";
|
private static final String EXTRA_MESSAGE_ID = "messageId";
|
||||||
public static final String EXTRA_LIMIT_BYTES = "limitBytes";
|
private static final String EXTRA_LIMIT_BYTES = "limitBytes";
|
||||||
|
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
final Bundle args = new Bundle();
|
final Bundle args = new Bundle();
|
||||||
@@ -1278,7 +1289,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
* Dialog to edit {@link NetworkPolicy#cycleDay}.
|
* Dialog to edit {@link NetworkPolicy#cycleDay}.
|
||||||
*/
|
*/
|
||||||
public static class CycleEditorFragment extends DialogFragment {
|
public static class CycleEditorFragment extends DialogFragment {
|
||||||
public static final String EXTRA_CYCLE_DAY = "cycleDay";
|
private static final String EXTRA_CYCLE_DAY = "cycleDay";
|
||||||
|
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
final NetworkPolicy policy = parent.mPolicyEditor.getPolicy(parent.mTemplate);
|
final NetworkPolicy policy = parent.mPolicyEditor.getPolicy(parent.mTemplate);
|
||||||
@@ -1331,7 +1342,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
* and giving the user an option to bypass.
|
* and giving the user an option to bypass.
|
||||||
*/
|
*/
|
||||||
public static class PolicyLimitFragment extends DialogFragment {
|
public static class PolicyLimitFragment extends DialogFragment {
|
||||||
public static final String EXTRA_TITLE_ID = "titleId";
|
private static final String EXTRA_TITLE_ID = "titleId";
|
||||||
|
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
final Bundle args = new Bundle();
|
final Bundle args = new Bundle();
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.android.settings.widget;
|
package com.android.settings.widget;
|
||||||
|
|
||||||
|
import static android.text.format.DateUtils.DAY_IN_MILLIS;
|
||||||
|
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
@@ -46,11 +49,13 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
private Paint mPaintStroke;
|
private Paint mPaintStroke;
|
||||||
private Paint mPaintFill;
|
private Paint mPaintFill;
|
||||||
private Paint mPaintFillSecondary;
|
private Paint mPaintFillSecondary;
|
||||||
|
private Paint mPaintEstimate;
|
||||||
|
|
||||||
private NetworkStatsHistory mStats;
|
private NetworkStatsHistory mStats;
|
||||||
|
|
||||||
private Path mPathStroke;
|
private Path mPathStroke;
|
||||||
private Path mPathFill;
|
private Path mPathFill;
|
||||||
|
private Path mPathEstimate;
|
||||||
|
|
||||||
private long mPrimaryLeft;
|
private long mPrimaryLeft;
|
||||||
private long mPrimaryRight;
|
private long mPrimaryRight;
|
||||||
@@ -81,6 +86,7 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
|
|
||||||
mPathStroke = new Path();
|
mPathStroke = new Path();
|
||||||
mPathFill = new Path();
|
mPathFill = new Path();
|
||||||
|
mPathEstimate = new Path();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(ChartAxis horiz, ChartAxis vert) {
|
void init(ChartAxis horiz, ChartAxis vert) {
|
||||||
@@ -104,6 +110,12 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
mPaintFillSecondary.setColor(fillSecondary);
|
mPaintFillSecondary.setColor(fillSecondary);
|
||||||
mPaintFillSecondary.setStyle(Style.FILL);
|
mPaintFillSecondary.setStyle(Style.FILL);
|
||||||
mPaintFillSecondary.setAntiAlias(true);
|
mPaintFillSecondary.setAntiAlias(true);
|
||||||
|
|
||||||
|
mPaintEstimate = new Paint();
|
||||||
|
mPaintEstimate.setStrokeWidth(3.0f);
|
||||||
|
mPaintEstimate.setColor(fillSecondary);
|
||||||
|
mPaintEstimate.setStyle(Style.STROKE);
|
||||||
|
mPaintEstimate.setAntiAlias(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindNetworkStats(NetworkStatsHistory stats) {
|
public void bindNetworkStats(NetworkStatsHistory stats) {
|
||||||
@@ -111,6 +123,7 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
|
|
||||||
mPathStroke.reset();
|
mPathStroke.reset();
|
||||||
mPathFill.reset();
|
mPathFill.reset();
|
||||||
|
mPathEstimate.reset();
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +151,7 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
|
|
||||||
mPathStroke.reset();
|
mPathStroke.reset();
|
||||||
mPathFill.reset();
|
mPathFill.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) return;
|
||||||
@@ -149,6 +163,7 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
float firstX = 0;
|
float firstX = 0;
|
||||||
float lastX = 0;
|
float lastX = 0;
|
||||||
float lastY = 0;
|
float lastY = 0;
|
||||||
|
long lastTime = Long.MIN_VALUE;
|
||||||
|
|
||||||
// TODO: count fractional data from first bucket crossing start;
|
// TODO: count fractional data from first bucket crossing start;
|
||||||
// currently it only accepts first full bucket.
|
// currently it only accepts first full bucket.
|
||||||
@@ -159,6 +174,7 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
for (int i = 0; i < mStats.size(); i++) {
|
for (int i = 0; i < mStats.size(); i++) {
|
||||||
entry = mStats.getValues(i, entry);
|
entry = mStats.getValues(i, entry);
|
||||||
|
|
||||||
|
lastTime = entry.bucketStart;
|
||||||
final float x = mHoriz.convertToPoint(entry.bucketStart);
|
final float x = mHoriz.convertToPoint(entry.bucketStart);
|
||||||
final float y = mVert.convertToPoint(totalData);
|
final float y = mVert.convertToPoint(totalData);
|
||||||
|
|
||||||
@@ -193,6 +209,35 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
// drop to bottom of graph from current location
|
// drop to bottom of graph from current location
|
||||||
mPathFill.lineTo(lastX, height);
|
mPathFill.lineTo(lastX, height);
|
||||||
mPathFill.lineTo(firstX, height);
|
mPathFill.lineTo(firstX, height);
|
||||||
|
|
||||||
|
// build estimated data
|
||||||
|
mPathEstimate.moveTo(lastX, lastY);
|
||||||
|
|
||||||
|
final long now = System.currentTimeMillis();
|
||||||
|
final long bucketDuration = mStats.getBucketDuration();
|
||||||
|
|
||||||
|
// long window is average over two weeks
|
||||||
|
entry = mStats.getValues(lastTime - WEEK_IN_MILLIS * 2, lastTime, now, entry);
|
||||||
|
final long longWindow = (entry.rxBytes + entry.txBytes) * bucketDuration
|
||||||
|
/ entry.bucketDuration;
|
||||||
|
|
||||||
|
long futureTime = 0;
|
||||||
|
while (lastX < width) {
|
||||||
|
futureTime += bucketDuration;
|
||||||
|
|
||||||
|
// short window is day average last week
|
||||||
|
final long lastWeekTime = lastTime - WEEK_IN_MILLIS + (futureTime % WEEK_IN_MILLIS);
|
||||||
|
entry = mStats.getValues(lastWeekTime - DAY_IN_MILLIS, lastWeekTime, now, entry);
|
||||||
|
final long shortWindow = (entry.rxBytes + entry.txBytes) * bucketDuration
|
||||||
|
/ entry.bucketDuration;
|
||||||
|
|
||||||
|
totalData += (longWindow * 7 + shortWindow * 3) / 10;
|
||||||
|
|
||||||
|
lastX = mHoriz.convertToPoint(lastTime + futureTime);
|
||||||
|
final float y = mVert.convertToPoint(totalData);
|
||||||
|
|
||||||
|
mPathEstimate.lineTo(lastX, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -202,6 +247,11 @@ public class ChartNetworkSeriesView extends View {
|
|||||||
final float primaryLeftPoint = mHoriz.convertToPoint(mPrimaryLeft);
|
final float primaryLeftPoint = mHoriz.convertToPoint(mPrimaryLeft);
|
||||||
final float primaryRightPoint = mHoriz.convertToPoint(mPrimaryRight);
|
final float primaryRightPoint = mHoriz.convertToPoint(mPrimaryRight);
|
||||||
|
|
||||||
|
save = canvas.save();
|
||||||
|
canvas.clipRect(0, 0, getWidth(), getHeight());
|
||||||
|
canvas.drawPath(mPathEstimate, mPaintEstimate);
|
||||||
|
canvas.restoreToCount(save);
|
||||||
|
|
||||||
save = canvas.save();
|
save = canvas.save();
|
||||||
canvas.clipRect(0, 0, primaryLeftPoint, getHeight());
|
canvas.clipRect(0, 0, primaryLeftPoint, getHeight());
|
||||||
canvas.drawPath(mPathFill, mPaintFillSecondary);
|
canvas.drawPath(mPathFill, mPaintFillSecondary);
|
||||||
|
|||||||
Reference in New Issue
Block a user