Cycle day editor and other confirmation dialogs.
Create dialog to edit "cycle day" when data usage resets. Also added dialogs to confirm enabling limit and restricting an application. Change-Id: I1e08b17fabd1fcfc2f260807a61435d0ff1a8627
This commit is contained in:
40
res/layout/data_usage_cycle_editor.xml
Normal file
40
res/layout/data_usage_cycle_editor.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?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:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="@string/data_usage_cycle_editor_subtitle" />
|
||||
|
||||
<NumberPicker
|
||||
android:id="@+id/cycle_day"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true" />
|
||||
|
||||
</LinearLayout>
|
@@ -23,7 +23,9 @@
|
||||
android:id="@+id/switches"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
android:orientation="vertical"
|
||||
android:showDividers="middle|end"
|
||||
android:divider="?android:attr/listDivider" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@@ -3399,7 +3399,27 @@ found in the list of installed applications.</string>
|
||||
<string name="data_usage_app_settings">View application settings</string>
|
||||
<!-- Checkbox label that restricts background data usage of a specific application. [CHAR LIMIT=32] -->
|
||||
<string name="data_usage_app_restrict_background">Restrict background data usage</string>
|
||||
<!-- Summary message for checkbox that restricts background data usage of a specific application. [CHAR LIMIT=32] -->
|
||||
<!-- Summary message for checkbox that restricts background data usage of a specific application. [CHAR LIMIT=64] -->
|
||||
<string name="data_usage_app_restrict_background_summary">Only allow application background data when using an unlimited network</string>
|
||||
<!-- 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">Restricting background data</string>
|
||||
<!-- 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>
|
||||
|
||||
<!-- 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>
|
||||
<!-- Subtitle of dialog for editing data usage cycle reset date. [CHAR LIMIT=32] -->
|
||||
<string name="data_usage_cycle_editor_subtitle">Date of each month:</string>
|
||||
<!-- Positive button title for data usage cycle editor, confirming that changes should be saved. [CHAR LIMIT=32] -->
|
||||
<string name="data_usage_cycle_editor_positive">set</string>
|
||||
|
||||
<!-- Title of dialog shown before user limits data usage. [CHAR LIMIT=48] -->
|
||||
<string name="data_usage_limit_dialog_title">Limiting data usage</string>
|
||||
<!-- First paragraph of dialog shown before user limits mobile data usage. [CHAR LIMIT=NONE] -->
|
||||
<string name="data_usage_limit_dialog_mobile">Your mobile data connection will be disabled when the specified limit is reached.\n\nTo avoid overage charges, consider using a reduced limit, as device and carrier accounting methods may vary.</string>
|
||||
<!-- First paragraph of dialog shown before user limits 3G data usage. [CHAR LIMIT=NONE] -->
|
||||
<string name="data_usage_limit_dialog_3g">Your 2G-3G data connection will be disabled when the specified limit is reached.\n\nTo avoid overage charges, consider using a reduced limit, as device and carrier accounting methods may vary.</string>
|
||||
<!-- First paragraph of dialog shown before user limits 4G data usage. [CHAR LIMIT=NONE] -->
|
||||
<string name="data_usage_limit_dialog_4g">Your 4G data connection will be disabled when the specified limit is reached.\n\nTo avoid overage charges, consider using a reduced limit, as device and carrier accounting methods may vary.</string>
|
||||
|
||||
</resources>
|
||||
|
@@ -21,8 +21,12 @@ import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND;
|
||||
import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL;
|
||||
import static com.android.settings.DataUsageSummary.getHistoryBounds;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
@@ -55,6 +59,8 @@ public class DataUsageAppDetail extends Fragment {
|
||||
|
||||
private int mUid;
|
||||
|
||||
private static final String TAG_CONFIRM_RESTRICT = "confirmRestrict";
|
||||
|
||||
private INetworkStatsService mStatsService;
|
||||
private INetworkPolicyManager mPolicyService;
|
||||
|
||||
@@ -167,6 +173,19 @@ public class DataUsageAppDetail extends Fragment {
|
||||
mText1.setText(Formatter.formatFileSize(context, totalCombined));
|
||||
}
|
||||
|
||||
private void setRestrictBackground(boolean restrictBackground) {
|
||||
if (LOGD) Log.d(TAG, "setRestrictBackground()");
|
||||
try {
|
||||
mPolicyService.setUidPolicy(
|
||||
mUid, restrictBackground ? POLICY_REJECT_PAID_BACKGROUND : POLICY_NONE);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("unable to save policy", e);
|
||||
}
|
||||
|
||||
mRestrictBackground.setChecked(restrictBackground);
|
||||
refreshPreferenceViews();
|
||||
}
|
||||
|
||||
/**
|
||||
* Force rebind of hijacked {@link Preference} views.
|
||||
*/
|
||||
@@ -209,16 +228,48 @@ public class DataUsageAppDetail extends Fragment {
|
||||
/** {@inheritDoc} */
|
||||
public void onClick(View v) {
|
||||
final boolean restrictBackground = !mRestrictBackground.isChecked();
|
||||
mRestrictBackground.setChecked(restrictBackground);
|
||||
refreshPreferenceViews();
|
||||
|
||||
try {
|
||||
mPolicyService.setUidPolicy(
|
||||
mUid, restrictBackground ? POLICY_REJECT_PAID_BACKGROUND : POLICY_NONE);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("unable to save policy", e);
|
||||
if (restrictBackground) {
|
||||
// enabling restriction; show confirmation dialog which
|
||||
// eventually calls setRestrictBackground() once user confirms.
|
||||
ConfirmRestrictFragment.show(DataUsageAppDetail.this);
|
||||
} else {
|
||||
setRestrictBackground(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dialog to request user confirmation before setting
|
||||
* {@link #POLICY_REJECT_PAID_BACKGROUND}.
|
||||
*/
|
||||
public static class ConfirmRestrictFragment extends DialogFragment {
|
||||
public static void show(DataUsageAppDetail parent) {
|
||||
final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment();
|
||||
dialog.setTargetFragment(parent, 0);
|
||||
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Context context = getActivity();
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.data_usage_app_restrict_dialog_title);
|
||||
builder.setMessage(R.string.data_usage_app_restrict_dialog);
|
||||
|
||||
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
final DataUsageAppDetail target = (DataUsageAppDetail) getTargetFragment();
|
||||
if (target != null) {
|
||||
target.setRestrictBackground(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -25,8 +25,12 @@ import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL;
|
||||
import static android.net.TrafficStats.TEMPLATE_WIFI;
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.INetworkPolicyManager;
|
||||
@@ -61,6 +65,7 @@ import android.widget.ArrayAdapter;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.NumberPicker;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TabHost;
|
||||
import android.widget.TabHost.OnTabChangeListener;
|
||||
@@ -90,6 +95,9 @@ public class DataUsageSummary extends Fragment {
|
||||
private static final String TAB_MOBILE = "mobile";
|
||||
private static final String TAB_WIFI = "wifi";
|
||||
|
||||
private static final String TAG_CONFIRM_LIMIT = "confirmLimit";
|
||||
private static final String TAG_CYCLE_EDITOR = "cycleEditor";
|
||||
|
||||
private static final long KB_IN_BYTES = 1024;
|
||||
private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
|
||||
private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
|
||||
@@ -365,6 +373,24 @@ public class DataUsageSummary extends Fragment {
|
||||
refreshPreferenceViews();
|
||||
}
|
||||
|
||||
private void setPolicyCycleDay(int cycleDay) {
|
||||
if (LOGD) Log.d(TAG, "setPolicyCycleDay()");
|
||||
mPolicyModifier.setPolicyCycleDay(mTemplate, cycleDay);
|
||||
updatePolicy(true);
|
||||
}
|
||||
|
||||
private void setPolicyWarningBytes(long warningBytes) {
|
||||
if (LOGD) Log.d(TAG, "setPolicyWarningBytes()");
|
||||
mPolicyModifier.setPolicyWarningBytes(mTemplate, warningBytes);
|
||||
updatePolicy(false);
|
||||
}
|
||||
|
||||
private void setPolicyLimitBytes(long limitBytes) {
|
||||
if (LOGD) Log.d(TAG, "setPolicyLimitBytes()");
|
||||
mPolicyModifier.setPolicyLimitBytes(mTemplate, limitBytes);
|
||||
updatePolicy(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update chart sweeps and cycle list to reflect {@link NetworkPolicy} for
|
||||
* current {@link #mTemplate}.
|
||||
@@ -474,14 +500,13 @@ public class DataUsageSummary extends Fragment {
|
||||
/** {@inheritDoc} */
|
||||
public void onClick(View v) {
|
||||
final boolean disableAtLimit = !mDisableAtLimit.isChecked();
|
||||
mDisableAtLimit.setChecked(disableAtLimit);
|
||||
refreshPreferenceViews();
|
||||
|
||||
// TODO: create policy if none exists
|
||||
// TODO: show interstitial warning dialog to user
|
||||
final long limitBytes = disableAtLimit ? 5 * GB_IN_BYTES : LIMIT_DISABLED;
|
||||
mPolicyModifier.setPolicyLimitBytes(mTemplate, limitBytes);
|
||||
updatePolicy(false);
|
||||
if (disableAtLimit) {
|
||||
// enabling limit; show confirmation dialog which eventually
|
||||
// calls setPolicyLimitBytes() once user confirms.
|
||||
ConfirmLimitFragment.show(DataUsageSummary.this);
|
||||
} else {
|
||||
setPolicyLimitBytes(LIMIT_DISABLED);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -504,12 +529,15 @@ public class DataUsageSummary extends Fragment {
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
final CycleItem cycle = (CycleItem) parent.getItemAtPosition(position);
|
||||
if (cycle instanceof CycleChangeItem) {
|
||||
// TODO: show "define cycle" dialog
|
||||
// also reset back to first cycle
|
||||
Log.d(TAG, "CHANGE CYCLE DIALOG!!");
|
||||
// show cycle editor; will eventually call setPolicyCycleDay()
|
||||
// when user finishes editing.
|
||||
CycleEditorFragment.show(DataUsageSummary.this);
|
||||
|
||||
// reset spinner to something other than "change cycle..."
|
||||
mCycleSpinner.setSelection(0);
|
||||
|
||||
} else {
|
||||
if (LOGD) Log.d(TAG, "shoiwng cycle " + cycle);
|
||||
if (LOGD) Log.d(TAG, "showing cycle " + cycle);
|
||||
|
||||
// update chart to show selected cycle, and update detail data
|
||||
// to match updated sweep bounds.
|
||||
@@ -558,19 +586,12 @@ public class DataUsageSummary extends Fragment {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void onWarningChanged() {
|
||||
if (LOGD) Log.d(TAG, "onWarningChanged()");
|
||||
final long warningBytes = mChart.getWarningBytes();
|
||||
mPolicyModifier.setPolicyWarningBytes(mTemplate, warningBytes);
|
||||
updatePolicy(false);
|
||||
setPolicyWarningBytes(mChart.getWarningBytes());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void onLimitChanged() {
|
||||
if (LOGD) Log.d(TAG, "onLimitChanged()");
|
||||
final long limitBytes = mDisableAtLimit.isChecked() ? mChart.getLimitBytes()
|
||||
: LIMIT_DISABLED;
|
||||
mPolicyModifier.setPolicyLimitBytes(mTemplate, limitBytes);
|
||||
updatePolicy(false);
|
||||
setPolicyLimitBytes(mChart.getLimitBytes());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -696,5 +717,116 @@ public class DataUsageSummary extends Fragment {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog to request user confirmation before setting
|
||||
* {@link NetworkPolicy#limitBytes}.
|
||||
*/
|
||||
public static class ConfirmLimitFragment extends DialogFragment {
|
||||
public static final String EXTRA_MESSAGE_ID = "messageId";
|
||||
public static final String EXTRA_LIMIT_BYTES = "limitBytes";
|
||||
|
||||
public static void show(DataUsageSummary parent) {
|
||||
final Bundle args = new Bundle();
|
||||
|
||||
// TODO: customize default limits based on network template
|
||||
switch (parent.mTemplate) {
|
||||
case TEMPLATE_MOBILE_3G_LOWER: {
|
||||
args.putInt(EXTRA_MESSAGE_ID, R.string.data_usage_limit_dialog_3g);
|
||||
args.putLong(EXTRA_LIMIT_BYTES, 5 * GB_IN_BYTES);
|
||||
break;
|
||||
}
|
||||
case TEMPLATE_MOBILE_4G: {
|
||||
args.putInt(EXTRA_MESSAGE_ID, R.string.data_usage_limit_dialog_4g);
|
||||
args.putLong(EXTRA_LIMIT_BYTES, 5 * GB_IN_BYTES);
|
||||
break;
|
||||
}
|
||||
case TEMPLATE_MOBILE_ALL: {
|
||||
args.putInt(EXTRA_MESSAGE_ID, R.string.data_usage_limit_dialog_mobile);
|
||||
args.putLong(EXTRA_LIMIT_BYTES, 5 * GB_IN_BYTES);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final ConfirmLimitFragment dialog = new ConfirmLimitFragment();
|
||||
dialog.setArguments(args);
|
||||
dialog.setTargetFragment(parent, 0);
|
||||
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_LIMIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Context context = getActivity();
|
||||
|
||||
final int messageId = getArguments().getInt(EXTRA_MESSAGE_ID);
|
||||
final long limitBytes = getArguments().getLong(EXTRA_LIMIT_BYTES);
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.data_usage_limit_dialog_title);
|
||||
builder.setMessage(messageId);
|
||||
|
||||
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
|
||||
if (target != null) {
|
||||
target.setPolicyLimitBytes(limitBytes);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog to edit {@link NetworkPolicy#cycleDay}.
|
||||
*/
|
||||
public static class CycleEditorFragment extends DialogFragment {
|
||||
public static final String EXTRA_CYCLE_DAY = "cycleDay";
|
||||
|
||||
public static void show(DataUsageSummary parent) {
|
||||
final NetworkPolicy policy = parent.mPolicyModifier.getPolicy(parent.mTemplate);
|
||||
final Bundle args = new Bundle();
|
||||
args.putInt(CycleEditorFragment.EXTRA_CYCLE_DAY, policy.cycleDay);
|
||||
|
||||
final CycleEditorFragment dialog = new CycleEditorFragment();
|
||||
dialog.setArguments(args);
|
||||
dialog.setTargetFragment(parent, 0);
|
||||
dialog.show(parent.getFragmentManager(), TAG_CYCLE_EDITOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Context context = getActivity();
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
|
||||
|
||||
final View view = dialogInflater.inflate(R.layout.data_usage_cycle_editor, null, false);
|
||||
final NumberPicker cycleDayPicker = (NumberPicker) view.findViewById(R.id.cycle_day);
|
||||
|
||||
final int oldCycleDay = getArguments().getInt(EXTRA_CYCLE_DAY, 1);
|
||||
|
||||
cycleDayPicker.setMinValue(1);
|
||||
cycleDayPicker.setMaxValue(31);
|
||||
cycleDayPicker.setValue(oldCycleDay);
|
||||
cycleDayPicker.setWrapSelectorWheel(true);
|
||||
|
||||
builder.setTitle(R.string.data_usage_cycle_editor_title);
|
||||
builder.setView(view);
|
||||
|
||||
builder.setPositiveButton(R.string.data_usage_cycle_editor_positive,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
final int cycleDay = cycleDayPicker.getValue();
|
||||
final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
|
||||
if (target != null) {
|
||||
target.setPolicyCycleDay(cycleDay);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -36,6 +36,8 @@ import java.util.ArrayList;
|
||||
* about which policies can coexist.
|
||||
*/
|
||||
public class NetworkPolicyModifier {
|
||||
// TODO: refactor to "Editor"
|
||||
// TODO: be more robust when missing policies from service
|
||||
|
||||
private INetworkPolicyManager mPolicyService;
|
||||
private String mSubscriberId;
|
||||
|
@@ -127,6 +127,8 @@ public class DataUsageChartView extends ChartView {
|
||||
} else {
|
||||
mSweepDataWarn.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
private OnSweepListener mSweepListener = new OnSweepListener() {
|
||||
@@ -195,6 +197,7 @@ public class DataUsageChartView extends ChartView {
|
||||
|
||||
requestLayout();
|
||||
mSeries.generatePath();
|
||||
mSeries.invalidate();
|
||||
}
|
||||
|
||||
public static class TimeAxis implements ChartAxis {
|
||||
|
Reference in New Issue
Block a user