MidiCTS: test new MIDI API without devices

Change-Id: I88e4210946e59f7a0fc4d304cac525cace274c6b
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/tests/tests/media/src/android/media/cts/MidiSoloTest.java b/tests/tests/media/src/android/media/cts/MidiSoloTest.java
new file mode 100644
index 0000000..4c1a5e8
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MidiSoloTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import java.io.IOException;
+
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.cts.util.CtsAndroidTestCase;
+import android.media.midi.MidiDevice;
+import android.media.midi.MidiDevice.MidiConnection;
+import android.media.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceStatus;
+import android.media.midi.MidiInputPort;
+import android.media.midi.MidiManager;
+import android.media.midi.MidiReceiver;
+import android.media.midi.MidiSender;
+import android.os.Handler;
+import android.os.Looper;
+
+/**
+ * Test MIDI when there may be no MIDI devices available. There is not much we
+ * can test without a device.
+ */
+public class MidiSoloTest extends CtsAndroidTestCase {
+    private static final String TAG = "MidiSoloTest";
+    private final static int LOCAL_STORAGE_SIZE = 256;
+
+    // Store received data so we can check it later.
+    class MyMidiReceiver extends MidiReceiver {
+        public int byteCount;
+        public byte[] data = new byte[LOCAL_STORAGE_SIZE];
+
+        public MyMidiReceiver(int maxMessageSize) {
+            super(maxMessageSize);
+        }
+
+        @Override
+        // Abstract method declared in MidiReceiver
+        public void onSend(byte[] msg, int offset, int count, long timestamp)
+                throws IOException {
+            assertTrue("Message too large.", (count <= getMaxMessageSize()));
+            try {
+                System.arraycopy(msg, offset, data, byteCount, count);
+            } catch (ArrayIndexOutOfBoundsException e) {
+                throw new IOException("Exceeded local storage.", e);
+            }
+            byteCount += count;
+        }
+
+        @Override
+        public void onFlush() {
+            byteCount = 0;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        // setup for each test case.
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        // Test case clean up.
+        super.tearDown();
+    }
+
+    public void testMidiManager() throws Exception {
+        PackageManager pm = getContext().getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_MIDI)) {
+            return; // Not supported so don't test it.
+        }
+
+        MidiManager midiManager = (MidiManager) getContext().getSystemService(
+                Context.MIDI_SERVICE);
+        assertTrue("MidiManager not supported.", midiManager != null);
+
+        MidiDeviceInfo[] infos = midiManager.getDevices();
+        assertTrue("Device list was null.", infos != null);
+
+        MidiManager.DeviceCallback callback = new MidiManager.DeviceCallback();
+
+        // These should not crash.
+        midiManager.unregisterDeviceCallback(null);
+        midiManager.unregisterDeviceCallback(callback);
+        midiManager.registerDeviceCallback(null, null);
+        midiManager.registerDeviceCallback(callback, null);
+        midiManager.unregisterDeviceCallback(callback);
+        midiManager.registerDeviceCallback(callback, new Handler(Looper.getMainLooper()));
+        midiManager.registerDeviceCallback(callback, new Handler(Looper.getMainLooper()));
+        midiManager.unregisterDeviceCallback(callback);
+        midiManager.unregisterDeviceCallback(callback);
+        midiManager.unregisterDeviceCallback(callback);
+        midiManager.registerDeviceCallback(null, new Handler(Looper.getMainLooper()));
+        midiManager.unregisterDeviceCallback(callback);
+        midiManager.unregisterDeviceCallback(null);
+    }
+
+    public void testMidiReceiver() throws Exception {
+        PackageManager pm = getContext().getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_MIDI)) {
+            return; // Not supported so don't test it.
+        }
+
+        MidiReceiver receiver = new MidiReceiver() {
+                @Override
+            public void onSend(byte[] msg, int offset, int count,
+                    long timestamp) throws IOException {
+            }
+        };
+        assertEquals("MidiReceiver default size wrong.", Integer.MAX_VALUE,
+                receiver.getMaxMessageSize());
+
+        int maxSize = 11;
+        MyMidiReceiver myReceiver = new MyMidiReceiver(maxSize);
+        assertEquals("MidiReceiver set size wrong.", maxSize,
+                myReceiver.getMaxMessageSize());
+
+        // Fill array with predictable data.
+        byte[] bar = new byte[200];
+        for (int i = 0; i < bar.length; i++) {
+            bar[i] = (byte) (i ^ 15);
+        }
+        // Small message with no offset.
+        int offset = 0;
+        int count = 3;
+        checkReceivedData(myReceiver, bar, offset, count);
+
+        // Small with an offset.
+        offset = 50;
+        count = 3;
+        checkReceivedData(myReceiver, bar, offset, count);
+
+        // Entire array.
+        offset = 0;
+        count = bar.length;
+        checkReceivedData(myReceiver, bar, offset, count);
+
+        offset = 20;
+        count = 100;
+        checkReceivedData(myReceiver, bar, offset, count);
+    }
+
+    public void testMidiReceiverException() throws Exception {
+        PackageManager pm = getContext().getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_MIDI)) {
+            return; // Not supported so don't test it.
+        }
+
+        int maxSize = 11;
+        MyMidiReceiver myReceiver = new MyMidiReceiver(maxSize);
+        assertEquals("MidiReceiver set size wrong.", maxSize,
+                myReceiver.getMaxMessageSize());
+
+        // Fill array with predictable data.
+        byte[] bar = new byte[200];
+        int offset = 0;
+        int count = bar.length;
+        myReceiver.flush(); // reset byte counter
+        IOException exception = null;
+        // Send too much data and intentionally cause an IOException.
+        try {
+            int sent = 0;
+            while (sent < LOCAL_STORAGE_SIZE) {
+                myReceiver.send(bar, offset, count);
+                sent += count;
+            }
+        } catch (IOException e) {
+            exception = e;
+        }
+        assertTrue("We should have caught an IOException", exception != null);
+    }
+
+    // Does the data we sent match the data received by the MidiReceiver?
+    private void checkReceivedData(MyMidiReceiver myReceiver, byte[] bar,
+            int offset, int count) throws IOException {
+        myReceiver.flush(); // reset byte counter
+        assertEquals("MidiReceiver flush ", 0, myReceiver.byteCount);
+        myReceiver.send(bar, offset, count);
+        // Did we get all the data
+        assertEquals("MidiReceiver count ", count, myReceiver.byteCount);
+        for (int i = 0; i < count; i++) {
+            assertEquals("MidiReceiver byte " + i + " + " + offset,
+                    bar[i + offset], myReceiver.data[i]);
+        }
+    }
+}