The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

980 lines
38KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. } // (juce namespace)
  18. extern juce::JUCEApplicationBase* juce_CreateApplication(); // (from START_JUCE_APPLICATION)
  19. namespace juce
  20. {
  21. //==============================================================================
  22. JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, launchApp, void, (JNIEnv* env, jobject activity,
  23. jstring appFile, jstring appDataDir))
  24. {
  25. setEnv (env);
  26. android.initialise (env, activity, appFile, appDataDir);
  27. DBG (SystemStats::getJUCEVersion());
  28. JUCEApplicationBase::createInstance = &juce_CreateApplication;
  29. initialiseJuce_GUI();
  30. if (JUCEApplicationBase* app = JUCEApplicationBase::createInstance())
  31. {
  32. if (! app->initialiseApp())
  33. exit (app->shutdownApp());
  34. }
  35. else
  36. {
  37. jassertfalse; // you must supply an application object for an android app!
  38. }
  39. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  40. }
  41. JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, suspendApp, void, (JNIEnv* env, jobject))
  42. {
  43. setEnv (env);
  44. if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
  45. app->suspended();
  46. }
  47. JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, resumeApp, void, (JNIEnv* env, jobject))
  48. {
  49. setEnv (env);
  50. if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
  51. app->resumed();
  52. }
  53. JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, quitApp, void, (JNIEnv* env, jobject))
  54. {
  55. setEnv (env);
  56. JUCEApplicationBase::appWillTerminateByForce();
  57. android.shutdown (env);
  58. }
  59. //==============================================================================
  60. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
  61. METHOD (drawBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \
  62. METHOD (getClipBounds, "getClipBounds", "()Landroid/graphics/Rect;")
  63. DECLARE_JNI_CLASS (CanvasMinimal, "android/graphics/Canvas");
  64. #undef JNI_CLASS_MEMBERS
  65. //==============================================================================
  66. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
  67. METHOD (setViewName, "setViewName", "(Ljava/lang/String;)V") \
  68. METHOD (layout, "layout", "(IIII)V") \
  69. METHOD (getLeft, "getLeft", "()I") \
  70. METHOD (getTop, "getTop", "()I") \
  71. METHOD (getWidth, "getWidth", "()I") \
  72. METHOD (getHeight, "getHeight", "()I") \
  73. METHOD (getLocationOnScreen, "getLocationOnScreen", "([I)V") \
  74. METHOD (bringToFront, "bringToFront", "()V") \
  75. METHOD (requestFocus, "requestFocus", "()Z") \
  76. METHOD (setVisible, "setVisible", "(Z)V") \
  77. METHOD (isVisible, "isVisible", "()Z") \
  78. METHOD (hasFocus, "hasFocus", "()Z") \
  79. METHOD (invalidate, "invalidate", "(IIII)V") \
  80. METHOD (containsPoint, "containsPoint", "(II)Z") \
  81. METHOD (showKeyboard, "showKeyboard", "(Ljava/lang/String;)V") \
  82. METHOD (setSystemUiVisibility, "setSystemUiVisibilityCompat", "(I)V") \
  83. DECLARE_JNI_CLASS (ComponentPeerView, JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView");
  84. #undef JNI_CLASS_MEMBERS
  85. //==============================================================================
  86. class AndroidComponentPeer : public ComponentPeer,
  87. private Timer
  88. {
  89. public:
  90. AndroidComponentPeer (Component& comp, const int windowStyleFlags)
  91. : ComponentPeer (comp, windowStyleFlags),
  92. usingAndroidGraphics (false),
  93. fullScreen (false),
  94. sizeAllocated (0),
  95. scale ((float) Desktop::getInstance().getDisplays().getMainDisplay().scale)
  96. {
  97. // NB: must not put this in the initialiser list, as it invokes a callback,
  98. // which will fail if the peer is only half-constructed.
  99. view = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.createNewView,
  100. (jboolean) component.isOpaque(),
  101. (jlong) this));
  102. if (isFocused())
  103. handleFocusGain();
  104. }
  105. ~AndroidComponentPeer()
  106. {
  107. if (MessageManager::getInstance()->isThisTheMessageThread())
  108. {
  109. frontWindow = nullptr;
  110. android.activity.callVoidMethod (JuceAppActivity.deleteView, view.get());
  111. }
  112. else
  113. {
  114. struct ViewDeleter : public CallbackMessage
  115. {
  116. ViewDeleter (const GlobalRef& view_) : view (view_) {}
  117. void messageCallback() override
  118. {
  119. android.activity.callVoidMethod (JuceAppActivity.deleteView, view.get());
  120. }
  121. private:
  122. GlobalRef view;
  123. };
  124. (new ViewDeleter (view))->post();
  125. }
  126. view.clear();
  127. }
  128. void* getNativeHandle() const override
  129. {
  130. return (void*) view.get();
  131. }
  132. void setVisible (bool shouldBeVisible) override
  133. {
  134. if (MessageManager::getInstance()->isThisTheMessageThread())
  135. {
  136. view.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible);
  137. }
  138. else
  139. {
  140. struct VisibilityChanger : public CallbackMessage
  141. {
  142. VisibilityChanger (const GlobalRef& view_, bool shouldBeVisible_)
  143. : view (view_), shouldBeVisible (shouldBeVisible_)
  144. {}
  145. void messageCallback() override
  146. {
  147. view.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible);
  148. }
  149. GlobalRef view;
  150. bool shouldBeVisible;
  151. };
  152. (new VisibilityChanger (view, shouldBeVisible))->post();
  153. }
  154. }
  155. void setTitle (const String& title) override
  156. {
  157. view.callVoidMethod (ComponentPeerView.setViewName, javaString (title).get());
  158. }
  159. void setBounds (const Rectangle<int>& userRect, bool isNowFullScreen) override
  160. {
  161. Rectangle<int> r = (userRect.toFloat() * scale).toNearestInt();
  162. if (MessageManager::getInstance()->isThisTheMessageThread())
  163. {
  164. fullScreen = isNowFullScreen;
  165. view.callVoidMethod (ComponentPeerView.layout,
  166. r.getX(), r.getY(), r.getRight(), r.getBottom());
  167. }
  168. else
  169. {
  170. class ViewMover : public CallbackMessage
  171. {
  172. public:
  173. ViewMover (const GlobalRef& v, const Rectangle<int>& boundsToUse) : view (v), bounds (boundsToUse) {}
  174. void messageCallback() override
  175. {
  176. view.callVoidMethod (ComponentPeerView.layout,
  177. bounds.getX(), bounds.getY(), bounds.getRight(), bounds.getBottom());
  178. }
  179. private:
  180. GlobalRef view;
  181. Rectangle<int> bounds;
  182. };
  183. (new ViewMover (view, r))->post();
  184. }
  185. }
  186. Rectangle<int> getBounds() const override
  187. {
  188. return (Rectangle<float> (view.callIntMethod (ComponentPeerView.getLeft),
  189. view.callIntMethod (ComponentPeerView.getTop),
  190. view.callIntMethod (ComponentPeerView.getWidth),
  191. view.callIntMethod (ComponentPeerView.getHeight)) / scale).toNearestInt();
  192. }
  193. void handleScreenSizeChange() override
  194. {
  195. ComponentPeer::handleScreenSizeChange();
  196. if (isFullScreen())
  197. setFullScreen (true);
  198. }
  199. Point<int> getScreenPosition() const
  200. {
  201. return Point<int> (view.callIntMethod (ComponentPeerView.getLeft),
  202. view.callIntMethod (ComponentPeerView.getTop)) / scale;
  203. }
  204. Point<float> localToGlobal (Point<float> relativePosition) override
  205. {
  206. return relativePosition + getScreenPosition().toFloat();
  207. }
  208. Point<float> globalToLocal (Point<float> screenPosition) override
  209. {
  210. return screenPosition - getScreenPosition().toFloat();
  211. }
  212. void setMinimised (bool /*shouldBeMinimised*/) override
  213. {
  214. // n/a
  215. }
  216. bool isMinimised() const override
  217. {
  218. return false;
  219. }
  220. bool shouldNavBarsBeHidden() const
  221. {
  222. if (fullScreen)
  223. if (Component* kiosk = Desktop::getInstance().getKioskModeComponent())
  224. if (kiosk->getPeer() == this)
  225. return true;
  226. return false;
  227. }
  228. void setNavBarsHidden (bool hidden) const
  229. {
  230. enum
  231. {
  232. SYSTEM_UI_FLAG_VISIBLE = 0,
  233. SYSTEM_UI_FLAG_LOW_PROFILE = 1,
  234. SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2,
  235. SYSTEM_UI_FLAG_FULLSCREEN = 4,
  236. SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512,
  237. SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024,
  238. SYSTEM_UI_FLAG_IMMERSIVE = 2048,
  239. SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 4096
  240. };
  241. view.callVoidMethod (ComponentPeerView.setSystemUiVisibility,
  242. hidden ? (jint) (SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
  243. : (jint) (SYSTEM_UI_FLAG_VISIBLE));
  244. }
  245. void setFullScreen (bool shouldBeFullScreen) override
  246. {
  247. // updating the nav bar visibility is a bit odd on Android - need to wait for
  248. if (shouldNavBarsBeHidden())
  249. {
  250. if (! isTimerRunning())
  251. startTimer (500);
  252. }
  253. else
  254. setNavBarsHidden (false);
  255. Rectangle<int> r (shouldBeFullScreen ? Desktop::getInstance().getDisplays().getMainDisplay().userArea
  256. : lastNonFullscreenBounds);
  257. if ((! shouldBeFullScreen) && r.isEmpty())
  258. r = getBounds();
  259. // (can't call the component's setBounds method because that'll reset our fullscreen flag)
  260. if (! r.isEmpty())
  261. setBounds (r, shouldBeFullScreen);
  262. component.repaint();
  263. }
  264. bool isFullScreen() const override
  265. {
  266. return fullScreen;
  267. }
  268. void timerCallback() override
  269. {
  270. setNavBarsHidden (shouldNavBarsBeHidden());
  271. setFullScreen (fullScreen);
  272. stopTimer();
  273. }
  274. void setIcon (const Image& /*newIcon*/) override
  275. {
  276. // n/a
  277. }
  278. bool contains (Point<int> localPos, bool trueIfInAChildWindow) const override
  279. {
  280. return isPositiveAndBelow (localPos.x, component.getWidth())
  281. && isPositiveAndBelow (localPos.y, component.getHeight())
  282. && ((! trueIfInAChildWindow) || view.callBooleanMethod (ComponentPeerView.containsPoint,
  283. localPos.x * scale,
  284. localPos.y * scale));
  285. }
  286. BorderSize<int> getFrameSize() const override
  287. {
  288. // TODO
  289. return BorderSize<int>();
  290. }
  291. bool setAlwaysOnTop (bool /*alwaysOnTop*/) override
  292. {
  293. // TODO
  294. return false;
  295. }
  296. void toFront (bool makeActive) override
  297. {
  298. // Avoid calling bringToFront excessively: it's very slow
  299. if (frontWindow != this)
  300. {
  301. view.callVoidMethod (ComponentPeerView.bringToFront);
  302. frontWindow = this;
  303. }
  304. if (makeActive)
  305. grabFocus();
  306. handleBroughtToFront();
  307. }
  308. void toBehind (ComponentPeer*) override
  309. {
  310. // TODO
  311. }
  312. //==============================================================================
  313. void handleMouseDownCallback (int index, Point<float> sysPos, int64 time)
  314. {
  315. Point<float> pos = sysPos / scale;
  316. lastMousePos = pos;
  317. // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before.
  318. handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, currentModifiers.withoutMouseButtons(),
  319. MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, time, {}, index);
  320. if (isValidPeer (this))
  321. handleMouseDragCallback (index, sysPos, time);
  322. }
  323. void handleMouseDragCallback (int index, Point<float> pos, int64 time)
  324. {
  325. pos /= scale;
  326. lastMousePos = pos;
  327. jassert (index < 64);
  328. touchesDown = (touchesDown | (1 << (index & 63)));
  329. currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier);
  330. handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier),
  331. MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation, time, {}, index);
  332. }
  333. void handleMouseUpCallback (int index, Point<float> pos, int64 time)
  334. {
  335. pos /= scale;
  336. lastMousePos = pos;
  337. jassert (index < 64);
  338. touchesDown = (touchesDown & ~(1 << (index & 63)));
  339. if (touchesDown == 0)
  340. currentModifiers = currentModifiers.withoutMouseButtons();
  341. handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, currentModifiers.withoutMouseButtons(), MouseInputSource::invalidPressure,
  342. MouseInputSource::invalidOrientation, time, {}, index);
  343. }
  344. void handleKeyDownCallback (int k, int kc)
  345. {
  346. handleKeyPress (k, static_cast<juce_wchar> (kc));
  347. }
  348. void handleKeyUpCallback (int /*k*/, int /*kc*/)
  349. {
  350. }
  351. //==============================================================================
  352. bool isFocused() const override
  353. {
  354. if (view != nullptr)
  355. return view.callBooleanMethod (ComponentPeerView.hasFocus);
  356. return false;
  357. }
  358. void grabFocus() override
  359. {
  360. if (view != nullptr)
  361. view.callBooleanMethod (ComponentPeerView.requestFocus);
  362. }
  363. void handleFocusChangeCallback (bool hasFocus)
  364. {
  365. if (hasFocus)
  366. handleFocusGain();
  367. else
  368. handleFocusLoss();
  369. }
  370. static const char* getVirtualKeyboardType (TextInputTarget::VirtualKeyboardType type) noexcept
  371. {
  372. switch (type)
  373. {
  374. case TextInputTarget::textKeyboard: return "text";
  375. case TextInputTarget::numericKeyboard: return "number";
  376. case TextInputTarget::decimalKeyboard: return "numberDecimal";
  377. case TextInputTarget::urlKeyboard: return "textUri";
  378. case TextInputTarget::emailAddressKeyboard: return "textEmailAddress";
  379. case TextInputTarget::phoneNumberKeyboard: return "phone";
  380. default: jassertfalse; break;
  381. }
  382. return "text";
  383. }
  384. void textInputRequired (Point<int>, TextInputTarget& target) override
  385. {
  386. view.callVoidMethod (ComponentPeerView.showKeyboard,
  387. javaString (getVirtualKeyboardType (target.getKeyboardType())).get());
  388. }
  389. void dismissPendingTextInput() override
  390. {
  391. view.callVoidMethod (ComponentPeerView.showKeyboard, javaString ("").get());
  392. }
  393. //==============================================================================
  394. void handlePaintCallback (JNIEnv* env, jobject canvas, jobject paint)
  395. {
  396. jobject rect = env->CallObjectMethod (canvas, CanvasMinimal.getClipBounds);
  397. const int left = env->GetIntField (rect, RectClass.left);
  398. const int top = env->GetIntField (rect, RectClass.top);
  399. const int right = env->GetIntField (rect, RectClass.right);
  400. const int bottom = env->GetIntField (rect, RectClass.bottom);
  401. env->DeleteLocalRef (rect);
  402. const Rectangle<int> clip (left, top, right - left, bottom - top);
  403. const int sizeNeeded = clip.getWidth() * clip.getHeight();
  404. if (sizeAllocated < sizeNeeded)
  405. {
  406. buffer.clear();
  407. sizeAllocated = sizeNeeded;
  408. buffer = GlobalRef (env->NewIntArray (sizeNeeded));
  409. }
  410. if (jint* dest = env->GetIntArrayElements ((jintArray) buffer.get(), 0))
  411. {
  412. {
  413. Image temp (new PreallocatedImage (clip.getWidth(), clip.getHeight(),
  414. dest, ! component.isOpaque()));
  415. {
  416. LowLevelGraphicsSoftwareRenderer g (temp);
  417. g.setOrigin (-clip.getPosition());
  418. g.addTransform (AffineTransform::scale (scale));
  419. handlePaint (g);
  420. }
  421. }
  422. env->ReleaseIntArrayElements ((jintArray) buffer.get(), dest, 0);
  423. env->CallVoidMethod (canvas, CanvasMinimal.drawBitmap, (jintArray) buffer.get(), 0, clip.getWidth(),
  424. (jfloat) clip.getX(), (jfloat) clip.getY(),
  425. clip.getWidth(), clip.getHeight(), true, paint);
  426. }
  427. }
  428. void repaint (const Rectangle<int>& userArea) override
  429. {
  430. Rectangle<int> area = userArea * scale;
  431. if (MessageManager::getInstance()->isThisTheMessageThread())
  432. {
  433. view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom());
  434. }
  435. else
  436. {
  437. struct ViewRepainter : public CallbackMessage
  438. {
  439. ViewRepainter (const GlobalRef& view_, const Rectangle<int>& area_)
  440. : view (view_), area (area_) {}
  441. void messageCallback() override
  442. {
  443. view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(),
  444. area.getRight(), area.getBottom());
  445. }
  446. private:
  447. GlobalRef view;
  448. const Rectangle<int> area;
  449. };
  450. (new ViewRepainter (view, area))->post();
  451. }
  452. }
  453. void performAnyPendingRepaintsNow() override
  454. {
  455. // TODO
  456. }
  457. void setAlpha (float /*newAlpha*/) override
  458. {
  459. // TODO
  460. }
  461. StringArray getAvailableRenderingEngines() override
  462. {
  463. return StringArray ("Software Renderer");
  464. }
  465. //==============================================================================
  466. static ModifierKeys currentModifiers;
  467. static Point<float> lastMousePos;
  468. static int64 touchesDown;
  469. private:
  470. //==============================================================================
  471. GlobalRef view;
  472. GlobalRef buffer;
  473. bool usingAndroidGraphics, fullScreen;
  474. int sizeAllocated;
  475. float scale;
  476. static AndroidComponentPeer* frontWindow;
  477. struct PreallocatedImage : public ImagePixelData
  478. {
  479. PreallocatedImage (const int width_, const int height_, jint* data_, bool hasAlpha_)
  480. : ImagePixelData (Image::ARGB, width_, height_), data (data_), hasAlpha (hasAlpha_)
  481. {
  482. if (hasAlpha_)
  483. zeromem (data_, static_cast<size_t> (width * height) * sizeof (jint));
  484. }
  485. ~PreallocatedImage()
  486. {
  487. if (hasAlpha)
  488. {
  489. PixelARGB* pix = (PixelARGB*) data;
  490. for (int i = width * height; --i >= 0;)
  491. {
  492. pix->unpremultiply();
  493. ++pix;
  494. }
  495. }
  496. }
  497. ImageType* createType() const override { return new SoftwareImageType(); }
  498. LowLevelGraphicsContext* createLowLevelContext() override { return new LowLevelGraphicsSoftwareRenderer (Image (this)); }
  499. void initialiseBitmapData (Image::BitmapData& bm, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) override
  500. {
  501. bm.lineStride = width * static_cast<int> (sizeof (jint));
  502. bm.pixelStride = static_cast<int> (sizeof (jint));
  503. bm.pixelFormat = Image::ARGB;
  504. bm.data = (uint8*) (data + x + y * width);
  505. }
  506. ImagePixelData::Ptr clone() override
  507. {
  508. PreallocatedImage* s = new PreallocatedImage (width, height, 0, hasAlpha);
  509. s->allocatedData.malloc (sizeof (jint) * static_cast<size_t> (width * height));
  510. s->data = s->allocatedData;
  511. memcpy (s->data, data, sizeof (jint) * static_cast<size_t> (width * height));
  512. return s;
  513. }
  514. private:
  515. jint* data;
  516. HeapBlock<jint> allocatedData;
  517. bool hasAlpha;
  518. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreallocatedImage)
  519. };
  520. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidComponentPeer)
  521. };
  522. ModifierKeys AndroidComponentPeer::currentModifiers = 0;
  523. Point<float> AndroidComponentPeer::lastMousePos;
  524. int64 AndroidComponentPeer::touchesDown = 0;
  525. AndroidComponentPeer* AndroidComponentPeer::frontWindow = nullptr;
  526. //==============================================================================
  527. #define JUCE_VIEW_CALLBACK(returnType, javaMethodName, params, juceMethodInvocation) \
  528. JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024ComponentPeerView), javaMethodName, returnType, params) \
  529. { \
  530. setEnv (env); \
  531. if (AndroidComponentPeer* peer = (AndroidComponentPeer*) (pointer_sized_uint) host) \
  532. peer->juceMethodInvocation; \
  533. }
  534. JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject /*view*/, jlong host, jobject canvas, jobject paint), handlePaintCallback (env, canvas, paint))
  535. JUCE_VIEW_CALLBACK (void, handleMouseDown, (JNIEnv* env, jobject /*view*/, jlong host, jint i, jfloat x, jfloat y, jlong time), handleMouseDownCallback (i, Point<float> ((float) x, (float) y), (int64) time))
  536. JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv* env, jobject /*view*/, jlong host, jint i, jfloat x, jfloat y, jlong time), handleMouseDragCallback (i, Point<float> ((float) x, (float) y), (int64) time))
  537. JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv* env, jobject /*view*/, jlong host, jint i, jfloat x, jfloat y, jlong time), handleMouseUpCallback (i, Point<float> ((float) x, (float) y), (int64) time))
  538. JUCE_VIEW_CALLBACK (void, viewSizeChanged, (JNIEnv* env, jobject /*view*/, jlong host), handleMovedOrResized())
  539. JUCE_VIEW_CALLBACK (void, focusChanged, (JNIEnv* env, jobject /*view*/, jlong host, jboolean hasFocus), handleFocusChangeCallback (hasFocus))
  540. JUCE_VIEW_CALLBACK (void, handleKeyDown, (JNIEnv* env, jobject /*view*/, jlong host, jint k, jint kc), handleKeyDownCallback ((int) k, (int) kc))
  541. JUCE_VIEW_CALLBACK (void, handleKeyUp, (JNIEnv* env, jobject /*view*/, jlong host, jint k, jint kc), handleKeyUpCallback ((int) k, (int) kc))
  542. //==============================================================================
  543. ComponentPeer* Component::createNewPeer (int styleFlags, void*)
  544. {
  545. return new AndroidComponentPeer (*this, styleFlags);
  546. }
  547. //==============================================================================
  548. bool Desktop::canUseSemiTransparentWindows() noexcept
  549. {
  550. return true;
  551. }
  552. double Desktop::getDefaultMasterScale()
  553. {
  554. return 1.0;
  555. }
  556. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  557. {
  558. // TODO
  559. return upright;
  560. }
  561. bool MouseInputSource::SourceList::addSource()
  562. {
  563. addSource (sources.size(), MouseInputSource::InputSourceType::touch);
  564. return true;
  565. }
  566. bool MouseInputSource::SourceList::canUseTouch()
  567. {
  568. return true;
  569. }
  570. Point<float> MouseInputSource::getCurrentRawMousePosition()
  571. {
  572. return AndroidComponentPeer::lastMousePos;
  573. }
  574. void MouseInputSource::setRawMousePosition (Point<float>)
  575. {
  576. // not needed
  577. }
  578. //==============================================================================
  579. bool KeyPress::isKeyCurrentlyDown (const int /*keyCode*/)
  580. {
  581. // TODO
  582. return false;
  583. }
  584. void ModifierKeys::updateCurrentModifiers() noexcept
  585. {
  586. currentModifiers = AndroidComponentPeer::currentModifiers;
  587. }
  588. ModifierKeys ModifierKeys::getCurrentModifiersRealtime() noexcept
  589. {
  590. return AndroidComponentPeer::currentModifiers;
  591. }
  592. //==============================================================================
  593. // TODO
  594. JUCE_API bool JUCE_CALLTYPE Process::isForegroundProcess() { return true; }
  595. JUCE_API void JUCE_CALLTYPE Process::makeForegroundProcess() {}
  596. JUCE_API void JUCE_CALLTYPE Process::hide() {}
  597. //==============================================================================
  598. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/,
  599. const String& title, const String& message,
  600. Component* /*associatedComponent*/,
  601. ModalComponentManager::Callback* callback)
  602. {
  603. android.activity.callVoidMethod (JuceAppActivity.showMessageBox, javaString (title).get(),
  604. javaString (message).get(), (jlong) (pointer_sized_int) callback);
  605. }
  606. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType /*iconType*/,
  607. const String& title, const String& message,
  608. Component* /*associatedComponent*/,
  609. ModalComponentManager::Callback* callback)
  610. {
  611. jassert (callback != nullptr); // on android, all alerts must be non-modal!!
  612. android.activity.callVoidMethod (JuceAppActivity.showOkCancelBox, javaString (title).get(),
  613. javaString (message).get(), (jlong) (pointer_sized_int) callback,
  614. javaString (TRANS ("OK")).get(), javaString (TRANS ("Cancel")).get());
  615. return false;
  616. }
  617. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/,
  618. const String& title, const String& message,
  619. Component* /*associatedComponent*/,
  620. ModalComponentManager::Callback* callback)
  621. {
  622. jassert (callback != nullptr); // on android, all alerts must be non-modal!!
  623. android.activity.callVoidMethod (JuceAppActivity.showYesNoCancelBox, javaString (title).get(),
  624. javaString (message).get(), (jlong) (pointer_sized_int) callback);
  625. return 0;
  626. }
  627. int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType /*iconType*/,
  628. const String& title, const String& message,
  629. Component* /*associatedComponent*/,
  630. ModalComponentManager::Callback* callback)
  631. {
  632. jassert (callback != nullptr); // on android, all alerts must be non-modal!!
  633. android.activity.callVoidMethod (JuceAppActivity.showOkCancelBox, javaString (title).get(),
  634. javaString (message).get(), (jlong) (pointer_sized_int) callback,
  635. javaString (TRANS ("Yes")).get(), javaString (TRANS ("No")).get());
  636. return 0;
  637. }
  638. JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, alertDismissed, void, (JNIEnv* env, jobject /*activity*/,
  639. jlong callbackAsLong, jint result))
  640. {
  641. setEnv (env);
  642. if (ModalComponentManager::Callback* callback = (ModalComponentManager::Callback*) callbackAsLong)
  643. {
  644. callback->modalStateFinished (result);
  645. delete callback;
  646. }
  647. }
  648. //==============================================================================
  649. void Desktop::setScreenSaverEnabled (const bool isEnabled)
  650. {
  651. android.activity.callVoidMethod (JuceAppActivity.setScreenSaver, isEnabled);
  652. }
  653. bool Desktop::isScreenSaverEnabled()
  654. {
  655. return android.activity.callBooleanMethod (JuceAppActivity.getScreenSaver);
  656. }
  657. //==============================================================================
  658. void Desktop::setKioskComponent (Component* kioskComp, bool enableOrDisable, bool allowMenusAndBars)
  659. {
  660. ignoreUnused (allowMenusAndBars);
  661. if (AndroidComponentPeer* peer = dynamic_cast<AndroidComponentPeer*> (kioskComp->getPeer()))
  662. peer->setFullScreen (enableOrDisable);
  663. else
  664. jassertfalse; // (this should have been checked by the caller)
  665. }
  666. //==============================================================================
  667. static jint getAndroidOrientationFlag (int orientations) noexcept
  668. {
  669. enum
  670. {
  671. SCREEN_ORIENTATION_LANDSCAPE = 0,
  672. SCREEN_ORIENTATION_PORTRAIT = 1,
  673. SCREEN_ORIENTATION_USER = 2,
  674. SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8,
  675. SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9,
  676. SCREEN_ORIENTATION_USER_LANDSCAPE = 11,
  677. SCREEN_ORIENTATION_USER_PORTRAIT = 12,
  678. };
  679. switch (orientations)
  680. {
  681. case Desktop::upright: return (jint) SCREEN_ORIENTATION_PORTRAIT;
  682. case Desktop::upsideDown: return (jint) SCREEN_ORIENTATION_REVERSE_PORTRAIT;
  683. case Desktop::upright + Desktop::upsideDown: return (jint) SCREEN_ORIENTATION_USER_PORTRAIT;
  684. case Desktop::rotatedAntiClockwise: return (jint) SCREEN_ORIENTATION_LANDSCAPE;
  685. case Desktop::rotatedClockwise: return (jint) SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
  686. case Desktop::rotatedClockwise + Desktop::rotatedAntiClockwise: return (jint) SCREEN_ORIENTATION_USER_LANDSCAPE;
  687. default: return (jint) SCREEN_ORIENTATION_USER;
  688. }
  689. }
  690. void Desktop::allowedOrientationsChanged()
  691. {
  692. android.activity.callVoidMethod (JuceAppActivity.setRequestedOrientation,
  693. getAndroidOrientationFlag (allowedOrientations));
  694. }
  695. //==============================================================================
  696. bool juce_areThereAnyAlwaysOnTopWindows()
  697. {
  698. return false;
  699. }
  700. //==============================================================================
  701. void Desktop::Displays::findDisplays (float masterScale)
  702. {
  703. Display d;
  704. d.isMain = true;
  705. d.dpi = android.dpi;
  706. d.scale = masterScale * (d.dpi / 150.);
  707. d.userArea = d.totalArea = Rectangle<int> (android.screenWidth,
  708. android.screenHeight) / d.scale;
  709. displays.add (d);
  710. }
  711. JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, setScreenSize, void, (JNIEnv* env, jobject /*activity*/,
  712. jint screenWidth, jint screenHeight,
  713. jint dpi))
  714. {
  715. setEnv (env);
  716. android.screenWidth = screenWidth;
  717. android.screenHeight = screenHeight;
  718. android.dpi = dpi;
  719. const_cast<Desktop::Displays&> (Desktop::getInstance().getDisplays()).refresh();
  720. }
  721. //==============================================================================
  722. Image juce_createIconForFile (const File& /*file*/)
  723. {
  724. return Image();
  725. }
  726. //==============================================================================
  727. void* CustomMouseCursorInfo::create() const { return nullptr; }
  728. void* MouseCursor::createStandardMouseCursor (const MouseCursor::StandardCursorType) { return nullptr; }
  729. void MouseCursor::deleteMouseCursor (void* const /*cursorHandle*/, const bool /*isStandard*/) {}
  730. //==============================================================================
  731. void MouseCursor::showInWindow (ComponentPeer*) const {}
  732. void MouseCursor::showInAllWindows() const {}
  733. //==============================================================================
  734. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& /*files*/, const bool /*canMove*/)
  735. {
  736. return false;
  737. }
  738. bool DragAndDropContainer::performExternalDragDropOfText (const String& /*text*/)
  739. {
  740. return false;
  741. }
  742. //==============================================================================
  743. void LookAndFeel::playAlertSound()
  744. {
  745. }
  746. //==============================================================================
  747. void SystemClipboard::copyTextToClipboard (const String& text)
  748. {
  749. const LocalRef<jstring> t (javaString (text));
  750. android.activity.callVoidMethod (JuceAppActivity.setClipboardContent, t.get());
  751. }
  752. String SystemClipboard::getTextFromClipboard()
  753. {
  754. const LocalRef<jstring> text ((jstring) android.activity.callObjectMethod (JuceAppActivity.getClipboardContent));
  755. return juceString (text);
  756. }
  757. //==============================================================================
  758. const int extendedKeyModifier = 0x10000;
  759. const int KeyPress::spaceKey = ' ';
  760. const int KeyPress::returnKey = 66;
  761. const int KeyPress::escapeKey = 4;
  762. const int KeyPress::backspaceKey = 67;
  763. const int KeyPress::leftKey = extendedKeyModifier + 1;
  764. const int KeyPress::rightKey = extendedKeyModifier + 2;
  765. const int KeyPress::upKey = extendedKeyModifier + 3;
  766. const int KeyPress::downKey = extendedKeyModifier + 4;
  767. const int KeyPress::pageUpKey = extendedKeyModifier + 5;
  768. const int KeyPress::pageDownKey = extendedKeyModifier + 6;
  769. const int KeyPress::endKey = extendedKeyModifier + 7;
  770. const int KeyPress::homeKey = extendedKeyModifier + 8;
  771. const int KeyPress::deleteKey = extendedKeyModifier + 9;
  772. const int KeyPress::insertKey = -1;
  773. const int KeyPress::tabKey = 61;
  774. const int KeyPress::F1Key = extendedKeyModifier + 10;
  775. const int KeyPress::F2Key = extendedKeyModifier + 11;
  776. const int KeyPress::F3Key = extendedKeyModifier + 12;
  777. const int KeyPress::F4Key = extendedKeyModifier + 13;
  778. const int KeyPress::F5Key = extendedKeyModifier + 14;
  779. const int KeyPress::F6Key = extendedKeyModifier + 16;
  780. const int KeyPress::F7Key = extendedKeyModifier + 17;
  781. const int KeyPress::F8Key = extendedKeyModifier + 18;
  782. const int KeyPress::F9Key = extendedKeyModifier + 19;
  783. const int KeyPress::F10Key = extendedKeyModifier + 20;
  784. const int KeyPress::F11Key = extendedKeyModifier + 21;
  785. const int KeyPress::F12Key = extendedKeyModifier + 22;
  786. const int KeyPress::F13Key = extendedKeyModifier + 23;
  787. const int KeyPress::F14Key = extendedKeyModifier + 24;
  788. const int KeyPress::F15Key = extendedKeyModifier + 25;
  789. const int KeyPress::F16Key = extendedKeyModifier + 26;
  790. const int KeyPress::numberPad0 = extendedKeyModifier + 27;
  791. const int KeyPress::numberPad1 = extendedKeyModifier + 28;
  792. const int KeyPress::numberPad2 = extendedKeyModifier + 29;
  793. const int KeyPress::numberPad3 = extendedKeyModifier + 30;
  794. const int KeyPress::numberPad4 = extendedKeyModifier + 31;
  795. const int KeyPress::numberPad5 = extendedKeyModifier + 32;
  796. const int KeyPress::numberPad6 = extendedKeyModifier + 33;
  797. const int KeyPress::numberPad7 = extendedKeyModifier + 34;
  798. const int KeyPress::numberPad8 = extendedKeyModifier + 35;
  799. const int KeyPress::numberPad9 = extendedKeyModifier + 36;
  800. const int KeyPress::numberPadAdd = extendedKeyModifier + 37;
  801. const int KeyPress::numberPadSubtract = extendedKeyModifier + 38;
  802. const int KeyPress::numberPadMultiply = extendedKeyModifier + 39;
  803. const int KeyPress::numberPadDivide = extendedKeyModifier + 40;
  804. const int KeyPress::numberPadSeparator = extendedKeyModifier + 41;
  805. const int KeyPress::numberPadDecimalPoint = extendedKeyModifier + 42;
  806. const int KeyPress::numberPadEquals = extendedKeyModifier + 43;
  807. const int KeyPress::numberPadDelete = extendedKeyModifier + 44;
  808. const int KeyPress::playKey = extendedKeyModifier + 45;
  809. const int KeyPress::stopKey = extendedKeyModifier + 46;
  810. const int KeyPress::fastForwardKey = extendedKeyModifier + 47;
  811. const int KeyPress::rewindKey = extendedKeyModifier + 48;