Merge "Data usage fit and finish."

This commit is contained in:
Jeff Sharkey
2011-07-27 22:08:05 -07:00
committed by Android (Google) Code Review
8 changed files with 242 additions and 111 deletions

View File

@@ -128,6 +128,7 @@ public class DataUsageSummary extends Fragment {
private static final boolean LOGD = true;
// TODO: remove this testing code
private static final boolean TEST_ANIM = false;
private static final boolean TEST_RADIOS = false;
private static final String TEST_RADIOS_PROP = "test.radios";
@@ -175,10 +176,12 @@ public class DataUsageSummary extends Fragment {
private CheckBox mDisableAtLimit;
private View mDisableAtLimitView;
private View mCycleView;
private Spinner mCycleSpinner;
private CycleAdapter mCycleAdapter;
private DataUsageChartView mChart;
private TextView mUsageSummary;
private View mAppDetail;
private TextView mAppTitle;
@@ -272,7 +275,8 @@ public class DataUsageSummary extends Fragment {
}
// 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);
mCycleSpinner.setAdapter(mCycleAdapter);
mCycleSpinner.setOnItemSelectedListener(mCycleListener);
@@ -282,12 +286,12 @@ public class DataUsageSummary extends Fragment {
{
// bind app detail controls
mAppDetail = view.findViewById(R.id.app_detail);
mAppTitle = (TextView) view.findViewById(R.id.app_title);
mAppSubtitle = (TextView) view.findViewById(R.id.app_subtitle);
mAppSwitches = (LinearLayout) view.findViewById(R.id.app_switches);
mAppDetail = mHeader.findViewById(R.id.app_detail);
mAppTitle = (TextView) mAppDetail.findViewById(R.id.app_title);
mAppSubtitle = (TextView) mAppDetail.findViewById(R.id.app_subtitle);
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);
mAppRestrict = new CheckBox(inflater.getContext());
@@ -300,8 +304,10 @@ public class DataUsageSummary extends Fragment {
mAppSwitches.addView(mAppRestrictView);
}
mUsageSummary = (TextView) mHeader.findViewById(R.id.usage_summary);
// only assign layout transitions once first layout is finished
mHeader.getViewTreeObserver().addOnGlobalLayoutListener(mFirstLayoutListener);
mListView.getViewTreeObserver().addOnGlobalLayoutListener(mFirstLayoutListener);
mAdapter = new DataUsageAdapter();
mListView.setOnItemClickListener(mListListener);
@@ -443,19 +449,28 @@ public class DataUsageSummary extends Fragment {
private OnGlobalLayoutListener mFirstLayoutListener = new OnGlobalLayoutListener() {
/** {@inheritDoc} */
public void onGlobalLayout() {
mHeader.getViewTreeObserver().removeGlobalOnLayoutListener(mFirstLayoutListener);
mListView.getViewTreeObserver().removeGlobalOnLayoutListener(mFirstLayoutListener);
mTabsContainer.setLayoutTransition(new LayoutTransition());
mHeader.setLayoutTransition(new LayoutTransition());
mNetworkSwitchesContainer.setLayoutTransition(new LayoutTransition());
mTabsContainer.setLayoutTransition(buildLayoutTransition());
mHeader.setLayoutTransition(buildLayoutTransition());
mNetworkSwitchesContainer.setLayoutTransition(buildLayoutTransition());
final LayoutTransition chartTransition = new LayoutTransition();
final LayoutTransition chartTransition = buildLayoutTransition();
chartTransition.setStartDelay(LayoutTransition.APPEARING, 0);
chartTransition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
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
* {@link #mShowWifi}, hiding the tabs entirely when applicable. Selects
@@ -668,7 +683,7 @@ public class DataUsageSummary extends Fragment {
updateDetailData();
final Context context = getActivity();
if (NetworkPolicyManager.isUidValidForPolicy(context, mUid)) {
if (NetworkPolicyManager.isUidValidForPolicy(context, mUid) && !getRestrictBackground()) {
mAppRestrictView.setVisibility(View.VISIBLE);
mAppRestrict.setChecked(getAppRestrictBackground());
@@ -710,13 +725,22 @@ public class DataUsageSummary extends Fragment {
}
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) {
if (LOGD) Log.d(TAG, "setRestrictBackground()");
mConnService.setBackgroundDataSetting(!restrictBackground);
mMenuRestrictBackground.setChecked(restrictBackground);
try {
mPolicyService.setRestrictBackground(restrictBackground);
mMenuRestrictBackground.setChecked(restrictBackground);
} catch (RemoteException e) {
Log.w(TAG, "problem talking with policy service: " + e);
}
}
private boolean getAppRestrictBackground() {
@@ -732,7 +756,7 @@ public class DataUsageSummary extends Fragment {
}
private void setAppRestrictBackground(boolean restrictBackground) {
if (LOGD) Log.d(TAG, "setRestrictBackground()");
if (LOGD) Log.d(TAG, "setAppRestrictBackground()");
try {
mPolicyService.setUidPolicy(
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
// to match updated sweep bounds.
mChart.setVisibleRange(cycle.start, cycle.end, mHistory.getEnd());
mChart.setVisibleRange(cycle.start, cycle.end);
updateDetailData();
}
@@ -932,28 +956,40 @@ public class DataUsageSummary extends Fragment {
final long start = mChart.getInspectStart();
final long end = mChart.getInspectEnd();
final long now = System.currentTimeMillis();
final Context context = getActivity();
final NetworkStatsHistory.Entry entry;
if (isAppDetailMode()) {
if (mDetailHistory != null) {
final Context context = mChart.getContext();
final long now = System.currentTimeMillis();
final NetworkStatsHistory.Entry entry = mDetailHistory.getValues(
start, end, now, null);
entry = mDetailHistory.getValues(start, end, now, null);
mAppSubtitle.setText(
getString(R.string.data_usage_received_sent,
Formatter.formatFileSize(context, entry.rxBytes),
Formatter.formatFileSize(context, entry.txBytes)));
} else {
entry = null;
}
getLoaderManager().destroyLoader(LOADER_SUMMARY);
} else {
entry = mHistory.getValues(start, end, now, null);
// kick off loader for detailed stats
getLoaderManager().restartLoader(LOADER_SUMMARY,
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<
@@ -1022,10 +1058,6 @@ public class DataUsageSummary extends Fragment {
public long start;
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) {
this.label = label;
}
@@ -1036,21 +1068,30 @@ public class DataUsageSummary extends Fragment {
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
public String 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
* {@link NetworkPolicy#cycleDay}.
@@ -1366,7 +1407,7 @@ public class DataUsageSummary extends Fragment {
/**
* Dialog to request user confirmation before setting
* {@link ConnectivityManager#setBackgroundDataSetting(boolean)}.
* {@link INetworkPolicyManager#setRestrictBackground(boolean)}.
*/
public static class ConfirmRestrictFragment extends DialogFragment {
public static void show(DataUsageSummary parent) {

View File

@@ -61,8 +61,11 @@ public class ChartSweepView extends FrameLayout {
private ChartAxis mAxis;
private long mValue;
private ChartSweepView mClampAfter;
private ChartSweepView mClampBefore;
private long mValidAfter;
private long mValidBefore;
private ChartSweepView mValidAfterDynamic;
private ChartSweepView mValidBeforeDynamic;
private long mValidBufferArea;
public static final int HORIZONTAL = 0;
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
@@ -285,6 +301,12 @@ public class ChartSweepView extends FrameLayout {
if (accept) {
mTracking = event.copy();
// starting drag should activate entire chart
if (!parent.isActivated()) {
parent.setActivated(true);
}
return true;
} else {
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
* be clamped inside of, usually from {@link #setClampAfter(ChartSweepView)}
* be clamped inside of, usually from {@link #setValidRange(long, long)}
* style rules.
*/
private Rect computeClampRect(Rect parentContent) {
final Rect clampRect = new Rect(parentContent);
final ChartSweepView after = mClampAfter;
final ChartSweepView before = mClampBefore;
float validAfterPoint = mAxis.convertToPoint(getValidAfterValue());
float validBeforePoint = mAxis.convertToPoint(getValidBeforeValue());
if (validAfterPoint > validBeforePoint) {
float swap = validBeforePoint;
validBeforePoint = validAfterPoint;
validAfterPoint = swap;
}
if (mFollowAxis == VERTICAL) {
if (after != null) {
clampRect.top += after.getPoint();
}
if (before != null) {
clampRect.bottom -= clampRect.height() - before.getPoint();
}
clampRect.bottom = clampRect.top + (int) validBeforePoint;
clampRect.top += validAfterPoint;
} else {
if (after != null) {
clampRect.left += after.getPoint();
}
if (before != null) {
clampRect.right -= clampRect.width() - before.getPoint();
}
clampRect.right = clampRect.left + (int) validBeforePoint;
clampRect.left += validAfterPoint;
}
return clampRect;
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.widget;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import android.content.Context;
import android.content.res.Resources;
import android.net.NetworkPolicy;
@@ -47,6 +49,8 @@ public class DataUsageChartView extends ChartView {
private ChartNetworkSeriesView mSeries;
private ChartNetworkSeriesView mDetailSeries;
private NetworkStatsHistory mHistory;
private ChartSweepView mSweepLeft;
private ChartSweepView mSweepRight;
private ChartSweepView mSweepWarning;
@@ -88,10 +92,14 @@ public class DataUsageChartView extends ChartView {
mSweepWarning = (ChartSweepView) findViewById(R.id.sweep_warning);
// prevent sweeps from crossing each other
mSweepLeft.setClampBefore(mSweepRight);
mSweepRight.setClampAfter(mSweepLeft);
mSweepLimit.setClampBefore(mSweepWarning);
mSweepWarning.setClampAfter(mSweepLimit);
mSweepLeft.setValidRangeDynamic(null, mSweepRight, HOUR_IN_MILLIS);
mSweepRight.setValidRangeDynamic(mSweepLeft, null, HOUR_IN_MILLIS);
// 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);
mSweepRight.addOnSweepListener(mSweepListener);
@@ -116,6 +124,7 @@ public class DataUsageChartView extends ChartView {
public void bindNetworkStats(NetworkStatsHistory stats) {
mSeries.bindNetworkStats(stats);
mHistory = stats;
updatePrimaryRange();
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() {
return mSweepLeft.getValue();
}
@@ -222,18 +222,33 @@ public class DataUsageChartView extends ChartView {
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
* {@link ChartNetworkSeriesView} paints. Moves inspection ranges to be the
* last "week" of available data, without triggering listener events.
*/
public void setVisibleRange(long start, long end, long dataBoundary) {
mHoriz.setBounds(start, end);
public void setVisibleRange(long visibleStart, long visibleEnd) {
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
final long halfRange = (end + start) / 2;
final long sweepMax = Math.min(end, dataBoundary);
final long sweepMin = Math.max(start, (sweepMax - DateUtils.WEEK_IN_MILLIS));
final long halfRange = (visibleEnd + visibleStart) / 2;
final long sweepMax = validEnd;
final long sweepMin = Math.max(visibleStart, (sweepMax - DateUtils.WEEK_IN_MILLIS));
mSweepLeft.setValue(sweepMin);
mSweepRight.setValue(sweepMax);