1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settingslib;
18
19import static android.net.NetworkPolicy.CYCLE_NONE;
20import static android.net.NetworkPolicy.LIMIT_DISABLED;
21import static android.net.NetworkPolicy.SNOOZE_NEVER;
22import static android.net.NetworkPolicy.WARNING_DISABLED;
23import static android.net.NetworkTemplate.MATCH_WIFI;
24import static com.android.internal.util.Preconditions.checkNotNull;
25
26import android.net.NetworkPolicy;
27import android.net.NetworkPolicyManager;
28import android.net.NetworkTemplate;
29import android.net.wifi.WifiInfo;
30import android.os.AsyncTask;
31import android.text.TextUtils;
32import android.text.format.Time;
33
34import com.google.android.collect.Lists;
35
36import java.util.ArrayList;
37
38/**
39 * Utility class to modify list of {@link NetworkPolicy}. Specifically knows
40 * about which policies can coexist. This editor offers thread safety when
41 * talking with {@link NetworkPolicyManager}.
42 *
43 * @hide
44 */
45public class NetworkPolicyEditor {
46    // TODO: be more robust when missing policies from service
47
48    public static final boolean ENABLE_SPLIT_POLICIES = false;
49
50    private NetworkPolicyManager mPolicyManager;
51    private ArrayList<NetworkPolicy> mPolicies = Lists.newArrayList();
52
53    public NetworkPolicyEditor(NetworkPolicyManager policyManager) {
54        mPolicyManager = checkNotNull(policyManager);
55    }
56
57    public void read() {
58        final NetworkPolicy[] policies = mPolicyManager.getNetworkPolicies();
59
60        boolean modified = false;
61        mPolicies.clear();
62        for (NetworkPolicy policy : policies) {
63            // TODO: find better place to clamp these
64            if (policy.limitBytes < -1) {
65                policy.limitBytes = LIMIT_DISABLED;
66                modified = true;
67            }
68            if (policy.warningBytes < -1) {
69                policy.warningBytes = WARNING_DISABLED;
70                modified = true;
71            }
72
73            mPolicies.add(policy);
74        }
75
76        // when we cleaned policies above, write back changes
77        if (modified) writeAsync();
78    }
79
80    public void writeAsync() {
81        // TODO: consider making more robust by passing through service
82        final NetworkPolicy[] policies = mPolicies.toArray(new NetworkPolicy[mPolicies.size()]);
83        new AsyncTask<Void, Void, Void>() {
84            @Override
85            protected Void doInBackground(Void... params) {
86                write(policies);
87                return null;
88            }
89        }.execute();
90    }
91
92    public void write(NetworkPolicy[] policies) {
93        mPolicyManager.setNetworkPolicies(policies);
94    }
95
96    public boolean hasLimitedPolicy(NetworkTemplate template) {
97        final NetworkPolicy policy = getPolicy(template);
98        return policy != null && policy.limitBytes != LIMIT_DISABLED;
99    }
100
101    public NetworkPolicy getOrCreatePolicy(NetworkTemplate template) {
102        NetworkPolicy policy = getPolicy(template);
103        if (policy == null) {
104            policy = buildDefaultPolicy(template);
105            mPolicies.add(policy);
106        }
107        return policy;
108    }
109
110    public NetworkPolicy getPolicy(NetworkTemplate template) {
111        for (NetworkPolicy policy : mPolicies) {
112            if (policy.template.equals(template)) {
113                return policy;
114            }
115        }
116        return null;
117    }
118
119    public NetworkPolicy getPolicyMaybeUnquoted(NetworkTemplate template) {
120        NetworkPolicy policy = getPolicy(template);
121        if (policy != null) {
122            return policy;
123        } else {
124            return getPolicy(buildUnquotedNetworkTemplate(template));
125        }
126    }
127
128    @Deprecated
129    private static NetworkPolicy buildDefaultPolicy(NetworkTemplate template) {
130        // TODO: move this into framework to share with NetworkPolicyManagerService
131        final int cycleDay;
132        final String cycleTimezone;
133        final boolean metered;
134
135        if (template.getMatchRule() == MATCH_WIFI) {
136            cycleDay = CYCLE_NONE;
137            cycleTimezone = Time.TIMEZONE_UTC;
138            metered = false;
139        } else {
140            final Time time = new Time();
141            time.setToNow();
142            cycleDay = time.monthDay;
143            cycleTimezone = time.timezone;
144            metered = true;
145        }
146
147        return new NetworkPolicy(template, cycleDay, cycleTimezone, WARNING_DISABLED,
148                LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, metered, true);
149    }
150
151    public int getPolicyCycleDay(NetworkTemplate template) {
152        final NetworkPolicy policy = getPolicy(template);
153        return (policy != null) ? policy.cycleDay : -1;
154    }
155
156    public void setPolicyCycleDay(NetworkTemplate template, int cycleDay, String cycleTimezone) {
157        final NetworkPolicy policy = getOrCreatePolicy(template);
158        policy.cycleDay = cycleDay;
159        policy.cycleTimezone = cycleTimezone;
160        policy.inferred = false;
161        policy.clearSnooze();
162        writeAsync();
163    }
164
165    public long getPolicyWarningBytes(NetworkTemplate template) {
166        final NetworkPolicy policy = getPolicy(template);
167        return (policy != null) ? policy.warningBytes : WARNING_DISABLED;
168    }
169
170    public void setPolicyWarningBytes(NetworkTemplate template, long warningBytes) {
171        final NetworkPolicy policy = getOrCreatePolicy(template);
172        policy.warningBytes = warningBytes;
173        policy.inferred = false;
174        policy.clearSnooze();
175        writeAsync();
176    }
177
178    public long getPolicyLimitBytes(NetworkTemplate template) {
179        final NetworkPolicy policy = getPolicy(template);
180        return (policy != null) ? policy.limitBytes : LIMIT_DISABLED;
181    }
182
183    public void setPolicyLimitBytes(NetworkTemplate template, long limitBytes) {
184        final NetworkPolicy policy = getOrCreatePolicy(template);
185        policy.limitBytes = limitBytes;
186        policy.inferred = false;
187        policy.clearSnooze();
188        writeAsync();
189    }
190
191    public boolean getPolicyMetered(NetworkTemplate template) {
192        NetworkPolicy policy = getPolicy(template);
193        if (policy != null) {
194            return policy.metered;
195        } else {
196            return false;
197        }
198    }
199
200    public void setPolicyMetered(NetworkTemplate template, boolean metered) {
201        boolean modified = false;
202
203        NetworkPolicy policy = getPolicy(template);
204        if (metered) {
205            if (policy == null) {
206                policy = buildDefaultPolicy(template);
207                policy.metered = true;
208                policy.inferred = false;
209                mPolicies.add(policy);
210                modified = true;
211            } else if (!policy.metered) {
212                policy.metered = true;
213                policy.inferred = false;
214                modified = true;
215            }
216
217        } else {
218            if (policy == null) {
219                // ignore when policy doesn't exist
220            } else if (policy.metered) {
221                policy.metered = false;
222                policy.inferred = false;
223                modified = true;
224            }
225        }
226
227        // Remove legacy unquoted policies while we're here
228        final NetworkTemplate unquoted = buildUnquotedNetworkTemplate(template);
229        final NetworkPolicy unquotedPolicy = getPolicy(unquoted);
230        if (unquotedPolicy != null) {
231            mPolicies.remove(unquotedPolicy);
232            modified = true;
233        }
234
235        if (modified) writeAsync();
236    }
237
238    /**
239     * Build a revised {@link NetworkTemplate} that matches the same rule, but
240     * with an unquoted {@link NetworkTemplate#getNetworkId()}. Used to work
241     * around legacy bugs.
242     */
243    private static NetworkTemplate buildUnquotedNetworkTemplate(NetworkTemplate template) {
244        if (template == null) return null;
245        final String networkId = template.getNetworkId();
246        final String strippedNetworkId = WifiInfo.removeDoubleQuotes(networkId);
247        if (!TextUtils.equals(strippedNetworkId, networkId)) {
248            return new NetworkTemplate(
249                    template.getMatchRule(), template.getSubscriberId(), strippedNetworkId);
250        } else {
251            return null;
252        }
253    }
254}
255