Data usage fit and finish.

Show time range and data summary based on current sweep selection for
both network and app details.  Fix animations by opting-out of parent
hierarchy animation, since it fights with ListView.

Switch to using NPMS "restrict background" instead of overloading
setBackgroundDataSetting(), and hide app background checkbox when
global background is restricted.

Limit sweeps to valid historical data, and activate sweeps on touch
instead of requiring separate tap.  Fix z-order and avoid animating
sweeps.  Align all elements along vertical edge, and fix item layout
to handle long app title.

Bug: 4979025, 5058107, 5038590, 5079887, 5058108, 5058026, 5037381
Change-Id: Ib45b61ff2a62303f47aa3f47f88d2e688fe4d076
This commit is contained in:
Jeff Sharkey
2011-07-26 19:30:26 -07:00
parent 271ec8a8f8
commit d360e5efaa
8 changed files with 242 additions and 111 deletions

View File

@@ -50,20 +50,6 @@
settings:fillColor="#c0ba7f3e" settings:fillColor="#c0ba7f3e"
settings:fillColorSecondary="#0000" /> settings:fillColorSecondary="#0000" />
<com.android.settings.widget.ChartSweepView
android:id="@+id/sweep_left"
android:layout_width="wrap_content"
android:layout_height="match_parent"
settings:sweepDrawable="@drawable/data_sweep_left"
settings:followAxis="horizontal" />
<com.android.settings.widget.ChartSweepView
android:id="@+id/sweep_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
settings:sweepDrawable="@drawable/data_sweep_right"
settings:followAxis="horizontal" />
<com.android.settings.widget.ChartSweepView <com.android.settings.widget.ChartSweepView
android:id="@+id/sweep_warning" android:id="@+id/sweep_warning"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -84,4 +70,18 @@
settings:labelTemplate="@string/data_usage_sweep_limit" settings:labelTemplate="@string/data_usage_sweep_limit"
settings:labelColor="#c01a2c" /> settings:labelColor="#c01a2c" />
<com.android.settings.widget.ChartSweepView
android:id="@+id/sweep_left"
android:layout_width="wrap_content"
android:layout_height="match_parent"
settings:sweepDrawable="@drawable/data_sweep_left"
settings:followAxis="horizontal" />
<com.android.settings.widget.ChartSweepView
android:id="@+id/sweep_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
settings:sweepDrawable="@drawable/data_sweep_right"
settings:followAxis="horizontal" />
</com.android.settings.widget.DataUsageChartView> </com.android.settings.widget.DataUsageChartView>

View 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cycles"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="16dip"
android:paddingRight="16dip">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/data_usage_cycle" />
<Spinner
android:id="@+id/cycles_spinner"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>

View File

@@ -32,28 +32,19 @@
android:divider="?android:attr/listDivider" /> android:divider="?android:attr/listDivider" />
</FrameLayout> </FrameLayout>
<LinearLayout <include layout="@layout/data_usage_cycles" />
android:layout_width="match_parent" <include layout="@layout/data_usage_chart" />
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="16dip"
android:paddingRight="16dip">
<TextView <TextView
android:layout_width="wrap_content" android:id="@+id/usage_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:paddingLeft="16dip"
android:text="@string/data_usage_cycle" /> android:paddingRight="16dip"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:textAppearance="?android:attr/textAppearanceSmall" />
<Spinner
android:id="@+id/cycles"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<include layout="@layout/data_usage_chart" />
<include layout="@layout/data_usage_detail" /> <include layout="@layout/data_usage_detail" />
</LinearLayout> </LinearLayout>

View File

@@ -17,20 +17,22 @@
<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:padding="8dip" android:paddingLeft="16dip"
android:paddingRight="16dip"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:columnCount="2"> android:columnCount="2">
<!-- TODO: consider using canShrink -->
<TextView <TextView
android:id="@android:id/title" android:id="@android:id/title"
android:layout_width="0dip"
android:layout_gravity="fill_horizontal"
android:singleLine="true" android:singleLine="true"
android:ellipsize="marquee" android:ellipsize="marquee"
android:layout_columnFlexibility="canStretch"
android:textAppearance="?android:attr/textAppearanceMedium" /> android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView <TextView
android:id="@android:id/summary" android:id="@android:id/summary"
android:layout_gravity="right"
android:layout_marginLeft="8dip" android:layout_marginLeft="8dip"
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />

View File

@@ -3464,6 +3464,8 @@ found in the list of installed applications.</string>
<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] --> <!-- 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] -->
<string name="data_usage_total_during_range">Data usage: <xliff:g id="total" example="128KB">%1$s</xliff:g> between <xliff:g id="range" example="Jul 1 - Jul 31">%2$s</xliff:g></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>

View File

@@ -128,6 +128,7 @@ public class DataUsageSummary extends Fragment {
private static final boolean LOGD = true; private static final boolean LOGD = true;
// TODO: remove this testing code // TODO: remove this testing code
private static final boolean TEST_ANIM = false;
private static final boolean TEST_RADIOS = false; private static final boolean TEST_RADIOS = false;
private static final String TEST_RADIOS_PROP = "test.radios"; private static final String TEST_RADIOS_PROP = "test.radios";
@@ -175,10 +176,12 @@ public class DataUsageSummary extends Fragment {
private CheckBox mDisableAtLimit; private CheckBox mDisableAtLimit;
private View mDisableAtLimitView; private View mDisableAtLimitView;
private View mCycleView;
private Spinner mCycleSpinner; private Spinner mCycleSpinner;
private CycleAdapter mCycleAdapter; private CycleAdapter mCycleAdapter;
private DataUsageChartView mChart; private DataUsageChartView mChart;
private TextView mUsageSummary;
private View mAppDetail; private View mAppDetail;
private TextView mAppTitle; private TextView mAppTitle;
@@ -272,7 +275,8 @@ public class DataUsageSummary extends Fragment {
} }
// bind cycle dropdown // bind cycle dropdown
mCycleSpinner = (Spinner) mHeader.findViewById(R.id.cycles); mCycleView = mHeader.findViewById(R.id.cycles);
mCycleSpinner = (Spinner) mCycleView.findViewById(R.id.cycles_spinner);
mCycleAdapter = new CycleAdapter(context); mCycleAdapter = new CycleAdapter(context);
mCycleSpinner.setAdapter(mCycleAdapter); mCycleSpinner.setAdapter(mCycleAdapter);
mCycleSpinner.setOnItemSelectedListener(mCycleListener); mCycleSpinner.setOnItemSelectedListener(mCycleListener);
@@ -282,12 +286,12 @@ public class DataUsageSummary extends Fragment {
{ {
// bind app detail controls // bind app detail controls
mAppDetail = view.findViewById(R.id.app_detail); mAppDetail = mHeader.findViewById(R.id.app_detail);
mAppTitle = (TextView) view.findViewById(R.id.app_title); mAppTitle = (TextView) mAppDetail.findViewById(R.id.app_title);
mAppSubtitle = (TextView) view.findViewById(R.id.app_subtitle); mAppSubtitle = (TextView) mAppDetail.findViewById(R.id.app_subtitle);
mAppSwitches = (LinearLayout) view.findViewById(R.id.app_switches); mAppSwitches = (LinearLayout) mAppDetail.findViewById(R.id.app_switches);
mAppSettings = (Button) view.findViewById(R.id.app_settings); mAppSettings = (Button) mAppDetail.findViewById(R.id.app_settings);
mAppSettings.setOnClickListener(mAppSettingsListener); mAppSettings.setOnClickListener(mAppSettingsListener);
mAppRestrict = new CheckBox(inflater.getContext()); mAppRestrict = new CheckBox(inflater.getContext());
@@ -300,8 +304,10 @@ public class DataUsageSummary extends Fragment {
mAppSwitches.addView(mAppRestrictView); mAppSwitches.addView(mAppRestrictView);
} }
mUsageSummary = (TextView) mHeader.findViewById(R.id.usage_summary);
// only assign layout transitions once first layout is finished // only assign layout transitions once first layout is finished
mHeader.getViewTreeObserver().addOnGlobalLayoutListener(mFirstLayoutListener); mListView.getViewTreeObserver().addOnGlobalLayoutListener(mFirstLayoutListener);
mAdapter = new DataUsageAdapter(); mAdapter = new DataUsageAdapter();
mListView.setOnItemClickListener(mListListener); mListView.setOnItemClickListener(mListListener);
@@ -443,19 +449,28 @@ public class DataUsageSummary extends Fragment {
private OnGlobalLayoutListener mFirstLayoutListener = new OnGlobalLayoutListener() { private OnGlobalLayoutListener mFirstLayoutListener = new OnGlobalLayoutListener() {
/** {@inheritDoc} */ /** {@inheritDoc} */
public void onGlobalLayout() { public void onGlobalLayout() {
mHeader.getViewTreeObserver().removeGlobalOnLayoutListener(mFirstLayoutListener); mListView.getViewTreeObserver().removeGlobalOnLayoutListener(mFirstLayoutListener);
mTabsContainer.setLayoutTransition(new LayoutTransition()); mTabsContainer.setLayoutTransition(buildLayoutTransition());
mHeader.setLayoutTransition(new LayoutTransition()); mHeader.setLayoutTransition(buildLayoutTransition());
mNetworkSwitchesContainer.setLayoutTransition(new LayoutTransition()); mNetworkSwitchesContainer.setLayoutTransition(buildLayoutTransition());
final LayoutTransition chartTransition = new LayoutTransition(); final LayoutTransition chartTransition = buildLayoutTransition();
chartTransition.setStartDelay(LayoutTransition.APPEARING, 0); chartTransition.setStartDelay(LayoutTransition.APPEARING, 0);
chartTransition.setStartDelay(LayoutTransition.DISAPPEARING, 0); chartTransition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
mChart.setLayoutTransition(chartTransition); mChart.setLayoutTransition(chartTransition);
} }
}; };
private static LayoutTransition buildLayoutTransition() {
final LayoutTransition transition = new LayoutTransition();
if (TEST_ANIM) {
transition.setDuration(1500);
}
transition.setAnimateParentHierarchy(false);
return transition;
}
/** /**
* Rebuild all tabs based on {@link NetworkPolicyEditor} and * Rebuild all tabs based on {@link NetworkPolicyEditor} and
* {@link #mShowWifi}, hiding the tabs entirely when applicable. Selects * {@link #mShowWifi}, hiding the tabs entirely when applicable. Selects
@@ -668,7 +683,7 @@ public class DataUsageSummary extends Fragment {
updateDetailData(); updateDetailData();
final Context context = getActivity(); final Context context = getActivity();
if (NetworkPolicyManager.isUidValidForPolicy(context, mUid)) { if (NetworkPolicyManager.isUidValidForPolicy(context, mUid) && !getRestrictBackground()) {
mAppRestrictView.setVisibility(View.VISIBLE); mAppRestrictView.setVisibility(View.VISIBLE);
mAppRestrict.setChecked(getAppRestrictBackground()); mAppRestrict.setChecked(getAppRestrictBackground());
@@ -710,13 +725,22 @@ public class DataUsageSummary extends Fragment {
} }
private boolean getRestrictBackground() { private boolean getRestrictBackground() {
return !mConnService.getBackgroundDataSetting(); try {
return mPolicyService.getRestrictBackground();
} catch (RemoteException e) {
Log.w(TAG, "problem talking with policy service: " + e);
return false;
}
} }
private void setRestrictBackground(boolean restrictBackground) { private void setRestrictBackground(boolean restrictBackground) {
if (LOGD) Log.d(TAG, "setRestrictBackground()"); if (LOGD) Log.d(TAG, "setRestrictBackground()");
mConnService.setBackgroundDataSetting(!restrictBackground); try {
mPolicyService.setRestrictBackground(restrictBackground);
mMenuRestrictBackground.setChecked(restrictBackground); mMenuRestrictBackground.setChecked(restrictBackground);
} catch (RemoteException e) {
Log.w(TAG, "problem talking with policy service: " + e);
}
} }
private boolean getAppRestrictBackground() { private boolean getAppRestrictBackground() {
@@ -732,7 +756,7 @@ public class DataUsageSummary extends Fragment {
} }
private void setAppRestrictBackground(boolean restrictBackground) { private void setAppRestrictBackground(boolean restrictBackground) {
if (LOGD) Log.d(TAG, "setRestrictBackground()"); if (LOGD) Log.d(TAG, "setAppRestrictBackground()");
try { try {
mPolicyService.setUidPolicy( mPolicyService.setUidPolicy(
mUid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE); mUid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
@@ -909,7 +933,7 @@ public class DataUsageSummary extends Fragment {
// update chart to show selected cycle, and update detail data // update chart to show selected cycle, and update detail data
// to match updated sweep bounds. // to match updated sweep bounds.
mChart.setVisibleRange(cycle.start, cycle.end, mHistory.getEnd()); mChart.setVisibleRange(cycle.start, cycle.end);
updateDetailData(); updateDetailData();
} }
@@ -932,28 +956,40 @@ public class DataUsageSummary extends Fragment {
final long start = mChart.getInspectStart(); final long start = mChart.getInspectStart();
final long end = mChart.getInspectEnd(); final long end = mChart.getInspectEnd();
final long now = System.currentTimeMillis();
final Context context = getActivity();
final NetworkStatsHistory.Entry entry;
if (isAppDetailMode()) { if (isAppDetailMode()) {
if (mDetailHistory != null) { if (mDetailHistory != null) {
final Context context = mChart.getContext(); entry = mDetailHistory.getValues(start, end, now, null);
final long now = System.currentTimeMillis();
final NetworkStatsHistory.Entry entry = mDetailHistory.getValues(
start, end, now, null);
mAppSubtitle.setText( mAppSubtitle.setText(
getString(R.string.data_usage_received_sent, getString(R.string.data_usage_received_sent,
Formatter.formatFileSize(context, entry.rxBytes), Formatter.formatFileSize(context, entry.rxBytes),
Formatter.formatFileSize(context, entry.txBytes))); Formatter.formatFileSize(context, entry.txBytes)));
} else {
entry = null;
} }
getLoaderManager().destroyLoader(LOADER_SUMMARY); getLoaderManager().destroyLoader(LOADER_SUMMARY);
} else { } else {
entry = mHistory.getValues(start, end, now, null);
// kick off loader for detailed stats // kick off loader for detailed stats
getLoaderManager().restartLoader(LOADER_SUMMARY, getLoaderManager().restartLoader(LOADER_SUMMARY,
SummaryForAllUidLoader.buildArgs(mTemplate, start, end), mSummaryForAllUid); SummaryForAllUidLoader.buildArgs(mTemplate, start, end), mSummaryForAllUid);
} }
final long totalBytes = entry != null ? entry.rxBytes + entry.txBytes : 0;
final String totalPhrase = Formatter.formatFileSize(context, totalBytes);
final String rangePhrase = formatDateRangeUtc(context, start, end);
mUsageSummary.setText(
getString(R.string.data_usage_total_during_range, totalPhrase, rangePhrase));
} }
private final LoaderCallbacks<NetworkStats> mSummaryForAllUid = new LoaderCallbacks< private final LoaderCallbacks<NetworkStats> mSummaryForAllUid = new LoaderCallbacks<
@@ -1022,10 +1058,6 @@ public class DataUsageSummary extends Fragment {
public long start; public long start;
public long end; public long end;
private static final StringBuilder sBuilder = new StringBuilder(50);
private static final java.util.Formatter sFormatter = new java.util.Formatter(
sBuilder, Locale.getDefault());
CycleItem(CharSequence label) { CycleItem(CharSequence label) {
this.label = label; this.label = label;
} }
@@ -1036,21 +1068,30 @@ public class DataUsageSummary extends Fragment {
this.end = end; this.end = end;
} }
private static String formatDateRangeUtc(Context context, long start, long end) {
synchronized (sBuilder) {
sBuilder.setLength(0);
return DateUtils.formatDateRange(context, sFormatter, start, end,
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH,
Time.TIMEZONE_UTC).toString();
}
}
@Override @Override
public String toString() { public String toString() {
return label.toString(); return label.toString();
} }
} }
private static final StringBuilder sBuilder = new StringBuilder(50);
private static final java.util.Formatter sFormatter = new java.util.Formatter(
sBuilder, Locale.getDefault());
private static String formatDateRangeUtc(Context context, long start, long end) {
synchronized (sBuilder) {
int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH;
if (Time.getJulianDay(start, 0) == Time.getJulianDay(end, 0)) {
// when times are on same day, include time detail
flags |= DateUtils.FORMAT_SHOW_TIME;
}
sBuilder.setLength(0);
return DateUtils.formatDateRange(
context, sFormatter, start, end, flags, Time.TIMEZONE_UTC).toString();
}
}
/** /**
* Special-case data usage cycle that triggers dialog to change * Special-case data usage cycle that triggers dialog to change
* {@link NetworkPolicy#cycleDay}. * {@link NetworkPolicy#cycleDay}.
@@ -1366,7 +1407,7 @@ public class DataUsageSummary extends Fragment {
/** /**
* Dialog to request user confirmation before setting * Dialog to request user confirmation before setting
* {@link ConnectivityManager#setBackgroundDataSetting(boolean)}. * {@link INetworkPolicyManager#setRestrictBackground(boolean)}.
*/ */
public static class ConfirmRestrictFragment extends DialogFragment { public static class ConfirmRestrictFragment extends DialogFragment {
public static void show(DataUsageSummary parent) { public static void show(DataUsageSummary parent) {

View File

@@ -61,8 +61,11 @@ public class ChartSweepView extends FrameLayout {
private ChartAxis mAxis; private ChartAxis mAxis;
private long mValue; private long mValue;
private ChartSweepView mClampAfter; private long mValidAfter;
private ChartSweepView mClampBefore; private long mValidBefore;
private ChartSweepView mValidAfterDynamic;
private ChartSweepView mValidBeforeDynamic;
private long mValidBufferArea;
public static final int HORIZONTAL = 0; public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1; public static final int VERTICAL = 1;
@@ -259,12 +262,25 @@ public class ChartSweepView extends FrameLayout {
} }
} }
public void setClampAfter(ChartSweepView clampAfter) { /**
mClampAfter = clampAfter; * Set valid range this sweep can move within, in {@link #mAxis} values. The
* most restrictive combination of all valid ranges is used.
*/
public void setValidRange(long validAfter, long validBefore) {
mValidAfter = validAfter;
mValidBefore = validBefore;
} }
public void setClampBefore(ChartSweepView clampBefore) { /**
mClampBefore = clampBefore; * Set valid range this sweep can move within, defined by the given
* {@link ChartSweepView}. The most restrictive combination of all valid
* ranges is used.
*/
public void setValidRangeDynamic(
ChartSweepView validAfter, ChartSweepView validBefore, long bufferArea) {
mValidAfterDynamic = validAfter;
mValidBeforeDynamic = validBefore;
mValidBufferArea = bufferArea;
} }
@Override @Override
@@ -285,6 +301,12 @@ public class ChartSweepView extends FrameLayout {
if (accept) { if (accept) {
mTracking = event.copy(); mTracking = event.copy();
// starting drag should activate entire chart
if (!parent.isActivated()) {
parent.setActivated(true);
}
return true; return true;
} else { } else {
return false; return false;
@@ -336,31 +358,52 @@ public class ChartSweepView extends FrameLayout {
} }
} }
@Override
public void addOnLayoutChangeListener(OnLayoutChangeListener listener) {
// ignored to keep LayoutTransition from animating us
}
@Override
public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) {
// ignored to keep LayoutTransition from animating us
}
private long getValidAfterValue() {
final ChartSweepView dynamic = mValidAfterDynamic;
final boolean dynamicEnabled = dynamic != null && dynamic.isEnabled();
return Math.max(mValidAfter,
dynamicEnabled ? dynamic.getValue() + mValidBufferArea : Long.MIN_VALUE);
}
private long getValidBeforeValue() {
final ChartSweepView dynamic = mValidBeforeDynamic;
final boolean dynamicEnabled = dynamic != null && dynamic.isEnabled();
return Math.min(mValidBefore,
dynamicEnabled ? dynamic.getValue() - mValidBufferArea : Long.MAX_VALUE);
}
/** /**
* Compute {@link Rect} in {@link #getParent()} coordinates that we should * Compute {@link Rect} in {@link #getParent()} coordinates that we should
* be clamped inside of, usually from {@link #setClampAfter(ChartSweepView)} * be clamped inside of, usually from {@link #setValidRange(long, long)}
* style rules. * style rules.
*/ */
private Rect computeClampRect(Rect parentContent) { private Rect computeClampRect(Rect parentContent) {
final Rect clampRect = new Rect(parentContent); final Rect clampRect = new Rect(parentContent);
final ChartSweepView after = mClampAfter; float validAfterPoint = mAxis.convertToPoint(getValidAfterValue());
final ChartSweepView before = mClampBefore; float validBeforePoint = mAxis.convertToPoint(getValidBeforeValue());
if (validAfterPoint > validBeforePoint) {
float swap = validBeforePoint;
validBeforePoint = validAfterPoint;
validAfterPoint = swap;
}
if (mFollowAxis == VERTICAL) { if (mFollowAxis == VERTICAL) {
if (after != null) { clampRect.bottom = clampRect.top + (int) validBeforePoint;
clampRect.top += after.getPoint(); clampRect.top += validAfterPoint;
}
if (before != null) {
clampRect.bottom -= clampRect.height() - before.getPoint();
}
} else { } else {
if (after != null) { clampRect.right = clampRect.left + (int) validBeforePoint;
clampRect.left += after.getPoint(); clampRect.left += validAfterPoint;
}
if (before != null) {
clampRect.right -= clampRect.width() - before.getPoint();
}
} }
return clampRect; return clampRect;
} }

View File

@@ -16,6 +16,8 @@
package com.android.settings.widget; package com.android.settings.widget;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.net.NetworkPolicy; import android.net.NetworkPolicy;
@@ -47,6 +49,8 @@ public class DataUsageChartView extends ChartView {
private ChartNetworkSeriesView mSeries; private ChartNetworkSeriesView mSeries;
private ChartNetworkSeriesView mDetailSeries; private ChartNetworkSeriesView mDetailSeries;
private NetworkStatsHistory mHistory;
private ChartSweepView mSweepLeft; private ChartSweepView mSweepLeft;
private ChartSweepView mSweepRight; private ChartSweepView mSweepRight;
private ChartSweepView mSweepWarning; private ChartSweepView mSweepWarning;
@@ -88,10 +92,14 @@ public class DataUsageChartView extends ChartView {
mSweepWarning = (ChartSweepView) findViewById(R.id.sweep_warning); mSweepWarning = (ChartSweepView) findViewById(R.id.sweep_warning);
// prevent sweeps from crossing each other // prevent sweeps from crossing each other
mSweepLeft.setClampBefore(mSweepRight); mSweepLeft.setValidRangeDynamic(null, mSweepRight, HOUR_IN_MILLIS);
mSweepRight.setClampAfter(mSweepLeft); mSweepRight.setValidRangeDynamic(mSweepLeft, null, HOUR_IN_MILLIS);
mSweepLimit.setClampBefore(mSweepWarning);
mSweepWarning.setClampAfter(mSweepLimit); // TODO: assign these ranges as user changes data axis
mSweepWarning.setValidRange(0L, 5 * GB_IN_BYTES);
mSweepWarning.setValidRangeDynamic(null, mSweepLimit, MB_IN_BYTES);
mSweepLimit.setValidRange(0L, 5 * GB_IN_BYTES);
mSweepLimit.setValidRangeDynamic(mSweepWarning, null, MB_IN_BYTES);
mSweepLeft.addOnSweepListener(mSweepListener); mSweepLeft.addOnSweepListener(mSweepListener);
mSweepRight.addOnSweepListener(mSweepListener); mSweepRight.addOnSweepListener(mSweepListener);
@@ -116,6 +124,7 @@ public class DataUsageChartView extends ChartView {
public void bindNetworkStats(NetworkStatsHistory stats) { public void bindNetworkStats(NetworkStatsHistory stats) {
mSeries.bindNetworkStats(stats); mSeries.bindNetworkStats(stats);
mHistory = stats;
updatePrimaryRange(); updatePrimaryRange();
requestLayout(); requestLayout();
} }
@@ -197,15 +206,6 @@ public class DataUsageChartView extends ChartView {
} }
} }
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (!isActivated()) {
return true;
} else {
return super.onInterceptTouchEvent(ev);
}
}
public long getInspectStart() { public long getInspectStart() {
return mSweepLeft.getValue(); return mSweepLeft.getValue();
} }
@@ -222,18 +222,33 @@ public class DataUsageChartView extends ChartView {
return mSweepLimit.getValue(); return mSweepLimit.getValue();
} }
private long getStatsStart() {
return mHistory != null ? mHistory.getStart() : Long.MIN_VALUE;
}
private long getStatsEnd() {
return mHistory != null ? mHistory.getEnd() : Long.MAX_VALUE;
}
/** /**
* Set the exact time range that should be displayed, updating how * Set the exact time range that should be displayed, updating how
* {@link ChartNetworkSeriesView} paints. Moves inspection ranges to be the * {@link ChartNetworkSeriesView} paints. Moves inspection ranges to be the
* last "week" of available data, without triggering listener events. * last "week" of available data, without triggering listener events.
*/ */
public void setVisibleRange(long start, long end, long dataBoundary) { public void setVisibleRange(long visibleStart, long visibleEnd) {
mHoriz.setBounds(start, end); mHoriz.setBounds(visibleStart, visibleEnd);
final long validStart = Math.max(visibleStart, getStatsStart());
final long validEnd = Math.min(visibleEnd, getStatsEnd());
// prevent time sweeps from leaving valid data
mSweepLeft.setValidRange(validStart, validEnd);
mSweepRight.setValidRange(validStart, validEnd);
// default sweeps to last week of data // default sweeps to last week of data
final long halfRange = (end + start) / 2; final long halfRange = (visibleEnd + visibleStart) / 2;
final long sweepMax = Math.min(end, dataBoundary); final long sweepMax = validEnd;
final long sweepMin = Math.max(start, (sweepMax - DateUtils.WEEK_IN_MILLIS)); final long sweepMin = Math.max(visibleStart, (sweepMax - DateUtils.WEEK_IN_MILLIS));
mSweepLeft.setValue(sweepMin); mSweepLeft.setValue(sweepMin);
mSweepRight.setValue(sweepMax); mSweepRight.setValue(sweepMax);