| @@ -186,7 +186,6 @@ static const uint8 javaComponentPeerView[] = | |||
| //============================================================================== | |||
| #if JUCE_PUSH_NOTIFICATIONS && JUCE_MODULE_AVAILABLE_juce_gui_extra | |||
| // Returns true if the intent was handled. | |||
| extern bool juce_handleNotificationIntent (void*); | |||
| extern void juce_firebaseDeviceNotificationsTokenRefreshed (void*); | |||
| extern void juce_firebaseRemoteNotificationReceived (void*); | |||
| @@ -197,21 +196,19 @@ static const uint8 javaComponentPeerView[] = | |||
| //============================================================================== | |||
| #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ | |||
| METHOD (create, "<init>", "(II)V") | |||
| METHOD (create, "<init>", "(II)V") | |||
| DECLARE_JNI_CLASS (AndroidLayoutParams, "android/view/ViewGroup$LayoutParams") | |||
| #undef JNI_CLASS_MEMBERS | |||
| //============================================================================== | |||
| #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ | |||
| METHOD (addView, "addView", "(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V") \ | |||
| METHOD (removeView, "removeView", "(Landroid/view/View;)V") \ | |||
| METHOD (updateViewLayout, "updateViewLayout", "(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V") | |||
| METHOD (addView, "addView", "(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V") \ | |||
| METHOD (removeView, "removeView", "(Landroid/view/View;)V") \ | |||
| METHOD (updateViewLayout, "updateViewLayout", "(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V") | |||
| DECLARE_JNI_CLASS (AndroidViewManager, "android/view/ViewManager") | |||
| #undef JNI_CLASS_MEMBERS | |||
| //============================================================================== | |||
| #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ | |||
| METHOD (create, "<init>", "(IIIIIII)V") \ | |||
| FIELD (gravity, "gravity", "I") \ | |||
| @@ -220,7 +217,6 @@ DECLARE_JNI_CLASS (AndroidViewManager, "android/view/ViewManager") | |||
| DECLARE_JNI_CLASS (AndroidWindowManagerLayoutParams, "android/view/WindowManager$LayoutParams") | |||
| #undef JNI_CLASS_MEMBERS | |||
| //============================================================================== | |||
| #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ | |||
| METHOD (getDecorView, "getDecorView", "()Landroid/view/View;") \ | |||
| METHOD (setFlags, "setFlags", "(II)V") \ | |||
| @@ -229,6 +225,7 @@ DECLARE_JNI_CLASS (AndroidWindowManagerLayoutParams, "android/view/WindowManager | |||
| DECLARE_JNI_CLASS (AndroidWindow, "android/view/Window") | |||
| #undef JNI_CLASS_MEMBERS | |||
| //============================================================================== | |||
| namespace | |||
| { | |||
| enum | |||
| @@ -244,7 +241,6 @@ namespace | |||
| }; | |||
| constexpr int fullScreenFlags = SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_IMMERSIVE_STICKY; | |||
| constexpr int FLAG_NOT_FOCUSABLE = 0x8; | |||
| } | |||
| @@ -254,11 +250,7 @@ class AndroidComponentPeer : public ComponentPeer, | |||
| { | |||
| public: | |||
| AndroidComponentPeer (Component& comp, int windowStyleFlags, void* nativeViewHandle) | |||
| : ComponentPeer (comp, windowStyleFlags), | |||
| fullScreen (false), | |||
| navBarsHidden (false), | |||
| sizeAllocated (0), | |||
| scale ((float) Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale) | |||
| : ComponentPeer (comp, windowStyleFlags) | |||
| { | |||
| auto* env = getEnv(); | |||
| @@ -274,7 +266,7 @@ public: | |||
| // we don't know if the user is holding on to a local ref to this, so | |||
| // explicitly create a new one | |||
| auto nativeView = LocalRef<jobject>(env->NewLocalRef(static_cast<jobject> (nativeViewHandle))); | |||
| auto nativeView = LocalRef<jobject> (env->NewLocalRef (static_cast<jobject> (nativeViewHandle))); | |||
| if (env->IsInstanceOf (nativeView.get(), AndroidActivity)) | |||
| { | |||
| @@ -301,10 +293,9 @@ public: | |||
| viewGroupIsWindow = true; | |||
| LocalRef<jobject> viewLayoutParams (env->NewObject (AndroidLayoutParams, AndroidLayoutParams.create, -2, -2)); | |||
| env->CallVoidMethod (view.get(), AndroidView.setLayoutParams, viewLayoutParams.get()); | |||
| Rectangle<int> physicalBounds = comp.getBoundsInParent() * scale; | |||
| auto physicalBounds = (comp.getBoundsInParent().toFloat() * scale).toNearestInt(); | |||
| view.callVoidMethod (AndroidView.layout, | |||
| physicalBounds.getX(), physicalBounds.getY(), physicalBounds.getRight(), physicalBounds.getBottom()); | |||
| @@ -314,6 +305,7 @@ public: | |||
| physicalBounds.getX(), physicalBounds.getY(), | |||
| TYPE_APPLICATION, FLAG_NOT_TOUCH_MODAL | FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_NO_LIMITS | FLAG_NOT_FOCUSABLE, | |||
| component.isOpaque() ? PIXEL_FORMAT_OPAQUE : PIXEL_FORMAT_TRANSPARENT)); | |||
| env->SetIntField (windowLayoutParams.get(), AndroidWindowManagerLayoutParams.gravity, GRAVITY_LEFT | GRAVITY_TOP); | |||
| env->SetIntField (windowLayoutParams.get(), AndroidWindowManagerLayoutParams.windowAnimations, 0x01030000 /* android.R.style.Animation */); | |||
| @@ -335,40 +327,23 @@ public: | |||
| ~AndroidComponentPeer() override | |||
| { | |||
| stopTimer(); | |||
| auto* env = getEnv(); | |||
| env->CallVoidMethod (view, ComponentPeerView.clear); | |||
| frontWindow = nullptr; | |||
| if (MessageManager::getInstance()->isThisTheMessageThread()) | |||
| GlobalRef localView (view); | |||
| GlobalRef localViewGroup (viewGroup); | |||
| callOnMessageThread ([env, localView, localViewGroup] | |||
| { | |||
| if (env->IsInstanceOf (viewGroup.get(), AndroidActivity)) | |||
| env->CallVoidMethod (viewGroup.get(), AndroidActivity.setContentView, nullptr); | |||
| if (env->IsInstanceOf (localViewGroup.get(), AndroidActivity)) | |||
| env->CallVoidMethod (localViewGroup.get(), AndroidActivity.setContentView, nullptr); | |||
| else | |||
| env->CallVoidMethod (viewGroup.get(), AndroidViewManager.removeView, view.get()); | |||
| } | |||
| else | |||
| { | |||
| struct ViewDeleter : public CallbackMessage | |||
| { | |||
| ViewDeleter (const GlobalRef& view_, const GlobalRef& viewGroup_) : view (view_), group (viewGroup_) {} | |||
| void messageCallback() override | |||
| { | |||
| auto* callbackEnv = getEnv(); | |||
| if (callbackEnv->IsInstanceOf (group.get(), AndroidActivity)) | |||
| callbackEnv->CallVoidMethod (group.get(), AndroidActivity.setContentView, nullptr); | |||
| else | |||
| callbackEnv->CallVoidMethod (group.get(), AndroidViewManager.removeView, view.get()); | |||
| } | |||
| private: | |||
| GlobalRef view, group; | |||
| }; | |||
| (new ViewDeleter (view, viewGroup))->post(); | |||
| } | |||
| env->CallVoidMethod (localViewGroup.get(), AndroidViewManager.removeView, localView.get()); | |||
| }); | |||
| } | |||
| void* getNativeHandle() const override | |||
| @@ -378,29 +353,12 @@ public: | |||
| void setVisible (bool shouldBeVisible) override | |||
| { | |||
| if (MessageManager::getInstance()->isThisTheMessageThread()) | |||
| { | |||
| view.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible); | |||
| } | |||
| else | |||
| { | |||
| struct VisibilityChanger : public CallbackMessage | |||
| { | |||
| VisibilityChanger (const GlobalRef& view_, bool shouldBeVisible_) | |||
| : view (view_), shouldBeVisible (shouldBeVisible_) | |||
| {} | |||
| GlobalRef localView (view); | |||
| void messageCallback() override | |||
| { | |||
| view.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible); | |||
| } | |||
| GlobalRef view; | |||
| bool shouldBeVisible; | |||
| }; | |||
| (new VisibilityChanger (view, shouldBeVisible))->post(); | |||
| } | |||
| callOnMessageThread ([localView, shouldBeVisible] | |||
| { | |||
| localView.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible); | |||
| }); | |||
| } | |||
| void setTitle (const String& title) override | |||
| @@ -410,60 +368,48 @@ public: | |||
| void setBounds (const Rectangle<int>& userRect, bool isNowFullScreen) override | |||
| { | |||
| Rectangle<int> r = (userRect.toFloat() * scale).toNearestInt(); | |||
| auto bounds = (userRect.toFloat() * scale).toNearestInt(); | |||
| if (MessageManager::getInstance()->isThisTheMessageThread()) | |||
| { | |||
| auto* env = getEnv(); | |||
| fullScreen = isNowFullScreen; | |||
| view.callVoidMethod (AndroidView.layout, | |||
| bounds.getX(), bounds.getY(), bounds.getRight(), bounds.getBottom()); | |||
| if (viewGroup != nullptr && viewGroupIsWindow) | |||
| { | |||
| view.callVoidMethod (AndroidView.layout, | |||
| r.getX(), r.getY(), r.getRight(), r.getBottom()); | |||
| auto* env = getEnv(); | |||
| if (viewGroup != nullptr && viewGroupIsWindow) | |||
| { | |||
| LocalRef<jobject> windowLayoutParams (env->NewObject (AndroidWindowManagerLayoutParams, AndroidWindowManagerLayoutParams.create, | |||
| r.getWidth(), r.getHeight(), | |||
| r.getX(), r.getY(), | |||
| TYPE_APPLICATION, FLAG_NOT_TOUCH_MODAL | FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_NO_LIMITS, | |||
| component.isOpaque() ? PIXEL_FORMAT_OPAQUE : PIXEL_FORMAT_TRANSPARENT)); | |||
| env->SetIntField (windowLayoutParams.get(), AndroidWindowManagerLayoutParams.gravity, 0x3 /* LEFT */ | 0x30 /* TOP */); | |||
| env->CallVoidMethod (viewGroup.get(), AndroidViewManager.updateViewLayout, view.get(), windowLayoutParams.get()); | |||
| } | |||
| LocalRef<jobject> windowLayoutParams (env->NewObject (AndroidWindowManagerLayoutParams, AndroidWindowManagerLayoutParams.create, | |||
| bounds.getWidth(), bounds.getHeight(), bounds.getX(), bounds.getY(), | |||
| TYPE_APPLICATION, FLAG_NOT_TOUCH_MODAL | FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_NO_LIMITS, | |||
| component.isOpaque() ? PIXEL_FORMAT_OPAQUE : PIXEL_FORMAT_TRANSPARENT)); | |||
| env->SetIntField (windowLayoutParams.get(), AndroidWindowManagerLayoutParams.gravity, GRAVITY_LEFT | GRAVITY_TOP); | |||
| env->CallVoidMethod (viewGroup.get(), AndroidViewManager.updateViewLayout, view.get(), windowLayoutParams.get()); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| class ViewMover : public CallbackMessage | |||
| { | |||
| public: | |||
| ViewMover (const GlobalRef& v, Rectangle<int> boundsToUse) : view (v), bounds (boundsToUse) {} | |||
| void messageCallback() override | |||
| { | |||
| view.callVoidMethod (AndroidView.layout, | |||
| bounds.getX(), bounds.getY(), bounds.getRight(), bounds.getBottom()); | |||
| } | |||
| private: | |||
| GlobalRef view; | |||
| Rectangle<int> bounds; | |||
| }; | |||
| GlobalRef localView (view); | |||
| (new ViewMover (view, r))->post(); | |||
| MessageManager::callAsync ([localView, bounds] | |||
| { | |||
| localView.callVoidMethod (AndroidView.layout, | |||
| bounds.getX(), bounds.getY(), bounds.getRight(), bounds.getBottom()); | |||
| }); | |||
| } | |||
| } | |||
| Rectangle<int> getBounds() const override | |||
| { | |||
| Rectangle<int> r (view.callIntMethod (AndroidView.getLeft), | |||
| view.callIntMethod (AndroidView.getTop), | |||
| view.callIntMethod (AndroidView.getWidth), | |||
| view.callIntMethod (AndroidView.getHeight)); | |||
| Rectangle<int> bounds (view.callIntMethod (AndroidView.getLeft), | |||
| view.callIntMethod (AndroidView.getTop), | |||
| view.callIntMethod (AndroidView.getWidth), | |||
| view.callIntMethod (AndroidView.getHeight)); | |||
| return r / scale; | |||
| return (bounds.toFloat() / scale).toNearestInt(); | |||
| } | |||
| void handleScreenSizeChange() override | |||
| @@ -512,49 +458,32 @@ public: | |||
| return false; | |||
| } | |||
| bool shouldNavBarsBeHidden (bool shouldBeFullScreen) const | |||
| { | |||
| if (shouldBeFullScreen) | |||
| if (Component* kiosk = Desktop::getInstance().getKioskModeComponent()) | |||
| if (kiosk->getPeer() == this) | |||
| return true; | |||
| return false; | |||
| } | |||
| void setNavBarsHidden (bool hidden) | |||
| { | |||
| view.callVoidMethod (ComponentPeerView.setSystemUiVisibilityCompat, | |||
| hidden ? (jint) (fullScreenFlags) | |||
| : (jint) (SYSTEM_UI_FLAG_VISIBLE)); | |||
| navBarsHidden = hidden; | |||
| } | |||
| void setFullScreen (bool shouldBeFullScreen) override | |||
| { | |||
| // updating the nav bar visibility is a bit odd on Android - need to wait for | |||
| if (shouldNavBarsBeHidden (shouldBeFullScreen)) | |||
| { | |||
| if (! isTimerRunning()) | |||
| { | |||
| startTimer (500); | |||
| } | |||
| if (isTimerRunning()) | |||
| return; | |||
| startTimer (500); | |||
| } | |||
| else | |||
| { | |||
| setNavBarsHidden (false); | |||
| } | |||
| Rectangle<int> r (shouldBeFullScreen ? Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea | |||
| : lastNonFullscreenBounds); | |||
| auto newBounds = [&] | |||
| { | |||
| if (navBarsHidden || shouldBeFullScreen) | |||
| if (auto* display = Desktop::getInstance().getDisplays().getPrimaryDisplay()) | |||
| return navBarsHidden ? display->totalArea | |||
| : display->userArea; | |||
| if ((! shouldBeFullScreen) && r.isEmpty()) | |||
| r = getBounds(); | |||
| return lastNonFullscreenBounds.isEmpty() ? getBounds() : lastNonFullscreenBounds; | |||
| }(); | |||
| // (can't call the component's setBounds method because that'll reset our fullscreen flag) | |||
| if (! r.isEmpty()) | |||
| setBounds (r, shouldBeFullScreen); | |||
| if (! newBounds.isEmpty()) | |||
| setBounds (newBounds, shouldBeFullScreen); | |||
| component.repaint(); | |||
| } | |||
| @@ -564,13 +493,6 @@ public: | |||
| return fullScreen; | |||
| } | |||
| void timerCallback() override | |||
| { | |||
| setNavBarsHidden (shouldNavBarsBeHidden (fullScreen)); | |||
| setFullScreen (fullScreen); | |||
| stopTimer(); | |||
| } | |||
| void setIcon (const Image& /*newIcon*/) override | |||
| { | |||
| // n/a | |||
| @@ -588,7 +510,7 @@ public: | |||
| BorderSize<int> getFrameSize() const override | |||
| { | |||
| // TODO | |||
| return BorderSize<int>(); | |||
| return {}; | |||
| } | |||
| bool setAlwaysOnTop (bool /*alwaysOnTop*/) override | |||
| @@ -603,7 +525,6 @@ public: | |||
| if (frontWindow != this) | |||
| { | |||
| view.callVoidMethod (AndroidView.bringToFront); | |||
| frontWindow = this; | |||
| } | |||
| @@ -622,11 +543,17 @@ public: | |||
| void handleMouseDownCallback (int index, Point<float> sysPos, int64 time) | |||
| { | |||
| lastMousePos = sysPos / scale; | |||
| Point<float> pos = globalToLocal (lastMousePos); | |||
| auto pos = globalToLocal (lastMousePos); | |||
| // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | |||
| handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, ModifierKeys::currentModifiers.withoutMouseButtons(), | |||
| MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, time, {}, index); | |||
| handleMouseEvent (MouseInputSource::InputSourceType::touch, | |||
| pos, | |||
| ModifierKeys::currentModifiers.withoutMouseButtons(), | |||
| MouseInputSource::invalidPressure, | |||
| MouseInputSource::invalidOrientation, | |||
| time, | |||
| {}, | |||
| index); | |||
| if (isValidPeer (this)) | |||
| handleMouseDragCallback (index, sysPos, time); | |||
| @@ -635,19 +562,27 @@ public: | |||
| void handleMouseDragCallback (int index, Point<float> sysPos, int64 time) | |||
| { | |||
| lastMousePos = sysPos / scale; | |||
| Point<float> pos = globalToLocal (lastMousePos); | |||
| auto pos = globalToLocal (lastMousePos); | |||
| jassert (index < 64); | |||
| touchesDown = (touchesDown | (1 << (index & 63))); | |||
| ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); | |||
| handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, ModifierKeys::currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier), | |||
| MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, time, {}, index); | |||
| handleMouseEvent (MouseInputSource::InputSourceType::touch, | |||
| pos, | |||
| ModifierKeys::currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier), | |||
| MouseInputSource::invalidPressure, | |||
| MouseInputSource::invalidOrientation, | |||
| time, | |||
| {}, | |||
| index); | |||
| } | |||
| void handleMouseUpCallback (int index, Point<float> sysPos, int64 time) | |||
| { | |||
| lastMousePos = sysPos / scale; | |||
| Point<float> pos = globalToLocal (lastMousePos); | |||
| auto pos = globalToLocal (lastMousePos); | |||
| jassert (index < 64); | |||
| touchesDown = (touchesDown & ~(1 << (index & 63))); | |||
| @@ -655,8 +590,14 @@ public: | |||
| if (touchesDown == 0) | |||
| ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutMouseButtons(); | |||
| handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, ModifierKeys::currentModifiers.withoutMouseButtons(), MouseInputSource::invalidPressure, | |||
| MouseInputSource::invalidOrientation, time, {}, index); | |||
| handleMouseEvent (MouseInputSource::InputSourceType::touch, | |||
| pos, | |||
| ModifierKeys::currentModifiers.withoutMouseButtons(), | |||
| MouseInputSource::invalidPressure, | |||
| MouseInputSource::invalidOrientation, | |||
| time, | |||
| {}, | |||
| index); | |||
| } | |||
| void handleKeyDownCallback (int k, int kc) | |||
| @@ -675,9 +616,8 @@ public: | |||
| if (auto* app = JUCEApplicationBase::getInstance()) | |||
| handled = app->backButtonPressed(); | |||
| if (Component* kiosk = Desktop::getInstance().getKioskModeComponent()) | |||
| if (kiosk->getPeer() == this) | |||
| setNavBarsHidden (navBarsHidden); | |||
| if (isKioskModeComponent()) | |||
| setNavBarsHidden (navBarsHidden); | |||
| if (! handled) | |||
| { | |||
| @@ -692,7 +632,6 @@ public: | |||
| env->CallVoidMethod (activity.get(), finishMethod); | |||
| } | |||
| } | |||
| } | |||
| void handleKeyboardHiddenCallback() | |||
| @@ -704,9 +643,8 @@ public: | |||
| void handleAppResumedCallback() | |||
| { | |||
| if (Component* kiosk = Desktop::getInstance().getKioskModeComponent()) | |||
| if (kiosk->getPeer() == this) | |||
| setNavBarsHidden (navBarsHidden); | |||
| if (isKioskModeComponent()) | |||
| setNavBarsHidden (navBarsHidden); | |||
| } | |||
| //============================================================================== | |||
| @@ -761,41 +699,35 @@ public: | |||
| { | |||
| view.callVoidMethod (ComponentPeerView.showKeyboard, javaString ("").get()); | |||
| // updating the nav bar visibility is a bit odd on Android - need to wait for | |||
| if (! isTimerRunning()) | |||
| hideNavBarDelayed(); | |||
| startTimer (500); | |||
| } | |||
| void hideNavBarDelayed() | |||
| { | |||
| startTimer (500); | |||
| } | |||
| //============================================================================== | |||
| void handlePaintCallback (jobject canvas, jobject paint) | |||
| { | |||
| auto* env = getEnv(); | |||
| jobject rect = env->CallObjectMethod (canvas, AndroidCanvas.getClipBounds); | |||
| const int left = env->GetIntField (rect, AndroidRect.left); | |||
| const int top = env->GetIntField (rect, AndroidRect.top); | |||
| const int right = env->GetIntField (rect, AndroidRect.right); | |||
| const int bottom = env->GetIntField (rect, AndroidRect.bottom); | |||
| auto left = env->GetIntField (rect, AndroidRect.left); | |||
| auto top = env->GetIntField (rect, AndroidRect.top); | |||
| auto right = env->GetIntField (rect, AndroidRect.right); | |||
| auto bottom = env->GetIntField (rect, AndroidRect.bottom); | |||
| env->DeleteLocalRef (rect); | |||
| const Rectangle<int> clip (left, top, right - left, bottom - top); | |||
| auto clip = Rectangle<int>::leftTopRightBottom (left, top, right, bottom); | |||
| if (clip.isEmpty()) | |||
| return; | |||
| auto sizeNeeded = clip.getWidth() * clip.getHeight(); | |||
| const int sizeNeeded = clip.getWidth() * clip.getHeight(); | |||
| if (sizeAllocated < sizeNeeded) | |||
| { | |||
| buffer.clear(); | |||
| sizeAllocated = sizeNeeded; | |||
| buffer = GlobalRef (LocalRef<jobject> ((jobject) env->NewIntArray (sizeNeeded))); | |||
| } | |||
| else if (sizeNeeded == 0) | |||
| { | |||
| return; | |||
| } | |||
| if (jint* dest = env->GetIntArrayElements ((jintArray) buffer.get(), nullptr)) | |||
| { | |||
| @@ -821,32 +753,15 @@ public: | |||
| void repaint (const Rectangle<int>& userArea) override | |||
| { | |||
| Rectangle<int> area = userArea * scale; | |||
| auto area = (userArea.toFloat() * scale).toNearestInt(); | |||
| if (MessageManager::getInstance()->isThisTheMessageThread()) | |||
| { | |||
| view.callVoidMethod (AndroidView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); | |||
| } | |||
| else | |||
| { | |||
| struct ViewRepainter : public CallbackMessage | |||
| { | |||
| ViewRepainter (const GlobalRef& view_, const Rectangle<int>& area_) | |||
| : view (view_), area (area_) {} | |||
| GlobalRef localView (view); | |||
| void messageCallback() override | |||
| { | |||
| view.callVoidMethod (AndroidView.invalidate, area.getX(), area.getY(), | |||
| area.getRight(), area.getBottom()); | |||
| } | |||
| private: | |||
| GlobalRef view; | |||
| const Rectangle<int> area; | |||
| }; | |||
| (new ViewRepainter (view, area))->post(); | |||
| } | |||
| callOnMessageThread ([area, localView] | |||
| { | |||
| localView.callVoidMethod (AndroidView.invalidate, | |||
| area.getX(), area.getY(), area.getRight(), area.getBottom()); | |||
| }); | |||
| } | |||
| void performAnyPendingRepaintsNow() override | |||
| @@ -878,28 +793,18 @@ public: | |||
| if (appContext.get() != nullptr) | |||
| { | |||
| env->CallVoidMethod (appContext.get(), | |||
| AndroidApplication.unregisterActivityLifecycleCallbacks, | |||
| activityCallbackListener.get()); | |||
| clear(); | |||
| activityCallbackListener.clear(); | |||
| const_cast<Displays &> (Desktop::getInstance().getDisplays()).refresh(); | |||
| const_cast<Displays&> (Desktop::getInstance().getDisplays()).refresh(); | |||
| } | |||
| } | |||
| }; | |||
| private: | |||
| //============================================================================== | |||
| GlobalRef view, viewGroup; | |||
| bool viewGroupIsWindow = false; | |||
| GlobalRef buffer; | |||
| bool fullScreen; | |||
| bool navBarsHidden; | |||
| int sizeAllocated; | |||
| float scale; | |||
| //============================================================================== | |||
| #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ | |||
| METHOD (create, "<init>", "(Landroid/content/Context;ZJ)V") \ | |||
| @@ -940,16 +845,6 @@ private: | |||
| static void JNICALL handleAppResumedJni (JNIEnv*, jobject /*view*/, jlong host) { if (auto* myself = reinterpret_cast<AndroidComponentPeer*> (host)) myself->handleAppResumedCallback(); } | |||
| //============================================================================== | |||
| friend class Displays; | |||
| static AndroidComponentPeer* frontWindow; | |||
| static GlobalRef activityCallbackListener; | |||
| //============================================================================== | |||
| static constexpr int GRAVITY_LEFT = 0x3, GRAVITY_TOP = 0x30; | |||
| static constexpr int TYPE_APPLICATION = 0x2; | |||
| static constexpr int FLAG_NOT_TOUCH_MODAL = 0x20, FLAG_LAYOUT_IN_SCREEN = 0x100, FLAG_LAYOUT_NO_LIMITS = 0x200; | |||
| static constexpr int PIXEL_FORMAT_OPAQUE = -1, PIXEL_FORMAT_TRANSPARENT = -2; | |||
| struct PreallocatedImage : public ImagePixelData | |||
| { | |||
| PreallocatedImage (int width_, int height_, jint* data_, bool hasAlpha_) | |||
| @@ -1008,6 +903,63 @@ private: | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreallocatedImage) | |||
| }; | |||
| //============================================================================== | |||
| void timerCallback() override | |||
| { | |||
| setNavBarsHidden (shouldNavBarsBeHidden (fullScreen)); | |||
| setFullScreen (fullScreen); | |||
| stopTimer(); | |||
| } | |||
| bool isKioskModeComponent() const | |||
| { | |||
| if (auto* kiosk = Desktop::getInstance().getKioskModeComponent()) | |||
| return kiosk->getPeer() == this; | |||
| return false; | |||
| } | |||
| bool shouldNavBarsBeHidden (bool shouldBeFullScreen) const | |||
| { | |||
| return (shouldBeFullScreen && isKioskModeComponent()); | |||
| } | |||
| void setNavBarsHidden (bool hidden) | |||
| { | |||
| if (navBarsHidden != hidden) | |||
| { | |||
| navBarsHidden = hidden; | |||
| view.callVoidMethod (ComponentPeerView.setSystemUiVisibilityCompat, | |||
| (navBarsHidden ? (jint) (fullScreenFlags) : (jint) (SYSTEM_UI_FLAG_VISIBLE))); | |||
| } | |||
| } | |||
| template <typename Callback> | |||
| static void callOnMessageThread (Callback&& callback) | |||
| { | |||
| if (MessageManager::getInstance()->isThisTheMessageThread()) | |||
| callback(); | |||
| else | |||
| MessageManager::callAsync (std::forward<Callback> (callback)); | |||
| } | |||
| //============================================================================== | |||
| friend class Displays; | |||
| static AndroidComponentPeer* frontWindow; | |||
| static GlobalRef activityCallbackListener; | |||
| static constexpr int GRAVITY_LEFT = 0x3, GRAVITY_TOP = 0x30; | |||
| static constexpr int TYPE_APPLICATION = 0x2; | |||
| static constexpr int FLAG_NOT_TOUCH_MODAL = 0x20, FLAG_LAYOUT_IN_SCREEN = 0x100, FLAG_LAYOUT_NO_LIMITS = 0x200; | |||
| static constexpr int PIXEL_FORMAT_OPAQUE = -1, PIXEL_FORMAT_TRANSPARENT = -2; | |||
| GlobalRef view, viewGroup, buffer; | |||
| bool viewGroupIsWindow = false, fullScreen = false, navBarsHidden = false; | |||
| int sizeAllocated = 0; | |||
| float scale = (float) Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale; | |||
| //============================================================================== | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidComponentPeer) | |||
| }; | |||
| @@ -1430,7 +1382,7 @@ public: | |||
| auto& displays = Desktop::getInstance().getDisplays(); | |||
| auto& mainDisplay = *displays.getPrimaryDisplay(); | |||
| Rectangle<int> userArea = newBounds / mainDisplay.scale; | |||
| auto userArea = (newBounds.toFloat() / mainDisplay.scale).toNearestInt(); | |||
| if (userArea != mainDisplay.userArea) | |||
| const_cast<Displays&> (displays).refresh(); | |||