Fix animation bugs, stop disabled sweep touches.
Change sweep drawables to crossfade correctly between states, and work around 4946591 by nesting container one level deeper. Also wait until first layout pass is finished before applying LayoutTransition. Prevent touches from reaching sweeps when chart is disabled. Also bring back log scale for data. Change-Id: I2194714ab075fd32525681119f30427c1b96fc50
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:enterFadeDuration="@android:integer/config_mediumAnimTime"
|
||||||
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
|
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
|
||||||
|
|
||||||
<item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_left_activated" />
|
<item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_left_activated" />
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:enterFadeDuration="@android:integer/config_mediumAnimTime"
|
||||||
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
|
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
|
||||||
|
|
||||||
<item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_limit_activated" />
|
<item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_limit_activated" />
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:enterFadeDuration="@android:integer/config_mediumAnimTime"
|
||||||
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
|
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
|
||||||
|
|
||||||
<item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_right_activated" />
|
<item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_right_activated" />
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:enterFadeDuration="@android:integer/config_mediumAnimTime"
|
||||||
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
|
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
|
||||||
|
|
||||||
<item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_warning_activated" />
|
<item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_warning_activated" />
|
||||||
|
@@ -19,13 +19,18 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<FrameLayout
|
||||||
android:id="@+id/network_switches"
|
android:id="@+id/network_switches_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:orientation="vertical"
|
<LinearLayout
|
||||||
android:showDividers="middle|end"
|
android:id="@+id/network_switches"
|
||||||
android:divider="?android:attr/listDivider" />
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:showDividers="middle|end"
|
||||||
|
android:divider="?android:attr/listDivider" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/tabs_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
@@ -71,6 +71,7 @@ import android.view.MenuItem;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.AdapterView.OnItemClickListener;
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
import android.widget.AdapterView.OnItemSelectedListener;
|
import android.widget.AdapterView.OnItemSelectedListener;
|
||||||
@@ -136,12 +137,14 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private SharedPreferences mPrefs;
|
private SharedPreferences mPrefs;
|
||||||
|
|
||||||
private TabHost mTabHost;
|
private TabHost mTabHost;
|
||||||
|
private ViewGroup mTabsContainer;
|
||||||
private TabWidget mTabWidget;
|
private TabWidget mTabWidget;
|
||||||
private ListView mListView;
|
private ListView mListView;
|
||||||
private DataUsageAdapter mAdapter;
|
private DataUsageAdapter mAdapter;
|
||||||
|
|
||||||
private ViewGroup mHeader;
|
private ViewGroup mHeader;
|
||||||
|
|
||||||
|
private ViewGroup mNetworkSwitchesContainer;
|
||||||
private LinearLayout mNetworkSwitches;
|
private LinearLayout mNetworkSwitches;
|
||||||
private Switch mDataEnabled;
|
private Switch mDataEnabled;
|
||||||
private View mDataEnabledView;
|
private View mDataEnabledView;
|
||||||
@@ -176,6 +179,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private NetworkStatsHistory mHistory;
|
private NetworkStatsHistory mHistory;
|
||||||
private NetworkStatsHistory mDetailHistory;
|
private NetworkStatsHistory mDetailHistory;
|
||||||
|
|
||||||
|
private String mCurrentTab = null;
|
||||||
private String mIntentTab = null;
|
private String mIntentTab = null;
|
||||||
|
|
||||||
/** Flag used to ignore listeners during binding. */
|
/** Flag used to ignore listeners during binding. */
|
||||||
@@ -209,6 +213,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
final View view = inflater.inflate(R.layout.data_usage_summary, container, false);
|
final View view = inflater.inflate(R.layout.data_usage_summary, container, false);
|
||||||
|
|
||||||
mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
|
mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
|
||||||
|
mTabsContainer = (ViewGroup) view.findViewById(R.id.tabs_container);
|
||||||
mTabWidget = (TabWidget) view.findViewById(android.R.id.tabs);
|
mTabWidget = (TabWidget) view.findViewById(android.R.id.tabs);
|
||||||
mListView = (ListView) view.findViewById(android.R.id.list);
|
mListView = (ListView) view.findViewById(android.R.id.list);
|
||||||
|
|
||||||
@@ -220,6 +225,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// bind network switches
|
// bind network switches
|
||||||
|
mNetworkSwitchesContainer = (ViewGroup) mHeader.findViewById(
|
||||||
|
R.id.network_switches_container);
|
||||||
mNetworkSwitches = (LinearLayout) mHeader.findViewById(R.id.network_switches);
|
mNetworkSwitches = (LinearLayout) mHeader.findViewById(R.id.network_switches);
|
||||||
|
|
||||||
mDataEnabled = new Switch(inflater.getContext());
|
mDataEnabled = new Switch(inflater.getContext());
|
||||||
@@ -263,9 +270,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
mAppSwitches.addView(mAppRestrictView);
|
mAppSwitches.addView(mAppRestrictView);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: tweak these transitions
|
// only assign layout transitions once first layout is finished
|
||||||
final LayoutTransition transition = new LayoutTransition();
|
mHeader.getViewTreeObserver().addOnGlobalLayoutListener(mFirstLayoutListener);
|
||||||
mHeader.setLayoutTransition(transition);
|
|
||||||
|
|
||||||
mAdapter = new DataUsageAdapter();
|
mAdapter = new DataUsageAdapter();
|
||||||
mListView.setOnItemClickListener(mListListener);
|
mListView.setOnItemClickListener(mListListener);
|
||||||
@@ -344,6 +350,25 @@ public class DataUsageSummary extends Fragment {
|
|||||||
mDisableAtLimitView = null;
|
mDisableAtLimitView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener to setup {@link LayoutTransition} after first layout pass.
|
||||||
|
*/
|
||||||
|
private OnGlobalLayoutListener mFirstLayoutListener = new OnGlobalLayoutListener() {
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
mHeader.getViewTreeObserver().removeGlobalOnLayoutListener(mFirstLayoutListener);
|
||||||
|
|
||||||
|
mTabsContainer.setLayoutTransition(new LayoutTransition());
|
||||||
|
mHeader.setLayoutTransition(new LayoutTransition());
|
||||||
|
mNetworkSwitchesContainer.setLayoutTransition(new LayoutTransition());
|
||||||
|
|
||||||
|
final LayoutTransition chartTransition = new LayoutTransition();
|
||||||
|
chartTransition.setStartDelay(LayoutTransition.APPEARING, 0);
|
||||||
|
chartTransition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
|
||||||
|
mChart.setLayoutTransition(chartTransition);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@@ -434,6 +459,9 @@ public class DataUsageSummary extends Fragment {
|
|||||||
throw new IllegalStateException("no mobile or wifi radios");
|
throw new IllegalStateException("no mobile or wifi radios");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean tabChanged = !currentTab.equals(mCurrentTab);
|
||||||
|
mCurrentTab = currentTab;
|
||||||
|
|
||||||
if (LOGD) Log.d(TAG, "updateBody() with currentTab=" + currentTab);
|
if (LOGD) Log.d(TAG, "updateBody() with currentTab=" + currentTab);
|
||||||
|
|
||||||
if (TAB_WIFI.equals(currentTab)) {
|
if (TAB_WIFI.equals(currentTab)) {
|
||||||
@@ -480,7 +508,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
// bind chart to historical stats
|
// bind chart to historical stats
|
||||||
mChart.bindNetworkStats(mHistory);
|
mChart.bindNetworkStats(mHistory);
|
||||||
|
|
||||||
updatePolicy(true);
|
// only update policy when switching tabs
|
||||||
|
updatePolicy(tabChanged);
|
||||||
updateAppDetail();
|
updateAppDetail();
|
||||||
|
|
||||||
// force scroll to top of body
|
// force scroll to top of body
|
||||||
@@ -607,6 +636,12 @@ public class DataUsageSummary extends Fragment {
|
|||||||
// we fall through to update cycle list for detail mode
|
// we fall through to update cycle list for detail mode
|
||||||
} else {
|
} else {
|
||||||
mNetworkSwitches.setVisibility(View.VISIBLE);
|
mNetworkSwitches.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
// when heading back to summary without cycle refresh, kick details
|
||||||
|
// update to repopulate list.
|
||||||
|
if (!refreshCycle) {
|
||||||
|
updateDetailData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final NetworkPolicy policy = mPolicyEditor.getPolicy(mTemplate);
|
final NetworkPolicy policy = mPolicyEditor.getPolicy(mTemplate);
|
||||||
|
@@ -188,7 +188,12 @@ public class ChartSweepView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public float getPoint() {
|
public float getPoint() {
|
||||||
return mAxis.convertToPoint(mValue);
|
if (isEnabled()) {
|
||||||
|
return mAxis.convertToPoint(mValue);
|
||||||
|
} else {
|
||||||
|
// when disabled, show along top edge
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
@@ -93,7 +94,6 @@ public class ChartView extends FrameLayout {
|
|||||||
// sweep is always placed along specific dimension
|
// sweep is always placed along specific dimension
|
||||||
final ChartSweepView sweep = (ChartSweepView) child;
|
final ChartSweepView sweep = (ChartSweepView) child;
|
||||||
final Rect sweepMargins = sweep.getSweepMargins();
|
final Rect sweepMargins = sweep.getSweepMargins();
|
||||||
final float point = sweep.getPoint();
|
|
||||||
|
|
||||||
if (sweep.getFollowAxis() == ChartSweepView.HORIZONTAL) {
|
if (sweep.getFollowAxis() == ChartSweepView.HORIZONTAL) {
|
||||||
parentRect.left = parentRect.right =
|
parentRect.left = parentRect.right =
|
||||||
|
@@ -129,9 +129,7 @@ public class DataUsageChartView extends ChartView {
|
|||||||
mSweepLimit.setValue(policy.limitBytes);
|
mSweepLimit.setValue(policy.limitBytes);
|
||||||
mSweepLimit.setEnabled(true);
|
mSweepLimit.setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
// TODO: set limit default based on axis maximum
|
|
||||||
mSweepLimit.setVisibility(View.VISIBLE);
|
mSweepLimit.setVisibility(View.VISIBLE);
|
||||||
mSweepLimit.setValue(5 * GB_IN_BYTES);
|
|
||||||
mSweepLimit.setEnabled(false);
|
mSweepLimit.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +187,15 @@ public class DataUsageChartView extends ChartView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
|
if (!isActivated()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return super.onInterceptTouchEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return current inspection range (start and end time) based on internal
|
* Return current inspection range (start and end time) based on internal
|
||||||
* {@link ChartSweepView} positions.
|
* {@link ChartSweepView} positions.
|
||||||
@@ -302,56 +309,45 @@ public class DataUsageChartView extends ChartView {
|
|||||||
public static class DataAxis implements ChartAxis {
|
public static class DataAxis implements ChartAxis {
|
||||||
private long mMin;
|
private long mMin;
|
||||||
private long mMax;
|
private long mMax;
|
||||||
private long mMinLog;
|
|
||||||
private long mMaxLog;
|
|
||||||
private float mSize;
|
private float mSize;
|
||||||
|
|
||||||
public DataAxis() {
|
public DataAxis() {
|
||||||
// TODO: adapt ranges to show when history >5GB, and handle 4G
|
// TODO: adapt ranges to show when history >5GB, and handle 4G
|
||||||
// interfaces with higher limits.
|
// interfaces with higher limits.
|
||||||
setBounds(1 * MB_IN_BYTES, 5 * GB_IN_BYTES);
|
setBounds(0, 5 * GB_IN_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public void setBounds(long min, long max) {
|
public void setBounds(long min, long max) {
|
||||||
mMin = min;
|
mMin = min;
|
||||||
mMax = max;
|
mMax = max;
|
||||||
mMinLog = (long) Math.log(mMin);
|
|
||||||
mMaxLog = (long) Math.log(mMax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public void setSize(float size) {
|
public void setSize(float size) {
|
||||||
this.mSize = size;
|
mSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public float convertToPoint(long value) {
|
public float convertToPoint(long value) {
|
||||||
return (mSize * (value - mMin)) / (mMax - mMin);
|
// TODO: this assumes range of [0,5]GB
|
||||||
|
final double fraction = Math.pow(
|
||||||
// TODO: finish tweaking log scale
|
10, 0.36884343106175160321 * Math.log10(value) + -3.62828151137812282556);
|
||||||
// if (value > mMin) {
|
return (float) fraction * mSize;
|
||||||
// return (float) ((mSize * (Math.log(value) - mMinLog)) / (mMaxLog - mMinLog));
|
|
||||||
// } else {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public long convertToValue(float point) {
|
public long convertToValue(float point) {
|
||||||
return (long) (mMin + ((point * (mMax - mMin)) / mSize));
|
final double y = point / mSize;
|
||||||
|
// TODO: this assumes range of [0,5]GB
|
||||||
// TODO: finish tweaking log scale
|
final double fraction = 6.869341163271789302 * Math.pow(10, 9)
|
||||||
// return (long) Math.pow(Math.E, (mMinLog + ((point * (mMaxLog - mMinLog)) / mSize)));
|
* Math.pow(y, 2.71117746931646030774);
|
||||||
|
return (long) fraction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public CharSequence getLabel(long value) {
|
public CharSequence getLabel(long value) {
|
||||||
|
|
||||||
// TODO: use exploded string here
|
// TODO: use exploded string here
|
||||||
|
|
||||||
|
|
||||||
// TODO: convert to string
|
|
||||||
return Long.toString(value);
|
return Long.toString(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,13 +361,13 @@ public class DataUsageChartView extends ChartView {
|
|||||||
public float[] getTickPoints() {
|
public float[] getTickPoints() {
|
||||||
final float[] tickPoints = new float[16];
|
final float[] tickPoints = new float[16];
|
||||||
|
|
||||||
long value = mMax;
|
final long jump = ((mMax - mMin) / tickPoints.length);
|
||||||
float mult = 0.8f;
|
long value = mMin;
|
||||||
for (int i = 0; i < tickPoints.length; i++) {
|
for (int i = 0; i < tickPoints.length; i++) {
|
||||||
tickPoints[i] = convertToPoint(value);
|
tickPoints[i] = convertToPoint(value);
|
||||||
value = (long) (value * mult);
|
value += jump;
|
||||||
mult *= 0.9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return tickPoints;
|
return tickPoints;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user