mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
TextInputTarget: Improve IME support on Android
This commit is contained in:
parent
5ed4b19e4d
commit
da38c1ed2a
22 changed files with 1796 additions and 928 deletions
|
|
@ -327,7 +327,7 @@ static const uint8 javaMidiByteCode[] =
|
|||
STATICMETHOD (getAndroidMidiDeviceManager, "getAndroidMidiDeviceManager", "(Landroid/content/Context;)Lcom/rmsl/juce/JuceMidiSupport$MidiDeviceManager;") \
|
||||
STATICMETHOD (getAndroidBluetoothManager, "getAndroidBluetoothManager", "(Landroid/content/Context;)Lcom/rmsl/juce/JuceMidiSupport$BluetoothManager;")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceMidiSupport, "com/rmsl/juce/JuceMidiSupport", 23, javaMidiByteCode, sizeof (javaMidiByteCode))
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceMidiSupport, "com/rmsl/juce/JuceMidiSupport", 23, javaMidiByteCode)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
|
|
|
|||
|
|
@ -113,4 +113,19 @@ Object withMember (Object copy, Member OtherObject::* member, Other&& value)
|
|||
template <typename Fn> struct ScopeGuard : Fn { ~ScopeGuard() { Fn::operator()(); } };
|
||||
template <typename Fn> ScopeGuard (Fn) -> ScopeGuard<Fn>;
|
||||
|
||||
#ifndef DOXYGEN
|
||||
namespace detail
|
||||
{
|
||||
template <typename Functor, typename Return, typename... Args>
|
||||
static constexpr auto toFnPtr (Functor functor, Return (Functor::*) (Args...) const)
|
||||
{
|
||||
return static_cast<Return (*) (Args...)> (functor);
|
||||
}
|
||||
} // namespace detail
|
||||
#endif
|
||||
|
||||
/** Converts a captureless lambda to its equivalent function pointer type. */
|
||||
template <typename Functor>
|
||||
static constexpr auto toFnPtr (Functor functor) { return detail::toFnPtr (functor, &Functor::operator()); }
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ static const uint8 invocationHandleByteCode[] =
|
|||
CALLBACK (juce_invokeImplementer, "dispatchInvoke", "(JLjava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;") \
|
||||
CALLBACK (juce_dispatchDelete, "dispatchFinalize", "(J)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceInvocationHandler, "com/rmsl/juce/JuceInvocationHandler", 10, invocationHandleByteCode, sizeof (invocationHandleByteCode))
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceInvocationHandler, "com/rmsl/juce/JuceInvocationHandler", 10, invocationHandleByteCode)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
|
|
@ -116,7 +116,7 @@ struct SystemJavaClassComparator
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
JNIClassBase::JNIClassBase (const char* cp, int classMinSDK, const void* bc, size_t n)
|
||||
JNIClassBase::JNIClassBase (const char* cp, int classMinSDK, const uint8* bc, size_t n)
|
||||
: classPath (cp), byteCode (bc), byteCodeSize (n), minSDK (classMinSDK), classRef (nullptr)
|
||||
{
|
||||
SystemJavaClassComparator comparator;
|
||||
|
|
@ -552,12 +552,12 @@ static const uint8 javaFragmentOverlay[] =
|
|||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (construct, "<init>", "()V") \
|
||||
METHOD (close, "close", "()V") \
|
||||
CALLBACK (FragmentOverlay::onActivityResultNative, "onActivityResultNative", "(JIILandroid/content/Intent;)V") \
|
||||
CALLBACK (FragmentOverlay::onCreateNative, "onCreateNative", "(JLandroid/os/Bundle;)V") \
|
||||
CALLBACK (FragmentOverlay::onStartNative, "onStartNative", "(J)V") \
|
||||
CALLBACK (FragmentOverlay::onRequestPermissionsResultNative, "onRequestPermissionsResultNative", "(JI[Ljava/lang/String;[I)V")
|
||||
CALLBACK (generatedCallback<&FragmentOverlay::onActivityResultCallback>, "onActivityResultNative", "(JIILandroid/content/Intent;)V") \
|
||||
CALLBACK (generatedCallback<&FragmentOverlay::onCreatedCallback>, "onCreateNative", "(JLandroid/os/Bundle;)V") \
|
||||
CALLBACK (generatedCallback<&FragmentOverlay::onStartCallback>, "onStartNative", "(J)V") \
|
||||
CALLBACK (generatedCallback<&FragmentOverlay::onRequestPermissionsResultCallback>, "onRequestPermissionsResultNative", "(JI[Ljava/lang/String;[I)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceFragmentOverlay, "com/rmsl/juce/FragmentOverlay", 16, javaFragmentOverlay, sizeof(javaFragmentOverlay))
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceFragmentOverlay, "com/rmsl/juce/FragmentOverlay", 16, javaFragmentOverlay)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
|
|
@ -590,47 +590,39 @@ void FragmentOverlay::open()
|
|||
env->CallVoidMethod (native.get(), AndroidDialogFragment.show, fm.get(), javaString ("FragmentOverlay").get());
|
||||
}
|
||||
|
||||
void FragmentOverlay::onActivityResultNative (JNIEnv* env, jobject, jlong host,
|
||||
jint requestCode, jint resultCode, jobject data)
|
||||
void FragmentOverlay::onCreatedCallback (JNIEnv* env, FragmentOverlay& t, jobject obj)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<FragmentOverlay*> (host))
|
||||
myself->onActivityResult (requestCode, resultCode, LocalRef<jobject> (env->NewLocalRef (data)));
|
||||
t.onCreated (LocalRef<jobject> { env->NewLocalRef (obj) });
|
||||
}
|
||||
|
||||
void FragmentOverlay::onCreateNative (JNIEnv* env, jobject, jlong host, jobject bundle)
|
||||
void FragmentOverlay::onStartCallback (JNIEnv*, FragmentOverlay& t)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<FragmentOverlay*> (host))
|
||||
myself->onCreated (LocalRef<jobject> (env->NewLocalRef (bundle)));
|
||||
t.onStart();
|
||||
}
|
||||
|
||||
void FragmentOverlay::onStartNative (JNIEnv*, jobject, jlong host)
|
||||
void FragmentOverlay::onRequestPermissionsResultCallback (JNIEnv* env, FragmentOverlay& t, jint requestCode, jobjectArray jPermissions, jintArray jGrantResults)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<FragmentOverlay*> (host))
|
||||
myself->onStart();
|
||||
}
|
||||
Array<int> grantResults;
|
||||
int n = (jGrantResults != nullptr ? env->GetArrayLength (jGrantResults) : 0);
|
||||
|
||||
void FragmentOverlay::onRequestPermissionsResultNative (JNIEnv* env, jobject, jlong host, jint requestCode,
|
||||
jobjectArray jPermissions, jintArray jGrantResults)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<FragmentOverlay*> (host))
|
||||
if (n > 0)
|
||||
{
|
||||
Array<int> grantResults;
|
||||
int n = (jGrantResults != nullptr ? env->GetArrayLength (jGrantResults) : 0);
|
||||
auto* data = env->GetIntArrayElements (jGrantResults, nullptr);
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
auto* data = env->GetIntArrayElements (jGrantResults, nullptr);
|
||||
for (int i = 0; i < n; ++i)
|
||||
grantResults.add (data[i]);
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
grantResults.add (data[i]);
|
||||
|
||||
env->ReleaseIntArrayElements (jGrantResults, data, 0);
|
||||
}
|
||||
|
||||
myself->onRequestPermissionsResult (requestCode,
|
||||
javaStringArrayToJuce (LocalRef<jobjectArray> (jPermissions)),
|
||||
grantResults);
|
||||
env->ReleaseIntArrayElements (jGrantResults, data, 0);
|
||||
}
|
||||
|
||||
t.onRequestPermissionsResult (requestCode,
|
||||
javaStringArrayToJuce (LocalRef<jobjectArray> (jPermissions)),
|
||||
grantResults);
|
||||
}
|
||||
|
||||
void FragmentOverlay::onActivityResultCallback (JNIEnv* env, FragmentOverlay& t, jint requestCode, jint resultCode, jobject data)
|
||||
{
|
||||
t.onActivityResult (requestCode, resultCode, LocalRef<jobject> (env->NewLocalRef (data)));
|
||||
}
|
||||
|
||||
jobject FragmentOverlay::getNativeHandle()
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ struct SystemJavaClassComparator;
|
|||
class JNIClassBase
|
||||
{
|
||||
public:
|
||||
JNIClassBase (const char* classPath, int minSDK, const void* byteCode, size_t byteCodeSize);
|
||||
JNIClassBase (const char* classPath, int minSDK, const uint8* byteCode, size_t byteCodeSize);
|
||||
virtual ~JNIClassBase();
|
||||
|
||||
operator jclass() const noexcept { return classRef; }
|
||||
|
|
@ -210,6 +210,9 @@ private:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
template <typename T, size_t N> constexpr auto numBytes (const T (&) [N]) { return N; }
|
||||
constexpr auto numBytes (std::nullptr_t) { return static_cast<size_t> (0); }
|
||||
|
||||
#define CREATE_JNI_METHOD(methodID, stringName, params) methodID = resolveMethod (env, stringName, params);
|
||||
#define CREATE_JNI_STATICMETHOD(methodID, stringName, params) methodID = resolveStaticMethod (env, stringName, params);
|
||||
#define CREATE_JNI_FIELD(fieldID, stringName, signature) fieldID = resolveField (env, stringName, signature);
|
||||
|
|
@ -219,26 +222,26 @@ private:
|
|||
#define DECLARE_JNI_FIELD(fieldID, stringName, signature) jfieldID fieldID;
|
||||
#define DECLARE_JNI_CALLBACK(fieldID, stringName, signature)
|
||||
|
||||
#define DECLARE_JNI_CLASS_WITH_BYTECODE(CppClassName, javaPath, minSDK, byteCodeData, byteCodeSize) \
|
||||
class CppClassName ## _Class : public JNIClassBase \
|
||||
{ \
|
||||
public: \
|
||||
CppClassName ## _Class() : JNIClassBase (javaPath, minSDK, byteCodeData, byteCodeSize) {} \
|
||||
\
|
||||
void initialiseFields (JNIEnv* env) \
|
||||
{ \
|
||||
Array<JNINativeMethod> callbacks; \
|
||||
JNI_CLASS_MEMBERS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD, CREATE_JNI_CALLBACK); \
|
||||
resolveCallbacks (env, callbacks); \
|
||||
} \
|
||||
\
|
||||
JNI_CLASS_MEMBERS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD, DECLARE_JNI_CALLBACK) \
|
||||
}; \
|
||||
static CppClassName ## _Class CppClassName;
|
||||
#define DECLARE_JNI_CLASS_WITH_BYTECODE(CppClassName, javaPath, minSDK, byteCodeData) \
|
||||
class CppClassName ## _Class : public JNIClassBase \
|
||||
{ \
|
||||
public: \
|
||||
CppClassName ## _Class() : JNIClassBase (javaPath, minSDK, byteCodeData, numBytes (byteCodeData)) {} \
|
||||
\
|
||||
void initialiseFields (JNIEnv* env) \
|
||||
{ \
|
||||
Array<JNINativeMethod> callbacks; \
|
||||
JNI_CLASS_MEMBERS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD, CREATE_JNI_CALLBACK); \
|
||||
resolveCallbacks (env, callbacks); \
|
||||
} \
|
||||
\
|
||||
JNI_CLASS_MEMBERS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD, DECLARE_JNI_CALLBACK) \
|
||||
}; \
|
||||
static inline const CppClassName ## _Class CppClassName;
|
||||
|
||||
//==============================================================================
|
||||
#define DECLARE_JNI_CLASS_WITH_MIN_SDK(CppClassName, javaPath, minSDK) \
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (CppClassName, javaPath, minSDK, nullptr, 0)
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (CppClassName, javaPath, minSDK, nullptr)
|
||||
|
||||
//==============================================================================
|
||||
#define DECLARE_JNI_CLASS(CppClassName, javaPath) \
|
||||
|
|
@ -1005,20 +1008,20 @@ public:
|
|||
const Array<int>& /*grantResults*/) {}
|
||||
virtual void onActivityResult (int /*requestCode*/, int /*resultCode*/, LocalRef<jobject> /*data*/) {}
|
||||
|
||||
/** @internal */
|
||||
static void onCreatedCallback (JNIEnv*, FragmentOverlay&, jobject obj);
|
||||
/** @internal */
|
||||
static void onStartCallback (JNIEnv*, FragmentOverlay&);
|
||||
/** @internal */
|
||||
static void onRequestPermissionsResultCallback (JNIEnv*, FragmentOverlay&, jint requestCode, jobjectArray jPermissions, jintArray jGrantResults);
|
||||
/** @internal */
|
||||
static void onActivityResultCallback (JNIEnv*, FragmentOverlay&, jint requestCode, jint resultCode, jobject data);
|
||||
|
||||
protected:
|
||||
jobject getNativeHandle();
|
||||
|
||||
private:
|
||||
|
||||
GlobalRef native;
|
||||
|
||||
public:
|
||||
/* internal: do not use */
|
||||
static void onActivityResultNative (JNIEnv*, jobject, jlong, jint, jint, jobject);
|
||||
static void onCreateNative (JNIEnv*, jobject, jlong, jobject);
|
||||
static void onStartNative (JNIEnv*, jobject, jlong);
|
||||
static void onRequestPermissionsResultNative (JNIEnv*, jobject, jlong, jint,
|
||||
jobjectArray, jintArray);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -1030,4 +1033,30 @@ void startAndroidActivityForResult (const LocalRef<jobject>& intent, int request
|
|||
bool androidHasSystemFeature (const String& property);
|
||||
String audioManagerGetProperty (const String& property);
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <auto Fn, typename Result, typename Class, typename... Args>
|
||||
inline constexpr auto generatedCallbackImpl =
|
||||
juce::toFnPtr (JNICALL [] (JNIEnv* env, jobject, jlong host, Args... args) -> Result
|
||||
{
|
||||
if (auto* object = reinterpret_cast<Class*> (host))
|
||||
return Fn (env, *object, args...);
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
template <auto Fn, typename Result, typename Class, typename... Args>
|
||||
constexpr auto generateCallbackImpl (Result (*) (JNIEnv*, Class&, Args...)) { return generatedCallbackImpl<Fn, Result, Class, Args...>; }
|
||||
|
||||
template <auto Fn, typename Result, typename Class, typename... Args>
|
||||
constexpr auto generateCallbackImpl (Result (*) (JNIEnv*, const Class&, Args...)) { return generatedCallbackImpl<Fn, Result, Class, Args...>; }
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Evaluates to a static function that forwards to the provided Fn, assuming that the
|
||||
// 'host' argument points to an object on which it is valid to call Fn
|
||||
template <auto Fn>
|
||||
inline constexpr auto generatedCallback = detail::generateCallbackImpl<Fn> (Fn);
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer")
|
|||
METHOD (isExhausted, "isExhausted", "()Z") \
|
||||
METHOD (setPosition, "setPosition", "(J)Z") \
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (HTTPStream, "com/rmsl/juce/JuceHTTPStream", 16, javaJuceHttpStream, sizeof(javaJuceHttpStream))
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (HTTPStream, "com/rmsl/juce/JuceHTTPStream", 16, javaJuceHttpStream)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -342,15 +342,6 @@ namespace detail
|
|||
{
|
||||
return joinCompileTimeStr (v, makeCompileTimeStr (others...));
|
||||
}
|
||||
|
||||
template <typename Functor, typename Return, typename... Args>
|
||||
static constexpr auto toFnPtr (Functor functor, Return (Functor::*) (Args...) const)
|
||||
{
|
||||
return static_cast<Return (*) (Args...)> (functor);
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
static constexpr auto toFnPtr (Functor functor) { return toFnPtr (functor, &Functor::operator()); }
|
||||
} // namespace detail
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -396,7 +387,7 @@ struct ObjCClass
|
|||
}
|
||||
|
||||
template <typename Fn>
|
||||
void addMethod (SEL selector, Fn callbackFn) { addMethod (selector, detail::toFnPtr (callbackFn)); }
|
||||
void addMethod (SEL selector, Fn callbackFn) { addMethod (selector, toFnPtr (callbackFn)); }
|
||||
|
||||
template <typename Result, typename... Args>
|
||||
void addMethod (SEL selector, Result (*callbackFn) (id, SEL, Args...))
|
||||
|
|
|
|||
|
|
@ -336,6 +336,28 @@ namespace juce
|
|||
#include "native/juce_linux_FileChooser.cpp"
|
||||
|
||||
#elif JUCE_ANDROID
|
||||
|
||||
namespace juce
|
||||
{
|
||||
static jobject makeAndroidRect (Rectangle<int> r)
|
||||
{
|
||||
return getEnv()->NewObject (AndroidRect,
|
||||
AndroidRect.constructor,
|
||||
r.getX(),
|
||||
r.getY(),
|
||||
r.getRight(),
|
||||
r.getBottom());
|
||||
}
|
||||
|
||||
static jobject makeAndroidPoint (Point<int> p)
|
||||
{
|
||||
return getEnv()->NewObject (AndroidPoint,
|
||||
AndroidPoint.create,
|
||||
p.getX(),
|
||||
p.getY());
|
||||
}
|
||||
} // namespace juce
|
||||
|
||||
#include "juce_core/files/juce_common_MimeTypes.h"
|
||||
#include "native/accessibility/juce_android_Accessibility.cpp"
|
||||
#include "native/juce_android_Windowing.cpp"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An abstract base class which can be implemented by components that function as
|
||||
text editors.
|
||||
|
|
|
|||
|
|
@ -297,21 +297,13 @@ public:
|
|||
{
|
||||
const auto scale = Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale;
|
||||
|
||||
const auto screenBounds = accessibilityHandler.getComponent().getScreenBounds() * scale;
|
||||
LocalRef<jobject> screenBounds (makeAndroidRect (accessibilityHandler.getComponent().getScreenBounds() * scale));
|
||||
|
||||
LocalRef<jobject> rect (env->NewObject (AndroidRect, AndroidRect.constructor,
|
||||
screenBounds.getX(), screenBounds.getY(),
|
||||
screenBounds.getRight(), screenBounds.getBottom()));
|
||||
env->CallVoidMethod (info, AndroidAccessibilityNodeInfo.setBoundsInScreen, screenBounds.get());
|
||||
|
||||
env->CallVoidMethod (info, AndroidAccessibilityNodeInfo.setBoundsInScreen, rect.get());
|
||||
LocalRef<jobject> boundsInParent (makeAndroidRect (accessibilityHandler.getComponent().getBoundsInParent() * scale));
|
||||
|
||||
const auto boundsInParent = accessibilityHandler.getComponent().getBoundsInParent() * scale;
|
||||
|
||||
rect = LocalRef<jobject> (env->NewObject (AndroidRect, AndroidRect.constructor,
|
||||
boundsInParent.getX(), boundsInParent.getY(),
|
||||
boundsInParent.getRight(), boundsInParent.getBottom()));
|
||||
|
||||
env->CallVoidMethod (info, AndroidAccessibilityNodeInfo.setBoundsInParent, rect.get());
|
||||
env->CallVoidMethod (info, AndroidAccessibilityNodeInfo.setBoundsInParent, boundsInParent.get());
|
||||
}
|
||||
|
||||
const auto state = accessibilityHandler.getCurrentState();
|
||||
|
|
|
|||
|
|
@ -32,9 +32,19 @@ import android.graphics.Canvas;
|
|||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.text.Selection;
|
||||
import android.text.SpanWatcher;
|
||||
import android.text.Spannable;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Pair;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.view.Choreographer;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
|
@ -51,6 +61,7 @@ import android.view.inputmethod.InputMethodManager;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class ComponentPeerView extends ViewGroup
|
||||
|
|
@ -63,9 +74,10 @@ public final class ComponentPeerView extends ViewGroup
|
|||
if (Application.class.isInstance (context))
|
||||
{
|
||||
((Application) context).registerActivityLifecycleCallbacks (this);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
((Application) context.getApplicationContext ()).registerActivityLifecycleCallbacks (this);
|
||||
((Application) context.getApplicationContext()).registerActivityLifecycleCallbacks (this);
|
||||
}
|
||||
|
||||
this.host = host;
|
||||
|
|
@ -77,7 +89,7 @@ public final class ComponentPeerView extends ViewGroup
|
|||
setOnFocusChangeListener (this);
|
||||
|
||||
// swap red and blue colours to match internal opengl texture format
|
||||
ColorMatrix colorMatrix = new ColorMatrix ();
|
||||
ColorMatrix colorMatrix = new ColorMatrix();
|
||||
|
||||
float[] colorTransform = {0, 0, 1.0f, 0, 0,
|
||||
0, 1.0f, 0, 0, 0,
|
||||
|
|
@ -91,10 +103,12 @@ public final class ComponentPeerView extends ViewGroup
|
|||
|
||||
try
|
||||
{
|
||||
method = getClass ().getMethod ("setLayerType", int.class, Paint.class);
|
||||
} catch (SecurityException e)
|
||||
method = getClass().getMethod ("setLayerType", int.class, Paint.class);
|
||||
}
|
||||
catch (SecurityException e)
|
||||
{
|
||||
} catch (NoSuchMethodException e)
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -104,11 +118,14 @@ public final class ComponentPeerView extends ViewGroup
|
|||
{
|
||||
int layerTypeNone = 0;
|
||||
method.invoke (this, layerTypeNone, null);
|
||||
} catch (java.lang.IllegalArgumentException e)
|
||||
}
|
||||
catch (java.lang.IllegalArgumentException e)
|
||||
{
|
||||
} catch (java.lang.IllegalAccessException e)
|
||||
}
|
||||
catch (java.lang.IllegalAccessException e)
|
||||
{
|
||||
} catch (java.lang.reflect.InvocationTargetException e)
|
||||
}
|
||||
catch (java.lang.reflect.InvocationTargetException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -116,7 +133,7 @@ public final class ComponentPeerView extends ViewGroup
|
|||
Choreographer.getInstance().postFrameCallback (this);
|
||||
}
|
||||
|
||||
public void clear ()
|
||||
public void clear()
|
||||
{
|
||||
host = 0;
|
||||
}
|
||||
|
|
@ -147,14 +164,14 @@ public final class ComponentPeerView extends ViewGroup
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque ()
|
||||
public boolean isOpaque()
|
||||
{
|
||||
return opaque;
|
||||
}
|
||||
|
||||
private final boolean opaque;
|
||||
private long host;
|
||||
private final Paint paint = new Paint ();
|
||||
private final Paint paint = new Paint();
|
||||
|
||||
//==============================================================================
|
||||
private native void handleMouseDown (long host, int index, float x, float y, long time);
|
||||
|
|
@ -168,25 +185,25 @@ public final class ComponentPeerView extends ViewGroup
|
|||
if (host == 0)
|
||||
return false;
|
||||
|
||||
int action = event.getAction ();
|
||||
long time = event.getEventTime ();
|
||||
int action = event.getAction();
|
||||
long time = event.getEventTime();
|
||||
|
||||
switch (action & MotionEvent.ACTION_MASK)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
handleMouseDown (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
|
||||
handleMouseDown (host, event.getPointerId (0), event.getRawX(), event.getRawY(), time);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
handleMouseUp (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
|
||||
handleMouseUp (host, event.getPointerId (0), event.getRawX(), event.getRawY(), time);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
{
|
||||
handleMouseDrag (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
|
||||
handleMouseDrag (host, event.getPointerId (0), event.getRawX(), event.getRawY(), time);
|
||||
|
||||
int n = event.getPointerCount ();
|
||||
int n = event.getPointerCount();
|
||||
|
||||
if (n > 1)
|
||||
{
|
||||
|
|
@ -206,8 +223,9 @@ public final class ComponentPeerView extends ViewGroup
|
|||
|
||||
if (i == 0)
|
||||
{
|
||||
handleMouseUp (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
|
||||
} else
|
||||
handleMouseUp (host, event.getPointerId (0), event.getRawX(), event.getRawY(), time);
|
||||
}
|
||||
else
|
||||
{
|
||||
int point[] = new int[2];
|
||||
getLocationOnScreen (point);
|
||||
|
|
@ -223,8 +241,9 @@ public final class ComponentPeerView extends ViewGroup
|
|||
|
||||
if (i == 0)
|
||||
{
|
||||
handleMouseDown (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
|
||||
} else
|
||||
handleMouseDown (host, event.getPointerId (0), event.getRawX(), event.getRawY(), time);
|
||||
}
|
||||
else
|
||||
{
|
||||
int point[] = new int[2];
|
||||
getLocationOnScreen (point);
|
||||
|
|
@ -253,32 +272,132 @@ public final class ComponentPeerView extends ViewGroup
|
|||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public static class TextInputTarget
|
||||
{
|
||||
public TextInputTarget (long owner) { host = owner; }
|
||||
|
||||
public boolean isTextInputActive() { return ComponentPeerView.textInputTargetIsTextInputActive (host); }
|
||||
public int getHighlightedRegionBegin() { return ComponentPeerView.textInputTargetGetHighlightedRegionBegin (host); }
|
||||
public int getHighlightedRegionEnd() { return ComponentPeerView.textInputTargetGetHighlightedRegionEnd (host); }
|
||||
public void setHighlightedRegion (int b, int e) { ComponentPeerView.textInputTargetSetHighlightedRegion (host, b, e); }
|
||||
public String getTextInRange (int b, int e) { return ComponentPeerView.textInputTargetGetTextInRange (host, b, e); }
|
||||
public void insertTextAtCaret (String text) { ComponentPeerView.textInputTargetInsertTextAtCaret (host, text); }
|
||||
public int getCaretPosition() { return ComponentPeerView.textInputTargetGetCaretPosition (host); }
|
||||
public int getTotalNumChars() { return ComponentPeerView.textInputTargetGetTotalNumChars (host); }
|
||||
public int getCharIndexForPoint (Point point) { return ComponentPeerView.textInputTargetGetCharIndexForPoint (host, point); }
|
||||
public int getKeyboardType() { return ComponentPeerView.textInputTargetGetKeyboardType (host); }
|
||||
public void setTemporaryUnderlining (List<Pair<Integer, Integer>> list) { ComponentPeerView.textInputTargetSetTemporaryUnderlining (host, list); }
|
||||
|
||||
//==============================================================================
|
||||
private final long host;
|
||||
}
|
||||
|
||||
private native static boolean textInputTargetIsTextInputActive (long host);
|
||||
private native static int textInputTargetGetHighlightedRegionBegin (long host);
|
||||
private native static int textInputTargetGetHighlightedRegionEnd (long host);
|
||||
private native static void textInputTargetSetHighlightedRegion (long host, int begin, int end);
|
||||
private native static String textInputTargetGetTextInRange (long host, int begin, int end);
|
||||
private native static void textInputTargetInsertTextAtCaret (long host, String text);
|
||||
private native static int textInputTargetGetCaretPosition (long host);
|
||||
private native static int textInputTargetGetTotalNumChars (long host);
|
||||
private native static int textInputTargetGetCharIndexForPoint (long host, Point point);
|
||||
private native static int textInputTargetGetKeyboardType (long host);
|
||||
private native static void textInputTargetSetTemporaryUnderlining (long host, List<Pair<Integer, Integer>> list);
|
||||
|
||||
private native long getFocusedTextInputTargetPointer (long host);
|
||||
|
||||
private TextInputTarget getFocusedTextInputTarget (long host)
|
||||
{
|
||||
final long ptr = getFocusedTextInputTargetPointer (host);
|
||||
return ptr != 0 ? new TextInputTarget (ptr) : null;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private native void handleKeyDown (long host, int keycode, int textchar, int kbFlags);
|
||||
private native void handleKeyUp (long host, int keycode, int textchar);
|
||||
private native void handleBackButton (long host);
|
||||
private native void handleKeyboardHidden (long host);
|
||||
|
||||
public void showKeyboard (String type)
|
||||
private static int getInputTypeForJuceVirtualKeyboardType (int type)
|
||||
{
|
||||
InputMethodManager imm = (InputMethodManager) getContext ().getSystemService (Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
if (imm != null)
|
||||
switch (type)
|
||||
{
|
||||
if (type.length () > 0)
|
||||
{
|
||||
imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
|
||||
imm.setInputMethod (getWindowToken (), type);
|
||||
keyboardDismissListener.startListening ();
|
||||
} else
|
||||
{
|
||||
imm.hideSoftInputFromWindow (getWindowToken (), 0);
|
||||
keyboardDismissListener.stopListening ();
|
||||
}
|
||||
case 0: // textKeyboard
|
||||
return InputType.TYPE_CLASS_TEXT
|
||||
| InputType.TYPE_TEXT_VARIATION_NORMAL
|
||||
| InputType.TYPE_TEXT_FLAG_MULTI_LINE
|
||||
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
|
||||
case 1: // numericKeyboard
|
||||
return InputType.TYPE_CLASS_NUMBER
|
||||
| InputType.TYPE_NUMBER_VARIATION_NORMAL;
|
||||
case 2: // decimalKeyboard
|
||||
return InputType.TYPE_CLASS_NUMBER
|
||||
| InputType.TYPE_NUMBER_VARIATION_NORMAL
|
||||
| InputType.TYPE_NUMBER_FLAG_DECIMAL;
|
||||
case 3: // urlKeyboard
|
||||
return InputType.TYPE_CLASS_TEXT
|
||||
| InputType.TYPE_TEXT_VARIATION_URI
|
||||
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
|
||||
case 4: // emailAddressKeyboard
|
||||
return InputType.TYPE_CLASS_TEXT
|
||||
| InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
||||
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
|
||||
case 5: // phoneNumberKeyboard
|
||||
return InputType.TYPE_CLASS_PHONE;
|
||||
case 6: // passwordKeyboard
|
||||
return InputType.TYPE_CLASS_TEXT
|
||||
| InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void backButtonPressed ()
|
||||
InputMethodManager getInputMethodManager()
|
||||
{
|
||||
return (InputMethodManager) getContext().getSystemService (Context.INPUT_METHOD_SERVICE);
|
||||
}
|
||||
|
||||
public void closeInputMethodContext()
|
||||
{
|
||||
InputMethodManager imm = getInputMethodManager();
|
||||
|
||||
if (imm == null)
|
||||
return;
|
||||
|
||||
if (cachedConnection != null)
|
||||
cachedConnection.closeConnection();
|
||||
|
||||
imm.restartInput (this);
|
||||
}
|
||||
|
||||
public void showKeyboard (int virtualKeyboardType, int selectionStart, int selectionEnd)
|
||||
{
|
||||
InputMethodManager imm = getInputMethodManager();
|
||||
|
||||
if (imm == null)
|
||||
return;
|
||||
|
||||
// restartingInput causes a call back to onCreateInputConnection, where we'll pick
|
||||
// up the correct keyboard characteristics to use for the focused TextInputTarget.
|
||||
imm.restartInput (this);
|
||||
imm.showSoftInput (this, 0);
|
||||
keyboardDismissListener.startListening();
|
||||
}
|
||||
|
||||
public void hideKeyboard()
|
||||
{
|
||||
InputMethodManager imm = getInputMethodManager();
|
||||
|
||||
if (imm == null)
|
||||
return;
|
||||
|
||||
imm.hideSoftInputFromWindow (getWindowToken(), 0);
|
||||
keyboardDismissListener.stopListening();
|
||||
}
|
||||
|
||||
public void backButtonPressed()
|
||||
{
|
||||
if (host == 0)
|
||||
return;
|
||||
|
|
@ -292,6 +411,11 @@ public final class ComponentPeerView extends ViewGroup
|
|||
if (host == 0)
|
||||
return false;
|
||||
|
||||
// The key event may move the cursor, or in some cases it might enter characters (e.g.
|
||||
// digits). In this case, we need to reset the IME so that it's aware of the new contents
|
||||
// of the TextInputTarget.
|
||||
closeInputMethodContext();
|
||||
|
||||
switch (keyCode)
|
||||
{
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
|
|
@ -299,7 +423,7 @@ public final class ComponentPeerView extends ViewGroup
|
|||
return super.onKeyDown (keyCode, event);
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
{
|
||||
backButtonPressed ();
|
||||
backButtonPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -309,8 +433,9 @@ public final class ComponentPeerView extends ViewGroup
|
|||
|
||||
handleKeyDown (host,
|
||||
keyCode,
|
||||
event.getUnicodeChar (),
|
||||
event.getMetaState ());
|
||||
event.getUnicodeChar(),
|
||||
event.getMetaState());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -320,7 +445,7 @@ public final class ComponentPeerView extends ViewGroup
|
|||
if (host == 0)
|
||||
return false;
|
||||
|
||||
handleKeyUp (host, keyCode, event.getUnicodeChar ());
|
||||
handleKeyUp (host, keyCode, event.getUnicodeChar());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -330,17 +455,17 @@ public final class ComponentPeerView extends ViewGroup
|
|||
if (host == 0)
|
||||
return false;
|
||||
|
||||
if (keyCode != KeyEvent.KEYCODE_UNKNOWN || event.getAction () != KeyEvent.ACTION_MULTIPLE)
|
||||
if (keyCode != KeyEvent.KEYCODE_UNKNOWN || (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && event.getAction() != KeyEvent.ACTION_MULTIPLE))
|
||||
return super.onKeyMultiple (keyCode, count, event);
|
||||
|
||||
if (event.getCharacters () != null)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && event.getCharacters() != null)
|
||||
{
|
||||
int utf8Char = event.getCharacters ().codePointAt (0);
|
||||
int utf8Char = event.getCharacters().codePointAt (0);
|
||||
|
||||
handleKeyDown (host,
|
||||
keyCode,
|
||||
utf8Char,
|
||||
event.getMetaState ());
|
||||
event.getMetaState());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -355,39 +480,40 @@ public final class ComponentPeerView extends ViewGroup
|
|||
view = viewToUse;
|
||||
}
|
||||
|
||||
private void startListening ()
|
||||
private void startListening()
|
||||
{
|
||||
view.getViewTreeObserver ().addOnGlobalLayoutListener (viewTreeObserver);
|
||||
view.getViewTreeObserver().addOnGlobalLayoutListener (viewTreeObserver);
|
||||
}
|
||||
|
||||
private void stopListening ()
|
||||
private void stopListening()
|
||||
{
|
||||
view.getViewTreeObserver ().removeGlobalOnLayoutListener (viewTreeObserver);
|
||||
view.getViewTreeObserver().removeOnGlobalLayoutListener (viewTreeObserver);
|
||||
}
|
||||
|
||||
private class TreeObserver implements ViewTreeObserver.OnGlobalLayoutListener
|
||||
{
|
||||
TreeObserver ()
|
||||
TreeObserver()
|
||||
{
|
||||
keyboardShown = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGlobalLayout ()
|
||||
public void onGlobalLayout()
|
||||
{
|
||||
Rect r = new Rect ();
|
||||
Rect r = new Rect();
|
||||
|
||||
View parentView = getRootView ();
|
||||
View parentView = getRootView();
|
||||
int diff;
|
||||
|
||||
if (parentView == null)
|
||||
{
|
||||
getWindowVisibleDisplayFrame (r);
|
||||
diff = getHeight () - (r.bottom - r.top);
|
||||
} else
|
||||
diff = getHeight() - (r.bottom - r.top);
|
||||
}
|
||||
else
|
||||
{
|
||||
parentView.getWindowVisibleDisplayFrame (r);
|
||||
diff = parentView.getHeight () - (r.bottom - r.top);
|
||||
diff = parentView.getHeight() - (r.bottom - r.top);
|
||||
}
|
||||
|
||||
// Arbitrary threshold, surely keyboard would take more than 20 pix.
|
||||
|
|
@ -397,7 +523,7 @@ public final class ComponentPeerView extends ViewGroup
|
|||
handleKeyboardHidden (view.host);
|
||||
}
|
||||
|
||||
if (!keyboardShown && diff > 20)
|
||||
if (! keyboardShown && diff > 20)
|
||||
keyboardShown = true;
|
||||
}
|
||||
|
||||
|
|
@ -405,26 +531,219 @@ public final class ComponentPeerView extends ViewGroup
|
|||
}
|
||||
|
||||
private final ComponentPeerView view;
|
||||
private final TreeObserver viewTreeObserver = new TreeObserver ();
|
||||
private final TreeObserver viewTreeObserver = new TreeObserver();
|
||||
}
|
||||
|
||||
private final KeyboardDismissListener keyboardDismissListener = new KeyboardDismissListener (this);
|
||||
|
||||
// this is here to make keyboard entry work on a Galaxy Tab2 10.1
|
||||
//==============================================================================
|
||||
// This implementation is quite similar to the ChangeListener in Android's built-in TextView.
|
||||
private static final class ChangeWatcher implements SpanWatcher, TextWatcher
|
||||
{
|
||||
public ChangeWatcher (ComponentPeerView viewIn, Editable editableIn, TextInputTarget targetIn)
|
||||
{
|
||||
view = viewIn;
|
||||
editable = editableIn;
|
||||
target = targetIn;
|
||||
|
||||
updateEditableSelectionFromTarget (editable, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpanAdded (Spannable text, Object what, int start, int end)
|
||||
{
|
||||
updateTargetRangesFromEditable (editable, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpanRemoved (Spannable text, Object what, int start, int end)
|
||||
{
|
||||
updateTargetRangesFromEditable (editable, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpanChanged (Spannable text, Object what, int ostart, int oend, int nstart, int nend)
|
||||
{
|
||||
updateTargetRangesFromEditable (editable, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged (Editable s)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged (CharSequence s, int start, int count, int after)
|
||||
{
|
||||
contentsBeforeChange = s.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged (CharSequence s, int start, int before, int count)
|
||||
{
|
||||
if (editable != s || contentsBeforeChange == null)
|
||||
return;
|
||||
|
||||
final String newText = s.subSequence (start, start + count).toString();
|
||||
|
||||
int code = 0;
|
||||
|
||||
if (newText.endsWith ("\n") || newText.endsWith ("\r"))
|
||||
code = KeyEvent.KEYCODE_ENTER;
|
||||
|
||||
if (newText.endsWith ("\t"))
|
||||
code = KeyEvent.KEYCODE_TAB;
|
||||
|
||||
target.setHighlightedRegion (contentsBeforeChange.codePointCount (0, start),
|
||||
contentsBeforeChange.codePointCount (0, start + before));
|
||||
target.insertTextAtCaret (code != 0 ? newText.substring (0, newText.length() - 1)
|
||||
: newText);
|
||||
|
||||
// Treating return/tab as individual keypresses rather than part of the composition
|
||||
// sequence allows TextEditor onReturn and onTab to work as expected.
|
||||
if (code != 0)
|
||||
view.onKeyDown (code, new KeyEvent (KeyEvent.ACTION_DOWN, code));
|
||||
|
||||
updateTargetRangesFromEditable (editable, target);
|
||||
contentsBeforeChange = null;
|
||||
}
|
||||
|
||||
private static void updateEditableSelectionFromTarget (Editable editable, TextInputTarget text)
|
||||
{
|
||||
final int start = text.getHighlightedRegionBegin();
|
||||
final int end = text.getHighlightedRegionEnd();
|
||||
|
||||
if (start < 0 || end < 0)
|
||||
return;
|
||||
|
||||
final String string = editable.toString();
|
||||
Selection.setSelection (editable,
|
||||
string.offsetByCodePoints (0, start),
|
||||
string.offsetByCodePoints (0, end));
|
||||
}
|
||||
|
||||
private static void updateTargetSelectionFromEditable (Editable editable, TextInputTarget target)
|
||||
{
|
||||
final int start = Selection.getSelectionStart (editable);
|
||||
final int end = Selection.getSelectionEnd (editable);
|
||||
|
||||
if (start < 0 || end < 0)
|
||||
return;
|
||||
|
||||
final String string = editable.toString();
|
||||
target.setHighlightedRegion (string.codePointCount (0, start),
|
||||
string.codePointCount (0, end));
|
||||
}
|
||||
|
||||
private static List<Pair<Integer, Integer>> getUnderlinedRanges (Editable editable)
|
||||
{
|
||||
final int start = BaseInputConnection.getComposingSpanStart (editable);
|
||||
final int end = BaseInputConnection.getComposingSpanEnd (editable);
|
||||
|
||||
if (start < 0 || end < 0)
|
||||
return null;
|
||||
|
||||
final String string = editable.toString();
|
||||
|
||||
final ArrayList<Pair<Integer, Integer>> pairs = new ArrayList<>();
|
||||
pairs.add (new Pair<> (string.codePointCount (0, start), string.codePointCount (0, end)));
|
||||
return pairs;
|
||||
}
|
||||
|
||||
private static void updateTargetCompositionRangesFromEditable (Editable editable, TextInputTarget target)
|
||||
{
|
||||
target.setTemporaryUnderlining (getUnderlinedRanges (editable));
|
||||
}
|
||||
|
||||
private static void updateTargetRangesFromEditable (Editable editable, TextInputTarget target)
|
||||
{
|
||||
updateTargetSelectionFromEditable (editable, target);
|
||||
updateTargetCompositionRangesFromEditable (editable, target);
|
||||
}
|
||||
|
||||
private final ComponentPeerView view;
|
||||
private final TextInputTarget target;
|
||||
private final Editable editable;
|
||||
private String contentsBeforeChange;
|
||||
}
|
||||
|
||||
private static final class Connection extends BaseInputConnection
|
||||
{
|
||||
Connection (ComponentPeerView viewIn, boolean fullEditor, TextInputTarget targetIn)
|
||||
{
|
||||
super (viewIn, fullEditor);
|
||||
view = viewIn;
|
||||
target = targetIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editable getEditable()
|
||||
{
|
||||
if (cached != null)
|
||||
return cached;
|
||||
|
||||
if (target == null)
|
||||
return cached = super.getEditable();
|
||||
|
||||
int length = target.getTotalNumChars();
|
||||
String initialText = target.getTextInRange (0, length);
|
||||
cached = new SpannableStringBuilder (initialText);
|
||||
// Span the entire range of text, so that we pick up changes at any location.
|
||||
// Use cached.length rather than target.getTotalNumChars here, because this
|
||||
// range is in UTF-16 code units, rather than code points.
|
||||
changeWatcher = new ChangeWatcher (view, cached, target);
|
||||
cached.setSpan (changeWatcher, 0, cached.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
return cached;
|
||||
}
|
||||
|
||||
/** Call this to stop listening for selection/composition updates.
|
||||
|
||||
We do this before closing the current input method context (e.g. when the user
|
||||
taps on a text view to move the cursor), because otherwise the input system
|
||||
might send another round of notifications *during* the restartInput call, after we've
|
||||
requested that the input session should end.
|
||||
*/
|
||||
@Override
|
||||
public void closeConnection()
|
||||
{
|
||||
if (cached != null && changeWatcher != null)
|
||||
cached.removeSpan (changeWatcher);
|
||||
|
||||
cached = null;
|
||||
target = null;
|
||||
|
||||
super.closeConnection();
|
||||
}
|
||||
|
||||
private ComponentPeerView view;
|
||||
private TextInputTarget target;
|
||||
private Editable cached;
|
||||
private ChangeWatcher changeWatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection (EditorInfo outAttrs)
|
||||
{
|
||||
TextInputTarget focused = getFocusedTextInputTarget (host);
|
||||
|
||||
outAttrs.actionLabel = "";
|
||||
outAttrs.hintText = "";
|
||||
outAttrs.initialCapsMode = 0;
|
||||
outAttrs.initialSelEnd = outAttrs.initialSelStart = -1;
|
||||
outAttrs.initialSelStart = focused != null ? focused.getHighlightedRegionBegin() : -1;
|
||||
outAttrs.initialSelEnd = focused != null ? focused.getHighlightedRegionEnd() : -1;
|
||||
outAttrs.label = "";
|
||||
outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI;
|
||||
outAttrs.inputType = InputType.TYPE_NULL;
|
||||
outAttrs.imeOptions = EditorInfo.IME_ACTION_UNSPECIFIED
|
||||
| EditorInfo.IME_FLAG_NO_EXTRACT_UI
|
||||
| EditorInfo.IME_FLAG_NO_ENTER_ACTION;
|
||||
outAttrs.inputType = focused != null ? getInputTypeForJuceVirtualKeyboardType (focused.getKeyboardType())
|
||||
: 0;
|
||||
|
||||
return new BaseInputConnection (this, false);
|
||||
cachedConnection = new Connection (this, true, focused);
|
||||
return cachedConnection;
|
||||
}
|
||||
|
||||
private Connection cachedConnection;
|
||||
|
||||
//==============================================================================
|
||||
@Override
|
||||
protected void onSizeChanged (int w, int h, int oldw, int oldh)
|
||||
|
|
@ -463,11 +782,13 @@ public final class ComponentPeerView extends ViewGroup
|
|||
Method systemUIVisibilityMethod = null;
|
||||
try
|
||||
{
|
||||
systemUIVisibilityMethod = this.getClass ().getMethod ("setSystemUiVisibility", int.class);
|
||||
} catch (SecurityException e)
|
||||
systemUIVisibilityMethod = this.getClass().getMethod ("setSystemUiVisibility", int.class);
|
||||
}
|
||||
catch (SecurityException e)
|
||||
{
|
||||
return;
|
||||
} catch (NoSuchMethodException e)
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -476,18 +797,21 @@ public final class ComponentPeerView extends ViewGroup
|
|||
try
|
||||
{
|
||||
systemUIVisibilityMethod.invoke (this, visibility);
|
||||
} catch (java.lang.IllegalArgumentException e)
|
||||
}
|
||||
catch (java.lang.IllegalArgumentException e)
|
||||
{
|
||||
} catch (java.lang.IllegalAccessException e)
|
||||
}
|
||||
catch (java.lang.IllegalAccessException e)
|
||||
{
|
||||
} catch (java.lang.reflect.InvocationTargetException e)
|
||||
}
|
||||
catch (java.lang.reflect.InvocationTargetException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isVisible ()
|
||||
public boolean isVisible()
|
||||
{
|
||||
return getVisibility () == VISIBLE;
|
||||
return getVisibility() == VISIBLE;
|
||||
}
|
||||
|
||||
public void setVisible (boolean b)
|
||||
|
|
@ -572,11 +896,22 @@ public final class ComponentPeerView extends ViewGroup
|
|||
if (host == 0)
|
||||
return null;
|
||||
|
||||
final AccessibilityNodeInfo nodeInfo = AccessibilityNodeInfo.obtain (view, virtualViewId);
|
||||
final AccessibilityNodeInfo nodeInfo;
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R)
|
||||
{
|
||||
nodeInfo = new AccessibilityNodeInfo (view, virtualViewId);
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeInfo = AccessibilityNodeInfo.obtain (view, virtualViewId);
|
||||
}
|
||||
|
||||
if (! populateAccessibilityNodeInfo (host, virtualViewId, nodeInfo))
|
||||
{
|
||||
nodeInfo.recycle();
|
||||
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R)
|
||||
nodeInfo.recycle();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -617,10 +952,10 @@ public final class ComponentPeerView extends ViewGroup
|
|||
}
|
||||
|
||||
private final JuceAccessibilityNodeProvider nodeProvider = new JuceAccessibilityNodeProvider (this);
|
||||
private final AccessibilityManager accessibilityManager = (AccessibilityManager) getContext ().getSystemService (Context.ACCESSIBILITY_SERVICE);
|
||||
private final AccessibilityManager accessibilityManager = (AccessibilityManager) getContext().getSystemService (Context.ACCESSIBILITY_SERVICE);
|
||||
|
||||
@Override
|
||||
public AccessibilityNodeProvider getAccessibilityNodeProvider ()
|
||||
public AccessibilityNodeProvider getAccessibilityNodeProvider()
|
||||
{
|
||||
return nodeProvider;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ public final class JuceContentProviderFileObserver extends FileObserver
|
|||
public JuceContentProviderFileObserver (long hostToUse, String path, int mask)
|
||||
{
|
||||
super (path, mask);
|
||||
|
||||
host = hostToUse;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ public:
|
|||
class Owner
|
||||
{
|
||||
public:
|
||||
virtual ~Owner() {}
|
||||
virtual ~Owner() = default;
|
||||
|
||||
virtual void cursorClosed (const AndroidContentSharerCursor&) = 0;
|
||||
};
|
||||
|
|
@ -121,9 +121,9 @@ public:
|
|||
|
||||
jobject getNativeCursor() { return cursor.get(); }
|
||||
|
||||
void cursorClosed()
|
||||
static void cursorClosed (JNIEnv*, AndroidContentSharerCursor& t)
|
||||
{
|
||||
MessageManager::callAsync ([this] { owner.cursorClosed (*this); });
|
||||
MessageManager::callAsync ([&t] { t.owner.cursorClosed (t); });
|
||||
}
|
||||
|
||||
void addRow (LocalRef<jobjectArray>& values)
|
||||
|
|
@ -141,20 +141,12 @@ private:
|
|||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (addRow, "addRow", "([Ljava/lang/Object;)V") \
|
||||
METHOD (constructor, "<init>", "(J[Ljava/lang/String;)V") \
|
||||
CALLBACK (contentSharerCursorClosed, "contentSharerCursorClosed", "(J)V") \
|
||||
CALLBACK (generatedCallback<&AndroidContentSharerCursor::cursorClosed>, "contentSharerCursorClosed", "(J)V") \
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceContentProviderCursor, "com/rmsl/juce/JuceContentProviderCursor", 16, javaJuceContentProviderCursor, sizeof (javaJuceContentProviderCursor))
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceContentProviderCursor, "com/rmsl/juce/JuceContentProviderCursor", 16, javaJuceContentProviderCursor)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
static void JNICALL contentSharerCursorClosed (JNIEnv*, jobject, jlong host)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<AndroidContentSharerCursor*> (host))
|
||||
myself->cursorClosed();
|
||||
}
|
||||
};
|
||||
|
||||
AndroidContentSharerCursor::JuceContentProviderCursor_Class AndroidContentSharerCursor::JuceContentProviderCursor;
|
||||
|
||||
//==============================================================================
|
||||
class AndroidContentSharerFileObserver
|
||||
{
|
||||
|
|
@ -228,20 +220,17 @@ private:
|
|||
METHOD (constructor, "<init>", "(JLjava/lang/String;I)V") \
|
||||
METHOD (startWatching, "startWatching", "()V") \
|
||||
METHOD (stopWatching, "stopWatching", "()V") \
|
||||
CALLBACK (contentSharerFileObserverEvent, "contentSharerFileObserverEvent", "(JILjava/lang/String;)V") \
|
||||
CALLBACK (generatedCallback<&AndroidContentSharerFileObserver::onFileEventCallback>, "contentSharerFileObserverEvent", "(JILjava/lang/String;)V") \
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceContentProviderFileObserver, "com/rmsl/juce/JuceContentProviderFileObserver", 16, javaJuceContentProviderFileObserver, sizeof (javaJuceContentProviderFileObserver))
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceContentProviderFileObserver, "com/rmsl/juce/JuceContentProviderFileObserver", 16, javaJuceContentProviderFileObserver)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
static void JNICALL contentSharerFileObserverEvent (JNIEnv*, jobject /*fileObserver*/, jlong host, int event, jstring path)
|
||||
static void onFileEventCallback (JNIEnv*, AndroidContentSharerFileObserver& t, jint event, jstring path)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<AndroidContentSharerFileObserver*> (host))
|
||||
myself->onFileEvent (event, LocalRef<jstring> (path));
|
||||
t.onFileEvent (event, LocalRef<jstring> (path));
|
||||
}
|
||||
};
|
||||
|
||||
AndroidContentSharerFileObserver::JuceContentProviderFileObserver_Class AndroidContentSharerFileObserver::JuceContentProviderFileObserver;
|
||||
|
||||
//==============================================================================
|
||||
class AndroidContentSharerPrepareFilesThread : private Thread
|
||||
{
|
||||
|
|
@ -891,6 +880,4 @@ ContentSharer::Pimpl* ContentSharer::createPimpl()
|
|||
return new ContentSharerNativeImpl (*this);
|
||||
}
|
||||
|
||||
ContentSharer::ContentSharerNativeImpl::JuceSharingContentProvider_Class ContentSharer::ContentSharerNativeImpl::JuceSharingContentProvider;
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -948,6 +948,11 @@ TextEditor::TextEditor (const String& name, juce_wchar passwordChar)
|
|||
|
||||
TextEditor::~TextEditor()
|
||||
{
|
||||
giveAwayKeyboardFocus();
|
||||
|
||||
if (auto* peer = getPeer())
|
||||
peer->refreshTextInputTarget();
|
||||
|
||||
textValue.removeListener (textHolder);
|
||||
textValue.referTo (Value());
|
||||
|
||||
|
|
@ -1240,7 +1245,7 @@ void TextEditor::setText (const String& newText, bool sendTextChangeMessage)
|
|||
textValue = newText;
|
||||
|
||||
auto oldCursorPos = caretPosition;
|
||||
bool cursorWasAtEnd = oldCursorPos >= getTotalNumChars();
|
||||
auto cursorWasAtEnd = oldCursorPos >= getTotalNumChars();
|
||||
|
||||
clearInternal (nullptr);
|
||||
insert (newText, 0, currentFont, findColour (textColourId), nullptr, caretPosition);
|
||||
|
|
@ -1376,26 +1381,23 @@ void TextEditor::repaintText (Range<int> range)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void TextEditor::moveCaret (int newCaretPos)
|
||||
void TextEditor::moveCaret (const int newCaretPos)
|
||||
{
|
||||
if (newCaretPos < 0)
|
||||
newCaretPos = 0;
|
||||
else
|
||||
newCaretPos = jmin (newCaretPos, getTotalNumChars());
|
||||
const auto clamped = std::clamp (newCaretPos, 0, getTotalNumChars());
|
||||
|
||||
if (newCaretPos != getCaretPosition())
|
||||
{
|
||||
caretPosition = newCaretPos;
|
||||
if (clamped == getCaretPosition())
|
||||
return;
|
||||
|
||||
if (hasKeyboardFocus (false))
|
||||
textHolder->restartTimer();
|
||||
caretPosition = clamped;
|
||||
|
||||
scrollToMakeSureCursorIsVisible();
|
||||
updateCaretPosition();
|
||||
if (hasKeyboardFocus (false))
|
||||
textHolder->restartTimer();
|
||||
|
||||
if (auto* handler = getAccessibilityHandler())
|
||||
handler->notifyAccessibilityEvent (AccessibilityEvent::textChanged);
|
||||
}
|
||||
scrollToMakeSureCursorIsVisible();
|
||||
updateCaretPosition();
|
||||
|
||||
if (auto* handler = getAccessibilityHandler())
|
||||
handler->notifyAccessibilityEvent (AccessibilityEvent::textChanged);
|
||||
}
|
||||
|
||||
int TextEditor::getCaretPosition() const
|
||||
|
|
|
|||
|
|
@ -182,7 +182,6 @@ bool ComponentPeer::handleKeyPress (const int keyCode, const juce_wchar textChar
|
|||
textCharacter));
|
||||
}
|
||||
|
||||
|
||||
bool ComponentPeer::handleKeyPress (const KeyPress& keyInfo)
|
||||
{
|
||||
bool keyWasUsed = false;
|
||||
|
|
@ -607,7 +606,7 @@ void ComponentPeer::forceDisplayUpdate()
|
|||
Desktop::getInstance().displays->refresh();
|
||||
}
|
||||
|
||||
void ComponentPeer::globalFocusChanged (Component*)
|
||||
void ComponentPeer::globalFocusChanged ([[maybe_unused]] Component* comp)
|
||||
{
|
||||
refreshTextInputTarget();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,6 +476,11 @@ CodeEditorComponent::CodeEditorComponent (CodeDocument& doc, CodeTokeniser* cons
|
|||
|
||||
CodeEditorComponent::~CodeEditorComponent()
|
||||
{
|
||||
giveAwayKeyboardFocus();
|
||||
|
||||
if (auto* peer = getPeer())
|
||||
peer->refreshTextInputTarget();
|
||||
|
||||
document.removeListener (pimpl.get());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1549,8 +1549,6 @@ struct JuceFirebaseInstanceIdService
|
|||
instance->pimpl->notifyListenersTokenRefreshed (juceString (static_cast<jstring> (token)));
|
||||
}
|
||||
};
|
||||
|
||||
JuceFirebaseInstanceIdService::InstanceIdService_Class JuceFirebaseInstanceIdService::InstanceIdService;
|
||||
#endif
|
||||
|
||||
#if defined(JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME)
|
||||
|
|
@ -1592,8 +1590,6 @@ struct JuceFirebaseMessagingService
|
|||
LocalRef<jstring> (static_cast<jstring> (error)));
|
||||
}
|
||||
};
|
||||
|
||||
JuceFirebaseMessagingService::MessagingService_Class JuceFirebaseMessagingService::MessagingService;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace juce
|
|||
//==============================================================================
|
||||
// This byte-code is generated from native/java/com/rmsl/juce/JuceWebView.java with min sdk version 16
|
||||
// See juce_core/native/java/README.txt on how to generate this byte-code.
|
||||
static const unsigned char JuceWebView16ByteCode[] =
|
||||
static const uint8 JuceWebView16ByteCode[] =
|
||||
{31,139,8,8,150,114,161,94,0,3,74,117,99,101,87,101,98,86,105,101,119,49,54,66,121,116,101,67,111,100,101,46,100,101,120,0,125,
|
||||
150,93,108,20,85,20,199,207,124,236,78,119,218,110,183,5,74,191,40,109,69,168,72,89,176,162,165,11,88,40,159,101,81,161,88,226,
|
||||
106,34,211,221,107,59,101,118,102,153,153,109,27,67,16,161,137,134,240,96,4,222,72,140,9,18,35,62,18,195,131,15,4,53,250,226,155,
|
||||
|
|
@ -81,7 +81,7 @@ static const unsigned char JuceWebView16ByteCode[] =
|
|||
//==============================================================================
|
||||
// This byte-code is generated from native/javacore/app/com/rmsl/juce/JuceWebView21.java with min sdk version 21
|
||||
// See juce_core/native/java/README.txt on how to generate this byte-code.
|
||||
static const unsigned char JuceWebView21ByteCode[] =
|
||||
static const uint8 JuceWebView21ByteCode[] =
|
||||
{31,139,8,8,45,103,161,94,0,3,74,117,99,101,87,101,98,86,105,101,119,50,49,46,100,101,120,0,141,151,93,140,27,87,21,199,207,
|
||||
204,216,30,219,99,59,182,55,251,145,143,221,110,210,173,178,105,154,186,155,164,52,169,211,106,241,38,219,221,48,41,52,155,108,
|
||||
138,43,85,154,181,47,235,73,188,51,206,204,120,119,65,162,132,80,148,138,34,148,168,20,181,125,129,135,16,129,4,18,168,125,136,
|
||||
|
|
@ -479,82 +479,62 @@ private:
|
|||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(J)V") \
|
||||
METHOD (hostDeleted, "hostDeleted", "()V") \
|
||||
CALLBACK (webViewReceivedHttpError, "webViewReceivedHttpError", "(JLandroid/webkit/WebView;Landroid/webkit/WebResourceRequest;Landroid/webkit/WebResourceResponse;)V") \
|
||||
CALLBACK (webViewPageLoadStarted, "webViewPageLoadStarted", "(JLandroid/webkit/WebView;Ljava/lang/String;)Z") \
|
||||
CALLBACK (webViewPageLoadFinished, "webViewPageLoadFinished", "(JLandroid/webkit/WebView;Ljava/lang/String;)V") \
|
||||
CALLBACK (webViewReceivedSslError, "webViewReceivedSslError", "(JLandroid/webkit/WebView;Landroid/webkit/SslErrorHandler;Landroid/net/http/SslError;)V") \
|
||||
CALLBACK (generatedCallback<&Pimpl::webViewReceivedHttpError>, "webViewReceivedHttpError", "(JLandroid/webkit/WebView;Landroid/webkit/WebResourceRequest;Landroid/webkit/WebResourceResponse;)V") \
|
||||
CALLBACK (generatedCallback<&Pimpl::webViewPageLoadStarted>, "webViewPageLoadStarted", "(JLandroid/webkit/WebView;Ljava/lang/String;)Z") \
|
||||
CALLBACK (generatedCallback<&Pimpl::webViewPageLoadFinished>, "webViewPageLoadFinished", "(JLandroid/webkit/WebView;Ljava/lang/String;)V") \
|
||||
CALLBACK (generatedCallback<&Pimpl::webViewReceivedSslError>, "webViewReceivedSslError", "(JLandroid/webkit/WebView;Landroid/webkit/SslErrorHandler;Landroid/net/http/SslError;)V") \
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceWebViewClient21, "com/rmsl/juce/JuceWebView21$Client", 21, JuceWebView21ByteCode, sizeof (JuceWebView21ByteCode))
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceWebViewClient21, "com/rmsl/juce/JuceWebView21$Client", 21, JuceWebView21ByteCode)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(J)V") \
|
||||
METHOD (hostDeleted, "hostDeleted", "()V") \
|
||||
CALLBACK (webViewPageLoadStarted, "webViewPageLoadStarted", "(JLandroid/webkit/WebView;Ljava/lang/String;)Z") \
|
||||
CALLBACK (webViewPageLoadFinished, "webViewPageLoadFinished", "(JLandroid/webkit/WebView;Ljava/lang/String;)V") \
|
||||
CALLBACK (webViewReceivedSslError, "webViewReceivedSslError", "(JLandroid/webkit/WebView;Landroid/webkit/SslErrorHandler;Landroid/net/http/SslError;)V") \
|
||||
CALLBACK (generatedCallback<&Pimpl::webViewPageLoadStarted>, "webViewPageLoadStarted", "(JLandroid/webkit/WebView;Ljava/lang/String;)Z") \
|
||||
CALLBACK (generatedCallback<&Pimpl::webViewPageLoadFinished>, "webViewPageLoadFinished", "(JLandroid/webkit/WebView;Ljava/lang/String;)V") \
|
||||
CALLBACK (generatedCallback<&Pimpl::webViewReceivedSslError>, "webViewReceivedSslError", "(JLandroid/webkit/WebView;Landroid/webkit/SslErrorHandler;Landroid/net/http/SslError;)V") \
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceWebViewClient16, "com/rmsl/juce/JuceWebView$Client", 16, JuceWebView16ByteCode, sizeof (JuceWebView16ByteCode))
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceWebViewClient16, "com/rmsl/juce/JuceWebView$Client", 16, JuceWebView16ByteCode)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
static jboolean JNICALL webViewPageLoadStarted (JNIEnv*, jobject /*activity*/, jlong host, jobject /*webView*/, jstring url)
|
||||
static jboolean webViewPageLoadStarted (JNIEnv*, Pimpl& t, jstring url)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<WebBrowserComponent::Pimpl*> (host))
|
||||
return myself->handlePageAboutToLoad (juceString (url));
|
||||
|
||||
return 0;
|
||||
return t.handlePageAboutToLoad (juceString (url));
|
||||
}
|
||||
|
||||
static void JNICALL webViewPageLoadFinished (JNIEnv*, jobject /*activity*/, jlong host, jobject /*webView*/, jstring url)
|
||||
static void webViewPageLoadFinished (JNIEnv*, Pimpl& t, jstring url)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<WebBrowserComponent::Pimpl*> (host))
|
||||
myself->owner.pageFinishedLoading (juceString (url));
|
||||
t.owner.pageFinishedLoading (juceString (url));
|
||||
}
|
||||
|
||||
static void JNICALL webViewReceivedHttpError (JNIEnv*, jobject /*activity*/, jlong host, jobject /*webView*/, jobject /*request*/, jobject errorResponse)
|
||||
static void webViewReceivedSslError (JNIEnv* env, Pimpl& t, jobject sslError)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<WebBrowserComponent::Pimpl*> (host))
|
||||
myself->webReceivedHttpError (errorResponse);
|
||||
}
|
||||
|
||||
static void JNICALL webViewReceivedSslError (JNIEnv*, jobject /*activity*/, jlong host, jobject /*webView*/, jobject /*sslErrorHandler*/, jobject sslError)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
if (auto* myself = reinterpret_cast<WebBrowserComponent::Pimpl*> (host))
|
||||
{
|
||||
auto errorString = LocalRef<jstring> ((jstring) env->CallObjectMethod (sslError, SslError.toString));
|
||||
|
||||
myself->owner.pageLoadHadNetworkError (juceString (errorString));
|
||||
}
|
||||
const auto errorString = LocalRef<jstring> ((jstring) env->CallObjectMethod (sslError, SslError.toString));
|
||||
t.owner.pageLoadHadNetworkError (juceString (errorString));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(J)V") \
|
||||
CALLBACK (webViewCloseWindowRequest, "webViewCloseWindowRequest", "(JLandroid/webkit/WebView;)V") \
|
||||
CALLBACK (webViewCreateWindowRequest, "webViewCreateWindowRequest", "(JLandroid/webkit/WebView;)V") \
|
||||
CALLBACK (generatedCallback<&Pimpl::webViewCloseWindowRequest>, "webViewCloseWindowRequest", "(JLandroid/webkit/WebView;)V") \
|
||||
CALLBACK (generatedCallback<&Pimpl::webViewCreateWindowRequest>, "webViewCreateWindowRequest", "(JLandroid/webkit/WebView;)V") \
|
||||
|
||||
DECLARE_JNI_CLASS (JuceWebChromeClient, "com/rmsl/juce/JuceWebView$ChromeClient")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
static void JNICALL webViewCloseWindowRequest (JNIEnv*, jobject /*activity*/, jlong host, jobject /*webView*/)
|
||||
static void webViewCloseWindowRequest (JNIEnv*, Pimpl& t, jobject)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<WebBrowserComponent::Pimpl*> (host))
|
||||
myself->owner.windowCloseRequest();
|
||||
t.owner.windowCloseRequest();
|
||||
}
|
||||
|
||||
static void JNICALL webViewCreateWindowRequest (JNIEnv*, jobject /*activity*/, jlong host, jobject /*webView*/)
|
||||
static void webViewCreateWindowRequest (JNIEnv*, Pimpl& t, jobject)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<WebBrowserComponent::Pimpl*> (host))
|
||||
myself->owner.newWindowAttemptingToLoad ({});
|
||||
t.owner.newWindowAttemptingToLoad ({});
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void webReceivedHttpError (jobject errorResponse)
|
||||
static void webViewReceivedHttpError (JNIEnv* env, Pimpl& t, jobject errorResponse)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
LocalRef<jclass> responseClass (env->FindClass ("android/webkit/WebResourceResponse"));
|
||||
|
||||
if (responseClass != nullptr)
|
||||
|
|
@ -565,14 +545,14 @@ private:
|
|||
{
|
||||
auto errorString = LocalRef<jstring> ((jstring) env->CallObjectMethod (errorResponse, method));
|
||||
|
||||
owner.pageLoadHadNetworkError (juceString (errorString));
|
||||
t.owner.pageLoadHadNetworkError (juceString (errorString));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Should never get here!
|
||||
jassertfalse;
|
||||
owner.pageLoadHadNetworkError ({});
|
||||
t.owner.pageLoadHadNetworkError ({});
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -596,9 +576,7 @@ WebBrowserComponent::WebBrowserComponent (const Options& options)
|
|||
addAndMakeVisible (browser.get());
|
||||
}
|
||||
|
||||
WebBrowserComponent::~WebBrowserComponent()
|
||||
{
|
||||
}
|
||||
WebBrowserComponent::~WebBrowserComponent() = default;
|
||||
|
||||
//==============================================================================
|
||||
void WebBrowserComponent::goToURL (const String& url,
|
||||
|
|
@ -728,7 +706,4 @@ bool WebBrowserComponent::areOptionsSupported (const Options& options)
|
|||
return (options.getBackend() == Options::Backend::defaultBackend);
|
||||
}
|
||||
|
||||
WebBrowserComponent::Pimpl::JuceWebViewClient16_Class WebBrowserComponent::Pimpl::JuceWebViewClient16;
|
||||
WebBrowserComponent::Pimpl::JuceWebViewClient21_Class WebBrowserComponent::Pimpl::JuceWebViewClient21;
|
||||
WebBrowserComponent::Pimpl::JuceWebChromeClient_Class WebBrowserComponent::Pimpl::JuceWebChromeClient;
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -103,26 +103,6 @@ static const uint8 javaJuceOpenGLView[] =
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
struct AndroidGLCallbacks
|
||||
{
|
||||
static void attachedToWindow (JNIEnv*, jobject, jlong);
|
||||
static void detachedFromWindow (JNIEnv*, jobject, jlong);
|
||||
static void dispatchDraw (JNIEnv*, jobject, jlong, jobject);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(Landroid/content/Context;J)V") \
|
||||
METHOD (getParent, "getParent", "()Landroid/view/ViewParent;") \
|
||||
METHOD (getHolder, "getHolder", "()Landroid/view/SurfaceHolder;") \
|
||||
METHOD (layout, "layout", "(IIII)V" ) \
|
||||
CALLBACK (AndroidGLCallbacks::attachedToWindow, "onAttchedWindowNative", "(J)V") \
|
||||
CALLBACK (AndroidGLCallbacks::detachedFromWindow, "onDetachedFromWindowNative", "(J)V") \
|
||||
CALLBACK (AndroidGLCallbacks::dispatchDraw, "onDrawNative", "(JLandroid/graphics/Canvas;)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceOpenGLViewSurface, "com/rmsl/juce/JuceOpenGLView", 16, javaJuceOpenGLView, sizeof(javaJuceOpenGLView))
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
class OpenGLContext::NativeContext : private SurfaceHolderCallback
|
||||
{
|
||||
|
|
@ -266,40 +246,46 @@ public:
|
|||
Component& component;
|
||||
|
||||
private:
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(Landroid/content/Context;J)V") \
|
||||
METHOD (getParent, "getParent", "()Landroid/view/ViewParent;") \
|
||||
METHOD (getHolder, "getHolder", "()Landroid/view/SurfaceHolder;") \
|
||||
METHOD (layout, "layout", "(IIII)V" ) \
|
||||
CALLBACK (generatedCallback<&NativeContext::attachedToWindow>, "onAttchedWindowNative", "(J)V") \
|
||||
CALLBACK (generatedCallback<&NativeContext::detachedFromWindow>, "onDetachedFromWindowNative", "(J)V") \
|
||||
CALLBACK (generatedCallback<&NativeContext::dispatchDraw>, "onDrawNative", "(JLandroid/graphics/Canvas;)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceOpenGLViewSurface, "com/rmsl/juce/JuceOpenGLView", 16, javaJuceOpenGLView)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
friend struct AndroidGLCallbacks;
|
||||
|
||||
void attachedToWindow()
|
||||
static void attachedToWindow (JNIEnv* env, NativeContext& t)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
LocalRef<jobject> holder (env->CallObjectMethod (t.surfaceView.get(), JuceOpenGLViewSurface.getHolder));
|
||||
|
||||
LocalRef<jobject> holder (env->CallObjectMethod (surfaceView.get(), JuceOpenGLViewSurface.getHolder));
|
||||
if (t.surfaceHolderCallback == nullptr)
|
||||
t.surfaceHolderCallback = GlobalRef (CreateJavaInterface (&t, "android/view/SurfaceHolder$Callback"));
|
||||
|
||||
if (surfaceHolderCallback == nullptr)
|
||||
surfaceHolderCallback = GlobalRef (CreateJavaInterface (this, "android/view/SurfaceHolder$Callback"));
|
||||
|
||||
env->CallVoidMethod (holder, AndroidSurfaceHolder.addCallback, surfaceHolderCallback.get());
|
||||
env->CallVoidMethod (holder, AndroidSurfaceHolder.addCallback, t.surfaceHolderCallback.get());
|
||||
}
|
||||
|
||||
void detachedFromWindow()
|
||||
static void detachedFromWindow (JNIEnv* env, NativeContext& t)
|
||||
{
|
||||
if (surfaceHolderCallback != nullptr)
|
||||
if (t.surfaceHolderCallback != nullptr)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
LocalRef<jobject> holder (env->CallObjectMethod (t.surfaceView.get(), JuceOpenGLViewSurface.getHolder));
|
||||
|
||||
LocalRef<jobject> holder (env->CallObjectMethod (surfaceView.get(), JuceOpenGLViewSurface.getHolder));
|
||||
|
||||
env->CallVoidMethod (holder.get(), AndroidSurfaceHolder.removeCallback, surfaceHolderCallback.get());
|
||||
surfaceHolderCallback.clear();
|
||||
env->CallVoidMethod (holder.get(), AndroidSurfaceHolder.removeCallback, t.surfaceHolderCallback.get());
|
||||
t.surfaceHolderCallback.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void dispatchDraw (jobject /*canvas*/)
|
||||
static void dispatchDraw (JNIEnv*, NativeContext& t, jobject /*canvas*/)
|
||||
{
|
||||
const std::lock_guard lock { nativeHandleMutex };
|
||||
const std::lock_guard lock { t.nativeHandleMutex };
|
||||
|
||||
if (juceContext != nullptr)
|
||||
juceContext->triggerRepaint();
|
||||
if (t.juceContext != nullptr)
|
||||
t.juceContext->triggerRepaint();
|
||||
}
|
||||
|
||||
bool tryChooseConfig (const std::vector<EGLint>& optionalAttribs)
|
||||
|
|
@ -414,25 +400,6 @@ private:
|
|||
EGLDisplay OpenGLContext::NativeContext::display = EGL_NO_DISPLAY;
|
||||
EGLDisplay OpenGLContext::NativeContext::config;
|
||||
|
||||
//==============================================================================
|
||||
void AndroidGLCallbacks::attachedToWindow (JNIEnv*, jobject /*this*/, jlong host)
|
||||
{
|
||||
if (auto* nativeContext = reinterpret_cast<OpenGLContext::NativeContext*> (host))
|
||||
nativeContext->attachedToWindow();
|
||||
}
|
||||
|
||||
void AndroidGLCallbacks::detachedFromWindow (JNIEnv*, jobject /*this*/, jlong host)
|
||||
{
|
||||
if (auto* nativeContext = reinterpret_cast<OpenGLContext::NativeContext*> (host))
|
||||
nativeContext->detachedFromWindow();
|
||||
}
|
||||
|
||||
void AndroidGLCallbacks::dispatchDraw (JNIEnv*, jobject /*this*/, jlong host, jobject canvas)
|
||||
{
|
||||
if (auto* nativeContext = reinterpret_cast<OpenGLContext::NativeContext*> (host))
|
||||
nativeContext->dispatchDraw (canvas);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool OpenGLHelpers::isContextActive()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ inline StringArray javaListOfStringToJuceStringArray (const LocalRef<jobject>& j
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
constexpr unsigned char juceBillingClientCompiled[]
|
||||
constexpr uint8 juceBillingClientCompiled[]
|
||||
{
|
||||
0x1f, 0x8b, 0x08, 0x08, 0xa4, 0x53, 0xd0, 0x62, 0x04, 0x03, 0x63, 0x6c,
|
||||
0x61, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x78, 0x00, 0x9d, 0x5a,
|
||||
|
|
@ -720,42 +720,17 @@ private:
|
|||
METHOD (queryPurchases, "queryPurchases", "()V") \
|
||||
METHOD (consumePurchase, "consumePurchase", "(Ljava/lang/String;Ljava/lang/String;)V") \
|
||||
\
|
||||
CALLBACK (productDetailsQueryCallback, "productDetailsQueryCallback", "(JLjava/util/List;)V") \
|
||||
CALLBACK (purchasesListQueryCallback, "purchasesListQueryCallback", "(JLjava/util/List;)V") \
|
||||
CALLBACK (purchaseCompletedCallback, "purchaseCompletedCallback", "(JLcom/android/billingclient/api/Purchase;I)V") \
|
||||
CALLBACK (purchaseConsumedCallback, "purchaseConsumedCallback", "(JLjava/lang/String;I)V")
|
||||
CALLBACK (generatedCallback<&Pimpl::updateProductDetails>, "productDetailsQueryCallback", "(JLjava/util/List;)V") \
|
||||
CALLBACK (generatedCallback<&Pimpl::updatePurchasesList>, "purchasesListQueryCallback", "(JLjava/util/List;)V") \
|
||||
CALLBACK (generatedCallback<&Pimpl::purchaseCompleted>, "purchaseCompletedCallback", "(JLcom/android/billingclient/api/Purchase;I)V") \
|
||||
CALLBACK (generatedCallback<&Pimpl::purchaseConsumed>, "purchaseConsumedCallback", "(JLjava/lang/String;I)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceBillingClient,
|
||||
"com/rmsl/juce/JuceBillingClient",
|
||||
16,
|
||||
juceBillingClientCompiled,
|
||||
numElementsInArray (juceBillingClientCompiled))
|
||||
juceBillingClientCompiled)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
static void JNICALL productDetailsQueryCallback (JNIEnv*, jobject, jlong host, jobject productDetailsList)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<Pimpl*> (host))
|
||||
myself->updateProductDetails (productDetailsList);
|
||||
}
|
||||
|
||||
static void JNICALL purchasesListQueryCallback (JNIEnv*, jobject, jlong host, jobject purchasesList)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<Pimpl*> (host))
|
||||
myself->updatePurchasesList (purchasesList);
|
||||
}
|
||||
|
||||
static void JNICALL purchaseCompletedCallback (JNIEnv*, jobject, jlong host, jobject purchase, int responseCode)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<Pimpl*> (host))
|
||||
myself->purchaseCompleted (purchase, responseCode);
|
||||
}
|
||||
|
||||
static void JNICALL purchaseConsumedCallback (JNIEnv*, jobject, jlong host, jstring productIdentifier, int responseCode)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<Pimpl*> (host))
|
||||
myself->purchaseConsumed (productIdentifier, responseCode);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isReady() const
|
||||
{
|
||||
|
|
@ -1095,7 +1070,4 @@ void juce_handleOnResume()
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
InAppPurchases::Pimpl::JuceBillingClient_Class InAppPurchases::Pimpl::JuceBillingClient;
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -400,7 +400,7 @@ class MediaRecorderOnInfoListener : public AndroidInterfaceImplementer
|
|||
public:
|
||||
struct Owner
|
||||
{
|
||||
virtual ~Owner() {}
|
||||
virtual ~Owner() = default;
|
||||
|
||||
virtual void onInfo (LocalRef<jobject>& mediaRecorder, int what, int extra) = 0;
|
||||
};
|
||||
|
|
@ -1711,26 +1711,25 @@ private:
|
|||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(JZ)V") \
|
||||
CALLBACK (cameraCaptureSessionCaptureCompletedCallback, "cameraCaptureSessionCaptureCompleted", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/TotalCaptureResult;)V") \
|
||||
CALLBACK (cameraCaptureSessionCaptureFailedCallback, "cameraCaptureSessionCaptureFailed", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/CaptureFailure;)V") \
|
||||
CALLBACK (cameraCaptureSessionCaptureProgressedCallback, "cameraCaptureSessionCaptureProgressed", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/CaptureResult;)V") \
|
||||
CALLBACK (cameraCaptureSessionCaptureStartedCallback, "cameraCaptureSessionCaptureStarted", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;JJ)V") \
|
||||
CALLBACK (cameraCaptureSessionCaptureSequenceAbortedCallback, "cameraCaptureSessionCaptureSequenceAborted", "(JZLandroid/hardware/camera2/CameraCaptureSession;I)V") \
|
||||
CALLBACK (cameraCaptureSessionCaptureSequenceCompletedCallback, "cameraCaptureSessionCaptureSequenceCompleted", "(JZLandroid/hardware/camera2/CameraCaptureSession;IJ)V")
|
||||
CALLBACK (generatedCallback<&StillPictureTaker::cameraCaptureSessionCaptureCompletedCallback>, "cameraCaptureSessionCaptureCompleted", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/TotalCaptureResult;)V") \
|
||||
CALLBACK (generatedCallback<&StillPictureTaker::cameraCaptureSessionCaptureFailedCallback>, "cameraCaptureSessionCaptureFailed", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/CaptureFailure;)V") \
|
||||
CALLBACK (generatedCallback<&StillPictureTaker::cameraCaptureSessionCaptureProgressedCallback>, "cameraCaptureSessionCaptureProgressed", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;Landroid/hardware/camera2/CaptureResult;)V") \
|
||||
CALLBACK (generatedCallback<&StillPictureTaker::cameraCaptureSessionCaptureStartedCallback>, "cameraCaptureSessionCaptureStarted", "(JZLandroid/hardware/camera2/CameraCaptureSession;Landroid/hardware/camera2/CaptureRequest;JJ)V") \
|
||||
CALLBACK (generatedCallback<&StillPictureTaker::cameraCaptureSessionCaptureSequenceAbortedCallback>, "cameraCaptureSessionCaptureSequenceAborted", "(JZLandroid/hardware/camera2/CameraCaptureSession;I)V") \
|
||||
CALLBACK (generatedCallback<&StillPictureTaker::cameraCaptureSessionCaptureSequenceCompletedCallback>, "cameraCaptureSessionCaptureSequenceCompleted", "(JZLandroid/hardware/camera2/CameraCaptureSession;IJ)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (CameraCaptureSessionCaptureCallback, "com/rmsl/juce/CameraCaptureSessionCaptureCallback", 21, CameraSupportByteCode, sizeof(CameraSupportByteCode))
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (CameraCaptureSessionCaptureCallback, "com/rmsl/juce/CameraCaptureSessionCaptureCallback", 21, CameraSupportByteCode)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
LocalRef<jobject> createCaptureSessionCallback (bool createPreviewSession)
|
||||
{
|
||||
return LocalRef<jobject>(getEnv()->NewObject (CameraCaptureSessionCaptureCallback,
|
||||
CameraCaptureSessionCaptureCallback.constructor,
|
||||
reinterpret_cast<jlong> (this),
|
||||
createPreviewSession ? 1 : 0));
|
||||
return LocalRef<jobject> (getEnv()->NewObject (CameraCaptureSessionCaptureCallback,
|
||||
CameraCaptureSessionCaptureCallback.constructor,
|
||||
reinterpret_cast<jlong> (this),
|
||||
createPreviewSession ? 1 : 0));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
enum class State
|
||||
{
|
||||
idle = 0,
|
||||
|
|
@ -2022,71 +2021,53 @@ private:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
static void cameraCaptureSessionCaptureCompletedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jobject rawRequest, jobject rawResult)
|
||||
static void cameraCaptureSessionCaptureCompletedCallback (JNIEnv* env, StillPictureTaker& t, jboolean isPreview, jobject rawSession, jobject rawRequest, jobject rawResult)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
LocalRef<jobject> request (getEnv()->NewLocalRef(rawRequest));
|
||||
LocalRef<jobject> result (getEnv()->NewLocalRef(rawResult));
|
||||
LocalRef<jobject> session (env->NewLocalRef (rawSession));
|
||||
LocalRef<jobject> request (env->NewLocalRef (rawRequest));
|
||||
LocalRef<jobject> result (env->NewLocalRef (rawResult));
|
||||
|
||||
myself->cameraCaptureSessionCaptureCompleted (isPreview != 0, session, request, result);
|
||||
}
|
||||
t.cameraCaptureSessionCaptureCompleted (isPreview != 0, session, request, result);
|
||||
}
|
||||
|
||||
static void cameraCaptureSessionCaptureFailedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jobject rawRequest, jobject rawResult)
|
||||
static void cameraCaptureSessionCaptureFailedCallback (JNIEnv* env, StillPictureTaker& t, jboolean isPreview, jobject rawSession, jobject rawRequest, jobject rawResult)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
LocalRef<jobject> request (getEnv()->NewLocalRef(rawRequest));
|
||||
LocalRef<jobject> result (getEnv()->NewLocalRef(rawResult));
|
||||
LocalRef<jobject> session (env->NewLocalRef (rawSession));
|
||||
LocalRef<jobject> request (env->NewLocalRef (rawRequest));
|
||||
LocalRef<jobject> result (env->NewLocalRef (rawResult));
|
||||
|
||||
myself->cameraCaptureSessionCaptureFailed (isPreview != 0, session, request, result);
|
||||
}
|
||||
t.cameraCaptureSessionCaptureFailed (isPreview != 0, session, request, result);
|
||||
}
|
||||
|
||||
static void cameraCaptureSessionCaptureProgressedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jobject rawRequest, jobject rawResult)
|
||||
static void cameraCaptureSessionCaptureProgressedCallback (JNIEnv* env, StillPictureTaker& t, jboolean isPreview, jobject rawSession, jobject rawRequest, jobject rawResult)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
LocalRef<jobject> request (getEnv()->NewLocalRef(rawRequest));
|
||||
LocalRef<jobject> result (getEnv()->NewLocalRef(rawResult));
|
||||
LocalRef<jobject> session (env->NewLocalRef (rawSession));
|
||||
LocalRef<jobject> request (env->NewLocalRef (rawRequest));
|
||||
LocalRef<jobject> result (env->NewLocalRef (rawResult));
|
||||
|
||||
myself->cameraCaptureSessionCaptureProgressed (isPreview != 0, session, request, result);
|
||||
}
|
||||
t.cameraCaptureSessionCaptureProgressed (isPreview != 0, session, request, result);
|
||||
}
|
||||
|
||||
static void cameraCaptureSessionCaptureSequenceAbortedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jint sequenceId)
|
||||
static void cameraCaptureSessionCaptureSequenceAbortedCallback (JNIEnv* env, StillPictureTaker& t, jboolean isPreview, jobject rawSession, jint sequenceId)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
LocalRef<jobject> session (env->NewLocalRef (rawSession));
|
||||
|
||||
myself->cameraCaptureSessionCaptureSequenceAborted (isPreview != 0, session, sequenceId);
|
||||
}
|
||||
t.cameraCaptureSessionCaptureSequenceAborted (isPreview != 0, session, sequenceId);
|
||||
}
|
||||
|
||||
static void cameraCaptureSessionCaptureSequenceCompletedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jint sequenceId, jlong frameNumber)
|
||||
static void cameraCaptureSessionCaptureSequenceCompletedCallback (JNIEnv* env, StillPictureTaker& t, jboolean isPreview, jobject rawSession, jint sequenceId, jlong frameNumber)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
LocalRef<jobject> session (env->NewLocalRef (rawSession));
|
||||
|
||||
myself->cameraCaptureSessionCaptureSequenceCompleted (isPreview != 0, session, sequenceId, frameNumber);
|
||||
}
|
||||
t.cameraCaptureSessionCaptureSequenceCompleted (isPreview != 0, session, sequenceId, frameNumber);
|
||||
}
|
||||
|
||||
static void cameraCaptureSessionCaptureStartedCallback (JNIEnv*, jobject /*object*/, jlong host, jboolean isPreview, jobject rawSession, jobject rawRequest, jlong timestamp, jlong frameNumber)
|
||||
static void cameraCaptureSessionCaptureStartedCallback (JNIEnv* env, StillPictureTaker& t, jboolean isPreview, jobject rawSession, jobject rawRequest, jlong timestamp, jlong frameNumber)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<StillPictureTaker*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
LocalRef<jobject> request (getEnv()->NewLocalRef(rawRequest));
|
||||
LocalRef<jobject> session (env->NewLocalRef (rawSession));
|
||||
LocalRef<jobject> request (env->NewLocalRef (rawRequest));
|
||||
|
||||
myself->cameraCaptureSessionCaptureStarted (isPreview != 0, session, request, timestamp, frameNumber);
|
||||
}
|
||||
t.cameraCaptureSessionCaptureStarted (isPreview != 0, session, request, timestamp, frameNumber);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -2115,11 +2096,11 @@ private:
|
|||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(J)V") \
|
||||
CALLBACK(cameraCaptureSessionActiveCallback, "cameraCaptureSessionActive", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
|
||||
CALLBACK(cameraCaptureSessionClosedCallback, "cameraCaptureSessionClosed", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
|
||||
CALLBACK(cameraCaptureSessionConfigureFailedCallback, "cameraCaptureSessionConfigureFailed", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
|
||||
CALLBACK(cameraCaptureSessionConfiguredCallback, "cameraCaptureSessionConfigured", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
|
||||
CALLBACK(cameraCaptureSessionReadyCallback, "cameraCaptureSessionReady", "(JLandroid/hardware/camera2/CameraCaptureSession;)V")
|
||||
CALLBACK (generatedCallback<&CaptureSession::cameraCaptureSessionActiveCallback>, "cameraCaptureSessionActive", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
|
||||
CALLBACK (generatedCallback<&CaptureSession::cameraCaptureSessionClosedCallback>, "cameraCaptureSessionClosed", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
|
||||
CALLBACK (generatedCallback<&CaptureSession::cameraCaptureSessionConfigureFailedCallback>, "cameraCaptureSessionConfigureFailed", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
|
||||
CALLBACK (generatedCallback<&CaptureSession::cameraCaptureSessionConfiguredCallback>, "cameraCaptureSessionConfigured", "(JLandroid/hardware/camera2/CameraCaptureSession;)V") \
|
||||
CALLBACK (generatedCallback<&CaptureSession::cameraCaptureSessionReadyCallback>, "cameraCaptureSessionReady", "(JLandroid/hardware/camera2/CameraCaptureSession;)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_MIN_SDK (CameraCaptureSessionStateCallback, "com/rmsl/juce/CameraCaptureSessionStateCallback", 21)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
|
@ -2161,124 +2142,83 @@ private:
|
|||
env->CallVoidMethod (captureRequestBuilder, CaptureRequestBuilder.set, jKey.get(), jValue.get());
|
||||
}
|
||||
|
||||
void cameraCaptureSessionActive ([[maybe_unused]] jobject session)
|
||||
//==============================================================================
|
||||
static void cameraCaptureSessionActiveCallback ([[maybe_unused]] JNIEnv* env,
|
||||
[[maybe_unused]] CaptureSession& t,
|
||||
[[maybe_unused]] jobject rawSession)
|
||||
{
|
||||
JUCE_CAMERA_LOG ("cameraCaptureSessionActive()");
|
||||
}
|
||||
|
||||
void cameraCaptureSessionClosed ([[maybe_unused]] jobject session)
|
||||
static void cameraCaptureSessionClosedCallback ([[maybe_unused]] JNIEnv* env,
|
||||
CaptureSession& t,
|
||||
[[maybe_unused]] jobject rawSession)
|
||||
{
|
||||
JUCE_CAMERA_LOG ("cameraCaptureSessionClosed()");
|
||||
|
||||
closedEvent.signal();
|
||||
t.closedEvent.signal();
|
||||
}
|
||||
|
||||
void cameraCaptureSessionConfigureFailed ([[maybe_unused]] jobject session)
|
||||
static void cameraCaptureSessionConfigureFailedCallback ([[maybe_unused]] JNIEnv* env,
|
||||
CaptureSession& t,
|
||||
[[maybe_unused]] jobject rawSession)
|
||||
{
|
||||
JUCE_CAMERA_LOG ("cameraCaptureSessionConfigureFailed()");
|
||||
|
||||
MessageManager::callAsync ([weakRef = WeakReference<CaptureSession> { this }]
|
||||
{
|
||||
if (weakRef != nullptr)
|
||||
weakRef->configuredCallback.captureSessionConfigured (nullptr);
|
||||
});
|
||||
MessageManager::callAsync ([weakRef = WeakReference<CaptureSession> { &t }]
|
||||
{
|
||||
if (weakRef != nullptr)
|
||||
weakRef->configuredCallback.captureSessionConfigured (nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
void cameraCaptureSessionConfigured (const LocalRef<jobject>& session)
|
||||
static void cameraCaptureSessionConfiguredCallback (JNIEnv* env, CaptureSession& t, jobject rawSession)
|
||||
{
|
||||
LocalRef<jobject> session (env->NewLocalRef (rawSession));
|
||||
JUCE_CAMERA_LOG ("cameraCaptureSessionConfigured()");
|
||||
|
||||
if (pendingClose.get() == 1)
|
||||
if (t.pendingClose.get() == 1)
|
||||
{
|
||||
// Already closing, bailout.
|
||||
closedEvent.signal();
|
||||
t.closedEvent.signal();
|
||||
|
||||
GlobalRef s (session);
|
||||
|
||||
MessageManager::callAsync ([s]()
|
||||
{
|
||||
getEnv()->CallVoidMethod (s, CameraCaptureSession.close);
|
||||
});
|
||||
{
|
||||
getEnv()->CallVoidMethod (s, CameraCaptureSession.close);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
const ScopedLock lock (captureSessionLock);
|
||||
captureSession = GlobalRef (session);
|
||||
const ScopedLock lock (t.captureSessionLock);
|
||||
t.captureSession = GlobalRef (session);
|
||||
}
|
||||
|
||||
MessageManager::callAsync ([weakRef = WeakReference<CaptureSession> { this }]
|
||||
{
|
||||
if (weakRef == nullptr)
|
||||
return;
|
||||
MessageManager::callAsync ([weakRef = WeakReference<CaptureSession> { &t }]
|
||||
{
|
||||
if (weakRef == nullptr)
|
||||
return;
|
||||
|
||||
weakRef->stillPictureTaker.reset (new StillPictureTaker (weakRef->captureSession,
|
||||
weakRef->captureRequestBuilder,
|
||||
weakRef->previewCaptureRequest,
|
||||
weakRef->handler,
|
||||
weakRef->autoFocusMode));
|
||||
weakRef->stillPictureTaker.reset (new StillPictureTaker (weakRef->captureSession,
|
||||
weakRef->captureRequestBuilder,
|
||||
weakRef->previewCaptureRequest,
|
||||
weakRef->handler,
|
||||
weakRef->autoFocusMode));
|
||||
|
||||
weakRef->configuredCallback.captureSessionConfigured (weakRef.get());
|
||||
});
|
||||
weakRef->configuredCallback.captureSessionConfigured (weakRef.get());
|
||||
});
|
||||
}
|
||||
|
||||
void cameraCaptureSessionReady ([[maybe_unused]] const LocalRef<jobject>& session)
|
||||
static void cameraCaptureSessionReadyCallback ([[maybe_unused]] JNIEnv* env,
|
||||
[[maybe_unused]] CaptureSession& t,
|
||||
[[maybe_unused]] jobject rawSession)
|
||||
{
|
||||
JUCE_CAMERA_LOG ("cameraCaptureSessionReady()");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void cameraCaptureSessionActiveCallback (JNIEnv*, jobject, jlong host, jobject rawSession)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<CaptureSession*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
|
||||
myself->cameraCaptureSessionActive (session);
|
||||
}
|
||||
}
|
||||
|
||||
static void cameraCaptureSessionClosedCallback (JNIEnv*, jobject, jlong host, jobject rawSession)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<CaptureSession*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
|
||||
myself->cameraCaptureSessionClosed (session);
|
||||
}
|
||||
}
|
||||
|
||||
static void cameraCaptureSessionConfigureFailedCallback (JNIEnv*, jobject, jlong host, jobject rawSession)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<CaptureSession*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
|
||||
myself->cameraCaptureSessionConfigureFailed (session);
|
||||
}
|
||||
}
|
||||
|
||||
static void cameraCaptureSessionConfiguredCallback (JNIEnv*, jobject, jlong host, jobject rawSession)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<CaptureSession*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
|
||||
myself->cameraCaptureSessionConfigured (session);
|
||||
}
|
||||
}
|
||||
|
||||
static void cameraCaptureSessionReadyCallback (JNIEnv*, jobject, jlong host, jobject rawSession)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<CaptureSession*> (host))
|
||||
{
|
||||
LocalRef<jobject> session (getEnv()->NewLocalRef(rawSession));
|
||||
|
||||
myself->cameraCaptureSessionReady (session);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
friend class ScopedCameraDevice;
|
||||
|
||||
|
|
@ -2374,10 +2314,10 @@ private:
|
|||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(J)V") \
|
||||
CALLBACK (cameraDeviceStateClosedCallback, "cameraDeviceStateClosed", "(JLandroid/hardware/camera2/CameraDevice;)V") \
|
||||
CALLBACK (cameraDeviceStateDisconnectedCallback, "cameraDeviceStateDisconnected", "(JLandroid/hardware/camera2/CameraDevice;)V") \
|
||||
CALLBACK (cameraDeviceStateErrorCallback, "cameraDeviceStateError", "(JLandroid/hardware/camera2/CameraDevice;I)V") \
|
||||
CALLBACK (cameraDeviceStateOpenedCallback, "cameraDeviceStateOpened", "(JLandroid/hardware/camera2/CameraDevice;)V")
|
||||
CALLBACK (generatedCallback<&ScopedCameraDevice::cameraDeviceStateClosedCallback>, "cameraDeviceStateClosed", "(JLandroid/hardware/camera2/CameraDevice;)V") \
|
||||
CALLBACK (generatedCallback<&ScopedCameraDevice::cameraDeviceStateDisconnectedCallback>, "cameraDeviceStateDisconnected", "(JLandroid/hardware/camera2/CameraDevice;)V") \
|
||||
CALLBACK (generatedCallback<&ScopedCameraDevice::cameraDeviceStateErrorCallback>, "cameraDeviceStateError", "(JLandroid/hardware/camera2/CameraDevice;I)V") \
|
||||
CALLBACK (generatedCallback<&ScopedCameraDevice::cameraDeviceStateOpenedCallback>, "cameraDeviceStateOpened", "(JLandroid/hardware/camera2/CameraDevice;)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_MIN_SDK (CameraDeviceStateCallback, "com/rmsl/juce/CameraDeviceStateCallback", 21)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
|
@ -2390,92 +2330,66 @@ private:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void cameraDeviceStateClosed()
|
||||
{
|
||||
JUCE_CAMERA_LOG ("cameraDeviceStateClosed()");
|
||||
|
||||
closedEvent.signal();
|
||||
}
|
||||
|
||||
void cameraDeviceStateDisconnected()
|
||||
{
|
||||
JUCE_CAMERA_LOG ("cameraDeviceStateDisconnected()");
|
||||
|
||||
if (pendingOpen.compareAndSetBool (0, 1))
|
||||
{
|
||||
openError = "Device disconnected";
|
||||
|
||||
notifyOpenResult();
|
||||
}
|
||||
|
||||
MessageManager::callAsync ([this]() { close(); });
|
||||
}
|
||||
|
||||
void cameraDeviceStateError (int errorCode)
|
||||
{
|
||||
String error = cameraErrorCodeToString (errorCode);
|
||||
|
||||
JUCE_CAMERA_LOG ("cameraDeviceStateError(), error: " + error);
|
||||
|
||||
if (pendingOpen.compareAndSetBool (0, 1))
|
||||
{
|
||||
openError = error;
|
||||
|
||||
notifyOpenResult();
|
||||
}
|
||||
|
||||
fatalErrorOccurred.set (1);
|
||||
|
||||
MessageManager::callAsync ([this, error]()
|
||||
{
|
||||
owner.cameraDeviceError (error);
|
||||
close();
|
||||
});
|
||||
}
|
||||
|
||||
void cameraDeviceStateOpened (const LocalRef<jobject>& cameraDeviceToUse)
|
||||
{
|
||||
JUCE_CAMERA_LOG ("cameraDeviceStateOpened()");
|
||||
|
||||
pendingOpen.set (0);
|
||||
|
||||
cameraDevice = GlobalRef (cameraDeviceToUse);
|
||||
|
||||
notifyOpenResult();
|
||||
}
|
||||
|
||||
void notifyOpenResult()
|
||||
{
|
||||
MessageManager::callAsync ([this]() { owner.cameraOpenFinished (openError); });
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void JNICALL cameraDeviceStateClosedCallback (JNIEnv*, jobject, jlong host, jobject)
|
||||
static void cameraDeviceStateClosedCallback (JNIEnv*, ScopedCameraDevice& s, jobject)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<ScopedCameraDevice*>(host))
|
||||
myself->cameraDeviceStateClosed();
|
||||
JUCE_CAMERA_LOG ("cameraDeviceStateClosed()");
|
||||
|
||||
s.closedEvent.signal();
|
||||
}
|
||||
|
||||
static void JNICALL cameraDeviceStateDisconnectedCallback (JNIEnv*, jobject, jlong host, jobject)
|
||||
static void cameraDeviceStateDisconnectedCallback (JNIEnv*, ScopedCameraDevice& s, jobject)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<ScopedCameraDevice*>(host))
|
||||
myself->cameraDeviceStateDisconnected();
|
||||
}
|
||||
JUCE_CAMERA_LOG ("cameraDeviceStateDisconnected()");
|
||||
|
||||
static void JNICALL cameraDeviceStateErrorCallback (JNIEnv*, jobject, jlong host, jobject, jint error)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<ScopedCameraDevice*>(host))
|
||||
myself->cameraDeviceStateError (error);
|
||||
}
|
||||
|
||||
static void JNICALL cameraDeviceStateOpenedCallback (JNIEnv*, jobject, jlong host, jobject rawCamera)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<ScopedCameraDevice*>(host))
|
||||
if (s.pendingOpen.compareAndSetBool (0, 1))
|
||||
{
|
||||
LocalRef<jobject> camera(getEnv()->NewLocalRef(rawCamera));
|
||||
s.openError = "Device disconnected";
|
||||
|
||||
myself->cameraDeviceStateOpened (camera);
|
||||
s.notifyOpenResult();
|
||||
}
|
||||
|
||||
MessageManager::callAsync ([&s] { s.close(); });
|
||||
}
|
||||
|
||||
static void cameraDeviceStateErrorCallback (JNIEnv*, ScopedCameraDevice& s, jobject, jint errorCode)
|
||||
{
|
||||
auto error = cameraErrorCodeToString (errorCode);
|
||||
|
||||
JUCE_CAMERA_LOG ("cameraDeviceStateError(), error: " + error);
|
||||
|
||||
if (s.pendingOpen.compareAndSetBool (0, 1))
|
||||
{
|
||||
s.openError = error;
|
||||
|
||||
s.notifyOpenResult();
|
||||
}
|
||||
|
||||
s.fatalErrorOccurred.set (1);
|
||||
|
||||
MessageManager::callAsync ([&s, error]()
|
||||
{
|
||||
s.owner.cameraDeviceError (error);
|
||||
s.close();
|
||||
});
|
||||
}
|
||||
|
||||
static void cameraDeviceStateOpenedCallback (JNIEnv* env, ScopedCameraDevice& s, jobject cameraDeviceToUse)
|
||||
{
|
||||
JUCE_CAMERA_LOG ("cameraDeviceStateOpened()");
|
||||
|
||||
LocalRef<jobject> camera (env->NewLocalRef (cameraDeviceToUse));
|
||||
|
||||
s.pendingOpen.set (0);
|
||||
|
||||
s.cameraDevice = GlobalRef (camera);
|
||||
|
||||
s.notifyOpenResult();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -2815,7 +2729,7 @@ private:
|
|||
METHOD (constructor, "<init>", "(JLandroid/content/Context;I)V") \
|
||||
METHOD (disable, "disable", "()V") \
|
||||
METHOD (enable, "enable", "()V") \
|
||||
CALLBACK (deviceOrientationChanged, "deviceOrientationChanged", "(JI)V")
|
||||
CALLBACK (generatedCallback<&DeviceOrientationChangeListener::orientationChanged>, "deviceOrientationChanged", "(JI)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_MIN_SDK (OrientationEventListener, "com/rmsl/juce/JuceOrientationEventListener", 21)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
|
@ -2830,7 +2744,7 @@ private:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void orientationChanged (int orientation)
|
||||
static void orientationChanged (JNIEnv*, DeviceOrientationChangeListener& t, jint orientation)
|
||||
{
|
||||
jassert (orientation < 360);
|
||||
|
||||
|
|
@ -2838,25 +2752,31 @@ private:
|
|||
if (orientation < 0)
|
||||
return;
|
||||
|
||||
auto oldOrientation = deviceOrientation;
|
||||
const auto oldOrientation = t.deviceOrientation;
|
||||
|
||||
t.deviceOrientation = [orientation]
|
||||
{
|
||||
if (orientation > (360 - 45) || orientation < 45)
|
||||
return Desktop::upright;
|
||||
|
||||
if (orientation < 135)
|
||||
return Desktop::rotatedClockwise;
|
||||
|
||||
if (orientation < 225)
|
||||
return Desktop::upsideDown;
|
||||
|
||||
return Desktop::rotatedAntiClockwise;
|
||||
}();
|
||||
|
||||
// NB: this assumes natural position to be portrait always, but some devices may be landscape...
|
||||
if (orientation > (360 - 45) || orientation < 45)
|
||||
deviceOrientation = Desktop::upright;
|
||||
else if (orientation < 135)
|
||||
deviceOrientation = Desktop::rotatedClockwise;
|
||||
else if (orientation < 225)
|
||||
deviceOrientation = Desktop::upsideDown;
|
||||
else
|
||||
deviceOrientation = Desktop::rotatedAntiClockwise;
|
||||
|
||||
if (oldOrientation != deviceOrientation)
|
||||
if (oldOrientation != t.deviceOrientation)
|
||||
{
|
||||
lastKnownScreenOrientation = Desktop::getInstance().getCurrentOrientation();
|
||||
t.lastKnownScreenOrientation = Desktop::getInstance().getCurrentOrientation();
|
||||
|
||||
// Need to update preview transform, but screen orientation will change slightly
|
||||
// later than sensor orientation.
|
||||
startTimer (500);
|
||||
t.startTimer (500);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2881,12 +2801,6 @@ private:
|
|||
numChecksForOrientationChange = 10;
|
||||
}
|
||||
}
|
||||
|
||||
static void deviceOrientationChanged (JNIEnv*, jobject /*obj*/, jlong host, jint orientation)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<DeviceOrientationChangeListener*> (host))
|
||||
myself->orientationChanged (orientation);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -3180,7 +3094,7 @@ private:
|
|||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
auto quitSafelyMethod = env->GetMethodID(AndroidHandlerThread, "quitSafely", "()Z");
|
||||
auto quitSafelyMethod = env->GetMethodID (AndroidHandlerThread, "quitSafely", "()Z");
|
||||
|
||||
// this code will only run on SDK >= 21
|
||||
jassert(quitSafelyMethod != nullptr);
|
||||
|
|
@ -3268,9 +3182,3 @@ String CameraDevice::getFileExtension()
|
|||
{
|
||||
return ".mp4";
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
CameraDevice::Pimpl::ScopedCameraDevice::CaptureSession::StillPictureTaker::CameraCaptureSessionCaptureCallback_Class CameraDevice::Pimpl::ScopedCameraDevice::CaptureSession::StillPictureTaker::CameraCaptureSessionCaptureCallback;
|
||||
CameraDevice::Pimpl::ScopedCameraDevice::CameraDeviceStateCallback_Class CameraDevice::Pimpl::ScopedCameraDevice::CameraDeviceStateCallback;
|
||||
CameraDevice::Pimpl::ScopedCameraDevice::CaptureSession::CameraCaptureSessionStateCallback_Class CameraDevice::Pimpl::ScopedCameraDevice::CaptureSession::CameraCaptureSessionStateCallback;
|
||||
CameraDevice::Pimpl::DeviceOrientationChangeListener::OrientationEventListener_Class CameraDevice::Pimpl::DeviceOrientationChangeListener::OrientationEventListener;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
//
|
||||
// files with min sdk version 21
|
||||
// See juce_core/native/java/README.txt on how to generate this byte-code.
|
||||
static const unsigned char MediaSessionByteCode[] =
|
||||
static const uint8 MediaSessionByteCode[] =
|
||||
{ 31,139,8,8,247,108,161,94,0,3,77,101,100,105,97,83,101,115,115,105,111,110,66,121,116,101,67,111,100,101,46,100,101,120,0,149,
|
||||
152,127,108,28,71,21,199,223,236,253,180,207,190,95,254,221,186,169,211,56,137,19,234,220,145,26,226,228,28,99,199,216,196,233,
|
||||
249,71,125,182,107,76,168,187,246,109,236,77,238,118,143,221,189,171,45,132,168,170,32,21,209,63,144,74,165,170,82,81,144,64,
|
||||
|
|
@ -757,12 +757,12 @@ private:
|
|||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(J)V") \
|
||||
CALLBACK (audioInfoChanged, "mediaControllerAudioInfoChanged", "(JLandroid/media/session/MediaController$PlaybackInfo;)V") \
|
||||
CALLBACK (metadataChanged, "mediaControllerMetadataChanged", "(JLandroid/media/MediaMetadata;)V") \
|
||||
CALLBACK (playbackStateChanged, "mediaControllerPlaybackStateChanged", "(JLandroid/media/session/PlaybackState;)V") \
|
||||
CALLBACK (sessionDestroyed, "mediaControllerSessionDestroyed", "(J)V")
|
||||
CALLBACK (generatedCallback<&Controller::audioInfoChanged>, "mediaControllerAudioInfoChanged", "(JLandroid/media/session/MediaController$PlaybackInfo;)V") \
|
||||
CALLBACK (generatedCallback<&Controller::metadataChanged>, "mediaControllerMetadataChanged", "(JLandroid/media/MediaMetadata;)V") \
|
||||
CALLBACK (generatedCallback<&Controller::playbackStateChanged>, "mediaControllerPlaybackStateChanged", "(JLandroid/media/session/PlaybackState;)V") \
|
||||
CALLBACK (generatedCallback<&Controller::sessionDestroyed>, "mediaControllerSessionDestroyed", "(J)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (AndroidMediaControllerCallback, "com/rmsl/juce/MediaControllerCallback", 21, MediaSessionByteCode, sizeof (MediaSessionByteCode))
|
||||
DECLARE_JNI_CLASS_WITH_BYTECODE (AndroidMediaControllerCallback, "com/rmsl/juce/MediaControllerCallback", 21, MediaSessionByteCode)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
LocalRef<jobject> createControllerCallbacks()
|
||||
|
|
@ -774,32 +774,24 @@ private:
|
|||
|
||||
//==============================================================================
|
||||
// MediaSessionController callbacks
|
||||
static void audioInfoChanged (JNIEnv*, jobject, jlong host, [[maybe_unused]] jobject playbackInfo)
|
||||
static void audioInfoChanged (JNIEnv*, [[maybe_unused]] Controller& t, [[maybe_unused]] jobject playbackInfo)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<VideoComponent::Pimpl::MediaSession::Controller*> (host))
|
||||
{
|
||||
JUCE_VIDEO_LOG ("MediaSessionController::audioInfoChanged()");
|
||||
}
|
||||
JUCE_VIDEO_LOG ("MediaSessionController::audioInfoChanged()");
|
||||
}
|
||||
|
||||
static void metadataChanged (JNIEnv*, jobject, jlong host, [[maybe_unused]] jobject metadata)
|
||||
static void metadataChanged (JNIEnv*, [[maybe_unused]] Controller&, [[maybe_unused]] jobject metadata)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<VideoComponent::Pimpl::MediaSession::Controller*> (host))
|
||||
{
|
||||
JUCE_VIDEO_LOG ("MediaSessionController::metadataChanged()");
|
||||
}
|
||||
JUCE_VIDEO_LOG ("MediaSessionController::metadataChanged()");
|
||||
}
|
||||
|
||||
static void playbackStateChanged (JNIEnv*, jobject, jlong host, jobject state)
|
||||
static void playbackStateChanged (JNIEnv*, Controller& t, [[maybe_unused]] jobject state)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<VideoComponent::Pimpl::MediaSession::Controller*> (host))
|
||||
myself->stateChanged (state);
|
||||
t.stateChanged (state);
|
||||
}
|
||||
|
||||
static void sessionDestroyed (JNIEnv*, jobject, jlong host)
|
||||
static void sessionDestroyed (JNIEnv*, [[maybe_unused]] Controller& t)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<VideoComponent::Pimpl::MediaSession::Controller*> (host))
|
||||
JUCE_VIDEO_LOG ("MediaSessionController::sessionDestroyed()");
|
||||
JUCE_VIDEO_LOG ("MediaSessionController::sessionDestroyed()");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1279,11 +1271,11 @@ private:
|
|||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(J)V") \
|
||||
CALLBACK (pauseCallback, "mediaSessionPause", "(J)V") \
|
||||
CALLBACK (playCallback, "mediaSessionPlay", "(J)V") \
|
||||
CALLBACK (playFromMediaIdCallback, "mediaSessionPlayFromMediaId", "(JLjava/lang/String;Landroid/os/Bundle;)V") \
|
||||
CALLBACK (seekToCallback, "mediaSessionSeekTo", "(JJ)V") \
|
||||
CALLBACK (stopCallback, "mediaSessionStop", "(J)V")
|
||||
CALLBACK (generatedCallback<&MediaSession::pauseCallback>, "mediaSessionPause", "(J)V") \
|
||||
CALLBACK (generatedCallback<&MediaSession::playCallback>, "mediaSessionPlay", "(J)V") \
|
||||
CALLBACK (generatedCallback<&MediaSession::playFromMediaIdCallback>, "mediaSessionPlayFromMediaId", "(JLjava/lang/String;Landroid/os/Bundle;)V") \
|
||||
CALLBACK (generatedCallback<&MediaSession::seekToCallback>, "mediaSessionSeekTo", "(JJ)V") \
|
||||
CALLBACK (generatedCallback<&MediaSession::stopCallback>, "mediaSessionStop", "(J)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidMediaSessionCallback, "com/rmsl/juce/MediaSessionCallback", 21)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
|
@ -1297,78 +1289,62 @@ private:
|
|||
|
||||
//==============================================================================
|
||||
// MediaSession callbacks
|
||||
static void pauseCallback (JNIEnv*, jobject, jlong host)
|
||||
static void pauseCallback (JNIEnv*, MediaSession& t)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<VideoComponent::Pimpl::MediaSession*> (host))
|
||||
{
|
||||
JUCE_VIDEO_LOG ("MediaSession::pauseCallback()");
|
||||
myself->player.pause();
|
||||
myself->updatePlaybackState();
|
||||
|
||||
myself->abandonAudioFocus();
|
||||
}
|
||||
JUCE_VIDEO_LOG ("MediaSession::pauseCallback()");
|
||||
t.player.pause();
|
||||
t.updatePlaybackState();
|
||||
t.abandonAudioFocus();
|
||||
}
|
||||
|
||||
static void playCallback (JNIEnv*, jobject, jlong host)
|
||||
static void playCallback (JNIEnv* env, MediaSession& t)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<VideoComponent::Pimpl::MediaSession*> (host))
|
||||
JUCE_VIDEO_LOG ("MediaSession::playCallback()");
|
||||
|
||||
t.requestAudioFocus();
|
||||
|
||||
if (! t.hasAudioFocus)
|
||||
{
|
||||
JUCE_VIDEO_LOG ("MediaSession::playCallback()");
|
||||
|
||||
myself->requestAudioFocus();
|
||||
|
||||
if (! myself->hasAudioFocus)
|
||||
{
|
||||
myself->errorOccurred ("Application has been denied audio focus. Try again later.");
|
||||
return;
|
||||
}
|
||||
|
||||
getEnv()->CallVoidMethod (myself->nativeMediaSession, AndroidMediaSession.setActive, true);
|
||||
|
||||
myself->player.play();
|
||||
myself->setSpeed (myself->playSpeedMult);
|
||||
myself->updatePlaybackState();
|
||||
t.errorOccurred ("Application has been denied audio focus. Try again later.");
|
||||
return;
|
||||
}
|
||||
|
||||
env->CallVoidMethod (t.nativeMediaSession, AndroidMediaSession.setActive, true);
|
||||
|
||||
t.player.play();
|
||||
t.setSpeed (t.playSpeedMult);
|
||||
t.updatePlaybackState();
|
||||
}
|
||||
|
||||
static void playFromMediaIdCallback (JNIEnv* env, jobject, jlong host, jstring mediaId, jobject extras)
|
||||
static void playFromMediaIdCallback (JNIEnv* env, MediaSession& t, jstring mediaId, jobject extras)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<VideoComponent::Pimpl::MediaSession*> (host))
|
||||
{
|
||||
JUCE_VIDEO_LOG ("MediaSession::playFromMediaIdCallback()");
|
||||
JUCE_VIDEO_LOG ("MediaSession::playFromMediaIdCallback()");
|
||||
|
||||
myself->player.load (LocalRef<jstring> ((jstring) env->NewLocalRef(mediaId)), LocalRef<jobject> (env->NewLocalRef(extras)));
|
||||
myself->updatePlaybackState();
|
||||
}
|
||||
t.player.load (LocalRef<jstring> ((jstring) env->NewLocalRef (mediaId)), LocalRef<jobject> (env->NewLocalRef (extras)));
|
||||
t.updatePlaybackState();
|
||||
}
|
||||
|
||||
static void seekToCallback (JNIEnv* /*env*/, jobject, jlong host, jlong pos)
|
||||
static void seekToCallback (JNIEnv*, MediaSession& t, jlong pos)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<VideoComponent::Pimpl::MediaSession*> (host))
|
||||
{
|
||||
JUCE_VIDEO_LOG ("MediaSession::seekToCallback()");
|
||||
JUCE_VIDEO_LOG ("MediaSession::seekToCallback()");
|
||||
|
||||
myself->pendingSeekRequest = true;
|
||||
myself->player.setPlayPosition ((jint) pos);
|
||||
myself->updatePlaybackState();
|
||||
}
|
||||
t.pendingSeekRequest = true;
|
||||
t.player.setPlayPosition ((jint) pos);
|
||||
t.updatePlaybackState();
|
||||
}
|
||||
|
||||
static void stopCallback(JNIEnv* env, jobject, jlong host)
|
||||
static void stopCallback (JNIEnv* env, MediaSession& t)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<VideoComponent::Pimpl::MediaSession*> (host))
|
||||
{
|
||||
JUCE_VIDEO_LOG ("MediaSession::stopCallback()");
|
||||
JUCE_VIDEO_LOG ("MediaSession::stopCallback()");
|
||||
|
||||
env->CallVoidMethod (myself->nativeMediaSession, AndroidMediaSession.setActive, false);
|
||||
env->CallVoidMethod (t.nativeMediaSession, AndroidMediaSession.setActive, false);
|
||||
|
||||
myself->player.closeVideo();
|
||||
myself->updatePlaybackState();
|
||||
t.player.closeVideo();
|
||||
t.updatePlaybackState();
|
||||
|
||||
myself->abandonAudioFocus();
|
||||
t.abandonAudioFocus();
|
||||
|
||||
myself->owner.closeVideoFinished();
|
||||
}
|
||||
t.owner.closeVideoFinished();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -1673,7 +1649,7 @@ private:
|
|||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (constructor, "<init>", "(Landroid/app/Activity;J)V") \
|
||||
METHOD (setEnabled, "setEnabled", "(Z)V") \
|
||||
CALLBACK (systemVolumeChangedCallback, "mediaSessionSystemVolumeChanged", "(J)V")
|
||||
CALLBACK (generatedCallback<&SystemVolumeListener::systemVolumeChanged>, "mediaSessionSystemVolumeChanged", "(J)V")
|
||||
|
||||
DECLARE_JNI_CLASS_WITH_MIN_SDK (SystemVolumeObserver, "com/rmsl/juce/SystemVolumeObserver", 21)
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
|
@ -1693,14 +1669,14 @@ private:
|
|||
|
||||
// Send first notification instantly to ensure sync.
|
||||
if (shouldBeEnabled)
|
||||
systemVolumeChanged();
|
||||
systemVolumeChanged (getEnv(), *this);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void systemVolumeChanged()
|
||||
static void systemVolumeChanged (JNIEnv*, SystemVolumeListener& t)
|
||||
{
|
||||
MessageManager::callAsync ([weakThis = WeakReference<SystemVolumeListener> { this }]() mutable
|
||||
MessageManager::callAsync ([weakThis = WeakReference<SystemVolumeListener> { &t }]
|
||||
{
|
||||
if (weakThis == nullptr)
|
||||
return;
|
||||
|
|
@ -1711,13 +1687,6 @@ private:
|
|||
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void systemVolumeChangedCallback (JNIEnv*, jobject, jlong host)
|
||||
{
|
||||
if (auto* myself = reinterpret_cast<VideoComponent::Pimpl::SystemVolumeListener*> (host))
|
||||
myself->systemVolumeChanged();
|
||||
}
|
||||
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (SystemVolumeListener)
|
||||
};
|
||||
|
||||
|
|
@ -1829,8 +1798,3 @@ private:
|
|||
|
||||
//==============================================================================
|
||||
constexpr VideoComponent::Pimpl::MediaSession::Player::StateInfo VideoComponent::Pimpl::MediaSession::Player::stateInfos[];
|
||||
|
||||
//==============================================================================
|
||||
VideoComponent::Pimpl::MediaSession::AndroidMediaSessionCallback_Class VideoComponent::Pimpl::MediaSession::AndroidMediaSessionCallback;
|
||||
VideoComponent::Pimpl::MediaSession::Controller::AndroidMediaControllerCallback_Class VideoComponent::Pimpl::MediaSession::Controller::AndroidMediaControllerCallback;
|
||||
VideoComponent::Pimpl::SystemVolumeListener::SystemVolumeObserver_Class VideoComponent::Pimpl::SystemVolumeListener::SystemVolumeObserver;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue