1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.hotspot2.osu; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; 20 21 import android.annotation.Nullable; 22 import android.app.Activity; 23 import android.content.Context; 24 import android.graphics.Bitmap; 25 import android.net.ConnectivityManager; 26 import android.net.Network; 27 import android.net.NetworkCapabilities; 28 import android.net.NetworkRequest; 29 import android.net.wifi.WifiManager; 30 import android.os.Bundle; 31 import android.util.Log; 32 import android.view.KeyEvent; 33 import android.view.View; 34 import android.webkit.WebChromeClient; 35 import android.webkit.WebResourceError; 36 import android.webkit.WebResourceRequest; 37 import android.webkit.WebSettings; 38 import android.webkit.WebView; 39 import android.webkit.WebViewClient; 40 import android.widget.ProgressBar; 41 import android.widget.Toast; 42 43 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; 44 45 import com.android.hotspot2.R; 46 47 import java.net.MalformedURLException; 48 import java.net.URL; 49 50 /** 51 * Online Sign Up Login Web View launched during Provision Process of Hotspot 2.0 rel2. 52 */ 53 public class OsuLoginActivity extends Activity { 54 private static final String TAG = "OsuLogin"; 55 private static final boolean DBG = true; 56 57 private String mUrl; 58 private String mHostName; 59 private Network mNetwork; 60 private ConnectivityManager mCm; 61 private ConnectivityManager.NetworkCallback mNetworkCallback; 62 private WifiManager mWifiManager; 63 private WebView mWebView; 64 private SwipeRefreshLayout mSwipeRefreshLayout; 65 private ProgressBar mProgressBar; 66 private boolean mForceDisconnect = true; 67 boolean mRedirectResponseReceived = false; 68 69 @Override onCreate(@ullable Bundle savedInstanceState)70 protected void onCreate(@Nullable Bundle savedInstanceState) { 71 super.onCreate(savedInstanceState); 72 if (DBG) { 73 Log.d(TAG, "onCreate: Opening OSU Web View"); 74 } 75 76 mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); 77 if (mWifiManager == null) { 78 Log.e(TAG, "Cannot get wifi service"); 79 finishAndRemoveTask(); 80 return; 81 } 82 83 if (getIntent() == null) { 84 Log.e(TAG, "Intent is null"); 85 finishAndRemoveTask(); 86 return; 87 } 88 89 mNetwork = getIntent().getParcelableExtra(WifiManager.EXTRA_OSU_NETWORK); 90 if (mNetwork == null) { 91 Log.e(TAG, "Cannot get the network instance for OSU from intent"); 92 finishAndRemoveTask(); 93 return; 94 } 95 96 mUrl = getIntent().getStringExtra(WifiManager.EXTRA_URL); 97 if (mUrl == null) { 98 Log.e(TAG, "Cannot get OSU server url from intent"); 99 finishAndRemoveTask(); 100 return; 101 } 102 103 mHostName = getHost(mUrl); 104 if (mHostName == null) { 105 Log.e(TAG, "Cannot get host from the url"); 106 finishAndRemoveTask(); 107 return; 108 } 109 110 mCm = (ConnectivityManager) getApplicationContext().getSystemService( 111 Context.CONNECTIVITY_SERVICE); 112 if (mCm == null) { 113 Log.e(TAG, "Cannot get connectivity service"); 114 finishAndRemoveTask(); 115 return; 116 } 117 118 if (!mCm.bindProcessToNetwork(mNetwork)) { 119 Log.e(TAG, "Network is no longer valid"); 120 finishAndRemoveTask(); 121 return; 122 } 123 124 final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork); 125 if (networkCapabilities == null || !networkCapabilities.hasTransport( 126 NetworkCapabilities.TRANSPORT_WIFI)) { 127 Log.e(TAG, "WiFi is not supported for the Network"); 128 finishAndRemoveTask(); 129 return; 130 } 131 132 getActionBar().setDisplayShowHomeEnabled(false); 133 getActionBar().setElevation(0); // remove shadow 134 getActionBar().setTitle(getString(R.string.action_bar_label)); 135 getActionBar().setSubtitle(""); 136 setContentView(R.layout.osu_web_view); 137 138 // Exit this app if network disappeared. 139 mNetworkCallback = new ConnectivityManager.NetworkCallback() { 140 @Override 141 public void onLost(Network network) { 142 if (DBG) { 143 Log.d(TAG, "Lost for the current Network, close the browser"); 144 } 145 mForceDisconnect = false; // It is already disconnected. 146 if (!mRedirectResponseReceived) { 147 showSignUpFailedToast(); 148 } 149 if (mNetwork.equals(network)) { 150 finishAndRemoveTask(); 151 } 152 } 153 }; 154 155 mCm.registerNetworkCallback( 156 new NetworkRequest.Builder().addTransportType( 157 NetworkCapabilities.TRANSPORT_WIFI).removeCapability( 158 NET_CAPABILITY_TRUSTED).build(), 159 mNetworkCallback); 160 161 mWebView = findViewById(R.id.webview); 162 mWebView.clearCache(true); 163 WebSettings webSettings = mWebView.getSettings(); 164 webSettings.setJavaScriptEnabled(true); 165 webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); 166 webSettings.setUseWideViewPort(true); 167 webSettings.setLoadWithOverviewMode(true); 168 webSettings.setSupportZoom(true); 169 webSettings.setBuiltInZoomControls(true); 170 webSettings.setDisplayZoomControls(false); 171 mProgressBar = findViewById(R.id.progress_bar); 172 mWebView.setWebViewClient(new OsuWebViewClient()); 173 mWebView.setWebChromeClient(new WebChromeClient() { 174 @Override 175 public void onProgressChanged(WebView view, int newProgress) { 176 mProgressBar.setProgress(newProgress); 177 } 178 }); 179 180 if (DBG) { 181 Log.d(TAG, "OSU Web View to " + mUrl); 182 } 183 184 mWebView.loadUrl(mUrl); 185 mSwipeRefreshLayout = findViewById(R.id.swipe_refresh); 186 mSwipeRefreshLayout.setOnRefreshListener(() -> { 187 mWebView.reload(); 188 mSwipeRefreshLayout.setRefreshing(true); 189 }); 190 } 191 192 @Override onKeyDown(int keyCode, KeyEvent event)193 public boolean onKeyDown(int keyCode, KeyEvent event) { 194 // Check if the key event was the Back button. 195 if ((keyCode == KeyEvent.KEYCODE_BACK)) { 196 // If there is a history to move back 197 if (mWebView.canGoBack()){ 198 mWebView.goBack(); 199 return true; 200 } 201 } 202 return super.onKeyDown(keyCode, event); 203 } 204 205 @Override onDestroy()206 protected void onDestroy() { 207 if (mNetworkCallback != null) { 208 mCm.unregisterNetworkCallback(mNetworkCallback); 209 mNetworkCallback = null; 210 } 211 if (mWifiManager != null && mForceDisconnect) { 212 mWifiManager.disconnect(); 213 mWifiManager = null; 214 } 215 super.onDestroy(); 216 } 217 getHost(String url)218 private String getHost(String url) { 219 try { 220 return new URL(url).getHost(); 221 } catch (MalformedURLException e) { 222 Log.e(TAG, "Invalid URL " + url); 223 } 224 return null; 225 } 226 getHeaderSubtitle(String urlString)227 private String getHeaderSubtitle(String urlString) { 228 try { 229 URL url = new URL(urlString); 230 return url.getProtocol() + "://" + url.getHost(); 231 } catch (MalformedURLException e) { 232 Log.e(TAG, "Invalid URL " + urlString); 233 } 234 return ""; 235 } 236 showSignUpFailedToast()237 private void showSignUpFailedToast() { 238 Toast.makeText(getApplicationContext(), R.string.sign_up_failed, 239 Toast.LENGTH_SHORT).show(); 240 } 241 242 private class OsuWebViewClient extends WebViewClient { 243 boolean mPageError = false; 244 245 @Override onPageStarted(WebView view, String urlString, Bitmap favicon)246 public void onPageStarted(WebView view, String urlString, Bitmap favicon) { 247 String subtitle = getHeaderSubtitle(urlString); 248 getActionBar().setSubtitle(subtitle); 249 mProgressBar.setVisibility(View.VISIBLE); 250 } 251 252 @Override onPageFinished(WebView view, String url)253 public void onPageFinished(WebView view, String url) { 254 mProgressBar.setVisibility(View.INVISIBLE); 255 mSwipeRefreshLayout.setRefreshing(false); 256 257 // Do not show the page error on UI. 258 if (mPageError) { 259 if (mRedirectResponseReceived) { 260 // Do not disconnect current connection while provisioning is in progress. 261 mForceDisconnect = false; 262 } 263 finishAndRemoveTask(); 264 } 265 } 266 267 @Override onReceivedError(WebView view, WebResourceRequest request, WebResourceError error)268 public void onReceivedError(WebView view, WebResourceRequest request, 269 WebResourceError error) { 270 if (request.getUrl().toString().startsWith("http://127.0.0.1")) { 271 mRedirectResponseReceived = true; 272 view.stopLoading(); 273 } 274 275 if (request.isForMainFrame()) { 276 // This happens right after getting HTTP redirect response from an OSU server 277 // since no more Http request is allowed to send to the OSU server. 278 mPageError = true; 279 Log.e(TAG, "onReceived Error for MainFrame: " + error.getErrorCode()); 280 } 281 } 282 } 283 } 284