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