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.

513 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. getHolder().setFormat(PixelFormat.TRANSLUCENT);
  295. setVisibility (VISIBLE);
  296. setRenderer (this);
  297. //setRenderMode (RENDERMODE_CONTINUOUSLY);
  298. //requestRender();
  299. }
  300. @Override
  301. public void onSurfaceCreated (GL10 unused, EGLConfig config)
  302. {
  303. // contextCreated();
  304. }
  305. @Override
  306. public void onDrawFrame (GL10 unused)
  307. {
  308. //GLES20.glClearColor (1.0f, 0.5f, 0.0f, 1.0f);
  309. //GLES20.glClear (GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
  310. // render();
  311. }
  312. @Override
  313. public void onSurfaceChanged (GL10 unused, int width, int height)
  314. {
  315. //GLES20.glViewport (0, 0, width, height);
  316. }
  317. @Override
  318. protected void onLayout (boolean changed, int left, int top, int right, int bottom)
  319. {
  320. super.onLayout (changed, left, top, right, bottom);
  321. requestLayout();
  322. ((ViewGroup) getParent()).requestTransparentRegion (this);
  323. }
  324. private native void contextCreated();
  325. private native void render();
  326. }
  327. //==============================================================================
  328. public final int[] renderGlyph (char glyph, Paint paint, android.graphics.Matrix matrix, Rect bounds)
  329. {
  330. Path p = new Path();
  331. paint.getTextPath (String.valueOf (glyph), 0, 1, 0.0f, 0.0f, p);
  332. RectF boundsF = new RectF();
  333. p.computeBounds (boundsF, true);
  334. matrix.mapRect (boundsF);
  335. boundsF.roundOut (bounds);
  336. bounds.left--;
  337. bounds.right++;
  338. final int w = bounds.width();
  339. final int h = bounds.height();
  340. Bitmap bm = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888);
  341. Canvas c = new Canvas (bm);
  342. matrix.postTranslate (-bounds.left, -bounds.top);
  343. c.setMatrix (matrix);
  344. c.drawPath (p, paint);
  345. final int sizeNeeded = w * h;
  346. if (cachedRenderArray.length < sizeNeeded)
  347. cachedRenderArray = new int [sizeNeeded];
  348. bm.getPixels (cachedRenderArray, 0, w, 0, 0, w, h);
  349. bm.recycle();
  350. return cachedRenderArray;
  351. }
  352. private int[] cachedRenderArray = new int [256];
  353. //==============================================================================
  354. public static class HTTPStream
  355. {
  356. public HTTPStream (HttpURLConnection connection_) throws IOException
  357. {
  358. connection = connection_;
  359. inputStream = new BufferedInputStream (connection.getInputStream());
  360. }
  361. public final void release()
  362. {
  363. try
  364. {
  365. inputStream.close();
  366. }
  367. catch (IOException e)
  368. {}
  369. connection.disconnect();
  370. }
  371. public final int read (byte[] buffer, int numBytes)
  372. {
  373. int num = 0;
  374. try
  375. {
  376. num = inputStream.read (buffer, 0, numBytes);
  377. }
  378. catch (IOException e)
  379. {}
  380. if (num > 0)
  381. position += num;
  382. return num;
  383. }
  384. public final long getPosition() { return position; }
  385. public final long getTotalLength() { return -1; }
  386. public final boolean isExhausted() { return false; }
  387. public final boolean setPosition (long newPos) { return false; }
  388. private HttpURLConnection connection;
  389. private InputStream inputStream;
  390. private long position;
  391. }
  392. public static final HTTPStream createHTTPStream (String address, boolean isPost, byte[] postData,
  393. String headers, int timeOutMs,
  394. java.lang.StringBuffer responseHeaders)
  395. {
  396. try
  397. {
  398. HttpURLConnection connection = (HttpURLConnection) (new URL (address).openConnection());
  399. if (connection != null)
  400. {
  401. try
  402. {
  403. if (isPost)
  404. {
  405. connection.setConnectTimeout (timeOutMs);
  406. connection.setDoOutput (true);
  407. connection.setChunkedStreamingMode (0);
  408. OutputStream out = connection.getOutputStream();
  409. out.write (postData);
  410. out.flush();
  411. }
  412. return new HTTPStream (connection);
  413. }
  414. catch (Throwable e)
  415. {
  416. connection.disconnect();
  417. }
  418. }
  419. }
  420. catch (Throwable e)
  421. {}
  422. return null;
  423. }
  424. }