CaptivePortalLoginActivity.java revision e836b6847af968460f36a4e6649b8cb6f6da18db
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2014 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.captiveportallogin; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.Activity; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.LoadedApk; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Bitmap; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.ConnectivityManager; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.ConnectivityManager.NetworkCallback; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Network; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.NetworkCapabilities; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.NetworkRequest; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Proxy; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.http.SslError; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.ArrayMap; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.TypedValue; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Menu; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MenuItem; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.webkit.SslErrorHandler; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.webkit.WebChromeClient; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.webkit.WebSettings; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.webkit.WebView; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.webkit.WebViewClient; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.ProgressBar; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.net.HttpURLConnection; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.net.MalformedURLException; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.net.URL; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.InterruptedException; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Field; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Method; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Random; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class CaptivePortalLoginActivity extends Activity { 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "CaptivePortalLogin"; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String DEFAULT_SERVER = "connectivitycheck.android.com"; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int SOCKET_TIMEOUT_MS = 10000; 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS }; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private URL mURL; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Network mNetwork; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mResponseToken; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private NetworkCallback mNetworkCallback; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ConnectivityManager mCm; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mLaunchBrowser = false; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MyWebViewClient mWebViewClient; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onCreate(Bundle savedInstanceState) { 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onCreate(savedInstanceState); 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String server = Settings.Global.getString(getContentResolver(), "captive_portal_server"); 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (server == null) server = DEFAULT_SERVER; 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCm = ConnectivityManager.from(this); 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mURL = new URL("http", server, "/generate_204"); 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (MalformedURLException e) { 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // System misconfigured, bail out in a way that at least provides network access. 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Invalid captive portal URL, server=" + server); 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project done(Result.WANTED_AS_IS); 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mResponseToken = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_TOKEN); 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Also initializes proxy system properties. 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCm.bindProcessToNetwork(mNetwork); 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Proxy system properties must be initialized before setContentView is called because 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // setContentView initializes the WebView logic which in turn reads the system properties. 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setContentView(R.layout.activity_captive_portal_login); 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getActionBar().setDisplayShowHomeEnabled(false); 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Exit app if Network disappears. 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork); 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (networkCapabilities == null) { 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project finish(); 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNetworkCallback = new NetworkCallback() { 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onLost(Network lostNetwork) { 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED); 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 108a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru }; 109a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru final NetworkRequest.Builder builder = new NetworkRequest.Builder(); 110a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru for (int transportType : networkCapabilities.getTransportTypes()) { 111a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru builder.addTransportType(transportType); 112a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru } 113a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru mCm.registerNetworkCallback(builder.build(), mNetworkCallback); 114a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru 115a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru final WebView myWebView = (WebView) findViewById(R.id.webview); 116a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru myWebView.clearCache(true); 117a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru WebSettings webSettings = myWebView.getSettings(); 118a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru webSettings.setJavaScriptEnabled(true); 119a8675f67e33bc7337d148358783b0fd138b501ffJean-Baptiste Queru mWebViewClient = new MyWebViewClient(); 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project myWebView.setWebViewClient(mWebViewClient); 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project myWebView.setWebChromeClient(new MyWebChromeClient()); 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Start initial page load so WebView finishes loading proxy settings. 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Actual load of mUrl is initiated by MyWebViewClient. 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project myWebView.loadData("", "text/html", null); 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties. 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void setWebViewProxy() { 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LoadedApk loadedApk = getApplication().mLoadedApk; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Field receiversField = LoadedApk.class.getDeclaredField("mReceivers"); 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project receiversField.setAccessible(true); 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk); 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Object receiverMap : receivers.values()) { 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Object rec : ((ArrayMap) receiverMap).keySet()) { 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Class clazz = rec.getClass(); 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (clazz.getName().contains("ProxyChangeListener")) { 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent.class); 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onReceiveMethod.invoke(rec, getApplicationContext(), intent); 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "Prompting WebView proxy reload."); 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (Exception e) { 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Exception while setting WebView proxy: " + e); 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void done(Result result) { 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mNetworkCallback != null) { 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCm.unregisterNetworkCallback(mNetworkCallback); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNetworkCallback = null; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (result) { 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case DISMISSED: 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCm.reportCaptivePortalDismissed(mNetwork, mResponseToken); 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case UNWANTED: 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCm.ignoreNetworkWithCaptivePortal(mNetwork, mResponseToken); 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case WANTED_AS_IS: 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCm.useNetworkWithCaptivePortal(mNetwork, mResponseToken); 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project finish(); 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onCreateOptionsMenu(Menu menu) { 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getMenuInflater().inflate(R.menu.captive_portal_login, menu); 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onBackPressed() { 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project WebView myWebView = (WebView) findViewById(R.id.webview); 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (myWebView.canGoBack() && mWebViewClient.allowBack()) { 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project myWebView.goBack(); 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onBackPressed(); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onOptionsItemSelected(MenuItem item) { 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int id = item.getItemId(); 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (id == R.id.action_use_network) { 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project done(Result.WANTED_AS_IS); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (id == R.id.action_do_not_use_network) { 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project done(Result.UNWANTED); 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.onOptionsItemSelected(item); 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onDestroy() { 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onDestroy(); 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mNetworkCallback != null) { 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCm.unregisterNetworkCallback(mNetworkCallback); 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNetworkCallback = null; 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLaunchBrowser) { 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Give time for this network to become default. After 500ms just proceed. 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 5; i++) { 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: This misses when mNetwork underlies a VPN. 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mNetwork.equals(mCm.getActiveNetwork())) break; 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Thread.sleep(100); 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException e) { 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(mURL.toString()))); 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void testForCaptivePortal() { 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new Thread(new Runnable() { 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Give time for captive portal to open. 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Thread.sleep(1000); 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException e) { 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpURLConnection urlConnection = null; 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int httpResponseCode = 500; 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection = (HttpURLConnection) mURL.openConnection(); 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection.setInstanceFollowRedirects(false); 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection.setUseCaches(false); 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection.getInputStream(); 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project httpResponseCode = urlConnection.getResponseCode(); 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (urlConnection != null) urlConnection.disconnect(); 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (httpResponseCode == 204) { 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project done(Result.DISMISSED); 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }).start(); 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class MyWebViewClient extends WebViewClient { 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String INTERNAL_ASSETS = "file:///android_asset/"; 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final String mBrowserBailOutToken = Long.toString(new Random().nextLong()); 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // How many Android device-independent-pixels per scaled-pixel 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // dp/sp = (px/sp) / (px/dp) = (1/sp) / (1/dp) 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final float mDpPerSp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1, 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getResources().getDisplayMetrics()) / 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getResources().getDisplayMetrics()); 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPagesLoaded; 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If we haven't finished cleaning up the history, don't allow going back. 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean allowBack() { 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPagesLoaded > 1; 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onPageStarted(WebView view, String url, Bitmap favicon) { 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (url.contains(mBrowserBailOutToken)) { 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLaunchBrowser = true; 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project done(Result.WANTED_AS_IS); 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The first page load is used only to cause the WebView to 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // fetch the proxy settings. Don't update the URL bar, and 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // don't check if the captive portal is still there. 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPagesLoaded == 0) return; 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // For internally generated pages, leave URL bar listing prior URL as this is the URL 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the page refers to. 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!url.startsWith(INTERNAL_ASSETS)) { 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final TextView myUrlBar = (TextView) findViewById(R.id.url_bar); 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project myUrlBar.setText(url); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project testForCaptivePortal(); 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onPageFinished(WebView view, String url) { 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPagesLoaded++; 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPagesLoaded == 1) { 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Now that WebView has loaded at least one page we know it has read in the proxy 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // settings. Now prompt the WebView read the Network-specific proxy settings. 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setWebViewProxy(); 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Load the real page. 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.loadUrl(mURL.toString()); 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mPagesLoaded == 2) { 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Prevent going back to empty first page. 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.clearHistory(); 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project testForCaptivePortal(); 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Convert Android device-independent-pixels (dp) to HTML size. 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String dp(int dp) { 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // HTML px's are scaled just like dp's, so just add "px" suffix. 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Integer.toString(dp) + "px"; 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Convert Android scaled-pixels (sp) to HTML size. 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String sp(int sp) { 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Convert sp to dp's. 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float dp = sp * mDpPerSp; 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Apply a scale factor to make things look right. 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dp *= 1.3; 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Convert dp's to HTML size. 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return dp((int)dp); 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // A web page consisting of a large broken lock icon to indicate SSL failure. 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final String SSL_ERROR_HTML = "<html><head><style>" + 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "body { margin-left:" + dp(48) + "; margin-right:" + dp(48) + "; " + 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "margin-top:" + dp(96) + "; background-color:#fafafa; }" + 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "img { width:" + dp(48) + "; height:" + dp(48) + "; }" + 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "div.warn { font-size:" + sp(16) + "; margin-top:" + dp(16) + "; " + 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " opacity:0.87; line-height:1.28; }" + 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "div.example { font-size:" + sp(14) + "; margin-top:" + dp(16) + "; " + 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " opacity:0.54; line-height:1.21905; }" + 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "a { font-size:" + sp(14) + "; text-decoration:none; text-transform:uppercase; " + 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " margin-top:" + dp(24) + "; display:inline-block; color:#4285F4; " + 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " height:" + dp(48) + "; font-weight:bold; }" + 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "</style></head><body><p><img src=quantum_ic_warning_amber_96.png><br>" + 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "<div class=warn>%s</div>" + 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "<div class=example>%s</div>" + 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "<a href=%s>%s</a></body></html>"; 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "SSL error; displaying SSL warning."); 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String html = String.format(SSL_ERROR_HTML, getString(R.string.ssl_error_warning), 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getString(R.string.ssl_error_example), mBrowserBailOutToken, 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getString(R.string.ssl_error_continue)); 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view.loadDataWithBaseURL(INTERNAL_ASSETS, html, "text/HTML", "UTF-8", null); 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class MyWebChromeClient extends WebChromeClient { 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onProgressChanged(WebView view, int newProgress) { 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ProgressBar myProgressBar = (ProgressBar) findViewById(R.id.progress_bar); 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project myProgressBar.setProgress(newProgress); 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project