mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 730192 - allow headset controls to function by passing media keyevents through to Android OS; r=jchen
This commit is contained in:
parent
782f52a633
commit
bd8cdd84ef
@ -98,7 +98,7 @@ final class GeckoEditable extends JNIObject
|
||||
private native void onKeyEvent(int action, int keyCode, int scanCode, int metaState,
|
||||
long time, int unicodeChar, int baseUnicodeChar,
|
||||
int domPrintableKeyValue, int repeatCount, int flags,
|
||||
boolean isSynthesizedImeKey);
|
||||
boolean isSynthesizedImeKey, KeyEvent event);
|
||||
|
||||
private void onKeyEvent(KeyEvent event, int action, int savedMetaState,
|
||||
boolean isSynthesizedImeKey) {
|
||||
@ -123,7 +123,7 @@ final class GeckoEditable extends JNIObject
|
||||
// e.g. for Ctrl+A, Android returns 0 for unicodeChar,
|
||||
// but Gecko expects 'a', so we return that in baseUnicodeChar.
|
||||
event.getUnicodeChar(0), domPrintableKeyValue, event.getRepeatCount(),
|
||||
event.getFlags(), isSynthesizedImeKey);
|
||||
event.getFlags(), isSynthesizedImeKey, event);
|
||||
}
|
||||
|
||||
@WrapForJNI
|
||||
@ -1125,6 +1125,31 @@ final class GeckoEditable extends JNIObject
|
||||
});
|
||||
}
|
||||
|
||||
@WrapForJNI @Override
|
||||
public void onDefaultKeyEvent(final KeyEvent event) {
|
||||
if (DEBUG) {
|
||||
// GeckoEditableListener methods should all be called from the Gecko thread
|
||||
ThreadUtils.assertOnGeckoThread();
|
||||
StringBuilder sb = new StringBuilder("onDefaultKeyEvent(");
|
||||
sb.append("action=").append(event.getAction()).append(", ")
|
||||
.append("keyCode=").append(event.getKeyCode()).append(", ")
|
||||
.append("metaState=").append(event.getMetaState()).append(", ")
|
||||
.append("time=").append(event.getEventTime()).append(", ")
|
||||
.append("repeatCount=").append(event.getRepeatCount()).append(")");
|
||||
Log.d(LOGTAG, sb.toString());
|
||||
}
|
||||
|
||||
geckoPostToIc(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mListener == null) {
|
||||
return;
|
||||
}
|
||||
mListener.onDefaultKeyEvent(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// InvocationHandler interface
|
||||
|
||||
static String getConstantName(Class<?> cls, String prefix, Object value) {
|
||||
|
@ -7,6 +7,8 @@ package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
|
||||
/**
|
||||
* Interface for the Editable to listen on the Gecko thread, as well as for the IC thread to listen
|
||||
* to the Editable.
|
||||
@ -35,4 +37,5 @@ interface GeckoEditableListener {
|
||||
void notifyIMEContext(int state, String typeHint, String modeHint, String actionHint);
|
||||
void onSelectionChange(int start, int end);
|
||||
void onTextChange(CharSequence text, int start, int oldEnd, int newEnd);
|
||||
void onDefaultKeyEvent(KeyEvent event);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import org.mozilla.gecko.util.ThreadUtils.AssertBehavior;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@ -382,6 +383,16 @@ class GeckoInputConnection
|
||||
getComposingSpanEnd(editable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDefaultKeyEvent(final KeyEvent event) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
GeckoInputConnection.this.performDefaultKeyAction(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized Handler getBackgroundHandler() {
|
||||
if (sBackgroundHandler != null) {
|
||||
return sBackgroundHandler;
|
||||
@ -680,6 +691,8 @@ class GeckoInputConnection
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
case KeyEvent.KEYCODE_SEARCH:
|
||||
// ignore HEADSETHOOK to allow hold-for-voice-search to work
|
||||
case KeyEvent.KEYCODE_HEADSETHOOK:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -721,6 +734,37 @@ class GeckoInputConnection
|
||||
return event;
|
||||
}
|
||||
|
||||
// Called by OnDefaultKeyEvent handler, up from Gecko
|
||||
/* package */ void performDefaultKeyAction(KeyEvent event) {
|
||||
switch (event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_MUTE:
|
||||
case KeyEvent.KEYCODE_HEADSETHOOK:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
||||
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_STOP:
|
||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
|
||||
case KeyEvent.KEYCODE_MEDIA_REWIND:
|
||||
case KeyEvent.KEYCODE_MEDIA_RECORD:
|
||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
|
||||
case KeyEvent.KEYCODE_MEDIA_CLOSE:
|
||||
case KeyEvent.KEYCODE_MEDIA_EJECT:
|
||||
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
|
||||
// Forward media keypresses to the registered handler so headset controls work
|
||||
// Does the same thing as Chromium
|
||||
// https://chromium.googlesource.com/chromium/src/+/49.0.2623.67/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java#445
|
||||
// These are all the keys dispatchMediaKeyEvent supports.
|
||||
if (AppConstants.Versions.feature19Plus) {
|
||||
// dispatchMediaKeyEvent is only available on Android 4.4+
|
||||
Context viewContext = getView().getContext();
|
||||
AudioManager am = (AudioManager)viewContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
am.dispatchMediaKeyEvent(event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processKey(final int action, final int keyCode, final KeyEvent event) {
|
||||
|
||||
if (keyCode > KeyEvent.getMaxKeyCode() || !shouldProcessKey(keyCode, event)) {
|
||||
|
@ -768,6 +768,14 @@ auto GeckoEditable::NotifyIMEContext(int32_t a0, mozilla::jni::String::Param a1,
|
||||
return mozilla::jni::Method<NotifyIMEContext_t>::Call(GeckoEditable::mCtx, nullptr, a0, a1, a2, a3);
|
||||
}
|
||||
|
||||
constexpr char GeckoEditable::OnDefaultKeyEvent_t::name[];
|
||||
constexpr char GeckoEditable::OnDefaultKeyEvent_t::signature[];
|
||||
|
||||
auto GeckoEditable::OnDefaultKeyEvent(mozilla::jni::Object::Param a0) const -> void
|
||||
{
|
||||
return mozilla::jni::Method<OnDefaultKeyEvent_t>::Call(GeckoEditable::mCtx, nullptr, a0);
|
||||
}
|
||||
|
||||
constexpr char GeckoEditable::OnImeAcknowledgeFocus_t::name[];
|
||||
constexpr char GeckoEditable::OnImeAcknowledgeFocus_t::signature[];
|
||||
|
||||
|
@ -1597,6 +1597,22 @@ public:
|
||||
|
||||
auto NotifyIMEContext(int32_t, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param) const -> void;
|
||||
|
||||
struct OnDefaultKeyEvent_t {
|
||||
typedef GeckoEditable Owner;
|
||||
typedef void ReturnType;
|
||||
typedef void SetterType;
|
||||
typedef mozilla::jni::Args<
|
||||
mozilla::jni::Object::Param> Args;
|
||||
static constexpr char name[] = "onDefaultKeyEvent";
|
||||
static constexpr char signature[] =
|
||||
"(Landroid/view/KeyEvent;)V";
|
||||
static const bool isStatic = false;
|
||||
static const mozilla::jni::ExceptionMode exceptionMode =
|
||||
mozilla::jni::ExceptionMode::ABORT;
|
||||
};
|
||||
|
||||
auto OnDefaultKeyEvent(mozilla::jni::Object::Param) const -> void;
|
||||
|
||||
struct OnImeAcknowledgeFocus_t {
|
||||
typedef GeckoEditable Owner;
|
||||
typedef void ReturnType;
|
||||
@ -1691,10 +1707,11 @@ public:
|
||||
int32_t,
|
||||
int32_t,
|
||||
int32_t,
|
||||
bool> Args;
|
||||
bool,
|
||||
mozilla::jni::Object::Param> Args;
|
||||
static constexpr char name[] = "onKeyEvent";
|
||||
static constexpr char signature[] =
|
||||
"(IIIIJIIIIIZ)V";
|
||||
"(IIIIJIIIIIZLandroid/view/KeyEvent;)V";
|
||||
static const bool isStatic = false;
|
||||
static const mozilla::jni::ExceptionMode exceptionMode =
|
||||
mozilla::jni::ExceptionMode::ABORT;
|
||||
|
@ -350,7 +350,7 @@ public:
|
||||
int32_t aMetaState, int64_t aTime, int32_t aUnicodeChar,
|
||||
int32_t aBaseUnicodeChar, int32_t aDomPrintableKeyValue,
|
||||
int32_t aRepeatCount, int32_t aFlags,
|
||||
bool aIsSynthesizedImeKey);
|
||||
bool aIsSynthesizedImeKey, jni::Object::Param originalEvent);
|
||||
|
||||
// Synchronize Gecko thread with the InputConnection thread.
|
||||
void OnImeSynchronize();
|
||||
@ -2445,7 +2445,7 @@ nsWindow::GeckoViewSupport::OnKeyEvent(int32_t aAction, int32_t aKeyCode,
|
||||
int32_t aScanCode, int32_t aMetaState, int64_t aTime,
|
||||
int32_t aUnicodeChar, int32_t aBaseUnicodeChar,
|
||||
int32_t aDomPrintableKeyValue, int32_t aRepeatCount, int32_t aFlags,
|
||||
bool aIsSynthesizedImeKey)
|
||||
bool aIsSynthesizedImeKey, jni::Object::Param originalEvent)
|
||||
{
|
||||
RefPtr<nsWindow> kungFuDeathGrip(&window);
|
||||
window.UserActivity();
|
||||
@ -2480,6 +2480,10 @@ nsWindow::GeckoViewSupport::OnKeyEvent(int32_t aAction, int32_t aKeyCode,
|
||||
mozilla::UniquePtr<WidgetEvent>(event.Duplicate()));
|
||||
} else {
|
||||
window.DispatchEvent(&event, status);
|
||||
|
||||
if (status != nsEventStatus_eConsumeNoDefault) {
|
||||
mEditable->OnDefaultKeyEvent(originalEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.Destroyed() ||
|
||||
|
Loading…
Reference in New Issue
Block a user