MidiManager.java revision 9db9326ad47279709a0f7989addaf4b45221b6b9
1/* 2 * Copyright (C) 2014 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 17package android.media.midi; 18 19import android.content.ComponentName; 20import android.content.Context; 21import android.content.Intent; 22import android.content.ServiceConnection; 23import android.content.pm.ServiceInfo; 24import android.os.Binder; 25import android.os.IBinder; 26import android.os.Bundle; 27import android.os.Handler; 28import android.os.RemoteException; 29import android.util.Log; 30 31import java.util.HashMap; 32 33/** 34 * This class is the public application interface to the MIDI service. 35 * 36 * <p>You can obtain an instance of this class by calling 37 * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. 38 * 39 * {@samplecode 40 * MidiManager manager = (MidiManager) getSystemService(Context.MIDI_SERVICE);} 41 */ 42public final class MidiManager { 43 private static final String TAG = "MidiManager"; 44 45 private final Context mContext; 46 private final IMidiManager mService; 47 private final IBinder mToken = new Binder(); 48 49 private HashMap<DeviceCallback,DeviceListener> mDeviceListeners = 50 new HashMap<DeviceCallback,DeviceListener>(); 51 52 // Binder stub for receiving device notifications from MidiService 53 private class DeviceListener extends IMidiDeviceListener.Stub { 54 private final DeviceCallback mCallback; 55 private final Handler mHandler; 56 57 public DeviceListener(DeviceCallback callback, Handler handler) { 58 mCallback = callback; 59 mHandler = handler; 60 } 61 62 @Override 63 public void onDeviceAdded(MidiDeviceInfo device) { 64 if (mHandler != null) { 65 final MidiDeviceInfo deviceF = device; 66 mHandler.post(new Runnable() { 67 @Override public void run() { 68 mCallback.onDeviceAdded(deviceF); 69 } 70 }); 71 } else { 72 mCallback.onDeviceAdded(device); 73 } 74 } 75 76 @Override 77 public void onDeviceRemoved(MidiDeviceInfo device) { 78 if (mHandler != null) { 79 final MidiDeviceInfo deviceF = device; 80 mHandler.post(new Runnable() { 81 @Override public void run() { 82 mCallback.onDeviceRemoved(deviceF); 83 } 84 }); 85 } else { 86 mCallback.onDeviceRemoved(device); 87 } 88 } 89 90 @Override 91 public void onDeviceStatusChanged(MidiDeviceStatus status) { 92 if (mHandler != null) { 93 final MidiDeviceStatus statusF = status; 94 mHandler.post(new Runnable() { 95 @Override public void run() { 96 mCallback.onDeviceStatusChanged(statusF); 97 } 98 }); 99 } else { 100 mCallback.onDeviceStatusChanged(status); 101 } 102 } 103 } 104 105 /** 106 * Callback class used for clients to receive MIDI device added and removed notifications 107 */ 108 public static class DeviceCallback { 109 /** 110 * Called to notify when a new MIDI device has been added 111 * 112 * @param device a {@link MidiDeviceInfo} for the newly added device 113 */ 114 public void onDeviceAdded(MidiDeviceInfo device) { 115 } 116 117 /** 118 * Called to notify when a MIDI device has been removed 119 * 120 * @param device a {@link MidiDeviceInfo} for the removed device 121 */ 122 public void onDeviceRemoved(MidiDeviceInfo device) { 123 } 124 125 /** 126 * Called to notify when the status of a MIDI device has changed 127 * 128 * @param status a {@link MidiDeviceStatus} for the changed device 129 */ 130 public void onDeviceStatusChanged(MidiDeviceStatus status) { 131 } 132 } 133 134 /** 135 * Callback class used for receiving the results of {@link #openDevice} 136 */ 137 abstract public static class DeviceOpenCallback { 138 /** 139 * Called to respond to a {@link #openDevice} request 140 * 141 * @param deviceInfo the {@link MidiDeviceInfo} for the device to open 142 * @param device a {@link MidiDevice} for opened device, or null if opening failed 143 */ 144 abstract public void onDeviceOpened(MidiDeviceInfo deviceInfo, MidiDevice device); 145 } 146 147 /** 148 * @hide 149 */ 150 public MidiManager(Context context, IMidiManager service) { 151 mContext = context; 152 mService = service; 153 } 154 155 /** 156 * Registers a callback to receive notifications when MIDI devices are added and removed. 157 * 158 * @param callback a {@link DeviceCallback} for MIDI device notifications 159 * @param handler The {@link android.os.Handler Handler} that will be used for delivering the 160 * device notifications. If handler is null, then the thread used for the 161 * callback is unspecified. 162 */ 163 public void registerDeviceCallback(DeviceCallback callback, Handler handler) { 164 DeviceListener deviceListener = new DeviceListener(callback, handler); 165 try { 166 mService.registerListener(mToken, deviceListener); 167 } catch (RemoteException e) { 168 Log.e(TAG, "RemoteException in registerDeviceListener"); 169 return; 170 } 171 mDeviceListeners.put(callback, deviceListener); 172 } 173 174 /** 175 * Unregisters a {@link DeviceCallback}. 176 * 177 * @param callback a {@link DeviceCallback} to unregister 178 */ 179 public void unregisterDeviceCallback(DeviceCallback callback) { 180 DeviceListener deviceListener = mDeviceListeners.remove(callback); 181 if (deviceListener != null) { 182 try { 183 mService.unregisterListener(mToken, deviceListener); 184 } catch (RemoteException e) { 185 Log.e(TAG, "RemoteException in unregisterDeviceListener"); 186 } 187 } 188 } 189 190 /** 191 * Gets the list of all connected MIDI devices. 192 * 193 * @return an array of all MIDI devices 194 */ 195 public MidiDeviceInfo[] getDeviceList() { 196 try { 197 return mService.getDeviceList(); 198 } catch (RemoteException e) { 199 Log.e(TAG, "RemoteException in getDeviceList"); 200 return new MidiDeviceInfo[0]; 201 } 202 } 203 204 private void sendOpenDeviceResponse(final MidiDeviceInfo deviceInfo, final MidiDevice device, 205 final DeviceOpenCallback callback, Handler handler) { 206 if (handler != null) { 207 handler.post(new Runnable() { 208 @Override public void run() { 209 callback.onDeviceOpened(deviceInfo, device); 210 } 211 }); 212 } else { 213 callback.onDeviceOpened(deviceInfo, device); 214 } 215 } 216 217 /** 218 * Opens a MIDI device for reading and writing. 219 * 220 * @param deviceInfo a {@link android.media.midi.MidiDeviceInfo} to open 221 * @param callback a {@link MidiManager.DeviceOpenCallback} to be called to receive the result 222 * @param handler the {@link android.os.Handler Handler} that will be used for delivering 223 * the result. If handler is null, then the thread used for the 224 * callback is unspecified. 225 */ 226 public void openDevice(MidiDeviceInfo deviceInfo, DeviceOpenCallback callback, 227 Handler handler) { 228 MidiDevice device = null; 229 try { 230 IMidiDeviceServer server = mService.openDevice(mToken, deviceInfo); 231 if (server == null) { 232 ServiceInfo serviceInfo = (ServiceInfo)deviceInfo.getProperties().getParcelable( 233 MidiDeviceInfo.PROPERTY_SERVICE_INFO); 234 if (serviceInfo == null) { 235 Log.e(TAG, "no ServiceInfo for " + deviceInfo); 236 } else { 237 Intent intent = new Intent(MidiDeviceService.SERVICE_INTERFACE); 238 intent.setComponent(new ComponentName(serviceInfo.packageName, 239 serviceInfo.name)); 240 final MidiDeviceInfo deviceInfoF = deviceInfo; 241 final DeviceOpenCallback callbackF = callback; 242 final Handler handlerF = handler; 243 if (mContext.bindService(intent, 244 new ServiceConnection() { 245 @Override 246 public void onServiceConnected(ComponentName name, IBinder binder) { 247 IMidiDeviceServer server = 248 IMidiDeviceServer.Stub.asInterface(binder); 249 MidiDevice device = new MidiDevice(deviceInfoF, server, mContext, this); 250 sendOpenDeviceResponse(deviceInfoF, device, callbackF, handlerF); 251 } 252 253 @Override 254 public void onServiceDisconnected(ComponentName name) { 255 // FIXME - anything to do here? 256 } 257 }, 258 Context.BIND_AUTO_CREATE)) 259 { 260 // return immediately to avoid calling sendOpenDeviceResponse below 261 return; 262 } else { 263 Log.e(TAG, "Unable to bind service: " + intent); 264 } 265 } 266 } else { 267 device = new MidiDevice(deviceInfo, server); 268 } 269 } catch (RemoteException e) { 270 Log.e(TAG, "RemoteException in openDevice"); 271 } 272 sendOpenDeviceResponse(deviceInfo, device, callback, handler); 273 } 274 275 /** @hide */ 276 public MidiDeviceServer createDeviceServer(MidiReceiver[] inputPortReceivers, 277 int numOutputPorts, String[] inputPortNames, String[] outputPortNames, 278 Bundle properties, int type, MidiDeviceServer.Callback callback) { 279 try { 280 MidiDeviceServer server = new MidiDeviceServer(mService, inputPortReceivers, 281 numOutputPorts, callback); 282 MidiDeviceInfo deviceInfo = mService.registerDeviceServer(server.getBinderInterface(), 283 inputPortReceivers.length, numOutputPorts, inputPortNames, outputPortNames, 284 properties, type); 285 if (deviceInfo == null) { 286 Log.e(TAG, "registerVirtualDevice failed"); 287 return null; 288 } 289 server.setDeviceInfo(deviceInfo); 290 return server; 291 } catch (RemoteException e) { 292 Log.e(TAG, "RemoteException in createVirtualDevice"); 293 return null; 294 } 295 } 296} 297