/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2022 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. By using JUCE, you agree to the terms of both the JUCE 7 End-User License Agreement and JUCE Privacy Policy. End User License Agreement: www.juce.com/juce-7-licence Privacy Policy: www.juce.com/juce-privacy-policy Or: You may also use this code under the terms of the GPL v3 (see www.gnu.org/licenses). JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ namespace juce { class AndroidViewComponent::Pimpl : public ComponentMovementWatcher { public: Pimpl (const LocalRef& v, Component& comp) : ComponentMovementWatcher (&comp), view (v), owner (comp) { if (owner.isShowing()) componentPeerChanged(); } ~Pimpl() override { removeFromParent(); } void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override { auto* topComp = owner.getTopLevelComponent(); if (topComp->getPeer() != nullptr) { auto pos = topComp->getLocalPoint (&owner, Point()); Rectangle r (pos.x, pos.y, owner.getWidth(), owner.getHeight()); r *= Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale; getEnv()->CallVoidMethod (view, AndroidView.layout, r.getX(), r.getY(), r.getRight(), r.getBottom()); } } void componentPeerChanged() override { auto* peer = owner.getPeer(); if (currentPeer != peer) { removeFromParent(); currentPeer = peer; addToParent(); } enum { VISIBLE = 0, INVISIBLE = 4 }; getEnv()->CallVoidMethod (view, AndroidView.setVisibility, owner.isShowing() ? VISIBLE : INVISIBLE); } void componentVisibilityChanged() override { componentPeerChanged(); } void componentBroughtToFront (Component& comp) override { ComponentMovementWatcher::componentBroughtToFront (comp); } Rectangle getViewBounds() const { auto* env = getEnv(); int width = env->CallIntMethod (view, AndroidView.getWidth); int height = env->CallIntMethod (view, AndroidView.getHeight); return Rectangle (width, height); } GlobalRef view; private: void addToParent() { if (currentPeer != nullptr) { jobject peerView = (jobject) currentPeer->getNativeHandle(); // NB: Assuming a parent is always of ViewGroup type auto* env = getEnv(); env->CallVoidMethod (peerView, AndroidViewGroup.addView, view.get()); componentMovedOrResized (false, false); } } void removeFromParent() { auto* env = getEnv(); auto parentView = env->CallObjectMethod (view, AndroidView.getParent); if (parentView != nullptr) { // Assuming a parent is always of ViewGroup type env->CallVoidMethod (parentView, AndroidViewGroup.removeView, view.get()); } } Component& owner; ComponentPeer* currentPeer = nullptr; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) }; //============================================================================== AndroidViewComponent::AndroidViewComponent() { } AndroidViewComponent::~AndroidViewComponent() {} void AndroidViewComponent::setView (void* view) { if (view != getView()) { pimpl.reset(); if (view != nullptr) { // explicitly create a new local ref here so that we don't // delete the users pointer auto* env = getEnv(); auto localref = LocalRef(env->NewLocalRef((jobject) view)); pimpl.reset (new Pimpl (localref, *this)); } } } void* AndroidViewComponent::getView() const { return pimpl == nullptr ? nullptr : (void*) pimpl->view; } void AndroidViewComponent::resizeToFitView() { if (pimpl != nullptr) setBounds (pimpl->getViewBounds()); } void AndroidViewComponent::paint (Graphics&) {} } // namespace juce