| Index: android_webview/tools/WebViewShell/src/org/chromium/webview_shell/WebViewBrowserActivity.java
|
| diff --git a/android_webview/tools/WebViewShell/src/org/chromium/webview_shell/WebViewBrowserActivity.java b/android_webview/tools/WebViewShell/src/org/chromium/webview_shell/WebViewBrowserActivity.java
|
| deleted file mode 100644
|
| index 2aee9e374658cd8f1a025b9e857d3605563b1c64..0000000000000000000000000000000000000000
|
| --- a/android_webview/tools/WebViewShell/src/org/chromium/webview_shell/WebViewBrowserActivity.java
|
| +++ /dev/null
|
| @@ -1,527 +0,0 @@
|
| -// Copyright 2015 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -package org.chromium.webview_shell;
|
| -
|
| -import android.Manifest;
|
| -import android.app.Activity;
|
| -import android.app.AlertDialog;
|
| -import android.content.ActivityNotFoundException;
|
| -import android.content.Context;
|
| -import android.content.Intent;
|
| -import android.content.IntentFilter;
|
| -import android.content.pm.PackageManager;
|
| -import android.content.pm.ResolveInfo;
|
| -import android.graphics.Bitmap;
|
| -import android.graphics.Color;
|
| -import android.net.Uri;
|
| -import android.os.Build;
|
| -import android.os.Bundle;
|
| -import android.provider.Browser;
|
| -import android.util.SparseArray;
|
| -
|
| -import android.view.KeyEvent;
|
| -import android.view.MenuItem;
|
| -import android.view.View;
|
| -import android.view.View.OnKeyListener;
|
| -import android.view.ViewGroup;
|
| -import android.view.ViewGroup.LayoutParams;
|
| -import android.view.inputmethod.InputMethodManager;
|
| -
|
| -import android.webkit.GeolocationPermissions;
|
| -import android.webkit.PermissionRequest;
|
| -import android.webkit.WebChromeClient;
|
| -import android.webkit.WebSettings;
|
| -import android.webkit.WebView;
|
| -import android.webkit.WebViewClient;
|
| -
|
| -import android.widget.EditText;
|
| -import android.widget.PopupMenu;
|
| -import android.widget.TextView;
|
| -
|
| -import org.chromium.base.Log;
|
| -
|
| -import java.lang.reflect.InvocationTargetException;
|
| -import java.lang.reflect.Method;
|
| -
|
| -import java.net.URI;
|
| -import java.net.URISyntaxException;
|
| -
|
| -import java.util.ArrayList;
|
| -import java.util.HashMap;
|
| -import java.util.List;
|
| -import java.util.regex.Matcher;
|
| -import java.util.regex.Pattern;
|
| -
|
| -/**
|
| - * This activity is designed for starting a "mini-browser" for manual testing of WebView.
|
| - * It takes an optional URL as an argument, and displays the page. There is a URL bar
|
| - * on top of the webview for manually specifying URLs to load.
|
| - */
|
| -public class WebViewBrowserActivity extends Activity implements PopupMenu.OnMenuItemClickListener {
|
| - private static final String TAG = "WebViewShell";
|
| -
|
| - // Our imaginary Android permission to associate with the WebKit geo permission
|
| - private static final String RESOURCE_GEO = "RESOURCE_GEO";
|
| - // Our imaginary WebKit permission to request when loading a file:// URL
|
| - private static final String RESOURCE_FILE_URL = "RESOURCE_FILE_URL";
|
| - // WebKit permissions with no corresponding Android permission can always be granted
|
| - private static final String NO_ANDROID_PERMISSION = "NO_ANDROID_PERMISSION";
|
| -
|
| - // Map from WebKit permissions to Android permissions
|
| - private static final HashMap<String, String> sPermissions;
|
| - static {
|
| - sPermissions = new HashMap<String, String>();
|
| - sPermissions.put(RESOURCE_GEO, Manifest.permission.ACCESS_FINE_LOCATION);
|
| - sPermissions.put(RESOURCE_FILE_URL, Manifest.permission.READ_EXTERNAL_STORAGE);
|
| - sPermissions.put(PermissionRequest.RESOURCE_AUDIO_CAPTURE,
|
| - Manifest.permission.RECORD_AUDIO);
|
| - sPermissions.put(PermissionRequest.RESOURCE_MIDI_SYSEX, NO_ANDROID_PERMISSION);
|
| - sPermissions.put(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID, NO_ANDROID_PERMISSION);
|
| - sPermissions.put(PermissionRequest.RESOURCE_VIDEO_CAPTURE,
|
| - Manifest.permission.CAMERA);
|
| - }
|
| -
|
| - private static final Pattern WEBVIEW_VERSION_PATTERN =
|
| - Pattern.compile("(Chrome/)([\\d\\.]+)\\s");
|
| -
|
| - private EditText mUrlBar;
|
| - private WebView mWebView;
|
| - private String mWebViewVersion;
|
| -
|
| - // Each time we make a request, store it here with an int key. onRequestPermissionsResult will
|
| - // look up the request in order to grant the approprate permissions.
|
| - private SparseArray<PermissionRequest> mPendingRequests = new SparseArray<PermissionRequest>();
|
| - private int mNextRequestKey = 0;
|
| -
|
| - // Work around our wonky API by wrapping a geo permission prompt inside a regular
|
| - // PermissionRequest.
|
| - private static class GeoPermissionRequest extends PermissionRequest {
|
| - private String mOrigin;
|
| - private GeolocationPermissions.Callback mCallback;
|
| -
|
| - public GeoPermissionRequest(String origin, GeolocationPermissions.Callback callback) {
|
| - mOrigin = origin;
|
| - mCallback = callback;
|
| - }
|
| -
|
| - public Uri getOrigin() {
|
| - return Uri.parse(mOrigin);
|
| - }
|
| -
|
| - public String[] getResources() {
|
| - return new String[] { WebViewBrowserActivity.RESOURCE_GEO };
|
| - }
|
| -
|
| - public void grant(String[] resources) {
|
| - assert resources.length == 1;
|
| - assert WebViewBrowserActivity.RESOURCE_GEO.equals(resources[0]);
|
| - mCallback.invoke(mOrigin, true, false);
|
| - }
|
| -
|
| - public void deny() {
|
| - mCallback.invoke(mOrigin, false, false);
|
| - }
|
| - }
|
| -
|
| - // For simplicity, also treat the read access needed for file:// URLs as a regular
|
| - // PermissionRequest.
|
| - private class FilePermissionRequest extends PermissionRequest {
|
| - private String mOrigin;
|
| -
|
| - public FilePermissionRequest(String origin) {
|
| - mOrigin = origin;
|
| - }
|
| -
|
| - public Uri getOrigin() {
|
| - return Uri.parse(mOrigin);
|
| - }
|
| -
|
| - public String[] getResources() {
|
| - return new String[] { WebViewBrowserActivity.RESOURCE_FILE_URL };
|
| - }
|
| -
|
| - public void grant(String[] resources) {
|
| - assert resources.length == 1;
|
| - assert WebViewBrowserActivity.RESOURCE_FILE_URL.equals(resources[0]);
|
| - // Try again now that we have read access.
|
| - WebViewBrowserActivity.this.mWebView.loadUrl(mOrigin);
|
| - }
|
| -
|
| - public void deny() {
|
| - // womp womp
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void onCreate(Bundle savedInstanceState) {
|
| - super.onCreate(savedInstanceState);
|
| - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
| - WebView.setWebContentsDebuggingEnabled(true);
|
| - }
|
| - setContentView(R.layout.activity_webview_browser);
|
| - mUrlBar = (EditText) findViewById(R.id.url_field);
|
| - mUrlBar.setOnKeyListener(new OnKeyListener() {
|
| - public boolean onKey(View view, int keyCode, KeyEvent event) {
|
| - if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) {
|
| - loadUrlFromUrlBar(view);
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| - });
|
| -
|
| - createAndInitializeWebView();
|
| -
|
| - String url = getUrlFromIntent(getIntent());
|
| - if (url != null) {
|
| - setUrlBarText(url);
|
| - setUrlFail(false);
|
| - loadUrlFromUrlBar(mUrlBar);
|
| - }
|
| - }
|
| -
|
| - ViewGroup getContainer() {
|
| - return (ViewGroup) findViewById(R.id.container);
|
| - }
|
| -
|
| - private void createAndInitializeWebView() {
|
| - WebView webview = new WebView(this);
|
| - WebSettings settings = webview.getSettings();
|
| - initializeSettings(settings);
|
| -
|
| - Matcher matcher = WEBVIEW_VERSION_PATTERN.matcher(settings.getUserAgentString());
|
| - if (matcher.find()) {
|
| - mWebViewVersion = matcher.group(2);
|
| - } else {
|
| - mWebViewVersion = "-";
|
| - }
|
| - setTitle(getResources().getString(R.string.title_activity_browser) + " " + mWebViewVersion);
|
| -
|
| - webview.setWebViewClient(new WebViewClient() {
|
| - @Override
|
| - public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
| - setUrlBarText(url);
|
| - }
|
| -
|
| - @Override
|
| - public void onPageFinished(WebView view, String url) {
|
| - setUrlBarText(url);
|
| - }
|
| -
|
| - @Override
|
| - public boolean shouldOverrideUrlLoading(WebView webView, String url) {
|
| - // "about:" and "chrome:" schemes are internal to Chromium;
|
| - // don't want these to be dispatched to other apps.
|
| - if (url.startsWith("about:") || url.startsWith("chrome:")) {
|
| - return false;
|
| - }
|
| - return startBrowsingIntent(WebViewBrowserActivity.this, url);
|
| - }
|
| -
|
| - @Override
|
| - public void onReceivedError(WebView view, int errorCode, String description,
|
| - String failingUrl) {
|
| - setUrlFail(true);
|
| - }
|
| - });
|
| -
|
| - webview.setWebChromeClient(new WebChromeClient() {
|
| - @Override
|
| - public Bitmap getDefaultVideoPoster() {
|
| - return Bitmap.createBitmap(
|
| - new int[] {Color.TRANSPARENT}, 1, 1, Bitmap.Config.ARGB_8888);
|
| - }
|
| -
|
| - @Override
|
| - public void onGeolocationPermissionsShowPrompt(String origin,
|
| - GeolocationPermissions.Callback callback) {
|
| - onPermissionRequest(new GeoPermissionRequest(origin, callback));
|
| - }
|
| -
|
| - @Override
|
| - public void onPermissionRequest(PermissionRequest request) {
|
| - WebViewBrowserActivity.this.requestPermissionsForPage(request);
|
| - }
|
| - });
|
| -
|
| - mWebView = webview;
|
| - getContainer().addView(
|
| - webview, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
|
| - setUrlBarText("");
|
| - }
|
| -
|
| - // WebKit permissions which can be granted because either they have no associated Android
|
| - // permission or the associated Android permission has been granted
|
| - private boolean canGrant(String webkitPermission) {
|
| - String androidPermission = sPermissions.get(webkitPermission);
|
| - if (androidPermission == NO_ANDROID_PERMISSION) {
|
| - return true;
|
| - }
|
| - return PackageManager.PERMISSION_GRANTED == checkSelfPermission(androidPermission);
|
| - }
|
| -
|
| - private void requestPermissionsForPage(PermissionRequest request) {
|
| - // Deny any unrecognized permissions.
|
| - for (String webkitPermission : request.getResources()) {
|
| - if (!sPermissions.containsKey(webkitPermission)) {
|
| - Log.w(TAG, "Unrecognized WebKit permission: " + webkitPermission);
|
| - request.deny();
|
| - return;
|
| - }
|
| - }
|
| -
|
| - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
| - request.grant(request.getResources());
|
| - return;
|
| - }
|
| -
|
| - // Find what Android permissions we need before we can grant these WebKit permissions.
|
| - ArrayList<String> androidPermissionsNeeded = new ArrayList<String>();
|
| - for (String webkitPermission : request.getResources()) {
|
| - if (!canGrant(webkitPermission)) {
|
| - // We already checked for unrecognized permissions, and canGrant will skip over
|
| - // NO_ANDROID_PERMISSION cases, so this is guaranteed to be a regular Android
|
| - // permission.
|
| - String androidPermission = sPermissions.get(webkitPermission);
|
| - androidPermissionsNeeded.add(androidPermission);
|
| - }
|
| - }
|
| -
|
| - // If there are no such Android permissions, grant the WebKit permissions immediately.
|
| - if (androidPermissionsNeeded.isEmpty()) {
|
| - request.grant(request.getResources());
|
| - return;
|
| - }
|
| -
|
| - // Otherwise, file a new request
|
| - if (mNextRequestKey == Integer.MAX_VALUE) {
|
| - Log.e(TAG, "Too many permission requests");
|
| - return;
|
| - }
|
| - int requestCode = mNextRequestKey;
|
| - mNextRequestKey++;
|
| - mPendingRequests.append(requestCode, request);
|
| - requestPermissions(androidPermissionsNeeded.toArray(new String[0]), requestCode);
|
| - }
|
| -
|
| - @Override
|
| - public void onRequestPermissionsResult(int requestCode,
|
| - String permissions[], int[] grantResults) {
|
| - // Verify that we can now grant all the requested permissions. Note that although grant()
|
| - // takes a list of permissions, grant() is actually all-or-nothing. If there are any
|
| - // requested permissions not included in the granted permissions, all will be denied.
|
| - PermissionRequest request = mPendingRequests.get(requestCode);
|
| - for (String webkitPermission : request.getResources()) {
|
| - if (!canGrant(webkitPermission)) {
|
| - request.deny();
|
| - return;
|
| - }
|
| - }
|
| - request.grant(request.getResources());
|
| - mPendingRequests.delete(requestCode);
|
| - }
|
| -
|
| - public void loadUrlFromUrlBar(View view) {
|
| - String url = mUrlBar.getText().toString();
|
| - try {
|
| - URI uri = new URI(url);
|
| - url = (uri.getScheme() == null) ? "http://" + uri.toString() : uri.toString();
|
| - } catch (URISyntaxException e) {
|
| - String message = "<html><body>URISyntaxException: " + e.getMessage() + "</body></html>";
|
| - mWebView.loadData(message, "text/html", "UTF-8");
|
| - setUrlFail(true);
|
| - return;
|
| - }
|
| -
|
| - setUrlBarText(url);
|
| - setUrlFail(false);
|
| - loadUrl(url);
|
| - hideKeyboard(mUrlBar);
|
| - }
|
| -
|
| - public void showPopup(View v) {
|
| - PopupMenu popup = new PopupMenu(this, v);
|
| - popup.setOnMenuItemClickListener(this);
|
| - popup.inflate(R.menu.main_menu);
|
| - popup.show();
|
| - }
|
| -
|
| - @Override
|
| - public boolean onMenuItemClick(MenuItem item) {
|
| - switch(item.getItemId()) {
|
| - case R.id.menu_reset_webview:
|
| - if (mWebView != null) {
|
| - ViewGroup container = getContainer();
|
| - container.removeView(mWebView);
|
| - mWebView.destroy();
|
| - mWebView = null;
|
| - }
|
| - createAndInitializeWebView();
|
| - return true;
|
| - case R.id.menu_clear_cache:
|
| - if (mWebView != null) {
|
| - mWebView.clearCache(true);
|
| - }
|
| - return true;
|
| - case R.id.menu_about:
|
| - about();
|
| - hideKeyboard(mUrlBar);
|
| - return true;
|
| - default:
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - private void initializeSettings(WebSettings settings) {
|
| - settings.setJavaScriptEnabled(true);
|
| -
|
| - // configure local storage apis and their database paths.
|
| - settings.setAppCachePath(getDir("appcache", 0).getPath());
|
| - settings.setGeolocationDatabasePath(getDir("geolocation", 0).getPath());
|
| - settings.setDatabasePath(getDir("databases", 0).getPath());
|
| -
|
| - settings.setAppCacheEnabled(true);
|
| - settings.setGeolocationEnabled(true);
|
| - settings.setDatabaseEnabled(true);
|
| - settings.setDomStorageEnabled(true);
|
| - }
|
| -
|
| - private void about() {
|
| - WebSettings settings = mWebView.getSettings();
|
| - StringBuilder summary = new StringBuilder();
|
| - summary.append("WebView version : " + mWebViewVersion + "\n");
|
| -
|
| - for (Method method : settings.getClass().getMethods()) {
|
| - if (!methodIsSimpleInspector(method)) continue;
|
| - try {
|
| - summary.append(method.getName() + " : " + method.invoke(settings) + "\n");
|
| - } catch (IllegalAccessException e) {
|
| - } catch (InvocationTargetException e) { }
|
| - }
|
| -
|
| - AlertDialog dialog = new AlertDialog.Builder(this)
|
| - .setTitle(getResources().getString(R.string.menu_about))
|
| - .setMessage(summary)
|
| - .setPositiveButton("OK", null)
|
| - .create();
|
| - dialog.show();
|
| - dialog.getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
|
| - }
|
| -
|
| - // Returns true is a method has no arguments and returns either a boolean or a String.
|
| - private boolean methodIsSimpleInspector(Method method) {
|
| - Class<?> returnType = method.getReturnType();
|
| - return ((returnType.equals(boolean.class) || returnType.equals(String.class))
|
| - && method.getParameterTypes().length == 0);
|
| - }
|
| -
|
| - private void loadUrl(String url) {
|
| - // Request read access if necessary
|
| - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
| - && "file".equals(Uri.parse(url).getScheme())
|
| - && PackageManager.PERMISSION_DENIED
|
| - == checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
| - requestPermissionsForPage(new FilePermissionRequest(url));
|
| - }
|
| -
|
| - // If it is file:// and we don't have permission, they'll get the "Webpage not available"
|
| - // "net::ERR_ACCESS_DENIED" page. When we get permission, FilePermissionRequest.grant()
|
| - // will reload.
|
| - mWebView.loadUrl(url);
|
| - mWebView.requestFocus();
|
| - }
|
| -
|
| - private void setUrlBarText(String url) {
|
| - mUrlBar.setText(url, TextView.BufferType.EDITABLE);
|
| - }
|
| -
|
| - private void setUrlFail(boolean fail) {
|
| - mUrlBar.setTextColor(fail ? Color.RED : Color.BLACK);
|
| - }
|
| -
|
| - /**
|
| - * Hides the keyboard.
|
| - * @param view The {@link View} that is currently accepting input.
|
| - * @return Whether the keyboard was visible before.
|
| - */
|
| - private static boolean hideKeyboard(View view) {
|
| - InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(
|
| - Context.INPUT_METHOD_SERVICE);
|
| - return imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
| - }
|
| -
|
| - private static String getUrlFromIntent(Intent intent) {
|
| - return intent != null ? intent.getDataString() : null;
|
| - }
|
| -
|
| - static final Pattern BROWSER_URI_SCHEMA = Pattern.compile(
|
| - "(?i)" // switch on case insensitive matching
|
| - + "(" // begin group for schema
|
| - + "(?:http|https|file):\\/\\/"
|
| - + "|(?:inline|data|about|chrome|javascript):"
|
| - + ")"
|
| - + "(.*)");
|
| -
|
| - private static boolean startBrowsingIntent(Context context, String url) {
|
| - Intent intent;
|
| - // Perform generic parsing of the URI to turn it into an Intent.
|
| - try {
|
| - intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
|
| - } catch (Exception ex) {
|
| - Log.w(TAG, "Bad URI %s", url, ex);
|
| - return false;
|
| - }
|
| - // Check for regular URIs that WebView supports by itself, but also
|
| - // check if there is a specialized app that had registered itself
|
| - // for this kind of an intent.
|
| - Matcher m = BROWSER_URI_SCHEMA.matcher(url);
|
| - if (m.matches() && !isSpecializedHandlerAvailable(context, intent)) {
|
| - return false;
|
| - }
|
| - // Sanitize the Intent, ensuring web pages can not bypass browser
|
| - // security (only access to BROWSABLE activities).
|
| - intent.addCategory(Intent.CATEGORY_BROWSABLE);
|
| - intent.setComponent(null);
|
| - Intent selector = intent.getSelector();
|
| - if (selector != null) {
|
| - selector.addCategory(Intent.CATEGORY_BROWSABLE);
|
| - selector.setComponent(null);
|
| - }
|
| -
|
| - // Pass the package name as application ID so that the intent from the
|
| - // same application can be opened in the same tab.
|
| - intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
|
| - try {
|
| - context.startActivity(intent);
|
| - return true;
|
| - } catch (ActivityNotFoundException ex) {
|
| - Log.w(TAG, "No application can handle %s", url);
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - /**
|
| - * Search for intent handlers that are specific to the scheme of the URL in the intent.
|
| - */
|
| - private static boolean isSpecializedHandlerAvailable(Context context, Intent intent) {
|
| - PackageManager pm = context.getPackageManager();
|
| - List<ResolveInfo> handlers = pm.queryIntentActivities(intent,
|
| - PackageManager.GET_RESOLVED_FILTER);
|
| - if (handlers == null || handlers.size() == 0) {
|
| - return false;
|
| - }
|
| - for (ResolveInfo resolveInfo : handlers) {
|
| - if (!isNullOrGenericHandler(resolveInfo.filter)) {
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - private static boolean isNullOrGenericHandler(IntentFilter filter) {
|
| - return filter == null
|
| - || (filter.countDataAuthorities() == 0 && filter.countDataPaths() == 0);
|
| - }
|
| -}
|
|
|