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.

457 lines
15KB

  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.text.ClipboardManager;
  27. import java.io.BufferedInputStream;
  28. import java.io.IOException;
  29. import java.io.InputStream;
  30. import java.io.OutputStream;
  31. import java.net.URL;
  32. import java.net.HttpURLConnection;
  33. //==============================================================================
  34. public final class JuceAppActivity extends Activity
  35. {
  36. //==============================================================================
  37. static
  38. {
  39. System.loadLibrary ("juce_jni");
  40. }
  41. @Override
  42. public final void onCreate (Bundle savedInstanceState)
  43. {
  44. super.onCreate (savedInstanceState);
  45. viewHolder = new ViewHolder (this);
  46. setContentView (viewHolder);
  47. }
  48. @Override
  49. protected final void onDestroy()
  50. {
  51. quitApp();
  52. super.onDestroy();
  53. }
  54. private void callAppLauncher()
  55. {
  56. launchApp (getApplicationInfo().publicSourceDir,
  57. getApplicationInfo().dataDir);
  58. }
  59. //==============================================================================
  60. public native void launchApp (String appFile, String appDataDir);
  61. public native void quitApp();
  62. public native void setScreenSize (int screenWidth, int screenHeight);
  63. //==============================================================================
  64. public static final void printToConsole (String s)
  65. {
  66. android.util.Log.i ("Juce", s);
  67. }
  68. //==============================================================================
  69. public native void deliverMessage (long value);
  70. private android.os.Handler messageHandler = new android.os.Handler();
  71. public final void postMessage (long value)
  72. {
  73. messageHandler.post (new MessageCallback (value));
  74. }
  75. private final class MessageCallback implements Runnable
  76. {
  77. public MessageCallback (long value_) { value = value_; }
  78. public final void run() { deliverMessage (value); }
  79. private long value;
  80. }
  81. //==============================================================================
  82. private ViewHolder viewHolder;
  83. public final ComponentPeerView createNewView (boolean opaque)
  84. {
  85. ComponentPeerView v = new ComponentPeerView (this, opaque);
  86. viewHolder.addView (v);
  87. return v;
  88. }
  89. public final void deleteView (ComponentPeerView view)
  90. {
  91. viewHolder.removeView (view);
  92. }
  93. final class ViewHolder extends ViewGroup
  94. {
  95. public ViewHolder (Context context)
  96. {
  97. super (context);
  98. setDescendantFocusability (ViewGroup.FOCUS_AFTER_DESCENDANTS);
  99. setFocusable (false);
  100. }
  101. protected final void onLayout (boolean changed, int left, int top, int right, int bottom)
  102. {
  103. setScreenSize (getWidth(), getHeight());
  104. if (isFirstResize)
  105. {
  106. isFirstResize = false;
  107. callAppLauncher();
  108. }
  109. }
  110. private boolean isFirstResize = true;
  111. }
  112. public final void excludeClipRegion (android.graphics.Canvas canvas, float left, float top, float right, float bottom)
  113. {
  114. canvas.clipRect (left, top, right, bottom, android.graphics.Region.Op.DIFFERENCE);
  115. }
  116. //==============================================================================
  117. public final String getClipboardContent()
  118. {
  119. ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
  120. return clipboard.getText().toString();
  121. }
  122. public final void setClipboardContent (String newText)
  123. {
  124. ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
  125. clipboard.setText (newText);
  126. }
  127. //==============================================================================
  128. public final void showMessageBox (String title, String message, final long callback)
  129. {
  130. AlertDialog.Builder builder = new AlertDialog.Builder (this);
  131. builder.setTitle (title)
  132. .setMessage (message)
  133. .setCancelable (true)
  134. .setPositiveButton ("OK", new DialogInterface.OnClickListener()
  135. {
  136. public void onClick (DialogInterface dialog, int id)
  137. {
  138. dialog.cancel();
  139. JuceAppActivity.this.alertDismissed (callback, 0);
  140. }
  141. });
  142. builder.create().show();
  143. }
  144. public final void showOkCancelBox (String title, String message, final long callback)
  145. {
  146. AlertDialog.Builder builder = new AlertDialog.Builder (this);
  147. builder.setTitle (title)
  148. .setMessage (message)
  149. .setCancelable (true)
  150. .setPositiveButton ("OK", new DialogInterface.OnClickListener()
  151. {
  152. public void onClick (DialogInterface dialog, int id)
  153. {
  154. dialog.cancel();
  155. JuceAppActivity.this.alertDismissed (callback, 1);
  156. }
  157. })
  158. .setNegativeButton ("Cancel", new DialogInterface.OnClickListener()
  159. {
  160. public void onClick (DialogInterface dialog, int id)
  161. {
  162. dialog.cancel();
  163. JuceAppActivity.this.alertDismissed (callback, 0);
  164. }
  165. });
  166. builder.create().show();
  167. }
  168. public final void showYesNoCancelBox (String title, String message, final long callback)
  169. {
  170. AlertDialog.Builder builder = new AlertDialog.Builder (this);
  171. builder.setTitle (title)
  172. .setMessage (message)
  173. .setCancelable (true)
  174. .setPositiveButton ("Yes", new DialogInterface.OnClickListener()
  175. {
  176. public void onClick (DialogInterface dialog, int id)
  177. {
  178. dialog.cancel();
  179. JuceAppActivity.this.alertDismissed (callback, 1);
  180. }
  181. })
  182. .setNegativeButton ("No", new DialogInterface.OnClickListener()
  183. {
  184. public void onClick (DialogInterface dialog, int id)
  185. {
  186. dialog.cancel();
  187. JuceAppActivity.this.alertDismissed (callback, 2);
  188. }
  189. })
  190. .setNeutralButton ("Cancel", new DialogInterface.OnClickListener()
  191. {
  192. public void onClick (DialogInterface dialog, int id)
  193. {
  194. dialog.cancel();
  195. JuceAppActivity.this.alertDismissed (callback, 0);
  196. }
  197. });
  198. builder.create().show();
  199. }
  200. public native void alertDismissed (long callback, int id);
  201. //==============================================================================
  202. public class ComponentPeerView extends View
  203. implements View.OnFocusChangeListener
  204. {
  205. public ComponentPeerView (Context context, boolean opaque_)
  206. {
  207. super (context);
  208. opaque = opaque_;
  209. setFocusable (true);
  210. setFocusableInTouchMode (true);
  211. setOnFocusChangeListener (this);
  212. requestFocus();
  213. }
  214. //==============================================================================
  215. private native void handlePaint (Canvas canvas);
  216. @Override
  217. public void draw (Canvas canvas)
  218. {
  219. handlePaint (canvas);
  220. }
  221. @Override
  222. public boolean isOpaque()
  223. {
  224. return opaque;
  225. }
  226. private boolean opaque;
  227. //==============================================================================
  228. private native void handleMouseDown (float x, float y, long time);
  229. private native void handleMouseDrag (float x, float y, long time);
  230. private native void handleMouseUp (float x, float y, long time);
  231. @Override
  232. public boolean onTouchEvent (MotionEvent event)
  233. {
  234. switch (event.getAction())
  235. {
  236. case MotionEvent.ACTION_DOWN: handleMouseDown (event.getX(), event.getY(), event.getEventTime()); return true;
  237. case MotionEvent.ACTION_MOVE: handleMouseDrag (event.getX(), event.getY(), event.getEventTime()); return true;
  238. case MotionEvent.ACTION_CANCEL:
  239. case MotionEvent.ACTION_UP: handleMouseUp (event.getX(), event.getY(), event.getEventTime()); return true;
  240. default: break;
  241. }
  242. return false;
  243. }
  244. //==============================================================================
  245. @Override
  246. protected void onSizeChanged (int w, int h, int oldw, int oldh)
  247. {
  248. viewSizeChanged();
  249. }
  250. @Override
  251. protected void onLayout (boolean changed, int left, int top, int right, int bottom) {}
  252. private native void viewSizeChanged();
  253. @Override
  254. public void onFocusChange (View v, boolean hasFocus)
  255. {
  256. if (v == this)
  257. focusChanged (hasFocus);
  258. }
  259. private native void focusChanged (boolean hasFocus);
  260. public void setViewName (String newName) {}
  261. public boolean isVisible() { return getVisibility() == VISIBLE; }
  262. public void setVisible (boolean b) { setVisibility (b ? VISIBLE : INVISIBLE); }
  263. public boolean containsPoint (int x, int y)
  264. {
  265. return true; //xxx needs to check overlapping views
  266. }
  267. }
  268. //==============================================================================
  269. public final int[] renderGlyph (char glyph, Paint paint, android.graphics.Matrix matrix, Rect bounds)
  270. {
  271. Path p = new Path();
  272. paint.getTextPath (String.valueOf (glyph), 0, 1, 0.0f, 0.0f, p);
  273. RectF boundsF = new RectF();
  274. p.computeBounds (boundsF, true);
  275. matrix.mapRect (boundsF);
  276. boundsF.roundOut (bounds);
  277. bounds.left--;
  278. bounds.right++;
  279. final int w = bounds.width();
  280. final int h = bounds.height();
  281. Bitmap bm = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888);
  282. Canvas c = new Canvas (bm);
  283. matrix.postTranslate (-bounds.left, -bounds.top);
  284. c.setMatrix (matrix);
  285. c.drawPath (p, paint);
  286. int sizeNeeded = w * h;
  287. if (cachedRenderArray.length < sizeNeeded)
  288. cachedRenderArray = new int [sizeNeeded];
  289. bm.getPixels (cachedRenderArray, 0, w, 0, 0, w, h);
  290. bm.recycle();
  291. return cachedRenderArray;
  292. }
  293. private int[] cachedRenderArray = new int [256];
  294. //==============================================================================
  295. public static class HTTPStream
  296. {
  297. public HTTPStream (HttpURLConnection connection_) throws IOException
  298. {
  299. connection = connection_;
  300. inputStream = new BufferedInputStream (connection.getInputStream());
  301. }
  302. public final void release()
  303. {
  304. try
  305. {
  306. inputStream.close();
  307. }
  308. catch (IOException e)
  309. {}
  310. connection.disconnect();
  311. }
  312. public final int read (byte[] buffer, int numBytes)
  313. {
  314. int num = 0;
  315. try
  316. {
  317. num = inputStream.read (buffer, 0, numBytes);
  318. }
  319. catch (IOException e)
  320. {}
  321. if (num > 0)
  322. position += num;
  323. return num;
  324. }
  325. public final long getPosition()
  326. {
  327. return position;
  328. }
  329. public final long getTotalLength()
  330. {
  331. return -1;
  332. }
  333. public final boolean isExhausted()
  334. {
  335. return false;
  336. }
  337. public final boolean setPosition (long newPos)
  338. {
  339. return false;
  340. }
  341. private HttpURLConnection connection;
  342. private InputStream inputStream;
  343. private long position;
  344. }
  345. public static final HTTPStream createHTTPStream (String address, boolean isPost, byte[] postData,
  346. String headers, int timeOutMs, java.lang.StringBuffer responseHeaders)
  347. {
  348. try
  349. {
  350. HttpURLConnection connection = (HttpURLConnection) (new URL (address).openConnection());
  351. if (connection != null)
  352. {
  353. try
  354. {
  355. if (isPost)
  356. {
  357. connection.setConnectTimeout (timeOutMs);
  358. connection.setDoOutput (true);
  359. connection.setChunkedStreamingMode (0);
  360. OutputStream out = connection.getOutputStream();
  361. out.write (postData);
  362. out.flush();
  363. }
  364. return new HTTPStream (connection);
  365. }
  366. catch (Throwable e)
  367. {
  368. connection.disconnect();
  369. }
  370. }
  371. }
  372. catch (Throwable e)
  373. {}
  374. return null;
  375. }
  376. }