Merge "Start reading drp setting from GoogleSetting" into lmp-dev
diff --git a/chromium/java/com/android/webview/chromium/DataReductionProxyManager.java b/chromium/java/com/android/webview/chromium/DataReductionProxyManager.java
new file mode 100644
index 0000000..54e2151
--- /dev/null
+++ b/chromium/java/com/android/webview/chromium/DataReductionProxyManager.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2014 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.webview.chromium;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.Log;
+import android.webkit.WebView;
+
+import org.chromium.android_webview.AwContentsStatics;
+
+/**
+ * Controls data reduction proxy. This logic will be moved to upstream fully.
+ */
+public final class DataReductionProxyManager {
+
+    // The setting Uri. Used when querying GoogleSettings.
+    private static final Uri CONTENT_URI = Uri.parse("content://com.google.settings/partner");
+
+    // Setting name for allowing data reduction proxy. Used when querying GoogleSettings.
+    // Setting type: int ( 0 = disallow, 1 = allow )
+    private static final String WEBVIEW_DATA_REDUCTION_PROXY = "use_webview_data_reduction_proxy";
+
+    private static final String TAG = "DataReductionProxySettingListener";
+
+    /*
+     * Listen for DataReductionProxySetting changes and take action.
+     * TODO: This is the old mechanism. Will be obsolete after L release.
+     * remove before release.
+     */
+    private static final class ProxySettingListener extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            applyDataReductionProxySettingsAsync(context);
+        }
+    }
+
+    // Accessed from multiple threads.
+    private volatile static boolean sOptedOutDataReductionProxy = false;
+
+    private ProxySettingListener mProxySettingListener;
+
+    private ContentObserver mProxySettingObserver;
+
+    public DataReductionProxyManager() { }
+
+    public void start(final Context context) {
+        applyDataReductionProxySettingsAsync(context);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WebView.DATA_REDUCTION_PROXY_SETTING_CHANGED);
+        mProxySettingListener = new ProxySettingListener();
+        context.registerReceiver(mProxySettingListener, filter);
+        ContentResolver resolver = context.getContentResolver();
+        mProxySettingObserver = new ContentObserver(new Handler()) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                applyDataReductionProxySettingsAsync(context);
+            }
+        };
+        resolver.registerContentObserver(
+                    Uri.withAppendedPath(CONTENT_URI, WEBVIEW_DATA_REDUCTION_PROXY),
+                    false, mProxySettingObserver);
+    }
+
+    private static class ProxySettings {
+        boolean enabled;
+        String key;
+    }
+
+    private static void applyDataReductionProxySettingsAsync(final Context context) {
+        AsyncTask<Void, Void, ProxySettings> task = new AsyncTask<Void, Void, ProxySettings>() {
+            @Override
+            protected ProxySettings doInBackground(Void... params) {
+                return readProxySettings(context);
+            }
+            @Override
+            protected void onPostExecute(ProxySettings settings) {
+                if (settings.enabled) {
+                    // Set the data reduction proxy key.
+                    AwContentsStatics.setDataReductionProxyKey(settings.key);
+                }
+                AwContentsStatics.setDataReductionProxyEnabled(settings.enabled);
+            }
+        };
+        task.execute();
+    }
+
+    private static ProxySettings readProxySettings(Context context) {
+        ProxySettings settings = new ProxySettings();
+        settings.enabled = isDataReductionProxyEnabled(context);
+        if (settings.enabled) {
+            // Re-read the key in case it was updated.
+            String key = Settings.Secure.getString(context.getContentResolver(),
+                Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY);
+            if (key == null || key.isEmpty()) {
+                Log.w(TAG, "No DRP key available");
+                settings.enabled = false;
+            }
+            settings.key = key;
+        }
+        return settings;
+    }
+
+    private static boolean isDataReductionProxyEnabled(Context context) {
+        if (sOptedOutDataReductionProxy) {
+            return false;
+        }
+
+        boolean enabled = getProxySetting(context.getContentResolver(),
+                    WEBVIEW_DATA_REDUCTION_PROXY) != 0;
+        // intentional fallback. remove before L release.
+        if (!enabled) {
+            enabled = Settings.Secure.getInt(context.getContentResolver(),
+                        Settings.Secure.WEBVIEW_DATA_REDUCTION_PROXY, 0) != 0;
+        }
+        return enabled;
+    }
+
+    // Read query setting from GoogleSettings.
+    private static int getProxySetting(ContentResolver resolver, String name) {
+        String value = null;
+        Cursor c = null;
+        try {
+            c = resolver.query(CONTENT_URI, new String[] { "value" },
+                    "name=?", new String[]{ name }, null);
+            if (c != null && c.moveToNext()) value = c.getString(0);
+        } catch (SQLException e) {
+            // SQL error: return null, but don't cache it.
+            Log.e(TAG, "Can't get key " + name + " from " + CONTENT_URI, e);
+        } finally {
+            if (c != null) c.close();
+        }
+        int enabled = 0;
+        try {
+            if (value != null) {
+                enabled = Integer.parseInt(value);
+            }
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "cannot parse" + value, e);
+        }
+        return enabled;
+    }
+
+    // UI thread
+    public static void optOutDataReductionProxy() {
+        if (!sOptedOutDataReductionProxy) {
+            sOptedOutDataReductionProxy = true;
+            AwContentsStatics.setDataReductionProxyEnabled(false);
+        }
+    }
+}
diff --git a/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index 067ce0b..b26ad35 100644
--- a/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -20,17 +20,13 @@
 import android.content.res.Resources;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
-import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.Looper;
 import android.os.SystemProperties;
 import android.os.Trace;
-import android.provider.Settings;
 import android.util.Log;
 import android.webkit.CookieManager;
 import android.webkit.GeolocationPermissions;
@@ -68,16 +64,6 @@
 
 public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
 
-    /*
-     * Listen for DataReductionProxySetting changes and take action.
-     */
-    private static final class DataReductionProxySettingListener extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            EnableDataReductionProxyIfNecessary(context);
-        }
-    }
-
     private static final String TAG = "WebViewChromiumFactoryProvider";
 
     private static final String CHROMIUM_PREFS_NAME = "WebViewChromiumPrefs";
@@ -103,10 +89,7 @@
     // Read/write protected by mLock.
     private boolean mStarted;
 
-    private DataReductionProxySettingListener mProxySettingListener;
-    // TODO(sgurun) Temporary. Remove this after a corresponding CL to keep this state in
-    // AwContentsStatics is merged to M37.
-    private static boolean sOptedOutDataReductionProxy = false;
+    private DataReductionProxyManager mProxyManager;
 
     public WebViewChromiumFactoryProvider() {
         ThreadUtils.setWillOverrideUiThread();
@@ -167,7 +150,7 @@
         });
         while (!mStarted) {
             try {
-                // Important: wait() releases |mLock| so the UI thread can take it :-)
+                // Important: wait() releases |mLock| the UI thread can take it :-)
                 mLock.wait();
             } catch (InterruptedException e) {
                 // Keep trying... eventually the UI thread will process the task we sent it.
@@ -244,49 +227,9 @@
         mWebViewsToStart.clear();
         mWebViewsToStart = null;
 
-        // starts listening for data reduction proxy setting changes.
-        initDataReductionProxySettingListener(ActivityThread.currentApplication());
-    }
-
-    private void initDataReductionProxySettingListener(Context context) {
-        EnableDataReductionProxyIfNecessary(context);
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(WebView.DATA_REDUCTION_PROXY_SETTING_CHANGED);
-        mProxySettingListener = new DataReductionProxySettingListener();
-        context.registerReceiver(mProxySettingListener, filter);
-    }
-
-    private static void EnableDataReductionProxyIfNecessary(Context context) {
-        boolean enabled = isDataReductionProxyEnabled(context);
-        if (enabled) {
-            // Re-read the key in case it was updated.
-            String key = Settings.Secure.getString(context.getContentResolver(),
-                Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY);
-            if (key == null || key.isEmpty()) {
-                Log.w(TAG, "No DRP key available");
-                return;
-            }
-            // Set the data reduction proxy key.
-            AwContentsStatics.setDataReductionProxyKey(key);
-        }
-        AwContentsStatics.setDataReductionProxyEnabled(enabled);
-    }
-
-    private static boolean isDataReductionProxyEnabled(Context context) {
-        if (sOptedOutDataReductionProxy) {
-            return false;
-        }
-        return Settings.Secure.getInt(context.getContentResolver(),
-                    Settings.Secure.WEBVIEW_DATA_REDUCTION_PROXY, 0) != 0;
-    }
-
-    // TODO(sgurun) Temporary. Remove this logic after a corresponding CL to have this logic
-    // in AwContentsStatics is merged to M37.
-    private static void optOutDataReductionProxy() {
-        if (!sOptedOutDataReductionProxy) {
-            sOptedOutDataReductionProxy = true;
-            AwContentsStatics.setDataReductionProxyEnabled(false);
-        }
+        // Start listening for data reduction proxy setting changes.
+        mProxyManager = new DataReductionProxyManager();
+        mProxyManager.start(ActivityThread.currentApplication());
     }
 
     boolean hasStarted() {
@@ -385,10 +328,7 @@
 
                     @Override
                     public void optOutDataReductionProxy() {
-                        // TODO(sgurun) Normally I would route this through AwContentsStatics,
-                        // however we need to merge it to M37. Due to a conflict in API deadlines vs. M37, wil
-                        // route it from WebViewChromiumFactoryProvider for now.
-                        WebViewChromiumFactoryProvider.this.optOutDataReductionProxy();
+                        DataReductionProxyManager.optOutDataReductionProxy();
                     }
 
                     // TODO: Add @Override.