Bug 1035774 - Support dynamic input device changes for Android. r=jchen

Though we can't write automation tests for this, I have confirmed that the input
device added/removed are properly notified to 'browser.xul'. Unfortunately the
notifications don't reach to conent documents because of bug 1478212, but I've
also confirmed they did reach to content documents with replacing
MediaFeatureValuesChanged with MediaFeatureValuesChangedAllDocuments in
nsPresContext::RefreshSystemMetrics().

Differential Revision: https://phabricator.services.mozilla.com/D3303
This commit is contained in:
Hiroyuki Ikezoe 2018-08-14 16:38:03 +09:00
parent 2b678040eb
commit b2160ed2cf
6 changed files with 176 additions and 10 deletions

View File

@ -32,6 +32,7 @@ import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.util.BitmapUtils;
import org.mozilla.gecko.util.HardwareCodecCapabilityUtils;
import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.InputDeviceUtils;
import org.mozilla.gecko.util.IOUtils;
import org.mozilla.gecko.util.ProxySelector;
import org.mozilla.gecko.util.StrictModeContext;
@ -1879,14 +1880,6 @@ public class GeckoAppShell
return result;
}
private static boolean isPointerTypeDevice(InputDevice inputDevice) {
int sources = inputDevice.getSources();
return (sources & (InputDevice.SOURCE_CLASS_JOYSTICK |
InputDevice.SOURCE_CLASS_POINTER |
InputDevice.SOURCE_CLASS_POSITION |
InputDevice.SOURCE_CLASS_TRACKBALL)) != 0;
}
@WrapForJNI(calledFrom = "gecko")
// For any-pointer and any-hover media queries features.
private static int getAllPointerCapabilities() {
@ -1895,7 +1888,7 @@ public class GeckoAppShell
for (int deviceId : InputDevice.getDeviceIds()) {
InputDevice inputDevice = InputDevice.getDevice(deviceId);
if (inputDevice == null ||
!isPointerTypeDevice(inputDevice)) {
!InputDeviceUtils.isPointerTypeDevice(inputDevice)) {
continue;
}
@ -1913,7 +1906,7 @@ public class GeckoAppShell
for (int deviceId : InputDevice.getDeviceIds()) {
InputDevice inputDevice = InputDevice.getDevice(deviceId);
if (inputDevice == null ||
!isPointerTypeDevice(inputDevice)) {
!InputDeviceUtils.isPointerTypeDevice(inputDevice)) {
continue;
}

View File

@ -0,0 +1,88 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import android.content.Context;
import android.hardware.input.InputManager;
import android.util.Log;
import android.view.InputDevice;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.util.InputDeviceUtils;
import org.mozilla.gecko.util.ThreadUtils;
public class GeckoInputDeviceListener
implements InputManager.InputDeviceListener {
private static final String LOGTAG = "GeckoInputDeviceListener";
private static final GeckoInputDeviceListener listenerInstance = new GeckoInputDeviceListener();
private boolean initialized;
private InputManager mInputManager;
public static GeckoInputDeviceListener getInstance() {
return listenerInstance;
}
private GeckoInputDeviceListener() {
}
public synchronized void initialize(final Context context) {
if (initialized) {
Log.w(LOGTAG, "Already initialized!");
return;
}
mInputManager = (InputManager)
context.getSystemService(Context.INPUT_SERVICE);
mInputManager.registerInputDeviceListener(listenerInstance, ThreadUtils.getUiHandler());
initialized = true;
}
public synchronized void shutdown() {
if (!initialized) {
Log.w(LOGTAG, "Already shut down!");
return;
}
if (mInputManager != null) {
Log.e(LOGTAG, "mInputManager should be valid!");
return;
}
mInputManager.unregisterInputDeviceListener(listenerInstance);
initialized = false;
mInputManager = null;
}
@WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
private static native void onDeviceChanged();
private void notifyDeviceChanged(int deviceId) {
InputDevice device = InputDevice.getDevice(deviceId);
if (device == null ||
!InputDeviceUtils.isPointerTypeDevice(device)) {
return;
}
onDeviceChanged();
}
@Override
public void onInputDeviceAdded(int deviceId) {
notifyDeviceChanged(deviceId);
}
@Override
public void onInputDeviceRemoved(int deviceId) {
// Call onDeviceChanged directly without checking device source types
// since we can no longer get a valid `InputDevice` in the case of
// device removal.
onDeviceChanged();
}
@Override
public void onInputDeviceChanged(int deviceId) {
notifyDeviceChanged(deviceId);
}
}

View File

@ -0,0 +1,18 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.util;
import android.view.InputDevice;
public class InputDeviceUtils {
public static boolean isPointerTypeDevice(InputDevice inputDevice) {
int sources = inputDevice.getSources();
return (sources & (InputDevice.SOURCE_CLASS_JOYSTICK |
InputDevice.SOURCE_CLASS_POINTER |
InputDevice.SOURCE_CLASS_POSITION |
InputDevice.SOURCE_CLASS_TRACKBALL)) != 0;
}
}

View File

@ -23,6 +23,7 @@ import android.util.Log;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoInputDeviceListener;
import org.mozilla.gecko.GeckoScreenOrientation;
import org.mozilla.gecko.GeckoThread;
import org.mozilla.gecko.PrefsHelper;
@ -223,6 +224,8 @@ public final class GeckoRuntime implements Parcelable {
// Initialize the system ClipboardManager by accessing it on the main thread.
GeckoAppShell.getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE);
GeckoInputDeviceListener.getInstance().initialize(context);
return true;
}
@ -278,6 +281,7 @@ public final class GeckoRuntime implements Parcelable {
Log.d(LOGTAG, "shutdown");
}
GeckoInputDeviceListener.getInstance().shutdown();
GeckoThread.forceQuit();
}

View File

@ -0,0 +1,61 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GeckoInputDeviceListener_h
#define GeckoInputDeviceListener_h
#include "GeneratedJNINatives.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
#include "nsIWindowMediator.h"
#include "nsPIDOMWindow.h"
#include "mozilla/Assertions.h"
namespace mozilla {
class GeckoInputDeviceListener final
: public java::GeckoInputDeviceListener::Natives<GeckoInputDeviceListener>
{
GeckoInputDeviceListener() = delete;
public:
static void
OnDeviceChanged()
{
MOZ_ASSERT(NS_IsMainThread());
// Iterate all toplevel windows
nsCOMPtr<nsIWindowMediator> windowMediator =
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
NS_ENSURE_TRUE_VOID(windowMediator);
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
NS_ENSURE_TRUE_VOID(windowEnumerator);
bool more;
while (NS_SUCCEEDED(windowEnumerator->HasMoreElements(&more)) && more) {
nsCOMPtr<nsISupports> elements;
if (NS_FAILED(windowEnumerator->GetNext(getter_AddRefs(elements)))) {
break;
}
if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(elements)) {
if (window->Closed()) {
continue;
}
if (nsIDocument* doc = window->GetExtantDoc()) {
if (nsIPresShell* presShell = doc->GetShell()) {
presShell->ThemeChanged();
}
}
}
}
}
};
} // namespace mozilla
#endif // GeckoInputDeviceListener_h

View File

@ -64,6 +64,7 @@
#include "GeckoNetworkManager.h"
#include "GeckoProcessManager.h"
#include "GeckoScreenOrientation.h"
#include "GeckoInputDeviceListener.h"
#include "GeckoVRManager.h"
#include "PrefsHelper.h"
#include "fennec/MemoryMonitor.h"
@ -427,6 +428,7 @@ nsAppShell::nsAppShell()
GeckoAppShellSupport::Init();
GeckoThreadSupport::Init();
mozilla::GeckoBatteryManager::Init();
mozilla::GeckoInputDeviceListener::Init();
mozilla::GeckoNetworkManager::Init();
mozilla::GeckoProcessManager::Init();
mozilla::GeckoScreenOrientation::Init();