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.

955 lines
36KB

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