Bug 1262251 - Make openWindow() launch Fennec if it isn't already running. r=catalinb

This commit is contained in:
Dylan Roeh 2016-10-27 13:58:39 -05:00
Родитель fdb96b726d
Коммит df4c14e4bb
7 изменённых файлов: 124 добавлений и 4 удалений

Просмотреть файл

@ -33,6 +33,10 @@
#include "nsWindowWatcher.h"
#include "nsWeakReference.h"
#ifdef MOZ_WIDGET_ANDROID
#include "AndroidBridge.h"
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::workers;
@ -498,6 +502,12 @@ public:
return NS_OK;
}
#ifdef MOZ_WIDGET_ANDROID
// This fires an intent that will start launching Fennec and foreground it,
// if necessary.
java::GeckoAppShell::OpenWindowForNotification();
#endif
nsCOMPtr<nsPIDOMWindowOuter> window;
nsresult rv = OpenWindow(getter_AddRefs(window));
if (NS_SUCCEEDED(rv)) {
@ -550,6 +560,41 @@ public:
MOZ_ASSERT(NS_SUCCEEDED(rv));
return NS_OK;
}
#ifdef MOZ_WIDGET_ANDROID
else if (rv == NS_ERROR_NOT_AVAILABLE) {
// We couldn't get a browser window, so Fennec must not be running.
// Send an Intent to launch Fennec and wait for "BrowserChrome:Ready"
// to try opening a window again.
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
NS_ENSURE_STATE(os);
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
MOZ_ASSERT(workerPrivate);
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
MOZ_ASSERT(principal);
RefPtr<ServiceWorkerRegistrationInfo> registration =
swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
if (NS_WARN_IF(!registration)) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerInfo> serviceWorkerInfo =
registration->GetServiceWorkerInfoById(workerPrivate->ServiceWorkerID());
if (NS_WARN_IF(!serviceWorkerInfo)) {
return NS_ERROR_FAILURE;
}
os->AddObserver(static_cast<nsIObserver*>(serviceWorkerInfo->WorkerPrivate()),
"BrowserChrome:Ready", true);
serviceWorkerInfo->WorkerPrivate()->AddPendingWindow(this);
return NS_OK;
}
#endif
RefPtr<ResolveOpenWindowRunnable> resolveRunnable =
new ResolveOpenWindowRunnable(mPromiseProxy, nullptr, rv);
@ -627,7 +672,7 @@ private:
// It is possible to be running without a browser window on Mac OS, so
// we need to open a new chrome window.
// TODO(catalinb): open new chrome window. Bug 1218080
return NS_ERROR_FAILURE;
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(browserWindow);
@ -758,7 +803,7 @@ ServiceWorkerClients::OpenWindow(const nsAString& aUrl,
mWorkerScope->GetScope(scope);
RefPtr<OpenWindowRunnable> r = new OpenWindowRunnable(promiseProxy,
aUrl, scope);
aUrl, scope);
MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget()));
return promise.forget();

Просмотреть файл

@ -41,7 +41,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerPrivate)
NS_IMPL_CYCLE_COLLECTION(ServiceWorkerPrivate, mSupportsArray)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerPrivate)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_END
// Tracks the "dom.disable_open_click_delay" preference. Modified on main
@ -2012,4 +2012,36 @@ ServiceWorkerPrivate::CreateEventKeepAliveToken()
return ref.forget();
}
void
ServiceWorkerPrivate::AddPendingWindow(Runnable* aPendingWindow)
{
AssertIsOnMainThread();
pendingWindows.AppendElement(aPendingWindow);
}
nsresult
ServiceWorkerPrivate::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
{
AssertIsOnMainThread();
nsCString topic(aTopic);
if (!topic.Equals(NS_LITERAL_CSTRING("BrowserChrome:Ready"))) {
MOZ_ASSERT(false, "Unexpected topic.");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
NS_ENSURE_STATE(os);
os->RemoveObserver(static_cast<nsIObserver*>(this), "BrowserChrome:Ready");
size_t len = pendingWindows.Length();
for (int i = len-1; i >= 0; i--) {
RefPtr<Runnable> runnable = pendingWindows[i];
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
pendingWindows.RemoveElementAt(i);
}
return NS_OK;
}
END_WORKERS_NAMESPACE

Просмотреть файл

@ -62,13 +62,14 @@ public:
// with an appropriate reason before any runnable is dispatched to the worker.
// If the event is extendable then the runnable should inherit
// ExtendableEventWorkerRunnable.
class ServiceWorkerPrivate final : public nsISupports
class ServiceWorkerPrivate final : public nsIObserver
{
friend class KeepAliveToken;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(ServiceWorkerPrivate)
NS_DECL_NSIOBSERVER
explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo);
@ -149,6 +150,9 @@ public:
bool
IsIdle() const;
void
AddPendingWindow(Runnable* aPendingWindow);
private:
enum WakeUpReason {
FetchEvent = 0,
@ -221,6 +225,8 @@ private:
// Array of function event worker runnables that are pending due to
// the worker activating. Main thread only.
nsTArray<RefPtr<WorkerRunnable>> mPendingFunctionalEvents;
nsTArray<Runnable*> pendingWindows;
};
} // namespace workers

Просмотреть файл

@ -353,6 +353,7 @@ var BrowserApp = {
startup: function startup() {
window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = new nsBrowserAccess();
dump("zerdatime " + Date.now() + " - browser chrome startup finished.");
Services.obs.notifyObservers(this.browser, "BrowserChrome:Ready", null);
this.deck = document.getElementById("browsers");

Просмотреть файл

@ -319,6 +319,15 @@ public class GeckoAppShell
CRASH_HANDLER.uncaughtException(null, e);
}
@WrapForJNI
public static void openWindowForNotification() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
getApplicationContext().startActivity(intent);
}
private static float getLocationAccuracy(Location location) {
float radius = location.getAccuracy();
return (location.hasAccuracy() && radius > 0) ? radius : 1001;

Просмотреть файл

@ -537,6 +537,14 @@ auto GeckoAppShell::OpenUriExternal(mozilla::jni::String::Param a0, mozilla::jni
return mozilla::jni::Method<OpenUriExternal_t>::Call(GeckoAppShell::Context(), nullptr, a0, a1, a2, a3, a4, a5);
}
constexpr char GeckoAppShell::OpenWindowForNotification_t::name[];
constexpr char GeckoAppShell::OpenWindowForNotification_t::signature[];
auto GeckoAppShell::OpenWindowForNotification() -> void
{
return mozilla::jni::Method<OpenWindowForNotification_t>::Call(GeckoAppShell::Context(), nullptr);
}
constexpr char GeckoAppShell::PerformHapticFeedback_t::name[];
constexpr char GeckoAppShell::PerformHapticFeedback_t::signature[];

Просмотреть файл

@ -1452,6 +1452,25 @@ public:
static auto OpenUriExternal(mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param) -> bool;
struct OpenWindowForNotification_t {
typedef GeckoAppShell Owner;
typedef void ReturnType;
typedef void SetterType;
typedef mozilla::jni::Args<> Args;
static constexpr char name[] = "openWindowForNotification";
static constexpr char signature[] =
"()V";
static const bool isStatic = true;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::CURRENT;
};
static auto OpenWindowForNotification() -> void;
struct PerformHapticFeedback_t {
typedef GeckoAppShell Owner;
typedef void ReturnType;