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.

501 lines
17KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. package com.juce;
  19. import android.app.Activity;
  20. import android.app.AlertDialog;
  21. import android.content.DialogInterface;
  22. import android.content.Context;
  23. import android.os.Bundle;
  24. import android.view.*;
  25. import android.graphics.*;
  26. import android.opengl.*;
  27. import android.text.ClipboardManager;
  28. import java.io.BufferedInputStream;
  29. import java.io.IOException;
  30. import java.io.InputStream;
  31. import java.io.OutputStream;
  32. import java.net.URL;
  33. import java.net.HttpURLConnection;
  34. import javax.microedition.khronos.egl.EGLConfig;
  35. import javax.microedition.khronos.opengles.GL10;
  36. //==============================================================================
  37. public final class JuceAppActivity extends Activity
  38. {
  39. //==============================================================================
  40. static
  41. {
  42. System.loadLibrary ("juce_jni");
  43. }
  44. @Override
  45. public final void onCreate (Bundle savedInstanceState)
  46. {
  47. super.onCreate (savedInstanceState);
  48. viewHolder = new ViewHolder (this);
  49. setContentView (viewHolder);
  50. }
  51. @Override
  52. protected final void onDestroy()
  53. {
  54. quitApp();
  55. super.onDestroy();
  56. }
  57. private void callAppLauncher()
  58. {
  59. launchApp (getApplicationInfo().publicSourceDir,
  60. getApplicationInfo().dataDir);
  61. }
  62. //==============================================================================
  63. private native void launchApp (String appFile, String appDataDir);
  64. private native void quitApp();
  65. private native void setScreenSize (int screenWidth, int screenHeight);
  66. //==============================================================================
  67. public static final void printToConsole (String s)
  68. {
  69. android.util.Log.i ("Juce", s);
  70. }
  71. //==============================================================================
  72. public native void deliverMessage (long value);
  73. private android.os.Handler messageHandler = new android.os.Handler();
  74. public final void postMessage (long value)
  75. {
  76. messageHandler.post (new MessageCallback (value));
  77. }
  78. private final class MessageCallback implements Runnable
  79. {
  80. public MessageCallback (long value_) { value = value_; }
  81. public final void run() { deliverMessage (value); }
  82. private long value;
  83. }
  84. //==============================================================================
  85. private ViewHolder viewHolder;
  86. public final ComponentPeerView createNewView (boolean opaque)
  87. {
  88. ComponentPeerView v = new ComponentPeerView (this, opaque);
  89. viewHolder.addView (v);
  90. return v;
  91. }
  92. public final void deleteView (ComponentPeerView view)
  93. {
  94. ViewGroup group = (ViewGroup) (view.getParent());
  95. if (group != null)
  96. group.removeView (view);
  97. }
  98. final class ViewHolder extends ViewGroup
  99. {
  100. public ViewHolder (Context context)
  101. {
  102. super (context);
  103. setDescendantFocusability (ViewGroup.FOCUS_AFTER_DESCENDANTS);
  104. setFocusable (false);
  105. }
  106. protected final void onLayout (boolean changed, int left, int top, int right, int bottom)
  107. {
  108. setScreenSize (getWidth(), getHeight());
  109. if (isFirstResize)
  110. {
  111. isFirstResize = false;
  112. callAppLauncher();
  113. }
  114. }
  115. private boolean isFirstResize = true;
  116. }
  117. public final void excludeClipRegion (android.graphics.Canvas canvas, float left, float top, float right, float bottom)
  118. {
  119. canvas.clipRect (left, top, right, bottom, android.graphics.Region.Op.DIFFERENCE);
  120. }
  121. //==============================================================================
  122. public final String getClipboardContent()
  123. {
  124. ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
  125. return clipboard.getText().toString();
  126. }
  127. public final void setClipboardContent (String newText)
  128. {
  129. ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
  130. clipboard.setText (newText);
  131. }
  132. //==============================================================================
  133. public final void showMessageBox (String title, String message, final long callback)
  134. {
  135. AlertDialog.Builder builder = new AlertDialog.Builder (this);
  136. builder.setTitle (title)
  137. .setMessage (message)
  138. .setCancelable (true)
  139. .setPositiveButton ("OK", new DialogInterface.OnClickListener()
  140. {
  141. public void onClick (DialogInterface dialog, int id)
  142. {
  143. dialog.cancel();
  144. JuceAppActivity.this.alertDismissed (callback, 0);
  145. }
  146. });
  147. builder.create().show();
  148. }
  149. public final void showOkCancelBox (String title, String message, final long callback)
  150. {
  151. AlertDialog.Builder builder = new AlertDialog.Builder (this);
  152. builder.setTitle (title)
  153. .setMessage (message)
  154. .setCancelable (true)
  155. .setPositiveButton ("OK", new DialogInterface.OnClickListener()
  156. {
  157. public void onClick (DialogInterface dialog, int id)
  158. {
  159. dialog.cancel();
  160. JuceAppActivity.this.alertDismissed (callback, 1);
  161. }
  162. })
  163. .setNegativeButton ("Cancel", new DialogInterface.OnClickListener()
  164. {
  165. public void onClick (DialogInterface dialog, int id)
  166. {
  167. dialog.cancel();
  168. JuceAppActivity.this.alertDismissed (callback, 0);
  169. }
  170. });
  171. builder.create().show();
  172. }
  173. public final void showYesNoCancelBox (String title, String message, final long callback)
  174. {
  175. AlertDialog.Builder builder = new AlertDialog.Builder (this);
  176. builder.setTitle (title)
  177. .setMessage (message)
  178. .setCancelable (true)
  179. .setPositiveButton ("Yes", new DialogInterface.OnClickListener()
  180. {
  181. public void onClick (DialogInterface dialog, int id)
  182. {
  183. dialog.cancel();
  184. JuceAppActivity.this.alertDismissed (callback, 1);
  185. }
  186. })
  187. .setNegativeButton ("No", new DialogInterface.OnClickListener()
  188. {
  189. public void onClick (DialogInterface dialog, int id)
  190. {
  191. dialog.cancel();
  192. JuceAppActivity.this.alertDismissed (callback, 2);
  193. }
  194. })
  195. .setNeutralButton ("Cancel", new DialogInterface.OnClickListener()
  196. {
  197. public void onClick (DialogInterface dialog, int id)
  198. {
  199. dialog.cancel();
  200. JuceAppActivity.this.alertDismissed (callback, 0);
  201. }
  202. });
  203. builder.create().show();
  204. }
  205. public native void alertDismissed (long callback, int id);
  206. //==============================================================================
  207. public final class ComponentPeerView extends ViewGroup
  208. implements View.OnFocusChangeListener
  209. {
  210. public ComponentPeerView (Context context, boolean opaque_)
  211. {
  212. super (context);
  213. setWillNotDraw (false);
  214. opaque = opaque_;
  215. setFocusable (true);
  216. setFocusableInTouchMode (true);
  217. setOnFocusChangeListener (this);
  218. requestFocus();
  219. }
  220. //==============================================================================
  221. private native void handlePaint (Canvas canvas);
  222. @Override
  223. public void draw (Canvas canvas)
  224. {
  225. super.draw (canvas);
  226. handlePaint (canvas);
  227. }
  228. @Override
  229. public boolean isOpaque()
  230. {
  231. return opaque;
  232. }
  233. private boolean opaque;
  234. //==============================================================================
  235. private native void handleMouseDown (float x, float y, long time);
  236. private native void handleMouseDrag (float x, float y, long time);
  237. private native void handleMouseUp (float x, float y, long time);
  238. @Override
  239. public boolean onTouchEvent (MotionEvent event)
  240. {
  241. switch (event.getAction())
  242. {
  243. case MotionEvent.ACTION_DOWN: handleMouseDown (event.getX(), event.getY(), event.getEventTime()); return true;
  244. case MotionEvent.ACTION_MOVE: handleMouseDrag (event.getX(), event.getY(), event.getEventTime()); return true;
  245. case MotionEvent.ACTION_CANCEL:
  246. case MotionEvent.ACTION_UP: handleMouseUp (event.getX(), event.getY(), event.getEventTime()); return true;
  247. default: break;
  248. }
  249. return false;
  250. }
  251. //==============================================================================
  252. @Override
  253. protected void onSizeChanged (int w, int h, int oldw, int oldh)
  254. {
  255. super.onSizeChanged (w, h, oldw, oldh);
  256. viewSizeChanged();
  257. }
  258. @Override
  259. protected void onLayout (boolean changed, int left, int top, int right, int bottom)
  260. {
  261. for (int i = getChildCount(); --i >= 0;)
  262. requestTransparentRegion (getChildAt (i));
  263. }
  264. private native void viewSizeChanged();
  265. @Override
  266. public void onFocusChange (View v, boolean hasFocus)
  267. {
  268. if (v == this)
  269. focusChanged (hasFocus);
  270. }
  271. private native void focusChanged (boolean hasFocus);
  272. public void setViewName (String newName) {}
  273. public boolean isVisible() { return getVisibility() == VISIBLE; }
  274. public void setVisible (boolean b) { setVisibility (b ? VISIBLE : INVISIBLE); }
  275. public boolean containsPoint (int x, int y)
  276. {
  277. return true; //xxx needs to check overlapping views
  278. }
  279. public OpenGLView createGLView()
  280. {
  281. OpenGLView glView = new OpenGLView (getContext());
  282. addView (glView);
  283. return glView;
  284. }
  285. }
  286. //==============================================================================
  287. public final class OpenGLView extends GLSurfaceView
  288. implements GLSurfaceView.Renderer
  289. {
  290. OpenGLView (Context context)
  291. {
  292. super (context);
  293. setEGLContextClientVersion (2);
  294. setRenderer (this);
  295. }
  296. @Override
  297. public void onSurfaceCreated (GL10 unused, EGLConfig config)
  298. {
  299. contextCreated();
  300. }
  301. @Override
  302. public void onSurfaceChanged (GL10 unused, int width, int height)
  303. {
  304. contextCreated();
  305. }
  306. @Override
  307. public void onDrawFrame (GL10 unused)
  308. {
  309. render();
  310. }
  311. private native void contextCreated();
  312. private native void render();
  313. }
  314. //==============================================================================
  315. public final int[] renderGlyph (char glyph, Paint paint, android.graphics.Matrix matrix, Rect bounds)
  316. {
  317. Path p = new Path();
  318. paint.getTextPath (String.valueOf (glyph), 0, 1, 0.0f, 0.0f, p);
  319. RectF boundsF = new RectF();
  320. p.computeBounds (boundsF, true);
  321. matrix.mapRect (boundsF);
  322. boundsF.roundOut (bounds);
  323. bounds.left--;
  324. bounds.right++;
  325. final int w = bounds.width();
  326. final int h = bounds.height();
  327. Bitmap bm = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888);
  328. Canvas c = new Canvas (bm);
  329. matrix.postTranslate (-bounds.left, -bounds.top);
  330. c.setMatrix (matrix);
  331. c.drawPath (p, paint);
  332. final int sizeNeeded = w * h;
  333. if (cachedRenderArray.length < sizeNeeded)
  334. cachedRenderArray = new int [sizeNeeded];
  335. bm.getPixels (cachedRenderArray, 0, w, 0, 0, w, h);
  336. bm.recycle();
  337. return cachedRenderArray;
  338. }
  339. private int[] cachedRenderArray = new int [256];
  340. //==============================================================================
  341. public static class HTTPStream
  342. {
  343. public HTTPStream (HttpURLConnection connection_) throws IOException
  344. {
  345. connection = connection_;
  346. inputStream = new BufferedInputStream (connection.getInputStream());
  347. }
  348. public final void release()
  349. {
  350. try
  351. {
  352. inputStream.close();
  353. }
  354. catch (IOException e)
  355. {}
  356. connection.disconnect();
  357. }
  358. public final int read (byte[] buffer, int numBytes)
  359. {
  360. int num = 0;
  361. try
  362. {
  363. num = inputStream.read (buffer, 0, numBytes);
  364. }
  365. catch (IOException e)
  366. {}
  367. if (num > 0)
  368. position += num;
  369. return num;
  370. }
  371. public final long getPosition() { return position; }
  372. public final long getTotalLength() { return -1; }
  373. public final boolean isExhausted() { return false; }
  374. public final boolean setPosition (long newPos) { return false; }
  375. private HttpURLConnection connection;
  376. private InputStream inputStream;
  377. private long position;
  378. }
  379. public static final HTTPStream createHTTPStream (String address, boolean isPost, byte[] postData,
  380. String headers, int timeOutMs,
  381. java.lang.StringBuffer responseHeaders)
  382. {
  383. try
  384. {
  385. HttpURLConnection connection = (HttpURLConnection) (new URL (address).openConnection());
  386. if (connection != null)
  387. {
  388. try
  389. {
  390. if (isPost)
  391. {
  392. connection.setConnectTimeout (timeOutMs);
  393. connection.setDoOutput (true);
  394. connection.setChunkedStreamingMode (0);
  395. OutputStream out = connection.getOutputStream();
  396. out.write (postData);
  397. out.flush();
  398. }
  399. return new HTTPStream (connection);
  400. }
  401. catch (Throwable e)
  402. {
  403. connection.disconnect();
  404. }
  405. }
  406. }
  407. catch (Throwable e)
  408. {}
  409. return null;
  410. }
  411. public final void launchURL (String url)
  412. {
  413. startActivity (new Intent (Intent.ACTION_VIEW, Uri.parse (url)));
  414. }
  415. }