111fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood/* 211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * Copyright (C) 2015 The Android Open Source Project 311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * 411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License"); 511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * you may not use this file except in compliance with the License. 611fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * You may obtain a copy of the License at 711fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * 811fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * http://www.apache.org/licenses/LICENSE-2.0 911fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * 1011fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * Unless required by applicable law or agreed to in writing, software 1111fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS, 1211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * See the License for the specific language governing permissions and 1411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * limitations under the License. 1511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood */ 1611fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood 1711fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwoodpackage android.media.midi; 1811fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood 1911fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwoodimport android.app.Service; 2011fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwoodimport android.content.Context; 2111fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwoodimport android.content.Intent; 2211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwoodimport android.os.IBinder; 2311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwoodimport android.os.RemoteException; 2411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwoodimport android.os.ServiceManager; 2511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwoodimport android.util.Log; 2611fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood 2711fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood/** 2811fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * A service that implements a virtual MIDI device. 2981b9f7d325a552c54e793b51f571ae3d65b26e94Mike Lockwood * Subclasses must implement the {@link #onGetInputPortReceivers} method to provide a 3011fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * list of {@link MidiReceiver}s to receive data sent to the device's input ports. 3111fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * Similarly, subclasses can call {@link #getOutputPortReceivers} to fetch a list 3211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * of {@link MidiReceiver}s for sending data out the output ports. 3311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * 3411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * <p>To extend this class, you must declare the service in your manifest file with 3511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * an intent filter with the {@link #SERVICE_INTERFACE} action 3611fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * and meta-data to describe the virtual device. 3711fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood For example:</p> 3811fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * <pre> 3911fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * <service android:name=".VirtualDeviceService" 4011fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * android:label="@string/service_name"> 4111fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * <intent-filter> 4211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * <action android:name="android.media.midi.MidiDeviceService" /> 4311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * </intent-filter> 4411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * <meta-data android:name="android.media.midi.MidiDeviceService" 4511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood android:resource="@xml/device_info" /> 4611fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * </service></pre> 4711fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood */ 4811fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwoodabstract public class MidiDeviceService extends Service { 4911fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood private static final String TAG = "MidiDeviceService"; 5011fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood 5111fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood public static final String SERVICE_INTERFACE = "android.media.midi.MidiDeviceService"; 5211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood 5311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood private IMidiManager mMidiManager; 5411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood private MidiDeviceServer mServer; 55eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood private MidiDeviceInfo mDeviceInfo; 5611fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood 575ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() { 585ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood @Override 595ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) { 605ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood MidiDeviceService.this.onDeviceStatusChanged(status); 615ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood } 62e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood 63e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood @Override 64e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood public void onClose() { 65e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood MidiDeviceService.this.onClose(); 66e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood } 675ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood }; 685ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood 6911fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood @Override 7011fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood public void onCreate() { 7111fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood mMidiManager = IMidiManager.Stub.asInterface( 7211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood ServiceManager.getService(Context.MIDI_SERVICE)); 7311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood MidiDeviceServer server; 7411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood try { 7511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood MidiDeviceInfo deviceInfo = mMidiManager.getServiceDeviceInfo(getPackageName(), 7611fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood this.getClass().getName()); 77eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood if (deviceInfo == null) { 78eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood Log.e(TAG, "Could not find MidiDeviceInfo for MidiDeviceService " + this); 79eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood return; 80eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood } 81eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood mDeviceInfo = deviceInfo; 8281b9f7d325a552c54e793b51f571ae3d65b26e94Mike Lockwood MidiReceiver[] inputPortReceivers = onGetInputPortReceivers(); 8311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood if (inputPortReceivers == null) { 8411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood inputPortReceivers = new MidiReceiver[0]; 8511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood } 86acd4321872387212bbd956e134faf22eee4bbadcMike Lockwood server = new MidiDeviceServer(mMidiManager, inputPortReceivers, deviceInfo, mCallback); 8711fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood } catch (RemoteException e) { 8811fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood Log.e(TAG, "RemoteException in IMidiManager.getServiceDeviceInfo"); 8911fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood server = null; 9011fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood } 9111fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood mServer = server; 9211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood } 9311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood 9411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood /** 9511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * Returns an array of {@link MidiReceiver} for the device's input ports. 9611fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * Subclasses must override this to provide the receivers which will receive 979189f5f0252e1ef3e7d00978ef12e964565dd6f1Mike Lockwood * data sent to the device's input ports. An empty array should be returned if 9811fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * the device has no input ports. 9911fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * @return array of MidiReceivers 10011fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood */ 10181b9f7d325a552c54e793b51f571ae3d65b26e94Mike Lockwood abstract public MidiReceiver[] onGetInputPortReceivers(); 10211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood 10311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood /** 10411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * Returns an array of {@link MidiReceiver} for the device's output ports. 10511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * These can be used to send data out the device's output ports. 10611fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood * @return array of MidiReceivers 10711fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood */ 10881b9f7d325a552c54e793b51f571ae3d65b26e94Mike Lockwood public final MidiReceiver[] getOutputPortReceivers() { 10911fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood if (mServer == null) { 11011fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood return null; 11111fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood } else { 11211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood return mServer.getOutputPortReceivers(); 11311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood } 11411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood } 11511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood 116eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood /** 117eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood * returns the {@link MidiDeviceInfo} instance for this service 118eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood * @return our MidiDeviceInfo 119eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood */ 12081b9f7d325a552c54e793b51f571ae3d65b26e94Mike Lockwood public final MidiDeviceInfo getDeviceInfo() { 121eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood return mDeviceInfo; 122eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood } 123eebc98ff18c1ee92dff3fcd505158ea161d552beMike Lockwood 1245ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood /** 1255ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood * Called to notify when an our {@link MidiDeviceStatus} has changed 1265ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood * @param status the number of the port that was opened 1275ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood */ 1285ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood public void onDeviceStatusChanged(MidiDeviceStatus status) { 1295ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood } 1305ff9e2a1719f78cddc7a23d6572ab15ab595dafdMike Lockwood 131e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood /** 132e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood * Called to notify when our device has been closed by all its clients 133e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood */ 134e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood public void onClose() { 135e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood } 136e0a6ca64fac5bd4f10139321604031816e90adb4Mike Lockwood 13711fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood @Override 13811fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood public IBinder onBind(Intent intent) { 13911fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood if (SERVICE_INTERFACE.equals(intent.getAction()) && mServer != null) { 14011fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood return mServer.getBinderInterface().asBinder(); 14111fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood } else { 14211fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood return null; 14311fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood } 14411fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood } 14511fd96d6ff25bc1d710448eab545fe09da55a5f5Mike Lockwood} 146