| /* |
| * 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()); |
| } |
| } |