Data usage strings, sweep touches, fixes.
Change strings around limiting background data. Move limit/warning sweeps above inspection sweeps, and teach about additional neighbors on different axis. Guard against DialogFragment.show(), fix pie chart to draw edges, and remove data usage from battery UI. Bug: 5341374, 5337650, 5337385, 5319465, 5236335 Change-Id: Iea8c2a2ab405b645d85abe34a0178d4b8874cdd5
This commit is contained in:
@@ -58,6 +58,22 @@
|
|||||||
settings:fillColor="#c0ba7f3e"
|
settings:fillColor="#c0ba7f3e"
|
||||||
settings:fillColorSecondary="#60ba7f3e" />
|
settings:fillColorSecondary="#60ba7f3e" />
|
||||||
|
|
||||||
|
<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"
|
||||||
|
settings:neighborMargin="5dip" />
|
||||||
|
|
||||||
|
<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"
|
||||||
|
settings:neighborMargin="5dip" />
|
||||||
|
|
||||||
<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"
|
||||||
@@ -82,20 +98,4 @@
|
|||||||
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"
|
|
||||||
settings:neighborMargin="5dip" />
|
|
||||||
|
|
||||||
<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"
|
|
||||||
settings:neighborMargin="5dip" />
|
|
||||||
|
|
||||||
</com.android.settings.widget.ChartDataUsageView>
|
</com.android.settings.widget.ChartDataUsageView>
|
||||||
|
@@ -3490,7 +3490,7 @@ found in the list of installed applications.</string>
|
|||||||
<!-- Title for checkbox menu option to enable mobile data when roaming. [CHAR LIMIT=32] -->
|
<!-- Title for checkbox menu option to enable mobile data when roaming. [CHAR LIMIT=32] -->
|
||||||
<string name="data_usage_menu_roaming">Data roaming</string>
|
<string name="data_usage_menu_roaming">Data roaming</string>
|
||||||
<!-- Title for checkbox menu option to restrict background data usage. [CHAR LIMIT=20] -->
|
<!-- Title for checkbox menu option to restrict background data usage. [CHAR LIMIT=20] -->
|
||||||
<string name="data_usage_menu_restrict_background">Restrict 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">Separate 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] -->
|
||||||
@@ -3547,13 +3547,15 @@ found in the list of installed applications.</string>
|
|||||||
<!-- Checkbox label that restricts background data usage of a specific application. [CHAR LIMIT=32] -->
|
<!-- Checkbox label that restricts background data usage of a specific application. [CHAR LIMIT=32] -->
|
||||||
<string name="data_usage_app_restrict_background">Restrict background data</string>
|
<string name="data_usage_app_restrict_background">Restrict background data</string>
|
||||||
<!-- Summary message for checkbox that restricts background data usage of a specific application. [CHAR LIMIT=64] -->
|
<!-- Summary message for checkbox that restricts background data usage of a specific application. [CHAR LIMIT=64] -->
|
||||||
<string name="data_usage_app_restrict_background_summary">Disable background data on networks that you\'ve chosen to limit (<xliff:g id="networks" example="Mobile, Wi-Fi">%1$s</xliff:g>).</string>
|
<string name="data_usage_app_restrict_background_summary">Disable background data on mobile data network only. Wi-Fi will be used if available.</string>
|
||||||
|
<!-- Summary message for checkbox that restricts background data usage of a specific application when no networks have been limited. [CHAR LIMIT=64] -->
|
||||||
|
<string name="data_usage_app_restrict_background_summary_disabled">To restrict background data for this app, first set a mobile data limit.</string>
|
||||||
<!-- Title of dialog shown when user restricts background data usage of a specific application. [CHAR LIMIT=48] -->
|
<!-- Title of dialog shown when user restricts background data usage of a specific application. [CHAR LIMIT=48] -->
|
||||||
<string name="data_usage_app_restrict_dialog_title">Restrict background data?</string>
|
<string name="data_usage_app_restrict_dialog_title">Restrict background data?</string>
|
||||||
<!-- Body of dialog shown when user restricts background data usage of a specific application. [CHAR LIMIT=NONE] -->
|
<!-- Body of dialog shown when user restricts background data usage of a specific application. [CHAR LIMIT=NONE] -->
|
||||||
<string name="data_usage_app_restrict_dialog">This feature may negatively impact applications which depend on background data usage.\n\nMore appropriate data usage controls may be found within this application\'s settings.</string>
|
<string name="data_usage_app_restrict_dialog">This feature may cause an app that depends on background data to stop working when Wi-Fi isn\'t available.\n\nMore appropriate data usage controls may be found in the settings available from within the app.</string>
|
||||||
<!-- Body of dialog shown when user attempts to restrict background data before a network data limit has been set. [CHAR LIMIT=NONE] -->
|
<!-- Body of dialog shown when user attempts to restrict background data before a network data limit has been set. [CHAR LIMIT=NONE] -->
|
||||||
<string name="data_usage_restrict_denied_dialog">Restricting background data is only available when you\'ve set a network data limit.</string>
|
<string name="data_usage_restrict_denied_dialog">Restricting background data is possible only when you\'ve set a mobile data limit.</string>
|
||||||
|
|
||||||
<!-- Title of dialog for editing data usage cycle reset date. [CHAR LIMIT=48] -->
|
<!-- Title of dialog for editing data usage cycle reset date. [CHAR LIMIT=48] -->
|
||||||
<string name="data_usage_cycle_editor_title">Usage cycle reset date</string>
|
<string name="data_usage_cycle_editor_title">Usage cycle reset date</string>
|
||||||
@@ -3575,7 +3577,7 @@ found in the list of installed applications.</string>
|
|||||||
<!-- Title of dialog shown before user restricts background data usage. [CHAR LIMIT=48] -->
|
<!-- Title of dialog shown before user restricts background data usage. [CHAR LIMIT=48] -->
|
||||||
<string name="data_usage_restrict_background_title">Restrict background data?</string>
|
<string name="data_usage_restrict_background_title">Restrict background data?</string>
|
||||||
<!-- Body of dialog shown before user restricts background data usage. [CHAR LIMIT=NONE] -->
|
<!-- Body of dialog shown before user restricts background data usage. [CHAR LIMIT=NONE] -->
|
||||||
<string name="data_usage_restrict_background">If you restrict background data, some apps and services won\'t work on networks that you\'ve chosen to limit.\n\nCurrently limited networks: <xliff:g id="networks" example="Mobile, Wi-Fi">%1$s</xliff:g></string>
|
<string name="data_usage_restrict_background">If you restrict background mobile data, some apps and services won\'t work unless Wi-Fi is available.</string>
|
||||||
|
|
||||||
<!-- Label displaying current network data usage warning threshold. [CHAR LIMIT=18] -->
|
<!-- Label displaying current network data usage warning threshold. [CHAR LIMIT=18] -->
|
||||||
<string name="data_usage_sweep_warning"><font size="21"><xliff:g id="number" example="128">^1</xliff:g></font> <font size="9"><xliff:g id="unit" example="KB">^2</xliff:g></font>\n<font size="12">warning</font></string>
|
<string name="data_usage_sweep_warning"><font size="21"><xliff:g id="number" example="128">^1</xliff:g></font> <font size="9"><xliff:g id="unit" example="KB">^2</xliff:g></font>\n<font size="12">warning</font></string>
|
||||||
|
@@ -751,9 +751,13 @@ public class DataUsageSummary extends Fragment {
|
|||||||
if (NetworkPolicyManager.isUidValidForPolicy(context, primaryUid)
|
if (NetworkPolicyManager.isUidValidForPolicy(context, primaryUid)
|
||||||
&& !getRestrictBackground() && isBandwidthControlEnabled()) {
|
&& !getRestrictBackground() && isBandwidthControlEnabled()) {
|
||||||
setPreferenceTitle(mAppRestrictView, R.string.data_usage_app_restrict_background);
|
setPreferenceTitle(mAppRestrictView, R.string.data_usage_app_restrict_background);
|
||||||
setPreferenceSummary(mAppRestrictView,
|
if (hasLimitedNetworks()) {
|
||||||
getString(R.string.data_usage_app_restrict_background_summary,
|
setPreferenceSummary(mAppRestrictView,
|
||||||
buildLimitedNetworksString()));
|
getString(R.string.data_usage_app_restrict_background_summary));
|
||||||
|
} else {
|
||||||
|
setPreferenceSummary(mAppRestrictView,
|
||||||
|
getString(R.string.data_usage_app_restrict_background_summary_disabled));
|
||||||
|
}
|
||||||
|
|
||||||
mAppRestrictView.setVisibility(View.VISIBLE);
|
mAppRestrictView.setVisibility(View.VISIBLE);
|
||||||
mAppRestrict.setChecked(getAppRestrictBackground());
|
mAppRestrict.setChecked(getAppRestrictBackground());
|
||||||
@@ -925,8 +929,9 @@ public class DataUsageSummary extends Fragment {
|
|||||||
historyEnd = mChartData.network.getEnd();
|
historyEnd = mChartData.network.getEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (historyStart == Long.MAX_VALUE) historyStart = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
if (historyEnd == Long.MIN_VALUE) historyEnd = System.currentTimeMillis();
|
if (historyStart == Long.MAX_VALUE) historyStart = now;
|
||||||
|
if (historyEnd == Long.MIN_VALUE) historyEnd = now + 1;
|
||||||
|
|
||||||
boolean hasCycles = false;
|
boolean hasCycles = false;
|
||||||
if (policy != null) {
|
if (policy != null) {
|
||||||
@@ -1489,6 +1494,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private static final String EXTRA_UIDS = "uids";
|
private static final String EXTRA_UIDS = "uids";
|
||||||
|
|
||||||
public static void show(DataUsageSummary parent, int[] uids, CharSequence label) {
|
public static void show(DataUsageSummary parent, int[] uids, CharSequence label) {
|
||||||
|
if (!parent.isAdded()) return;
|
||||||
|
|
||||||
final Bundle args = new Bundle();
|
final Bundle args = new Bundle();
|
||||||
args.putIntArray(EXTRA_UIDS, uids);
|
args.putIntArray(EXTRA_UIDS, uids);
|
||||||
|
|
||||||
@@ -1529,8 +1536,9 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private 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 Resources res = parent.getResources();
|
if (!parent.isAdded()) return;
|
||||||
|
|
||||||
|
final Resources res = parent.getResources();
|
||||||
final CharSequence message;
|
final CharSequence message;
|
||||||
final long limitBytes;
|
final long limitBytes;
|
||||||
|
|
||||||
@@ -1597,6 +1605,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private static final String EXTRA_TEMPLATE = "template";
|
private static final String EXTRA_TEMPLATE = "template";
|
||||||
|
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
|
if (!parent.isAdded()) return;
|
||||||
|
|
||||||
final Bundle args = new Bundle();
|
final Bundle args = new Bundle();
|
||||||
args.putParcelable(EXTRA_TEMPLATE, parent.mTemplate);
|
args.putParcelable(EXTRA_TEMPLATE, parent.mTemplate);
|
||||||
|
|
||||||
@@ -1649,6 +1659,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private static final String EXTRA_TEMPLATE = "template";
|
private static final String EXTRA_TEMPLATE = "template";
|
||||||
|
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
|
if (!parent.isAdded()) return;
|
||||||
|
|
||||||
final Bundle args = new Bundle();
|
final Bundle args = new Bundle();
|
||||||
args.putParcelable(EXTRA_TEMPLATE, parent.mTemplate);
|
args.putParcelable(EXTRA_TEMPLATE, parent.mTemplate);
|
||||||
|
|
||||||
@@ -1709,6 +1721,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private static final String EXTRA_TEMPLATE = "template";
|
private static final String EXTRA_TEMPLATE = "template";
|
||||||
|
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
|
if (!parent.isAdded()) return;
|
||||||
|
|
||||||
final Bundle args = new Bundle();
|
final Bundle args = new Bundle();
|
||||||
args.putParcelable(EXTRA_TEMPLATE, parent.mTemplate);
|
args.putParcelable(EXTRA_TEMPLATE, parent.mTemplate);
|
||||||
|
|
||||||
@@ -1766,6 +1780,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
*/
|
*/
|
||||||
public static class ConfirmDataDisableFragment extends DialogFragment {
|
public static class ConfirmDataDisableFragment extends DialogFragment {
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
|
if (!parent.isAdded()) return;
|
||||||
|
|
||||||
final ConfirmDataDisableFragment dialog = new ConfirmDataDisableFragment();
|
final ConfirmDataDisableFragment dialog = new ConfirmDataDisableFragment();
|
||||||
dialog.setTargetFragment(parent, 0);
|
dialog.setTargetFragment(parent, 0);
|
||||||
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_DATA_DISABLE);
|
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_DATA_DISABLE);
|
||||||
@@ -1799,6 +1815,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
*/
|
*/
|
||||||
public static class ConfirmDataRoamingFragment extends DialogFragment {
|
public static class ConfirmDataRoamingFragment extends DialogFragment {
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
|
if (!parent.isAdded()) return;
|
||||||
|
|
||||||
final ConfirmDataRoamingFragment dialog = new ConfirmDataRoamingFragment();
|
final ConfirmDataRoamingFragment dialog = new ConfirmDataRoamingFragment();
|
||||||
dialog.setTargetFragment(parent, 0);
|
dialog.setTargetFragment(parent, 0);
|
||||||
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_DATA_ROAMING);
|
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_DATA_ROAMING);
|
||||||
@@ -1832,6 +1850,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
*/
|
*/
|
||||||
public static class ConfirmRestrictFragment extends DialogFragment {
|
public static class ConfirmRestrictFragment extends DialogFragment {
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
|
if (!parent.isAdded()) return;
|
||||||
|
|
||||||
final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment();
|
final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment();
|
||||||
dialog.setTargetFragment(parent, 0);
|
dialog.setTargetFragment(parent, 0);
|
||||||
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT);
|
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT);
|
||||||
@@ -1843,13 +1863,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
|
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
builder.setTitle(R.string.data_usage_restrict_background_title);
|
builder.setTitle(R.string.data_usage_restrict_background_title);
|
||||||
|
builder.setMessage(getString(R.string.data_usage_restrict_background));
|
||||||
final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
|
|
||||||
if (target != null) {
|
|
||||||
final CharSequence limitedNetworks = target.buildLimitedNetworksString();
|
|
||||||
builder.setMessage(
|
|
||||||
getString(R.string.data_usage_restrict_background, limitedNetworks));
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
@@ -1872,6 +1886,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
*/
|
*/
|
||||||
public static class DeniedRestrictFragment extends DialogFragment {
|
public static class DeniedRestrictFragment extends DialogFragment {
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
|
if (!parent.isAdded()) return;
|
||||||
|
|
||||||
final DeniedRestrictFragment dialog = new DeniedRestrictFragment();
|
final DeniedRestrictFragment dialog = new DeniedRestrictFragment();
|
||||||
dialog.setTargetFragment(parent, 0);
|
dialog.setTargetFragment(parent, 0);
|
||||||
dialog.show(parent.getFragmentManager(), TAG_DENIED_RESTRICT);
|
dialog.show(parent.getFragmentManager(), TAG_DENIED_RESTRICT);
|
||||||
@@ -1896,6 +1912,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
*/
|
*/
|
||||||
public static class ConfirmAppRestrictFragment extends DialogFragment {
|
public static class ConfirmAppRestrictFragment extends DialogFragment {
|
||||||
public static void show(DataUsageSummary parent) {
|
public static void show(DataUsageSummary parent) {
|
||||||
|
if (!parent.isAdded()) return;
|
||||||
|
|
||||||
final ConfirmAppRestrictFragment dialog = new ConfirmAppRestrictFragment();
|
final ConfirmAppRestrictFragment dialog = new ConfirmAppRestrictFragment();
|
||||||
dialog.setTargetFragment(parent, 0);
|
dialog.setTargetFragment(parent, 0);
|
||||||
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_APP_RESTRICT);
|
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_APP_RESTRICT);
|
||||||
|
@@ -202,6 +202,8 @@ public class PowerUsageSummary extends PreferenceFragment implements Runnable {
|
|||||||
switch (sipper.drainType) {
|
switch (sipper.drainType) {
|
||||||
case APP:
|
case APP:
|
||||||
{
|
{
|
||||||
|
// TODO: surface tcpBytesSent/tcpBytesReceived again once
|
||||||
|
// measured separately from uid_stats.
|
||||||
Uid uid = sipper.uidObj;
|
Uid uid = sipper.uidObj;
|
||||||
types = new int[] {
|
types = new int[] {
|
||||||
R.string.usage_type_cpu,
|
R.string.usage_type_cpu,
|
||||||
@@ -209,8 +211,6 @@ public class PowerUsageSummary extends PreferenceFragment implements Runnable {
|
|||||||
R.string.usage_type_wake_lock,
|
R.string.usage_type_wake_lock,
|
||||||
R.string.usage_type_gps,
|
R.string.usage_type_gps,
|
||||||
R.string.usage_type_wifi_running,
|
R.string.usage_type_wifi_running,
|
||||||
R.string.usage_type_data_send,
|
|
||||||
R.string.usage_type_data_recv,
|
|
||||||
R.string.usage_type_audio,
|
R.string.usage_type_audio,
|
||||||
R.string.usage_type_video,
|
R.string.usage_type_video,
|
||||||
};
|
};
|
||||||
@@ -220,8 +220,6 @@ public class PowerUsageSummary extends PreferenceFragment implements Runnable {
|
|||||||
sipper.wakeLockTime,
|
sipper.wakeLockTime,
|
||||||
sipper.gpsTime,
|
sipper.gpsTime,
|
||||||
sipper.wifiRunningTime,
|
sipper.wifiRunningTime,
|
||||||
sipper.tcpBytesSent,
|
|
||||||
sipper.tcpBytesReceived,
|
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
@@ -120,6 +120,12 @@ public class ChartDataUsageView extends ChartView {
|
|||||||
mSweepWarning.setValidRangeDynamic(null, mSweepLimit);
|
mSweepWarning.setValidRangeDynamic(null, mSweepLimit);
|
||||||
mSweepLimit.setValidRangeDynamic(mSweepWarning, null);
|
mSweepLimit.setValidRangeDynamic(mSweepWarning, null);
|
||||||
|
|
||||||
|
// mark neighbors for checking touch events against
|
||||||
|
mSweepLeft.setNeighbors(mSweepRight);
|
||||||
|
mSweepRight.setNeighbors(mSweepLeft);
|
||||||
|
mSweepLimit.setNeighbors(mSweepWarning, mSweepLeft, mSweepRight);
|
||||||
|
mSweepWarning.setNeighbors(mSweepLimit, mSweepLeft, mSweepRight);
|
||||||
|
|
||||||
mSweepLeft.addOnSweepListener(mHorizListener);
|
mSweepLeft.addOnSweepListener(mHorizListener);
|
||||||
mSweepRight.addOnSweepListener(mHorizListener);
|
mSweepRight.addOnSweepListener(mHorizListener);
|
||||||
mSweepWarning.addOnSweepListener(mVertListener);
|
mSweepWarning.addOnSweepListener(mVertListener);
|
||||||
@@ -375,12 +381,12 @@ public class ChartDataUsageView extends ChartView {
|
|||||||
return mSweepLimit.getLabelValue();
|
return mSweepLimit.getLabelValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getStatsStart() {
|
private long getHistoryStart() {
|
||||||
return mHistory != null ? mHistory.getStart() : Long.MIN_VALUE;
|
return mHistory != null ? mHistory.getStart() : Long.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getStatsEnd() {
|
private long getHistoryEnd() {
|
||||||
return mHistory != null ? mHistory.getEnd() : Long.MAX_VALUE;
|
return mHistory != null ? mHistory.getEnd() : Long.MIN_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -394,8 +400,13 @@ public class ChartDataUsageView extends ChartView {
|
|||||||
mSeries.setBounds(visibleStart, visibleEnd);
|
mSeries.setBounds(visibleStart, visibleEnd);
|
||||||
mDetailSeries.setBounds(visibleStart, visibleEnd);
|
mDetailSeries.setBounds(visibleStart, visibleEnd);
|
||||||
|
|
||||||
final long validStart = Math.max(visibleStart, getStatsStart());
|
final long historyStart = getHistoryStart();
|
||||||
final long validEnd = Math.min(visibleEnd, getStatsEnd());
|
final long historyEnd = getHistoryEnd();
|
||||||
|
|
||||||
|
final long validStart = historyStart == Long.MAX_VALUE ? visibleStart
|
||||||
|
: Math.max(visibleStart, historyStart);
|
||||||
|
final long validEnd = historyEnd == Long.MIN_VALUE ? visibleEnd
|
||||||
|
: Math.min(visibleEnd, historyEnd);
|
||||||
|
|
||||||
if (LIMIT_SWEEPS_TO_VALID_DATA) {
|
if (LIMIT_SWEEPS_TO_VALID_DATA) {
|
||||||
// prevent time sweeps from leaving valid data
|
// prevent time sweeps from leaving valid data
|
||||||
|
@@ -101,6 +101,8 @@ public class ChartSweepView extends View {
|
|||||||
private float mTrackingStart;
|
private float mTrackingStart;
|
||||||
private MotionEvent mTracking;
|
private MotionEvent mTracking;
|
||||||
|
|
||||||
|
private ChartSweepView[] mNeighbors = new ChartSweepView[0];
|
||||||
|
|
||||||
public ChartSweepView(Context context) {
|
public ChartSweepView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
}
|
}
|
||||||
@@ -149,6 +151,10 @@ public class ChartSweepView extends View {
|
|||||||
mAxis = Preconditions.checkNotNull(axis, "missing axis");
|
mAxis = Preconditions.checkNotNull(axis, "missing axis");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setNeighbors(ChartSweepView... neighbors) {
|
||||||
|
mNeighbors = neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
public int getFollowAxis() {
|
public int getFollowAxis() {
|
||||||
return mFollowAxis;
|
return mFollowAxis;
|
||||||
}
|
}
|
||||||
@@ -381,18 +387,16 @@ public class ChartSweepView extends View {
|
|||||||
* {@link ChartSweepView} compared to ourselves.
|
* {@link ChartSweepView} compared to ourselves.
|
||||||
*/
|
*/
|
||||||
public boolean isTouchCloserTo(MotionEvent eventInParent, ChartSweepView another) {
|
public boolean isTouchCloserTo(MotionEvent eventInParent, ChartSweepView another) {
|
||||||
if (another == null) return false;
|
final float selfDist = getTouchDistanceFromTarget(eventInParent);
|
||||||
|
final float anotherDist = another.getTouchDistanceFromTarget(eventInParent);
|
||||||
|
return anotherDist < selfDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getTouchDistanceFromTarget(MotionEvent eventInParent) {
|
||||||
if (mFollowAxis == HORIZONTAL) {
|
if (mFollowAxis == HORIZONTAL) {
|
||||||
final float selfDist = Math.abs(eventInParent.getX() - (getX() + getTargetInset()));
|
return Math.abs(eventInParent.getX() - (getX() + getTargetInset()));
|
||||||
final float anotherDist = Math.abs(
|
|
||||||
eventInParent.getX() - (another.getX() + another.getTargetInset()));
|
|
||||||
return anotherDist < selfDist;
|
|
||||||
} else {
|
} else {
|
||||||
final float selfDist = Math.abs(eventInParent.getY() - (getY() + getTargetInset()));
|
return Math.abs(eventInParent.getY() - (getY() + getTargetInset()));
|
||||||
final float anotherDist = Math.abs(
|
|
||||||
eventInParent.getY() - (another.getY() + another.getTargetInset()));
|
|
||||||
return anotherDist < selfDist;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,9 +425,10 @@ public class ChartSweepView extends View {
|
|||||||
eventInParent.offsetLocation(getLeft(), getTop());
|
eventInParent.offsetLocation(getLeft(), getTop());
|
||||||
|
|
||||||
// ignore event when closer to a neighbor
|
// ignore event when closer to a neighbor
|
||||||
if (isTouchCloserTo(eventInParent, mValidAfterDynamic)
|
for (ChartSweepView neighbor : mNeighbors) {
|
||||||
|| isTouchCloserTo(eventInParent, mValidBeforeDynamic)) {
|
if (isTouchCloserTo(eventInParent, neighbor)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acceptDrag) {
|
if (acceptDrag) {
|
||||||
|
@@ -20,6 +20,7 @@ import android.content.Context;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Paint.Style;
|
import android.graphics.Paint.Style;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
@@ -42,31 +43,34 @@ public class PieChartView extends View {
|
|||||||
public static final String TAG = "PieChartView";
|
public static final String TAG = "PieChartView";
|
||||||
public static final boolean LOGD = false;
|
public static final boolean LOGD = false;
|
||||||
|
|
||||||
|
private static final boolean FILL_GRADIENT = false;
|
||||||
|
|
||||||
private ArrayList<Slice> mSlices = Lists.newArrayList();
|
private ArrayList<Slice> mSlices = Lists.newArrayList();
|
||||||
|
|
||||||
private int mOriginAngle;
|
private int mOriginAngle;
|
||||||
|
private Matrix mMatrix = new Matrix();
|
||||||
|
|
||||||
private Paint mPaintPrimary = new Paint();
|
private Paint mPaintOutline = new Paint();
|
||||||
private Paint mPaintShadow = new Paint();
|
|
||||||
|
|
||||||
private Path mPathSide = new Path();
|
private Path mPathSide = new Path();
|
||||||
private Path mPathSideShadow = new Path();
|
private Path mPathSideOutline = new Path();
|
||||||
|
|
||||||
private Path mPathShadow = new Path();
|
private Path mPathOutline = new Path();
|
||||||
|
|
||||||
private int mSideWidth;
|
private int mSideWidth;
|
||||||
|
|
||||||
public class Slice {
|
public class Slice {
|
||||||
public long value;
|
public long value;
|
||||||
|
|
||||||
public Path pathPrimary = new Path();
|
public Path path = new Path();
|
||||||
public Path pathShadow = new Path();
|
public Path pathSide = new Path();
|
||||||
|
public Path pathOutline = new Path();
|
||||||
|
|
||||||
public Paint paintPrimary;
|
public Paint paint;
|
||||||
|
|
||||||
public Slice(long value, int color) {
|
public Slice(long value, int color) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.paintPrimary = buildFillPaint(color, getResources());
|
this.paint = buildFillPaint(color, getResources());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,12 +85,10 @@ public class PieChartView extends View {
|
|||||||
public PieChartView(Context context, AttributeSet attrs, int defStyle) {
|
public PieChartView(Context context, AttributeSet attrs, int defStyle) {
|
||||||
super(context, attrs, defStyle);
|
super(context, attrs, defStyle);
|
||||||
|
|
||||||
mPaintPrimary = buildFillPaint(Color.parseColor("#666666"), getResources());
|
mPaintOutline.setColor(Color.BLACK);
|
||||||
|
mPaintOutline.setStyle(Style.STROKE);
|
||||||
mPaintShadow.setColor(Color.BLACK);
|
mPaintOutline.setStrokeWidth(3f * getResources().getDisplayMetrics().density);
|
||||||
mPaintShadow.setStyle(Style.STROKE);
|
mPaintOutline.setAntiAlias(true);
|
||||||
mPaintShadow.setStrokeWidth(3f * getResources().getDisplayMetrics().density);
|
|
||||||
mPaintShadow.setAntiAlias(true);
|
|
||||||
|
|
||||||
mSideWidth = (int) (20 * getResources().getDisplayMetrics().density);
|
mSideWidth = (int) (20 * getResources().getDisplayMetrics().density);
|
||||||
|
|
||||||
@@ -100,8 +102,10 @@ public class PieChartView extends View {
|
|||||||
paint.setStyle(Style.FILL_AND_STROKE);
|
paint.setStyle(Style.FILL_AND_STROKE);
|
||||||
paint.setAntiAlias(true);
|
paint.setAntiAlias(true);
|
||||||
|
|
||||||
final int width = (int) (280 * res.getDisplayMetrics().density);
|
if (FILL_GRADIENT) {
|
||||||
paint.setShader(new RadialGradient(0, 0, width, color, darken(color), TileMode.MIRROR));
|
final int width = (int) (280 * res.getDisplayMetrics().density);
|
||||||
|
paint.setShader(new RadialGradient(0, 0, width, color, darken(color), TileMode.MIRROR));
|
||||||
|
}
|
||||||
|
|
||||||
return paint;
|
return paint;
|
||||||
}
|
}
|
||||||
@@ -120,6 +124,13 @@ public class PieChartView extends View {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
|
final float centerX = getWidth() / 2;
|
||||||
|
final float centerY = getHeight() / 2;
|
||||||
|
|
||||||
|
mMatrix.reset();
|
||||||
|
mMatrix.postScale(0.665f, 0.95f, centerX, centerY);
|
||||||
|
mMatrix.postRotate(-40, centerX, centerY);
|
||||||
|
|
||||||
generatePath();
|
generatePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,14 +139,15 @@ public class PieChartView extends View {
|
|||||||
|
|
||||||
long total = 0;
|
long total = 0;
|
||||||
for (Slice slice : mSlices) {
|
for (Slice slice : mSlices) {
|
||||||
slice.pathPrimary.reset();
|
slice.path.reset();
|
||||||
slice.pathShadow.reset();
|
slice.pathSide.reset();
|
||||||
|
slice.pathOutline.reset();
|
||||||
total += slice.value;
|
total += slice.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
mPathSide.reset();
|
mPathSide.reset();
|
||||||
mPathSideShadow.reset();
|
mPathSideOutline.reset();
|
||||||
mPathShadow.reset();
|
mPathOutline.reset();
|
||||||
|
|
||||||
// bail when not enough stats to render
|
// bail when not enough stats to render
|
||||||
if (total == 0) {
|
if (total == 0) {
|
||||||
@@ -147,23 +159,56 @@ public class PieChartView extends View {
|
|||||||
final int height = getHeight();
|
final int height = getHeight();
|
||||||
|
|
||||||
final RectF rect = new RectF(0, 0, width, height);
|
final RectF rect = new RectF(0, 0, width, height);
|
||||||
|
final RectF rectSide = new RectF();
|
||||||
|
rectSide.set(rect);
|
||||||
|
rectSide.offset(-mSideWidth, 0);
|
||||||
|
|
||||||
mPathSide.addOval(rect, Direction.CW);
|
mPathSide.addOval(rectSide, Direction.CW);
|
||||||
mPathSideShadow.addOval(rect, Direction.CW);
|
mPathSideOutline.addOval(rectSide, Direction.CW);
|
||||||
mPathShadow.addOval(rect, Direction.CW);
|
mPathOutline.addOval(rect, Direction.CW);
|
||||||
|
|
||||||
int startAngle = mOriginAngle;
|
int startAngle = mOriginAngle;
|
||||||
for (Slice slice : mSlices) {
|
for (Slice slice : mSlices) {
|
||||||
final int sweepAngle = (int) (slice.value * 360 / total);
|
final int sweepAngle = (int) (slice.value * 360 / total);
|
||||||
|
final int endAngle = startAngle + sweepAngle;
|
||||||
|
|
||||||
slice.pathPrimary.moveTo(rect.centerX(), rect.centerY());
|
final float startAngleMod = startAngle % 360;
|
||||||
slice.pathPrimary.arcTo(rect, startAngle, sweepAngle);
|
final float endAngleMod = endAngle % 360;
|
||||||
slice.pathPrimary.lineTo(rect.centerX(), rect.centerY());
|
final boolean startSideVisible = startAngleMod > 90 && startAngleMod < 270;
|
||||||
|
final boolean endSideVisible = endAngleMod > 90 && endAngleMod < 270;
|
||||||
|
|
||||||
slice.pathShadow.moveTo(rect.centerX(), rect.centerY());
|
// draw slice
|
||||||
slice.pathShadow.arcTo(rect, startAngle, 0);
|
slice.path.moveTo(rect.centerX(), rect.centerY());
|
||||||
slice.pathShadow.moveTo(rect.centerX(), rect.centerY());
|
slice.path.arcTo(rect, startAngle, sweepAngle);
|
||||||
slice.pathShadow.arcTo(rect, startAngle + sweepAngle, 0);
|
slice.path.lineTo(rect.centerX(), rect.centerY());
|
||||||
|
|
||||||
|
if (startSideVisible || endSideVisible) {
|
||||||
|
|
||||||
|
// when start is beyond horizon, push until visible
|
||||||
|
final float startAngleSide = startSideVisible ? startAngle : 450;
|
||||||
|
final float endAngleSide = endSideVisible ? endAngle : 270;
|
||||||
|
final float sweepAngleSide = endAngleSide - startAngleSide;
|
||||||
|
|
||||||
|
// draw slice side
|
||||||
|
slice.pathSide.moveTo(rect.centerX(), rect.centerY());
|
||||||
|
slice.pathSide.arcTo(rect, startAngleSide, 0);
|
||||||
|
slice.pathSide.rLineTo(-mSideWidth, 0);
|
||||||
|
slice.pathSide.arcTo(rectSide, startAngleSide, sweepAngleSide);
|
||||||
|
slice.pathSide.rLineTo(mSideWidth, 0);
|
||||||
|
slice.pathSide.arcTo(rect, endAngleSide, -sweepAngleSide);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw slice outline
|
||||||
|
slice.pathOutline.moveTo(rect.centerX(), rect.centerY());
|
||||||
|
slice.pathOutline.arcTo(rect, startAngle, 0);
|
||||||
|
if (startSideVisible) {
|
||||||
|
slice.pathOutline.rLineTo(-mSideWidth, 0);
|
||||||
|
}
|
||||||
|
slice.pathOutline.moveTo(rect.centerX(), rect.centerY());
|
||||||
|
slice.pathOutline.arcTo(rect, startAngle + sweepAngle, 0);
|
||||||
|
if (endSideVisible) {
|
||||||
|
slice.pathOutline.rLineTo(-mSideWidth, 0);
|
||||||
|
}
|
||||||
|
|
||||||
startAngle += sweepAngle;
|
startAngle += sweepAngle;
|
||||||
}
|
}
|
||||||
@@ -174,21 +219,18 @@ public class PieChartView extends View {
|
|||||||
@Override
|
@Override
|
||||||
protected void onDraw(Canvas canvas) {
|
protected void onDraw(Canvas canvas) {
|
||||||
|
|
||||||
canvas.translate(getWidth() * 0.25f, getHeight() * -0.05f);
|
canvas.concat(mMatrix);
|
||||||
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) {
|
for (Slice slice : mSlices) {
|
||||||
canvas.drawPath(slice.pathPrimary, slice.paintPrimary);
|
canvas.drawPath(slice.pathSide, slice.paint);
|
||||||
canvas.drawPath(slice.pathShadow, mPaintShadow);
|
|
||||||
}
|
}
|
||||||
canvas.drawPath(mPathShadow, mPaintShadow);
|
canvas.drawPath(mPathSideOutline, mPaintOutline);
|
||||||
|
|
||||||
|
for (Slice slice : mSlices) {
|
||||||
|
canvas.drawPath(slice.path, slice.paint);
|
||||||
|
canvas.drawPath(slice.pathOutline, mPaintOutline);
|
||||||
|
}
|
||||||
|
canvas.drawPath(mPathOutline, mPaintOutline);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int darken(int color) {
|
public static int darken(int color) {
|
||||||
|
Reference in New Issue
Block a user