blob: ec8c60c6d1dc2cff71aff254208f5f23d8d7979d [file] [log] [blame]
/*
* Copyright (C) 2010 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 android.webruntime;
import android.app.Activity;
import android.content.Intent;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.Window;
import android.webkit.GeolocationPermissions;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView;
import android.widget.Toast;
import com.android.internal.R;
import java.net.MalformedURLException;
import java.net.URL;
/**
* The runtime used to display installed web applications.
* @hide
*/
public class WebRuntimeActivity extends Activity
{
private final static String LOGTAG = "WebRuntimeActivity";
private WebView mWebView;
private URL mBaseUrl;
private ImageView mSplashScreen;
public static class SensitiveFeatures {
// All of the sensitive features
private boolean mGeolocation;
// On Android, the Browser doesn't prompt for database access, so we don't require an
// explicit permission here in the WebRuntimeActivity, and there's no Android system
// permission required for it either.
//private boolean mDatabase;
public boolean getGeolocation() {
return mGeolocation;
}
public void setGeolocation(boolean geolocation) {
mGeolocation = geolocation;
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Can't get meta data using getApplicationInfo() as it doesn't pass GET_META_DATA
PackageManager packageManager = getPackageManager();
ComponentName componentName = new ComponentName(this, getClass());
ActivityInfo activityInfo = null;
try {
activityInfo = packageManager.getActivityInfo(componentName, PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
Log.d(LOGTAG, "Failed to find component");
return;
}
if (activityInfo == null) {
Log.d(LOGTAG, "Failed to get activity info");
return;
}
Bundle metaData = activityInfo.metaData;
if (metaData == null) {
Log.d(LOGTAG, "No meta data");
return;
}
String url = metaData.getString("android.webruntime.url");
if (url == null) {
Log.d(LOGTAG, "No URL");
return;
}
try {
mBaseUrl = new URL(url);
} catch (MalformedURLException e) {
Log.d(LOGTAG, "Invalid URL");
}
// All false by default, and reading non-existent bundle properties gives false too.
final SensitiveFeatures sensitiveFeatures = new SensitiveFeatures();
sensitiveFeatures.setGeolocation(metaData.getBoolean("android.webruntime.SensitiveFeaturesGeolocation"));
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.web_runtime);
mWebView = (WebView) findViewById(R.id.webview);
mSplashScreen = (ImageView) findViewById(R.id.splashscreen);
mSplashScreen.setImageResource(
getResources().getIdentifier("splash_screen", "drawable", getPackageName()));
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
try {
URL newOrigin = new URL(url);
if (areSameOrigin(mBaseUrl, newOrigin)) {
// If simple same origin test passes, load in the webview.
return false;
}
} catch(MalformedURLException e) {
// Don't load anything if this wasn't a proper URL.
return true;
}
// Otherwise this is a URL that is not same origin so pass it to the
// Browser to load.
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
if (mSplashScreen != null && mSplashScreen.getVisibility() == View.VISIBLE) {
mSplashScreen.setVisibility(View.GONE);
mSplashScreen = null;
}
}
});
// Use a custom WebChromeClient with geolocation permissions handling.
mWebView.setWebChromeClient(new WebChromeClient() {
public void onGeolocationPermissionsShowPrompt(
String origin, GeolocationPermissions.Callback callback) {
// Allow this origin if it has Geolocation permissions, otherwise deny.
boolean allowed = false;
if (sensitiveFeatures.getGeolocation()) {
try {
URL originUrl = new URL(origin);
allowed = areSameOrigin(mBaseUrl, originUrl);
} catch(MalformedURLException e) {
}
}
callback.invoke(origin, allowed, false);
}
});
// Set the DB location. Optional. Geolocation works without DBs.
mWebView.getSettings().setGeolocationDatabasePath(
getDir("geolocation", MODE_PRIVATE).getPath());
String title = metaData.getString("android.webruntime.title");
// We turned off the title bar to go full screen so display the
// webapp's title as a toast.
if (title != null) {
Toast.makeText(this, title, Toast.LENGTH_SHORT).show();
}
// Load the webapp's base URL.
mWebView.loadUrl(url);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, 0, 0, "Menu item 1");
menu.add(0, 1, 0, "Menu item 2");
return true;
}
private static boolean areSameOrigin(URL a, URL b) {
int aPort = a.getPort() == -1 ? a.getDefaultPort() : a.getPort();
int bPort = b.getPort() == -1 ? b.getDefaultPort() : b.getPort();
return a.getProtocol().equals(b.getProtocol()) && aPort == bPort && a.getHost().equals(b.getHost());
}
}