summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2014-11-13 17:50:25 -0800
committerJeff Sharkey <jsharkey@android.com>2014-11-14 11:21:12 -0800
commitc9cd4b66263697ddc227b012d96a90ead8d21d92 (patch)
tree8f4df22a224d91fe4c7684ba2fa7d83d80e553d9
parent2e368f6d87eb82691f855e93f85599b75b489731 (diff)
downloadandroid_packages_apps_HTMLViewer-c9cd4b66263697ddc227b012d96a90ead8d21d92.tar.gz
android_packages_apps_HTMLViewer-c9cd4b66263697ddc227b012d96a90ead8d21d92.tar.bz2
android_packages_apps_HTMLViewer-c9cd4b66263697ddc227b012d96a90ead8d21d92.zip
Modernize HTMLViewer, offer to decompress.
Spruce up the UI to match Material spec. We can also load file:// content directly instead of forcing through a ContentProvider. Since we're using this to show license content, try decompressing files that end in ".gz", but fall back to loading normally if it's not compressed. Let callers provide a window title. Bug: 18376908 Change-Id: I59ce02fb17fbe157239d365417a1a1e88e2a18d4
-rw-r--r--AndroidManifest.xml17
-rw-r--r--res/layout/main.xml35
-rw-r--r--src/com/android/htmlviewer/FileContentProvider.java94
-rw-r--r--src/com/android/htmlviewer/HTMLViewerActivity.java133
4 files changed, 88 insertions, 191 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 315a958..9a2ccd0 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -19,12 +19,14 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.htmlviewer">
-
<original-package android:name="com.android.htmlviewer" />
+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
<application android:label="@string/app_label">
- <activity android:name="HTMLViewerActivity" android:label="HTMLViewer"
- android:theme="@android:style/Theme.Holo" >
+ <activity android:name="HTMLViewerActivity"
+ android:label="@string/app_label"
+ android:theme="@android:style/Theme.DeviceDefault">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW" />
@@ -36,14 +38,5 @@
<data android:mimeType="application/vnd.wap.xhtml+xml"/>
</intent-filter>
</activity>
-
- <provider android:name="FileContentProvider"
- android:exported="false"
- android:authorities="com.android.htmlfileprovider"
- android:syncable="false" android:multiprocess="false"
- android:grantUriPermissions="true" />
-
</application>
-
</manifest>
-
diff --git a/res/layout/main.xml b/res/layout/main.xml
new file mode 100644
index 0000000..8a9f48a
--- /dev/null
+++ b/res/layout/main.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@*android:color/white">
+
+ <WebView
+ android:id="@+id/webview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <ProgressBar
+ android:id="@+id/loading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:indeterminate="true"
+ style="?android:attr/progressBarStyle" />
+
+</FrameLayout>
diff --git a/src/com/android/htmlviewer/FileContentProvider.java b/src/com/android/htmlviewer/FileContentProvider.java
deleted file mode 100644
index 4cf16a6..0000000
--- a/src/com/android/htmlviewer/FileContentProvider.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy
- * of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-package com.android.htmlviewer;
-
-import java.io.FileNotFoundException;
-import java.io.File;
-import java.lang.UnsupportedOperationException;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-
-/**
- * WebView does not support file: loading. This class wraps a file load
- * with a content provider.
- * As HTMLViewer does not have internet access nor does it allow
- * Javascript to be run, it is safe to load file based HTML content.
-*/
-public class FileContentProvider extends ContentProvider {
-
- public static final String BASE_URI =
- "content://com.android.htmlfileprovider";
-
- @Override
- public String getType(Uri uri) {
- // If the mimetype is not appended to the uri, then return an empty string
- String mimetype = uri.getQuery();
- return mimetype == null ? "" : mimetype;
- }
-
- @Override
- public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- // android:exported="false" is broken in older releases so we have to
- // manually enforce the calling identity.
- if (Process.myUid() != Binder.getCallingUid()) {
- throw new SecurityException("Permission denied");
- }
- if (!"r".equals(mode)) {
- throw new FileNotFoundException("Bad mode for " + uri + ": " + mode);
- }
- String filename = uri.getPath();
- File f = new File(filename);
- if (f.isDirectory()) {
- return null;
- }
- return ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean onCreate() {
- return true;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
- throw new UnsupportedOperationException();
- }
-
-}
diff --git a/src/com/android/htmlviewer/HTMLViewerActivity.java b/src/com/android/htmlviewer/HTMLViewerActivity.java
index d4f4f73..0de772d 100644
--- a/src/com/android/htmlviewer/HTMLViewerActivity.java
+++ b/src/com/android/htmlviewer/HTMLViewerActivity.java
@@ -17,73 +17,49 @@
package com.android.htmlviewer;
import android.app.Activity;
+import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
-import android.view.Window;
-import android.webkit.CookieSyncManager;
+import android.view.View;
import android.webkit.WebChromeClient;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
+import android.webkit.WebViewClient;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
/**
- * Wraps a WebView widget within an Activity. When launched, it uses the
- * URI from the intent as the URL to load into the WebView.
- * It supports all URLs schemes that a standard WebView supports, as well as
- * loading the top level markup using the file scheme.
- * The WebView default settings are used with the exception of normal layout
- * is set.
- * This activity shows a loading progress bar in the window title and sets
- * the window title to the title of the content.
- *
+ * Simple activity that shows the requested HTML page. This utility is
+ * purposefully very limited in what it supports, including no network or
+ * JavaScript.
*/
public class HTMLViewerActivity extends Activity {
+ private static final String TAG = "HTMLViewer";
- /*
- * The WebView that is placed in this Activity
- */
private WebView mWebView;
-
- /*
- * As the file content is loaded completely into RAM first, set
- * a limitation on the file size so we don't use too much RAM. If someone
- * wants to load content that is larger than this, then a content
- * provider should be used.
- */
- static final int MAXFILESIZE = 8096;
-
- static final String LOGTAG = "HTMLViewerActivity";
+ private View mLoading;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- // Call createInstance() explicitly. createInstance() is called in
- // BrowserFrame by WebView. As it is called in WebCore thread, it can
- // happen after onResume() is called. To use getInstance() in onResume,
- // createInstance() needs to be called first.
- CookieSyncManager.createInstance(this);
+ setContentView(R.layout.main);
- requestWindowFeature(Window.FEATURE_PROGRESS);
+ mWebView = (WebView) findViewById(R.id.webview);
+ mLoading = findViewById(R.id.loading);
- mWebView = new WebView(this);
- setContentView(mWebView);
+ mWebView.setWebChromeClient(new ChromeClient());
+ mWebView.setWebViewClient(new ViewClient());
- // Setup callback support for title and progress bar
- mWebView.setWebChromeClient( new WebChrome() );
-
- // Configure the webview
WebSettings s = mWebView.getSettings();
s.setUseWideViewPort(true);
s.setSupportZoom(true);
- s.setBuiltInZoomControls(true);
s.setSavePassword(false);
s.setSaveFormData(false);
s.setBlockNetworkLoads(true);
@@ -91,46 +67,14 @@ public class HTMLViewerActivity extends Activity {
// Javascript is purposely disabled, so that nothing can be
// automatically run.
s.setJavaScriptEnabled(false);
-
s.setDefaultTextEncodingName("utf-8");
- // Restore a webview if we are meant to restore
- if (savedInstanceState != null) {
- mWebView.restoreState(savedInstanceState);
- } else {
- // Check the intent for the content to view
- Intent intent = getIntent();
- if (intent.getData() != null) {
- Uri uri = intent.getData();
- String contentUri = "file".equals(uri.getScheme())
- ? FileContentProvider.BASE_URI + uri.getEncodedPath()
- : uri.toString();
- mWebView.loadUrl(contentUri);
- }
+ final Intent intent = getIntent();
+ if (intent.hasExtra(Intent.EXTRA_TITLE)) {
+ setTitle(intent.getStringExtra(Intent.EXTRA_TITLE));
}
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- CookieSyncManager.getInstance().startSync();
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- // the default implementation requires each view to have an id. As the
- // browser handles the state itself and it doesn't use id for the views,
- // don't call the default implementation. Otherwise it will trigger the
- // warning like this, "couldn't save which view has focus because the
- // focused view XXX has no id".
- mWebView.saveState(outState);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- CookieSyncManager.getInstance().stopSync();
+ mWebView.loadUrl(String.valueOf(intent.getData()));
}
@Override
@@ -139,21 +83,40 @@ public class HTMLViewerActivity extends Activity {
mWebView.destroy();
}
- class WebChrome extends WebChromeClient {
-
+ private class ChromeClient extends WebChromeClient {
@Override
public void onReceivedTitle(WebView view, String title) {
- HTMLViewerActivity.this.setTitle(title);
+ if (!getIntent().hasExtra(Intent.EXTRA_TITLE)) {
+ HTMLViewerActivity.this.setTitle(title);
+ }
}
+ }
+ private class ViewClient extends WebViewClient {
@Override
- public void onProgressChanged(WebView view, int newProgress) {
- getWindow().setFeatureInt(
- Window.FEATURE_PROGRESS, newProgress*100);
- if (newProgress == 100) {
- CookieSyncManager.getInstance().sync();
+ public void onPageFinished(WebView view, String url) {
+ mLoading.setVisibility(View.GONE);
+ }
+
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebView view,
+ WebResourceRequest request) {
+ final Uri uri = request.getUrl();
+ if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())
+ && uri.getPath().endsWith(".gz")) {
+ Log.d(TAG, "Trying to decompress " + uri + " on the fly");
+ try {
+ final InputStream in = new GZIPInputStream(
+ getContentResolver().openInputStream(uri));
+ final WebResourceResponse resp = new WebResourceResponse(
+ getIntent().getType(), "utf-8", in);
+ resp.setStatusCodeAndReasonPhrase(200, "OK");
+ return resp;
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to decompress; falling back", e);
+ }
}
+ return null;
}
}
-
}