Modifier to combine/split mobile network policy.
Create NetworkPolicyModifier which knows about which mobile network policies can coexist. Settings UI uses this modifier to drive UI and persist policies. Change-Id: Ib3f3841b0a74c14eefb99209dd644a2e7b7e525d
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.settings;
|
package com.android.settings;
|
||||||
|
|
||||||
|
import static android.net.NetworkPolicy.LIMIT_DISABLED;
|
||||||
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
|
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
|
||||||
import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
|
import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
|
||||||
import static android.net.TrafficStats.TEMPLATE_MOBILE_3G_LOWER;
|
import static android.net.TrafficStats.TEMPLATE_MOBILE_3G_LOWER;
|
||||||
@@ -37,6 +38,8 @@ import android.os.RemoteException;
|
|||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.preference.CheckBoxPreference;
|
import android.preference.CheckBoxPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
|
import android.preference.SwitchPreference;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.text.format.Formatter;
|
import android.text.format.Formatter;
|
||||||
import android.text.format.Time;
|
import android.text.format.Time;
|
||||||
@@ -64,6 +67,7 @@ import android.widget.TabHost.TabSpec;
|
|||||||
import android.widget.TabWidget;
|
import android.widget.TabWidget;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.settings.net.NetworkPolicyModifier;
|
||||||
import com.android.settings.widget.DataUsageChartView;
|
import com.android.settings.widget.DataUsageChartView;
|
||||||
import com.android.settings.widget.DataUsageChartView.DataUsageChartListener;
|
import com.android.settings.widget.DataUsageChartView.DataUsageChartListener;
|
||||||
import com.google.android.collect.Lists;
|
import com.google.android.collect.Lists;
|
||||||
@@ -99,7 +103,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private View mHeader;
|
private View mHeader;
|
||||||
private LinearLayout mSwitches;
|
private LinearLayout mSwitches;
|
||||||
|
|
||||||
private CheckBoxPreference mDataEnabled;
|
private SwitchPreference mDataEnabled;
|
||||||
private CheckBoxPreference mDisableAtLimit;
|
private CheckBoxPreference mDisableAtLimit;
|
||||||
private View mDataEnabledView;
|
private View mDataEnabledView;
|
||||||
private View mDisableAtLimitView;
|
private View mDisableAtLimitView;
|
||||||
@@ -109,25 +113,28 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private Spinner mCycleSpinner;
|
private Spinner mCycleSpinner;
|
||||||
private CycleAdapter mCycleAdapter;
|
private CycleAdapter mCycleAdapter;
|
||||||
|
|
||||||
private boolean mSplit4G = false;
|
// TODO: persist show wifi flag
|
||||||
private boolean mShowWifi = false;
|
private boolean mShowWifi = false;
|
||||||
|
|
||||||
private int mTemplate = TEMPLATE_INVALID;
|
private int mTemplate = TEMPLATE_INVALID;
|
||||||
|
|
||||||
private NetworkPolicy mPolicy;
|
private NetworkPolicyModifier mPolicyModifier;
|
||||||
private NetworkStatsHistory mHistory;
|
private NetworkStatsHistory mHistory;
|
||||||
|
|
||||||
// TODO: policy service should always provide valid stub policy
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
|
||||||
|
|
||||||
mStatsService = INetworkStatsService.Stub.asInterface(
|
mStatsService = INetworkStatsService.Stub.asInterface(
|
||||||
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
|
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
|
||||||
mPolicyService = INetworkPolicyManager.Stub.asInterface(
|
mPolicyService = INetworkPolicyManager.Stub.asInterface(
|
||||||
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
|
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
|
||||||
|
|
||||||
|
final Context context = getActivity();
|
||||||
|
final String subscriberId = getActiveSubscriberId(context);
|
||||||
|
mPolicyModifier = new NetworkPolicyModifier(mPolicyService, subscriberId);
|
||||||
|
|
||||||
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -147,7 +154,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
mHeader = inflater.inflate(R.layout.data_usage_header, mListView, false);
|
mHeader = inflater.inflate(R.layout.data_usage_header, mListView, false);
|
||||||
mListView.addHeaderView(mHeader, null, false);
|
mListView.addHeaderView(mHeader, null, false);
|
||||||
|
|
||||||
mDataEnabled = new CheckBoxPreference(context);
|
mDataEnabled = new SwitchPreference(context);
|
||||||
mDisableAtLimit = new CheckBoxPreference(context);
|
mDisableAtLimit = new CheckBoxPreference(context);
|
||||||
|
|
||||||
// kick refresh once to force-create views
|
// kick refresh once to force-create views
|
||||||
@@ -185,6 +192,9 @@ public class DataUsageSummary extends Fragment {
|
|||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
|
// read current policy state from service
|
||||||
|
mPolicyModifier.read();
|
||||||
|
|
||||||
// this kicks off chain reaction which creates tabs, binds the body to
|
// this kicks off chain reaction which creates tabs, binds the body to
|
||||||
// selected network, and binds chart, cycles and detail list.
|
// selected network, and binds chart, cycles and detail list.
|
||||||
updateTabs();
|
updateTabs();
|
||||||
@@ -196,13 +206,18 @@ public class DataUsageSummary extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public void onPrepareOptionsMenu(Menu menu) {
|
||||||
// TODO: persist checked-ness of options to restore tabs later
|
final MenuItem split4g = menu.findItem(R.id.action_split_4g);
|
||||||
|
split4g.setChecked(mPolicyModifier.isMobilePolicySplit());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.action_split_4g: {
|
case R.id.action_split_4g: {
|
||||||
mSplit4G = !item.isChecked();
|
final boolean mobileSplit = !item.isChecked();
|
||||||
item.setChecked(mSplit4G);
|
mPolicyModifier.setMobilePolicySplit(mobileSplit);
|
||||||
|
item.setChecked(mPolicyModifier.isMobilePolicySplit());
|
||||||
updateTabs();
|
updateTabs();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -217,24 +232,23 @@ public class DataUsageSummary extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rebuild all tabs based on {@link #mSplit4G} and {@link #mShowWifi},
|
* Rebuild all tabs based on {@link NetworkPolicyModifier} and
|
||||||
* hiding the tabs entirely when applicable. Selects first tab, and kicks
|
* {@link #mShowWifi}, hiding the tabs entirely when applicable. Selects
|
||||||
* off a full rebind of body contents.
|
* first tab, and kicks off a full rebind of body contents.
|
||||||
*/
|
*/
|
||||||
private void updateTabs() {
|
private void updateTabs() {
|
||||||
// TODO: persist/restore if user wants mobile split, or wifi visibility
|
final boolean mobileSplit = mPolicyModifier.isMobilePolicySplit();
|
||||||
|
final boolean tabsVisible = mobileSplit || mShowWifi;
|
||||||
final boolean tabsVisible = mSplit4G || mShowWifi;
|
|
||||||
mTabWidget.setVisibility(tabsVisible ? View.VISIBLE : View.GONE);
|
mTabWidget.setVisibility(tabsVisible ? View.VISIBLE : View.GONE);
|
||||||
mTabHost.clearAllTabs();
|
mTabHost.clearAllTabs();
|
||||||
|
|
||||||
if (mSplit4G) {
|
if (mobileSplit) {
|
||||||
mTabHost.addTab(buildTabSpec(TAB_3G, R.string.data_usage_tab_3g));
|
mTabHost.addTab(buildTabSpec(TAB_3G, R.string.data_usage_tab_3g));
|
||||||
mTabHost.addTab(buildTabSpec(TAB_4G, R.string.data_usage_tab_4g));
|
mTabHost.addTab(buildTabSpec(TAB_4G, R.string.data_usage_tab_4g));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mShowWifi) {
|
if (mShowWifi) {
|
||||||
if (!mSplit4G) {
|
if (!mobileSplit) {
|
||||||
mTabHost.addTab(buildTabSpec(TAB_MOBILE, R.string.data_usage_tab_mobile));
|
mTabHost.addTab(buildTabSpec(TAB_MOBILE, R.string.data_usage_tab_mobile));
|
||||||
}
|
}
|
||||||
mTabHost.addTab(buildTabSpec(TAB_WIFI, R.string.data_usage_tab_wifi));
|
mTabHost.addTab(buildTabSpec(TAB_WIFI, R.string.data_usage_tab_wifi));
|
||||||
@@ -323,8 +337,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
mDataEnabled.setChecked(true);
|
mDataEnabled.setChecked(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// load policy and stats for current template
|
// load stats for current template
|
||||||
mPolicy = mPolicyService.getNetworkPolicy(mTemplate, null);
|
|
||||||
mHistory = mStatsService.getHistoryForNetwork(mTemplate);
|
mHistory = mStatsService.getHistoryForNetwork(mTemplate);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// since we can't do much without policy or history, and we don't
|
// since we can't do much without policy or history, and we don't
|
||||||
@@ -332,20 +345,10 @@ public class DataUsageSummary extends Fragment {
|
|||||||
throw new RuntimeException("problem reading network policy or stats", e);
|
throw new RuntimeException("problem reading network policy or stats", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: eventually service will always provide stub policy
|
|
||||||
if (mPolicy == null) {
|
|
||||||
mPolicy = new NetworkPolicy(1, 4 * GB_IN_BYTES, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind chart to historical stats
|
// bind chart to historical stats
|
||||||
mChart.bindNetworkPolicy(mPolicy);
|
|
||||||
mChart.bindNetworkStats(mHistory);
|
mChart.bindNetworkStats(mHistory);
|
||||||
|
|
||||||
// generate cycle list based on policy and available history
|
updatePolicy();
|
||||||
updateCycleList();
|
|
||||||
|
|
||||||
// reflect policy limit in checkbox
|
|
||||||
mDisableAtLimit.setChecked(mPolicy.limitBytes != -1);
|
|
||||||
|
|
||||||
// force scroll to top of body
|
// force scroll to top of body
|
||||||
mListView.smoothScrollToPosition(0);
|
mListView.smoothScrollToPosition(0);
|
||||||
@@ -354,6 +357,24 @@ public class DataUsageSummary extends Fragment {
|
|||||||
refreshPreferenceViews();
|
refreshPreferenceViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update chart sweeps and cycle list to reflect {@link NetworkPolicy} for
|
||||||
|
* current {@link #mTemplate}.
|
||||||
|
*/
|
||||||
|
private void updatePolicy() {
|
||||||
|
final NetworkPolicy policy = mPolicyModifier.getPolicy(mTemplate);
|
||||||
|
|
||||||
|
// reflect policy limit in checkbox
|
||||||
|
mDisableAtLimit.setChecked(policy != null && policy.limitBytes != LIMIT_DISABLED);
|
||||||
|
mChart.bindNetworkPolicy(policy);
|
||||||
|
|
||||||
|
// generate cycle list based on policy and available history
|
||||||
|
updateCycleList(policy);
|
||||||
|
|
||||||
|
// kick preference views so they rebind from changes above
|
||||||
|
refreshPreferenceViews();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return full time bounds (earliest and latest time recorded) of the given
|
* Return full time bounds (earliest and latest time recorded) of the given
|
||||||
* {@link NetworkStatsHistory}.
|
* {@link NetworkStatsHistory}.
|
||||||
@@ -376,7 +397,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
* and available {@link NetworkStatsHistory} data. Always selects the newest
|
* and available {@link NetworkStatsHistory} data. Always selects the newest
|
||||||
* item, updating the inspection range on {@link #mChart}.
|
* item, updating the inspection range on {@link #mChart}.
|
||||||
*/
|
*/
|
||||||
private void updateCycleList() {
|
private void updateCycleList(NetworkPolicy policy) {
|
||||||
mCycleAdapter.clear();
|
mCycleAdapter.clear();
|
||||||
|
|
||||||
final Context context = mCycleSpinner.getContext();
|
final Context context = mCycleSpinner.getContext();
|
||||||
@@ -385,28 +406,36 @@ public class DataUsageSummary extends Fragment {
|
|||||||
final long historyStart = bounds[0];
|
final long historyStart = bounds[0];
|
||||||
final long historyEnd = bounds[1];
|
final long historyEnd = bounds[1];
|
||||||
|
|
||||||
// find the next cycle boundary
|
if (policy != null) {
|
||||||
long cycleEnd = computeNextCycleBoundary(historyEnd, mPolicy);
|
// find the next cycle boundary
|
||||||
|
long cycleEnd = computeNextCycleBoundary(historyEnd, policy);
|
||||||
|
|
||||||
int guardCount = 0;
|
int guardCount = 0;
|
||||||
|
|
||||||
// walk backwards, generating all valid cycle ranges
|
// walk backwards, generating all valid cycle ranges
|
||||||
while (cycleEnd > historyStart) {
|
while (cycleEnd > historyStart) {
|
||||||
final long cycleStart = computeLastCycleBoundary(cycleEnd, mPolicy);
|
final long cycleStart = computeLastCycleBoundary(cycleEnd, policy);
|
||||||
Log.d(TAG, "generating cs=" + cycleStart + " to ce=" + cycleEnd + " waiting for hs="
|
Log.d(TAG, "generating cs=" + cycleStart + " to ce=" + cycleEnd + " waiting for hs="
|
||||||
+ historyStart);
|
+ historyStart);
|
||||||
mCycleAdapter.add(new CycleItem(context, cycleStart, cycleEnd));
|
mCycleAdapter.add(new CycleItem(context, cycleStart, cycleEnd));
|
||||||
cycleEnd = cycleStart;
|
cycleEnd = cycleStart;
|
||||||
|
|
||||||
// TODO: remove this guard once we have better testing
|
// TODO: remove this guard once we have better testing
|
||||||
if (guardCount++ > 50) {
|
if (guardCount++ > 50) {
|
||||||
Log.wtf(TAG, "stuck generating ranges for bounds=" + Arrays.toString(bounds)
|
Log.wtf(TAG, "stuck generating ranges for bounds=" + Arrays.toString(bounds)
|
||||||
+ " and policy=" + mPolicy);
|
+ " and policy=" + policy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// one last cycle entry to change date
|
// one last cycle entry to modify policy cycle day
|
||||||
mCycleAdapter.add(new CycleChangeItem(context));
|
mCycleAdapter.add(new CycleChangeItem(context));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// no valid cycle; show all data
|
||||||
|
// TODO: offer simple ranges like "last week" etc
|
||||||
|
mCycleAdapter.add(new CycleItem(context, historyStart, historyEnd));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// force pick the current cycle (first item)
|
// force pick the current cycle (first item)
|
||||||
mCycleSpinner.setSelection(0);
|
mCycleSpinner.setSelection(0);
|
||||||
@@ -438,11 +467,11 @@ public class DataUsageSummary extends Fragment {
|
|||||||
mDisableAtLimit.setChecked(disableAtLimit);
|
mDisableAtLimit.setChecked(disableAtLimit);
|
||||||
refreshPreferenceViews();
|
refreshPreferenceViews();
|
||||||
|
|
||||||
// TODO: push updated policy to service
|
// TODO: create policy if none exists
|
||||||
// TODO: show interstitial warning dialog to user
|
// TODO: show interstitial warning dialog to user
|
||||||
final long limitBytes = disableAtLimit ? 5 * GB_IN_BYTES : -1;
|
final long limitBytes = disableAtLimit ? 5 * GB_IN_BYTES : LIMIT_DISABLED;
|
||||||
mPolicy = new NetworkPolicy(mPolicy.cycleDay, mPolicy.warningBytes, limitBytes);
|
mPolicyModifier.setPolicyLimitBytes(mTemplate, limitBytes);
|
||||||
mChart.bindNetworkPolicy(mPolicy);
|
updatePolicy();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -500,6 +529,12 @@ public class DataUsageSummary extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getActiveSubscriberId(Context context) {
|
||||||
|
final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
|
||||||
|
Context.TELEPHONY_SERVICE);
|
||||||
|
return telephony.getSubscriberId();
|
||||||
|
}
|
||||||
|
|
||||||
private DataUsageChartListener mChartListener = new DataUsageChartListener() {
|
private DataUsageChartListener mChartListener = new DataUsageChartListener() {
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public void onInspectRangeChanged() {
|
public void onInspectRangeChanged() {
|
||||||
@@ -508,26 +543,20 @@ public class DataUsageSummary extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
public void onLimitsChanged() {
|
public void onWarningChanged() {
|
||||||
if (LOGD) Log.d(TAG, "onLimitsChanged()");
|
if (LOGD) Log.d(TAG, "onWarningChanged()");
|
||||||
|
|
||||||
// redefine policy and persist into service
|
|
||||||
// TODO: kick this onto background thread, since service touches disk
|
|
||||||
|
|
||||||
// TODO: remove this mPolicy null check, since later service will
|
|
||||||
// always define baseline value.
|
|
||||||
final int cycleDay = mPolicy != null ? mPolicy.cycleDay : 1;
|
|
||||||
final long warningBytes = mChart.getWarningBytes();
|
final long warningBytes = mChart.getWarningBytes();
|
||||||
final long limitBytes = mDisableAtLimit.isChecked() ? -1 : mChart.getLimitBytes();
|
mPolicyModifier.setPolicyWarningBytes(mTemplate, warningBytes);
|
||||||
|
updatePolicy();
|
||||||
|
}
|
||||||
|
|
||||||
mPolicy = new NetworkPolicy(cycleDay, warningBytes, limitBytes);
|
/** {@inheritDoc} */
|
||||||
if (LOGD) Log.d(TAG, "persisting policy=" + mPolicy);
|
public void onLimitChanged() {
|
||||||
|
if (LOGD) Log.d(TAG, "onLimitChanged()");
|
||||||
try {
|
final long limitBytes = mDisableAtLimit.isChecked() ? mChart.getLimitBytes()
|
||||||
mPolicyService.setNetworkPolicy(mTemplate, null, mPolicy);
|
: LIMIT_DISABLED;
|
||||||
} catch (RemoteException e) {
|
mPolicyModifier.setPolicyLimitBytes(mTemplate, limitBytes);
|
||||||
Log.w(TAG, "problem persisting policy", e);
|
updatePolicy();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -605,7 +634,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
public void bindStats(NetworkStats stats) {
|
public void bindStats(NetworkStats stats) {
|
||||||
mItems.clear();
|
mItems.clear();
|
||||||
|
|
||||||
for (int i = 0; i < stats.length(); i++) {
|
for (int i = 0; i < stats.size; i++) {
|
||||||
final AppUsageItem item = new AppUsageItem();
|
final AppUsageItem item = new AppUsageItem();
|
||||||
item.uid = stats.uid[i];
|
item.uid = stats.uid[i];
|
||||||
item.total = stats.rx[i] + stats.tx[i];
|
item.total = stats.rx[i] + stats.tx[i];
|
||||||
|
145
src/com/android/settings/net/NetworkPolicyModifier.java
Normal file
145
src/com/android/settings/net/NetworkPolicyModifier.java
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.net;
|
||||||
|
|
||||||
|
import static android.net.TrafficStats.TEMPLATE_MOBILE_3G_LOWER;
|
||||||
|
import static android.net.TrafficStats.TEMPLATE_MOBILE_4G;
|
||||||
|
import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL;
|
||||||
|
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import android.net.INetworkPolicyManager;
|
||||||
|
import android.net.NetworkPolicy;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
import com.android.internal.util.Objects;
|
||||||
|
import com.google.android.collect.Lists;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to modify list of {@link NetworkPolicy}. Specifically knows
|
||||||
|
* about which policies can coexist.
|
||||||
|
*/
|
||||||
|
public class NetworkPolicyModifier {
|
||||||
|
|
||||||
|
private INetworkPolicyManager mPolicyService;
|
||||||
|
private String mSubscriberId;
|
||||||
|
|
||||||
|
private ArrayList<NetworkPolicy> mPolicies = Lists.newArrayList();
|
||||||
|
|
||||||
|
public NetworkPolicyModifier(INetworkPolicyManager policyService, String subscriberId) {
|
||||||
|
mPolicyService = checkNotNull(policyService);
|
||||||
|
mSubscriberId = subscriberId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void read() {
|
||||||
|
try {
|
||||||
|
final NetworkPolicy[] policies = mPolicyService.getNetworkPolicies();
|
||||||
|
mPolicies.clear();
|
||||||
|
for (NetworkPolicy policy : policies) {
|
||||||
|
mPolicies.add(policy);
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw new RuntimeException("problem reading policies", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeAsync() {
|
||||||
|
// TODO: consider making more robust by passing through service
|
||||||
|
new AsyncTask<Void, Void, Void>() {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
write();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write() {
|
||||||
|
try {
|
||||||
|
final NetworkPolicy[] policies = mPolicies.toArray(new NetworkPolicy[mPolicies.size()]);
|
||||||
|
mPolicyService.setNetworkPolicies(policies);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw new RuntimeException("problem reading policies", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkPolicy getPolicy(int networkTemplate) {
|
||||||
|
for (NetworkPolicy policy : mPolicies) {
|
||||||
|
if (policy.networkTemplate == networkTemplate
|
||||||
|
&& Objects.equal(policy.subscriberId, mSubscriberId)) {
|
||||||
|
return policy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPolicyCycleDay(int networkTemplate, int cycleDay) {
|
||||||
|
getPolicy(networkTemplate).cycleDay = cycleDay;
|
||||||
|
writeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPolicyWarningBytes(int networkTemplate, long warningBytes) {
|
||||||
|
getPolicy(networkTemplate).warningBytes = warningBytes;
|
||||||
|
writeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPolicyLimitBytes(int networkTemplate, long limitBytes) {
|
||||||
|
getPolicy(networkTemplate).limitBytes = limitBytes;
|
||||||
|
writeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMobilePolicySplit() {
|
||||||
|
return getPolicy(TEMPLATE_MOBILE_3G_LOWER) != null && getPolicy(TEMPLATE_MOBILE_4G) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMobilePolicySplit(boolean split) {
|
||||||
|
final boolean beforeSplit = isMobilePolicySplit();
|
||||||
|
if (split == beforeSplit) {
|
||||||
|
// already in requested state; skip
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if (beforeSplit && !split) {
|
||||||
|
// combine, picking most restrictive policy
|
||||||
|
final NetworkPolicy policy3g = getPolicy(TEMPLATE_MOBILE_3G_LOWER);
|
||||||
|
final NetworkPolicy policy4g = getPolicy(TEMPLATE_MOBILE_4G);
|
||||||
|
|
||||||
|
final NetworkPolicy restrictive = policy3g.compareTo(policy4g) < 0 ? policy3g
|
||||||
|
: policy4g;
|
||||||
|
mPolicies.remove(policy3g);
|
||||||
|
mPolicies.remove(policy4g);
|
||||||
|
mPolicies.add(new NetworkPolicy(TEMPLATE_MOBILE_ALL, restrictive.subscriberId,
|
||||||
|
restrictive.cycleDay, restrictive.warningBytes, restrictive.limitBytes));
|
||||||
|
writeAsync();
|
||||||
|
|
||||||
|
} else if (!beforeSplit && split) {
|
||||||
|
// duplicate existing policy into two rules
|
||||||
|
final NetworkPolicy policyAll = getPolicy(TEMPLATE_MOBILE_ALL);
|
||||||
|
mPolicies.remove(policyAll);
|
||||||
|
mPolicies.add(
|
||||||
|
new NetworkPolicy(TEMPLATE_MOBILE_3G_LOWER, policyAll.subscriberId,
|
||||||
|
policyAll.cycleDay, policyAll.warningBytes, policyAll.limitBytes));
|
||||||
|
mPolicies.add(
|
||||||
|
new NetworkPolicy(TEMPLATE_MOBILE_4G, policyAll.subscriberId,
|
||||||
|
policyAll.cycleDay, policyAll.warningBytes, policyAll.limitBytes));
|
||||||
|
writeAsync();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -21,6 +21,7 @@ import android.graphics.Color;
|
|||||||
import android.net.NetworkPolicy;
|
import android.net.NetworkPolicy;
|
||||||
import android.net.NetworkStatsHistory;
|
import android.net.NetworkStatsHistory;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import com.android.settings.widget.ChartSweepView.OnSweepListener;
|
import com.android.settings.widget.ChartSweepView.OnSweepListener;
|
||||||
|
|
||||||
@@ -44,7 +45,8 @@ public class DataUsageChartView extends ChartView {
|
|||||||
|
|
||||||
public interface DataUsageChartListener {
|
public interface DataUsageChartListener {
|
||||||
public void onInspectRangeChanged();
|
public void onInspectRangeChanged();
|
||||||
public void onLimitsChanged();
|
public void onWarningChanged();
|
||||||
|
public void onLimitChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataUsageChartListener mListener;
|
private DataUsageChartListener mListener;
|
||||||
@@ -78,6 +80,9 @@ public class DataUsageChartView extends ChartView {
|
|||||||
|
|
||||||
mSeries.bindSweepRange(mSweepTime1, mSweepTime2);
|
mSeries.bindSweepRange(mSweepTime1, mSweepTime2);
|
||||||
|
|
||||||
|
mSweepDataWarn.addOnSweepListener(mWarningListener);
|
||||||
|
mSweepDataLimit.addOnSweepListener(mLimitListener);
|
||||||
|
|
||||||
mSweepTime1.addOnSweepListener(mSweepListener);
|
mSweepTime1.addOnSweepListener(mSweepListener);
|
||||||
mSweepTime2.addOnSweepListener(mSweepListener);
|
mSweepTime2.addOnSweepListener(mSweepListener);
|
||||||
|
|
||||||
@@ -92,15 +97,29 @@ public class DataUsageChartView extends ChartView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void bindNetworkPolicy(NetworkPolicy policy) {
|
public void bindNetworkPolicy(NetworkPolicy policy) {
|
||||||
if (policy.limitBytes != -1) {
|
if (policy == null) {
|
||||||
|
mSweepDataLimit.setVisibility(View.INVISIBLE);
|
||||||
|
mSweepDataWarn.setVisibility(View.INVISIBLE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
|
||||||
|
mSweepDataLimit.setVisibility(View.VISIBLE);
|
||||||
mSweepDataLimit.setValue(policy.limitBytes);
|
mSweepDataLimit.setValue(policy.limitBytes);
|
||||||
mSweepDataLimit.setEnabled(true);
|
mSweepDataLimit.setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: set limit default based on axis maximum
|
||||||
|
mSweepDataLimit.setVisibility(View.VISIBLE);
|
||||||
mSweepDataLimit.setValue(5 * GB_IN_BYTES);
|
mSweepDataLimit.setValue(5 * GB_IN_BYTES);
|
||||||
mSweepDataLimit.setEnabled(false);
|
mSweepDataLimit.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
mSweepDataWarn.setValue(policy.warningBytes);
|
if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) {
|
||||||
|
mSweepDataWarn.setVisibility(View.VISIBLE);
|
||||||
|
mSweepDataWarn.setValue(policy.warningBytes);
|
||||||
|
} else {
|
||||||
|
mSweepDataWarn.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private OnSweepListener mSweepListener = new OnSweepListener() {
|
private OnSweepListener mSweepListener = new OnSweepListener() {
|
||||||
@@ -115,6 +134,22 @@ public class DataUsageChartView extends ChartView {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private OnSweepListener mWarningListener = new OnSweepListener() {
|
||||||
|
public void onSweep(ChartSweepView sweep, boolean sweepDone) {
|
||||||
|
if (sweepDone && mListener != null) {
|
||||||
|
mListener.onWarningChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private OnSweepListener mLimitListener = new OnSweepListener() {
|
||||||
|
public void onSweep(ChartSweepView sweep, boolean sweepDone) {
|
||||||
|
if (sweepDone && mListener != null) {
|
||||||
|
mListener.onLimitChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
Reference in New Issue
Block a user