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