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