Processing Android – Playing Sounds

How to play sounds on Android, using Processing Android.

The minim library doesn’t work on Android, so use APWidgets instead.

Example:

import apwidgets.*;
APMediaPlayer player;

void setup()
{
  player = new APMediaPlayer(this);

  // SOUND FILE IS LOCATED IN THE '/data' FOLDER
  player.setMediaFile("sound.mp3");
}

void keyPressed()
{
  if (key == 's') player.start();
}

Resources:
http://forum.processing.org/one/topic/audio-for-android.html
https://code.google.com/p/apwidgets/


Processing Android – Signing an Android app

How to sign an Android app, generated with Processing Android (or generated with another tool)?

Create a (Windows-) batch file (.bat) with the following code:

@echo off
ECHO.
set /p varSketchName="Please enter the Name of your sketch: "
ECHO.
set /p varSketchAlias="Please enter an Alias for your sketch: "
ECHO.
ECHO [KEYTOOL]
keytool -genkey -v -keystore %~dp0%varSketchName%-release-key.keystore -alias %varSketchAlias% -keyalg RSA -keysize 2048 -validity 10000
pause
ECHO [ANT RELEASE]
call ant release
pause
ECHO [JARSIGNER]
call jarsigner -verbose -keystore %~dp0%varSketchName%-release-key.keystore %~dp0bin\%varSketchName%-release-unsigned.apk %varSketchAlias%
pause
ECHO [JARSIGNER VERIFY]
call jarsigner -verify %~dp0bin\%varSketchName%-release-unsigned.apk
pause
ECHO [ZIPALIGN]
set /p varSignedAppName="Please enter name for final signed apk (w/o .apk extension): "
call zipalign -v 4 %~dp0bin\%varSketchName%-release-unsigned.apk %~dp0%varSignedAppName%.apk

Programs you need:

  • keytool.exe (part of the Java JDK)
  • ant.bat (part of Apache ant)
  • jarsigner.exe (part of the Java JDK)
  • zipalign.exe (part of the Android SDK)

Steps:

  1. In Processing: create your sketch in Android Mode
  2. Export the sketch as an Android Project (Ctrl-Shift-E)
  3. Copy the .bat-file above to the newly created android directory and run it
  4. Name of your sketch = name of the .pde-file (without .pde!)
  5. Alias = same as the name (or something else)
  6. Enter a password for your keystore
  7. Enter your personal data
  8. Enter the same keystore password again
  9. Enter the name of the final .apk-file (without the .apk extension!)

N.B. Make sure your folder names DON’T include any SPACES! That will break the batch file.

And there you go! You’ve got a signed .apk file!


Processing Android – Wakelock (Keep Screen On)

Set the Android WAKELOCK (Phone won’t go into power save mode)
You’re sketch will need the ‘WAKE_LOCK‘ permission!

// For WAKELOCK
import android.os.Bundle; 
import android.view.WindowManager;

/*****************************************************************************************
 *
 *   SET WAKELOCK (PHONE WON'T GO INTO POWER SAVE MODE)
 * 
 *****************************************************************************************/
void onCreate(Bundle bundle)
{ 
  super.onCreate(bundle);
  getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
} // onCreate()

Resources:
https://forum.processing.org/two/discussion/10486/how-do-i-get-the-android-view-for-my-sketch

Tested up to: Processing v3.1.2


Processing – Button Class

Button class for Java, Android and ProcessingJS modes:

Button btn;
btn = new Button(0, 0, btnWidth, btnHeight, color(255), color(255, 0, 0), "BUTTON");

/*****************************************************************************************
 * 
 *   BUTTON CLASS
 * 
 ****************************************************************************************/
class Button
{
  int x, y, w, h;
  color c;
  color cOver;
  String txt;
  int txtSize = 12;

  /****************************************************************************
   
   CONSTRUCTOR
   
   ****************************************************************************/
  Button (int _x, int _y, int _w, int _h, color _c, color _cover, String _txt)
  {
    x = _x;
    y = _y;
    w = _w;
    h = _h;
    c = _c;
    cOver = _cover;
    txt = _txt;
  }

  /****************************************************************************
   
   DISPLAY THE BUTTON
   
   ****************************************************************************/
  void display()
  {
    pushStyle();
    textAlign(CENTER);
    if (mouseOver())
      fill(cOver);
    else
      fill(c);
    stroke(100);
    strokeWeight(2);
    rect(x, y, w, h, 10);
    fill(0);
    textSize(txtSize);
    text(txt, x+w/2, y+h/2+txtSize/2);
    popStyle();
  }


  /****************************************************************************
   
   CHANGE THE TEXT ON THE BUTTON
   
   ****************************************************************************/
  void setText (String _txt)
  {
    txt = _txt;
    display();
  }

  /****************************************************************************
   
   IS THE MOUSE OVER THE BUTTON?
   
   ****************************************************************************/
  boolean mouseOver()
  {
    return (mouseX >= x && mouseX <= (x + w) && mouseY >= y && mouseY <= (y + h));
  }
} // Button

Processing – Crop Image Class

A Processing class for dynamically cropping an image.
For Java, Android and ProcessingJS modes:

Snippet:

/*****************************************************************************************
 * 
 *   CROPPER CLASS
 * 
 ****************************************************************************************/
public class Cropper
{
  // START POSITION: CENTER OF THE SCREEN
  float   x;
  float   y;

  float   xOffset = 0.0; 
  float   yOffset = 0.0;

  // MINIMUM SIZE OF THE CROP
  int     minWidth;
  int     minHeight;  

  boolean locked  = false;
  boolean enabled = false;


  /***************************************************************************************
   * 
   *   CONSTRUCTOR
   * 
   **************************************************************************************/
  Cropper(float _x, float _y, int _minWidth, int _minHeight)
  {
    x         = _x;
    y         = _y;
    minWidth  = _minWidth;
    minHeight = _minHeight;
  } // Cropper()


  /***************************************************************************************
   * 
   *   DISPLAY THE CROPPING FRAME
   * 
   **************************************************************************************/
  void display()
  {
    pushStyle();

    rectMode(RADIUS);
    strokeWeight(2);
    fill(255, 80);

    // IS ONE OF THE HANDLES BEING DRAGGED?
    boolean handleActive = false;

    // FIND THE ACTIVE HANDLE (=THE HANDLE BEING DRAGGED) AND MARK IT
    for (int i=0; i<4; i++) if (handles[i].locked) handleActive = true;

    if (handleActive)
    {
      // ONE OF THE HANDLES IS BEING DRAGGED
      stroke(255, 255, 0);
    } else
    {
      // CHANGE THE COLOR OF THE CROPPING FRAME, DEPENDING ON MOUSE OVER AND LOCKED STATE
      if (mouseOver())
      {
        if (!locked) stroke(255, 0, 0);
        else stroke(0, 0, 255);
      }
    }

    // DISPLAY CROPPING FRAME
    rect(x, y, cropperSizeDiv2, cropperSizeDiv2);

    // DISPLAY HANDLES
    // UPPER LEFT
    handles[0].display(x-cropperSizeDiv2+handleSizeDiv2, y-cropperSizeDiv2+handleSizeDiv2);    
    // UPPER RIGHT
    handles[1].display(x+cropperSizeDiv2-handleSizeDiv2, y-cropperSizeDiv2+handleSizeDiv2);
    // LOWER LEFT
    handles[2].display(x-cropperSizeDiv2+handleSizeDiv2, y+cropperSizeDiv2-handleSizeDiv2);
    // LOWER RIGHT
    handles[3].display(x+cropperSizeDiv2-handleSizeDiv2, y+cropperSizeDiv2-handleSizeDiv2);    

    popStyle();
  } // display()


  /***************************************************************************************
   * 
   *   MOUSE IS BEING DRAGGED
   * 
   **************************************************************************************/
  void mouseDragged()
  {     
    if (locked)
    { 
      x = mouseX - xOffset;
      y = mouseY - yOffset;
    }
  } // mouseDragged()


  /***************************************************************************************
   * 
   *   IS THE MOUSE OVER THE CROPPER?
   * 
   **************************************************************************************/
  boolean mouseOver()
  {
    return (mouseX > x-cropperSizeDiv2 && mouseX < x+cropperSizeDiv2
      && mouseY > y-cropperSizeDiv2 && mouseY < y+cropperSizeDiv2);
  } // mouseOver()
} // Cropper


/*****************************************************************************************
 * 
 *   HANDLE CLASS: THE HANDLES FOR CHANGING THE SIZE OF THE CROP
 * 
 ****************************************************************************************/
class Handle
{
  float   x, y;
  float   xOffset = 0.0; 
  float   yOffset = 0.0;
  boolean locked  = false;


  /***************************************************************************************
   * 
   *   CONSTRUCTOR
   * 
   **************************************************************************************/
  Handle()
  {
  } // Handle()


  /***************************************************************************************
   * 
   *   DISPLAY THE HANDLE
   * 
   **************************************************************************************/
  void display(float _x, float _y)
  {
    x = _x;
    y = _y;

    // IS ONE OF THE HANDLES BEING DRAGGED?
    boolean handleActive = false;
    for (int i=0; i<4; i++)
    {
      if (handles[i].locked) handleActive = true;
    }
    if (handleActive)
      // ONE OF THE HANDLES IS BEING DRAGGED: COLOR ALL HANDLES YELLOW
      fill(255, 255, 0);
    else    
      fill(0, 0, 255);

    noStroke();

    // DRAW HANDLE
    rect(x, y, handleSizeDiv2, handleSizeDiv2);
  } // display()


  /***************************************************************************************
   * 
   *   HANDLE IS BEING DRAGGED
   * 
   **************************************************************************************/
  void mouseDragged(int nr)
  {
    if (locked)
    { // THIS IS THE ACTIVE HANDLE (BEING DRAGGED)
      if (nr==0 || nr==2)
      { // UPPER LEFT OR LOWER LEFT
        xOffset = pmouseX-mouseX;
      } else
      { // UPPER RIGHT OR LOWER RIGHT
        xOffset = mouseX-pmouseX;
      }

      if (nr==0 || nr==1)
      { // UPPER LEFT OR UPPER RIGHT
        yOffset = pmouseY-mouseY;
      } else
      { // LOWER LEFT OR LOWER RIGHT
        yOffset = mouseY-pmouseY;
      }

      x = mouseX;     
      y = mouseY;

      cropperSizeDiv2 += xOffset;
      cropperSizeDiv2 += yOffset;

      // CONSTRAIN THE SIZE OF THE CROPPER
      if (cropperSizeDiv2 < thumbSizeDiv2) cropperSizeDiv2 = thumbSizeDiv2;
      if (cropperSizeDiv2 > (window.innerWidth>>1)) cropperSizeDiv2 = (window.innerWidth>>1);
    } // if (locked)
  } // mouseDragged()


  /***************************************************************************************
   * 
   *   IS THE MOUSE OVER THIS HANDLE?
   * 
   **************************************************************************************/
  boolean mouseOver()
  {
    return (mouseX > x-handleSizeDiv2 && mouseX < x+handleSizeDiv2
      && mouseY > y-handleSizeDiv2 && mouseY < y+handleSizeDiv2);
  } // mouseOver()
} // Handle

Resources:
SjansMachine 4.0 (‘Selfie’-version)


Processing – Error building Android for Processing project

Problem:
Error while building an Android for Processing v2.x project:
“Error from inside the Android tools, check the console.”

Fix:
Edit the file “C:\adt-bundle-windows-x86-20131030\sdk\tools\ant\build.xml
(Of course adjust the path to where your Android SDK is living… this fix works for Mac OSX too)

<!-- RvG changed to true -->
<property name="dex.disable.merger" value="true" />

If that doesn’t fix the problem have a look here:
http://forum.processing.org/one/topic/android-problems.html