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