upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)
This commit is contained in:
		@ -1,169 +0,0 @@
 | 
			
		||||
$$CameraApi21
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    public class CameraDeviceStateCallback  extends CameraDevice.StateCallback
 | 
			
		||||
    {
 | 
			
		||||
        private native void cameraDeviceStateClosed       (long host, CameraDevice camera);
 | 
			
		||||
        private native void cameraDeviceStateDisconnected (long host, CameraDevice camera);
 | 
			
		||||
        private native void cameraDeviceStateError        (long host, CameraDevice camera, int error);
 | 
			
		||||
        private native void cameraDeviceStateOpened       (long host, CameraDevice camera);
 | 
			
		||||
 | 
			
		||||
        CameraDeviceStateCallback (long hostToUse)
 | 
			
		||||
        {
 | 
			
		||||
            host = hostToUse;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onClosed (CameraDevice camera)
 | 
			
		||||
        {
 | 
			
		||||
            cameraDeviceStateClosed (host, camera);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onDisconnected (CameraDevice camera)
 | 
			
		||||
        {
 | 
			
		||||
            cameraDeviceStateDisconnected (host, camera);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onError (CameraDevice camera, int error)
 | 
			
		||||
        {
 | 
			
		||||
            cameraDeviceStateError (host, camera, error);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onOpened (CameraDevice camera)
 | 
			
		||||
        {
 | 
			
		||||
            cameraDeviceStateOpened (host, camera);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private long host;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    public class CameraCaptureSessionStateCallback  extends CameraCaptureSession.StateCallback
 | 
			
		||||
    {
 | 
			
		||||
        private native void cameraCaptureSessionActive          (long host, CameraCaptureSession session);
 | 
			
		||||
        private native void cameraCaptureSessionClosed          (long host, CameraCaptureSession session);
 | 
			
		||||
        private native void cameraCaptureSessionConfigureFailed (long host, CameraCaptureSession session);
 | 
			
		||||
        private native void cameraCaptureSessionConfigured      (long host, CameraCaptureSession session);
 | 
			
		||||
        private native void cameraCaptureSessionReady           (long host, CameraCaptureSession session);
 | 
			
		||||
 | 
			
		||||
        CameraCaptureSessionStateCallback (long hostToUse)
 | 
			
		||||
        {
 | 
			
		||||
            host = hostToUse;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onActive (CameraCaptureSession session)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionActive (host, session);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onClosed (CameraCaptureSession session)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionClosed (host, session);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onConfigureFailed (CameraCaptureSession session)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionConfigureFailed (host, session);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onConfigured (CameraCaptureSession session)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionConfigured (host, session);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onReady (CameraCaptureSession session)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionReady (host, session);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private long host;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    public class CameraCaptureSessionCaptureCallback    extends CameraCaptureSession.CaptureCallback
 | 
			
		||||
    {
 | 
			
		||||
        private native void cameraCaptureSessionCaptureCompleted  (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result);
 | 
			
		||||
        private native void cameraCaptureSessionCaptureFailed     (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, CaptureFailure failure);
 | 
			
		||||
        private native void cameraCaptureSessionCaptureProgressed (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult);
 | 
			
		||||
        private native void cameraCaptureSessionCaptureStarted    (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber);
 | 
			
		||||
        private native void cameraCaptureSessionCaptureSequenceAborted   (long host, boolean isPreview, CameraCaptureSession session, int sequenceId);
 | 
			
		||||
        private native void cameraCaptureSessionCaptureSequenceCompleted (long host, boolean isPreview, CameraCaptureSession session, int sequenceId, long frameNumber);
 | 
			
		||||
 | 
			
		||||
        CameraCaptureSessionCaptureCallback (long hostToUse, boolean shouldBePreview)
 | 
			
		||||
        {
 | 
			
		||||
            host = hostToUse;
 | 
			
		||||
            preview = shouldBePreview;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onCaptureCompleted (CameraCaptureSession session, CaptureRequest request,
 | 
			
		||||
                                        TotalCaptureResult result)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionCaptureCompleted (host, preview, session, request, result);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onCaptureFailed (CameraCaptureSession session, CaptureRequest request, CaptureFailure failure)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionCaptureFailed (host, preview, session, request, failure);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onCaptureProgressed (CameraCaptureSession session, CaptureRequest request,
 | 
			
		||||
                                         CaptureResult partialResult)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionCaptureProgressed (host, preview, session, request, partialResult);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onCaptureSequenceAborted (CameraCaptureSession session, int sequenceId)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionCaptureSequenceAborted (host, preview, session, sequenceId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onCaptureSequenceCompleted (CameraCaptureSession session, int sequenceId, long frameNumber)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionCaptureSequenceCompleted (host, preview, session, sequenceId, frameNumber);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onCaptureStarted (CameraCaptureSession session, CaptureRequest request, long timestamp,
 | 
			
		||||
                                      long frameNumber)
 | 
			
		||||
        {
 | 
			
		||||
            cameraCaptureSessionCaptureStarted (host, preview, session, request, timestamp, frameNumber);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private long host;
 | 
			
		||||
        private boolean preview;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    public class JuceOrientationEventListener    extends OrientationEventListener
 | 
			
		||||
    {
 | 
			
		||||
        private native void deviceOrientationChanged (long host, int orientation);
 | 
			
		||||
 | 
			
		||||
        public JuceOrientationEventListener (long hostToUse, Context context, int rate)
 | 
			
		||||
        {
 | 
			
		||||
            super (context, rate);
 | 
			
		||||
 | 
			
		||||
            host = hostToUse;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onOrientationChanged (int orientation)
 | 
			
		||||
        {
 | 
			
		||||
            deviceOrientationChanged (host, orientation);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private long host;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
CameraApi21$$
 | 
			
		||||
@ -1,999 +0,0 @@
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    public class BluetoothManager extends ScanCallback
 | 
			
		||||
    {
 | 
			
		||||
        BluetoothManager()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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 int getBluetoothDeviceStatus (String address)
 | 
			
		||||
        {
 | 
			
		||||
            return getAndroidMidiDeviceManager().getBluetoothDeviceStatus (address);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void startStopScan (boolean shouldStart)
 | 
			
		||||
        {
 | 
			
		||||
            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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (shouldStart)
 | 
			
		||||
            {
 | 
			
		||||
                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);
 | 
			
		||||
 | 
			
		||||
                bluetoothLeScanner.startScan (Arrays.asList (scanFilterBuilder.build()),
 | 
			
		||||
                                              scanSettingsBuilder.build(),
 | 
			
		||||
                                              this);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                bluetoothLeScanner.stopScan (this);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return getAndroidMidiDeviceManager().pairBluetoothDevice (btDevice);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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 (MidiDeviceManager mm, MidiOutputPort actualPort, MidiPortPath portPathToUse, long hostToUse)
 | 
			
		||||
        {
 | 
			
		||||
            owner = mm;
 | 
			
		||||
            androidPort = actualPort;
 | 
			
		||||
            portPath = portPathToUse;
 | 
			
		||||
            juceHost = hostToUse;
 | 
			
		||||
            isConnected = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected void finalize() throws Throwable
 | 
			
		||||
        {
 | 
			
		||||
            close();
 | 
			
		||||
            super.finalize();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean isInputPort()
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void start()
 | 
			
		||||
        {
 | 
			
		||||
            if (owner != null && androidPort != null && ! isConnected) {
 | 
			
		||||
                androidPort.connect(this);
 | 
			
		||||
                isConnected = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void stop()
 | 
			
		||||
        {
 | 
			
		||||
            if (owner != null && androidPort != null && isConnected) {
 | 
			
		||||
                androidPort.disconnect(this);
 | 
			
		||||
                isConnected = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void close()
 | 
			
		||||
        {
 | 
			
		||||
            if (androidPort != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    androidPort.close();
 | 
			
		||||
                } catch (IOException exception) {
 | 
			
		||||
                    Log.d("JUCE", "IO Exception while closing port");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (owner != null)
 | 
			
		||||
                owner.removePort (portPath);
 | 
			
		||||
 | 
			
		||||
            owner = null;
 | 
			
		||||
            androidPort = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onSend (byte[] msg, int offset, int count, long timestamp)
 | 
			
		||||
        {
 | 
			
		||||
            if (count > 0)
 | 
			
		||||
                handleReceive (juceHost, msg, offset, count, timestamp);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onFlush()
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void sendMidi (byte[] msg, int offset, int count)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MidiDeviceManager owner;
 | 
			
		||||
        MidiOutputPort androidPort;
 | 
			
		||||
        MidiPortPath portPath;
 | 
			
		||||
        long juceHost;
 | 
			
		||||
        boolean isConnected;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class JuceMidiOutputPort implements JuceMidiPort
 | 
			
		||||
    {
 | 
			
		||||
        public JuceMidiOutputPort (MidiDeviceManager mm, MidiInputPort actualPort, MidiPortPath portPathToUse)
 | 
			
		||||
        {
 | 
			
		||||
            owner = mm;
 | 
			
		||||
            androidPort = actualPort;
 | 
			
		||||
            portPath = portPathToUse;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected void finalize() throws Throwable
 | 
			
		||||
        {
 | 
			
		||||
            close();
 | 
			
		||||
            super.finalize();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean isInputPort()
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void start()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void stop()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void sendMidi (byte[] msg, int offset, int count)
 | 
			
		||||
        {
 | 
			
		||||
            if (androidPort != null)
 | 
			
		||||
            {
 | 
			
		||||
                try {
 | 
			
		||||
                    androidPort.send(msg, offset, count);
 | 
			
		||||
                } catch (IOException exception)
 | 
			
		||||
                {
 | 
			
		||||
                    Log.d ("JUCE", "send midi had IO exception");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void close()
 | 
			
		||||
        {
 | 
			
		||||
            if (androidPort != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    androidPort.close();
 | 
			
		||||
                } catch (IOException exception) {
 | 
			
		||||
                    Log.d("JUCE", "IO Exception while closing port");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (owner != null)
 | 
			
		||||
                owner.removePort (portPath);
 | 
			
		||||
 | 
			
		||||
            owner = null;
 | 
			
		||||
            androidPort = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MidiDeviceManager owner;
 | 
			
		||||
        MidiInputPort androidPort;
 | 
			
		||||
        MidiPortPath portPath;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class MidiPortPath extends Object
 | 
			
		||||
    {
 | 
			
		||||
        public MidiPortPath (int deviceIdToUse, boolean direction, int androidIndex)
 | 
			
		||||
        {
 | 
			
		||||
            deviceId = deviceIdToUse;
 | 
			
		||||
            isInput = direction;
 | 
			
		||||
            portIndex = androidIndex;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int deviceId;
 | 
			
		||||
        public int portIndex;
 | 
			
		||||
        public boolean isInput;
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public int hashCode()
 | 
			
		||||
        {
 | 
			
		||||
            Integer i = new Integer ((deviceId * 128) + (portIndex < 128 ? portIndex : 127));
 | 
			
		||||
            return i.hashCode() * (isInput ? -1 : 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean equals (Object obj)
 | 
			
		||||
        {
 | 
			
		||||
            if (obj == null)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if (getClass() != obj.getClass())
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            MidiPortPath other = (MidiPortPath) obj;
 | 
			
		||||
            return (portIndex == other.portIndex && isInput == other.isInput && deviceId == other.deviceId);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    public class MidiDeviceManager extends MidiManager.DeviceCallback implements MidiManager.OnDeviceOpenedListener
 | 
			
		||||
    {
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        private class DummyBluetoothGattCallback extends BluetoothGattCallback
 | 
			
		||||
        {
 | 
			
		||||
            public DummyBluetoothGattCallback (MidiDeviceManager mm)
 | 
			
		||||
            {
 | 
			
		||||
                super();
 | 
			
		||||
                owner = mm;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
 | 
			
		||||
            {
 | 
			
		||||
                if (newState == BluetoothProfile.STATE_CONNECTED)
 | 
			
		||||
                {
 | 
			
		||||
                    gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
 | 
			
		||||
                    owner.pairBluetoothDeviceStepTwo (gatt.getDevice());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {}
 | 
			
		||||
            public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {}
 | 
			
		||||
            public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {}
 | 
			
		||||
            public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {}
 | 
			
		||||
            public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {}
 | 
			
		||||
            public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {}
 | 
			
		||||
            public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {}
 | 
			
		||||
            public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {}
 | 
			
		||||
            public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {}
 | 
			
		||||
 | 
			
		||||
            private MidiDeviceManager owner;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        private class MidiDeviceOpenTask extends java.util.TimerTask
 | 
			
		||||
        {
 | 
			
		||||
            public MidiDeviceOpenTask (MidiDeviceManager deviceManager, MidiDevice device, BluetoothGatt gattToUse)
 | 
			
		||||
            {
 | 
			
		||||
                owner = deviceManager;
 | 
			
		||||
                midiDevice = device;
 | 
			
		||||
                btGatt = gattToUse;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public boolean cancel()
 | 
			
		||||
            {
 | 
			
		||||
                synchronized (MidiDeviceOpenTask.class)
 | 
			
		||||
                {
 | 
			
		||||
                    owner = null;
 | 
			
		||||
                    boolean retval = super.cancel();
 | 
			
		||||
 | 
			
		||||
                    if (btGatt != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        btGatt.disconnect();
 | 
			
		||||
                        btGatt.close();
 | 
			
		||||
 | 
			
		||||
                        btGatt = null;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (midiDevice != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            midiDevice.close();
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (IOException e)
 | 
			
		||||
                        {}
 | 
			
		||||
 | 
			
		||||
                        midiDevice = null;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return retval;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public String getBluetoothAddress()
 | 
			
		||||
            {
 | 
			
		||||
                synchronized (MidiDeviceOpenTask.class)
 | 
			
		||||
                {
 | 
			
		||||
                    if (midiDevice != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        MidiDeviceInfo info = midiDevice.getInfo();
 | 
			
		||||
                        if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH)
 | 
			
		||||
                        {
 | 
			
		||||
                            BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE);
 | 
			
		||||
                            if (btDevice != null)
 | 
			
		||||
                                return btDevice.getAddress();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return "";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public BluetoothGatt getGatt() { return btGatt; }
 | 
			
		||||
 | 
			
		||||
            public int getID()
 | 
			
		||||
            {
 | 
			
		||||
                return midiDevice.getInfo().getId();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void run()
 | 
			
		||||
            {
 | 
			
		||||
                synchronized (MidiDeviceOpenTask.class)
 | 
			
		||||
                {
 | 
			
		||||
                    if (owner != null && midiDevice != null)
 | 
			
		||||
                        owner.onDeviceOpenedDelayed (midiDevice);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private MidiDeviceManager owner;
 | 
			
		||||
            private MidiDevice midiDevice;
 | 
			
		||||
            private BluetoothGatt btGatt;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        public MidiDeviceManager()
 | 
			
		||||
        {
 | 
			
		||||
            manager = (MidiManager) getSystemService (MIDI_SERVICE);
 | 
			
		||||
 | 
			
		||||
            if (manager == null)
 | 
			
		||||
            {
 | 
			
		||||
                Log.d ("JUCE", "MidiDeviceManager error: could not get MidiManager system service");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            openPorts = new HashMap<MidiPortPath, WeakReference<JuceMidiPort>> ();
 | 
			
		||||
            midiDevices = new ArrayList<Pair<MidiDevice,BluetoothGatt>>();
 | 
			
		||||
            openTasks = new HashMap<Integer, MidiDeviceOpenTask>();
 | 
			
		||||
            btDevicesPairing = new HashMap<String, BluetoothGatt>();
 | 
			
		||||
 | 
			
		||||
            MidiDeviceInfo[] foundDevices = manager.getDevices();
 | 
			
		||||
            for (MidiDeviceInfo info : foundDevices)
 | 
			
		||||
                onDeviceAdded (info);
 | 
			
		||||
 | 
			
		||||
            manager.registerDeviceCallback (this, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected void finalize() throws Throwable
 | 
			
		||||
        {
 | 
			
		||||
            manager.unregisterDeviceCallback (this);
 | 
			
		||||
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                btDevicesPairing.clear();
 | 
			
		||||
 | 
			
		||||
                for (Integer deviceID : openTasks.keySet())
 | 
			
		||||
                    openTasks.get (deviceID).cancel();
 | 
			
		||||
 | 
			
		||||
                openTasks = null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (MidiPortPath key : openPorts.keySet())
 | 
			
		||||
                openPorts.get (key).get().close();
 | 
			
		||||
 | 
			
		||||
            openPorts = null;
 | 
			
		||||
 | 
			
		||||
            for (Pair<MidiDevice, BluetoothGatt> device : midiDevices)
 | 
			
		||||
            {
 | 
			
		||||
                if (device.second != null)
 | 
			
		||||
                {
 | 
			
		||||
                    device.second.disconnect();
 | 
			
		||||
                    device.second.close();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                device.first.close();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            midiDevices.clear();
 | 
			
		||||
 | 
			
		||||
            super.finalize();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String[] getJuceAndroidMidiInputDevices()
 | 
			
		||||
        {
 | 
			
		||||
            return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_OUTPUT);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String[] getJuceAndroidMidiOutputDevices()
 | 
			
		||||
        {
 | 
			
		||||
            return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_INPUT);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private String[] getJuceAndroidMidiDevices (int portType)
 | 
			
		||||
        {
 | 
			
		||||
            // only update the list when JUCE asks for a new list
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                deviceInfos = getDeviceInfos();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ArrayList<String> portNames = new ArrayList<String>();
 | 
			
		||||
 | 
			
		||||
            int index = 0;
 | 
			
		||||
            for (MidiPortPath portInfo = getPortPathForJuceIndex (portType, index); portInfo != null; portInfo = getPortPathForJuceIndex (portType, ++index))
 | 
			
		||||
                portNames.add (getPortName (portInfo));
 | 
			
		||||
 | 
			
		||||
            String[] names = new String[portNames.size()];
 | 
			
		||||
            return portNames.toArray (names);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private JuceMidiPort openMidiPortWithJuceIndex (int index, long host, boolean isInput)
 | 
			
		||||
        {
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                int portTypeToFind = (isInput ? MidiDeviceInfo.PortInfo.TYPE_OUTPUT : MidiDeviceInfo.PortInfo.TYPE_INPUT);
 | 
			
		||||
                MidiPortPath portInfo = getPortPathForJuceIndex (portTypeToFind, index);
 | 
			
		||||
 | 
			
		||||
                if (portInfo != null)
 | 
			
		||||
                {
 | 
			
		||||
                    // ports must be opened exclusively!
 | 
			
		||||
                    if (openPorts.containsKey (portInfo))
 | 
			
		||||
                        return null;
 | 
			
		||||
 | 
			
		||||
                    Pair<MidiDevice,BluetoothGatt> devicePair = getMidiDevicePairForId (portInfo.deviceId);
 | 
			
		||||
 | 
			
		||||
                    if (devicePair != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        MidiDevice device = devicePair.first;
 | 
			
		||||
                        if (device != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            JuceMidiPort juceMidiPort = null;
 | 
			
		||||
 | 
			
		||||
                            if (isInput)
 | 
			
		||||
                            {
 | 
			
		||||
                                MidiOutputPort outputPort = device.openOutputPort(portInfo.portIndex);
 | 
			
		||||
 | 
			
		||||
                                if (outputPort != null)
 | 
			
		||||
                                    juceMidiPort = new JuceMidiInputPort(this, outputPort, portInfo, host);
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                MidiInputPort inputPort = device.openInputPort(portInfo.portIndex);
 | 
			
		||||
 | 
			
		||||
                                if (inputPort != null)
 | 
			
		||||
                                    juceMidiPort = new JuceMidiOutputPort(this, inputPort, portInfo);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            if (juceMidiPort != null)
 | 
			
		||||
                            {
 | 
			
		||||
                                openPorts.put(portInfo, new WeakReference<JuceMidiPort>(juceMidiPort));
 | 
			
		||||
 | 
			
		||||
                                return juceMidiPort;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public JuceMidiPort openMidiInputPortWithJuceIndex (int index, long host)
 | 
			
		||||
        {
 | 
			
		||||
            return openMidiPortWithJuceIndex (index, host, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public JuceMidiPort openMidiOutputPortWithJuceIndex (int index)
 | 
			
		||||
        {
 | 
			
		||||
            return openMidiPortWithJuceIndex (index, 0, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* 0: unpaired, 1: paired, 2: pairing */
 | 
			
		||||
        public int getBluetoothDeviceStatus (String address)
 | 
			
		||||
        {
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                if (! address.isEmpty())
 | 
			
		||||
                {
 | 
			
		||||
                    if (findMidiDeviceForBluetoothAddress (address) != null)
 | 
			
		||||
                        return 1;
 | 
			
		||||
 | 
			
		||||
                    if (btDevicesPairing.containsKey (address))
 | 
			
		||||
                        return 2;
 | 
			
		||||
 | 
			
		||||
                    if (findOpenTaskForBluetoothAddress (address) != null)
 | 
			
		||||
                        return 2;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public boolean pairBluetoothDevice (BluetoothDevice btDevice)
 | 
			
		||||
        {
 | 
			
		||||
            String btAddress = btDevice.getAddress();
 | 
			
		||||
            if (btAddress.isEmpty())
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                if (getBluetoothDeviceStatus (btAddress) != 0)
 | 
			
		||||
                    return false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                btDevicesPairing.put (btDevice.getAddress(), null);
 | 
			
		||||
                BluetoothGatt gatt = btDevice.connectGatt (getApplicationContext(), true, new DummyBluetoothGattCallback (this));
 | 
			
		||||
 | 
			
		||||
                if (gatt != null)
 | 
			
		||||
                {
 | 
			
		||||
                    btDevicesPairing.put (btDevice.getAddress(), gatt);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    pairBluetoothDeviceStepTwo (btDevice);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void pairBluetoothDeviceStepTwo (BluetoothDevice btDevice)
 | 
			
		||||
        {
 | 
			
		||||
            manager.openBluetoothDevice(btDevice, this, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void unpairBluetoothDevice (String address)
 | 
			
		||||
        {
 | 
			
		||||
            if (address.isEmpty())
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                if (btDevicesPairing.containsKey (address))
 | 
			
		||||
                {
 | 
			
		||||
                    BluetoothGatt gatt = btDevicesPairing.get (address);
 | 
			
		||||
                    if (gatt != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        gatt.disconnect();
 | 
			
		||||
                        gatt.close();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    btDevicesPairing.remove (address);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                MidiDeviceOpenTask openTask = findOpenTaskForBluetoothAddress (address);
 | 
			
		||||
                if (openTask != null)
 | 
			
		||||
                {
 | 
			
		||||
                    int deviceID = openTask.getID();
 | 
			
		||||
                    openTask.cancel();
 | 
			
		||||
                    openTasks.remove (deviceID);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Pair<MidiDevice, BluetoothGatt> midiDevicePair = findMidiDeviceForBluetoothAddress (address);
 | 
			
		||||
                if (midiDevicePair != null)
 | 
			
		||||
                {
 | 
			
		||||
                    MidiDevice midiDevice = midiDevicePair.first;
 | 
			
		||||
                    onDeviceRemoved (midiDevice.getInfo());
 | 
			
		||||
 | 
			
		||||
                    try {
 | 
			
		||||
                        midiDevice.close();
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (IOException exception)
 | 
			
		||||
                    {
 | 
			
		||||
                        Log.d ("JUCE", "IOException while closing midi device");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Pair<MidiDevice, BluetoothGatt> findMidiDeviceForBluetoothAddress (String address)
 | 
			
		||||
        {
 | 
			
		||||
            for (Pair<MidiDevice,BluetoothGatt> midiDevice : midiDevices)
 | 
			
		||||
            {
 | 
			
		||||
                MidiDeviceInfo info = midiDevice.first.getInfo();
 | 
			
		||||
                if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH)
 | 
			
		||||
                {
 | 
			
		||||
                    BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE);
 | 
			
		||||
                    if (btDevice != null && btDevice.getAddress().equals (address))
 | 
			
		||||
                        return midiDevice;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private MidiDeviceOpenTask findOpenTaskForBluetoothAddress (String address)
 | 
			
		||||
        {
 | 
			
		||||
            for (Integer deviceID : openTasks.keySet())
 | 
			
		||||
            {
 | 
			
		||||
                MidiDeviceOpenTask openTask = openTasks.get (deviceID);
 | 
			
		||||
                if (openTask.getBluetoothAddress().equals (address))
 | 
			
		||||
                    return openTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void removePort (MidiPortPath path)
 | 
			
		||||
        {
 | 
			
		||||
            openPorts.remove (path);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getInputPortNameForJuceIndex (int index)
 | 
			
		||||
        {
 | 
			
		||||
            MidiPortPath portInfo = getPortPathForJuceIndex (MidiDeviceInfo.PortInfo.TYPE_OUTPUT, index);
 | 
			
		||||
            if (portInfo != null)
 | 
			
		||||
                return getPortName (portInfo);
 | 
			
		||||
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getOutputPortNameForJuceIndex (int index)
 | 
			
		||||
        {
 | 
			
		||||
            MidiPortPath portInfo = getPortPathForJuceIndex (MidiDeviceInfo.PortInfo.TYPE_INPUT, index);
 | 
			
		||||
            if (portInfo != null)
 | 
			
		||||
                return getPortName (portInfo);
 | 
			
		||||
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void onDeviceAdded (MidiDeviceInfo info)
 | 
			
		||||
        {
 | 
			
		||||
            // only add standard midi devices
 | 
			
		||||
            if (info.getType() == info.TYPE_BLUETOOTH)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            manager.openDevice (info, this, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void onDeviceRemoved (MidiDeviceInfo info)
 | 
			
		||||
        {
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                Pair<MidiDevice, BluetoothGatt> devicePair = getMidiDevicePairForId (info.getId());
 | 
			
		||||
 | 
			
		||||
                if (devicePair != null)
 | 
			
		||||
                {
 | 
			
		||||
                    MidiDevice midiDevice = devicePair.first;
 | 
			
		||||
                    BluetoothGatt gatt = devicePair.second;
 | 
			
		||||
 | 
			
		||||
                    // close all ports that use this device
 | 
			
		||||
                    boolean removedPort = true;
 | 
			
		||||
 | 
			
		||||
                    while (removedPort == true)
 | 
			
		||||
                    {
 | 
			
		||||
                        removedPort = false;
 | 
			
		||||
                        for (MidiPortPath key : openPorts.keySet())
 | 
			
		||||
                        {
 | 
			
		||||
                            if (key.deviceId == info.getId())
 | 
			
		||||
                            {
 | 
			
		||||
                                openPorts.get(key).get().close();
 | 
			
		||||
                                removedPort = true;
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (gatt != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        gatt.disconnect();
 | 
			
		||||
                        gatt.close();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    midiDevices.remove (devicePair);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void onDeviceStatusChanged (MidiDeviceStatus status)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onDeviceOpened (MidiDevice theDevice)
 | 
			
		||||
        {
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                MidiDeviceInfo info = theDevice.getInfo();
 | 
			
		||||
                int deviceID = info.getId();
 | 
			
		||||
                BluetoothGatt gatt = null;
 | 
			
		||||
                boolean isBluetooth = false;
 | 
			
		||||
 | 
			
		||||
                if (! openTasks.containsKey (deviceID))
 | 
			
		||||
                {
 | 
			
		||||
                    if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH)
 | 
			
		||||
                    {
 | 
			
		||||
                        isBluetooth = true;
 | 
			
		||||
                        BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE);
 | 
			
		||||
                        if (btDevice != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            String btAddress = btDevice.getAddress();
 | 
			
		||||
                            if (btDevicesPairing.containsKey (btAddress))
 | 
			
		||||
                            {
 | 
			
		||||
                                gatt = btDevicesPairing.get (btAddress);
 | 
			
		||||
                                btDevicesPairing.remove (btAddress);
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                // unpair was called in the mean time
 | 
			
		||||
                                try
 | 
			
		||||
                                {
 | 
			
		||||
                                    Pair<MidiDevice, BluetoothGatt> midiDevicePair = findMidiDeviceForBluetoothAddress (btDevice.getAddress());
 | 
			
		||||
                                    if (midiDevicePair != null)
 | 
			
		||||
                                    {
 | 
			
		||||
                                        gatt = midiDevicePair.second;
 | 
			
		||||
 | 
			
		||||
                                        if (gatt != null)
 | 
			
		||||
                                        {
 | 
			
		||||
                                            gatt.disconnect();
 | 
			
		||||
                                            gatt.close();
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                                    theDevice.close();
 | 
			
		||||
                                }
 | 
			
		||||
                                catch (IOException e)
 | 
			
		||||
                                {}
 | 
			
		||||
 | 
			
		||||
                                return;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    MidiDeviceOpenTask openTask = new MidiDeviceOpenTask (this, theDevice, gatt);
 | 
			
		||||
                    openTasks.put (deviceID, openTask);
 | 
			
		||||
 | 
			
		||||
                    new java.util.Timer().schedule (openTask, (isBluetooth ? 2000 : 100));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void onDeviceOpenedDelayed (MidiDevice theDevice)
 | 
			
		||||
        {
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                int deviceID = theDevice.getInfo().getId();
 | 
			
		||||
 | 
			
		||||
                if (openTasks.containsKey (deviceID))
 | 
			
		||||
                {
 | 
			
		||||
                    if (! midiDevices.contains(theDevice))
 | 
			
		||||
                    {
 | 
			
		||||
                        BluetoothGatt gatt = openTasks.get (deviceID).getGatt();
 | 
			
		||||
                        openTasks.remove (deviceID);
 | 
			
		||||
                        midiDevices.add (new Pair<MidiDevice,BluetoothGatt> (theDevice, gatt));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    // unpair was called in the mean time
 | 
			
		||||
                    MidiDeviceInfo info = theDevice.getInfo();
 | 
			
		||||
                    BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE);
 | 
			
		||||
                    if (btDevice != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        String btAddress = btDevice.getAddress();
 | 
			
		||||
                        Pair<MidiDevice, BluetoothGatt> midiDevicePair = findMidiDeviceForBluetoothAddress (btDevice.getAddress());
 | 
			
		||||
                        if (midiDevicePair != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            BluetoothGatt gatt = midiDevicePair.second;
 | 
			
		||||
 | 
			
		||||
                            if (gatt != null)
 | 
			
		||||
                            {
 | 
			
		||||
                                gatt.disconnect();
 | 
			
		||||
                                gatt.close();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        theDevice.close();
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (IOException e)
 | 
			
		||||
                    {}
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getPortName(MidiPortPath path)
 | 
			
		||||
        {
 | 
			
		||||
            int portTypeToFind = (path.isInput ? MidiDeviceInfo.PortInfo.TYPE_INPUT : MidiDeviceInfo.PortInfo.TYPE_OUTPUT);
 | 
			
		||||
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                for (MidiDeviceInfo info : deviceInfos)
 | 
			
		||||
                {
 | 
			
		||||
                    int localIndex = 0;
 | 
			
		||||
                    if (info.getId() == path.deviceId)
 | 
			
		||||
                    {
 | 
			
		||||
                        for (MidiDeviceInfo.PortInfo portInfo : info.getPorts())
 | 
			
		||||
                        {
 | 
			
		||||
                            int portType = portInfo.getType();
 | 
			
		||||
                            if (portType == portTypeToFind)
 | 
			
		||||
                            {
 | 
			
		||||
                                int portIndex = portInfo.getPortNumber();
 | 
			
		||||
                                if (portIndex == path.portIndex)
 | 
			
		||||
                                {
 | 
			
		||||
                                    String portName = portInfo.getName();
 | 
			
		||||
                                    if (portName.isEmpty())
 | 
			
		||||
                                        portName = (String) info.getProperties().get(info.PROPERTY_NAME);
 | 
			
		||||
 | 
			
		||||
                                    return portName;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public MidiPortPath getPortPathForJuceIndex (int portType, int juceIndex)
 | 
			
		||||
        {
 | 
			
		||||
            int portIdx = 0;
 | 
			
		||||
            for (MidiDeviceInfo info : deviceInfos)
 | 
			
		||||
            {
 | 
			
		||||
                for (MidiDeviceInfo.PortInfo portInfo : info.getPorts())
 | 
			
		||||
                {
 | 
			
		||||
                    if (portInfo.getType() == portType)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (portIdx == juceIndex)
 | 
			
		||||
                            return new MidiPortPath (info.getId(),
 | 
			
		||||
                                    (portType == MidiDeviceInfo.PortInfo.TYPE_INPUT),
 | 
			
		||||
                                    portInfo.getPortNumber());
 | 
			
		||||
 | 
			
		||||
                        portIdx++;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private MidiDeviceInfo[] getDeviceInfos()
 | 
			
		||||
        {
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                MidiDeviceInfo[] infos = new MidiDeviceInfo[midiDevices.size()];
 | 
			
		||||
 | 
			
		||||
                int idx = 0;
 | 
			
		||||
                for (Pair<MidiDevice,BluetoothGatt> midiDevice : midiDevices)
 | 
			
		||||
                    infos[idx++] = midiDevice.first.getInfo();
 | 
			
		||||
 | 
			
		||||
                return infos;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Pair<MidiDevice, BluetoothGatt> getMidiDevicePairForId (int deviceId)
 | 
			
		||||
        {
 | 
			
		||||
            synchronized (MidiDeviceManager.class)
 | 
			
		||||
            {
 | 
			
		||||
                for (Pair<MidiDevice,BluetoothGatt> midiDevice : midiDevices)
 | 
			
		||||
                    if (midiDevice.first.getInfo().getId() == deviceId)
 | 
			
		||||
                        return midiDevice;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private MidiManager manager;
 | 
			
		||||
        private HashMap<String, BluetoothGatt> btDevicesPairing;
 | 
			
		||||
        private HashMap<Integer, MidiDeviceOpenTask> openTasks;
 | 
			
		||||
        private ArrayList<Pair<MidiDevice, BluetoothGatt>> midiDevices;
 | 
			
		||||
        private MidiDeviceInfo[] deviceInfos;
 | 
			
		||||
        private HashMap<MidiPortPath, WeakReference<JuceMidiPort>> openPorts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MidiDeviceManager getAndroidMidiDeviceManager()
 | 
			
		||||
    {
 | 
			
		||||
        if (getSystemService (MIDI_SERVICE) == null)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        synchronized (JuceAppActivity.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 (JuceAppActivity.class)
 | 
			
		||||
        {
 | 
			
		||||
            if (bluetoothManager == null)
 | 
			
		||||
                bluetoothManager = new BluetoothManager();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return bluetoothManager;
 | 
			
		||||
    }
 | 
			
		||||
@ -1,85 +0,0 @@
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    public class BluetoothManager
 | 
			
		||||
    {
 | 
			
		||||
        BluetoothManager()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String[] getMidiBluetoothAddresses()
 | 
			
		||||
        {
 | 
			
		||||
            String[] bluetoothAddresses = new String[0];
 | 
			
		||||
            return bluetoothAddresses;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getHumanReadableStringForBluetoothAddress (String address)
 | 
			
		||||
        {
 | 
			
		||||
            return address;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int getBluetoothDeviceStatus (String address)
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void startStopScan (boolean shouldStart)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public boolean pairBluetoothMidiDevice(String address)
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void unpairBluetoothMidiDevice (String address)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    public class MidiDeviceManager
 | 
			
		||||
    {
 | 
			
		||||
        public MidiDeviceManager()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String[] getJuceAndroidMidiInputDevices()
 | 
			
		||||
        {
 | 
			
		||||
            return new String[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String[] getJuceAndroidMidiOutputDevices()
 | 
			
		||||
        {
 | 
			
		||||
            return new String[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public JuceMidiPort openMidiInputPortWithJuceIndex (int index, long host)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public JuceMidiPort openMidiOutputPortWithJuceIndex (int index)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getInputPortNameForJuceIndex (int index)
 | 
			
		||||
        {
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getOutputPortNameForJuceIndex (int index)
 | 
			
		||||
        {
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public MidiDeviceManager getAndroidMidiDeviceManager()
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BluetoothManager getAndroidBluetoothManager()
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
@ -1,12 +0,0 @@
 | 
			
		||||
    @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);
 | 
			
		||||
    }
 | 
			
		||||
@ -1,138 +0,0 @@
 | 
			
		||||
package com.juce;
 | 
			
		||||
 | 
			
		||||
import android.content.ContentProvider;
 | 
			
		||||
import android.content.ContentValues;
 | 
			
		||||
import android.content.res.AssetFileDescriptor;
 | 
			
		||||
import android.content.res.Resources;
 | 
			
		||||
import android.database.Cursor;
 | 
			
		||||
import android.database.MatrixCursor;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.FileObserver;
 | 
			
		||||
import android.os.ParcelFileDescriptor;
 | 
			
		||||
import java.lang.String;
 | 
			
		||||
 | 
			
		||||
public final class SharingContentProvider extends ContentProvider
 | 
			
		||||
{
 | 
			
		||||
    private Object lock = new Object();
 | 
			
		||||
 | 
			
		||||
    private native void contentSharerFileObserverEvent (long host, int event, String path);
 | 
			
		||||
 | 
			
		||||
    private native Cursor contentSharerQuery (Uri uri, String[] projection, String selection,
 | 
			
		||||
                                              String[] selectionArgs, String sortOrder);
 | 
			
		||||
 | 
			
		||||
    private native void contentSharerCursorClosed (long host);
 | 
			
		||||
 | 
			
		||||
    private native AssetFileDescriptor contentSharerOpenFile (Uri uri, String mode);
 | 
			
		||||
    private native String[] contentSharerGetStreamTypes (Uri uri, String mimeTypeFilter);
 | 
			
		||||
 | 
			
		||||
    public final class ProviderFileObserver extends FileObserver
 | 
			
		||||
    {
 | 
			
		||||
        public ProviderFileObserver (long hostToUse, String path, int mask)
 | 
			
		||||
        {
 | 
			
		||||
            super (path, mask);
 | 
			
		||||
 | 
			
		||||
            host = hostToUse;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void onEvent (int event, String path)
 | 
			
		||||
        {
 | 
			
		||||
            contentSharerFileObserverEvent (host, event, path);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private long host;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final class ProviderCursor extends MatrixCursor
 | 
			
		||||
    {
 | 
			
		||||
        ProviderCursor (long hostToUse, String[] columnNames)
 | 
			
		||||
        {
 | 
			
		||||
            super (columnNames);
 | 
			
		||||
 | 
			
		||||
            host = hostToUse;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void close()
 | 
			
		||||
        {
 | 
			
		||||
            super.close();
 | 
			
		||||
 | 
			
		||||
            contentSharerCursorClosed (host);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private long host;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCreate()
 | 
			
		||||
    {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Cursor query (Uri url, String[] projection, String selection,
 | 
			
		||||
                         String[] selectionArgs, String sortOrder)
 | 
			
		||||
    {
 | 
			
		||||
        synchronized (lock)
 | 
			
		||||
        {
 | 
			
		||||
            return contentSharerQuery (url, projection, selection, selectionArgs, sortOrder);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Uri insert (Uri uri, ContentValues values)
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int update (Uri uri, ContentValues values, String selection,
 | 
			
		||||
                       String[] selectionArgs)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int delete (Uri uri, String selection, String[] selectionArgs)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getType (Uri uri)
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public AssetFileDescriptor openAssetFile (Uri uri, String mode)
 | 
			
		||||
    {
 | 
			
		||||
        synchronized (lock)
 | 
			
		||||
        {
 | 
			
		||||
            return contentSharerOpenFile (uri, mode);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ParcelFileDescriptor openFile (Uri uri, String mode)
 | 
			
		||||
    {
 | 
			
		||||
        synchronized (lock)
 | 
			
		||||
        {
 | 
			
		||||
            AssetFileDescriptor result = contentSharerOpenFile (uri, mode);
 | 
			
		||||
 | 
			
		||||
            if (result != null)
 | 
			
		||||
                return result.getParcelFileDescriptor();
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
$$ContentProviderApi11
 | 
			
		||||
    @Override
 | 
			
		||||
    public String[] getStreamTypes (Uri uri, String mimeTypeFilter)
 | 
			
		||||
    {
 | 
			
		||||
        synchronized (lock)
 | 
			
		||||
        {
 | 
			
		||||
            return contentSharerGetStreamTypes (uri, mimeTypeFilter);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
ContentProviderApi11$$
 | 
			
		||||
}
 | 
			
		||||
@ -1,69 +0,0 @@
 | 
			
		||||
$$WebViewNativeApi23    private native void webViewReceivedError (long host, WebView view, WebResourceRequest request, WebResourceError error);WebViewNativeApi23$$
 | 
			
		||||
$$WebViewNativeApi21    private native void webViewReceivedHttpError (long host, WebView view, WebResourceRequest request, WebResourceResponse errorResponse);WebViewNativeApi21$$
 | 
			
		||||
 | 
			
		||||
$$WebViewApi1_10
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onPageStarted (WebView view, String url, Bitmap favicon)
 | 
			
		||||
        {
 | 
			
		||||
            if (host != 0)
 | 
			
		||||
                webViewPageLoadStarted (host, view, url);
 | 
			
		||||
        }
 | 
			
		||||
WebViewApi1_10$$
 | 
			
		||||
 | 
			
		||||
$$WebViewApi11_20
 | 
			
		||||
        @Override
 | 
			
		||||
        public WebResourceResponse shouldInterceptRequest (WebView view, String url)
 | 
			
		||||
        {
 | 
			
		||||
            synchronized (hostLock)
 | 
			
		||||
            {
 | 
			
		||||
                if (host != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    boolean shouldLoad = webViewPageLoadStarted (host, view, url);
 | 
			
		||||
 | 
			
		||||
                    if (shouldLoad)
 | 
			
		||||
                        return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new WebResourceResponse ("text/html", null, null);
 | 
			
		||||
        }
 | 
			
		||||
WebViewApi11_20$$
 | 
			
		||||
 | 
			
		||||
$$WebViewApi21
 | 
			
		||||
        @Override
 | 
			
		||||
        public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request)
 | 
			
		||||
        {
 | 
			
		||||
            synchronized (hostLock)
 | 
			
		||||
            {
 | 
			
		||||
                if (host != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    boolean shouldLoad = webViewPageLoadStarted (host, view, request.getUrl().toString());
 | 
			
		||||
 | 
			
		||||
                    if (shouldLoad)
 | 
			
		||||
                        return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new WebResourceResponse ("text/html", null, null);
 | 
			
		||||
        }
 | 
			
		||||
WebViewApi21$$
 | 
			
		||||
 | 
			
		||||
$$WebViewApi23
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onReceivedError (WebView view, WebResourceRequest request, WebResourceError error)
 | 
			
		||||
        {
 | 
			
		||||
            if (host == 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            webViewReceivedError (host, view, request, error);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onReceivedHttpError (WebView view, WebResourceRequest request, WebResourceResponse errorResponse)
 | 
			
		||||
        {
 | 
			
		||||
            if (host == 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            webViewReceivedHttpError (host, view, request, errorResponse);
 | 
			
		||||
        }
 | 
			
		||||
WebViewApi23$$
 | 
			
		||||
@ -1,971 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2017 - ROLI Ltd.
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   The code included in this file is provided under the terms of the ISC license
 | 
			
		||||
   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 | 
			
		||||
   To use, copy, modify, and/or distribute this software for any purpose with or
 | 
			
		||||
   without fee is hereby granted provided that the above copyright notice and
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package com.android.vending.billing;
 | 
			
		||||
/**
 | 
			
		||||
 * InAppBillingService is the service that provides in-app billing version 3 and beyond.
 | 
			
		||||
 * This service provides the following features:
 | 
			
		||||
 * 1. Provides a new API to get details of in-app items published for the app including
 | 
			
		||||
 *    price, type, title and description.
 | 
			
		||||
 * 2. The purchase flow is synchronous and purchase information is available immediately
 | 
			
		||||
 *    after it completes.
 | 
			
		||||
 * 3. Purchase information of in-app purchases is maintained within the Google Play system
 | 
			
		||||
 *    till the purchase is consumed.
 | 
			
		||||
 * 4. An API to consume a purchase of an inapp item. All purchases of one-time
 | 
			
		||||
 *    in-app items are consumable and thereafter can be purchased again.
 | 
			
		||||
 * 5. An API to get current purchases of the user immediately. This will not contain any
 | 
			
		||||
 *    consumed purchases.
 | 
			
		||||
 *
 | 
			
		||||
 * All calls will give a response code with the following possible values
 | 
			
		||||
 * RESULT_OK = 0 - success
 | 
			
		||||
 * RESULT_USER_CANCELED = 1 - User pressed back or canceled a dialog
 | 
			
		||||
 * RESULT_SERVICE_UNAVAILABLE = 2 - The network connection is down
 | 
			
		||||
 * RESULT_BILLING_UNAVAILABLE = 3 - This billing API version is not supported for the type requested
 | 
			
		||||
 * RESULT_ITEM_UNAVAILABLE = 4 - Requested SKU is not available for purchase
 | 
			
		||||
 * RESULT_DEVELOPER_ERROR = 5 - Invalid arguments provided to the API
 | 
			
		||||
 * RESULT_ERROR = 6 - Fatal error during the API action
 | 
			
		||||
 * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned
 | 
			
		||||
 * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned
 | 
			
		||||
 */
 | 
			
		||||
public interface IInAppBillingService extends android.os.IInterface
 | 
			
		||||
    {
 | 
			
		||||
        /** Local-side IPC implementation stub class. */
 | 
			
		||||
        public static abstract class Stub extends android.os.Binder implements com.android.vending.billing.IInAppBillingService
 | 
			
		||||
        {
 | 
			
		||||
            private static final java.lang.String DESCRIPTOR = "com.android.vending.billing.IInAppBillingService";
 | 
			
		||||
            /** Construct the stub at attach it to the interface. */
 | 
			
		||||
            public Stub()
 | 
			
		||||
            {
 | 
			
		||||
                this.attachInterface(this, DESCRIPTOR);
 | 
			
		||||
            }
 | 
			
		||||
            /**
 | 
			
		||||
             * Cast an IBinder object into an com.android.vending.billing.IInAppBillingService interface,
 | 
			
		||||
             * generating a proxy if needed.
 | 
			
		||||
             */
 | 
			
		||||
            public static com.android.vending.billing.IInAppBillingService asInterface(android.os.IBinder obj)
 | 
			
		||||
            {
 | 
			
		||||
                if ((obj==null)) {
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
 | 
			
		||||
                if (((iin!=null)&&(iin instanceof com.android.vending.billing.IInAppBillingService))) {
 | 
			
		||||
                    return ((com.android.vending.billing.IInAppBillingService)iin);
 | 
			
		||||
                }
 | 
			
		||||
                return new com.android.vending.billing.IInAppBillingService.Stub.Proxy(obj);
 | 
			
		||||
            }
 | 
			
		||||
            @Override public android.os.IBinder asBinder()
 | 
			
		||||
            {
 | 
			
		||||
                return this;
 | 
			
		||||
            }
 | 
			
		||||
            @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
 | 
			
		||||
            {
 | 
			
		||||
                switch (code)
 | 
			
		||||
                {
 | 
			
		||||
                    case INTERFACE_TRANSACTION:
 | 
			
		||||
                    {
 | 
			
		||||
                        reply.writeString(DESCRIPTOR);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    case TRANSACTION_isBillingSupported:
 | 
			
		||||
                    {
 | 
			
		||||
                        data.enforceInterface(DESCRIPTOR);
 | 
			
		||||
                        int _arg0;
 | 
			
		||||
                        _arg0 = data.readInt();
 | 
			
		||||
                        java.lang.String _arg1;
 | 
			
		||||
                        _arg1 = data.readString();
 | 
			
		||||
                        java.lang.String _arg2;
 | 
			
		||||
                        _arg2 = data.readString();
 | 
			
		||||
                        int _result = this.isBillingSupported(_arg0, _arg1, _arg2);
 | 
			
		||||
                        reply.writeNoException();
 | 
			
		||||
                        reply.writeInt(_result);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    case TRANSACTION_getSkuDetails:
 | 
			
		||||
                    {
 | 
			
		||||
                        data.enforceInterface(DESCRIPTOR);
 | 
			
		||||
                        int _arg0;
 | 
			
		||||
                        _arg0 = data.readInt();
 | 
			
		||||
                        java.lang.String _arg1;
 | 
			
		||||
                        _arg1 = data.readString();
 | 
			
		||||
                        java.lang.String _arg2;
 | 
			
		||||
                        _arg2 = data.readString();
 | 
			
		||||
                        android.os.Bundle _arg3;
 | 
			
		||||
                        if ((0!=data.readInt())) {
 | 
			
		||||
                            _arg3 = android.os.Bundle.CREATOR.createFromParcel(data);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _arg3 = null;
 | 
			
		||||
                        }
 | 
			
		||||
                        android.os.Bundle _result = this.getSkuDetails(_arg0, _arg1, _arg2, _arg3);
 | 
			
		||||
                        reply.writeNoException();
 | 
			
		||||
                        if ((_result!=null)) {
 | 
			
		||||
                            reply.writeInt(1);
 | 
			
		||||
                            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            reply.writeInt(0);
 | 
			
		||||
                        }
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    case TRANSACTION_getBuyIntent:
 | 
			
		||||
                    {
 | 
			
		||||
                        data.enforceInterface(DESCRIPTOR);
 | 
			
		||||
                        int _arg0;
 | 
			
		||||
                        _arg0 = data.readInt();
 | 
			
		||||
                        java.lang.String _arg1;
 | 
			
		||||
                        _arg1 = data.readString();
 | 
			
		||||
                        java.lang.String _arg2;
 | 
			
		||||
                        _arg2 = data.readString();
 | 
			
		||||
                        java.lang.String _arg3;
 | 
			
		||||
                        _arg3 = data.readString();
 | 
			
		||||
                        java.lang.String _arg4;
 | 
			
		||||
                        _arg4 = data.readString();
 | 
			
		||||
                        android.os.Bundle _result = this.getBuyIntent(_arg0, _arg1, _arg2, _arg3, _arg4);
 | 
			
		||||
                        reply.writeNoException();
 | 
			
		||||
                        if ((_result!=null)) {
 | 
			
		||||
                            reply.writeInt(1);
 | 
			
		||||
                            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            reply.writeInt(0);
 | 
			
		||||
                        }
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    case TRANSACTION_getPurchases:
 | 
			
		||||
                    {
 | 
			
		||||
                        data.enforceInterface(DESCRIPTOR);
 | 
			
		||||
                        int _arg0;
 | 
			
		||||
                        _arg0 = data.readInt();
 | 
			
		||||
                        java.lang.String _arg1;
 | 
			
		||||
                        _arg1 = data.readString();
 | 
			
		||||
                        java.lang.String _arg2;
 | 
			
		||||
                        _arg2 = data.readString();
 | 
			
		||||
                        java.lang.String _arg3;
 | 
			
		||||
                        _arg3 = data.readString();
 | 
			
		||||
                        android.os.Bundle _result = this.getPurchases(_arg0, _arg1, _arg2, _arg3);
 | 
			
		||||
                        reply.writeNoException();
 | 
			
		||||
                        if ((_result!=null)) {
 | 
			
		||||
                            reply.writeInt(1);
 | 
			
		||||
                            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            reply.writeInt(0);
 | 
			
		||||
                        }
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    case TRANSACTION_consumePurchase:
 | 
			
		||||
                    {
 | 
			
		||||
                        data.enforceInterface(DESCRIPTOR);
 | 
			
		||||
                        int _arg0;
 | 
			
		||||
                        _arg0 = data.readInt();
 | 
			
		||||
                        java.lang.String _arg1;
 | 
			
		||||
                        _arg1 = data.readString();
 | 
			
		||||
                        java.lang.String _arg2;
 | 
			
		||||
                        _arg2 = data.readString();
 | 
			
		||||
                        int _result = this.consumePurchase(_arg0, _arg1, _arg2);
 | 
			
		||||
                        reply.writeNoException();
 | 
			
		||||
                        reply.writeInt(_result);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    case TRANSACTION_stub:
 | 
			
		||||
                    {
 | 
			
		||||
                        data.enforceInterface(DESCRIPTOR);
 | 
			
		||||
                        int _arg0;
 | 
			
		||||
                        _arg0 = data.readInt();
 | 
			
		||||
                        java.lang.String _arg1;
 | 
			
		||||
                        _arg1 = data.readString();
 | 
			
		||||
                        java.lang.String _arg2;
 | 
			
		||||
                        _arg2 = data.readString();
 | 
			
		||||
                        int _result = this.stub(_arg0, _arg1, _arg2);
 | 
			
		||||
                        reply.writeNoException();
 | 
			
		||||
                        reply.writeInt(_result);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    case TRANSACTION_getBuyIntentToReplaceSkus:
 | 
			
		||||
                    {
 | 
			
		||||
                        data.enforceInterface(DESCRIPTOR);
 | 
			
		||||
                        int _arg0;
 | 
			
		||||
                        _arg0 = data.readInt();
 | 
			
		||||
                        java.lang.String _arg1;
 | 
			
		||||
                        _arg1 = data.readString();
 | 
			
		||||
                        java.util.List<java.lang.String> _arg2;
 | 
			
		||||
                        _arg2 = data.createStringArrayList();
 | 
			
		||||
                        java.lang.String _arg3;
 | 
			
		||||
                        _arg3 = data.readString();
 | 
			
		||||
                        java.lang.String _arg4;
 | 
			
		||||
                        _arg4 = data.readString();
 | 
			
		||||
                        java.lang.String _arg5;
 | 
			
		||||
                        _arg5 = data.readString();
 | 
			
		||||
                        android.os.Bundle _result = this.getBuyIntentToReplaceSkus(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
 | 
			
		||||
                        reply.writeNoException();
 | 
			
		||||
                        if ((_result!=null)) {
 | 
			
		||||
                            reply.writeInt(1);
 | 
			
		||||
                            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            reply.writeInt(0);
 | 
			
		||||
                        }
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    case TRANSACTION_getBuyIntentExtraParams:
 | 
			
		||||
                    {
 | 
			
		||||
                        data.enforceInterface(DESCRIPTOR);
 | 
			
		||||
                        int _arg0;
 | 
			
		||||
                        _arg0 = data.readInt();
 | 
			
		||||
                        java.lang.String _arg1;
 | 
			
		||||
                        _arg1 = data.readString();
 | 
			
		||||
                        java.lang.String _arg2;
 | 
			
		||||
                        _arg2 = data.readString();
 | 
			
		||||
                        java.lang.String _arg3;
 | 
			
		||||
                        _arg3 = data.readString();
 | 
			
		||||
                        java.lang.String _arg4;
 | 
			
		||||
                        _arg4 = data.readString();
 | 
			
		||||
                        android.os.Bundle _arg5;
 | 
			
		||||
                        if ((0!=data.readInt())) {
 | 
			
		||||
                            _arg5 = android.os.Bundle.CREATOR.createFromParcel(data);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _arg5 = null;
 | 
			
		||||
                        }
 | 
			
		||||
                        android.os.Bundle _result = this.getBuyIntentExtraParams(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
 | 
			
		||||
                        reply.writeNoException();
 | 
			
		||||
                        if ((_result!=null)) {
 | 
			
		||||
                            reply.writeInt(1);
 | 
			
		||||
                            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            reply.writeInt(0);
 | 
			
		||||
                        }
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    case TRANSACTION_getPurchaseHistory:
 | 
			
		||||
                    {
 | 
			
		||||
                        data.enforceInterface(DESCRIPTOR);
 | 
			
		||||
                        int _arg0;
 | 
			
		||||
                        _arg0 = data.readInt();
 | 
			
		||||
                        java.lang.String _arg1;
 | 
			
		||||
                        _arg1 = data.readString();
 | 
			
		||||
                        java.lang.String _arg2;
 | 
			
		||||
                        _arg2 = data.readString();
 | 
			
		||||
                        java.lang.String _arg3;
 | 
			
		||||
                        _arg3 = data.readString();
 | 
			
		||||
                        android.os.Bundle _arg4;
 | 
			
		||||
                        if ((0!=data.readInt())) {
 | 
			
		||||
                            _arg4 = android.os.Bundle.CREATOR.createFromParcel(data);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _arg4 = null;
 | 
			
		||||
                        }
 | 
			
		||||
                        android.os.Bundle _result = this.getPurchaseHistory(_arg0, _arg1, _arg2, _arg3, _arg4);
 | 
			
		||||
                        reply.writeNoException();
 | 
			
		||||
                        if ((_result!=null)) {
 | 
			
		||||
                            reply.writeInt(1);
 | 
			
		||||
                            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            reply.writeInt(0);
 | 
			
		||||
                        }
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    case TRANSACTION_isBillingSupportedExtraParams:
 | 
			
		||||
                    {
 | 
			
		||||
                        data.enforceInterface(DESCRIPTOR);
 | 
			
		||||
                        int _arg0;
 | 
			
		||||
                        _arg0 = data.readInt();
 | 
			
		||||
                        java.lang.String _arg1;
 | 
			
		||||
                        _arg1 = data.readString();
 | 
			
		||||
                        java.lang.String _arg2;
 | 
			
		||||
                        _arg2 = data.readString();
 | 
			
		||||
                        android.os.Bundle _arg3;
 | 
			
		||||
                        if ((0!=data.readInt())) {
 | 
			
		||||
                            _arg3 = android.os.Bundle.CREATOR.createFromParcel(data);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _arg3 = null;
 | 
			
		||||
                        }
 | 
			
		||||
                        int _result = this.isBillingSupportedExtraParams(_arg0, _arg1, _arg2, _arg3);
 | 
			
		||||
                        reply.writeNoException();
 | 
			
		||||
                        reply.writeInt(_result);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return super.onTransact(code, data, reply, flags);
 | 
			
		||||
            }
 | 
			
		||||
            private static class Proxy implements com.android.vending.billing.IInAppBillingService
 | 
			
		||||
            {
 | 
			
		||||
                private android.os.IBinder mRemote;
 | 
			
		||||
                Proxy(android.os.IBinder remote)
 | 
			
		||||
                {
 | 
			
		||||
                    mRemote = remote;
 | 
			
		||||
                }
 | 
			
		||||
                @Override public android.os.IBinder asBinder()
 | 
			
		||||
                {
 | 
			
		||||
                    return mRemote;
 | 
			
		||||
                }
 | 
			
		||||
                public java.lang.String getInterfaceDescriptor()
 | 
			
		||||
                {
 | 
			
		||||
                    return DESCRIPTOR;
 | 
			
		||||
                }
 | 
			
		||||
                @Override public int isBillingSupported(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException
 | 
			
		||||
                {
 | 
			
		||||
                    android.os.Parcel _data = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Parcel _reply = android.os.Parcel.obtain();
 | 
			
		||||
                    int _result;
 | 
			
		||||
                    try {
 | 
			
		||||
                        _data.writeInterfaceToken(DESCRIPTOR);
 | 
			
		||||
                        _data.writeInt(apiVersion);
 | 
			
		||||
                        _data.writeString(packageName);
 | 
			
		||||
                        _data.writeString(type);
 | 
			
		||||
                        mRemote.transact(Stub.TRANSACTION_isBillingSupported, _data, _reply, 0);
 | 
			
		||||
                        _reply.readException();
 | 
			
		||||
                        _result = _reply.readInt();
 | 
			
		||||
                    }
 | 
			
		||||
                    finally {
 | 
			
		||||
                        _reply.recycle();
 | 
			
		||||
                        _data.recycle();
 | 
			
		||||
                    }
 | 
			
		||||
                    return _result;
 | 
			
		||||
                }
 | 
			
		||||
                /**
 | 
			
		||||
                 * Provides details of a list of SKUs
 | 
			
		||||
                 * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
 | 
			
		||||
                 * with a list JSON strings containing the productId, price, title and description.
 | 
			
		||||
                 * This API can be called with a maximum of 20 SKUs.
 | 
			
		||||
                 * @param apiVersion billing API version that the app is using
 | 
			
		||||
                 * @param packageName the package name of the calling app
 | 
			
		||||
                 * @param type of the in-app items ("inapp" for one-time purchases
 | 
			
		||||
                 *        and "subs" for subscriptions)
 | 
			
		||||
                 * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
 | 
			
		||||
                 * @return Bundle containing the following key-value pairs
 | 
			
		||||
                 *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
 | 
			
		||||
                 *                         on failures.
 | 
			
		||||
                 *         "DETAILS_LIST" with a StringArrayList containing purchase information
 | 
			
		||||
                 *                        in JSON format similar to:
 | 
			
		||||
                 *                        '{ "productId" : "exampleSku",
 | 
			
		||||
                 *                           "type" : "inapp",
 | 
			
		||||
                 *                           "price" : "$5.00",
 | 
			
		||||
                 *                           "price_currency": "USD",
 | 
			
		||||
                 *                           "price_amount_micros": 5000000,
 | 
			
		||||
                 *                           "title : "Example Title",
 | 
			
		||||
                 *                           "description" : "This is an example description" }'
 | 
			
		||||
                 */
 | 
			
		||||
                @Override public android.os.Bundle getSkuDetails(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle skusBundle) throws android.os.RemoteException
 | 
			
		||||
                {
 | 
			
		||||
                    android.os.Parcel _data = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Parcel _reply = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Bundle _result;
 | 
			
		||||
                    try {
 | 
			
		||||
                        _data.writeInterfaceToken(DESCRIPTOR);
 | 
			
		||||
                        _data.writeInt(apiVersion);
 | 
			
		||||
                        _data.writeString(packageName);
 | 
			
		||||
                        _data.writeString(type);
 | 
			
		||||
                        if ((skusBundle!=null)) {
 | 
			
		||||
                            _data.writeInt(1);
 | 
			
		||||
                            skusBundle.writeToParcel(_data, 0);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _data.writeInt(0);
 | 
			
		||||
                        }
 | 
			
		||||
                        mRemote.transact(Stub.TRANSACTION_getSkuDetails, _data, _reply, 0);
 | 
			
		||||
                        _reply.readException();
 | 
			
		||||
                        if ((0!=_reply.readInt())) {
 | 
			
		||||
                            _result = android.os.Bundle.CREATOR.createFromParcel(_reply);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _result = null;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    finally {
 | 
			
		||||
                        _reply.recycle();
 | 
			
		||||
                        _data.recycle();
 | 
			
		||||
                    }
 | 
			
		||||
                    return _result;
 | 
			
		||||
                }
 | 
			
		||||
                /**
 | 
			
		||||
                 * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,
 | 
			
		||||
                 * the type, a unique purchase token and an optional developer payload.
 | 
			
		||||
                 * @param apiVersion billing API version that the app is using
 | 
			
		||||
                 * @param packageName package name of the calling app
 | 
			
		||||
                 * @param sku the SKU of the in-app item as published in the developer console
 | 
			
		||||
                 * @param type of the in-app item being purchased ("inapp" for one-time purchases
 | 
			
		||||
                 *        and "subs" for subscriptions)
 | 
			
		||||
                 * @param developerPayload optional argument to be sent back with the purchase information
 | 
			
		||||
                 * @return Bundle containing the following key-value pairs
 | 
			
		||||
                 *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
 | 
			
		||||
                 *                         on failures.
 | 
			
		||||
                 *         "BUY_INTENT" - PendingIntent to start the purchase flow
 | 
			
		||||
                 *
 | 
			
		||||
                 * The Pending intent should be launched with startIntentSenderForResult. When purchase flow
 | 
			
		||||
                 * has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
 | 
			
		||||
                 * If the purchase is successful, the result data will contain the following key-value pairs
 | 
			
		||||
                 *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response
 | 
			
		||||
                 *                         codes on failures.
 | 
			
		||||
                 *         "INAPP_PURCHASE_DATA" - String in JSON format similar to
 | 
			
		||||
                 *                                 '{"orderId":"12999763169054705758.1371079406387615",
 | 
			
		||||
                 *                                   "packageName":"com.example.app",
 | 
			
		||||
                 *                                   "productId":"exampleSku",
 | 
			
		||||
                 *                                   "purchaseTime":1345678900000,
 | 
			
		||||
                 *                                   "purchaseToken" : "122333444455555",
 | 
			
		||||
                 *                                   "developerPayload":"example developer payload" }'
 | 
			
		||||
                 *         "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
 | 
			
		||||
                 *                                  was signed with the private key of the developer
 | 
			
		||||
                 */
 | 
			
		||||
                @Override public android.os.Bundle getBuyIntent(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException
 | 
			
		||||
                {
 | 
			
		||||
                    android.os.Parcel _data = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Parcel _reply = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Bundle _result;
 | 
			
		||||
                    try {
 | 
			
		||||
                        _data.writeInterfaceToken(DESCRIPTOR);
 | 
			
		||||
                        _data.writeInt(apiVersion);
 | 
			
		||||
                        _data.writeString(packageName);
 | 
			
		||||
                        _data.writeString(sku);
 | 
			
		||||
                        _data.writeString(type);
 | 
			
		||||
                        _data.writeString(developerPayload);
 | 
			
		||||
                        mRemote.transact(Stub.TRANSACTION_getBuyIntent, _data, _reply, 0);
 | 
			
		||||
                        _reply.readException();
 | 
			
		||||
                        if ((0!=_reply.readInt())) {
 | 
			
		||||
                            _result = android.os.Bundle.CREATOR.createFromParcel(_reply);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _result = null;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    finally {
 | 
			
		||||
                        _reply.recycle();
 | 
			
		||||
                        _data.recycle();
 | 
			
		||||
                    }
 | 
			
		||||
                    return _result;
 | 
			
		||||
                }
 | 
			
		||||
                /**
 | 
			
		||||
                 * Returns the current SKUs owned by the user of the type and package name specified along with
 | 
			
		||||
                 * purchase information and a signature of the data to be validated.
 | 
			
		||||
                 * This will return all SKUs that have been purchased in V3 and managed items purchased using
 | 
			
		||||
                 * V1 and V2 that have not been consumed.
 | 
			
		||||
                 * @param apiVersion billing API version that the app is using
 | 
			
		||||
                 * @param packageName package name of the calling app
 | 
			
		||||
                 * @param type of the in-app items being requested ("inapp" for one-time purchases
 | 
			
		||||
                 *        and "subs" for subscriptions)
 | 
			
		||||
                 * @param continuationToken to be set as null for the first call, if the number of owned
 | 
			
		||||
                 *        skus are too many, a continuationToken is returned in the response bundle.
 | 
			
		||||
                 *        This method can be called again with the continuation token to get the next set of
 | 
			
		||||
                 *        owned skus.
 | 
			
		||||
                 * @return Bundle containing the following key-value pairs
 | 
			
		||||
                 *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
 | 
			
		||||
                 on failures.
 | 
			
		||||
                 *         "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
 | 
			
		||||
                 *         "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
 | 
			
		||||
                 *         "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
 | 
			
		||||
                 *                                      of the purchase information
 | 
			
		||||
                 *         "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
 | 
			
		||||
                 *                                      next set of in-app purchases. Only set if the
 | 
			
		||||
                 *                                      user has more owned skus than the current list.
 | 
			
		||||
                 */
 | 
			
		||||
                @Override public android.os.Bundle getPurchases(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken) throws android.os.RemoteException
 | 
			
		||||
                {
 | 
			
		||||
                    android.os.Parcel _data = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Parcel _reply = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Bundle _result;
 | 
			
		||||
                    try {
 | 
			
		||||
                        _data.writeInterfaceToken(DESCRIPTOR);
 | 
			
		||||
                        _data.writeInt(apiVersion);
 | 
			
		||||
                        _data.writeString(packageName);
 | 
			
		||||
                        _data.writeString(type);
 | 
			
		||||
                        _data.writeString(continuationToken);
 | 
			
		||||
                        mRemote.transact(Stub.TRANSACTION_getPurchases, _data, _reply, 0);
 | 
			
		||||
                        _reply.readException();
 | 
			
		||||
                        if ((0!=_reply.readInt())) {
 | 
			
		||||
                            _result = android.os.Bundle.CREATOR.createFromParcel(_reply);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _result = null;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    finally {
 | 
			
		||||
                        _reply.recycle();
 | 
			
		||||
                        _data.recycle();
 | 
			
		||||
                    }
 | 
			
		||||
                    return _result;
 | 
			
		||||
                }
 | 
			
		||||
                @Override public int consumePurchase(int apiVersion, java.lang.String packageName, java.lang.String purchaseToken) throws android.os.RemoteException
 | 
			
		||||
                {
 | 
			
		||||
                    android.os.Parcel _data = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Parcel _reply = android.os.Parcel.obtain();
 | 
			
		||||
                    int _result;
 | 
			
		||||
                    try {
 | 
			
		||||
                        _data.writeInterfaceToken(DESCRIPTOR);
 | 
			
		||||
                        _data.writeInt(apiVersion);
 | 
			
		||||
                        _data.writeString(packageName);
 | 
			
		||||
                        _data.writeString(purchaseToken);
 | 
			
		||||
                        mRemote.transact(Stub.TRANSACTION_consumePurchase, _data, _reply, 0);
 | 
			
		||||
                        _reply.readException();
 | 
			
		||||
                        _result = _reply.readInt();
 | 
			
		||||
                    }
 | 
			
		||||
                    finally {
 | 
			
		||||
                        _reply.recycle();
 | 
			
		||||
                        _data.recycle();
 | 
			
		||||
                    }
 | 
			
		||||
                    return _result;
 | 
			
		||||
                }
 | 
			
		||||
                @Override public int stub(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException
 | 
			
		||||
                {
 | 
			
		||||
                    android.os.Parcel _data = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Parcel _reply = android.os.Parcel.obtain();
 | 
			
		||||
                    int _result;
 | 
			
		||||
                    try {
 | 
			
		||||
                        _data.writeInterfaceToken(DESCRIPTOR);
 | 
			
		||||
                        _data.writeInt(apiVersion);
 | 
			
		||||
                        _data.writeString(packageName);
 | 
			
		||||
                        _data.writeString(type);
 | 
			
		||||
                        mRemote.transact(Stub.TRANSACTION_stub, _data, _reply, 0);
 | 
			
		||||
                        _reply.readException();
 | 
			
		||||
                        _result = _reply.readInt();
 | 
			
		||||
                    }
 | 
			
		||||
                    finally {
 | 
			
		||||
                        _reply.recycle();
 | 
			
		||||
                        _data.recycle();
 | 
			
		||||
                    }
 | 
			
		||||
                    return _result;
 | 
			
		||||
                }
 | 
			
		||||
                /**
 | 
			
		||||
                 * Returns a pending intent to launch the purchase flow for upgrading or downgrading a
 | 
			
		||||
                 * subscription. The existing owned SKU(s) should be provided along with the new SKU that
 | 
			
		||||
                 * the user is upgrading or downgrading to.
 | 
			
		||||
                 * @param apiVersion billing API version that the app is using, must be 5 or later
 | 
			
		||||
                 * @param packageName package name of the calling app
 | 
			
		||||
                 * @param oldSkus the SKU(s) that the user is upgrading or downgrading from,
 | 
			
		||||
                 *        if null or empty this method will behave like {@link #getBuyIntent}
 | 
			
		||||
                 * @param newSku the SKU that the user is upgrading or downgrading to
 | 
			
		||||
                 * @param type of the item being purchased, currently must be "subs"
 | 
			
		||||
                 * @param developerPayload optional argument to be sent back with the purchase information
 | 
			
		||||
                 * @return Bundle containing the following key-value pairs
 | 
			
		||||
                 *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
 | 
			
		||||
                 *                         on failures.
 | 
			
		||||
                 *         "BUY_INTENT" - PendingIntent to start the purchase flow
 | 
			
		||||
                 *
 | 
			
		||||
                 * The Pending intent should be launched with startIntentSenderForResult. When purchase flow
 | 
			
		||||
                 * has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
 | 
			
		||||
                 * If the purchase is successful, the result data will contain the following key-value pairs
 | 
			
		||||
                 *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response
 | 
			
		||||
                 *                         codes on failures.
 | 
			
		||||
                 *         "INAPP_PURCHASE_DATA" - String in JSON format similar to
 | 
			
		||||
                 *                                 '{"orderId":"12999763169054705758.1371079406387615",
 | 
			
		||||
                 *                                   "packageName":"com.example.app",
 | 
			
		||||
                 *                                   "productId":"exampleSku",
 | 
			
		||||
                 *                                   "purchaseTime":1345678900000,
 | 
			
		||||
                 *                                   "purchaseToken" : "122333444455555",
 | 
			
		||||
                 *                                   "developerPayload":"example developer payload" }'
 | 
			
		||||
                 *         "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
 | 
			
		||||
                 *                                  was signed with the private key of the developer
 | 
			
		||||
                 */
 | 
			
		||||
                @Override public android.os.Bundle getBuyIntentToReplaceSkus(int apiVersion, java.lang.String packageName, java.util.List<java.lang.String> oldSkus, java.lang.String newSku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException
 | 
			
		||||
                {
 | 
			
		||||
                    android.os.Parcel _data = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Parcel _reply = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Bundle _result;
 | 
			
		||||
                    try {
 | 
			
		||||
                        _data.writeInterfaceToken(DESCRIPTOR);
 | 
			
		||||
                        _data.writeInt(apiVersion);
 | 
			
		||||
                        _data.writeString(packageName);
 | 
			
		||||
                        _data.writeStringList(oldSkus);
 | 
			
		||||
                        _data.writeString(newSku);
 | 
			
		||||
                        _data.writeString(type);
 | 
			
		||||
                        _data.writeString(developerPayload);
 | 
			
		||||
                        mRemote.transact(Stub.TRANSACTION_getBuyIntentToReplaceSkus, _data, _reply, 0);
 | 
			
		||||
                        _reply.readException();
 | 
			
		||||
                        if ((0!=_reply.readInt())) {
 | 
			
		||||
                            _result = android.os.Bundle.CREATOR.createFromParcel(_reply);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _result = null;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    finally {
 | 
			
		||||
                        _reply.recycle();
 | 
			
		||||
                        _data.recycle();
 | 
			
		||||
                    }
 | 
			
		||||
                    return _result;
 | 
			
		||||
                }
 | 
			
		||||
                /**
 | 
			
		||||
                 * Returns a pending intent to launch the purchase flow for an in-app item. This method is
 | 
			
		||||
                 * a variant of the {@link #getBuyIntent} method and takes an additional {@code extraParams}
 | 
			
		||||
                 * parameter. This parameter is a Bundle of optional keys and values that affect the
 | 
			
		||||
                 * operation of the method.
 | 
			
		||||
                 * @param apiVersion billing API version that the app is using, must be 6 or later
 | 
			
		||||
                 * @param packageName package name of the calling app
 | 
			
		||||
                 * @param sku the SKU of the in-app item as published in the developer console
 | 
			
		||||
                 * @param type of the in-app item being purchased ("inapp" for one-time purchases
 | 
			
		||||
                 *        and "subs" for subscriptions)
 | 
			
		||||
                 * @param developerPayload optional argument to be sent back with the purchase information
 | 
			
		||||
                 * @extraParams a Bundle with the following optional keys:
 | 
			
		||||
                 *        "skusToReplace" - List<String> - an optional list of SKUs that the user is
 | 
			
		||||
                 *                          upgrading or downgrading from.
 | 
			
		||||
                 *                          Pass this field if the purchase is upgrading or downgrading
 | 
			
		||||
                 *                          existing subscriptions.
 | 
			
		||||
                 *                          The specified SKUs are replaced with the SKUs that the user is
 | 
			
		||||
                 *                          purchasing. Google Play replaces the specified SKUs at the start of
 | 
			
		||||
                 *                          the next billing cycle.
 | 
			
		||||
                 * "replaceSkusProration" - Boolean - whether the user should be credited for any unused
 | 
			
		||||
                 *                          subscription time on the SKUs they are upgrading or downgrading.
 | 
			
		||||
                 *                          If you set this field to true, Google Play swaps out the old SKUs
 | 
			
		||||
                 *                          and credits the user with the unused value of their subscription
 | 
			
		||||
                 *                          time on a pro-rated basis.
 | 
			
		||||
                 *                          Google Play applies this credit to the new subscription, and does
 | 
			
		||||
                 *                          not begin billing the user for the new subscription until after
 | 
			
		||||
                 *                          the credit is used up.
 | 
			
		||||
                 *                          If you set this field to false, the user does not receive credit for
 | 
			
		||||
                 *                          any unused subscription time and the recurrence date does not
 | 
			
		||||
                 *                          change.
 | 
			
		||||
                 *                          Default value is true. Ignored if you do not pass skusToReplace.
 | 
			
		||||
                 *            "accountId" - String - an optional obfuscated string that is uniquely
 | 
			
		||||
                 *                          associated with the user's account in your app.
 | 
			
		||||
                 *                          If you pass this value, Google Play can use it to detect irregular
 | 
			
		||||
                 *                          activity, such as many devices making purchases on the same
 | 
			
		||||
                 *                          account in a short period of time.
 | 
			
		||||
                 *                          Do not use the developer ID or the user's Google ID for this field.
 | 
			
		||||
                 *                          In addition, this field should not contain the user's ID in
 | 
			
		||||
                 *                          cleartext.
 | 
			
		||||
                 *                          We recommend that you use a one-way hash to generate a string from
 | 
			
		||||
                 *                          the user's ID, and store the hashed string in this field.
 | 
			
		||||
                 *                   "vr" - Boolean - an optional flag indicating whether the returned intent
 | 
			
		||||
                 *                          should start a VR purchase flow. The apiVersion must also be 7 or
 | 
			
		||||
                 *                          later to use this flag.
 | 
			
		||||
                 */
 | 
			
		||||
                @Override public android.os.Bundle getBuyIntentExtraParams(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload, android.os.Bundle extraParams) throws android.os.RemoteException
 | 
			
		||||
                {
 | 
			
		||||
                    android.os.Parcel _data = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Parcel _reply = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Bundle _result;
 | 
			
		||||
                    try {
 | 
			
		||||
                        _data.writeInterfaceToken(DESCRIPTOR);
 | 
			
		||||
                        _data.writeInt(apiVersion);
 | 
			
		||||
                        _data.writeString(packageName);
 | 
			
		||||
                        _data.writeString(sku);
 | 
			
		||||
                        _data.writeString(type);
 | 
			
		||||
                        _data.writeString(developerPayload);
 | 
			
		||||
                        if ((extraParams!=null)) {
 | 
			
		||||
                            _data.writeInt(1);
 | 
			
		||||
                            extraParams.writeToParcel(_data, 0);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _data.writeInt(0);
 | 
			
		||||
                        }
 | 
			
		||||
                        mRemote.transact(Stub.TRANSACTION_getBuyIntentExtraParams, _data, _reply, 0);
 | 
			
		||||
                        _reply.readException();
 | 
			
		||||
                        if ((0!=_reply.readInt())) {
 | 
			
		||||
                            _result = android.os.Bundle.CREATOR.createFromParcel(_reply);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _result = null;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    finally {
 | 
			
		||||
                        _reply.recycle();
 | 
			
		||||
                        _data.recycle();
 | 
			
		||||
                    }
 | 
			
		||||
                    return _result;
 | 
			
		||||
                }
 | 
			
		||||
                /**
 | 
			
		||||
                 * Returns the most recent purchase made by the user for each SKU, even if that purchase is
 | 
			
		||||
                 * expired, canceled, or consumed.
 | 
			
		||||
                 * @param apiVersion billing API version that the app is using, must be 6 or later
 | 
			
		||||
                 * @param packageName package name of the calling app
 | 
			
		||||
                 * @param type of the in-app items being requested ("inapp" for one-time purchases
 | 
			
		||||
                 *        and "subs" for subscriptions)
 | 
			
		||||
                 * @param continuationToken to be set as null for the first call, if the number of owned
 | 
			
		||||
                 *        skus is too large, a continuationToken is returned in the response bundle.
 | 
			
		||||
                 *        This method can be called again with the continuation token to get the next set of
 | 
			
		||||
                 *        owned skus.
 | 
			
		||||
                 * @param extraParams a Bundle with extra params that would be appended into http request
 | 
			
		||||
                 *        query string. Not used at this moment. Reserved for future functionality.
 | 
			
		||||
                 * @return Bundle containing the following key-value pairs
 | 
			
		||||
                 *         "RESPONSE_CODE" with int value: RESULT_OK(0) if success,
 | 
			
		||||
                 *         {@link IabHelper#BILLING_RESPONSE_RESULT_*} response codes on failures.
 | 
			
		||||
                 *
 | 
			
		||||
                 *         "INAPP_PURCHASE_ITEM_LIST" - ArrayList<String> containing the list of SKUs
 | 
			
		||||
                 *         "INAPP_PURCHASE_DATA_LIST" - ArrayList<String> containing the purchase information
 | 
			
		||||
                 *         "INAPP_DATA_SIGNATURE_LIST"- ArrayList<String> containing the signatures
 | 
			
		||||
                 *                                      of the purchase information
 | 
			
		||||
                 *         "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
 | 
			
		||||
                 *                                      next set of in-app purchases. Only set if the
 | 
			
		||||
                 *                                      user has more owned skus than the current list.
 | 
			
		||||
                 */
 | 
			
		||||
                @Override public android.os.Bundle getPurchaseHistory(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken, android.os.Bundle extraParams) throws android.os.RemoteException
 | 
			
		||||
                {
 | 
			
		||||
                    android.os.Parcel _data = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Parcel _reply = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Bundle _result;
 | 
			
		||||
                    try {
 | 
			
		||||
                        _data.writeInterfaceToken(DESCRIPTOR);
 | 
			
		||||
                        _data.writeInt(apiVersion);
 | 
			
		||||
                        _data.writeString(packageName);
 | 
			
		||||
                        _data.writeString(type);
 | 
			
		||||
                        _data.writeString(continuationToken);
 | 
			
		||||
                        if ((extraParams!=null)) {
 | 
			
		||||
                            _data.writeInt(1);
 | 
			
		||||
                            extraParams.writeToParcel(_data, 0);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _data.writeInt(0);
 | 
			
		||||
                        }
 | 
			
		||||
                        mRemote.transact(Stub.TRANSACTION_getPurchaseHistory, _data, _reply, 0);
 | 
			
		||||
                        _reply.readException();
 | 
			
		||||
                        if ((0!=_reply.readInt())) {
 | 
			
		||||
                            _result = android.os.Bundle.CREATOR.createFromParcel(_reply);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _result = null;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    finally {
 | 
			
		||||
                        _reply.recycle();
 | 
			
		||||
                        _data.recycle();
 | 
			
		||||
                    }
 | 
			
		||||
                    return _result;
 | 
			
		||||
                }
 | 
			
		||||
                @Override public int isBillingSupportedExtraParams(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle extraParams) throws android.os.RemoteException
 | 
			
		||||
                {
 | 
			
		||||
                    android.os.Parcel _data = android.os.Parcel.obtain();
 | 
			
		||||
                    android.os.Parcel _reply = android.os.Parcel.obtain();
 | 
			
		||||
                    int _result;
 | 
			
		||||
                    try {
 | 
			
		||||
                        _data.writeInterfaceToken(DESCRIPTOR);
 | 
			
		||||
                        _data.writeInt(apiVersion);
 | 
			
		||||
                        _data.writeString(packageName);
 | 
			
		||||
                        _data.writeString(type);
 | 
			
		||||
                        if ((extraParams!=null)) {
 | 
			
		||||
                            _data.writeInt(1);
 | 
			
		||||
                            extraParams.writeToParcel(_data, 0);
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            _data.writeInt(0);
 | 
			
		||||
                        }
 | 
			
		||||
                        mRemote.transact(Stub.TRANSACTION_isBillingSupportedExtraParams, _data, _reply, 0);
 | 
			
		||||
                        _reply.readException();
 | 
			
		||||
                        _result = _reply.readInt();
 | 
			
		||||
                    }
 | 
			
		||||
                    finally {
 | 
			
		||||
                        _reply.recycle();
 | 
			
		||||
                        _data.recycle();
 | 
			
		||||
                    }
 | 
			
		||||
                    return _result;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            static final int TRANSACTION_isBillingSupported = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
 | 
			
		||||
            static final int TRANSACTION_getSkuDetails = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
 | 
			
		||||
            static final int TRANSACTION_getBuyIntent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
 | 
			
		||||
            static final int TRANSACTION_getPurchases = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
 | 
			
		||||
            static final int TRANSACTION_consumePurchase = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
 | 
			
		||||
            static final int TRANSACTION_stub = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
 | 
			
		||||
            static final int TRANSACTION_getBuyIntentToReplaceSkus = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
 | 
			
		||||
            static final int TRANSACTION_getBuyIntentExtraParams = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
 | 
			
		||||
            static final int TRANSACTION_getPurchaseHistory = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
 | 
			
		||||
            static final int TRANSACTION_isBillingSupportedExtraParams = (android.os.IBinder.FIRST_CALL_TRANSACTION + 9);
 | 
			
		||||
        }
 | 
			
		||||
        public int isBillingSupported(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException;
 | 
			
		||||
        /**
 | 
			
		||||
         * Provides details of a list of SKUs
 | 
			
		||||
         * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
 | 
			
		||||
         * with a list JSON strings containing the productId, price, title and description.
 | 
			
		||||
         * This API can be called with a maximum of 20 SKUs.
 | 
			
		||||
         * @param apiVersion billing API version that the app is using
 | 
			
		||||
         * @param packageName the package name of the calling app
 | 
			
		||||
         * @param type of the in-app items ("inapp" for one-time purchases
 | 
			
		||||
         *        and "subs" for subscriptions)
 | 
			
		||||
         * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
 | 
			
		||||
         * @return Bundle containing the following key-value pairs
 | 
			
		||||
         *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
 | 
			
		||||
         *                         on failures.
 | 
			
		||||
         *         "DETAILS_LIST" with a StringArrayList containing purchase information
 | 
			
		||||
         *                        in JSON format similar to:
 | 
			
		||||
         *                        '{ "productId" : "exampleSku",
 | 
			
		||||
         *                           "type" : "inapp",
 | 
			
		||||
         *                           "price" : "$5.00",
 | 
			
		||||
         *                           "price_currency": "USD",
 | 
			
		||||
         *                           "price_amount_micros": 5000000,
 | 
			
		||||
         *                           "title : "Example Title",
 | 
			
		||||
         *                           "description" : "This is an example description" }'
 | 
			
		||||
         */
 | 
			
		||||
        public android.os.Bundle getSkuDetails(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle skusBundle) throws android.os.RemoteException;
 | 
			
		||||
        /**
 | 
			
		||||
         * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,
 | 
			
		||||
         * the type, a unique purchase token and an optional developer payload.
 | 
			
		||||
         * @param apiVersion billing API version that the app is using
 | 
			
		||||
         * @param packageName package name of the calling app
 | 
			
		||||
         * @param sku the SKU of the in-app item as published in the developer console
 | 
			
		||||
         * @param type of the in-app item being purchased ("inapp" for one-time purchases
 | 
			
		||||
         *        and "subs" for subscriptions)
 | 
			
		||||
         * @param developerPayload optional argument to be sent back with the purchase information
 | 
			
		||||
         * @return Bundle containing the following key-value pairs
 | 
			
		||||
         *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
 | 
			
		||||
         *                         on failures.
 | 
			
		||||
         *         "BUY_INTENT" - PendingIntent to start the purchase flow
 | 
			
		||||
         *
 | 
			
		||||
         * The Pending intent should be launched with startIntentSenderForResult. When purchase flow
 | 
			
		||||
         * has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
 | 
			
		||||
         * If the purchase is successful, the result data will contain the following key-value pairs
 | 
			
		||||
         *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response
 | 
			
		||||
         *                         codes on failures.
 | 
			
		||||
         *         "INAPP_PURCHASE_DATA" - String in JSON format similar to
 | 
			
		||||
         *                                 '{"orderId":"12999763169054705758.1371079406387615",
 | 
			
		||||
         *                                   "packageName":"com.example.app",
 | 
			
		||||
         *                                   "productId":"exampleSku",
 | 
			
		||||
         *                                   "purchaseTime":1345678900000,
 | 
			
		||||
         *                                   "purchaseToken" : "122333444455555",
 | 
			
		||||
         *                                   "developerPayload":"example developer payload" }'
 | 
			
		||||
         *         "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
 | 
			
		||||
         *                                  was signed with the private key of the developer
 | 
			
		||||
         */
 | 
			
		||||
        public android.os.Bundle getBuyIntent(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException;
 | 
			
		||||
        /**
 | 
			
		||||
         * Returns the current SKUs owned by the user of the type and package name specified along with
 | 
			
		||||
         * purchase information and a signature of the data to be validated.
 | 
			
		||||
         * This will return all SKUs that have been purchased in V3 and managed items purchased using
 | 
			
		||||
         * V1 and V2 that have not been consumed.
 | 
			
		||||
         * @param apiVersion billing API version that the app is using
 | 
			
		||||
         * @param packageName package name of the calling app
 | 
			
		||||
         * @param type of the in-app items being requested ("inapp" for one-time purchases
 | 
			
		||||
         *        and "subs" for subscriptions)
 | 
			
		||||
         * @param continuationToken to be set as null for the first call, if the number of owned
 | 
			
		||||
         *        skus are too many, a continuationToken is returned in the response bundle.
 | 
			
		||||
         *        This method can be called again with the continuation token to get the next set of
 | 
			
		||||
         *        owned skus.
 | 
			
		||||
         * @return Bundle containing the following key-value pairs
 | 
			
		||||
         *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
 | 
			
		||||
         on failures.
 | 
			
		||||
         *         "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
 | 
			
		||||
         *         "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
 | 
			
		||||
         *         "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
 | 
			
		||||
         *                                      of the purchase information
 | 
			
		||||
         *         "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
 | 
			
		||||
         *                                      next set of in-app purchases. Only set if the
 | 
			
		||||
         *                                      user has more owned skus than the current list.
 | 
			
		||||
         */
 | 
			
		||||
        public android.os.Bundle getPurchases(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken) throws android.os.RemoteException;
 | 
			
		||||
        public int consumePurchase(int apiVersion, java.lang.String packageName, java.lang.String purchaseToken) throws android.os.RemoteException;
 | 
			
		||||
        public int stub(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException;
 | 
			
		||||
        /**
 | 
			
		||||
         * Returns a pending intent to launch the purchase flow for upgrading or downgrading a
 | 
			
		||||
         * subscription. The existing owned SKU(s) should be provided along with the new SKU that
 | 
			
		||||
         * the user is upgrading or downgrading to.
 | 
			
		||||
         * @param apiVersion billing API version that the app is using, must be 5 or later
 | 
			
		||||
         * @param packageName package name of the calling app
 | 
			
		||||
         * @param oldSkus the SKU(s) that the user is upgrading or downgrading from,
 | 
			
		||||
         *        if null or empty this method will behave like {@link #getBuyIntent}
 | 
			
		||||
         * @param newSku the SKU that the user is upgrading or downgrading to
 | 
			
		||||
         * @param type of the item being purchased, currently must be "subs"
 | 
			
		||||
         * @param developerPayload optional argument to be sent back with the purchase information
 | 
			
		||||
         * @return Bundle containing the following key-value pairs
 | 
			
		||||
         *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
 | 
			
		||||
         *                         on failures.
 | 
			
		||||
         *         "BUY_INTENT" - PendingIntent to start the purchase flow
 | 
			
		||||
         *
 | 
			
		||||
         * The Pending intent should be launched with startIntentSenderForResult. When purchase flow
 | 
			
		||||
         * has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
 | 
			
		||||
         * If the purchase is successful, the result data will contain the following key-value pairs
 | 
			
		||||
         *         "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response
 | 
			
		||||
         *                         codes on failures.
 | 
			
		||||
         *         "INAPP_PURCHASE_DATA" - String in JSON format similar to
 | 
			
		||||
         *                                 '{"orderId":"12999763169054705758.1371079406387615",
 | 
			
		||||
         *                                   "packageName":"com.example.app",
 | 
			
		||||
         *                                   "productId":"exampleSku",
 | 
			
		||||
         *                                   "purchaseTime":1345678900000,
 | 
			
		||||
         *                                   "purchaseToken" : "122333444455555",
 | 
			
		||||
         *                                   "developerPayload":"example developer payload" }'
 | 
			
		||||
         *         "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
 | 
			
		||||
         *                                  was signed with the private key of the developer
 | 
			
		||||
         */
 | 
			
		||||
        public android.os.Bundle getBuyIntentToReplaceSkus(int apiVersion, java.lang.String packageName, java.util.List<java.lang.String> oldSkus, java.lang.String newSku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException;
 | 
			
		||||
        /**
 | 
			
		||||
         * Returns a pending intent to launch the purchase flow for an in-app item. This method is
 | 
			
		||||
         * a variant of the {@link #getBuyIntent} method and takes an additional {@code extraParams}
 | 
			
		||||
         * parameter. This parameter is a Bundle of optional keys and values that affect the
 | 
			
		||||
         * operation of the method.
 | 
			
		||||
         * @param apiVersion billing API version that the app is using, must be 6 or later
 | 
			
		||||
         * @param packageName package name of the calling app
 | 
			
		||||
         * @param sku the SKU of the in-app item as published in the developer console
 | 
			
		||||
         * @param type of the in-app item being purchased ("inapp" for one-time purchases
 | 
			
		||||
         *        and "subs" for subscriptions)
 | 
			
		||||
         * @param developerPayload optional argument to be sent back with the purchase information
 | 
			
		||||
         * @extraParams a Bundle with the following optional keys:
 | 
			
		||||
         *        "skusToReplace" - List<String> - an optional list of SKUs that the user is
 | 
			
		||||
         *                          upgrading or downgrading from.
 | 
			
		||||
         *                          Pass this field if the purchase is upgrading or downgrading
 | 
			
		||||
         *                          existing subscriptions.
 | 
			
		||||
         *                          The specified SKUs are replaced with the SKUs that the user is
 | 
			
		||||
         *                          purchasing. Google Play replaces the specified SKUs at the start of
 | 
			
		||||
         *                          the next billing cycle.
 | 
			
		||||
         * "replaceSkusProration" - Boolean - whether the user should be credited for any unused
 | 
			
		||||
         *                          subscription time on the SKUs they are upgrading or downgrading.
 | 
			
		||||
         *                          If you set this field to true, Google Play swaps out the old SKUs
 | 
			
		||||
         *                          and credits the user with the unused value of their subscription
 | 
			
		||||
         *                          time on a pro-rated basis.
 | 
			
		||||
         *                          Google Play applies this credit to the new subscription, and does
 | 
			
		||||
         *                          not begin billing the user for the new subscription until after
 | 
			
		||||
         *                          the credit is used up.
 | 
			
		||||
         *                          If you set this field to false, the user does not receive credit for
 | 
			
		||||
         *                          any unused subscription time and the recurrence date does not
 | 
			
		||||
         *                          change.
 | 
			
		||||
         *                          Default value is true. Ignored if you do not pass skusToReplace.
 | 
			
		||||
         *            "accountId" - String - an optional obfuscated string that is uniquely
 | 
			
		||||
         *                          associated with the user's account in your app.
 | 
			
		||||
         *                          If you pass this value, Google Play can use it to detect irregular
 | 
			
		||||
         *                          activity, such as many devices making purchases on the same
 | 
			
		||||
         *                          account in a short period of time.
 | 
			
		||||
         *                          Do not use the developer ID or the user's Google ID for this field.
 | 
			
		||||
         *                          In addition, this field should not contain the user's ID in
 | 
			
		||||
         *                          cleartext.
 | 
			
		||||
         *                          We recommend that you use a one-way hash to generate a string from
 | 
			
		||||
         *                          the user's ID, and store the hashed string in this field.
 | 
			
		||||
         *                   "vr" - Boolean - an optional flag indicating whether the returned intent
 | 
			
		||||
         *                          should start a VR purchase flow. The apiVersion must also be 7 or
 | 
			
		||||
         *                          later to use this flag.
 | 
			
		||||
         */
 | 
			
		||||
        public android.os.Bundle getBuyIntentExtraParams(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload, android.os.Bundle extraParams) throws android.os.RemoteException;
 | 
			
		||||
        /**
 | 
			
		||||
         * Returns the most recent purchase made by the user for each SKU, even if that purchase is
 | 
			
		||||
         * expired, canceled, or consumed.
 | 
			
		||||
         * @param apiVersion billing API version that the app is using, must be 6 or later
 | 
			
		||||
         * @param packageName package name of the calling app
 | 
			
		||||
         * @param type of the in-app items being requested ("inapp" for one-time purchases
 | 
			
		||||
         *        and "subs" for subscriptions)
 | 
			
		||||
         * @param continuationToken to be set as null for the first call, if the number of owned
 | 
			
		||||
         *        skus is too large, a continuationToken is returned in the response bundle.
 | 
			
		||||
         *        This method can be called again with the continuation token to get the next set of
 | 
			
		||||
         *        owned skus.
 | 
			
		||||
         * @param extraParams a Bundle with extra params that would be appended into http request
 | 
			
		||||
         *        query string. Not used at this moment. Reserved for future functionality.
 | 
			
		||||
         * @return Bundle containing the following key-value pairs
 | 
			
		||||
         *         "RESPONSE_CODE" with int value: RESULT_OK(0) if success,
 | 
			
		||||
         *         {@link IabHelper#BILLING_RESPONSE_RESULT_*} response codes on failures.
 | 
			
		||||
         *
 | 
			
		||||
         *         "INAPP_PURCHASE_ITEM_LIST" - ArrayList<String> containing the list of SKUs
 | 
			
		||||
         *         "INAPP_PURCHASE_DATA_LIST" - ArrayList<String> containing the purchase information
 | 
			
		||||
         *         "INAPP_DATA_SIGNATURE_LIST"- ArrayList<String> containing the signatures
 | 
			
		||||
         *                                      of the purchase information
 | 
			
		||||
         *         "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
 | 
			
		||||
         *                                      next set of in-app purchases. Only set if the
 | 
			
		||||
         *                                      user has more owned skus than the current list.
 | 
			
		||||
         */
 | 
			
		||||
        public android.os.Bundle getPurchaseHistory(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken, android.os.Bundle extraParams) throws android.os.RemoteException;
 | 
			
		||||
        public int isBillingSupportedExtraParams(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle extraParams) throws android.os.RemoteException;
 | 
			
		||||
    }
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -1,16 +0,0 @@
 | 
			
		||||
package com.juce;
 | 
			
		||||
 | 
			
		||||
import com.google.firebase.iid.*;
 | 
			
		||||
 | 
			
		||||
public final class JuceFirebaseInstanceIdService extends FirebaseInstanceIdService
 | 
			
		||||
{
 | 
			
		||||
    private native void firebaseInstanceIdTokenRefreshed (String token);
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onTokenRefresh()
 | 
			
		||||
    {
 | 
			
		||||
        String token = FirebaseInstanceId.getInstance().getToken();
 | 
			
		||||
 | 
			
		||||
        firebaseInstanceIdTokenRefreshed (token);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
package com.juce;
 | 
			
		||||
 | 
			
		||||
import com.google.firebase.messaging.*;
 | 
			
		||||
 | 
			
		||||
public final class JuceFirebaseMessagingService extends FirebaseMessagingService
 | 
			
		||||
{
 | 
			
		||||
    private native void firebaseRemoteMessageReceived (RemoteMessage message);
 | 
			
		||||
    private native void firebaseRemoteMessagesDeleted();
 | 
			
		||||
    private native void firebaseRemoteMessageSent (String messageId);
 | 
			
		||||
    private native void firebaseRemoteMessageSendError (String messageId, String error);
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onMessageReceived (RemoteMessage message)
 | 
			
		||||
    {
 | 
			
		||||
        firebaseRemoteMessageReceived (message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDeletedMessages()
 | 
			
		||||
    {
 | 
			
		||||
        firebaseRemoteMessagesDeleted();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onMessageSent (String messageId)
 | 
			
		||||
    {
 | 
			
		||||
        firebaseRemoteMessageSent (messageId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onSendError (String messageId, Exception e)
 | 
			
		||||
    {
 | 
			
		||||
        firebaseRemoteMessageSendError (messageId, e.toString());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								modules/juce_core/native/java/README.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								modules/juce_core/native/java/README.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
			
		||||
The Java code in the module's native/java subfolders have been used to generate
 | 
			
		||||
dex byte-code in various places in the JUCE framework. These are the steps
 | 
			
		||||
required to re-generate the dex byte-code from any Java source code inside the
 | 
			
		||||
native/java subfolders:
 | 
			
		||||
 | 
			
		||||
1. Create a new JUCE android project with the minimal sdk version which is
 | 
			
		||||
required for the Java source code you wish to compile.
 | 
			
		||||
 | 
			
		||||
2. If you are creating byte-code for new .java files, move the new files into
 | 
			
		||||
the native/javacore/app folder of the module, or create one if it doesn't
 | 
			
		||||
exist. Remember that .java files need to be in nested sub-folders which
 | 
			
		||||
resemble their package, i.e. a Java class com.roli.juce.HelloWorld.java
 | 
			
		||||
should be in the module's native/javacore/app/com/roli/juce folder.
 | 
			
		||||
If you wish to modify existing .java files in the JUCE modules then just rename
 | 
			
		||||
native/java to native/javacore.
 | 
			
		||||
 | 
			
		||||
3. Build your project with AS and run. The app will now use the source code in
 | 
			
		||||
the folder created in step 2 so you can debug your Java code this way.
 | 
			
		||||
 | 
			
		||||
4. Once everything is working rebuild your app in release mode.
 | 
			
		||||
 | 
			
		||||
5. Go to your app's Builds/Android folder. Inside there you will find
 | 
			
		||||
build/intermediates/javac/release_Release/compileRelease_ReleaseJavaWithJavac/classes. 
 | 
			
		||||
Inside of that folder, you will find all your Java byte-code compiled classes.
 | 
			
		||||
Remove any classes that you are not interested in (typically you'll find
 | 
			
		||||
Java.class, JuceApp.class and JuceSharingContentProvider.class which you will
 | 
			
		||||
probably want to remove).
 | 
			
		||||
 | 
			
		||||
6. Inside of app/build/intermediates/classes/release_/release execute the
 | 
			
		||||
following dx command:
 | 
			
		||||
 | 
			
		||||
    <path-to-your-android-sdk>/build-tools/<latest-build-tool-version>/dx --dex --verbose --min-sdk-version=<your-min-sdk-of-your-classes> --output /tmp/JavaDexByteCode.dex .
 | 
			
		||||
 | 
			
		||||
    (Replace <your-min-sdk-of-your-classes> with the minimal sdk version you used in step 1.)
 | 
			
		||||
   
 | 
			
		||||
7. gzip the output:
 | 
			
		||||
 | 
			
		||||
    gzip /tmp/JavaDexByteCode.dex
 | 
			
		||||
 | 
			
		||||
8. The output /tmp/JavaDexByteCode.dex.gz is now the byte code that can be
 | 
			
		||||
included into JUCE. You can use the Projucer's BinaryData generator
 | 
			
		||||
functionality to get this into a convenient char array like form.
 | 
			
		||||
@ -0,0 +1,58 @@
 | 
			
		||||
package com.roli.juce;
 | 
			
		||||
 | 
			
		||||
import android.app.DialogFragment;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
 | 
			
		||||
public class FragmentOverlay extends DialogFragment
 | 
			
		||||
{
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate (Bundle state)
 | 
			
		||||
    {
 | 
			
		||||
        super.onCreate (state);
 | 
			
		||||
        cppThis = getArguments ().getLong ("cppThis");
 | 
			
		||||
 | 
			
		||||
        if (cppThis != 0)
 | 
			
		||||
            onCreateNative (cppThis, state);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onStart ()
 | 
			
		||||
    {
 | 
			
		||||
        super.onStart ();
 | 
			
		||||
 | 
			
		||||
        if (cppThis != 0)
 | 
			
		||||
            onStartNative (cppThis);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void onRequestPermissionsResult (int requestCode,
 | 
			
		||||
                                            String[] permissions,
 | 
			
		||||
                                            int[] grantResults)
 | 
			
		||||
    {
 | 
			
		||||
        if (cppThis != 0)
 | 
			
		||||
            onRequestPermissionsResultNative (cppThis, requestCode,
 | 
			
		||||
                    permissions, grantResults);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onActivityResult (int requestCode, int resultCode, Intent data)
 | 
			
		||||
    {
 | 
			
		||||
        if (cppThis != 0)
 | 
			
		||||
            onActivityResultNative (cppThis, requestCode, resultCode, data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void close ()
 | 
			
		||||
    {
 | 
			
		||||
        cppThis = 0;
 | 
			
		||||
        dismiss ();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    private long cppThis = 0;
 | 
			
		||||
 | 
			
		||||
    private native void onActivityResultNative (long myself, int requestCode, int resultCode, Intent data);
 | 
			
		||||
    private native void onCreateNative (long myself, Bundle state);
 | 
			
		||||
    private native void onStartNative (long myself);
 | 
			
		||||
    private native void onRequestPermissionsResultNative (long myself, int requestCode,
 | 
			
		||||
                                                          String[] permissions, int[] grantResults);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,407 @@
 | 
			
		||||
package com.roli.juce;
 | 
			
		||||
 | 
			
		||||
import java.lang.Runnable;
 | 
			
		||||
import java.io.*;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.net.HttpURLConnection;
 | 
			
		||||
import java.util.concurrent.CancellationException;
 | 
			
		||||
import java.util.concurrent.Future;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
import java.util.concurrent.ExecutorService;
 | 
			
		||||
import java.util.concurrent.ExecutionException;
 | 
			
		||||
import java.util.concurrent.Callable;
 | 
			
		||||
import java.util.concurrent.locks.ReentrantLock;
 | 
			
		||||
import java.util.concurrent.atomic.*;
 | 
			
		||||
 | 
			
		||||
public class JuceHTTPStream
 | 
			
		||||
{
 | 
			
		||||
    public JuceHTTPStream(String address, boolean isPostToUse, byte[] postDataToUse,
 | 
			
		||||
                          String headersToUse, int timeOutMsToUse,
 | 
			
		||||
                          int[] statusCodeToUse, StringBuffer responseHeadersToUse,
 | 
			
		||||
                          int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
 | 
			
		||||
    {
 | 
			
		||||
        isPost = isPostToUse;
 | 
			
		||||
        postData = postDataToUse;
 | 
			
		||||
        headers = headersToUse;
 | 
			
		||||
        timeOutMs = timeOutMsToUse;
 | 
			
		||||
        statusCode = statusCodeToUse;
 | 
			
		||||
        responseHeaders = responseHeadersToUse;
 | 
			
		||||
        totalLength = -1;
 | 
			
		||||
        numRedirectsToFollow = numRedirectsToFollowToUse;
 | 
			
		||||
        httpRequestCmd = httpRequestCmdToUse;
 | 
			
		||||
 | 
			
		||||
        connection = createConnection(address, isPost, postData, headers, timeOutMs, httpRequestCmd);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static final JuceHTTPStream 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;
 | 
			
		||||
 | 
			
		||||
        for (; ; )
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                JuceHTTPStream httpStream = new JuceHTTPStream(address, isPost, postData, headers,
 | 
			
		||||
                        timeOutMs, statusCode, responseHeaders,
 | 
			
		||||
                        numRedirectsToFollow, httpRequestCmd);
 | 
			
		||||
 | 
			
		||||
                return httpStream;
 | 
			
		||||
            } catch (Throwable e)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final HttpURLConnection createConnection(String address, boolean isPost, byte[] postData,
 | 
			
		||||
                                                     String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
 | 
			
		||||
    {
 | 
			
		||||
        HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            newConnection.setInstanceFollowRedirects(false);
 | 
			
		||||
            newConnection.setConnectTimeout(timeOutMs);
 | 
			
		||||
            newConnection.setReadTimeout(timeOutMs);
 | 
			
		||||
 | 
			
		||||
            // 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");
 | 
			
		||||
 | 
			
		||||
            // 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)
 | 
			
		||||
                        newConnection.setRequestProperty(field, value);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            newConnection.setRequestMethod(httpRequestCmd);
 | 
			
		||||
 | 
			
		||||
            if (isPost)
 | 
			
		||||
            {
 | 
			
		||||
                newConnection.setDoOutput(true);
 | 
			
		||||
 | 
			
		||||
                if (postData != null)
 | 
			
		||||
                {
 | 
			
		||||
                    OutputStream out = newConnection.getOutputStream();
 | 
			
		||||
                    out.write(postData);
 | 
			
		||||
                    out.flush();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return newConnection;
 | 
			
		||||
        } catch (Throwable e)
 | 
			
		||||
        {
 | 
			
		||||
            newConnection.disconnect();
 | 
			
		||||
            throw new IOException("Connection error");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final InputStream getCancellableStream(final boolean isInput) throws ExecutionException
 | 
			
		||||
    {
 | 
			
		||||
        synchronized (createFutureLock)
 | 
			
		||||
        {
 | 
			
		||||
            if (hasBeenCancelled.get())
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            streamFuture = executor.submit(new Callable<BufferedInputStream>()
 | 
			
		||||
            {
 | 
			
		||||
                @Override
 | 
			
		||||
                public BufferedInputStream call() throws IOException
 | 
			
		||||
                {
 | 
			
		||||
                    return new BufferedInputStream(isInput ? connection.getInputStream()
 | 
			
		||||
                            : connection.getErrorStream());
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            return streamFuture.get();
 | 
			
		||||
        } catch (InterruptedException e)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (CancellationException e)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final boolean connect()
 | 
			
		||||
    {
 | 
			
		||||
        boolean result = false;
 | 
			
		||||
        int numFollowedRedirects = 0;
 | 
			
		||||
 | 
			
		||||
        while (true)
 | 
			
		||||
        {
 | 
			
		||||
            result = doConnect();
 | 
			
		||||
 | 
			
		||||
            if (!result)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if (++numFollowedRedirects > numRedirectsToFollow)
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            int status = statusCode[0];
 | 
			
		||||
 | 
			
		||||
            if (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 currentLocation = connection.getURL().toString();
 | 
			
		||||
                    String newLocation = responseHeaders.substring(pos1, pos2);
 | 
			
		||||
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        // Handle newLocation whether it's absolute or relative
 | 
			
		||||
                        URL baseUrl = new URL(currentLocation);
 | 
			
		||||
                        URL newUrl = new URL(baseUrl, newLocation);
 | 
			
		||||
                        String transformedNewLocation = newUrl.toString();
 | 
			
		||||
 | 
			
		||||
                        if (transformedNewLocation != currentLocation)
 | 
			
		||||
                        {
 | 
			
		||||
                            // Clear responseHeaders before next iteration
 | 
			
		||||
                            responseHeaders.delete(0, responseHeaders.length());
 | 
			
		||||
 | 
			
		||||
                            synchronized (createStreamLock)
 | 
			
		||||
                            {
 | 
			
		||||
                                if (hasBeenCancelled.get())
 | 
			
		||||
                                    return false;
 | 
			
		||||
 | 
			
		||||
                                connection.disconnect();
 | 
			
		||||
 | 
			
		||||
                                try
 | 
			
		||||
                                {
 | 
			
		||||
                                    connection = createConnection(transformedNewLocation, isPost,
 | 
			
		||||
                                            postData, headers, timeOutMs,
 | 
			
		||||
                                            httpRequestCmd);
 | 
			
		||||
                                } catch (Throwable e)
 | 
			
		||||
                                {
 | 
			
		||||
                                    return false;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        } else
 | 
			
		||||
                        {
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    } catch (Throwable e)
 | 
			
		||||
                    {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                } else
 | 
			
		||||
                {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            } else
 | 
			
		||||
            {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final boolean doConnect()
 | 
			
		||||
    {
 | 
			
		||||
        synchronized (createStreamLock)
 | 
			
		||||
        {
 | 
			
		||||
            if (hasBeenCancelled.get())
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    inputStream = getCancellableStream(true);
 | 
			
		||||
                } catch (ExecutionException e)
 | 
			
		||||
                {
 | 
			
		||||
                    if (connection.getResponseCode() < 400)
 | 
			
		||||
                    {
 | 
			
		||||
                        statusCode[0] = connection.getResponseCode();
 | 
			
		||||
                        connection.disconnect();
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                } finally
 | 
			
		||||
                {
 | 
			
		||||
                    statusCode[0] = connection.getResponseCode();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    if (statusCode[0] >= 400)
 | 
			
		||||
                        inputStream = getCancellableStream(false);
 | 
			
		||||
                    else
 | 
			
		||||
                        inputStream = getCancellableStream(true);
 | 
			
		||||
                } catch (ExecutionException e)
 | 
			
		||||
                {
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                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");
 | 
			
		||||
 | 
			
		||||
                        if (entry.getKey().compareTo("Content-Length") == 0)
 | 
			
		||||
                            totalLength = Integer.decode(entry.getValue().get(0));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return true;
 | 
			
		||||
            } catch (IOException e)
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static class DisconnectionRunnable implements Runnable
 | 
			
		||||
    {
 | 
			
		||||
        public DisconnectionRunnable(HttpURLConnection theConnection,
 | 
			
		||||
                                     InputStream theInputStream,
 | 
			
		||||
                                     ReentrantLock theCreateStreamLock,
 | 
			
		||||
                                     Object theCreateFutureLock,
 | 
			
		||||
                                     Future<BufferedInputStream> theStreamFuture)
 | 
			
		||||
        {
 | 
			
		||||
            connectionToDisconnect = theConnection;
 | 
			
		||||
            inputStream = theInputStream;
 | 
			
		||||
            createStreamLock = theCreateStreamLock;
 | 
			
		||||
            createFutureLock = theCreateFutureLock;
 | 
			
		||||
            streamFuture = theStreamFuture;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void run()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (!createStreamLock.tryLock())
 | 
			
		||||
                {
 | 
			
		||||
                    synchronized (createFutureLock)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (streamFuture != null)
 | 
			
		||||
                            streamFuture.cancel(true);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    createStreamLock.lock();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (connectionToDisconnect != null)
 | 
			
		||||
                    connectionToDisconnect.disconnect();
 | 
			
		||||
 | 
			
		||||
                if (inputStream != null)
 | 
			
		||||
                    inputStream.close();
 | 
			
		||||
            } catch (IOException e)
 | 
			
		||||
            {
 | 
			
		||||
            } finally
 | 
			
		||||
            {
 | 
			
		||||
                createStreamLock.unlock();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private HttpURLConnection connectionToDisconnect;
 | 
			
		||||
        private InputStream inputStream;
 | 
			
		||||
        private ReentrantLock createStreamLock;
 | 
			
		||||
        private Object createFutureLock;
 | 
			
		||||
        Future<BufferedInputStream> streamFuture;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final void release()
 | 
			
		||||
    {
 | 
			
		||||
        DisconnectionRunnable disconnectionRunnable = new DisconnectionRunnable(connection,
 | 
			
		||||
                inputStream,
 | 
			
		||||
                createStreamLock,
 | 
			
		||||
                createFutureLock,
 | 
			
		||||
                streamFuture);
 | 
			
		||||
 | 
			
		||||
        synchronized (createStreamLock)
 | 
			
		||||
        {
 | 
			
		||||
            hasBeenCancelled.set(true);
 | 
			
		||||
 | 
			
		||||
            connection = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Thread disconnectionThread = new Thread(disconnectionRunnable);
 | 
			
		||||
        disconnectionThread.start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final int read(byte[] buffer, int numBytes)
 | 
			
		||||
    {
 | 
			
		||||
        int num = 0;
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            synchronized (createStreamLock)
 | 
			
		||||
            {
 | 
			
		||||
                if (inputStream != null)
 | 
			
		||||
                    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 totalLength;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final boolean isExhausted()
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public final boolean setPosition(long newPos)
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean isPost;
 | 
			
		||||
    private byte[] postData;
 | 
			
		||||
    private String headers;
 | 
			
		||||
    private int timeOutMs;
 | 
			
		||||
    String httpRequestCmd;
 | 
			
		||||
    private HttpURLConnection connection;
 | 
			
		||||
    private int[] statusCode;
 | 
			
		||||
    private StringBuffer responseHeaders;
 | 
			
		||||
    private int totalLength;
 | 
			
		||||
    private int numRedirectsToFollow;
 | 
			
		||||
    private InputStream inputStream;
 | 
			
		||||
    private long position;
 | 
			
		||||
    private final ReentrantLock createStreamLock = new ReentrantLock();
 | 
			
		||||
    private final Object createFutureLock = new Object();
 | 
			
		||||
    private AtomicBoolean hasBeenCancelled = new AtomicBoolean();
 | 
			
		||||
 | 
			
		||||
    private final ExecutorService executor = Executors.newCachedThreadPool(Executors.defaultThreadFactory());
 | 
			
		||||
    Future<BufferedInputStream> streamFuture;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user