|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2015 - ROLI Ltd.
-
- Permission is granted to use this software under the terms of either:
- a) the GPL v2 (or any later version)
- b) the Affero GPL v3
-
- Details of these licenses can be found at: www.gnu.org/licenses
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.juce.com for more information.
-
- ==============================================================================
- */
-
- package com.juce.jucedemo;
-
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.content.DialogInterface;
- import android.content.Context;
- import android.content.Intent;
- import android.content.res.Configuration;
- import android.content.pm.PackageInfo;
- import android.content.pm.PackageManager;
- import android.net.Uri;
- import android.os.Bundle;
- import android.os.Looper;
- import android.os.Handler;
- import android.os.ParcelUuid;
- import android.os.Environment;
- import android.view.*;
- import android.view.inputmethod.BaseInputConnection;
- import android.view.inputmethod.EditorInfo;
- import android.view.inputmethod.InputConnection;
- import android.view.inputmethod.InputMethodManager;
- import android.graphics.*;
- import android.text.ClipboardManager;
- import android.text.InputType;
- import android.util.DisplayMetrics;
- import android.util.Log;
- import java.lang.Runnable;
- import java.util.*;
- import java.io.*;
- import java.net.URL;
- import java.net.HttpURLConnection;
- import android.media.AudioManager;
- import android.media.MediaScannerConnection;
- import android.media.MediaScannerConnection.MediaScannerConnectionClient;
- import android.support.v4.content.ContextCompat;
- import android.support.v4.app.ActivityCompat;
- import android.Manifest;
-
- import android.media.midi.*;
- import android.bluetooth.*;
- import android.bluetooth.le.*;
-
-
- //==============================================================================
- public class JuceDemo extends Activity
- {
- //==============================================================================
- static
- {
- System.loadLibrary ("juce_jni");
- }
-
- //==============================================================================
- public boolean isPermissionDeclaredInManifest (int permissionID)
- {
- String permissionToCheck = getAndroidPermissionName(permissionID);
-
- try
- {
- PackageInfo info = getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
-
- if (info.requestedPermissions != null)
- for (String permission : info.requestedPermissions)
- if (permission.equals (permissionToCheck))
- return true;
- }
- catch (PackageManager.NameNotFoundException e)
- {
- Log.d ("JUCE", "isPermissionDeclaredInManifest: PackageManager.NameNotFoundException = " + e.toString());
- }
-
- Log.d ("JUCE", "isPermissionDeclaredInManifest: could not find requested permission " + permissionToCheck);
- return false;
- }
-
- //==============================================================================
- // these have to match the values of enum PermissionID in C++ class RuntimePermissions:
- private static final int JUCE_PERMISSIONS_RECORD_AUDIO = 1;
- private static final int JUCE_PERMISSIONS_BLUETOOTH_MIDI = 2;
-
- private static String getAndroidPermissionName (int permissionID)
- {
- switch (permissionID)
- {
- case JUCE_PERMISSIONS_RECORD_AUDIO: return Manifest.permission.RECORD_AUDIO;
- case JUCE_PERMISSIONS_BLUETOOTH_MIDI: return Manifest.permission.ACCESS_COARSE_LOCATION;
- }
-
- // unknown permission ID!
- assert false;
- return new String();
- }
-
- public boolean isPermissionGranted (int permissionID)
- {
- return ContextCompat.checkSelfPermission (this, getAndroidPermissionName (permissionID)) == PackageManager.PERMISSION_GRANTED;
- }
-
- private Map<Integer, Long> permissionCallbackPtrMap;
-
- public void requestRuntimePermission (int permissionID, long ptrToCallback)
- {
- String permissionName = getAndroidPermissionName (permissionID);
-
- if (ContextCompat.checkSelfPermission (this, permissionName) != PackageManager.PERMISSION_GRANTED)
- {
- // remember callbackPtr, request permissions, and let onRequestPermissionResult call callback asynchronously
- permissionCallbackPtrMap.put (permissionID, ptrToCallback);
- ActivityCompat.requestPermissions (this, new String[]{permissionName}, permissionID);
- }
- else
- {
- // permissions were already granted before, we can call callback directly
- androidRuntimePermissionsCallback (true, ptrToCallback);
- }
- }
-
- private native void androidRuntimePermissionsCallback (boolean permissionWasGranted, long ptrToCallback);
-
- @Override
- public void onRequestPermissionsResult (int permissionID, String permissions[], int[] grantResults)
- {
- boolean permissionsGranted = (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED);
-
- if (! permissionsGranted)
- Log.d ("JUCE", "onRequestPermissionsResult: runtime permission was DENIED: " + getAndroidPermissionName (permissionID));
-
- Long ptrToCallback = permissionCallbackPtrMap.get (permissionID);
- permissionCallbackPtrMap.remove (permissionID);
- androidRuntimePermissionsCallback (permissionsGranted, ptrToCallback);
- }
-
- //==============================================================================
- public static class MidiPortID extends Object
- {
- public MidiPortID (int index, boolean direction)
- {
- androidIndex = index;
- isInput = direction;
- }
-
- public int androidIndex;
- public boolean isInput;
-
- @Override
- public int hashCode()
- {
- Integer i = new Integer (androidIndex);
- return i.hashCode() * (isInput ? -1 : 1);
- }
-
- @Override
- public boolean equals (Object obj)
- {
- if (obj == null)
- return false;
-
- if (getClass() != obj.getClass())
- return false;
-
- MidiPortID other = (MidiPortID) obj;
- return (androidIndex == other.androidIndex && isInput == other.isInput);
- }
- }
-
- public interface JuceMidiPort
- {
- boolean isInputPort();
-
- // start, stop does nothing on an output port
- void start();
- void stop();
-
- void close();
- MidiPortID getPortId();
-
- // send will do nothing on an input port
- void sendMidi (byte[] msg, int offset, int count);
- }
-
- //==============================================================================
- //==============================================================================
- public class BluetoothManager extends ScanCallback
- {
- BluetoothManager()
- {
- ScanFilter.Builder scanFilterBuilder = new ScanFilter.Builder();
- scanFilterBuilder.setServiceUuid (ParcelUuid.fromString (bluetoothLEMidiServiceUUID));
-
- ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder();
- scanSettingsBuilder.setCallbackType (ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
- .setScanMode (ScanSettings.SCAN_MODE_LOW_POWER)
- .setScanMode (ScanSettings.MATCH_MODE_STICKY);
-
- BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-
- if (bluetoothAdapter == null)
- {
- Log.d ("JUCE", "BluetoothManager error: could not get default Bluetooth adapter");
- return;
- }
-
- BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
-
- if (bluetoothLeScanner == null)
- {
- Log.d ("JUCE", "BluetoothManager error: could not get Bluetooth LE scanner");
- return;
- }
-
- bluetoothLeScanner.startScan (Arrays.asList (scanFilterBuilder.build()),
- scanSettingsBuilder.build(),
- this);
- }
-
- public String[] getMidiBluetoothAddresses()
- {
- return bluetoothMidiDevices.toArray (new String[bluetoothMidiDevices.size()]);
- }
-
- public String getHumanReadableStringForBluetoothAddress (String address)
- {
- BluetoothDevice btDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice (address);
- return btDevice.getName();
- }
-
- public boolean isBluetoothDevicePaired (String address)
- {
- return getAndroidMidiDeviceManager().isBluetoothDevicePaired (address);
- }
-
- public boolean pairBluetoothMidiDevice(String address)
- {
- BluetoothDevice btDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice (address);
-
- if (btDevice == null)
- {
- Log.d ("JUCE", "failed to create buletooth device from address");
- return false;
- }
-
- MidiManager mm = (MidiManager) getSystemService (MIDI_SERVICE);
-
- PhysicalMidiDevice midiDevice = PhysicalMidiDevice.fromBluetoothLeDevice (btDevice, mm);
-
- if (midiDevice != null)
- {
- getAndroidMidiDeviceManager().addDeviceToList (midiDevice);
- return true;
- }
-
- return false;
- }
-
- public void unpairBluetoothMidiDevice (String address)
- {
- getAndroidMidiDeviceManager().unpairBluetoothDevice (address);
- }
-
- public void onScanFailed (int errorCode)
- {
- }
-
- public void onScanResult (int callbackType, ScanResult result)
- {
- if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES
- || callbackType == ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
- {
- BluetoothDevice device = result.getDevice();
-
- if (device != null)
- bluetoothMidiDevices.add (device.getAddress());
- }
-
- if (callbackType == ScanSettings.CALLBACK_TYPE_MATCH_LOST)
- {
- Log.d ("JUCE", "ScanSettings.CALLBACK_TYPE_MATCH_LOST");
- BluetoothDevice device = result.getDevice();
-
- if (device != null)
- {
- bluetoothMidiDevices.remove (device.getAddress());
- unpairBluetoothMidiDevice (device.getAddress());
- }
- }
- }
-
- public void onBatchScanResults (List<ScanResult> results)
- {
- for (ScanResult result : results)
- onScanResult (ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result);
- }
-
- private BluetoothLeScanner scanner;
- private static final String bluetoothLEMidiServiceUUID = "03B80E5A-EDE8-4B33-A751-6CE34EC4C700";
-
- private HashSet<String> bluetoothMidiDevices = new HashSet<String>();
- }
-
- public static class JuceMidiInputPort extends MidiReceiver implements JuceMidiPort
- {
- private native void handleReceive (long host, byte[] msg, int offset, int count, long timestamp);
-
- public JuceMidiInputPort (PhysicalMidiDevice device, long host, MidiOutputPort midiPort)
- {
- parent = device;
- juceHost = host;
- port = midiPort;
- }
-
- @Override
- public boolean isInputPort()
- {
- return true;
- }
-
- @Override
- public void start()
- {
- port.connect (this);
- }
-
- @Override
- public void stop()
- {
- port.disconnect (this);
- }
-
- @Override
- public void close()
- {
- stop();
-
- try
- {
- port.close();
- }
- catch (IOException e)
- {
- Log.d ("JUCE", "JuceMidiInputPort::close: IOException = " + e.toString());
- }
-
- if (parent != null)
- {
- parent.removePort (port.getPortNumber(), true);
- parent = null;
- }
- }
-
- public void onSend (byte[] msg, int offset, int count, long timestamp)
- {
- if (count > 0)
- handleReceive (juceHost, msg, offset, count, timestamp);
- }
-
- @Override
- public MidiPortID getPortId()
- {
- return new MidiPortID (port.getPortNumber(), true);
- }
-
- @Override
- public void sendMidi (byte[] msg, int offset, int count)
- {
- }
-
- private PhysicalMidiDevice parent = null;
- private long juceHost = 0;
- private MidiOutputPort port;
- }
-
- public static class JuceMidiOutputPort implements JuceMidiPort
- {
- public JuceMidiOutputPort (PhysicalMidiDevice device, MidiInputPort midiPort)
- {
- parent = device;
- port = midiPort;
- }
-
- @Override
- public boolean isInputPort()
- {
- return false;
- }
-
- @Override
- public void start()
- {
- }
-
- @Override
- public void stop()
- {
- }
-
- @Override
- public void sendMidi (byte[] msg, int offset, int count)
- {
- try
- {
- port.send(msg, offset, count);
- }
- catch (IOException e)
- {
- Log.d ("JUCE", "JuceMidiOutputPort::sendMidi: IOException = " + e.toString());
- }
- }
-
- @Override
- public void close()
- {
- try
- {
- port.close();
- }
- catch (IOException e)
- {
- Log.d ("JUCE", "JuceMidiOutputPort::close: IOException = " + e.toString());
- }
-
- if (parent != null)
- {
- parent.removePort (port.getPortNumber(), false);
- parent = null;
- }
- }
-
-
- @Override
- public MidiPortID getPortId()
- {
- return new MidiPortID (port.getPortNumber(), false);
- }
-
- private PhysicalMidiDevice parent = null;
- private MidiInputPort port;
- }
-
- public static class PhysicalMidiDevice
- {
- private static class MidiDeviceThread extends Thread
- {
- public Handler handler = null;
- public Object sync = null;
-
- public MidiDeviceThread (Object syncrhonization)
- {
- sync = syncrhonization;
- }
-
- public void run()
- {
- Looper.prepare();
-
- synchronized (sync)
- {
- handler = new Handler();
- sync.notifyAll();
- }
-
- Looper.loop();
- }
- }
-
- private static class MidiDeviceOpenCallback implements MidiManager.OnDeviceOpenedListener
- {
- public Object sync = null;
- public boolean isWaiting = true;
- public android.media.midi.MidiDevice theDevice = null;
-
- public MidiDeviceOpenCallback (Object waiter)
- {
- sync = waiter;
- }
-
- public void onDeviceOpened (MidiDevice device)
- {
- synchronized (sync)
- {
- theDevice = device;
- isWaiting = false;
- sync.notifyAll();
- }
- }
- }
-
- public static PhysicalMidiDevice fromBluetoothLeDevice (BluetoothDevice bluetoothDevice, MidiManager mm)
- {
- Object waitForCreation = new Object();
- MidiDeviceThread thread = new MidiDeviceThread (waitForCreation);
- thread.start();
-
- synchronized (waitForCreation)
- {
- while (thread.handler == null)
- {
- try
- {
- waitForCreation.wait();
- }
- catch (InterruptedException e)
- {
- Log.d ("JUCE", "Wait was interrupted but we don't care");
- }
- }
- }
-
- Object waitForDevice = new Object();
-
- MidiDeviceOpenCallback openCallback = new MidiDeviceOpenCallback (waitForDevice);
-
- synchronized (waitForDevice)
- {
- mm.openBluetoothDevice (bluetoothDevice, openCallback, thread.handler);
-
- while (openCallback.isWaiting)
- {
- try
- {
- waitForDevice.wait();
- }
- catch (InterruptedException e)
- {
- Log.d ("JUCE", "Wait was interrupted but we don't care");
- }
- }
- }
-
- if (openCallback.theDevice == null)
- {
- Log.d ("JUCE", "openBluetoothDevice failed");
- return null;
- }
-
- PhysicalMidiDevice device = new PhysicalMidiDevice();
-
- device.handle = openCallback.theDevice;
- device.info = device.handle.getInfo();
- device.bluetoothAddress = bluetoothDevice.getAddress();
- device.midiManager = mm;
-
- return device;
- }
-
- public void unpair()
- {
- if (! bluetoothAddress.equals ("") && handle != null)
- {
- JuceMidiPort ports[] = new JuceMidiPort[0];
- ports = juceOpenedPorts.values().toArray(ports);
-
- for (int i = 0; i < ports.length; ++i)
- ports[i].close();
-
- juceOpenedPorts.clear();
-
- try
- {
- handle.close();
- }
- catch (IOException e)
- {
- Log.d ("JUCE", "handle.close(): IOException = " + e.toString());
- }
-
- handle = null;
- }
- }
-
- public static PhysicalMidiDevice fromMidiDeviceInfo (MidiDeviceInfo info, MidiManager mm)
- {
- PhysicalMidiDevice device = new PhysicalMidiDevice();
- device.info = info;
- device.midiManager = mm;
- return device;
- }
-
- public PhysicalMidiDevice()
- {
- bluetoothAddress = "";
- juceOpenedPorts = new Hashtable<MidiPortID, JuceMidiPort>();
- handle = null;
- }
-
- public MidiDeviceInfo.PortInfo[] getPorts()
- {
- return info.getPorts();
- }
-
- public String getHumanReadableNameForPort (MidiDeviceInfo.PortInfo port, int portIndexToUseInName)
- {
- String portName = port.getName();
-
- if (portName.equals (""))
- portName = ((port.getType() == MidiDeviceInfo.PortInfo.TYPE_OUTPUT) ? "Out " : "In ")
- + Integer.toString (portIndexToUseInName);
-
- return getHumanReadableDeviceName() + " " + portName;
- }
-
- public String getHumanReadableNameForPort (int portType, int androidPortID, int portIndexToUseInName)
- {
- MidiDeviceInfo.PortInfo[] ports = info.getPorts();
-
- for (MidiDeviceInfo.PortInfo port : ports)
- {
- if (port.getType() == portType)
- {
- if (port.getPortNumber() == androidPortID)
- return getHumanReadableNameForPort (port, portIndexToUseInName);
- }
- }
-
- return "Unknown";
- }
-
- public String getHumanReadableDeviceName()
- {
- Bundle bundle = info.getProperties();
- return bundle.getString (MidiDeviceInfo.PROPERTY_NAME , "Unknown device");
- }
-
- public void checkIfDeviceCanBeClosed()
- {
- if (juceOpenedPorts.size() == 0)
- {
- // never close bluetooth LE devices, otherwise they unpair and we have
- // no idea how many ports they have.
- // Only remove bluetooth devices when we specifically unpair
- if (bluetoothAddress.equals (""))
- {
- try
- {
- handle.close();
- handle = null;
- }
- catch (IOException e)
- {
- Log.d ("JUCE", "PhysicalMidiDevice::checkIfDeviceCanBeClosed: IOException = " + e.toString());
- }
- }
- }
- }
-
- public void removePort (int portIdx, boolean isInput)
- {
- MidiPortID portID = new MidiPortID (portIdx, isInput);
- JuceMidiPort port = juceOpenedPorts.get (portID);
-
- if (port != null)
- {
- juceOpenedPorts.remove (portID);
- checkIfDeviceCanBeClosed();
- return;
- }
-
- // tried to remove a port that was never added
- assert false;
- }
-
- public JuceMidiPort openPort (int portIdx, boolean isInput, long host)
- {
- open();
-
- if (handle == null)
- {
- Log.d ("JUCE", "PhysicalMidiDevice::openPort: handle = null, device not open");
- return null;
- }
-
- // make sure that the port is not already open
- if (findPortForIdx (portIdx, isInput) != null)
- {
- Log.d ("JUCE", "PhysicalMidiDevice::openInputPort: port already open, not opening again!");
- return null;
- }
-
- JuceMidiPort retval = null;
-
- if (isInput)
- {
- MidiOutputPort androidPort = handle.openOutputPort (portIdx);
-
- if (androidPort == null)
- {
- Log.d ("JUCE", "PhysicalMidiDevice::openPort: MidiDevice::openOutputPort (portIdx = "
- + Integer.toString (portIdx) + ") failed!");
- return null;
- }
-
- retval = new JuceMidiInputPort (this, host, androidPort);
- }
- else
- {
- MidiInputPort androidPort = handle.openInputPort (portIdx);
-
- if (androidPort == null)
- {
- Log.d ("JUCE", "PhysicalMidiDevice::openPort: MidiDevice::openInputPort (portIdx = "
- + Integer.toString (portIdx) + ") failed!");
- return null;
- }
-
- retval = new JuceMidiOutputPort (this, androidPort);
- }
-
- juceOpenedPorts.put (new MidiPortID (portIdx, isInput), retval);
- return retval;
- }
-
- private JuceMidiPort findPortForIdx (int idx, boolean isInput)
- {
- return juceOpenedPorts.get (new MidiPortID (idx, isInput));
- }
-
- // opens the device
- private synchronized void open()
- {
- if (handle != null)
- return;
-
- Object waitForCreation = new Object();
- MidiDeviceThread thread = new MidiDeviceThread (waitForCreation);
- thread.start();
-
- synchronized(waitForCreation)
- {
- while (thread.handler == null)
- {
- try
- {
- waitForCreation.wait();
- }
- catch (InterruptedException e)
- {
- Log.d ("JUCE", "wait was interrupted but we don't care");
- }
- }
- }
-
- Object waitForDevice = new Object();
-
- MidiDeviceOpenCallback openCallback = new MidiDeviceOpenCallback (waitForDevice);
-
- synchronized (waitForDevice)
- {
- midiManager.openDevice (info, openCallback, thread.handler);
-
- while (openCallback.isWaiting)
- {
- try
- {
- waitForDevice.wait();
- }
- catch (InterruptedException e)
- {
- Log.d ("JUCE", "wait was interrupted but we don't care");
- }
- }
- }
-
- handle = openCallback.theDevice;
- }
-
- private MidiDeviceInfo info;
- private Hashtable<MidiPortID, JuceMidiPort> juceOpenedPorts;
- public MidiDevice handle;
- public String bluetoothAddress;
- private MidiManager midiManager;
- }
-
- //==============================================================================
- public class MidiDeviceManager extends MidiManager.DeviceCallback
- {
- public class MidiPortPath
- {
- public PhysicalMidiDevice midiDevice;
- public int androidMidiPortID;
- public int portIndexToUseInName;
- }
-
- public class JuceDeviceList
- {
- public ArrayList<MidiPortPath> inPorts = new ArrayList<MidiPortPath>();
- public ArrayList<MidiPortPath> outPorts = new ArrayList<MidiPortPath>();
- }
-
- // We need to keep a thread local copy of the devices
- // which we returned the last time
- // getJuceAndroidMidiIn/OutputDevices() was called
- private final ThreadLocal<JuceDeviceList> lastDevicesReturned =
- new ThreadLocal<JuceDeviceList>()
- {
- @Override protected JuceDeviceList initialValue()
- {
- return new JuceDeviceList();
- }
- };
-
- public MidiDeviceManager()
- {
- physicalMidiDevices = new ArrayList<PhysicalMidiDevice>();
- manager = (MidiManager) getSystemService (MIDI_SERVICE);
-
- if (manager == null)
- {
- Log.d ("JUCE", "MidiDeviceManager error: could not get MidiManager system service");
- return;
- }
-
- manager.registerDeviceCallback (this, null);
-
- MidiDeviceInfo[] foundDevices = manager.getDevices();
-
- for (MidiDeviceInfo info : foundDevices)
- physicalMidiDevices.add (PhysicalMidiDevice.fromMidiDeviceInfo (info, manager));
- }
-
- // specifically add a device to the list
- public void addDeviceToList (PhysicalMidiDevice device)
- {
- physicalMidiDevices.add (device);
- }
-
- public void unpairBluetoothDevice (String address)
- {
- for (int i = 0; i < physicalMidiDevices.size(); ++i)
- {
- PhysicalMidiDevice device = physicalMidiDevices.get(i);
-
- if (device.bluetoothAddress.equals (address))
- {
- physicalMidiDevices.remove (i);
- device.unpair();
- return;
- }
- }
- }
-
- public boolean isBluetoothDevicePaired (String address)
- {
- for (int i = 0; i < physicalMidiDevices.size(); ++i)
- {
- PhysicalMidiDevice device = physicalMidiDevices.get(i);
-
- if (device.bluetoothAddress.equals (address))
- return true;
- }
-
- return false;
- }
-
- public String[] getJuceAndroidMidiInputDevices()
- {
- return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_INPUT);
- }
-
- public String[] getJuceAndroidMidiOutputDevices()
- {
- return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_OUTPUT);
- }
-
- private String[] getJuceAndroidMidiDevices (int portType)
- {
- ArrayList<MidiPortPath> listOfReturnedDevices = new ArrayList<MidiPortPath>();
- List<String> deviceNames = new ArrayList<String>();
-
- for (PhysicalMidiDevice physicalMidiDevice : physicalMidiDevices)
- {
- int portIdx = 0;
- MidiDeviceInfo.PortInfo[] ports = physicalMidiDevice.getPorts();
-
- for (MidiDeviceInfo.PortInfo port : ports)
- {
- if (port.getType() == portType)
- {
- MidiPortPath path = new MidiPortPath();
- path.midiDevice = physicalMidiDevice;
- path.androidMidiPortID = port.getPortNumber();
- path.portIndexToUseInName = ++portIdx;
- listOfReturnedDevices.add (path);
-
- deviceNames.add (physicalMidiDevice.getHumanReadableNameForPort (port,
- path.portIndexToUseInName));
- }
- }
- }
-
- String[] deviceNamesArray = new String[deviceNames.size()];
-
- if (portType == MidiDeviceInfo.PortInfo.TYPE_INPUT)
- {
- lastDevicesReturned.get().inPorts.clear();
- lastDevicesReturned.get().inPorts.addAll (listOfReturnedDevices);
- }
- else
- {
- lastDevicesReturned.get().outPorts.clear();
- lastDevicesReturned.get().outPorts.addAll (listOfReturnedDevices);
- }
-
- return deviceNames.toArray(deviceNamesArray);
- }
-
- public JuceMidiPort openMidiInputPortWithJuceIndex (int index, long host)
- {
- ArrayList<MidiPortPath> lastDevices = lastDevicesReturned.get().inPorts;
-
- if (index >= lastDevices.size() || index < 0)
- return null;
-
- MidiPortPath path = lastDevices.get (index);
- return path.midiDevice.openPort (path.androidMidiPortID, true, host);
- }
-
- public JuceMidiPort openMidiOutputPortWithJuceIndex (int index)
- {
- ArrayList<MidiPortPath> lastDevices = lastDevicesReturned.get().outPorts;
-
- if (index >= lastDevices.size() || index < 0)
- return null;
-
- MidiPortPath path = lastDevices.get (index);
- return path.midiDevice.openPort (path.androidMidiPortID, false, 0);
- }
-
- public String getInputPortNameForJuceIndex (int index)
- {
- ArrayList<MidiPortPath> lastDevices = lastDevicesReturned.get().inPorts;
-
- if (index >= lastDevices.size() || index < 0)
- return "";
-
- MidiPortPath path = lastDevices.get (index);
-
- return path.midiDevice.getHumanReadableNameForPort (MidiDeviceInfo.PortInfo.TYPE_INPUT,
- path.androidMidiPortID,
- path.portIndexToUseInName);
- }
-
- public String getOutputPortNameForJuceIndex (int index)
- {
- ArrayList<MidiPortPath> lastDevices = lastDevicesReturned.get().outPorts;
-
- if (index >= lastDevices.size() || index < 0)
- return "";
-
- MidiPortPath path = lastDevices.get (index);
-
- return path.midiDevice.getHumanReadableNameForPort (MidiDeviceInfo.PortInfo.TYPE_OUTPUT,
- path.androidMidiPortID,
- path.portIndexToUseInName);
- }
-
- public void onDeviceAdded (MidiDeviceInfo info)
- {
- PhysicalMidiDevice device = PhysicalMidiDevice.fromMidiDeviceInfo (info, manager);
-
- // Do not add bluetooth devices as they are already added by the native bluetooth dialog
- if (info.getType() != MidiDeviceInfo.TYPE_BLUETOOTH)
- physicalMidiDevices.add (device);
- }
-
- public void onDeviceRemoved (MidiDeviceInfo info)
- {
- for (int i = 0; i < physicalMidiDevices.size(); ++i)
- {
- if (physicalMidiDevices.get(i).info.getId() == info.getId())
- {
- physicalMidiDevices.remove (i);
- return;
- }
- }
- // Don't assert here as this may be called again after a bluetooth device is unpaired
- }
-
- public void onDeviceStatusChanged (MidiDeviceStatus status)
- {
- }
-
- private ArrayList<PhysicalMidiDevice> physicalMidiDevices;
- private MidiManager manager;
- }
-
- public MidiDeviceManager getAndroidMidiDeviceManager()
- {
- if (getSystemService (MIDI_SERVICE) == null)
- return null;
-
- synchronized (JuceDemo.class)
- {
- if (midiDeviceManager == null)
- midiDeviceManager = new MidiDeviceManager();
- }
-
- return midiDeviceManager;
- }
-
- public BluetoothManager getAndroidBluetoothManager()
- {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
- if (adapter == null)
- return null;
-
- if (adapter.getBluetoothLeScanner() == null)
- return null;
-
- synchronized (JuceDemo.class)
- {
- if (bluetoothManager == null)
- bluetoothManager = new BluetoothManager();
- }
-
- return bluetoothManager;
- }
-
- //==============================================================================
- @Override
- public void onCreate (Bundle savedInstanceState)
- {
- super.onCreate (savedInstanceState);
-
- isScreenSaverEnabled = true;
- hideActionBar();
- viewHolder = new ViewHolder (this);
- setContentView (viewHolder);
-
- setVolumeControlStream (AudioManager.STREAM_MUSIC);
-
- permissionCallbackPtrMap = new HashMap<Integer, Long>();
- }
-
- @Override
- protected void onDestroy()
- {
- quitApp();
- super.onDestroy();
-
- clearDataCache();
- }
-
- @Override
- protected void onPause()
- {
- suspendApp();
- super.onPause();
- }
-
- @Override
- protected void onResume()
- {
- super.onResume();
- resumeApp();
- }
-
- @Override
- public void onConfigurationChanged (Configuration cfg)
- {
- super.onConfigurationChanged (cfg);
- setContentView (viewHolder);
- }
-
- private void callAppLauncher()
- {
- launchApp (getApplicationInfo().publicSourceDir,
- getApplicationInfo().dataDir);
- }
-
- private void hideActionBar()
- {
- // get "getActionBar" method
- java.lang.reflect.Method getActionBarMethod = null;
- try
- {
- getActionBarMethod = this.getClass().getMethod ("getActionBar");
- }
- catch (SecurityException e) { return; }
- catch (NoSuchMethodException e) { return; }
- if (getActionBarMethod == null) return;
-
- // invoke "getActionBar" method
- Object actionBar = null;
- try
- {
- actionBar = getActionBarMethod.invoke (this);
- }
- catch (java.lang.IllegalArgumentException e) { return; }
- catch (java.lang.IllegalAccessException e) { return; }
- catch (java.lang.reflect.InvocationTargetException e) { return; }
- if (actionBar == null) return;
-
- // get "hide" method
- java.lang.reflect.Method actionBarHideMethod = null;
- try
- {
- actionBarHideMethod = actionBar.getClass().getMethod ("hide");
- }
- catch (SecurityException e) { return; }
- catch (NoSuchMethodException e) { return; }
- if (actionBarHideMethod == null) return;
-
- // invoke "hide" method
- try
- {
- actionBarHideMethod.invoke (actionBar);
- }
- catch (java.lang.IllegalArgumentException e) {}
- catch (java.lang.IllegalAccessException e) {}
- catch (java.lang.reflect.InvocationTargetException e) {}
- }
-
- //==============================================================================
- private native void launchApp (String appFile, String appDataDir);
- private native void quitApp();
- private native void suspendApp();
- private native void resumeApp();
- private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
-
- //==============================================================================
- public native void deliverMessage (long value);
- private android.os.Handler messageHandler = new android.os.Handler();
-
- public final void postMessage (long value)
- {
- messageHandler.post (new MessageCallback (value));
- }
-
- private final class MessageCallback implements Runnable
- {
- public MessageCallback (long value_) { value = value_; }
- public final void run() { deliverMessage (value); }
-
- private long value;
- }
-
- //==============================================================================
- private ViewHolder viewHolder;
- private MidiDeviceManager midiDeviceManager = null;
- private BluetoothManager bluetoothManager = null;
- private boolean isScreenSaverEnabled;
- private java.util.Timer keepAliveTimer;
-
- public final ComponentPeerView createNewView (boolean opaque, long host)
- {
- ComponentPeerView v = new ComponentPeerView (this, opaque, host);
- viewHolder.addView (v);
- return v;
- }
-
- public final void deleteView (ComponentPeerView view)
- {
- ViewGroup group = (ViewGroup) (view.getParent());
-
- if (group != null)
- group.removeView (view);
- }
-
- public final void deleteNativeSurfaceView (NativeSurfaceView view)
- {
- ViewGroup group = (ViewGroup) (view.getParent());
-
- if (group != null)
- group.removeView (view);
- }
-
- final class ViewHolder extends ViewGroup
- {
- public ViewHolder (Context context)
- {
- super (context);
- setDescendantFocusability (ViewGroup.FOCUS_AFTER_DESCENDANTS);
- setFocusable (false);
- }
-
- protected final void onLayout (boolean changed, int left, int top, int right, int bottom)
- {
- setScreenSize (getWidth(), getHeight(), getDPI());
-
- if (isFirstResize)
- {
- isFirstResize = false;
- callAppLauncher();
- }
- }
-
- private final int getDPI()
- {
- DisplayMetrics metrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics (metrics);
- return metrics.densityDpi;
- }
-
- private boolean isFirstResize = true;
- }
-
- public final void excludeClipRegion (android.graphics.Canvas canvas, float left, float top, float right, float bottom)
- {
- canvas.clipRect (left, top, right, bottom, android.graphics.Region.Op.DIFFERENCE);
- }
-
- //==============================================================================
- public final void setScreenSaver (boolean enabled)
- {
- if (isScreenSaverEnabled != enabled)
- {
- isScreenSaverEnabled = enabled;
-
- if (keepAliveTimer != null)
- {
- keepAliveTimer.cancel();
- keepAliveTimer = null;
- }
-
- if (enabled)
- {
- getWindow().clearFlags (WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
- else
- {
- getWindow().addFlags (WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
- // If no user input is received after about 3 seconds, the OS will lower the
- // task's priority, so this timer forces it to be kept active.
- keepAliveTimer = new java.util.Timer();
-
- keepAliveTimer.scheduleAtFixedRate (new TimerTask()
- {
- @Override
- public void run()
- {
- android.app.Instrumentation instrumentation = new android.app.Instrumentation();
-
- try
- {
- instrumentation.sendKeyDownUpSync (KeyEvent.KEYCODE_UNKNOWN);
- }
- catch (Exception e)
- {
- }
- }
- }, 2000, 2000);
- }
- }
- }
-
- public final boolean getScreenSaver()
- {
- return isScreenSaverEnabled;
- }
-
- //==============================================================================
- public final String getClipboardContent()
- {
- ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
- return clipboard.getText().toString();
- }
-
- public final void setClipboardContent (String newText)
- {
- ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
- clipboard.setText (newText);
- }
-
- //==============================================================================
- public final void showMessageBox (String title, String message, final long callback)
- {
- AlertDialog.Builder builder = new AlertDialog.Builder (this);
- builder.setTitle (title)
- .setMessage (message)
- .setCancelable (true)
- .setPositiveButton ("OK", new DialogInterface.OnClickListener()
- {
- public void onClick (DialogInterface dialog, int id)
- {
- dialog.cancel();
- JuceDemo.this.alertDismissed (callback, 0);
- }
- });
-
- builder.create().show();
- }
-
- public final void showOkCancelBox (String title, String message, final long callback)
- {
- AlertDialog.Builder builder = new AlertDialog.Builder (this);
- builder.setTitle (title)
- .setMessage (message)
- .setCancelable (true)
- .setPositiveButton ("OK", new DialogInterface.OnClickListener()
- {
- public void onClick (DialogInterface dialog, int id)
- {
- dialog.cancel();
- JuceDemo.this.alertDismissed (callback, 1);
- }
- })
- .setNegativeButton ("Cancel", new DialogInterface.OnClickListener()
- {
- public void onClick (DialogInterface dialog, int id)
- {
- dialog.cancel();
- JuceDemo.this.alertDismissed (callback, 0);
- }
- });
-
- builder.create().show();
- }
-
- public final void showYesNoCancelBox (String title, String message, final long callback)
- {
- AlertDialog.Builder builder = new AlertDialog.Builder (this);
- builder.setTitle (title)
- .setMessage (message)
- .setCancelable (true)
- .setPositiveButton ("Yes", new DialogInterface.OnClickListener()
- {
- public void onClick (DialogInterface dialog, int id)
- {
- dialog.cancel();
- JuceDemo.this.alertDismissed (callback, 1);
- }
- })
- .setNegativeButton ("No", new DialogInterface.OnClickListener()
- {
- public void onClick (DialogInterface dialog, int id)
- {
- dialog.cancel();
- JuceDemo.this.alertDismissed (callback, 2);
- }
- })
- .setNeutralButton ("Cancel", new DialogInterface.OnClickListener()
- {
- public void onClick (DialogInterface dialog, int id)
- {
- dialog.cancel();
- JuceDemo.this.alertDismissed (callback, 0);
- }
- });
-
- builder.create().show();
- }
-
- public native void alertDismissed (long callback, int id);
-
- //==============================================================================
- public final class ComponentPeerView extends ViewGroup
- implements View.OnFocusChangeListener
- {
- public ComponentPeerView (Context context, boolean opaque_, long host)
- {
- super (context);
- this.host = host;
- setWillNotDraw (false);
- opaque = opaque_;
-
- setFocusable (true);
- setFocusableInTouchMode (true);
- setOnFocusChangeListener (this);
- requestFocus();
-
- // swap red and blue colours to match internal opengl texture format
- ColorMatrix colorMatrix = new ColorMatrix();
-
- float[] colorTransform = { 0, 0, 1.0f, 0, 0,
- 0, 1.0f, 0, 0, 0,
- 1.0f, 0, 0, 0, 0,
- 0, 0, 0, 1.0f, 0 };
-
- colorMatrix.set (colorTransform);
- paint.setColorFilter (new ColorMatrixColorFilter (colorMatrix));
- }
-
- //==============================================================================
- private native void handlePaint (long host, Canvas canvas, Paint paint);
-
- @Override
- public void onDraw (Canvas canvas)
- {
- handlePaint (host, canvas, paint);
- }
-
- @Override
- public boolean isOpaque()
- {
- return opaque;
- }
-
- private boolean opaque;
- private long host;
- private Paint paint = new Paint();
-
- //==============================================================================
- private native void handleMouseDown (long host, int index, float x, float y, long time);
- private native void handleMouseDrag (long host, int index, float x, float y, long time);
- private native void handleMouseUp (long host, int index, float x, float y, long time);
-
- @Override
- public boolean onTouchEvent (MotionEvent event)
- {
- int action = event.getAction();
- long time = event.getEventTime();
-
- switch (action & MotionEvent.ACTION_MASK)
- {
- case MotionEvent.ACTION_DOWN:
- handleMouseDown (host, event.getPointerId(0), event.getX(), event.getY(), time);
- return true;
-
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- handleMouseUp (host, event.getPointerId(0), event.getX(), event.getY(), time);
- return true;
-
- case MotionEvent.ACTION_MOVE:
- {
- int n = event.getPointerCount();
- for (int i = 0; i < n; ++i)
- handleMouseDrag (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
-
- return true;
- }
-
- case MotionEvent.ACTION_POINTER_UP:
- {
- int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
- handleMouseUp (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
- return true;
- }
-
- case MotionEvent.ACTION_POINTER_DOWN:
- {
- int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
- handleMouseDown (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
- return true;
- }
-
- default:
- break;
- }
-
- return false;
- }
-
- //==============================================================================
- private native void handleKeyDown (long host, int keycode, int textchar);
- private native void handleKeyUp (long host, int keycode, int textchar);
-
- public void showKeyboard (String type)
- {
- InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE);
-
- if (imm != null)
- {
- if (type.length() > 0)
- {
- imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
- imm.setInputMethod (getWindowToken(), type);
- }
- else
- {
- imm.hideSoftInputFromWindow (getWindowToken(), 0);
- }
- }
- }
-
- @Override
- public boolean onKeyDown (int keyCode, KeyEvent event)
- {
- switch (keyCode)
- {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- return super.onKeyDown (keyCode, event);
-
- default: break;
- }
-
- handleKeyDown (host, keyCode, event.getUnicodeChar());
- return true;
- }
-
- @Override
- public boolean onKeyUp (int keyCode, KeyEvent event)
- {
- handleKeyUp (host, keyCode, event.getUnicodeChar());
- return true;
- }
-
- @Override
- public boolean onKeyMultiple (int keyCode, int count, KeyEvent event)
- {
- if (keyCode != KeyEvent.KEYCODE_UNKNOWN || event.getAction() != KeyEvent.ACTION_MULTIPLE)
- return super.onKeyMultiple (keyCode, count, event);
-
- if (event.getCharacters() != null)
- {
- int utf8Char = event.getCharacters().codePointAt (0);
- handleKeyDown (host, utf8Char, utf8Char);
- return true;
- }
-
- return false;
- }
-
- // this is here to make keyboard entry work on a Galaxy Tab2 10.1
- @Override
- public InputConnection onCreateInputConnection (EditorInfo outAttrs)
- {
- outAttrs.actionLabel = "";
- outAttrs.hintText = "";
- outAttrs.initialCapsMode = 0;
- outAttrs.initialSelEnd = outAttrs.initialSelStart = -1;
- outAttrs.label = "";
- outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI;
- outAttrs.inputType = InputType.TYPE_NULL;
-
- return new BaseInputConnection (this, false);
- }
-
- //==============================================================================
- @Override
- protected void onSizeChanged (int w, int h, int oldw, int oldh)
- {
- super.onSizeChanged (w, h, oldw, oldh);
- viewSizeChanged (host);
- }
-
- @Override
- protected void onLayout (boolean changed, int left, int top, int right, int bottom)
- {
- for (int i = getChildCount(); --i >= 0;)
- requestTransparentRegion (getChildAt (i));
- }
-
- private native void viewSizeChanged (long host);
-
- @Override
- public void onFocusChange (View v, boolean hasFocus)
- {
- if (v == this)
- focusChanged (host, hasFocus);
- }
-
- private native void focusChanged (long host, boolean hasFocus);
-
- public void setViewName (String newName) {}
-
- public boolean isVisible() { return getVisibility() == VISIBLE; }
- public void setVisible (boolean b) { setVisibility (b ? VISIBLE : INVISIBLE); }
-
- public boolean containsPoint (int x, int y)
- {
- return true; //xxx needs to check overlapping views
- }
- }
-
- //==============================================================================
- public static class NativeSurfaceView extends SurfaceView
- implements SurfaceHolder.Callback
- {
- private long nativeContext = 0;
-
- NativeSurfaceView (Context context, long nativeContextPtr)
- {
- super (context);
- nativeContext = nativeContextPtr;
- }
-
- public Surface getNativeSurface()
- {
- Surface retval = null;
-
- SurfaceHolder holder = getHolder();
- if (holder != null)
- retval = holder.getSurface();
-
- return retval;
- }
-
- //==============================================================================
- @Override
- public void surfaceChanged (SurfaceHolder holder, int format, int width, int height)
- {
- surfaceChangedNative (nativeContext, holder, format, width, height);
- }
-
- @Override
- public void surfaceCreated (SurfaceHolder holder)
- {
- surfaceCreatedNative (nativeContext, holder);
- }
-
- @Override
- public void surfaceDestroyed (SurfaceHolder holder)
- {
- surfaceDestroyedNative (nativeContext, holder);
- }
-
- @Override
- protected void dispatchDraw (Canvas canvas)
- {
- super.dispatchDraw (canvas);
- dispatchDrawNative (nativeContext, canvas);
- }
-
- //==============================================================================
- @Override
- protected void onAttachedToWindow ()
- {
- super.onAttachedToWindow();
- getHolder().addCallback (this);
- }
-
- @Override
- protected void onDetachedFromWindow ()
- {
- super.onDetachedFromWindow();
- getHolder().removeCallback (this);
- }
-
- //==============================================================================
- private native void dispatchDrawNative (long nativeContextPtr, Canvas canvas);
- private native void surfaceCreatedNative (long nativeContextptr, SurfaceHolder holder);
- private native void surfaceDestroyedNative (long nativeContextptr, SurfaceHolder holder);
- private native void surfaceChangedNative (long nativeContextptr, SurfaceHolder holder,
- int format, int width, int height);
- }
-
- public NativeSurfaceView createNativeSurfaceView (long nativeSurfacePtr)
- {
- return new NativeSurfaceView (this, nativeSurfacePtr);
- }
-
- //==============================================================================
- public final int[] renderGlyph (char glyph, Paint paint, android.graphics.Matrix matrix, Rect bounds)
- {
- Path p = new Path();
- paint.getTextPath (String.valueOf (glyph), 0, 1, 0.0f, 0.0f, p);
-
- RectF boundsF = new RectF();
- p.computeBounds (boundsF, true);
- matrix.mapRect (boundsF);
-
- boundsF.roundOut (bounds);
- bounds.left--;
- bounds.right++;
-
- final int w = bounds.width();
- final int h = Math.max (1, bounds.height());
-
- Bitmap bm = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888);
-
- Canvas c = new Canvas (bm);
- matrix.postTranslate (-bounds.left, -bounds.top);
- c.setMatrix (matrix);
- c.drawPath (p, paint);
-
- final int sizeNeeded = w * h;
- if (cachedRenderArray.length < sizeNeeded)
- cachedRenderArray = new int [sizeNeeded];
-
- bm.getPixels (cachedRenderArray, 0, w, 0, 0, w, h);
- bm.recycle();
- return cachedRenderArray;
- }
-
- private int[] cachedRenderArray = new int [256];
-
- //==============================================================================
- public static class HTTPStream
- {
- public HTTPStream (HttpURLConnection connection_,
- int[] statusCode, StringBuffer responseHeaders) throws IOException
- {
- connection = connection_;
-
- try
- {
- inputStream = new BufferedInputStream (connection.getInputStream());
- }
- catch (IOException e)
- {
- if (connection.getResponseCode() < 400)
- throw e;
- }
- finally
- {
- statusCode[0] = connection.getResponseCode();
- }
-
- if (statusCode[0] >= 400)
- inputStream = connection.getErrorStream();
- else
- inputStream = connection.getInputStream();
-
- for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
- if (entry.getKey() != null && entry.getValue() != null)
- responseHeaders.append (entry.getKey() + ": "
- + android.text.TextUtils.join (",", entry.getValue()) + "\n");
- }
-
- public final void release()
- {
- try
- {
- inputStream.close();
- }
- catch (IOException e)
- {}
-
- connection.disconnect();
- }
-
- public final int read (byte[] buffer, int numBytes)
- {
- int num = 0;
-
- try
- {
- num = inputStream.read (buffer, 0, numBytes);
- }
- catch (IOException e)
- {}
-
- if (num > 0)
- position += num;
-
- return num;
- }
-
- public final long getPosition() { return position; }
- public final long getTotalLength() { return -1; }
- public final boolean isExhausted() { return false; }
- public final boolean setPosition (long newPos) { return false; }
-
- private HttpURLConnection connection;
- private InputStream inputStream;
- private long position;
- }
-
- public static final HTTPStream createHTTPStream (String address, boolean isPost, byte[] postData,
- String headers, int timeOutMs, int[] statusCode,
- StringBuffer responseHeaders, int numRedirectsToFollow,
- String httpRequestCmd)
- {
- // timeout parameter of zero for HttpUrlConnection is a blocking connect (negative value for juce::URL)
- if (timeOutMs < 0)
- timeOutMs = 0;
- else if (timeOutMs == 0)
- timeOutMs = 30000;
-
- // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
- // So convert headers string to an array, with an element for each line
- String headerLines[] = headers.split("\\n");
-
- for (;;)
- {
- try
- {
- HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
-
- if (connection != null)
- {
- try
- {
- connection.setInstanceFollowRedirects (false);
- connection.setConnectTimeout (timeOutMs);
- connection.setReadTimeout (timeOutMs);
-
- // Set request headers
- for (int i = 0; i < headerLines.length; ++i)
- {
- int pos = headerLines[i].indexOf (":");
-
- if (pos > 0 && pos < headerLines[i].length())
- {
- String field = headerLines[i].substring (0, pos);
- String value = headerLines[i].substring (pos + 1);
-
- if (value.length() > 0)
- connection.setRequestProperty (field, value);
- }
- }
-
- connection.setRequestMethod (httpRequestCmd);
- if (isPost)
- {
- connection.setDoOutput (true);
-
- if (postData != null)
- {
- OutputStream out = connection.getOutputStream();
- out.write(postData);
- out.flush();
- }
- }
-
- HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
-
- // Process redirect & continue as necessary
- int status = statusCode[0];
-
- if (--numRedirectsToFollow >= 0
- && (status == 301 || status == 302 || status == 303 || status == 307))
- {
- // Assumes only one occurrence of "Location"
- int pos1 = responseHeaders.indexOf ("Location:") + 10;
- int pos2 = responseHeaders.indexOf ("\n", pos1);
-
- if (pos2 > pos1)
- {
- String newLocation = responseHeaders.substring(pos1, pos2);
- // Handle newLocation whether it's absolute or relative
- URL baseUrl = new URL (address);
- URL newUrl = new URL (baseUrl, newLocation);
- String transformedNewLocation = newUrl.toString();
-
- if (transformedNewLocation != address)
- {
- address = transformedNewLocation;
- // Clear responseHeaders before next iteration
- responseHeaders.delete (0, responseHeaders.length());
- continue;
- }
- }
- }
-
- return httpStream;
- }
- catch (Throwable e)
- {
- connection.disconnect();
- }
- }
- }
- catch (Throwable e) {}
-
- return null;
- }
- }
-
- public final void launchURL (String url)
- {
- startActivity (new Intent (Intent.ACTION_VIEW, Uri.parse (url)));
- }
-
- public static final String getLocaleValue (boolean isRegion)
- {
- java.util.Locale locale = java.util.Locale.getDefault();
-
- return isRegion ? locale.getDisplayCountry (java.util.Locale.US)
- : locale.getDisplayLanguage (java.util.Locale.US);
- }
-
- private static final String getFileLocation (String type)
- {
- return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath();
- }
-
- public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); }
- public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); }
- public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); }
- public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); }
- public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); }
-
- //==============================================================================
- private final class SingleMediaScanner implements MediaScannerConnectionClient
- {
- public SingleMediaScanner (Context context, String filename)
- {
- file = filename;
- msc = new MediaScannerConnection (context, this);
- msc.connect();
- }
-
- @Override
- public void onMediaScannerConnected()
- {
- msc.scanFile (file, null);
- }
-
- @Override
- public void onScanCompleted (String path, Uri uri)
- {
- msc.disconnect();
- }
-
- private MediaScannerConnection msc;
- private String file;
- }
-
- public final void scanFile (String filename)
- {
- new SingleMediaScanner (this, filename);
- }
-
- public final Typeface getTypeFaceFromAsset (String assetName)
- {
- try
- {
- return Typeface.createFromAsset (this.getResources().getAssets(), assetName);
- }
- catch (Throwable e) {}
-
- return null;
- }
-
- final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
-
- public static String bytesToHex (byte[] bytes)
- {
- char[] hexChars = new char[bytes.length * 2];
-
- for (int j = 0; j < bytes.length; ++j)
- {
- int v = bytes[j] & 0xff;
- hexChars[j * 2] = hexArray[v >>> 4];
- hexChars[j * 2 + 1] = hexArray[v & 0x0f];
- }
-
- return new String (hexChars);
- }
-
- final private java.util.Map dataCache = new java.util.HashMap();
-
- synchronized private final File getDataCacheFile (byte[] data)
- {
- try
- {
- java.security.MessageDigest digest = java.security.MessageDigest.getInstance ("MD5");
- digest.update (data);
-
- String key = bytesToHex (digest.digest());
-
- if (dataCache.containsKey (key))
- return (File) dataCache.get (key);
-
- File f = new File (this.getCacheDir(), "bindata_" + key);
- f.delete();
- FileOutputStream os = new FileOutputStream (f);
- os.write (data, 0, data.length);
- dataCache.put (key, f);
- return f;
- }
- catch (Throwable e) {}
-
- return null;
- }
-
- private final void clearDataCache()
- {
- java.util.Iterator it = dataCache.values().iterator();
-
- while (it.hasNext())
- {
- File f = (File) it.next();
- f.delete();
- }
- }
-
- public final Typeface getTypeFaceFromByteArray (byte[] data)
- {
- try
- {
- File f = getDataCacheFile (data);
-
- if (f != null)
- return Typeface.createFromFile (f);
- }
- catch (Exception e)
- {
- Log.e ("JUCE", e.toString());
- }
-
- return null;
- }
-
- public final int getAndroidSDKVersion()
- {
- return android.os.Build.VERSION.SDK_INT;
- }
-
- public final String audioManagerGetProperty (String property)
- {
- Object obj = getSystemService (AUDIO_SERVICE);
- if (obj == null)
- return null;
-
- java.lang.reflect.Method method;
-
- try
- {
- method = obj.getClass().getMethod ("getProperty", String.class);
- }
- catch (SecurityException e) { return null; }
- catch (NoSuchMethodException e) { return null; }
-
- if (method == null)
- return null;
-
- try
- {
- return (String) method.invoke (obj, property);
- }
- catch (java.lang.IllegalArgumentException e) {}
- catch (java.lang.IllegalAccessException e) {}
- catch (java.lang.reflect.InvocationTargetException e) {}
-
- return null;
- }
-
- public final int setCurrentThreadPriority (int priority)
- {
- android.os.Process.setThreadPriority (android.os.Process.myTid(), priority);
- return android.os.Process.getThreadPriority (android.os.Process.myTid());
- }
-
- public final boolean hasSystemFeature (String property)
- {
- return getPackageManager().hasSystemFeature (property);
- }
-
- private static class JuceThread extends Thread
- {
- public JuceThread (long host, String threadName, long threadStackSize)
- {
- super (null, null, threadName, threadStackSize);
- _this = host;
- }
-
- public void run()
- {
- runThread(_this);
- }
-
- private native void runThread (long host);
- private long _this;
- }
-
- public final Thread createNewThread(long host, String threadName, long threadStackSize)
- {
- return new JuceThread(host, threadName, threadStackSize);
- }
- }
|