Upstream version 9.37.195.0
[platform/framework/web/crosswalk.git] / src / net / android / java / src / org / chromium / net / ProxyChangeListener.java
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.net;
6
7 import android.content.BroadcastReceiver;
8 import android.content.Context;
9 import android.content.Intent;
10 import android.content.IntentFilter;
11 import android.net.Proxy;
12 import android.os.Build;
13 import android.util.Log;
14
15 import org.chromium.base.CalledByNative;
16 import org.chromium.base.JNINamespace;
17 import org.chromium.base.NativeClassQualifiedName;
18
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21
22 /**
23  * This class partners with native ProxyConfigServiceAndroid to listen for
24  * proxy change notifications from Android.
25  */
26 @JNINamespace("net")
27 public class ProxyChangeListener {
28     private static final String TAG = "ProxyChangeListener";
29     private static boolean sEnabled = true;
30
31     private long mNativePtr;
32     private Context mContext;
33     private ProxyReceiver mProxyReceiver;
34     private Delegate mDelegate;
35
36     private static class ProxyConfig {
37         public ProxyConfig(String host, int port) {
38             mHost = host;
39             mPort = port;
40         }
41         public final String mHost;
42         public final int mPort;
43     }
44
45     public interface Delegate {
46         public void proxySettingsChanged();
47     }
48
49     private ProxyChangeListener(Context context) {
50         mContext = context;
51     }
52
53     public static void setEnabled(boolean enabled) {
54         sEnabled = enabled;
55     }
56
57     public void setDelegateForTesting(Delegate delegate) {
58         mDelegate = delegate;
59     }
60
61     @CalledByNative
62     public static ProxyChangeListener create(Context context) {
63         return new ProxyChangeListener(context);
64     }
65
66     @CalledByNative
67     public static String getProperty(String property) {
68         return System.getProperty(property);
69     }
70
71     @CalledByNative
72     public void start(long nativePtr) {
73         assert mNativePtr == 0;
74         mNativePtr = nativePtr;
75         registerReceiver();
76     }
77
78     @CalledByNative
79     public void stop() {
80         mNativePtr = 0;
81         unregisterReceiver();
82     }
83
84     private class ProxyReceiver extends BroadcastReceiver {
85         @Override
86         public void onReceive(Context context, Intent intent) {
87             if (intent.getAction().equals(Proxy.PROXY_CHANGE_ACTION)) {
88                 proxySettingsChanged(extractNewProxy(intent));
89             }
90         }
91
92         // Extract a ProxyConfig object from the supplied Intent's extra data
93         // bundle. The android.net.ProxyProperties class is not exported from
94         // tne Android SDK, so we have to use reflection to get at it and invoke
95         // methods on it. If we fail, return an empty proxy config (meaning
96         // 'direct').
97         // TODO(sgurun): once android.net.ProxyInfo is public, rewrite this.
98         private ProxyConfig extractNewProxy(Intent intent) {
99             try {
100                 final String GET_HOST_NAME = "getHost";
101                 final String GET_PORT_NAME = "getPort";
102                 Object props = intent.getExtras().get("proxy");
103                 if (props == null) {
104                     return null;
105                 }
106                 String className;
107                 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
108                     className = "android.net.ProxyProperties";
109                 } else {
110                     className = "android.net.ProxyInfo";
111                 }
112
113                 Class<?> cls = Class.forName(className);
114                 Method getHostMethod = cls.getDeclaredMethod(GET_HOST_NAME);
115                 Method getPortMethod = cls.getDeclaredMethod(GET_PORT_NAME);
116
117                 String host = (String) getHostMethod.invoke(props);
118                 int port = (Integer) getPortMethod.invoke(props);
119
120                 return new ProxyConfig(host, port);
121             } catch (ClassNotFoundException ex) {
122                 Log.e(TAG, "Using no proxy configuration due to exception:" + ex);
123                 return null;
124             } catch (NoSuchMethodException ex) {
125                 Log.e(TAG, "Using no proxy configuration due to exception:" + ex);
126                 return null;
127             } catch (IllegalAccessException ex) {
128                 Log.e(TAG, "Using no proxy configuration due to exception:" + ex);
129                 return null;
130             } catch (InvocationTargetException ex) {
131                 Log.e(TAG, "Using no proxy configuration due to exception:" + ex);
132                 return null;
133             } catch (NullPointerException ex) {
134                 Log.e(TAG, "Using no proxy configuration due to exception:" + ex);
135                 return null;
136             }
137         }
138     }
139
140     private void proxySettingsChanged(ProxyConfig cfg) {
141         if (!sEnabled) {
142             return;
143         }
144         if (mDelegate != null) {
145             mDelegate.proxySettingsChanged();
146         }
147         if (mNativePtr == 0) {
148             return;
149         }
150         // Note that this code currently runs on a MESSAGE_LOOP_UI thread, but
151         // the C++ code must run the callbacks on the network thread.
152         if (cfg != null) {
153             nativeProxySettingsChangedTo(mNativePtr, cfg.mHost, cfg.mPort);
154         } else {
155             nativeProxySettingsChanged(mNativePtr);
156         }
157     }
158
159     private void registerReceiver() {
160         if (mProxyReceiver != null) {
161             return;
162         }
163         IntentFilter filter = new IntentFilter();
164         filter.addAction(Proxy.PROXY_CHANGE_ACTION);
165         mProxyReceiver = new ProxyReceiver();
166         mContext.getApplicationContext().registerReceiver(mProxyReceiver, filter);
167     }
168
169     private void unregisterReceiver() {
170         if (mProxyReceiver == null) {
171             return;
172         }
173         mContext.unregisterReceiver(mProxyReceiver);
174         mProxyReceiver = null;
175     }
176
177     /**
178      * See net/proxy/proxy_config_service_android.cc
179      */
180     @NativeClassQualifiedName("ProxyConfigServiceAndroid::JNIDelegate")
181     private native void nativeProxySettingsChangedTo(long nativePtr,
182                                                      String host,
183                                                      int port);
184     @NativeClassQualifiedName("ProxyConfigServiceAndroid::JNIDelegate")
185     private native void nativeProxySettingsChanged(long nativePtr);
186 }