CaptivePortalLoginActivity.java revision c820cb83bb031ad1d438fe7c92f19c69ebe87097
1da578042ae2560d2753bda5869adde7597a7ddf0fionaxu/* 2da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * Copyright (C) 2017 The Android Open Source Project 3da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * 4da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * Licensed under the Apache License, Version 2.0 (the "License"); 5da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * you may not use this file except in compliance with the License. 6da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * You may obtain a copy of the License at 7da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * 8da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * http://www.apache.org/licenses/LICENSE-2.0 9da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * 10da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * Unless required by applicable law or agreed to in writing, software 11da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * distributed under the License is distributed on an "AS IS" BASIS, 12da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * See the License for the specific language governing permissions and 14da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * limitations under the License. 15da578042ae2560d2753bda5869adde7597a7ddf0fionaxu */ 16da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 17da578042ae2560d2753bda5869adde7597a7ddf0fionaxupackage com.android.carrierdefaultapp; 18da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 19da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.app.Activity; 20da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.app.LoadedApk; 21da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.content.Context; 22da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.content.Intent; 23d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxuimport android.content.pm.ActivityInfo; 24d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxuimport android.content.pm.PackageInfo; 25d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxuimport android.content.pm.PackageManager; 26da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.graphics.Bitmap; 27da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.net.ConnectivityManager; 28da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.net.ConnectivityManager.NetworkCallback; 29da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.net.Network; 30da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.net.NetworkCapabilities; 31da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.net.NetworkRequest; 32da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.net.Proxy; 33da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.net.TrafficStats; 34da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.net.Uri; 35c43d2f5b1f12dadd8c87c069cd4a13cfbc481699Erik Klineimport android.net.dns.ResolvUtil; 36da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.net.http.SslError; 37da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.os.Bundle; 38da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.telephony.CarrierConfigManager; 39da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.telephony.Rlog; 40da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.telephony.SubscriptionManager; 41d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxuimport android.text.TextUtils; 42da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.util.ArrayMap; 43da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.util.Log; 44da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.util.TypedValue; 45da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.webkit.SslErrorHandler; 46da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.webkit.WebChromeClient; 47da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.webkit.WebSettings; 48da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.webkit.WebView; 49da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.webkit.WebViewClient; 50da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.widget.ProgressBar; 51da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport android.widget.TextView; 52da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 53da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport com.android.internal.telephony.PhoneConstants; 54da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport com.android.internal.telephony.TelephonyIntents; 55da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport com.android.internal.util.ArrayUtils; 56da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 57da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport java.io.IOException; 58da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport java.lang.reflect.Field; 59da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport java.lang.reflect.Method; 60da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport java.net.HttpURLConnection; 61da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport java.net.MalformedURLException; 62da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport java.net.URL; 63da578042ae2560d2753bda5869adde7597a7ddf0fionaxuimport java.util.Random; 64da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 65da578042ae2560d2753bda5869adde7597a7ddf0fionaxu/** 66da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * Activity that launches in response to the captive portal notification 67da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * @see com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION 68da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * This activity requests network connection if there is no available one before loading the real 69da578042ae2560d2753bda5869adde7597a7ddf0fionaxu * portal page and apply carrier actions on the portal activation result. 70da578042ae2560d2753bda5869adde7597a7ddf0fionaxu */ 71da578042ae2560d2753bda5869adde7597a7ddf0fionaxupublic class CaptivePortalLoginActivity extends Activity { 72da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private static final String TAG = CaptivePortalLoginActivity.class.getSimpleName(); 73da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private static final boolean DBG = true; 74da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 75da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private static final int SOCKET_TIMEOUT_MS = 10 * 1000; 76d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu private static final int NETWORK_REQUEST_TIMEOUT_MS = 5 * 1000; 77da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 78da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private URL mUrl; 79da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private Network mNetwork; 80da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private NetworkCallback mNetworkCallback; 81da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private ConnectivityManager mCm; 82da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private WebView mWebView; 83da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private MyWebViewClient mWebViewClient; 84da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private boolean mLaunchBrowser = false; 85f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu private Thread mTestingThread = null; 861c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu private boolean mReload = false; 87da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 88da578042ae2560d2753bda5869adde7597a7ddf0fionaxu @Override 89da578042ae2560d2753bda5869adde7597a7ddf0fionaxu protected void onCreate(Bundle savedInstanceState) { 90da578042ae2560d2753bda5869adde7597a7ddf0fionaxu super.onCreate(savedInstanceState); 91da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mCm = ConnectivityManager.from(this); 92da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mUrl = getUrlForCaptivePortal(); 93da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (mUrl == null) { 94da578042ae2560d2753bda5869adde7597a7ddf0fionaxu done(false); 95da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return; 96da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 97da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (DBG) logd(String.format("onCreate for %s", mUrl.toString())); 98da578042ae2560d2753bda5869adde7597a7ddf0fionaxu setContentView(R.layout.activity_captive_portal_login); 99da578042ae2560d2753bda5869adde7597a7ddf0fionaxu getActionBar().setDisplayShowHomeEnabled(false); 100da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 10151efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette mWebView = findViewById(R.id.webview); 102da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mWebView.clearCache(true); 103da578042ae2560d2753bda5869adde7597a7ddf0fionaxu WebSettings webSettings = mWebView.getSettings(); 104da578042ae2560d2753bda5869adde7597a7ddf0fionaxu webSettings.setJavaScriptEnabled(true); 105da578042ae2560d2753bda5869adde7597a7ddf0fionaxu webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); 1062e0915f14384901f25a41d698b39ef0add201550fionaxu webSettings.setUseWideViewPort(true); 1072e0915f14384901f25a41d698b39ef0add201550fionaxu webSettings.setLoadWithOverviewMode(true); 1082e0915f14384901f25a41d698b39ef0add201550fionaxu webSettings.setSupportZoom(true); 1092e0915f14384901f25a41d698b39ef0add201550fionaxu webSettings.setBuiltInZoomControls(true); 110da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mWebViewClient = new MyWebViewClient(); 111da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mWebView.setWebViewClient(mWebViewClient); 112da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mWebView.setWebChromeClient(new MyWebChromeClient()); 113da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 114c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline final Network network = getNetworkForCaptivePortal(); 115c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline if (network == null) { 116da578042ae2560d2753bda5869adde7597a7ddf0fionaxu requestNetworkForCaptivePortal(); 117da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } else { 118c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline setNetwork(network); 119da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Start initial page load so WebView finishes loading proxy settings. 120da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Actual load of mUrl is initiated by MyWebViewClient. 121da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mWebView.loadData("", "text/html", null); 122da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 123da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 124da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 125da578042ae2560d2753bda5869adde7597a7ddf0fionaxu @Override 126da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public void onBackPressed() { 12751efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette WebView myWebView = findViewById(R.id.webview); 128da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (myWebView.canGoBack() && mWebViewClient.allowBack()) { 129da578042ae2560d2753bda5869adde7597a7ddf0fionaxu myWebView.goBack(); 130da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } else { 131da578042ae2560d2753bda5869adde7597a7ddf0fionaxu super.onBackPressed(); 132da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 133da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 134da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 135da578042ae2560d2753bda5869adde7597a7ddf0fionaxu @Override 136da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public void onDestroy() { 137da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (mLaunchBrowser) { 138da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Give time for this network to become default. After 500ms just proceed. 139da578042ae2560d2753bda5869adde7597a7ddf0fionaxu for (int i = 0; i < 5; i++) { 140da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // TODO: This misses when mNetwork underlies a VPN. 141da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (mNetwork.equals(mCm.getActiveNetwork())) break; 142da578042ae2560d2753bda5869adde7597a7ddf0fionaxu try { 143da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Thread.sleep(100); 144da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } catch (InterruptedException e) { 145da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 146da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 147da578042ae2560d2753bda5869adde7597a7ddf0fionaxu final String url = mUrl.toString(); 148da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (DBG) logd("starting activity with intent ACTION_VIEW for " + url); 149da578042ae2560d2753bda5869adde7597a7ddf0fionaxu startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); 150da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 151f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu 152f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu if (mTestingThread != null) { 153f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu mTestingThread.interrupt(); 154f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu } 155f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu mWebView.destroy(); 156f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu releaseNetworkRequest(); 157f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu super.onDestroy(); 158da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 159da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 160c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline private void setNetwork(Network network) { 161c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline if (network != null) { 162c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline mCm.bindProcessToNetwork(network); 163c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline mCm.setProcessDefaultNetworkForHostResolution( 164c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline ResolvUtil.getNetworkWithUseLocalNameserversFlag(network)); 165c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline } 166c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline mNetwork = network; 167c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline } 168c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline 169da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties. 170da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private void setWebViewProxy() { 171da578042ae2560d2753bda5869adde7597a7ddf0fionaxu LoadedApk loadedApk = getApplication().mLoadedApk; 172da578042ae2560d2753bda5869adde7597a7ddf0fionaxu try { 173da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Field receiversField = LoadedApk.class.getDeclaredField("mReceivers"); 174da578042ae2560d2753bda5869adde7597a7ddf0fionaxu receiversField.setAccessible(true); 175da578042ae2560d2753bda5869adde7597a7ddf0fionaxu ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk); 176da578042ae2560d2753bda5869adde7597a7ddf0fionaxu for (Object receiverMap : receivers.values()) { 177da578042ae2560d2753bda5869adde7597a7ddf0fionaxu for (Object rec : ((ArrayMap) receiverMap).keySet()) { 178da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Class clazz = rec.getClass(); 179da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (clazz.getName().contains("ProxyChangeListener")) { 180da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, 181da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Intent.class); 182da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); 183da578042ae2560d2753bda5869adde7597a7ddf0fionaxu onReceiveMethod.invoke(rec, getApplicationContext(), intent); 184da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Log.v(TAG, "Prompting WebView proxy reload."); 185da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 186da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 187da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 188da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } catch (Exception e) { 189da578042ae2560d2753bda5869adde7597a7ddf0fionaxu loge("Exception while setting WebView proxy: " + e); 190da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 191da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 192da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 193da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private void done(boolean success) { 194fd11ce5fafeb599822f6a0b6a4071a8cf6ccc01aQiongcheng Luo if (DBG) logd(String.format("Result success %b for %s", success, 195fd11ce5fafeb599822f6a0b6a4071a8cf6ccc01aQiongcheng Luo mUrl != null ? mUrl.toString() : "null")); 196da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (success) { 197da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Trigger re-evaluation upon success http response code 198da578042ae2560d2753bda5869adde7597a7ddf0fionaxu CarrierActionUtils.applyCarrierAction( 199da578042ae2560d2753bda5869adde7597a7ddf0fionaxu CarrierActionUtils.CARRIER_ACTION_ENABLE_RADIO, getIntent(), 200da578042ae2560d2753bda5869adde7597a7ddf0fionaxu getApplicationContext()); 201da578042ae2560d2753bda5869adde7597a7ddf0fionaxu CarrierActionUtils.applyCarrierAction( 202da578042ae2560d2753bda5869adde7597a7ddf0fionaxu CarrierActionUtils.CARRIER_ACTION_ENABLE_METERED_APNS, getIntent(), 203da578042ae2560d2753bda5869adde7597a7ddf0fionaxu getApplicationContext()); 204da578042ae2560d2753bda5869adde7597a7ddf0fionaxu CarrierActionUtils.applyCarrierAction( 205da578042ae2560d2753bda5869adde7597a7ddf0fionaxu CarrierActionUtils.CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS, getIntent(), 206da578042ae2560d2753bda5869adde7597a7ddf0fionaxu getApplicationContext()); 207d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu CarrierActionUtils.applyCarrierAction( 208d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu CarrierActionUtils.CARRIER_ACTION_DISABLE_DEFAULT_URL_HANDLER, getIntent(), 209d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu getApplicationContext()); 210d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu CarrierActionUtils.applyCarrierAction( 211d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu CarrierActionUtils.CARRIER_ACTION_DEREGISTER_DEFAULT_NETWORK_AVAIL, getIntent(), 212d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu getApplicationContext()); 213da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 214da578042ae2560d2753bda5869adde7597a7ddf0fionaxu finishAndRemoveTask(); 215da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 216da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 217da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private URL getUrlForCaptivePortal() { 218da578042ae2560d2753bda5869adde7597a7ddf0fionaxu String url = getIntent().getStringExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY); 219d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu if (TextUtils.isEmpty(url)) url = mCm.getCaptivePortalServerUrl(); 220da578042ae2560d2753bda5869adde7597a7ddf0fionaxu final CarrierConfigManager configManager = getApplicationContext() 221da578042ae2560d2753bda5869adde7597a7ddf0fionaxu .getSystemService(CarrierConfigManager.class); 222da578042ae2560d2753bda5869adde7597a7ddf0fionaxu final int subId = getIntent().getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, 223da578042ae2560d2753bda5869adde7597a7ddf0fionaxu SubscriptionManager.getDefaultVoiceSubscriptionId()); 224da578042ae2560d2753bda5869adde7597a7ddf0fionaxu final String[] portalURLs = configManager.getConfigForSubId(subId).getStringArray( 225da578042ae2560d2753bda5869adde7597a7ddf0fionaxu CarrierConfigManager.KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY); 226da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (!ArrayUtils.isEmpty(portalURLs)) { 227da578042ae2560d2753bda5869adde7597a7ddf0fionaxu for (String portalUrl : portalURLs) { 228da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (url.startsWith(portalUrl)) { 229da578042ae2560d2753bda5869adde7597a7ddf0fionaxu break; 230da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 231da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 232da578042ae2560d2753bda5869adde7597a7ddf0fionaxu url = null; 233da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 234da578042ae2560d2753bda5869adde7597a7ddf0fionaxu try { 235da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return new URL(url); 236da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } catch (MalformedURLException e) { 237da578042ae2560d2753bda5869adde7597a7ddf0fionaxu loge("Invalid captive portal URL " + url); 238da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 239da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return null; 240da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 241da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 242da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private void testForCaptivePortal() { 243f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu mTestingThread = new Thread(new Runnable() { 244da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public void run() { 245c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline final Network network = ResolvUtil.makeNetworkWithPrivateDnsBypass(mNetwork); 246da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Give time for captive portal to open. 247da578042ae2560d2753bda5869adde7597a7ddf0fionaxu try { 248da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Thread.sleep(1000); 249da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } catch (InterruptedException e) { 250da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 251f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu if (isFinishing() || isDestroyed()) return; 252da578042ae2560d2753bda5869adde7597a7ddf0fionaxu HttpURLConnection urlConnection = null; 253da578042ae2560d2753bda5869adde7597a7ddf0fionaxu int httpResponseCode = 500; 254da578042ae2560d2753bda5869adde7597a7ddf0fionaxu int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE); 255da578042ae2560d2753bda5869adde7597a7ddf0fionaxu try { 256c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline urlConnection = (HttpURLConnection) network.openConnection( 257c457a04d937b0f3b81fb49b78f4cde46059e1ac9fionaxu new URL(mCm.getCaptivePortalServerUrl())); 258da578042ae2560d2753bda5869adde7597a7ddf0fionaxu urlConnection.setInstanceFollowRedirects(false); 259da578042ae2560d2753bda5869adde7597a7ddf0fionaxu urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); 260da578042ae2560d2753bda5869adde7597a7ddf0fionaxu urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); 261da578042ae2560d2753bda5869adde7597a7ddf0fionaxu urlConnection.setUseCaches(false); 262da578042ae2560d2753bda5869adde7597a7ddf0fionaxu urlConnection.getInputStream(); 263da578042ae2560d2753bda5869adde7597a7ddf0fionaxu httpResponseCode = urlConnection.getResponseCode(); 264da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } catch (IOException e) { 265c457a04d937b0f3b81fb49b78f4cde46059e1ac9fionaxu loge(e.getMessage()); 266da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } finally { 267da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (urlConnection != null) urlConnection.disconnect(); 268da578042ae2560d2753bda5869adde7597a7ddf0fionaxu TrafficStats.setThreadStatsTag(oldTag); 269da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 270da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (httpResponseCode == 204) { 271da578042ae2560d2753bda5869adde7597a7ddf0fionaxu done(true); 272da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 273da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 274f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu }); 275f62e4cc565330a42b669b0844ca62d2fd0a44491fionaxu mTestingThread.start(); 276da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 277da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 278da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private Network getNetworkForCaptivePortal() { 279da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Network[] info = mCm.getAllNetworks(); 280da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (!ArrayUtils.isEmpty(info)) { 281da578042ae2560d2753bda5869adde7597a7ddf0fionaxu for (Network nw : info) { 282da578042ae2560d2753bda5869adde7597a7ddf0fionaxu final NetworkCapabilities nc = mCm.getNetworkCapabilities(nw); 283da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) 284da578042ae2560d2753bda5869adde7597a7ddf0fionaxu && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { 285da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return nw; 286da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 287da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 288da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 289da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return null; 290da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 291da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 292da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private void requestNetworkForCaptivePortal() { 293da578042ae2560d2753bda5869adde7597a7ddf0fionaxu NetworkRequest request = new NetworkRequest.Builder() 294da578042ae2560d2753bda5869adde7597a7ddf0fionaxu .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 295da578042ae2560d2753bda5869adde7597a7ddf0fionaxu .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 296da578042ae2560d2753bda5869adde7597a7ddf0fionaxu .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 297da578042ae2560d2753bda5869adde7597a7ddf0fionaxu .build(); 298da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 299da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mNetworkCallback = new ConnectivityManager.NetworkCallback() { 300da578042ae2560d2753bda5869adde7597a7ddf0fionaxu @Override 301da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public void onAvailable(Network network) { 302da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (DBG) logd("Network available: " + network); 303c820cb83bb031ad1d438fe7c92f19c69ebe87097Erik Kline setNetwork(network); 304da578042ae2560d2753bda5869adde7597a7ddf0fionaxu runOnUiThreadIfNotFinishing(() -> { 3051c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu if (mReload) { 3061c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu mWebView.reload(); 3071c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu } else { 3081c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu // Start initial page load so WebView finishes loading proxy settings. 3091c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu // Actual load of mUrl is initiated by MyWebViewClient. 3101c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu mWebView.loadData("", "text/html", null); 3111c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu } 312da578042ae2560d2753bda5869adde7597a7ddf0fionaxu }); 313da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 314da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 315da578042ae2560d2753bda5869adde7597a7ddf0fionaxu @Override 316da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public void onUnavailable() { 317da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (DBG) logd("Network unavailable"); 318da578042ae2560d2753bda5869adde7597a7ddf0fionaxu runOnUiThreadIfNotFinishing(() -> { 319da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Instead of not loading anything in webview, simply load the page and return 320da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // HTTP error page in the absence of network connection. 321da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mWebView.loadUrl(mUrl.toString()); 322da578042ae2560d2753bda5869adde7597a7ddf0fionaxu }); 323da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 3241c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu 3251c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu @Override 3261c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu public void onLost(Network lostNetwork) { 3271c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu if (DBG) logd("Network lost"); 3281c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu mReload = true; 3291c0a86fc6ebe6dc8dcbd2e05cf8f2ce8ab3586dafionaxu } 330da578042ae2560d2753bda5869adde7597a7ddf0fionaxu }; 331da578042ae2560d2753bda5869adde7597a7ddf0fionaxu logd("request Network for captive portal"); 332da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mCm.requestNetwork(request, mNetworkCallback, NETWORK_REQUEST_TIMEOUT_MS); 333da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 334da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 335da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private void releaseNetworkRequest() { 336da578042ae2560d2753bda5869adde7597a7ddf0fionaxu logd("release Network for captive portal"); 337da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (mNetworkCallback != null) { 338da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mCm.unregisterNetworkCallback(mNetworkCallback); 339da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mNetworkCallback = null; 340da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mNetwork = null; 341da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 342da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 343da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 344da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private class MyWebViewClient extends WebViewClient { 345da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private static final String INTERNAL_ASSETS = "file:///android_asset/"; 346da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private final String mBrowserBailOutToken = Long.toString(new Random().nextLong()); 347da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // How many Android device-independent-pixels per scaled-pixel 348da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // dp/sp = (px/sp) / (px/dp) = (1/sp) / (1/dp) 349da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private final float mDpPerSp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1, 350da578042ae2560d2753bda5869adde7597a7ddf0fionaxu getResources().getDisplayMetrics()) 351da578042ae2560d2753bda5869adde7597a7ddf0fionaxu / TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, 352da578042ae2560d2753bda5869adde7597a7ddf0fionaxu getResources().getDisplayMetrics()); 353da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private int mPagesLoaded; 354da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 355da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // If we haven't finished cleaning up the history, don't allow going back. 356da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public boolean allowBack() { 357da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return mPagesLoaded > 1; 358da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 359da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 360da578042ae2560d2753bda5869adde7597a7ddf0fionaxu @Override 361da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public void onPageStarted(WebView view, String url, Bitmap favicon) { 362da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (url.contains(mBrowserBailOutToken)) { 363da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mLaunchBrowser = true; 364da578042ae2560d2753bda5869adde7597a7ddf0fionaxu done(false); 365da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return; 366da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 367da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // The first page load is used only to cause the WebView to 368da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // fetch the proxy settings. Don't update the URL bar, and 369da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // don't check if the captive portal is still there. 370da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (mPagesLoaded == 0) return; 371da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // For internally generated pages, leave URL bar listing prior URL as this is the URL 372da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // the page refers to. 373da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (!url.startsWith(INTERNAL_ASSETS)) { 37451efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette final TextView myUrlBar = findViewById(R.id.url_bar); 375da578042ae2560d2753bda5869adde7597a7ddf0fionaxu myUrlBar.setText(url); 376da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 377da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (mNetwork != null) { 378da578042ae2560d2753bda5869adde7597a7ddf0fionaxu testForCaptivePortal(); 379da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 380da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 381da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 382da578042ae2560d2753bda5869adde7597a7ddf0fionaxu @Override 383da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public void onPageFinished(WebView view, String url) { 384da578042ae2560d2753bda5869adde7597a7ddf0fionaxu mPagesLoaded++; 385da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (mPagesLoaded == 1) { 386da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Now that WebView has loaded at least one page we know it has read in the proxy 387da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // settings. Now prompt the WebView read the Network-specific proxy settings. 388da578042ae2560d2753bda5869adde7597a7ddf0fionaxu setWebViewProxy(); 389da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Load the real page. 390da578042ae2560d2753bda5869adde7597a7ddf0fionaxu view.loadUrl(mUrl.toString()); 391da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return; 392da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } else if (mPagesLoaded == 2) { 393da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Prevent going back to empty first page. 394da578042ae2560d2753bda5869adde7597a7ddf0fionaxu view.clearHistory(); 395da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 396da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (mNetwork != null) { 397da578042ae2560d2753bda5869adde7597a7ddf0fionaxu testForCaptivePortal(); 398da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 399da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 400da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 401da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Convert Android device-independent-pixels (dp) to HTML size. 402da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private String dp(int dp) { 403da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // HTML px's are scaled just like dp's, so just add "px" suffix. 404da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return Integer.toString(dp) + "px"; 405da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 406da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 407da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Convert Android scaled-pixels (sp) to HTML size. 408da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private String sp(int sp) { 409da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Convert sp to dp's. 410da578042ae2560d2753bda5869adde7597a7ddf0fionaxu float dp = sp * mDpPerSp; 411da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Apply a scale factor to make things look right. 412da578042ae2560d2753bda5869adde7597a7ddf0fionaxu dp *= 1.3; 413da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Convert dp's to HTML size. 414da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return dp((int) dp); 415da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 416da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 417da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // A web page consisting of a large broken lock icon to indicate SSL failure. 418da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private final String SSL_ERROR_HTML = "<html><head><style>" 419da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + "body { margin-left:" + dp(48) + "; margin-right:" + dp(48) + "; " 420da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + "margin-top:" + dp(96) + "; background-color:#fafafa; }" 421da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + "img { width:" + dp(48) + "; height:" + dp(48) + "; }" 422da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + "div.warn { font-size:" + sp(16) + "; margin-top:" + dp(16) + "; " 423da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + " opacity:0.87; line-height:1.28; }" 424da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + "div.example { font-size:" + sp(14) + "; margin-top:" + dp(16) + "; " 425da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + " opacity:0.54; line-height:1.21905; }" 426da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + "a { font-size:" + sp(14) + "; text-decoration:none; text-transform:uppercase; " 427da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + " margin-top:" + dp(24) + "; display:inline-block; color:#4285F4; " 428da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + " height:" + dp(48) + "; font-weight:bold; }" 429da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + "</style></head><body><p><img src=quantum_ic_warning_amber_96.png><br>" 430da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + "<div class=warn>%s</div>" 431da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + "<div class=example>%s</div>" + "<a href=%s>%s</a></body></html>"; 432da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 433da578042ae2560d2753bda5869adde7597a7ddf0fionaxu @Override 434da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { 435da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Log.w(TAG, "SSL error (error: " + error.getPrimaryError() + " host: " 436da578042ae2560d2753bda5869adde7597a7ddf0fionaxu // Only show host to avoid leaking private info. 437da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + Uri.parse(error.getUrl()).getHost() + " certificate: " 438da578042ae2560d2753bda5869adde7597a7ddf0fionaxu + error.getCertificate() + "); displaying SSL warning."); 439da578042ae2560d2753bda5869adde7597a7ddf0fionaxu final String html = String.format(SSL_ERROR_HTML, getString(R.string.ssl_error_warning), 440da578042ae2560d2753bda5869adde7597a7ddf0fionaxu getString(R.string.ssl_error_example), mBrowserBailOutToken, 441da578042ae2560d2753bda5869adde7597a7ddf0fionaxu getString(R.string.ssl_error_continue)); 442da578042ae2560d2753bda5869adde7597a7ddf0fionaxu view.loadDataWithBaseURL(INTERNAL_ASSETS, html, "text/HTML", "UTF-8", null); 443da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 444da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 445da578042ae2560d2753bda5869adde7597a7ddf0fionaxu @Override 446da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public boolean shouldOverrideUrlLoading(WebView view, String url) { 447da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (url.startsWith("tel:")) { 448da578042ae2560d2753bda5869adde7597a7ddf0fionaxu startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url))); 449da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return true; 450da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 451da578042ae2560d2753bda5869adde7597a7ddf0fionaxu return false; 452da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 453da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 454da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 455da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private class MyWebChromeClient extends WebChromeClient { 456da578042ae2560d2753bda5869adde7597a7ddf0fionaxu @Override 457da578042ae2560d2753bda5869adde7597a7ddf0fionaxu public void onProgressChanged(WebView view, int newProgress) { 45851efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette final ProgressBar myProgressBar = findViewById(R.id.progress_bar); 459da578042ae2560d2753bda5869adde7597a7ddf0fionaxu myProgressBar.setProgress(newProgress); 460da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 461da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 462da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 463da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private void runOnUiThreadIfNotFinishing(Runnable r) { 464da578042ae2560d2753bda5869adde7597a7ddf0fionaxu if (!isFinishing()) { 465da578042ae2560d2753bda5869adde7597a7ddf0fionaxu runOnUiThread(r); 466da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 467da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 468da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 469d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu /** 470d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu * This alias presents the target activity, CaptivePortalLoginActivity, as a independent 471d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu * entity with its own intent filter to handle URL links. This alias will be enabled/disabled 472d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu * dynamically to handle url links based on the network conditions. 473d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu */ 474d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu public static String getAlias(Context context) { 475d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu try { 476d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu PackageInfo p = context.getPackageManager().getPackageInfo(context.getPackageName(), 477d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS); 478d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu for (ActivityInfo activityInfo : p.activities) { 479d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu String targetActivity = activityInfo.targetActivity; 480d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu if (CaptivePortalLoginActivity.class.getName().equals(targetActivity)) { 481d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu return activityInfo.name; 482d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu } 483d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu } 484d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu } catch (PackageManager.NameNotFoundException e) { 485d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu e.printStackTrace(); 486d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu } 487d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu return null; 488d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu } 489d60a9d0e586e95be2f2730a940afdf1ed436c612fionaxu 490da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private static void logd(String s) { 491da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Rlog.d(TAG, s); 492da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 493da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 494da578042ae2560d2753bda5869adde7597a7ddf0fionaxu private static void loge(String s) { 495da578042ae2560d2753bda5869adde7597a7ddf0fionaxu Rlog.d(TAG, s); 496da578042ae2560d2753bda5869adde7597a7ddf0fionaxu } 497da578042ae2560d2753bda5869adde7597a7ddf0fionaxu 498da578042ae2560d2753bda5869adde7597a7ddf0fionaxu} 499