1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media.midi; 18 19 import android.app.Service; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.IBinder; 23 import android.os.RemoteException; 24 import android.os.ServiceManager; 25 import android.util.Log; 26 27 /** 28 * A service that implements a virtual MIDI device. 29 * Subclasses must implement the {@link #onGetInputPortReceivers} method to provide a 30 * list of {@link MidiReceiver}s to receive data sent to the device's input ports. 31 * Similarly, subclasses can call {@link #getOutputPortReceivers} to fetch a list 32 * of {@link MidiReceiver}s for sending data out the output ports. 33 * 34 * <p>To extend this class, you must declare the service in your manifest file with 35 * an intent filter with the {@link #SERVICE_INTERFACE} action 36 * and meta-data to describe the virtual device. 37 For example:</p> 38 * <pre> 39 * <service android:name=".VirtualDeviceService" 40 * android:label="@string/service_name"> 41 * <intent-filter> 42 * <action android:name="android.media.midi.MidiDeviceService" /> 43 * </intent-filter> 44 * <meta-data android:name="android.media.midi.MidiDeviceService" 45 android:resource="@xml/device_info" /> 46 * </service></pre> 47 */ 48 abstract public class MidiDeviceService extends Service { 49 private static final String TAG = "MidiDeviceService"; 50 51 public static final String SERVICE_INTERFACE = "android.media.midi.MidiDeviceService"; 52 53 private IMidiManager mMidiManager; 54 private MidiDeviceServer mServer; 55 private MidiDeviceInfo mDeviceInfo; 56 57 private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() { 58 @Override 59 public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) { 60 MidiDeviceService.this.onDeviceStatusChanged(status); 61 } 62 63 @Override 64 public void onClose() { 65 MidiDeviceService.this.onClose(); 66 } 67 }; 68 69 @Override onCreate()70 public void onCreate() { 71 mMidiManager = IMidiManager.Stub.asInterface( 72 ServiceManager.getService(Context.MIDI_SERVICE)); 73 MidiDeviceServer server; 74 try { 75 MidiDeviceInfo deviceInfo = mMidiManager.getServiceDeviceInfo(getPackageName(), 76 this.getClass().getName()); 77 if (deviceInfo == null) { 78 Log.e(TAG, "Could not find MidiDeviceInfo for MidiDeviceService " + this); 79 return; 80 } 81 mDeviceInfo = deviceInfo; 82 MidiReceiver[] inputPortReceivers = onGetInputPortReceivers(); 83 if (inputPortReceivers == null) { 84 inputPortReceivers = new MidiReceiver[0]; 85 } 86 server = new MidiDeviceServer(mMidiManager, inputPortReceivers, deviceInfo, mCallback); 87 } catch (RemoteException e) { 88 Log.e(TAG, "RemoteException in IMidiManager.getServiceDeviceInfo"); 89 server = null; 90 } 91 mServer = server; 92 } 93 94 /** 95 * Returns an array of {@link MidiReceiver} for the device's input ports. 96 * Subclasses must override this to provide the receivers which will receive 97 * data sent to the device's input ports. An empty array should be returned if 98 * the device has no input ports. 99 * @return array of MidiReceivers 100 */ onGetInputPortReceivers()101 abstract public MidiReceiver[] onGetInputPortReceivers(); 102 103 /** 104 * Returns an array of {@link MidiReceiver} for the device's output ports. 105 * These can be used to send data out the device's output ports. 106 * @return array of MidiReceivers 107 */ getOutputPortReceivers()108 public final MidiReceiver[] getOutputPortReceivers() { 109 if (mServer == null) { 110 return null; 111 } else { 112 return mServer.getOutputPortReceivers(); 113 } 114 } 115 116 /** 117 * returns the {@link MidiDeviceInfo} instance for this service 118 * @return our MidiDeviceInfo 119 */ getDeviceInfo()120 public final MidiDeviceInfo getDeviceInfo() { 121 return mDeviceInfo; 122 } 123 124 /** 125 * Called to notify when an our {@link MidiDeviceStatus} has changed 126 * @param status the number of the port that was opened 127 */ onDeviceStatusChanged(MidiDeviceStatus status)128 public void onDeviceStatusChanged(MidiDeviceStatus status) { 129 } 130 131 /** 132 * Called to notify when our device has been closed by all its clients 133 */ onClose()134 public void onClose() { 135 } 136 137 @Override onBind(Intent intent)138 public IBinder onBind(Intent intent) { 139 if (SERVICE_INTERFACE.equals(intent.getAction()) && mServer != null) { 140 return mServer.getBinderInterface().asBinder(); 141 } else { 142 return null; 143 } 144 } 145 } 146