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.

976 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. return view.callBooleanMethod (ComponentPeerView.hasFocus);
  355. }
  356. void grabFocus() override
  357. {
  358. view.callBooleanMethod (ComponentPeerView.requestFocus);
  359. }
  360. void handleFocusChangeCallback (bool hasFocus)
  361. {
  362. if (hasFocus)
  363. handleFocusGain();
  364. else
  365. handleFocusLoss();
  366. }
  367. static const char* getVirtualKeyboardType (TextInputTarget::VirtualKeyboardType type) noexcept
  368. {
  369. switch (type)
  370. {
  371. case TextInputTarget::textKeyboard: return "text";
  372. case TextInputTarget::numericKeyboard: return "number";
  373. case TextInputTarget::decimalKeyboard: return "numberDecimal";
  374. case TextInputTarget::urlKeyboard: return "textUri";
  375. case TextInputTarget::emailAddressKeyboard: return "textEmailAddress";
  376. case TextInputTarget::phoneNumberKeyboard: return "phone";
  377. default: jassertfalse; break;
  378. }
  379. return "text";
  380. }
  381. void textInputRequired (Point<int>, TextInputTarget& target) override
  382. {
  383. view.callVoidMethod (ComponentPeerView.showKeyboard,
  384. javaString (getVirtualKeyboardType (target.getKeyboardType())).get());
  385. }
  386. void dismissPendingTextInput() override
  387. {
  388. view.callVoidMethod (ComponentPeerView.showKeyboard, javaString ("").get());
  389. }
  390. //==============================================================================
  391. void handlePaintCallback (JNIEnv* env, jobject canvas, jobject paint)
  392. {
  393. jobject rect = env->CallObjectMethod (canvas, CanvasMinimal.getClipBounds);
  394. const int left = env->GetIntField (rect, RectClass.left);
  395. const int top = env->GetIntField (rect, RectClass.top);
  396. const int right = env->GetIntField (rect, RectClass.right);
  397. const int bottom = env->GetIntField (rect, RectClass.bottom);
  398. env->DeleteLocalRef (rect);
  399. const Rectangle<int> clip (left, top, right - left, bottom - top);
  400. const int sizeNeeded = clip.getWidth() * clip.getHeight();
  401. if (sizeAllocated < sizeNeeded)
  402. {
  403. buffer.clear();
  404. sizeAllocated = sizeNeeded;
  405. buffer = GlobalRef (env->NewIntArray (sizeNeeded));
  406. }
  407. if (jint* dest = env->GetIntArrayElements ((jintArray) buffer.get(), 0))
  408. {
  409. {
  410. Image temp (new PreallocatedImage (clip.getWidth(), clip.getHeight(),
  411. dest, ! component.isOpaque()));
  412. {
  413. LowLevelGraphicsSoftwareRenderer g (temp);
  414. g.setOrigin (-clip.getPosition());
  415. g.addTransform (AffineTransform::scale (scale));
  416. handlePaint (g);
  417. }
  418. }
  419. env->ReleaseIntArrayElements ((jintArray) buffer.get(), dest, 0);
  420. env->CallVoidMethod (canvas, CanvasMinimal.drawBitmap, (jintArray) buffer.get(), 0, clip.getWidth(),
  421. (jfloat) clip.getX(), (jfloat) clip.getY(),
  422. clip.getWidth(), clip.getHeight(), true, paint);
  423. }
  424. }
  425. void repaint (const Rectangle<int>& userArea) override
  426. {
  427. Rectangle<int> area = userArea * scale;
  428. if (MessageManager::getInstance()->isThisTheMessageThread())
  429. {
  430. view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom());
  431. }
  432. else
  433. {
  434. struct ViewRepainter : public CallbackMessage
  435. {
  436. ViewRepainter (const GlobalRef& view_, const Rectangle<int>& area_)
  437. : view (view_), area (area_) {}
  438. void messageCallback() override
  439. {
  440. view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(),
  441. area.getRight(), area.getBottom());
  442. }
  443. private:
  444. GlobalRef view;
  445. const Rectangle<int> area;
  446. };
  447. (new ViewRepainter (view, area))->post();
  448. }
  449. }
  450. void performAnyPendingRepaintsNow() override
  451. {
  452. // TODO
  453. }
  454. void setAlpha (float /*newAlpha*/) override
  455. {
  456. // TODO
  457. }
  458. StringArray getAvailableRenderingEngines() override
  459. {
  460. return StringArray ("Software Renderer");
  461. }
  462. //==============================================================================
  463. static ModifierKeys currentModifiers;
  464. static Point<float> lastMousePos;
  465. static int64 touchesDown;
  466. private:
  467. //==============================================================================
  468. GlobalRef view;
  469. GlobalRef buffer;
  470. bool usingAndroidGraphics, fullScreen;
  471. int sizeAllocated;
  472. float scale;
  473. static AndroidComponentPeer* frontWindow;
  474. struct PreallocatedImage : public ImagePixelData
  475. {
  476. PreallocatedImage (const int width_, const int height_, jint* data_, bool hasAlpha_)
  477. : ImagePixelData (Image::ARGB, width_, height_), data (data_), hasAlpha (hasAlpha_)
  478. {
  479. if (hasAlpha_)
  480. zeromem (data_, static_cast<size_t> (width * height) * sizeof (jint));
  481. }
  482. ~PreallocatedImage()
  483. {
  484. if (hasAlpha)
  485. {
  486. PixelARGB* pix = (PixelARGB*) data;
  487. for (int i = width * height; --i >= 0;)
  488. {
  489. pix->unpremultiply();
  490. ++pix;
  491. }
  492. }
  493. }
  494. ImageType* createType() const override { return new SoftwareImageType(); }
  495. LowLevelGraphicsContext* createLowLevelContext() override { return new LowLevelGraphicsSoftwareRenderer (Image (this)); }
  496. void initialiseBitmapData (Image::BitmapData& bm, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) override
  497. {
  498. bm.lineStride = width * static_cast<int> (sizeof (jint));
  499. bm.pixelStride = static_cast<int> (sizeof (jint));
  500. bm.pixelFormat = Image::ARGB;
  501. bm.data = (uint8*) (data + x + y * width);
  502. }
  503. ImagePixelData::Ptr clone() override
  504. {
  505. PreallocatedImage* s = new PreallocatedImage (width, height, 0, hasAlpha);
  506. s->allocatedData.malloc (sizeof (jint) * static_cast<size_t> (width * height));
  507. s->data = s->allocatedData;
  508. memcpy (s->data, data, sizeof (jint) * static_cast<size_t> (width * height));
  509. return s;
  510. }
  511. private:
  512. jint* data;
  513. HeapBlock<jint> allocatedData;
  514. bool hasAlpha;
  515. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreallocatedImage)
  516. };
  517. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidComponentPeer)
  518. };
  519. ModifierKeys AndroidComponentPeer::currentModifiers = 0;
  520. Point<float> AndroidComponentPeer::lastMousePos;
  521. int64 AndroidComponentPeer::touchesDown = 0;
  522. AndroidComponentPeer* AndroidComponentPeer::frontWindow = nullptr;
  523. //==============================================================================
  524. #define JUCE_VIEW_CALLBACK(returnType, javaMethodName, params, juceMethodInvocation) \
  525. JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024ComponentPeerView), javaMethodName, returnType, params) \
  526. { \
  527. setEnv (env); \
  528. if (AndroidComponentPeer* peer = (AndroidComponentPeer*) (pointer_sized_uint) host) \
  529. peer->juceMethodInvocation; \
  530. }
  531. JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject /*view*/, jlong host, jobject canvas, jobject paint), handlePaintCallback (env, canvas, paint))
  532. 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))
  533. 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))
  534. 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))
  535. JUCE_VIEW_CALLBACK (void, viewSizeChanged, (JNIEnv* env, jobject /*view*/, jlong host), handleMovedOrResized())
  536. JUCE_VIEW_CALLBACK (void, focusChanged, (JNIEnv* env, jobject /*view*/, jlong host, jboolean hasFocus), handleFocusChangeCallback (hasFocus))
  537. JUCE_VIEW_CALLBACK (void, handleKeyDown, (JNIEnv* env, jobject /*view*/, jlong host, jint k, jint kc), handleKeyDownCallback ((int) k, (int) kc))
  538. JUCE_VIEW_CALLBACK (void, handleKeyUp, (JNIEnv* env, jobject /*view*/, jlong host, jint k, jint kc), handleKeyUpCallback ((int) k, (int) kc))
  539. //==============================================================================
  540. ComponentPeer* Component::createNewPeer (int styleFlags, void*)
  541. {
  542. return new AndroidComponentPeer (*this, styleFlags);
  543. }
  544. //==============================================================================
  545. bool Desktop::canUseSemiTransparentWindows() noexcept
  546. {
  547. return true;
  548. }
  549. double Desktop::getDefaultMasterScale()
  550. {
  551. return 1.0;
  552. }
  553. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  554. {
  555. // TODO
  556. return upright;
  557. }
  558. bool MouseInputSource::SourceList::addSource()
  559. {
  560. addSource (sources.size(), MouseInputSource::InputSourceType::touch);
  561. return true;
  562. }
  563. bool MouseInputSource::SourceList::canUseTouch()
  564. {
  565. return true;
  566. }
  567. Point<float> MouseInputSource::getCurrentRawMousePosition()
  568. {
  569. return AndroidComponentPeer::lastMousePos;
  570. }
  571. void MouseInputSource::setRawMousePosition (Point<float>)
  572. {
  573. // not needed
  574. }
  575. //==============================================================================
  576. bool KeyPress::isKeyCurrentlyDown (const int /*keyCode*/)
  577. {
  578. // TODO
  579. return false;
  580. }
  581. void ModifierKeys::updateCurrentModifiers() noexcept
  582. {
  583. currentModifiers = AndroidComponentPeer::currentModifiers;
  584. }
  585. ModifierKeys ModifierKeys::getCurrentModifiersRealtime() noexcept
  586. {
  587. return AndroidComponentPeer::currentModifiers;
  588. }
  589. //==============================================================================
  590. // TODO
  591. JUCE_API bool JUCE_CALLTYPE Process::isForegroundProcess() { return true; }
  592. JUCE_API void JUCE_CALLTYPE Process::makeForegroundProcess() {}
  593. JUCE_API void JUCE_CALLTYPE Process::hide() {}
  594. //==============================================================================
  595. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType /*iconType*/,
  596. const String& title, const String& message,
  597. Component* /*associatedComponent*/,
  598. ModalComponentManager::Callback* callback)
  599. {
  600. android.activity.callVoidMethod (JuceAppActivity.showMessageBox, javaString (title).get(),
  601. javaString (message).get(), (jlong) (pointer_sized_int) callback);
  602. }
  603. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType /*iconType*/,
  604. const String& title, const String& message,
  605. Component* /*associatedComponent*/,
  606. ModalComponentManager::Callback* callback)
  607. {
  608. jassert (callback != nullptr); // on android, all alerts must be non-modal!!
  609. android.activity.callVoidMethod (JuceAppActivity.showOkCancelBox, javaString (title).get(),
  610. javaString (message).get(), (jlong) (pointer_sized_int) callback,
  611. javaString (TRANS ("OK")).get(), javaString (TRANS ("Cancel")).get());
  612. return false;
  613. }
  614. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType /*iconType*/,
  615. const String& title, const String& message,
  616. Component* /*associatedComponent*/,
  617. ModalComponentManager::Callback* callback)
  618. {
  619. jassert (callback != nullptr); // on android, all alerts must be non-modal!!
  620. android.activity.callVoidMethod (JuceAppActivity.showYesNoCancelBox, javaString (title).get(),
  621. javaString (message).get(), (jlong) (pointer_sized_int) callback);
  622. return 0;
  623. }
  624. int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType /*iconType*/,
  625. const String& title, const String& message,
  626. Component* /*associatedComponent*/,
  627. ModalComponentManager::Callback* callback)
  628. {
  629. jassert (callback != nullptr); // on android, all alerts must be non-modal!!
  630. android.activity.callVoidMethod (JuceAppActivity.showOkCancelBox, javaString (title).get(),
  631. javaString (message).get(), (jlong) (pointer_sized_int) callback,
  632. javaString (TRANS ("Yes")).get(), javaString (TRANS ("No")).get());
  633. return 0;
  634. }
  635. JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, alertDismissed, void, (JNIEnv* env, jobject /*activity*/,
  636. jlong callbackAsLong, jint result))
  637. {
  638. setEnv (env);
  639. if (ModalComponentManager::Callback* callback = (ModalComponentManager::Callback*) callbackAsLong)
  640. {
  641. callback->modalStateFinished (result);
  642. delete callback;
  643. }
  644. }
  645. //==============================================================================
  646. void Desktop::setScreenSaverEnabled (const bool isEnabled)
  647. {
  648. android.activity.callVoidMethod (JuceAppActivity.setScreenSaver, isEnabled);
  649. }
  650. bool Desktop::isScreenSaverEnabled()
  651. {
  652. return android.activity.callBooleanMethod (JuceAppActivity.getScreenSaver);
  653. }
  654. //==============================================================================
  655. void Desktop::setKioskComponent (Component* kioskComp, bool enableOrDisable, bool allowMenusAndBars)
  656. {
  657. ignoreUnused (allowMenusAndBars);
  658. if (AndroidComponentPeer* peer = dynamic_cast<AndroidComponentPeer*> (kioskComp->getPeer()))
  659. peer->setFullScreen (enableOrDisable);
  660. else
  661. jassertfalse; // (this should have been checked by the caller)
  662. }
  663. //==============================================================================
  664. static jint getAndroidOrientationFlag (int orientations) noexcept
  665. {
  666. enum
  667. {
  668. SCREEN_ORIENTATION_LANDSCAPE = 0,
  669. SCREEN_ORIENTATION_PORTRAIT = 1,
  670. SCREEN_ORIENTATION_USER = 2,
  671. SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8,
  672. SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9,
  673. SCREEN_ORIENTATION_USER_LANDSCAPE = 11,
  674. SCREEN_ORIENTATION_USER_PORTRAIT = 12,
  675. };
  676. switch (orientations)
  677. {
  678. case Desktop::upright: return (jint) SCREEN_ORIENTATION_PORTRAIT;
  679. case Desktop::upsideDown: return (jint) SCREEN_ORIENTATION_REVERSE_PORTRAIT;
  680. case Desktop::upright + Desktop::upsideDown: return (jint) SCREEN_ORIENTATION_USER_PORTRAIT;
  681. case Desktop::rotatedAntiClockwise: return (jint) SCREEN_ORIENTATION_LANDSCAPE;
  682. case Desktop::rotatedClockwise: return (jint) SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
  683. case Desktop::rotatedClockwise + Desktop::rotatedAntiClockwise: return (jint) SCREEN_ORIENTATION_USER_LANDSCAPE;
  684. default: return (jint) SCREEN_ORIENTATION_USER;
  685. }
  686. }
  687. void Desktop::allowedOrientationsChanged()
  688. {
  689. android.activity.callVoidMethod (JuceAppActivity.setRequestedOrientation,
  690. getAndroidOrientationFlag (allowedOrientations));
  691. }
  692. //==============================================================================
  693. bool juce_areThereAnyAlwaysOnTopWindows()
  694. {
  695. return false;
  696. }
  697. //==============================================================================
  698. void Desktop::Displays::findDisplays (float masterScale)
  699. {
  700. Display d;
  701. d.isMain = true;
  702. d.dpi = android.dpi;
  703. d.scale = masterScale * (d.dpi / 150.);
  704. d.userArea = d.totalArea = Rectangle<int> (android.screenWidth,
  705. android.screenHeight) / d.scale;
  706. displays.add (d);
  707. }
  708. JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, setScreenSize, void, (JNIEnv* env, jobject /*activity*/,
  709. jint screenWidth, jint screenHeight,
  710. jint dpi))
  711. {
  712. setEnv (env);
  713. android.screenWidth = screenWidth;
  714. android.screenHeight = screenHeight;
  715. android.dpi = dpi;
  716. const_cast<Desktop::Displays&> (Desktop::getInstance().getDisplays()).refresh();
  717. }
  718. //==============================================================================
  719. Image juce_createIconForFile (const File& /*file*/)
  720. {
  721. return Image();
  722. }
  723. //==============================================================================
  724. void* CustomMouseCursorInfo::create() const { return nullptr; }
  725. void* MouseCursor::createStandardMouseCursor (const MouseCursor::StandardCursorType) { return nullptr; }
  726. void MouseCursor::deleteMouseCursor (void* const /*cursorHandle*/, const bool /*isStandard*/) {}
  727. //==============================================================================
  728. void MouseCursor::showInWindow (ComponentPeer*) const {}
  729. void MouseCursor::showInAllWindows() const {}
  730. //==============================================================================
  731. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& /*files*/, const bool /*canMove*/)
  732. {
  733. return false;
  734. }
  735. bool DragAndDropContainer::performExternalDragDropOfText (const String& /*text*/)
  736. {
  737. return false;
  738. }
  739. //==============================================================================
  740. void LookAndFeel::playAlertSound()
  741. {
  742. }
  743. //==============================================================================
  744. void SystemClipboard::copyTextToClipboard (const String& text)
  745. {
  746. const LocalRef<jstring> t (javaString (text));
  747. android.activity.callVoidMethod (JuceAppActivity.setClipboardContent, t.get());
  748. }
  749. String SystemClipboard::getTextFromClipboard()
  750. {
  751. const LocalRef<jstring> text ((jstring) android.activity.callObjectMethod (JuceAppActivity.getClipboardContent));
  752. return juceString (text);
  753. }
  754. //==============================================================================
  755. const int extendedKeyModifier = 0x10000;
  756. const int KeyPress::spaceKey = ' ';
  757. const int KeyPress::returnKey = 66;
  758. const int KeyPress::escapeKey = 4;
  759. const int KeyPress::backspaceKey = 67;
  760. const int KeyPress::leftKey = extendedKeyModifier + 1;
  761. const int KeyPress::rightKey = extendedKeyModifier + 2;
  762. const int KeyPress::upKey = extendedKeyModifier + 3;
  763. const int KeyPress::downKey = extendedKeyModifier + 4;
  764. const int KeyPress::pageUpKey = extendedKeyModifier + 5;
  765. const int KeyPress::pageDownKey = extendedKeyModifier + 6;
  766. const int KeyPress::endKey = extendedKeyModifier + 7;
  767. const int KeyPress::homeKey = extendedKeyModifier + 8;
  768. const int KeyPress::deleteKey = extendedKeyModifier + 9;
  769. const int KeyPress::insertKey = -1;
  770. const int KeyPress::tabKey = 61;
  771. const int KeyPress::F1Key = extendedKeyModifier + 10;
  772. const int KeyPress::F2Key = extendedKeyModifier + 11;
  773. const int KeyPress::F3Key = extendedKeyModifier + 12;
  774. const int KeyPress::F4Key = extendedKeyModifier + 13;
  775. const int KeyPress::F5Key = extendedKeyModifier + 14;
  776. const int KeyPress::F6Key = extendedKeyModifier + 16;
  777. const int KeyPress::F7Key = extendedKeyModifier + 17;
  778. const int KeyPress::F8Key = extendedKeyModifier + 18;
  779. const int KeyPress::F9Key = extendedKeyModifier + 19;
  780. const int KeyPress::F10Key = extendedKeyModifier + 20;
  781. const int KeyPress::F11Key = extendedKeyModifier + 21;
  782. const int KeyPress::F12Key = extendedKeyModifier + 22;
  783. const int KeyPress::F13Key = extendedKeyModifier + 23;
  784. const int KeyPress::F14Key = extendedKeyModifier + 24;
  785. const int KeyPress::F15Key = extendedKeyModifier + 25;
  786. const int KeyPress::F16Key = extendedKeyModifier + 26;
  787. const int KeyPress::numberPad0 = extendedKeyModifier + 27;
  788. const int KeyPress::numberPad1 = extendedKeyModifier + 28;
  789. const int KeyPress::numberPad2 = extendedKeyModifier + 29;
  790. const int KeyPress::numberPad3 = extendedKeyModifier + 30;
  791. const int KeyPress::numberPad4 = extendedKeyModifier + 31;
  792. const int KeyPress::numberPad5 = extendedKeyModifier + 32;
  793. const int KeyPress::numberPad6 = extendedKeyModifier + 33;
  794. const int KeyPress::numberPad7 = extendedKeyModifier + 34;
  795. const int KeyPress::numberPad8 = extendedKeyModifier + 35;
  796. const int KeyPress::numberPad9 = extendedKeyModifier + 36;
  797. const int KeyPress::numberPadAdd = extendedKeyModifier + 37;
  798. const int KeyPress::numberPadSubtract = extendedKeyModifier + 38;
  799. const int KeyPress::numberPadMultiply = extendedKeyModifier + 39;
  800. const int KeyPress::numberPadDivide = extendedKeyModifier + 40;
  801. const int KeyPress::numberPadSeparator = extendedKeyModifier + 41;
  802. const int KeyPress::numberPadDecimalPoint = extendedKeyModifier + 42;
  803. const int KeyPress::numberPadEquals = extendedKeyModifier + 43;
  804. const int KeyPress::numberPadDelete = extendedKeyModifier + 44;
  805. const int KeyPress::playKey = extendedKeyModifier + 45;
  806. const int KeyPress::stopKey = extendedKeyModifier + 46;
  807. const int KeyPress::fastForwardKey = extendedKeyModifier + 47;
  808. const int KeyPress::rewindKey = extendedKeyModifier + 48;