am b54ec1bd: am d8cdba0d: Merge "Prepare some ConnectivityService logic for fallback to Cellular change" into mnc-dev

* commit 'b54ec1bd527882c5046ed4710fb8f1f9e1b90105':
  Prepare some ConnectivityService logic for fallback to Cellular change
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index de61c31..9a41b75 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7392,11 +7392,7 @@
      * @hide
      */
     public void getOutsets(Rect outOutsetRect) {
-        if (mAttachInfo != null) {
-            outOutsetRect.set(mAttachInfo.mOutsets);
-        } else {
-            outOutsetRect.setEmpty();
-        }
+        outOutsetRect.set(mAttachInfo.mOutsets);
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
new file mode 100644
index 0000000..cf08f50
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
@@ -0,0 +1,254 @@
+/*
+ * 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.settingslib;
+
+import static android.net.NetworkPolicy.CYCLE_NONE;
+import static android.net.NetworkPolicy.LIMIT_DISABLED;
+import static android.net.NetworkPolicy.SNOOZE_NEVER;
+import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkTemplate.MATCH_WIFI;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
+import android.net.NetworkTemplate;
+import android.net.wifi.WifiInfo;
+import android.os.AsyncTask;
+import android.text.TextUtils;
+import android.text.format.Time;
+
+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. This editor offers thread safety when
+ * talking with {@link NetworkPolicyManager}.
+ *
+ * @hide
+ */
+public class NetworkPolicyEditor {
+    // TODO: be more robust when missing policies from service
+
+    public static final boolean ENABLE_SPLIT_POLICIES = false;
+
+    private NetworkPolicyManager mPolicyManager;
+    private ArrayList<NetworkPolicy> mPolicies = Lists.newArrayList();
+
+    public NetworkPolicyEditor(NetworkPolicyManager policyManager) {
+        mPolicyManager = checkNotNull(policyManager);
+    }
+
+    public void read() {
+        final NetworkPolicy[] policies = mPolicyManager.getNetworkPolicies();
+
+        boolean modified = false;
+        mPolicies.clear();
+        for (NetworkPolicy policy : policies) {
+            // TODO: find better place to clamp these
+            if (policy.limitBytes < -1) {
+                policy.limitBytes = LIMIT_DISABLED;
+                modified = true;
+            }
+            if (policy.warningBytes < -1) {
+                policy.warningBytes = WARNING_DISABLED;
+                modified = true;
+            }
+
+            mPolicies.add(policy);
+        }
+
+        // when we cleaned policies above, write back changes
+        if (modified) writeAsync();
+    }
+
+    public void writeAsync() {
+        // TODO: consider making more robust by passing through service
+        final NetworkPolicy[] policies = mPolicies.toArray(new NetworkPolicy[mPolicies.size()]);
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                write(policies);
+                return null;
+            }
+        }.execute();
+    }
+
+    public void write(NetworkPolicy[] policies) {
+        mPolicyManager.setNetworkPolicies(policies);
+    }
+
+    public boolean hasLimitedPolicy(NetworkTemplate template) {
+        final NetworkPolicy policy = getPolicy(template);
+        return policy != null && policy.limitBytes != LIMIT_DISABLED;
+    }
+
+    public NetworkPolicy getOrCreatePolicy(NetworkTemplate template) {
+        NetworkPolicy policy = getPolicy(template);
+        if (policy == null) {
+            policy = buildDefaultPolicy(template);
+            mPolicies.add(policy);
+        }
+        return policy;
+    }
+
+    public NetworkPolicy getPolicy(NetworkTemplate template) {
+        for (NetworkPolicy policy : mPolicies) {
+            if (policy.template.equals(template)) {
+                return policy;
+            }
+        }
+        return null;
+    }
+
+    public NetworkPolicy getPolicyMaybeUnquoted(NetworkTemplate template) {
+        NetworkPolicy policy = getPolicy(template);
+        if (policy != null) {
+            return policy;
+        } else {
+            return getPolicy(buildUnquotedNetworkTemplate(template));
+        }
+    }
+
+    @Deprecated
+    private static NetworkPolicy buildDefaultPolicy(NetworkTemplate template) {
+        // TODO: move this into framework to share with NetworkPolicyManagerService
+        final int cycleDay;
+        final String cycleTimezone;
+        final boolean metered;
+
+        if (template.getMatchRule() == MATCH_WIFI) {
+            cycleDay = CYCLE_NONE;
+            cycleTimezone = Time.TIMEZONE_UTC;
+            metered = false;
+        } else {
+            final Time time = new Time();
+            time.setToNow();
+            cycleDay = time.monthDay;
+            cycleTimezone = time.timezone;
+            metered = true;
+        }
+
+        return new NetworkPolicy(template, cycleDay, cycleTimezone, WARNING_DISABLED,
+                LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, metered, true);
+    }
+
+    public int getPolicyCycleDay(NetworkTemplate template) {
+        final NetworkPolicy policy = getPolicy(template);
+        return (policy != null) ? policy.cycleDay : -1;
+    }
+
+    public void setPolicyCycleDay(NetworkTemplate template, int cycleDay, String cycleTimezone) {
+        final NetworkPolicy policy = getOrCreatePolicy(template);
+        policy.cycleDay = cycleDay;
+        policy.cycleTimezone = cycleTimezone;
+        policy.inferred = false;
+        policy.clearSnooze();
+        writeAsync();
+    }
+
+    public long getPolicyWarningBytes(NetworkTemplate template) {
+        final NetworkPolicy policy = getPolicy(template);
+        return (policy != null) ? policy.warningBytes : WARNING_DISABLED;
+    }
+
+    public void setPolicyWarningBytes(NetworkTemplate template, long warningBytes) {
+        final NetworkPolicy policy = getOrCreatePolicy(template);
+        policy.warningBytes = warningBytes;
+        policy.inferred = false;
+        policy.clearSnooze();
+        writeAsync();
+    }
+
+    public long getPolicyLimitBytes(NetworkTemplate template) {
+        final NetworkPolicy policy = getPolicy(template);
+        return (policy != null) ? policy.limitBytes : LIMIT_DISABLED;
+    }
+
+    public void setPolicyLimitBytes(NetworkTemplate template, long limitBytes) {
+        final NetworkPolicy policy = getOrCreatePolicy(template);
+        policy.limitBytes = limitBytes;
+        policy.inferred = false;
+        policy.clearSnooze();
+        writeAsync();
+    }
+
+    public boolean getPolicyMetered(NetworkTemplate template) {
+        NetworkPolicy policy = getPolicy(template);
+        if (policy != null) {
+            return policy.metered;
+        } else {
+            return false;
+        }
+    }
+
+    public void setPolicyMetered(NetworkTemplate template, boolean metered) {
+        boolean modified = false;
+
+        NetworkPolicy policy = getPolicy(template);
+        if (metered) {
+            if (policy == null) {
+                policy = buildDefaultPolicy(template);
+                policy.metered = true;
+                policy.inferred = false;
+                mPolicies.add(policy);
+                modified = true;
+            } else if (!policy.metered) {
+                policy.metered = true;
+                policy.inferred = false;
+                modified = true;
+            }
+
+        } else {
+            if (policy == null) {
+                // ignore when policy doesn't exist
+            } else if (policy.metered) {
+                policy.metered = false;
+                policy.inferred = false;
+                modified = true;
+            }
+        }
+
+        // Remove legacy unquoted policies while we're here
+        final NetworkTemplate unquoted = buildUnquotedNetworkTemplate(template);
+        final NetworkPolicy unquotedPolicy = getPolicy(unquoted);
+        if (unquotedPolicy != null) {
+            mPolicies.remove(unquotedPolicy);
+            modified = true;
+        }
+
+        if (modified) writeAsync();
+    }
+
+    /**
+     * Build a revised {@link NetworkTemplate} that matches the same rule, but
+     * with an unquoted {@link NetworkTemplate#getNetworkId()}. Used to work
+     * around legacy bugs.
+     */
+    private static NetworkTemplate buildUnquotedNetworkTemplate(NetworkTemplate template) {
+        if (template == null) return null;
+        final String networkId = template.getNetworkId();
+        final String strippedNetworkId = WifiInfo.removeDoubleQuotes(networkId);
+        if (!TextUtils.equals(strippedNetworkId, networkId)) {
+            return new NetworkTemplate(
+                    template.getMatchRule(), template.getSubscriberId(), strippedNetworkId);
+        } else {
+            return null;
+        }
+    }
+}