package com.cradle.iitc_mobile; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.net.http.SslError; import android.os.Environment; import android.preference.PreferenceManager; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.webkit.HttpAuthHandler; import android.webkit.SslErrorHandler; import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.TextView; import java.io.ByteArrayInputStream; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; public class IITC_WebViewClient extends WebViewClient { private static final ByteArrayInputStream STYLE = new ByteArrayInputStream( "body, #dashboard_container, #map_canvas { background: #000 !important; }" .getBytes()); private static final ByteArrayInputStream EMPTY = new ByteArrayInputStream("".getBytes()); private static final String DOMAIN = IITC_FileManager.DOMAIN; private final String mIitcPath; private boolean mIitcInjected = false; private final IITC_Mobile mIitc; private final IITC_TileManager mTileManager; public IITC_WebViewClient(final IITC_Mobile iitc) { mIitc = iitc; mTileManager = new IITC_TileManager(mIitc); mIitcPath = Environment.getExternalStorageDirectory().getPath() + "/IITC_Mobile/"; } // enable https @Override public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError error) { handler.proceed(); } @Override public void onPageFinished(final WebView view, final String url) { if (url.startsWith("http://www.ingress.com/intel") || url.startsWith("https://www.ingress.com/intel")) { if (mIitcInjected) return; Log.d("injecting iitc.."); loadScripts((IITC_WebView) view); mIitcInjected = true; } super.onPageFinished(view, url); } private void loadScripts(final IITC_WebView view) { final List scripts = new LinkedList(); // get the plugin preferences final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mIitc); final TreeMap all_prefs = new TreeMap(sharedPref.getAll()); // iterate through all plugins for (final Map.Entry entry : all_prefs.entrySet()) { final String plugin = entry.getKey(); if (plugin.endsWith(".user.js") && entry.getValue().toString().equals("true")) { if (plugin.startsWith(mIitcPath)) { scripts.add("user-plugin" + DOMAIN + plugin); } else { scripts.add("script" + DOMAIN + "/plugins/" + plugin); } } } // inject the user location script if enabled in settings if (Integer.parseInt(sharedPref.getString("pref_user_location_mode", "0")) != 0) { scripts.add("script" + DOMAIN + "/user-location.user.js"); } scripts.add("script" + DOMAIN + "/total-conversion-build.user.js"); final String js = "(function(){['" + TextUtils.join("','", scripts) + "'].forEach(function(src) {" + "var script = document.createElement('script');script.src = '//'+src;" + "(document.body || document.head || document.documentElement).appendChild(script);" + "});})();"; view.loadJS(js); } /** * this method is called automatically when the Google login form is opened. */ @Override public void onReceivedLoginRequest(final WebView view, final String realm, final String account, final String args) { mIitcInjected = false; // Log.d("iitcm", "Login requested: " + realm + " " + account + " " + args); // mIitc.onReceivedLoginRequest(this, view, realm, account, args); } /** * Check every external resource if it's okay to load it and maybe replace it with our own content. * This is used to block loading Niantic resources which aren’t required and to inject IITC early into the site. * via http://stackoverflow.com/a/8274881/1684530 */ @Override public WebResourceResponse shouldInterceptRequest(final WebView view, final String url) { // if any tiles are requested, handle it with IITC_TileManager if (url.matches(".*tile.*jpg.*") // mapquest tiles | ovi tiles || url.matches(".*tile.*png.*") // cloudmade tiles || url.matches(".*mts.*googleapis.*smartmaps") // google tiles || url.matches(".*khms.*googleapis.*") // google satellite tiles || url.matches(".*tile.*jpeg.*") // bing tiles || url.matches(".*maps.*yandex.*tiles.*") // yandex maps ) { try { return mTileManager.getTile(url); } catch (final Exception e) { Log.w(e); return super.shouldInterceptRequest(view, url); } } if (url.contains("/css/common.css")) { // return custom stylesheet return new WebResourceResponse("text/css", "UTF-8", STYLE); } if (url.contains("/css/ap_icons.css") || url.contains("/css/map_icons.css") || url.contains("/css/common.css") || url.contains("/css/misc_icons.css") || url.contains("/css/style_full.css") || url.contains("/css/style_mobile.css") || url.contains("/css/portalrender.css") || url.contains("/css/portalrender_mobile.css") || url.contains("js/analytics.js") || url.contains("google-analytics.com/ga.js")) { // don't load stylesheets return new WebResourceResponse("text/plain", "UTF-8", EMPTY); } final Uri uri = Uri.parse(url); if (uri.getHost() != null && uri.getHost().endsWith(DOMAIN) && ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme()))) return mIitc.getFileManager().getResponse(uri); return super.shouldInterceptRequest(view, url); } // start non-ingress-intel-urls in another app... @Override public boolean shouldOverrideUrlLoading(final WebView view, final String url) { if (url.contains("ingress.com") || url.contains("appengine.google.com")) { // reload iitc if a poslink is clicked inside the app if (url.contains("intel?ll=") || (url.contains("latE6") && url.contains("lngE6"))) { Log.d("should be an internal clicked position link...reload script for: " + url); mIitc.loadUrl(url); } return false; } else { Log.d("no ingress intel link, start external app to load url: " + url); final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); mIitc.startActivity(intent); return true; } } @Override public void onReceivedHttpAuthRequest(WebView view, final HttpAuthHandler handler, final String host, final String realm) { String username = null; String password = null; final boolean reuseHttpAuthUsernamePassword = handler.useHttpAuthUsernamePassword(); if (reuseHttpAuthUsernamePassword && view != null) { String[] credentials = view.getHttpAuthUsernamePassword(host, realm); if (credentials != null && credentials.length == 2) { username = credentials[0]; password = credentials[1]; } } if (username != null && password != null) { handler.proceed(username, password); } else { createSignInDialog(handler, host, realm).show(); } } public Dialog createSignInDialog(final HttpAuthHandler handler, final String host, final String realm) { final AlertDialog.Builder builder = new AlertDialog.Builder(mIitc); final LayoutInflater inflater = mIitc.getLayoutInflater(); final View v = inflater.inflate(R.layout.http_authentication, null); final TextView user = (TextView) v.findViewById(R.id.username); final TextView pass = (TextView) v.findViewById(R.id.password); final String title = String.format(mIitc.getResources().getString(R.string.sign_in_to), host, realm); builder.setView(v) .setTitle(title) .setPositiveButton(R.string.sign_in_action, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { handler.proceed(user.getText().toString(), pass.getText().toString()); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { handler.cancel(); } }); return builder.create(); } public void reset() { mIitcInjected = false; } }