OSDN Git Service

Implement navigator.isApplicationInstalled() API
authorAndrei Popescu <andreip@google.com>
Thu, 11 Feb 2010 15:33:07 +0000 (15:33 +0000)
committerAndrei Popescu <andreip@google.com>
Fri, 12 Feb 2010 18:36:53 +0000 (18:36 +0000)
This CL contains the wiring between the API and the Java side.

Fix b: 2371005

WebCore/Android.mk
WebCore/bindings/js/JSNavigatorCustom.cpp
WebCore/bindings/v8/custom/V8NavigatorCustom.cpp
WebCore/page/Navigator.cpp
WebCore/page/Navigator.h
WebCore/page/Page.cpp
WebCore/platform/android/PackageNotifier.cpp [new file with mode: 0644]
WebCore/platform/android/PackageNotifier.h [new file with mode: 0644]
WebKit/android/jni/JavaBridge.cpp

index de67b20..f153c9c 100644 (file)
@@ -410,6 +410,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
        platform/android/PlatformTouchPointAndroid.cpp \
        platform/android/PopupMenuAndroid.cpp \
        platform/android/RenderThemeAndroid.cpp \
+       platform/android/PackageNotifier.cpp \
        platform/android/ScreenAndroid.cpp \
        platform/android/ScrollViewAndroid.cpp \
        platform/android/SearchPopupMenuAndroid.cpp \
index b30db5a..af0c9ae 100644 (file)
@@ -69,7 +69,8 @@ JSC::JSValue  WebCore::JSNavigator::isApplicationInstalled(JSC::ExecState* exec,
     RefPtr<ApplicationInstalledCallback> callback(JSCustomApplicationInstalledCallback::create(
             object, static_cast<JSDOMGlobalObject*>(exec->dynamicGlobalObject())));
 
-    m_impl->isApplicationInstalled(appName, callback.release());
+    if (!m_impl->isApplicationInstalled(appName, callback.release()))
+        setDOMException(exec, INVALID_STATE_ERR);
     return jsUndefined();
 }
 
index c3c406e..b6ae42d 100644 (file)
@@ -84,7 +84,9 @@ v8::Handle<v8::Value> V8Navigator::isApplicationInstalledCallback(const v8::Argu
     ASSERT(callback);
 
     Navigator* navigator = V8Navigator::toNative(args.Holder());
-    navigator->isApplicationInstalled(toWebCoreString(args[0]), callback.release());
+    if (!navigator->isApplicationInstalled(toWebCoreString(args[0]), callback.release()))
+        return throwError(INVALID_STATE_ERR);
+
     return v8::Undefined();
 }
 
index 3c0424f..bb07911 100644 (file)
@@ -45,6 +45,7 @@
 #if PLATFORM(ANDROID)
 #include "ApplicationInstalledCallback.h"
 #include "Connection.h"
+#include "PackageNotifier.h"
 #endif
 
 namespace WebCore {
@@ -171,10 +172,26 @@ Connection* Navigator::connection() const
 #endif
 
 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
-void Navigator::isApplicationInstalled(const String& name, PassRefPtr<ApplicationInstalledCallback> callback)
+
+bool Navigator::isApplicationInstalled(const String& name, PassRefPtr<ApplicationInstalledCallback> callback)
+{
+    if (m_applicationInstalledCallback)
+        return false;
+
+    m_applicationInstalledCallback = callback;
+    m_applicationNameQuery = name;
+
+    packageNotifier().requestPackageResult();
+
+    return true;
+}
+
+void Navigator::onPackageResult()
 {
-    //TODO(implement);
-    callback->handleEvent(false);
+    if (m_applicationInstalledCallback) {
+        m_applicationInstalledCallback->handleEvent(packageNotifier().isPackageInstalled(m_applicationNameQuery));
+        m_applicationInstalledCallback = 0;
+    }
 }
 #endif
 
index 83ed83f..c6acfd5 100644 (file)
@@ -21,6 +21,7 @@
 #define Navigator_h
 
 #include "NavigatorBase.h"
+#include "PlatformString.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
@@ -32,7 +33,6 @@ namespace WebCore {
     class MimeTypeArray;
     class PluginData;
     class PluginArray;
-    class String;
 #if PLATFORM(ANDROID)
     class ApplicationInstalledCallback;
     class Connection;
@@ -67,7 +67,8 @@ namespace WebCore {
 #endif
 
 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
-        void isApplicationInstalled(const String& name, PassRefPtr<ApplicationInstalledCallback> callback);
+        bool isApplicationInstalled(const String& name, PassRefPtr<ApplicationInstalledCallback> callback);
+        void onPackageResult();
 #endif
 
 #if ENABLE(DOM_STORAGE)
@@ -87,6 +88,11 @@ namespace WebCore {
 #if PLATFORM(ANDROID)
         mutable RefPtr<Connection> m_connection;
 #endif
+
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+        RefPtr<ApplicationInstalledCallback> m_applicationInstalledCallback;
+        String m_applicationNameQuery;
+#endif
     };
 
 }
index 1704bfb..b685e59 100644 (file)
 #include "GeolocationController.h"
 #endif
 
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+#include "PackageNotifier.h"
+#endif
+
 namespace WebCore {
 
 static HashSet<Page*>* allPages;
@@ -105,6 +109,17 @@ static void networkStateChanged()
         frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false));
 }
 
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+static void onPackageResultAvailable()
+{
+    HashSet<Page*>::iterator end = allPages->end();
+    for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
+        for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
+            frame->domWindow()->navigator()->onPackageResult();
+    }
+}
+#endif
+
 Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, EditorClient* editorClient, DragClient* dragClient, InspectorClient* inspectorClient, PluginHalterClient* pluginHalterClient, GeolocationControllerClient* geolocationControllerClient)
     : m_chrome(new Chrome(this, chromeClient))
     , m_dragCaretController(new SelectionController(0, true))
@@ -163,6 +178,9 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi
         allPages = new HashSet<Page*>;
         
         networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+        packageNotifier().setOnResultAvailable(onPackageResultAvailable);
+#endif
     }
 
     ASSERT(!allPages->contains(this));
diff --git a/WebCore/platform/android/PackageNotifier.cpp b/WebCore/platform/android/PackageNotifier.cpp
new file mode 100644 (file)
index 0000000..e057cdf
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2010, 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:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+#include "config.h"
+#include "PackageNotifier.h"
+
+#if ENABLE(APPLICATION_INSTALLED)
+
+#include <wtf/Assertions.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+PackageNotifier::PackageNotifier()
+        : m_onResultAvailable(0), m_isInitialized(false), m_timer(this, &PackageNotifier::timerFired)  { }
+
+void PackageNotifier::setOnResultAvailable(Callback callback)
+{
+    m_onResultAvailable = callback;
+}
+
+void PackageNotifier::addPackageNames(const HashSet<String>& packageNames)
+{
+    if (!m_isInitialized)
+        m_isInitialized = true;
+
+    typedef HashSet<String>::const_iterator NamesIterator;
+    for (NamesIterator iter = packageNames.begin(); iter != packageNames.end(); ++iter)
+        m_packageNames.add(*iter);
+
+    if (m_onResultAvailable)
+        m_onResultAvailable();
+}
+
+void PackageNotifier::addPackageName(const String& packageName)
+{
+    ASSERT(m_isInitialized);
+    m_packageNames.add(packageName);
+}
+
+void PackageNotifier::removePackageName(const String& packageName)
+{
+    ASSERT(m_isInitialized);
+    m_packageNames.remove(packageName);
+}
+
+void PackageNotifier::requestPackageResult()
+{
+    if (!m_isInitialized || m_timer.isActive())
+        return;
+
+    m_timer.startOneShot(0);
+}
+
+void PackageNotifier::timerFired(Timer<PackageNotifier>*)
+{
+    m_timer.stop();
+    if (m_onResultAvailable)
+        m_onResultAvailable();
+}
+
+bool PackageNotifier::isPackageInstalled(const String& packageName)
+{
+    return m_packageNames.contains(packageName);
+}
+
+PackageNotifier& packageNotifier()
+{
+    AtomicallyInitializedStatic(PackageNotifier*, packageNotifier = new PackageNotifier);
+    return *packageNotifier;
+}
+
+}
+
+#endif // ENABLE(APPLICATION_INSTALLED)
diff --git a/WebCore/platform/android/PackageNotifier.h b/WebCore/platform/android/PackageNotifier.h
new file mode 100644 (file)
index 0000000..ad44bc7
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2010, 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:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef PackageNotifier_h
+#define PackageNotifier_h
+
+#if ENABLE(APPLICATION_INSTALLED)
+
+#include "PlatformString.h"
+#include "StringHash.h"
+#include "Timer.h"
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class PackageNotifier : public Noncopyable {
+public:
+    PackageNotifier();
+
+    typedef void (*Callback)();
+    void setOnResultAvailable(Callback);
+
+    void addPackageNames(const HashSet<String>& packageNames);
+    void addPackageName(const String& packageName);
+    void removePackageName(const String& packageName);
+
+    void requestPackageResult();
+    bool isPackageInstalled(const String& packageName);
+
+private:
+    void timerFired(Timer<PackageNotifier>*);
+
+    Callback m_onResultAvailable;
+
+    HashSet<String> m_packageNames;
+    bool m_isInitialized;
+    Timer<PackageNotifier> m_timer;
+};
+
+PackageNotifier& packageNotifier();
+
+}
+
+#endif
+
+#endif // PackageNotifier_h
\ No newline at end of file
index feca297..0e65e1c 100644 (file)
@@ -35,6 +35,7 @@
 #include "KeyGeneratorClient.h"
 #include "KURL.h"
 #include "NetworkStateNotifier.h"
+#include "PackageNotifier.h"
 #include "Page.h"
 #include "PluginClient.h"
 #include "PluginDatabase.h"
@@ -102,6 +103,10 @@ public:
     static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer);
     static void ServiceFuncPtrQueue(JNIEnv*);
     static void UpdatePluginDirectories(JNIEnv* env, jobject obj, jobjectArray array, jboolean reload);
+    static void AddPackageNames(JNIEnv* env, jobject obj, jobject packageNames);
+    static void AddPackageName(JNIEnv* env, jobject obj, jstring packageName);
+    static void RemovePackageName(JNIEnv* env, jobject obj, jstring packageName);
+
 
 private:
     jweak       mJavaObject;
@@ -392,6 +397,46 @@ void JavaBridge::UpdatePluginDirectories(JNIEnv* env, jobject obj,
     WebCore::Page::refreshPlugins(reload);
 }
 
+void JavaBridge::AddPackageNames(JNIEnv* env, jobject obj, jobject packageNames)
+{
+    if (!packageNames)
+        return;
+
+    // dalvikvm will raise exception if any of these fail
+    jclass setClass = env->FindClass("java/util/Set");
+    jmethodID iterator = env->GetMethodID(setClass, "iterator",
+            "()Ljava/util/Iterator;");
+    jobject iter = env->CallObjectMethod(packageNames, iterator);
+
+    jclass iteratorClass = env->FindClass("java/util/Iterator");
+    jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
+    jmethodID next = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
+
+    HashSet<WebCore::String> namesSet;
+    while (env->CallBooleanMethod(iter, hasNext)) {
+        jstring name = static_cast<jstring>(env->CallObjectMethod(iter, next));
+        namesSet.add(to_string(env, name));
+        env->DeleteLocalRef(name);
+    }
+
+    packageNotifier().addPackageNames(namesSet);
+
+    env->DeleteLocalRef(iteratorClass);
+    env->DeleteLocalRef(iter);
+    env->DeleteLocalRef(setClass);
+}
+
+void JavaBridge::AddPackageName(JNIEnv* env, jobject obj, jstring packageName)
+{
+    packageNotifier().addPackageName(to_string(env, packageName));
+}
+
+void JavaBridge::RemovePackageName(JNIEnv* env, jobject obj, jstring packageName)
+{
+    packageNotifier().removePackageName(to_string(env, packageName));
+}
+
+
 // ----------------------------------------------------------------------------
 
 /*
@@ -414,7 +459,13 @@ static JNINativeMethod gWebCoreJavaBridgeMethods[] = {
     { "nativeServiceFuncPtrQueue", "()V",
         (void*) JavaBridge::ServiceFuncPtrQueue },
     { "nativeUpdatePluginDirectories", "([Ljava/lang/String;Z)V",
-        (void*) JavaBridge::UpdatePluginDirectories }
+        (void*) JavaBridge::UpdatePluginDirectories },
+    { "addPackageNames", "(Ljava/util/Set;)V",
+        (void*) JavaBridge::AddPackageNames },
+    { "addPackageName", "(Ljava/lang/String;)V",
+        (void*) JavaBridge::AddPackageName },
+    { "removePackageName", "(Ljava/lang/String;)V",
+        (void*) JavaBridge::RemovePackageName }
 };
 
 int register_javabridge(JNIEnv* env)