upload android base code part8
This commit is contained in:
parent
841ae54672
commit
5425409085
57075 changed files with 9846578 additions and 0 deletions
17
android/packages/apps/Browser2/Android.mk
Normal file
17
android/packages/apps/Browser2/Android.mk
Normal file
|
@ -0,0 +1,17 @@
|
|||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_SDK_VERSION := current
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src)
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := junit
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := legacy-android-test
|
||||
|
||||
LOCAL_PACKAGE_NAME := Browser2
|
||||
|
||||
include $(BUILD_PACKAGE)
|
100
android/packages/apps/Browser2/AndroidManifest.xml
Normal file
100
android/packages/apps/Browser2/AndroidManifest.xml
Normal file
|
@ -0,0 +1,100 @@
|
|||
<!--
|
||||
* 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.
|
||||
-->
|
||||
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.chromium.webview_shell"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24" />
|
||||
|
||||
<!-- "Normal" permissions which do not require user prompt -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
|
||||
|
||||
<!-- "Dangerous" permissions which require user prompt -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Light" >
|
||||
<activity
|
||||
android:name=".TelemetryActivity"
|
||||
android:label="@string/title_activity_telemetry"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".TelemetryMemoryPressureActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:label="@string/title_activity_telemetry"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".JankActivity"
|
||||
android:label="@string/title_activity_jank"
|
||||
android:noHistory="true"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".StartupTimeActivity"
|
||||
android:label="@string/title_activity_startup_time"
|
||||
android:noHistory="true"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".WebViewBrowserActivity"
|
||||
android:label="@string/title_activity_browser"
|
||||
android:exported="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<!-- Catch intents which do not specify a MIME type -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
<!-- Catch intents which do specify a MIME type -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:mimeType="text/html"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
<data android:mimeType="application/xhtml+xml"/>
|
||||
<data android:mimeType="application/vnd.wap.xhtml+xml"/> <!-- XHTML MP -->
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".WebViewLayoutTestActivity"
|
||||
android:label="@string/title_activity_layout_test"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="org.chromium.webview_shell.WebViewLayoutTestRunner"
|
||||
android:targetPackage="org.chromium.webview_shell"
|
||||
android:label="Tests for org.chromium.webview_shell" />
|
||||
</manifest>
|
3
android/packages/apps/Browser2/OWNERS
Normal file
3
android/packages/apps/Browser2/OWNERS
Normal file
|
@ -0,0 +1,3 @@
|
|||
# timvolodine@google.com
|
||||
sgurun@android.com
|
||||
byi@google.com
|
4
android/packages/apps/Browser2/README
Normal file
4
android/packages/apps/Browser2/README
Normal file
|
@ -0,0 +1,4 @@
|
|||
Browser2 is a copy of the WebViewShell, a minimal test browser using WebView.
|
||||
The old Browser is no longer supported. To build a full-fledged browser for
|
||||
AOSP, please follow the instructions at:
|
||||
https://www.chromium.org/developers/how-tos/android-build-instructions
|
Binary file not shown.
After Width: | Height: | Size: 295 B |
BIN
android/packages/apps/Browser2/res/drawable/ic_launcher.png
Normal file
BIN
android/packages/apps/Browser2/res/drawable/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
BIN
android/packages/apps/Browser2/res/drawable/item_more_black.png
Normal file
BIN
android/packages/apps/Browser2/res/drawable/item_more_black.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 325 B |
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<EditText
|
||||
android:id="@+id/url_field"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:singleLine="true"
|
||||
android:inputType="textUri"
|
||||
android:imeOptions="actionGo" />
|
||||
<ImageButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:src="@drawable/breadcrumb_arrow_black"
|
||||
android:contentDescription="@string/load_url"
|
||||
android:onClick="loadUrlFromUrlBar" />
|
||||
<ImageButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:src="@drawable/item_more_black"
|
||||
android:contentDescription="@string/menu_about"
|
||||
android:onClick="showPopup" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
11
android/packages/apps/Browser2/res/menu/main_menu.xml
Normal file
11
android/packages/apps/Browser2/res/menu/main_menu.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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. -->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/menu_reset_webview"
|
||||
android:title="@string/menu_reset_webview"/>
|
||||
<item android:id="@+id/menu_about"
|
||||
android:title="@string/menu_about"/>
|
||||
</menu>
|
18
android/packages/apps/Browser2/res/values/strings.xml
Normal file
18
android/packages/apps/Browser2/res/values/strings.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">WebView Shell</string>
|
||||
<string name="title_activity_telemetry">WebView Telemetry</string>
|
||||
<string name="title_activity_jank">WebView Jank Tester</string>
|
||||
<string name="title_activity_startup_time">WebView Startup Time Tester</string>
|
||||
<string name="title_activity_browser">WebView Browser Tester</string>
|
||||
<string name="title_activity_layout_test">WebView Layout Test</string>
|
||||
<string name="title_activity_page_cycler">WebView Page Cycler Test</string>
|
||||
<string name="menu_reset_webview">Destroy and create new WebView</string>
|
||||
<string name="menu_about">About WebView</string>
|
||||
<string name="load_url">Load URL</string>
|
||||
</resources>
|
37
android/packages/apps/Browser2/run_startup_time_test.sh
Executable file
37
android/packages/apps/Browser2/run_startup_time_test.sh
Executable file
|
@ -0,0 +1,37 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
if ! which adb &> /dev/null; then
|
||||
echo "adb is not in your path, did you run envsetup.sh?"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
TMPFILE=$(tempfile)
|
||||
echo '<body><div>just some text</div></body>' > $TMPFILE
|
||||
adb push $TMPFILE /data/local/tmp/file.html
|
||||
rm $TMPFILE
|
||||
adb shell am start -n com.android.htmlviewer/.HTMLViewerActivity -d \
|
||||
"file:///data/local/tmp/file.html" -a VIEW -t "text/html"
|
||||
|
||||
sleep 3
|
||||
|
||||
echo 'Running test, you should run \
|
||||
`adb logcat | grep WebViewStartupTimeMillis=` in another shell to see results.'
|
||||
|
||||
# Launch webview test shell 100 times
|
||||
for i in $(seq 1 100); do
|
||||
if [[ $(($i % 10)) -eq 0 ]]; then
|
||||
echo -n "..$i.."
|
||||
fi
|
||||
adb shell kill -9 `adb shell ps | grep org.chromium.webview_shell \
|
||||
| tr -s " " " " | cut -d" " -f2`
|
||||
adb shell am start -n org.chromium.webview_shell/.StartupTimeActivity \
|
||||
-a VIEW > /dev/null
|
||||
sleep 0.5
|
||||
done
|
||||
echo
|
||||
|
||||
adb shell rm /data/local/tmp/file.html
|
|
@ -0,0 +1,45 @@
|
|||
// 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.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
/**
|
||||
* This activity is designed for Android Jank testing of WebView. It takes a URL as an argument, and
|
||||
* displays the page ready for the Jank tester to test scrolling etc.
|
||||
*/
|
||||
public class JankActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().setTitle(
|
||||
getResources().getString(R.string.title_activity_jank));
|
||||
setContentView(R.layout.activity_webview);
|
||||
|
||||
WebView webView = (WebView) findViewById(R.id.webview);
|
||||
CookieManager.setAcceptFileSchemeCookies(true);
|
||||
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
String url = getUrlFromIntent(getIntent());
|
||||
webView.loadUrl(url);
|
||||
}
|
||||
|
||||
private static String getUrlFromIntent(Intent intent) {
|
||||
return intent != null ? intent.getDataString() : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// 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.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.webkit.WebView;
|
||||
|
||||
/**
|
||||
* This activity is designed for startup time testing of the WebView.
|
||||
*/
|
||||
public class StartupTimeActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().setTitle(
|
||||
getResources().getString(R.string.title_activity_startup_time));
|
||||
|
||||
long t1 = SystemClock.elapsedRealtime();
|
||||
WebView webView = new WebView(this);
|
||||
setContentView(webView);
|
||||
long t2 = SystemClock.elapsedRealtime();
|
||||
android.util.Log.i("WebViewShell", "WebViewStartupTimeMillis=" + (t2 - t1));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// 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.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
/**
|
||||
* This activity is designed for Telemetry testing of WebView.
|
||||
*/
|
||||
public class TelemetryActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().setTitle(
|
||||
getResources().getString(R.string.title_activity_telemetry));
|
||||
setContentView(R.layout.activity_webview);
|
||||
|
||||
WebView webView = (WebView) findViewById(R.id.webview);
|
||||
CookieManager.setAcceptFileSchemeCookies(true);
|
||||
webView.getSettings().setJavaScriptEnabled(true);
|
||||
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
webView.loadUrl("about:blank");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// 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.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
/**
|
||||
* This activity is designed for sending memory pressure signals for testing WebView.
|
||||
*/
|
||||
public class TelemetryMemoryPressureActivity extends Activity {
|
||||
|
||||
private static final String TAG = "WebViewTelemetry";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().setTitle(
|
||||
getResources().getString(R.string.title_activity_telemetry));
|
||||
setContentView(R.layout.activity_webview);
|
||||
|
||||
WebView webview = (WebView) findViewById(R.id.webview);
|
||||
CookieManager.setAcceptFileSchemeCookies(true);
|
||||
webview.getSettings().setJavaScriptEnabled(true);
|
||||
|
||||
webview.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
webview.loadUrl("about:blank");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
moveTaskToBack(true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,527 @@
|
|||
// 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.Log;
|
||||
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.WebResourceRequest;
|
||||
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 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 view, WebResourceRequest request) {
|
||||
String url = request.getUrl().toString();
|
||||
// "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;
|
||||
}
|
||||
boolean allowLaunchingApps = request.hasGesture() || request.isRedirect();
|
||||
return startBrowsingIntent(WebViewBrowserActivity.this, url, allowLaunchingApps);
|
||||
}
|
||||
|
||||
@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_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,
|
||||
boolean allowLaunchingApps) {
|
||||
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 " + 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 {
|
||||
if (allowLaunchingApps) {
|
||||
context.startActivity(intent);
|
||||
}
|
||||
return true;
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
Log.w(TAG, "No application can handle " + 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
// 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.os.Environment;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* Tests running end-to-end layout tests.
|
||||
*/
|
||||
public class WebViewLayoutTest
|
||||
extends ActivityInstrumentationTestCase2<WebViewLayoutTestActivity> {
|
||||
|
||||
private static final String TAG = "WebViewLayoutTest";
|
||||
|
||||
private static final String EXTERNAL_PREFIX =
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath() + "/";
|
||||
private static final String BASE_WEBVIEW_TEST_PATH = "android_webview/tools/WebViewShell/test/";
|
||||
private static final String BASE_BLINK_TEST_PATH = "third_party/WebKit/LayoutTests/";
|
||||
private static final String PATH_WEBVIEW_PREFIX = EXTERNAL_PREFIX + BASE_WEBVIEW_TEST_PATH;
|
||||
private static final String PATH_BLINK_PREFIX = EXTERNAL_PREFIX + BASE_BLINK_TEST_PATH;
|
||||
|
||||
private static final long TIMEOUT_SECONDS = 20;
|
||||
|
||||
private WebViewLayoutTestActivity mTestActivity;
|
||||
|
||||
public WebViewLayoutTest() {
|
||||
super(WebViewLayoutTestActivity.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mTestActivity = (WebViewLayoutTestActivity) getActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
mTestActivity.finish();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebViewLayoutTestRunner getInstrumentation() {
|
||||
return (WebViewLayoutTestRunner) super.getInstrumentation();
|
||||
}
|
||||
|
||||
public void testSimple() throws Exception {
|
||||
runWebViewLayoutTest("experimental/basic-logging.html",
|
||||
"experimental/basic-logging-expected.txt");
|
||||
}
|
||||
|
||||
public void testGlobalInterface() throws Exception {
|
||||
runBlinkLayoutTest("webexposed/global-interface-listing.html",
|
||||
"webexposed/global-interface-listing-expected.txt");
|
||||
}
|
||||
|
||||
// test helper methods
|
||||
|
||||
private void runWebViewLayoutTest(final String fileName, final String fileNameExpected)
|
||||
throws Exception {
|
||||
runTest(PATH_WEBVIEW_PREFIX + fileName, PATH_WEBVIEW_PREFIX + fileNameExpected);
|
||||
}
|
||||
|
||||
private void runBlinkLayoutTest(final String fileName, final String fileNameExpected)
|
||||
throws Exception {
|
||||
ensureJsTestCopied();
|
||||
runTest(PATH_BLINK_PREFIX + fileName, PATH_WEBVIEW_PREFIX + fileNameExpected);
|
||||
}
|
||||
|
||||
private void runTest(final String fileName, final String fileNameExpected)
|
||||
throws FileNotFoundException, IOException, InterruptedException, TimeoutException {
|
||||
loadUrlWebViewAsync("file://" + fileName, mTestActivity);
|
||||
|
||||
if (getInstrumentation().isRebaseline()) {
|
||||
// this is the rebaseline process
|
||||
mTestActivity.waitForFinish(TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
String result = mTestActivity.getTestResult();
|
||||
writeFile(fileNameExpected, result, true);
|
||||
Log.i(TAG, "file: " + fileNameExpected + " --> rebaselined, length=" + result.length());
|
||||
} else {
|
||||
String expected = readFile(fileNameExpected);
|
||||
mTestActivity.waitForFinish(TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
String result = mTestActivity.getTestResult();
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadUrlWebViewAsync(final String fileUrl,
|
||||
final WebViewLayoutTestActivity activity) {
|
||||
getInstrumentation().runOnMainSync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
activity.loadUrl(fileUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void ensureJsTestCopied() throws IOException {
|
||||
File jsTestFile = new File(PATH_BLINK_PREFIX + "resources/js-test.js");
|
||||
if (jsTestFile.exists()) return;
|
||||
String original = readFile(PATH_WEBVIEW_PREFIX + "resources/js-test.js");
|
||||
writeFile(PATH_BLINK_PREFIX + "resources/js-test.js", original, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a file and returns it's contents as string.
|
||||
*/
|
||||
private static String readFile(String fileName) throws IOException {
|
||||
FileInputStream inputStream = new FileInputStream(new File(fileName));
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
try {
|
||||
StringBuilder contents = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
contents.append(line);
|
||||
contents.append("\n");
|
||||
}
|
||||
return contents.toString();
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a file with the given fileName and contents. If overwrite is true overwrites any
|
||||
* exisiting file with the same file name. If the file does not exist any intermediate
|
||||
* required directories are created.
|
||||
*/
|
||||
private static void writeFile(final String fileName, final String contents, boolean overwrite)
|
||||
throws FileNotFoundException, IOException {
|
||||
File fileOut = new File(fileName);
|
||||
|
||||
if (fileOut.exists() && !overwrite) {
|
||||
return;
|
||||
}
|
||||
|
||||
String absolutePath = fileOut.getAbsolutePath();
|
||||
File filePath = new File(absolutePath.substring(0, absolutePath.lastIndexOf("/")));
|
||||
|
||||
if (!filePath.exists()) {
|
||||
if (!filePath.mkdirs())
|
||||
throw new IOException("failed to create directories: " + filePath);
|
||||
}
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(fileOut);
|
||||
try {
|
||||
outputStream.write(contents.getBytes());
|
||||
} finally {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
// 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.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.webkit.ConsoleMessage;
|
||||
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 java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* This activity is used for running layout tests using webview. The activity
|
||||
* creates a webview instance, loads url and captures console messages from
|
||||
* JavaScript until the test is finished.
|
||||
* provides a blocking callback.
|
||||
*/
|
||||
public class WebViewLayoutTestActivity extends Activity {
|
||||
|
||||
private final StringBuilder mConsoleLog = new StringBuilder();
|
||||
private final Object mLock = new Object();
|
||||
private static final String TEST_FINISHED_SENTINEL = "TEST FINISHED";
|
||||
|
||||
private WebView mWebView;
|
||||
private boolean mFinished = false;
|
||||
|
||||
private static final String[] AUTOMATICALLY_GRANT =
|
||||
{ PermissionRequest.RESOURCE_VIDEO_CAPTURE, PermissionRequest.RESOURCE_AUDIO_CAPTURE };
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_webview);
|
||||
mWebView = (WebView) findViewById(R.id.webview);
|
||||
WebSettings settings = mWebView.getSettings();
|
||||
initializeSettings(settings);
|
||||
|
||||
mWebView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mWebView.setWebChromeClient(new WebChromeClient() {
|
||||
@Override
|
||||
public void onGeolocationPermissionsShowPrompt(String origin,
|
||||
GeolocationPermissions.Callback callback) {
|
||||
callback.invoke(origin, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionRequest(PermissionRequest request) {
|
||||
request.grant(AUTOMATICALLY_GRANT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
|
||||
// TODO(timvolodine): put log and warnings in separate string builders.
|
||||
mConsoleLog.append(consoleMessage.message() + "\n");
|
||||
if (consoleMessage.message().equals(TEST_FINISHED_SENTINEL)) {
|
||||
finishTest();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void waitForFinish(long timeout, TimeUnit unit) throws InterruptedException,
|
||||
TimeoutException {
|
||||
synchronized (mLock) {
|
||||
long deadline = System.currentTimeMillis() + unit.toMillis(timeout);
|
||||
while (!mFinished && System.currentTimeMillis() < deadline) {
|
||||
mLock.wait(deadline - System.currentTimeMillis());
|
||||
}
|
||||
if (!mFinished) {
|
||||
throw new TimeoutException("timeout");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getTestResult() {
|
||||
return mConsoleLog.toString();
|
||||
}
|
||||
|
||||
public void loadUrl(String url) {
|
||||
mWebView.loadUrl(url);
|
||||
mWebView.requestFocus();
|
||||
}
|
||||
|
||||
private void initializeSettings(WebSettings settings) {
|
||||
settings.setJavaScriptEnabled(true);
|
||||
settings.setGeolocationEnabled(true);
|
||||
}
|
||||
|
||||
private void finishTest() {
|
||||
mFinished = true;
|
||||
synchronized (mLock) {
|
||||
mLock.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// 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.os.Bundle;
|
||||
import android.test.InstrumentationTestRunner;
|
||||
|
||||
/**
|
||||
* Customized test runner for running instrumentation tests in WebViewBrowserTests.
|
||||
*/
|
||||
public class WebViewLayoutTestRunner extends InstrumentationTestRunner {
|
||||
private String mModeArgument;
|
||||
private static final String MODE_REBASELINE = "rebaseline";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle arguments) {
|
||||
super.onCreate(arguments);
|
||||
if (arguments != null) {
|
||||
mModeArgument = arguments.getString("mode");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRebaseline() {
|
||||
return mModeArgument != null ? mModeArgument.equals(MODE_REBASELINE) : false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
Test JavaScript feedback into WebView
|
||||
some debug text
|
||||
false
|
||||
undefined
|
||||
TEST FINISHED
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="../resources/js-test.js"></script>
|
||||
<body>
|
||||
SOMETEXT
|
||||
<script type="text/javascript">
|
||||
description("Test JavaScript feedback into WebView");
|
||||
debug("some debug text");
|
||||
debug(isWorker());
|
||||
debug(window.testRunner);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
45
android/packages/apps/Browser2/test/resources/js-test.js
Normal file
45
android/packages/apps/Browser2/test/resources/js-test.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
// 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.
|
||||
|
||||
debug = function debug(msg)
|
||||
{
|
||||
console.log(msg);
|
||||
};
|
||||
|
||||
description = function description(msg, quiet)
|
||||
{
|
||||
console.log(msg);
|
||||
};
|
||||
|
||||
finishJSTest = function finishJSTest() {
|
||||
console.log("TEST FINISHED");
|
||||
};
|
||||
|
||||
function isWorker()
|
||||
{
|
||||
// It's conceivable that someone would stub out 'document' in a worker so
|
||||
// also check for childNodes, an arbitrary DOM-related object that is
|
||||
// meaningless in a WorkerContext.
|
||||
return (typeof document === 'undefined' ||
|
||||
typeof document.childNodes === 'undefined') && !!self.importScripts;
|
||||
}
|
||||
|
||||
function handleTestFinished() {
|
||||
if (!window.jsTestIsAsync)
|
||||
finishJSTest();
|
||||
}
|
||||
|
||||
// Returns a sorted array of property names of object. This function returns
|
||||
// not only own properties but also properties on prototype chains.
|
||||
function getAllPropertyNames(object) {
|
||||
var properties = [];
|
||||
for (var property in object) {
|
||||
properties.push(property);
|
||||
}
|
||||
return properties.sort();
|
||||
}
|
||||
|
||||
if (!isWorker()) {
|
||||
window.addEventListener('DOMContentLoaded', handleTestFinished, false);
|
||||
}
|
23
android/packages/apps/Browser2/test/run_tests.sh
Executable file
23
android/packages/apps/Browser2/test/run_tests.sh
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 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_NAME="org.chromium.webview_shell"
|
||||
DEVICE_WEBVIEW_TEST_PATH="/sdcard/android_webview/tools/WebViewShell/test/"
|
||||
TESTRUNNER="../../../../build/android/test_runner.py"
|
||||
|
||||
$TESTRUNNER instrumentation \
|
||||
--test-apk AndroidWebViewShell \
|
||||
-f 'WebViewLayoutTest*' \
|
||||
--isolate-file-path android_webview/android_webview_shell_test_apk.isolate
|
||||
|
||||
if [ "$1" = "rebaseline" ]; then
|
||||
adb shell am instrument -w -e mode rebaseline -e class \
|
||||
$PACKAGE_NAME.WebViewLayoutTest \
|
||||
$PACKAGE_NAME/$PACKAGE_NAME.WebViewLayoutTestRunner
|
||||
adb pull $DEVICE_WEBVIEW_TEST_PATH ../test_rebaseline/
|
||||
fi
|
||||
|
||||
exit 0
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue