diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:43 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:43 -0800 |
commit | f013e1afd1e68af5e3b868c26a653bbfb39538f8 (patch) | |
tree | 7ad6c8fd9c7b55f4b4017171dec1cb760bbd26bf /core/java/android/webkit/gears | |
parent | e70cfafe580c6f2994c4827cd8a534aabf3eb05c (diff) | |
download | frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.zip frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.gz frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.bz2 |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'core/java/android/webkit/gears')
6 files changed, 387 insertions, 15 deletions
diff --git a/core/java/android/webkit/gears/AndroidWifiDataProvider.java b/core/java/android/webkit/gears/AndroidWifiDataProvider.java new file mode 100644 index 0000000..7379f59 --- /dev/null +++ b/core/java/android/webkit/gears/AndroidWifiDataProvider.java @@ -0,0 +1,136 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package android.webkit.gears; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.os.Looper; +import android.util.Config; +import android.util.Log; +import android.webkit.WebView; +import java.util.List; + +/** + * WiFi data provider implementation for Android. + * {@hide} + */ +public final class AndroidWifiDataProvider extends BroadcastReceiver { + /** + * Logging tag + */ + private static final String TAG = "Gears-J-WifiProvider"; + /** + * Our Wifi manager instance. + */ + private WifiManager mWifiManager; + /** + * The native object ID. + */ + private long mNativeObject; + /** + * The Context instance. + */ + private Context mContext; + + /** + * Constructs a instance of this class and registers for wifi scan + * updates. Note that this constructor must be called on a Looper + * thread. Suitable threads can be created on the native side using + * the AndroidLooperThread C++ class. + */ + public AndroidWifiDataProvider(WebView webview, long object) { + mNativeObject = object; + mContext = webview.getContext(); + mWifiManager = + (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + if (mWifiManager == null) { + Log.e(TAG, + "AndroidWifiDataProvider: could not get location manager."); + throw new NullPointerException( + "AndroidWifiDataProvider: locationManager is null."); + } + + // Create a Handler that identifies the message loop associated + // with the current thread. Note that it is not necessary to + // override handleMessage() at all since the Intent + // ReceiverDispatcher (see the ActivityThread class) only uses + // this handler to post a Runnable to this thread's loop. + Handler handler = new Handler(Looper.myLooper()); + + IntentFilter filter = new IntentFilter(); + filter.addAction(mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + mContext.registerReceiver(this, filter, null, handler); + + // Get the last scan results and pass them to the native side. + // We can't just invoke the callback here, so we queue a message + // to this thread's loop. + handler.post(new Runnable() { + public void run() { + onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject); + } + }); + } + + /** + * Called when the provider is no longer needed. + */ + public void shutdown() { + mContext.unregisterReceiver(this); + if (Config.LOGV) { + Log.v(TAG, "Wifi provider closed."); + } + } + + /** + * This method is called when the AndroidWifiDataProvider is receiving an + * Intent broadcast. + * @param context The Context in which the receiver is running. + * @param intent The Intent being received. + */ + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals( + mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { + if (Config.LOGV) { + Log.v(TAG, "Wifi scan resulst available"); + } + onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject); + } + } + + /** + * The native method called when new wifi data is available. + * @param scanResults is a list of ScanResults to pass to the native side. + * @param nativeObject is a pointer to the corresponding + * AndroidWifiDataProvider C++ instance. + */ + private static native void onUpdateAvailable( + List<ScanResult> scanResults, long nativeObject); +} diff --git a/core/java/android/webkit/gears/DesktopAndroid.java b/core/java/android/webkit/gears/DesktopAndroid.java index 00a9a47..ee8ca49 100644 --- a/core/java/android/webkit/gears/DesktopAndroid.java +++ b/core/java/android/webkit/gears/DesktopAndroid.java @@ -40,8 +40,6 @@ import android.webkit.WebView; public class DesktopAndroid { private static final String TAG = "Gears-J-Desktop"; - private static final String BROWSER = "com.android.browser"; - private static final String BROWSER_ACTIVITY = BROWSER + ".BrowserActivity"; private static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate"; private static final String ACTION_INSTALL_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT"; @@ -78,11 +76,9 @@ public class DesktopAndroid { String url, String imagePath) { Context context = webview.getContext(); - ComponentName browser = new ComponentName(BROWSER, BROWSER_ACTIVITY); - Intent viewWebPage = new Intent(Intent.ACTION_VIEW); - viewWebPage.setComponent(browser); viewWebPage.setData(Uri.parse(url)); + viewWebPage.addCategory(Intent.CATEGORY_BROWSABLE); Intent intent = new Intent(ACTION_INSTALL_SHORTCUT); intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, viewWebPage); diff --git a/core/java/android/webkit/gears/HttpRequestAndroid.java b/core/java/android/webkit/gears/HttpRequestAndroid.java index 8668c54..30f855f 100644 --- a/core/java/android/webkit/gears/HttpRequestAndroid.java +++ b/core/java/android/webkit/gears/HttpRequestAndroid.java @@ -163,7 +163,20 @@ public final class HttpRequestAndroid { // Setup the connection. This doesn't go to the wire yet - it // doesn't block. try { - connection = (HttpURLConnection) new URL(url).openConnection(); + URL url_object = new URL(url); + // Check that the protocol is indeed HTTP(S). + String protocol = url_object.getProtocol(); + if (protocol == null) { + log("null protocol for URL " + url); + return false; + } + protocol = protocol.toLowerCase(); + if (!"http".equals(protocol) && !"https".equals(protocol)) { + log("Url has wrong protocol: " + url); + return false; + } + + connection = (HttpURLConnection) url_object.openConnection(); connection.setRequestMethod(method); // Manually follow redirects. connection.setInstanceFollowRedirects(false); @@ -197,11 +210,13 @@ public final class HttpRequestAndroid { log("interrupt() called but no child thread"); return; } - if (inBlockingOperation) { - log("Interrupting blocking operation"); - childThread.interrupt(); - } else { - log("Nothing to interrupt"); + synchronized (this) { + if (inBlockingOperation) { + log("Interrupting blocking operation"); + childThread.interrupt(); + } else { + log("Nothing to interrupt"); + } } } @@ -472,7 +487,7 @@ public final class HttpRequestAndroid { String encoding = cacheResult.getEncoding(); // Encoding may not be specified. No default. String contentType = mimeType; - if (encoding != null) { + if (encoding != null && encoding.length() > 0) { contentType += "; charset=" + encoding; } setResponseHeader(KEY_CONTENT_TYPE, contentType); diff --git a/core/java/android/webkit/gears/NativeDialog.java b/core/java/android/webkit/gears/NativeDialog.java new file mode 100644 index 0000000..9e2b375 --- /dev/null +++ b/core/java/android/webkit/gears/NativeDialog.java @@ -0,0 +1,142 @@ +// Copyright 2008 The Android Open Source Project +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package android.webkit.gears; + +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import java.io.File; +import java.lang.InterruptedException; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Utility class to call a modal native dialog on Android + * The dialog itself is an Activity defined in the Browser. + * @hide + */ +public class NativeDialog { + + private static final String TAG = "Gears-J-NativeDialog"; + + private final String DIALOG_PACKAGE = "com.android.browser"; + private final String DIALOG_CLASS = DIALOG_PACKAGE + ".GearsNativeDialog"; + + private static Lock mLock = new ReentrantLock(); + private static Condition mDialogFinished = mLock.newCondition(); + private static String mResults = null; + + private static boolean mAsynchronousDialog; + + /** + * Utility function to build the intent calling the + * dialog activity + */ + private Intent createIntent(String type, String arguments) { + Intent intent = new Intent(); + intent.setClassName(DIALOG_PACKAGE, DIALOG_CLASS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra("dialogArguments", arguments); + intent.putExtra("dialogType", type); + return intent; + } + + /** + * Opens a native dialog synchronously and waits for its completion. + * + * The dialog is an activity (GearsNativeDialog) provided by the Browser + * that we call via startActivity(). Contrary to a normal activity though, + * we need to block until it returns. To do so, we define a static lock + * object in this class, which GearsNativeDialog can unlock once done + */ + public String showDialog(Context context, String file, + String arguments) { + + try { + mAsynchronousDialog = false; + mLock.lock(); + File path = new File(file); + String fileName = path.getName(); + String type = fileName.substring(0, fileName.indexOf(".html")); + Intent intent = createIntent(type, arguments); + + mResults = null; + context.startActivity(intent); + mDialogFinished.await(); + } catch (InterruptedException e) { + Log.e(TAG, "exception e: " + e); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "exception e: " + e); + } finally { + mLock.unlock(); + } + + return mResults; + } + + /** + * Opens a native dialog asynchronously + * + * The dialog is an activity (GearsNativeDialog) provided by the + * Browser. + */ + public void showAsyncDialog(Context context, String type, + String arguments) { + mAsynchronousDialog = true; + Intent intent = createIntent(type, arguments); + context.startActivity(intent); + } + + /** + * Static method that GearsNativeDialog calls to unlock us + */ + public static void signalFinishedDialog() { + if (!mAsynchronousDialog) { + mLock.lock(); + mDialogFinished.signal(); + mLock.unlock(); + } else { + // we call the native callback + closeAsynchronousDialog(mResults); + } + } + + /** + * Static method that GearsNativeDialog calls to set the + * dialog's result + */ + public static void closeDialog(String res) { + mResults = res; + } + + /** + * Native callback method + */ + private native static void closeAsynchronousDialog(String res); +} diff --git a/core/java/android/webkit/gears/PluginSettings.java b/core/java/android/webkit/gears/PluginSettings.java new file mode 100644 index 0000000..2d0cc13 --- /dev/null +++ b/core/java/android/webkit/gears/PluginSettings.java @@ -0,0 +1,79 @@ +// Copyright 2008 The Android Open Source Project +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package android.webkit.gears; + +import android.content.Context; +import android.util.Log; +import android.webkit.Plugin; +import android.webkit.Plugin.PreferencesClickHandler; + +/** + * Simple bridge class intercepting the click in the + * browser plugin list and calling the Gears settings + * dialog. + */ +public class PluginSettings { + + private static final String TAG = "Gears-J-PluginSettings"; + private Context mContext; + + public PluginSettings(Plugin plugin) { + plugin.setClickHandler(new ClickHandler()); + } + + /** + * We do not call the dialog synchronously here as the main + * message loop would be blocked, so we call it via a secondary thread. + */ + private class ClickHandler implements PreferencesClickHandler { + public void handleClickEvent(Context context) { + mContext = context.getApplicationContext(); + Thread startDialog = new Thread(new StartDialog(context)); + startDialog.start(); + } + } + + /** + * Simple wrapper class to call the gears native method in + * a separate thread (the native code will then instanciate a NativeDialog + * object which will start the GearsNativeDialog activity defined in + * the Browser). + */ + private class StartDialog implements Runnable { + Context mContext; + + public StartDialog(Context context) { + mContext = context; + } + + public void run() { + runSettingsDialog(mContext); + } + } + + private static native void runSettingsDialog(Context c); + +} diff --git a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java index 95fc30f..288240e 100644 --- a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java +++ b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java @@ -407,6 +407,8 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler { true); // forceCache if (cacheResult == null) { + // With the no-cache policy we could end up + // with a null result return null; } @@ -444,8 +446,7 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler { // be used for input. cacheResult = CacheManager.getCacheFile(gearsUrl, null); if (cacheResult != null) { - if (logEnabled) - log("Returning surrogate result"); + log("Returning surrogate result"); return cacheResult; } else { // Not an expected condition, but handle gracefully. Perhaps out @@ -476,7 +477,10 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler { } /** - * Convenience debug function. Calls Android logging mechanism. + * Convenience debug function. Calls the Android logging + * mechanism. logEnabled is not a constant, so if the string + * evaluation is potentially expensive, the caller also needs to + * check it. * @param str String to log to the Android console. */ private void log(String str) { |