CaptivePortalLoginActivity.java revision 9e8ab43ab22555acff9fefca2ed433425c92fb87
1869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen/* 2869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Copyright (C) 2014 The Android Open Source Project 3869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * 4869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Licensed under the Apache License, Version 2.0 (the "License"); 5869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * you may not use this file except in compliance with the License. 6869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * You may obtain a copy of the License at 7869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * 8869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * http://www.apache.org/licenses/LICENSE-2.0 9869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * 10869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Unless required by applicable law or agreed to in writing, software 11869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * distributed under the License is distributed on an "AS IS" BASIS, 12869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * See the License for the specific language governing permissions and 14869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * limitations under the License. 15869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen */ 16869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 17869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenpackage com.android.captiveportallogin; 18869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 19869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.app.Activity; 2088eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensenimport android.app.LoadedApk; 2188eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensenimport android.content.Context; 22869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.content.Intent; 23869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.graphics.Bitmap; 2449e3edff5156f471819e4ea2a88994bca70bd870Paul Jensenimport android.net.CaptivePortal; 25869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.net.ConnectivityManager; 268df099df1516d23c113be3121635dcd34984a4a0Paul Jensenimport android.net.ConnectivityManager.NetworkCallback; 27869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.net.Network; 288df099df1516d23c113be3121635dcd34984a4a0Paul Jensenimport android.net.NetworkCapabilities; 298df099df1516d23c113be3121635dcd34984a4a0Paul Jensenimport android.net.NetworkRequest; 3088eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensenimport android.net.Proxy; 3188eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensenimport android.net.Uri; 32fc8022f8cfffded3d94baef3ba5e5ce936799b06Paul Jensenimport android.net.http.SslError; 33869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.os.Bundle; 34869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.provider.Settings; 3588eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensenimport android.util.ArrayMap; 3688eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensenimport android.util.Log; 3765636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensenimport android.util.TypedValue; 38869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.view.Menu; 39869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.view.MenuItem; 40a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichiimport android.view.View; 41fc8022f8cfffded3d94baef3ba5e5ce936799b06Paul Jensenimport android.webkit.SslErrorHandler; 42869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.webkit.WebChromeClient; 43869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.webkit.WebSettings; 44869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.webkit.WebView; 45869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.webkit.WebViewClient; 468f333f19222ac9415152e31f10e0df2b571b0b77Paul Jensenimport android.widget.ProgressBar; 475344a4abdf239a19485a9c858b6cc3be96002eacPaul Jensenimport android.widget.TextView; 48869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 499e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichiimport com.android.internal.logging.MetricsLogger; 509e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichiimport com.android.internal.logging.nano.MetricsProto.MetricsEvent; 519e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi 52869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport java.io.IOException; 53869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport java.net.HttpURLConnection; 54869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport java.net.MalformedURLException; 55869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport java.net.URL; 56869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport java.lang.InterruptedException; 5788eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensenimport java.lang.reflect.Field; 5888eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensenimport java.lang.reflect.Method; 5965636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensenimport java.util.Random; 60869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 61869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenpublic class CaptivePortalLoginActivity extends Activity { 627f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi private static final String TAG = CaptivePortalLoginActivity.class.getSimpleName(); 637f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi private static final boolean DBG = true; 6460d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi private static final boolean VDBG = false; 657f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi 66869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private static final int SOCKET_TIMEOUT_MS = 10000; 67869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 689e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi private enum Result { 699e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi DISMISSED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED), 709e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi UNWANTED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_UNWANTED), 719e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi WANTED_AS_IS(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_WANTED_AS_IS); 729e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi 739e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi final int metricsEvent; 749e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi Result(int metricsEvent) { this.metricsEvent = metricsEvent; } 759e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi }; 76869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 777f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi private URL mUrl; 782c02197bdd12378c7b2f8ee4bcaa625b2c564edeHugo Benichi private String mUserAgent; 7925a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen private Network mNetwork; 8049e3edff5156f471819e4ea2a88994bca70bd870Paul Jensen private CaptivePortal mCaptivePortal; 818df099df1516d23c113be3121635dcd34984a4a0Paul Jensen private NetworkCallback mNetworkCallback; 8225a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen private ConnectivityManager mCm; 8365636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen private boolean mLaunchBrowser = false; 84e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen private MyWebViewClient mWebViewClient; 85869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 86869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 87869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen protected void onCreate(Bundle savedInstanceState) { 88869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen super.onCreate(savedInstanceState); 899e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi 909e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi logMetricsEvent(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY); 919e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi 9225a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen mCm = ConnectivityManager.from(this); 9325a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK); 9449e3edff5156f471819e4ea2a88994bca70bd870Paul Jensen mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL); 95ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi mUserAgent = 96ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT); 977f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi mUrl = getUrl(); 987f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi if (mUrl == null) { 997f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi // getUrl() failed to parse the url provided in the intent: bail out in a way that 1007f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi // at least provides network access. 1017f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi done(Result.WANTED_AS_IS); 1027f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi return; 1037f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi } 1047f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi if (DBG) { 1057f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi Log.d(TAG, String.format("onCreate for %s", mUrl.toString())); 1067f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi } 107869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 108e0bef71662d81caaaa0d7214fb0bef5d39996a69Paul Jensen // Also initializes proxy system properties. 10925a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen mCm.bindProcessToNetwork(mNetwork); 11088eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen 11188eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen // Proxy system properties must be initialized before setContentView is called because 11288eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen // setContentView initializes the WebView logic which in turn reads the system properties. 11388eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen setContentView(R.layout.activity_captive_portal_login); 11488eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen 1158df099df1516d23c113be3121635dcd34984a4a0Paul Jensen // Exit app if Network disappears. 11625a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork); 1178df099df1516d23c113be3121635dcd34984a4a0Paul Jensen if (networkCapabilities == null) { 1186a776c8317138cf4a3013addc1bd1a462f6dc1ebPaul Jensen finishAndRemoveTask(); 1198df099df1516d23c113be3121635dcd34984a4a0Paul Jensen return; 1208df099df1516d23c113be3121635dcd34984a4a0Paul Jensen } 1218df099df1516d23c113be3121635dcd34984a4a0Paul Jensen mNetworkCallback = new NetworkCallback() { 1228df099df1516d23c113be3121635dcd34984a4a0Paul Jensen @Override 1238df099df1516d23c113be3121635dcd34984a4a0Paul Jensen public void onLost(Network lostNetwork) { 12425a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED); 1258df099df1516d23c113be3121635dcd34984a4a0Paul Jensen } 1268df099df1516d23c113be3121635dcd34984a4a0Paul Jensen }; 1278df099df1516d23c113be3121635dcd34984a4a0Paul Jensen final NetworkRequest.Builder builder = new NetworkRequest.Builder(); 1288df099df1516d23c113be3121635dcd34984a4a0Paul Jensen for (int transportType : networkCapabilities.getTransportTypes()) { 1298df099df1516d23c113be3121635dcd34984a4a0Paul Jensen builder.addTransportType(transportType); 1308df099df1516d23c113be3121635dcd34984a4a0Paul Jensen } 13125a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen mCm.registerNetworkCallback(builder.build(), mNetworkCallback); 132869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 133a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi getActionBar().setDisplayShowHomeEnabled(false); 134a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi getActionBar().setElevation(0); // remove shadow 135a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi getActionBar().setTitle(getHeaderTitle()); 136a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi getActionBar().setSubtitle(""); 137a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi 138a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi final WebView webview = getWebview(); 139a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi webview.clearCache(true); 140a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi WebSettings webSettings = webview.getSettings(); 141869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen webSettings.setJavaScriptEnabled(true); 142b55bf38351fc06d267735e8e377d4049c2a7b5d3Lorenzo Colitti webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); 14394c5fb342bbb04bcf099807752243c84b26b9a9bHugo Benichi webSettings.setUseWideViewPort(true); 14494c5fb342bbb04bcf099807752243c84b26b9a9bHugo Benichi webSettings.setLoadWithOverviewMode(true); 14594c5fb342bbb04bcf099807752243c84b26b9a9bHugo Benichi webSettings.setSupportZoom(true); 14694c5fb342bbb04bcf099807752243c84b26b9a9bHugo Benichi webSettings.setBuiltInZoomControls(true); 14794c5fb342bbb04bcf099807752243c84b26b9a9bHugo Benichi webSettings.setDisplayZoomControls(false); 148e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen mWebViewClient = new MyWebViewClient(); 149a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi webview.setWebViewClient(mWebViewClient); 150a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi webview.setWebChromeClient(new MyWebChromeClient()); 15188eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen // Start initial page load so WebView finishes loading proxy settings. 15288eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen // Actual load of mUrl is initiated by MyWebViewClient. 153a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi webview.loadData("", "text/html", null); 15488eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen } 15588eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen 15688eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen // Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties. 15788eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen private void setWebViewProxy() { 15888eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen LoadedApk loadedApk = getApplication().mLoadedApk; 15988eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen try { 16088eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen Field receiversField = LoadedApk.class.getDeclaredField("mReceivers"); 16188eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen receiversField.setAccessible(true); 16288eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk); 16388eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen for (Object receiverMap : receivers.values()) { 16488eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen for (Object rec : ((ArrayMap) receiverMap).keySet()) { 16588eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen Class clazz = rec.getClass(); 16688eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen if (clazz.getName().contains("ProxyChangeListener")) { 16788eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, 16888eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen Intent.class); 16988eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); 17088eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen onReceiveMethod.invoke(rec, getApplicationContext(), intent); 17188eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen Log.v(TAG, "Prompting WebView proxy reload."); 17288eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen } 17388eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen } 17488eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen } 17588eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen } catch (Exception e) { 17688eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen Log.e(TAG, "Exception while setting WebView proxy: " + e); 17788eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen } 178869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 179869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 18025a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen private void done(Result result) { 1817f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi if (DBG) { 1827f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi Log.d(TAG, String.format("Result %s for %s", result.name(), mUrl.toString())); 1837f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi } 18471b645fe9cb8106dfcbf025a3fd7f58698c051bbPaul Jensen if (mNetworkCallback != null) { 18525a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen mCm.unregisterNetworkCallback(mNetworkCallback); 186868f6243bc6021465938a7b764bef8fd001cb39cPaul Jensen mNetworkCallback = null; 18725a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen } 1889e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi logMetricsEvent(result.metricsEvent); 18925a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen switch (result) { 19025a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen case DISMISSED: 19149e3edff5156f471819e4ea2a88994bca70bd870Paul Jensen mCaptivePortal.reportCaptivePortalDismissed(); 19225a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen break; 19325a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen case UNWANTED: 19449e3edff5156f471819e4ea2a88994bca70bd870Paul Jensen mCaptivePortal.ignoreNetwork(); 19525a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen break; 19625a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen case WANTED_AS_IS: 19749e3edff5156f471819e4ea2a88994bca70bd870Paul Jensen mCaptivePortal.useNetwork(); 19825a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen break; 19971b645fe9cb8106dfcbf025a3fd7f58698c051bbPaul Jensen } 2006a776c8317138cf4a3013addc1bd1a462f6dc1ebPaul Jensen finishAndRemoveTask(); 201869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 202869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 203869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 204869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public boolean onCreateOptionsMenu(Menu menu) { 205869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen getMenuInflater().inflate(R.menu.captive_portal_login, menu); 206869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen return true; 207869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 208869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 209869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 210b6ea9ee6fe6fc205f4f8be593ca993d594e8d504Paul Jensen public void onBackPressed() { 21151efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette WebView myWebView = findViewById(R.id.webview); 212e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen if (myWebView.canGoBack() && mWebViewClient.allowBack()) { 213b6ea9ee6fe6fc205f4f8be593ca993d594e8d504Paul Jensen myWebView.goBack(); 214b6ea9ee6fe6fc205f4f8be593ca993d594e8d504Paul Jensen } else { 215b6ea9ee6fe6fc205f4f8be593ca993d594e8d504Paul Jensen super.onBackPressed(); 216b6ea9ee6fe6fc205f4f8be593ca993d594e8d504Paul Jensen } 217b6ea9ee6fe6fc205f4f8be593ca993d594e8d504Paul Jensen } 218b6ea9ee6fe6fc205f4f8be593ca993d594e8d504Paul Jensen 219b6ea9ee6fe6fc205f4f8be593ca993d594e8d504Paul Jensen @Override 220869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public boolean onOptionsItemSelected(MenuItem item) { 2217f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi final Result result; 2227f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi final String action; 2237f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi final int id = item.getItemId(); 2247f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi switch (id) { 2257f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi case R.id.action_use_network: 2267f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi result = Result.WANTED_AS_IS; 2277f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi action = "USE_NETWORK"; 2287f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi break; 2297f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi case R.id.action_do_not_use_network: 2307f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi result = Result.UNWANTED; 2317f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi action = "DO_NOT_USE_NETWORK"; 2327f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi break; 2337f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi default: 2347f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi return super.onOptionsItemSelected(item); 235869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 2367f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi if (DBG) { 2377f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi Log.d(TAG, String.format("onOptionsItemSelect %s for %s", action, mUrl.toString())); 238869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 2397f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi done(result); 2407f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi return true; 241869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 242869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 243868f6243bc6021465938a7b764bef8fd001cb39cPaul Jensen @Override 244868f6243bc6021465938a7b764bef8fd001cb39cPaul Jensen public void onDestroy() { 245868f6243bc6021465938a7b764bef8fd001cb39cPaul Jensen super.onDestroy(); 246868f6243bc6021465938a7b764bef8fd001cb39cPaul Jensen if (mNetworkCallback != null) { 247868f6243bc6021465938a7b764bef8fd001cb39cPaul Jensen mCm.unregisterNetworkCallback(mNetworkCallback); 248868f6243bc6021465938a7b764bef8fd001cb39cPaul Jensen mNetworkCallback = null; 249868f6243bc6021465938a7b764bef8fd001cb39cPaul Jensen } 25065636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen if (mLaunchBrowser) { 25165636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen // Give time for this network to become default. After 500ms just proceed. 25265636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen for (int i = 0; i < 5; i++) { 25365636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen // TODO: This misses when mNetwork underlies a VPN. 25465636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen if (mNetwork.equals(mCm.getActiveNetwork())) break; 25565636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen try { 25665636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen Thread.sleep(100); 25765636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen } catch (InterruptedException e) { 25865636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen } 25965636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen } 2607f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi final String url = mUrl.toString(); 2617f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi if (DBG) { 2627f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi Log.d(TAG, "starting activity with intent ACTION_VIEW for " + url); 2637f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi } 2647f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); 2657f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi } 2667f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi } 2677f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi 2687f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi private URL getUrl() { 2697f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL); 2707f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi if (url == null) { 2717f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi url = mCm.getCaptivePortalServerUrl(); 2727f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi } 273a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi return makeURL(url); 274a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi } 275a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi 276a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi private static URL makeURL(String url) { 2777f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi try { 2787f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi return new URL(url); 2797f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi } catch (MalformedURLException e) { 280a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi Log.e(TAG, "Invalid URL " + url); 28165636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen } 2827f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi return null; 283868f6243bc6021465938a7b764bef8fd001cb39cPaul Jensen } 284868f6243bc6021465938a7b764bef8fd001cb39cPaul Jensen 285869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private void testForCaptivePortal() { 2862c02197bdd12378c7b2f8ee4bcaa625b2c564edeHugo Benichi // TODO: reuse NetworkMonitor facilities for consistent captive portal detection. 287869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen new Thread(new Runnable() { 288869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public void run() { 289869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen // Give time for captive portal to open. 290869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen try { 291869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen Thread.sleep(1000); 292869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } catch (InterruptedException e) { 293869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 294869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen HttpURLConnection urlConnection = null; 295869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen int httpResponseCode = 500; 296869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen try { 2972c02197bdd12378c7b2f8ee4bcaa625b2c564edeHugo Benichi urlConnection = (HttpURLConnection) mNetwork.openConnection(mUrl); 298869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen urlConnection.setInstanceFollowRedirects(false); 299869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); 300869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); 301869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen urlConnection.setUseCaches(false); 3022c02197bdd12378c7b2f8ee4bcaa625b2c564edeHugo Benichi if (mUserAgent != null) { 3032c02197bdd12378c7b2f8ee4bcaa625b2c564edeHugo Benichi urlConnection.setRequestProperty("User-Agent", mUserAgent); 3042c02197bdd12378c7b2f8ee4bcaa625b2c564edeHugo Benichi } 305ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi // cannot read request header after connection 306ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi String requestHeader = urlConnection.getRequestProperties().toString(); 307ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi 308869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen urlConnection.getInputStream(); 309869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen httpResponseCode = urlConnection.getResponseCode(); 310ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi if (DBG) { 311ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi Log.d(TAG, "probe at " + mUrl + 312ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi " ret=" + httpResponseCode + 313ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi " request=" + requestHeader + 314ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi " headers=" + urlConnection.getHeaderFields()); 315ec88fd6708c14515f75d0f9de24e505e62fc3550Hugo Benichi } 316869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } catch (IOException e) { 317869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } finally { 318869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen if (urlConnection != null) urlConnection.disconnect(); 319869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 320869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen if (httpResponseCode == 204) { 32125a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen done(Result.DISMISSED); 322869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 323869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 324869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen }).start(); 325869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 326869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 327869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private class MyWebViewClient extends WebViewClient { 3285344a4abdf239a19485a9c858b6cc3be96002eacPaul Jensen private static final String INTERNAL_ASSETS = "file:///android_asset/"; 32960d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi 33065636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen private final String mBrowserBailOutToken = Long.toString(new Random().nextLong()); 33165636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen // How many Android device-independent-pixels per scaled-pixel 33265636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen // dp/sp = (px/sp) / (px/dp) = (1/sp) / (1/dp) 33365636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen private final float mDpPerSp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1, 33465636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen getResources().getDisplayMetrics()) / 33565636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, 33665636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen getResources().getDisplayMetrics()); 337e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen private int mPagesLoaded; 338e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen 339e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen // If we haven't finished cleaning up the history, don't allow going back. 340e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen public boolean allowBack() { 341e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen return mPagesLoaded > 1; 342e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen } 34388eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen 344869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 345869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public void onPageStarted(WebView view, String url, Bitmap favicon) { 34665636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen if (url.contains(mBrowserBailOutToken)) { 34765636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen mLaunchBrowser = true; 34865636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen done(Result.WANTED_AS_IS); 34965636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen return; 35065636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen } 351e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen // The first page load is used only to cause the WebView to 352e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen // fetch the proxy settings. Don't update the URL bar, and 353e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen // don't check if the captive portal is still there. 354e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen if (mPagesLoaded == 0) return; 355e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen // For internally generated pages, leave URL bar listing prior URL as this is the URL 356e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen // the page refers to. 357e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen if (!url.startsWith(INTERNAL_ASSETS)) { 358a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi getActionBar().setSubtitle(getHeaderSubtitle(url)); 359e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen } 360a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi getProgressBar().setVisibility(View.VISIBLE); 361869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen testForCaptivePortal(); 362869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 363869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 364869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 365869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public void onPageFinished(WebView view, String url) { 366e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen mPagesLoaded++; 367a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi getProgressBar().setVisibility(View.INVISIBLE); 368e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen if (mPagesLoaded == 1) { 36988eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen // Now that WebView has loaded at least one page we know it has read in the proxy 37088eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen // settings. Now prompt the WebView read the Network-specific proxy settings. 37188eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen setWebViewProxy(); 37288eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen // Load the real page. 3737f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi view.loadUrl(mUrl.toString()); 37488eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen return; 375e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen } else if (mPagesLoaded == 2) { 376e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen // Prevent going back to empty first page. 377e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen view.clearHistory(); 3785344a4abdf239a19485a9c858b6cc3be96002eacPaul Jensen } 379869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen testForCaptivePortal(); 380869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 381fc8022f8cfffded3d94baef3ba5e5ce936799b06Paul Jensen 38265636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen // Convert Android scaled-pixels (sp) to HTML size. 38365636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen private String sp(int sp) { 38465636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen // Convert sp to dp's. 38565636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen float dp = sp * mDpPerSp; 38665636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen // Apply a scale factor to make things look right. 38765636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen dp *= 1.3; 38865636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen // Convert dp's to HTML size. 38960d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi // HTML px's are scaled just like dp's, so just add "px" suffix. 39060d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi return Integer.toString((int)dp) + "px"; 39165636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen } 39265636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen 393fc8022f8cfffded3d94baef3ba5e5ce936799b06Paul Jensen // A web page consisting of a large broken lock icon to indicate SSL failure. 394fc8022f8cfffded3d94baef3ba5e5ce936799b06Paul Jensen 395fc8022f8cfffded3d94baef3ba5e5ce936799b06Paul Jensen @Override 396fc8022f8cfffded3d94baef3ba5e5ce936799b06Paul Jensen public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { 3979e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi logMetricsEvent(MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR); 39841ff524a6325feb8dc9d3d64545c5f2aeb964f34Paul Jensen Log.w(TAG, "SSL error (error: " + error.getPrimaryError() + " host: " + 39941ff524a6325feb8dc9d3d64545c5f2aeb964f34Paul Jensen // Only show host to avoid leaking private info. 40041ff524a6325feb8dc9d3d64545c5f2aeb964f34Paul Jensen Uri.parse(error.getUrl()).getHost() + " certificate: " + 40141ff524a6325feb8dc9d3d64545c5f2aeb964f34Paul Jensen error.getCertificate() + "); displaying SSL warning."); 40260d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi final String sslErrorPage = makeSslErrorPage(); 40360d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi if (VDBG) { 40460d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi Log.d(TAG, sslErrorPage); 40560d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi } 40660d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi view.loadDataWithBaseURL(INTERNAL_ASSETS, sslErrorPage, "text/HTML", "UTF-8", null); 40760d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi } 40860d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi 40960d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi private String makeSslErrorPage() { 41060d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi final String warningMsg = getString(R.string.ssl_error_warning); 41160d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi final String exampleMsg = getString(R.string.ssl_error_example); 41260d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi final String continueMsg = getString(R.string.ssl_error_continue); 41360d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi return String.join("\n", 41460d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi "<html>", 41560d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi "<head>", 41660d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">", 41760d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " <style>", 41860d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " body {", 41960d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " background-color:#fafafa;", 42060d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " margin:auto;", 42160d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " width:80%;", 42260d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " margin-top: 96px", 42360d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " }", 42460d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " img {", 42560d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " height:48px;", 42660d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " width:48px;", 42760d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " }", 42860d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " div.warn {", 42960d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " font-size:" + sp(16) + ";", 43060d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " line-height:1.28;", 43160d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " margin-top:16px;", 43260d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " opacity:0.87;", 43360d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " }", 43460d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " div.example {", 43560d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " font-size:" + sp(14) + ";", 43660d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " line-height:1.21905;", 43760d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " margin-top:16px;", 43860d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " opacity:0.54;", 43960d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " }", 44060d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " a {", 44160d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " color:#4285F4;", 44260d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " display:inline-block;", 44360d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " font-size:" + sp(14) + ";", 44460d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " font-weight:bold;", 44560d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " height:48px;", 44660d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " margin-top:24px;", 44760d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " text-decoration:none;", 44860d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " text-transform:uppercase;", 44960d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " }", 45060d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " </style>", 45160d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi "</head>", 45260d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi "<body>", 45360d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " <p><img src=quantum_ic_warning_amber_96.png><br>", 45460d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " <div class=warn>" + warningMsg + "</div>", 45560d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " <div class=example>" + exampleMsg + "</div>", 45660d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi " <a href=" + mBrowserBailOutToken + ">" + continueMsg + "</a>", 45760d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi "</body>", 45860d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi "</html>"); 459fc8022f8cfffded3d94baef3ba5e5ce936799b06Paul Jensen } 460fd54da9b7ccf8218bb99cbbe540fd71ea411508bPaul Jensen 461fd54da9b7ccf8218bb99cbbe540fd71ea411508bPaul Jensen @Override 462fd54da9b7ccf8218bb99cbbe540fd71ea411508bPaul Jensen public boolean shouldOverrideUrlLoading (WebView view, String url) { 463fd54da9b7ccf8218bb99cbbe540fd71ea411508bPaul Jensen if (url.startsWith("tel:")) { 464fd54da9b7ccf8218bb99cbbe540fd71ea411508bPaul Jensen startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url))); 465fd54da9b7ccf8218bb99cbbe540fd71ea411508bPaul Jensen return true; 466fd54da9b7ccf8218bb99cbbe540fd71ea411508bPaul Jensen } 467fd54da9b7ccf8218bb99cbbe540fd71ea411508bPaul Jensen return false; 468fd54da9b7ccf8218bb99cbbe540fd71ea411508bPaul Jensen } 469869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 470869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen 471869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen private class MyWebChromeClient extends WebChromeClient { 472869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen @Override 473869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen public void onProgressChanged(WebView view, int newProgress) { 474a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi getProgressBar().setProgress(newProgress); 475a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi } 476a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi } 477a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi 478a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi private ProgressBar getProgressBar() { 479a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi return findViewById(R.id.progress_bar); 480a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi } 481a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi 482a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi private WebView getWebview() { 483a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi return findViewById(R.id.webview); 484a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi } 485a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi 486a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi private String getHeaderTitle() { 487ef0884f2e528aff83c3beddd759246bf635763d1Hugo Benichi return getString(R.string.action_bar_label); 488a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi } 489a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi 490a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi private String getHeaderSubtitle(String urlString) { 491a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi URL url = makeURL(urlString); 492a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi if (url == null) { 493a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi return urlString; 494a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi } 495a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi final String https = "https"; 496a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi if (https.equals(url.getProtocol())) { 497a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi return https + "://" + url.getHost(); 498869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 499a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi return url.getHost(); 500869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen } 5019e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi 5029e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi private void logMetricsEvent(int event) { 5039e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi MetricsLogger.action(this, event, getPackageName()); 5049e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi } 505869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen} 506