/*
 * 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 android.content.Context;
import android.content.pm.PackageManager;

import android.media.AudioAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioRouting;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.media.MediaFormat;
import android.media.MediaRecorder;

import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;

import android.platform.test.annotations.AppModeFull;
import android.test.AndroidTestCase;

import android.util.Log;

import com.android.compatibility.common.util.MediaUtils;

import java.io.File;
import java.lang.Runnable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * AudioTrack / AudioRecord / MediaPlayer / MediaRecorder preferred device
 * and routing listener tests.
 * The routing tests are mostly here to exercise the routing code, as an actual test would require
 * adding / removing an audio device for the listeners to be called.
 * The routing listener code is designed to run for two versions of the routing code:
 *  - the deprecated AudioTrack.OnRoutingChangedListener and AudioRecord.OnRoutingChangedListener
 *  - the N AudioRouting.OnRoutingChangedListener
 */
@AppModeFull(reason = "TODO: evaluate and port to instant")
public class RoutingTest extends AndroidTestCase {
    private static final String TAG = "RoutingTest";
    private static final int MAX_WAITING_ROUTING_CHANGED_COUNT = 3;
    private static final long WAIT_ROUTING_CHANGE_TIME_MS = 1000;
    private static final int AUDIO_BIT_RATE_IN_BPS = 12200;
    private static final int AUDIO_SAMPLE_RATE_HZ = 8000;
    private static final long MAX_FILE_SIZE_BYTE = 5000;
    private static final int RECORD_TIME_MS = 3000;
    private static final Set<Integer> AVAILABLE_INPUT_DEVICES_TYPE = new HashSet<>(
        Arrays.asList(AudioDeviceInfo.TYPE_BUILTIN_MIC));

    private boolean mRoutingChanged;
    private AudioManager mAudioManager;
    private CountDownLatch mRoutingChangedLatch;
    private File mOutFile;
    private Looper mRoutingChangedLooper;
    private Object mRoutingChangedLock = new Object();

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        // get the AudioManager
        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
        assertNotNull(mAudioManager);
    }

    @Override
    protected void tearDown() throws Exception {
        if (mOutFile != null && mOutFile.exists()) {
            mOutFile.delete();
        }
        super.tearDown();
    }

    private AudioTrack allocAudioTrack() {
        int bufferSize =
                AudioTrack.getMinBufferSize(
                    41000,
                    AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT);
        AudioTrack audioTrack =
            new AudioTrack(
                AudioManager.STREAM_MUSIC,
                41000,
                AudioFormat.CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT,
                bufferSize,
                AudioTrack.MODE_STREAM);
        return audioTrack;
    }

    public void test_audioTrack_preferredDevice() {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
            // Can't do it so skip this test
            return;
        }

        AudioTrack audioTrack = allocAudioTrack();
        assertNotNull(audioTrack);

        // None selected (new AudioTrack), so check for default
        assertNull(audioTrack.getPreferredDevice());

        // resets to default
        assertTrue(audioTrack.setPreferredDevice(null));

        // test each device
        AudioDeviceInfo[] deviceList = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
        for (int index = 0; index < deviceList.length; index++) {
            assertTrue(audioTrack.setPreferredDevice(deviceList[index]));
            assertTrue(audioTrack.getPreferredDevice() == deviceList[index]);
        }

        // Check defaults again
        assertTrue(audioTrack.setPreferredDevice(null));
        assertNull(audioTrack.getPreferredDevice());

        audioTrack.release();
    }

    public void test_audioTrack_incallMusicRoutingPermissions() {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
            // Can't do it so skip this test
            return;
        }

        // only apps with MODIFY_PHONE_STATE permission can route playback
        // to the uplink stream during a phone call, so this test makes sure that
        // audio is re-routed to default device when the permission is missing

        AudioDeviceInfo telephonyDevice = getTelephonyDeviceAndSetInCommunicationMode();
        if (telephonyDevice == null) {
            // Can't do it so skip this test
            return;
        }

        AudioTrack audioTrack = null;

        try {
            audioTrack = allocAudioTrack();
            assertNotNull(audioTrack);

            audioTrack.setPreferredDevice(telephonyDevice);
            assertEquals(AudioDeviceInfo.TYPE_TELEPHONY, audioTrack.getPreferredDevice().getType());

            audioTrack.play();
            assertTrue(audioTrack.getRoutedDevice().getType() != AudioDeviceInfo.TYPE_TELEPHONY);

        } finally {
            if (audioTrack != null) {
                audioTrack.stop();
                audioTrack.release();
            }
            mAudioManager.setMode(AudioManager.MODE_NORMAL);
        }
    }

    private AudioDeviceInfo getTelephonyDeviceAndSetInCommunicationMode() {
        // get the output device for telephony
        AudioDeviceInfo telephonyDevice = null;
        AudioDeviceInfo[] deviceList = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
        for (int index = 0; index < deviceList.length; index++) {
            if (deviceList[index].getType() == AudioDeviceInfo.TYPE_TELEPHONY) {
                telephonyDevice = deviceList[index];
            }
        }

        if (telephonyDevice == null) {
            return null;
        }

        // simulate an in call state using MODE_IN_COMMUNICATION since
        // AudioManager.setMode requires MODIFY_PHONE_STATE permission
        // for setMode with MODE_IN_CALL.
        mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
        assertEquals(AudioManager.MODE_IN_COMMUNICATION, mAudioManager.getMode());

        return telephonyDevice;
    }

    /*
     * tests if the Looper for the current thread has been prepared,
     * If not, it makes one, prepares it and returns it.
     * If this returns non-null, the caller is reponsible for calling quit()
     * on the returned Looper.
     */
    private Looper prepareIfNeededLooper() {
        // non-null Handler
        Looper myLooper = null;
        if (Looper.myLooper() == null) {
            Looper.prepare();
            myLooper = Looper.myLooper();
            assertNotNull(myLooper);
        }
        return myLooper;
    }

    private class AudioTrackRoutingListener implements AudioTrack.OnRoutingChangedListener,
            AudioRouting.OnRoutingChangedListener
    {
        public void onRoutingChanged(AudioTrack audioTrack) {}
        public void onRoutingChanged(AudioRouting audioRouting) {}
    }


    public void test_audioTrack_RoutingListener() {
        test_audioTrack_RoutingListener(false /*usesAudioRouting*/);
    }

    public void test_audioTrack_audioRouting_RoutingListener() {
        test_audioTrack_RoutingListener(true /*usesAudioRouting*/);
    }

    private void test_audioTrack_RoutingListener(boolean usesAudioRouting) {
        AudioTrack audioTrack = allocAudioTrack();

        // null listener
        if (usesAudioRouting) {
            audioTrack.addOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) null, null);
        } else {
            audioTrack.addOnRoutingChangedListener(
                    (AudioTrack.OnRoutingChangedListener) null, null);
        }

        AudioTrackRoutingListener listener = new AudioTrackRoutingListener();
        AudioTrackRoutingListener someOtherListener = new AudioTrackRoutingListener();

        // add a listener
        if (usesAudioRouting) {
            audioTrack.addOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) listener, null);
        } else {
            audioTrack.addOnRoutingChangedListener(listener, null);
        }

        // remove listeners
        if (usesAudioRouting) {
            // remove a listener we didn't add
            audioTrack.removeOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) someOtherListener);
            // remove a valid listener
            audioTrack.removeOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) listener);
        } else {
            // remove a listener we didn't add
            audioTrack.removeOnRoutingChangedListener(
                    (AudioTrack.OnRoutingChangedListener) someOtherListener);
            // remove a valid listener
            audioTrack.removeOnRoutingChangedListener(
                    (AudioTrack.OnRoutingChangedListener) listener);
        }

        Looper myLooper = prepareIfNeededLooper();

        if (usesAudioRouting) {
            audioTrack.addOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) listener, new Handler());
            audioTrack.removeOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) listener);
        } else {
            audioTrack.addOnRoutingChangedListener(
                    (AudioTrack.OnRoutingChangedListener) listener, new Handler());
            audioTrack.removeOnRoutingChangedListener(
                    (AudioTrack.OnRoutingChangedListener) listener);
        }

        audioTrack.release();
        if (myLooper != null) {
            myLooper.quit();
        }
   }

    private AudioRecord allocAudioRecord() {
        int bufferSize =
                AudioRecord.getMinBufferSize(
                    41000,
                    AudioFormat.CHANNEL_OUT_DEFAULT,
                    AudioFormat.ENCODING_PCM_16BIT);
        AudioRecord audioRecord =
            new AudioRecord(
                MediaRecorder.AudioSource.DEFAULT,
                41000, AudioFormat.CHANNEL_OUT_DEFAULT,
                AudioFormat.ENCODING_PCM_16BIT,
                bufferSize);
        return audioRecord;
    }

    private class AudioRecordRoutingListener implements AudioRecord.OnRoutingChangedListener,
            AudioRouting.OnRoutingChangedListener
    {
        public void onRoutingChanged(AudioRecord audioRecord) {}
        public void onRoutingChanged(AudioRouting audioRouting) {}
    }

    public void test_audioRecord_RoutingListener() {
        test_audioRecord_RoutingListener(false /*usesAudioRouting*/);
    }

    public void test_audioRecord_audioRouting_RoutingListener() {
        test_audioRecord_RoutingListener(true /*usesAudioRouting*/);
    }

    private void test_audioRecord_RoutingListener(boolean usesAudioRouting) {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
            // Can't do it so skip this test
            return;
        }
        AudioRecord audioRecord = allocAudioRecord();

        // null listener
        if (usesAudioRouting) {
            audioRecord.addOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) null, null);
        } else {
            audioRecord.addOnRoutingChangedListener(
                    (AudioRecord.OnRoutingChangedListener) null, null);
        }

        AudioRecordRoutingListener listener = new AudioRecordRoutingListener();
        AudioRecordRoutingListener someOtherListener = new AudioRecordRoutingListener();

        // add a listener
        if (usesAudioRouting) {
            audioRecord.addOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) listener, null);
        } else {
            audioRecord.addOnRoutingChangedListener(
                    (AudioRecord.OnRoutingChangedListener) listener, null);
        }

        // remove listeners
        if (usesAudioRouting) {
            // remove a listener we didn't add
            audioRecord.removeOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) someOtherListener);
            // remove a valid listener
            audioRecord.removeOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) listener);
        } else {
            // remove a listener we didn't add
            audioRecord.removeOnRoutingChangedListener(
                    (AudioRecord.OnRoutingChangedListener) someOtherListener);
            // remove a valid listener
            audioRecord.removeOnRoutingChangedListener(
                    (AudioRecord.OnRoutingChangedListener) listener);
        }

        Looper myLooper = prepareIfNeededLooper();
        if (usesAudioRouting) {
            audioRecord.addOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) listener, new Handler());
            audioRecord.removeOnRoutingChangedListener(
                    (AudioRouting.OnRoutingChangedListener) listener);
        } else {
            audioRecord.addOnRoutingChangedListener(
                    (AudioRecord.OnRoutingChangedListener) listener, new Handler());
            audioRecord.removeOnRoutingChangedListener(
                    (AudioRecord.OnRoutingChangedListener) listener);
        }

        audioRecord.release();
        if (myLooper != null) {
            myLooper.quit();
        }
    }

    public void test_audioRecord_preferredDevice() {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
            // Can't do it so skip this test
            return;
        }

        AudioRecord audioRecord = allocAudioRecord();
        assertNotNull(audioRecord);

        // None selected (new AudioRecord), so check for default
        assertNull(audioRecord.getPreferredDevice());

        // resets to default
        assertTrue(audioRecord.setPreferredDevice(null));

        // test each device
        AudioDeviceInfo[] deviceList = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
        for (int index = 0; index < deviceList.length; index++) {
            assertTrue(audioRecord.setPreferredDevice(deviceList[index]));
            assertTrue(audioRecord.getPreferredDevice() == deviceList[index]);
        }

        // Check defaults again
        assertTrue(audioRecord.setPreferredDevice(null));
        assertNull(audioRecord.getPreferredDevice());

        audioRecord.release();
    }

    private class AudioTrackFiller implements Runnable {
        AudioTrack mAudioTrack;
        int mBufferSize;

        boolean mPlaying;

        short[] mAudioData;

        public AudioTrackFiller(AudioTrack audioTrack, int bufferSize) {
            mAudioTrack = audioTrack;
            mBufferSize = bufferSize;
            mPlaying = false;

            // setup audio data (silence will suffice)
            mAudioData = new short[mBufferSize];
            for (int index = 0; index < mBufferSize; index++) {
                mAudioData[index] = 0;
            }
        }

        public void start() { mPlaying = true; }
        public void stop() { mPlaying = false; }

        @Override
        public void run() {
            while (mAudioTrack != null && mPlaying) {
                mAudioTrack.write(mAudioData, 0, mBufferSize);
            }
        }
    }

    public void test_audioTrack_getRoutedDevice() {
        if (!DeviceUtils.hasOutputDevice(mAudioManager)) {
            Log.i(TAG, "No output devices. Test skipped");
            return; // nothing to test here
        }

        int bufferSize =
                AudioTrack.getMinBufferSize(
                    41000,
                    AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT);
        AudioTrack audioTrack =
            new AudioTrack(
                AudioManager.STREAM_MUSIC,
                41000,
                AudioFormat.CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT,
                bufferSize,
                AudioTrack.MODE_STREAM);

        AudioTrackFiller filler = new AudioTrackFiller(audioTrack, bufferSize);
        filler.start();

        audioTrack.play();

        Thread fillerThread = new Thread(filler);
        fillerThread.start();

        try { Thread.sleep(1000); } catch (InterruptedException ex) {}

        // No explicit route
        AudioDeviceInfo routedDevice = audioTrack.getRoutedDevice();
        assertNotNull(routedDevice); // we probably can't say anything more than this

        filler.stop();
        audioTrack.stop();
        audioTrack.release();
    }

    private class AudioRecordPuller implements Runnable {
        AudioRecord mAudioRecord;
        int mBufferSize;

        boolean mRecording;

        short[] mAudioData;

        public AudioRecordPuller(AudioRecord audioRecord, int bufferSize) {
            mAudioRecord = audioRecord;
            mBufferSize = bufferSize;
            mRecording = false;
        }

        public void start() { mRecording = true; }
        public void stop() { mRecording = false; }

        @Override
        public void run() {
            while (mAudioRecord != null && mRecording) {
                mAudioRecord.read(mAudioData, 0, mBufferSize);
           }
        }
    }

    public void test_audioRecord_getRoutedDevice() {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
            return;
        }

        if (!DeviceUtils.hasInputDevice(mAudioManager)) {
            Log.i(TAG, "No input devices. Test skipped");
            return; // nothing to test here
        }

        int bufferSize =
                AudioRecord.getMinBufferSize(
                    41000,
                    AudioFormat.CHANNEL_OUT_DEFAULT,
                    AudioFormat.ENCODING_PCM_16BIT);
        AudioRecord audioRecord =
            new AudioRecord(
                MediaRecorder.AudioSource.DEFAULT,
                41000, AudioFormat.CHANNEL_OUT_DEFAULT,
                AudioFormat.ENCODING_PCM_16BIT,
                bufferSize);

        AudioRecordPuller puller = new AudioRecordPuller(audioRecord, bufferSize);
        puller.start();

        audioRecord.startRecording();

        Thread pullerThread = new Thread(puller);
        pullerThread.start();

        try { Thread.sleep(1000); } catch (InterruptedException ex) {}

        // No explicit route
        AudioDeviceInfo routedDevice = audioRecord.getRoutedDevice();
        assertNotNull(routedDevice); // we probably can't say anything more than this

        puller.stop();
        audioRecord.stop();
        audioRecord.release();
    }

    private class AudioRoutingListener implements AudioRouting.OnRoutingChangedListener
    {
        public void onRoutingChanged(AudioRouting audioRouting) {
            if (mRoutingChangedLatch != null) {
                mRoutingChangedLatch.countDown();
            }
            synchronized (mRoutingChangedLock) {
                mRoutingChanged = true;
                mRoutingChangedLock.notify();
            }
        }
    }

    private MediaPlayer allocMediaPlayer() {
        final int resid = R.raw.testmp3_2;
        MediaPlayer mediaPlayer = MediaPlayer.create(mContext, resid);
        mediaPlayer.setAudioAttributes(
                new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build());
        mediaPlayer.start();
        return mediaPlayer;
    }

    public void test_mediaPlayer_preferredDevice() {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
            // Can't do it so skip this test
            return;
        }

        MediaPlayer mediaPlayer = allocMediaPlayer();
        assertTrue(mediaPlayer.isPlaying());

        // None selected (new MediaPlayer), so check for default
        assertNull(mediaPlayer.getPreferredDevice());

        // resets to default
        assertTrue(mediaPlayer.setPreferredDevice(null));

        // test each device
        AudioDeviceInfo[] deviceList = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
        for (int index = 0; index < deviceList.length; index++) {
            assertTrue(mediaPlayer.setPreferredDevice(deviceList[index]));
            assertTrue(mediaPlayer.getPreferredDevice() == deviceList[index]);
        }

        // Check defaults again
        assertTrue(mediaPlayer.setPreferredDevice(null));
        assertNull(mediaPlayer.getPreferredDevice());

        mediaPlayer.stop();
        mediaPlayer.release();
    }

    public void test_mediaPlayer_getRoutedDevice() {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
            // Can't do it so skip this test
            return;
        }

        MediaPlayer mediaPlayer = allocMediaPlayer();
        assertTrue(mediaPlayer.isPlaying());

        // Sleep for 1s to ensure the output device open
        SystemClock.sleep(1000);

        // No explicit route
        AudioDeviceInfo routedDevice = mediaPlayer.getRoutedDevice();
        assertNotNull(routedDevice);

        mediaPlayer.stop();
        mediaPlayer.release();
    }

    public void test_MediaPlayer_RoutingListener() {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
            // Can't do it so skip this test
            return;
        }

        MediaPlayer mediaPlayer = allocMediaPlayer();

        // null listener
        mediaPlayer.addOnRoutingChangedListener(null, null);

        AudioRoutingListener listener = new AudioRoutingListener();
        AudioRoutingListener someOtherListener = new AudioRoutingListener();

        // add a listener
        mediaPlayer.addOnRoutingChangedListener(listener, null);

        // remove listeners
        // remove a listener we didn't add
        mediaPlayer.removeOnRoutingChangedListener(someOtherListener);
        // remove a valid listener
        mediaPlayer.removeOnRoutingChangedListener(listener);

        Looper myLooper = prepareIfNeededLooper();

        mediaPlayer.addOnRoutingChangedListener(listener, new Handler());
        mediaPlayer.removeOnRoutingChangedListener(listener);

        mediaPlayer.stop();
        mediaPlayer.release();
        if (myLooper != null) {
            myLooper.quit();
        }
    }

    public void test_MediaPlayer_RoutingChangedCallback() throws Exception {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
            // Can't do it so skip this test
            return;
        }

        AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
        if (devices.length < 2) {
            // In this case, we cannot switch output device, that may cause the test fail.
            return;
        }

        mRoutingChanged = false;
        mRoutingChangedLooper = null;
        // Create MediaPlayer in another thread to make sure there is a looper active for events.
        Thread t = new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                // Keep looper to terminate when the test is finished.
                mRoutingChangedLooper = Looper.myLooper();
                AudioRoutingListener listener = new AudioRoutingListener();
                MediaPlayer mediaPlayer = allocMediaPlayer();
                mediaPlayer.addOnRoutingChangedListener(listener, null);
                // With setting preferred device, the output device may switch.
                // Post the request delayed to ensure the message queue is running
                // so that the routing changed event can be handled correctly.
                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        AudioDeviceInfo routedDevice = mediaPlayer.getRoutedDevice();
                        if (routedDevice == null) {
                            return;
                        }
                        AudioDeviceInfo[] devices = mAudioManager.getDevices(
                                AudioManager.GET_DEVICES_OUTPUTS);
                        for (AudioDeviceInfo device : devices) {
                            if (routedDevice.getId() != device.getId()) {
                                mediaPlayer.setPreferredDevice(device);
                                break;
                            }
                        }
                    }
                }, 1000);
                Looper.loop();
                mediaPlayer.removeOnRoutingChangedListener(listener);
                mediaPlayer.stop();
                mediaPlayer.release();
            }
        };
        t.start();
        synchronized (mRoutingChangedLock) {
            mRoutingChangedLock.wait(WAIT_ROUTING_CHANGE_TIME_MS
                    * MAX_WAITING_ROUTING_CHANGED_COUNT);
        }
        if (mRoutingChangedLooper != null) {
            mRoutingChangedLooper.quitSafely();
            mRoutingChangedLooper = null;
        }
        t.join();
        assertTrue("Routing changed callback has not been called", mRoutingChanged);
    }

    public void test_mediaPlayer_incallMusicRoutingPermissions() {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
            // Can't do it so skip this test
            return;
        }

        // only apps with MODIFY_PHONE_STATE permission can route playback
        // to the uplink stream during a phone call, so this test makes sure that
        // audio is re-routed to default device when the permission is missing

        AudioDeviceInfo telephonyDevice = getTelephonyDeviceAndSetInCommunicationMode();
        if (telephonyDevice == null) {
            // Can't do it so skip this test
            return;
        }

        MediaPlayer mediaPlayer = null;

        try {
            mediaPlayer = allocMediaPlayer();

            mediaPlayer.setPreferredDevice(telephonyDevice);
            assertEquals(AudioDeviceInfo.TYPE_TELEPHONY, mediaPlayer.getPreferredDevice().getType());

            // Sleep for 1s to ensure the output device open
            SystemClock.sleep(1000);
            assertTrue(mediaPlayer.getRoutedDevice().getType() != AudioDeviceInfo.TYPE_TELEPHONY);

        } finally {
            if (mediaPlayer != null) {
                mediaPlayer.stop();
                mediaPlayer.release();
            }
            mAudioManager.setMode(AudioManager.MODE_NORMAL);
        }
    }

    private MediaRecorder allocMediaRecorder() throws Exception {
        final String outputPath = new File(Environment.getExternalStorageDirectory(),
            "record.out").getAbsolutePath();
        mOutFile = new File(outputPath);
        MediaRecorder mediaRecorder = new MediaRecorder();
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        assertEquals(0, mediaRecorder.getMaxAmplitude());
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mediaRecorder.setOutputFile(outputPath);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mediaRecorder.setAudioChannels(AudioFormat.CHANNEL_OUT_DEFAULT);
        mediaRecorder.setAudioSamplingRate(AUDIO_SAMPLE_RATE_HZ);
        mediaRecorder.setAudioEncodingBitRate(AUDIO_BIT_RATE_IN_BPS);
        mediaRecorder.setMaxFileSize(MAX_FILE_SIZE_BYTE);
        mediaRecorder.prepare();
        mediaRecorder.start();
        // Sleep a while to ensure the underlying AudioRecord is initialized.
        Thread.sleep(1000);
        return mediaRecorder;
    }

    public void test_mediaRecorder_preferredDevice() throws Exception {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE)
                || !MediaUtils.hasEncoder(MediaFormat.MIMETYPE_AUDIO_AAC)) {
            MediaUtils.skipTest("no audio codecs or microphone");
            return;
        }

        MediaRecorder mediaRecorder = allocMediaRecorder();

        // None selected (new MediaPlayer), so check for default
        assertNull(mediaRecorder.getPreferredDevice());

        // resets to default
        assertTrue(mediaRecorder.setPreferredDevice(null));

        // test each device
        AudioDeviceInfo[] deviceList = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
        for (int index = 0; index < deviceList.length; index++) {
            if (!AVAILABLE_INPUT_DEVICES_TYPE.contains(deviceList[index].getType())) {
                // Only try to set devices whose type is contained in predefined set as preferred
                // device in case of permission denied when switching input device.
                continue;
            }
            assertTrue(mediaRecorder.setPreferredDevice(deviceList[index]));
            assertTrue(mediaRecorder.getPreferredDevice() == deviceList[index]);
        }

        // Check defaults again
        assertTrue(mediaRecorder.setPreferredDevice(null));
        assertNull(mediaRecorder.getPreferredDevice());
        Thread.sleep(RECORD_TIME_MS);

        mediaRecorder.stop();
        mediaRecorder.release();
    }

    public void test_mediaRecorder_getRoutedDeviceId() throws Exception {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE)
            || !MediaUtils.hasEncoder(MediaFormat.MIMETYPE_AUDIO_AAC)) {
            MediaUtils.skipTest("no audio codecs or microphone");
            return;
        }

        MediaRecorder mediaRecorder = allocMediaRecorder();

        AudioDeviceInfo routedDevice = mediaRecorder.getRoutedDevice();
        assertNotNull(routedDevice); // we probably can't say anything more than this
        Thread.sleep(RECORD_TIME_MS);

        mediaRecorder.stop();
        mediaRecorder.release();
    }

    public void test_mediaRecorder_RoutingListener() throws Exception {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE)
            || !MediaUtils.hasEncoder(MediaFormat.MIMETYPE_AUDIO_AAC)) {
            MediaUtils.skipTest("no audio codecs or microphone");
            return;
        }

        MediaRecorder mediaRecorder = allocMediaRecorder();

        // null listener
        mediaRecorder.addOnRoutingChangedListener(null, null);

        AudioRoutingListener listener = new AudioRoutingListener();
        AudioRoutingListener someOtherListener = new AudioRoutingListener();

        // add a listener
        mediaRecorder.addOnRoutingChangedListener(listener, null);

        // remove listeners we didn't add
        mediaRecorder.removeOnRoutingChangedListener(someOtherListener);
        // remove a valid listener
        mediaRecorder.removeOnRoutingChangedListener(listener);

        Looper myLooper = prepareIfNeededLooper();
        mediaRecorder.addOnRoutingChangedListener(listener, new Handler());
        mediaRecorder.removeOnRoutingChangedListener(listener);

        Thread.sleep(RECORD_TIME_MS);

        mediaRecorder.stop();
        mediaRecorder.release();
        if (myLooper != null) {
            myLooper.quit();
        }
    }
}
