/*
 * Copyright (C) 2019 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.bluetooth.cts;

import static android.Manifest.permission.BLUETOOTH_CONNECT;

import static org.junit.Assert.assertThrows;

import android.app.UiAutomation;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;

import androidx.test.InstrumentationRegistry;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Unit test cases for {@link BluetoothHearingAid}.
 * <p>
 * To run the test, use adb shell am instrument -e class 'android.bluetooth.HearingAidProfileTest'
 * -w 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
 */
public class HearingAidProfileTest extends AndroidTestCase {
    private static final String TAG = "HearingAidProfileTest";

    private static final int WAIT_FOR_INTENT_TIMEOUT_MS = 10000; // ms to wait for intent callback
    private static final int PROXY_CONNECTION_TIMEOUT_MS = 500;  // ms timeout for Proxy Connect
    // ADAPTER_ENABLE_TIMEOUT_MS = AdapterState.BLE_START_TIMEOUT_DELAY +
    //                              AdapterState.BREDR_START_TIMEOUT_DELAY
    private static final int ADAPTER_ENABLE_TIMEOUT_MS = 8000;
    // ADAPTER_DISABLE_TIMEOUT_MS = AdapterState.BLE_STOP_TIMEOUT_DELAY +
    //                                  AdapterState.BREDR_STOP_TIMEOUT_DELAY
    private static final int ADAPTER_DISABLE_TIMEOUT_MS = 5000;

    private boolean mIsHearingAidSupported;
    private boolean mIsBleSupported;
    private BluetoothHearingAid mService;
    private BluetoothAdapter mBluetoothAdapter;
    private BroadcastReceiver mIntentReceiver;
    private UiAutomation mUiAutomation;;

    private Condition mConditionProfileIsConnected;
    private ReentrantLock mProfileConnectedlock;
    private boolean mIsProfileReady;

    private static List<Integer> mValidConnectionStates = new ArrayList<Integer>(
        Arrays.asList(BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED,
                      BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_DISCONNECTING));

    private List<BluetoothDevice> mIntentCallbackDeviceList;

    public void setUp() throws Exception {
        if (!isBleSupported()) return;
        mIsBleSupported = true;

        mIsHearingAidSupported = TestUtils.isProfileEnabled(BluetoothProfile.HEARING_AID);
        if (!mIsHearingAidSupported) return;

        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);

        BluetoothManager manager = (BluetoothManager) mContext.getSystemService(
                Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = manager.getAdapter();

        assertTrue(BTAdapterUtils.enableAdapter(mBluetoothAdapter, mContext));
        mProfileConnectedlock = new ReentrantLock();
        mConditionProfileIsConnected  = mProfileConnectedlock.newCondition();
        mIsProfileReady = false;
        mService = null;
        mBluetoothAdapter.getProfileProxy(getContext(), new HearingAidsServiceListener(),
                BluetoothProfile.HEARING_AID);
    }

    @Override
    public void tearDown() {
        if (!(mIsBleSupported && mIsHearingAidSupported)) {
            return;
        }
        if (mBluetoothAdapter != null) {
            assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
        }
        mUiAutomation.dropShellPermissionIdentity();
    }

    /**
     * Basic test case to make sure that Hearing Aid Profile Proxy can connect.
     */
    @MediumTest
    public void test_getProxyServiceConnect() {
        if (!(mIsBleSupported && mIsHearingAidSupported)) return;

        waitForProfileConnect();
        assertTrue(mIsProfileReady);
        assertNotNull(mService);
    }

    /**
     * Basic test case to make sure that a fictional device is disconnected.
     */
    @MediumTest
    public void test_getConnectionState() {
        if (!(mIsBleSupported && mIsHearingAidSupported)) {
            return;
        }

        waitForProfileConnect();
        assertTrue(mIsProfileReady);
        assertNotNull(mService);

        // Create a fake device
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
        assertNotNull(device);

        int connectionState = mService.getConnectionState(device);
        // Fake device should be disconnected
        assertEquals(connectionState, BluetoothProfile.STATE_DISCONNECTED);
    }

    /**
     * Basic test case to make sure that a fictional device throw a SecurityException when setting
     * volume.
     */
    @MediumTest
    public void test_setVolume() {
        if (!(mIsBleSupported && mIsHearingAidSupported)) {
            return;
        }

        waitForProfileConnect();
        assertTrue(mIsProfileReady);
        assertNotNull(mService);

        // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission
        assertThrows(SecurityException.class, () -> mService.setVolume(42));
    }


    /**
     * Basic test case to get the list of connected Hearing Aid devices.
     */
    @MediumTest
    public void test_getConnectedDevices() {
        if (!(mIsBleSupported && mIsHearingAidSupported)) {
            return;
        }

        waitForProfileConnect();
        assertTrue(mIsProfileReady);
        assertNotNull(mService);

        List<BluetoothDevice> deviceList;

        deviceList = mService.getConnectedDevices();
        Log.d(TAG, "getConnectedDevices(): size=" + deviceList.size());
        for (BluetoothDevice device : deviceList) {
            int connectionState = mService.getConnectionState(device);
            checkValidConnectionState(connectionState);
        }
    }

    /**
     * Basic test case to get the list of matching Hearing Aid devices for each of the 4 connection
     * states.
     */
    @MediumTest
    public void test_getDevicesMatchingConnectionStates() {
        if (!(mIsBleSupported && mIsHearingAidSupported)) {
            return;
        }

        waitForProfileConnect();
        assertTrue(mIsProfileReady);
        assertNotNull(mService);

        for (int connectionState : mValidConnectionStates) {
            List<BluetoothDevice> deviceList;

            deviceList = mService.getDevicesMatchingConnectionStates(new int[]{connectionState});
            assertNotNull(deviceList);
            Log.d(TAG, "getDevicesMatchingConnectionStates(" + connectionState + "): size="
                  + deviceList.size());
            checkDeviceListAndStates(deviceList, connectionState);
        }
    }

    /**
     * Test case to make sure that if the connection changed intent is called, the parameters and
     * device are correct.
     */
    @MediumTest
    public void test_getConnectionStateChangedIntent() {
        if (!(mIsBleSupported && mIsHearingAidSupported)) {
            return;
        }

        waitForProfileConnect();
        assertTrue(mIsProfileReady);
        assertNotNull(mService);

        // Find out how many Hearing Aid bonded devices
        List<BluetoothDevice> bondedDeviceList = new ArrayList();
        int numDevices = 0;
        for (int connectionState : mValidConnectionStates) {
            List<BluetoothDevice> deviceList;

            deviceList = mService.getDevicesMatchingConnectionStates(new int[]{connectionState});
            bondedDeviceList.addAll(deviceList);
            numDevices += deviceList.size();
        }

        if (numDevices <= 0) return;
        Log.d(TAG, "Number Hearing Aids devices bonded=" + numDevices);

        mIntentCallbackDeviceList = new ArrayList();

        // Set up the Connection State Changed receiver
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        mIntentReceiver = new HearingAidIntentReceiver();
        mContext.registerReceiver(mIntentReceiver, filter);

        Log.d(TAG, "test_getConnectionStateChangedIntent: disable adapter and wait");
        assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));

        Log.d(TAG, "test_getConnectionStateChangedIntent: enable adapter and wait");
        assertTrue(BTAdapterUtils.enableAdapter(mBluetoothAdapter, mContext));

        int sanityCount = WAIT_FOR_INTENT_TIMEOUT_MS;
        while ((numDevices != mIntentCallbackDeviceList.size()) && (sanityCount > 0)) {
            final int SLEEP_QUANTUM_MS = 100;
            sleep(SLEEP_QUANTUM_MS);
            sanityCount -= SLEEP_QUANTUM_MS;
        }

        // Tear down
        mContext.unregisterReceiver(mIntentReceiver);

        Log.d(TAG, "test_getConnectionStateChangedIntent: number of bonded device="
              + numDevices + ", mIntentCallbackDeviceList.size()="
              + mIntentCallbackDeviceList.size());
        for (BluetoothDevice device : mIntentCallbackDeviceList) {
            assertTrue(bondedDeviceList.contains(device));
        }
    }

    private boolean waitForProfileConnect() {
        mProfileConnectedlock.lock();
        try {
            // Wait for the Adapter to be disabled
            while (!mIsProfileReady) {
                if (!mConditionProfileIsConnected.await(
                    PROXY_CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
                    // Timeout
                    Log.e(TAG, "Timeout while waiting for Profile Connect");
                    break;
                } // else spurious wakeups
            }
        } catch(InterruptedException e) {
            Log.e(TAG, "waitForProfileConnect: interrrupted");
        } finally {
            mProfileConnectedlock.unlock();
        }
        return mIsProfileReady;
    }

    private final class HearingAidsServiceListener
            implements BluetoothProfile.ServiceListener {

        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            mProfileConnectedlock.lock();
            mService = (BluetoothHearingAid) proxy;
            mIsProfileReady = true;
            try {
                mConditionProfileIsConnected.signal();
            } finally {
                mProfileConnectedlock.unlock();
            }
        }

        public void onServiceDisconnected(int profile) {
            mProfileConnectedlock.lock();
            mIsProfileReady = false;
            mService = null;
            mProfileConnectedlock.unlock();
        }
    }

    private class HearingAidIntentReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
                int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
                int previousState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                Log.d(TAG,"HearingAidIntentReceiver.onReceive: device=" + device
                      + ", state=" + state + ", previousState=" + previousState);

                checkValidConnectionState(state);
                checkValidConnectionState(previousState);

                mIntentCallbackDeviceList.add(device);
            }
        }
    }

    private void checkDeviceListAndStates(List<BluetoothDevice> deviceList, int connectionState) {
        Log.d(TAG, "checkDeviceListAndStates(): size=" + deviceList.size()
              + ", connectionState=" + connectionState);
        for (BluetoothDevice device : deviceList) {
            int deviceConnectionState = mService.getConnectionState(device);
            assertEquals("Mismatched connection state for " + device,
                         connectionState, deviceConnectionState);
        }
    }

    private void checkValidConnectionState(int connectionState) {
        assertTrue(mValidConnectionStates.contains(connectionState));
    }

    // Returns whether offloaded scan batching is supported.
    private boolean isBleBatchScanSupported() {
        return mBluetoothAdapter.isOffloadedScanBatchingSupported();
    }

    // Check if Bluetooth LE feature is supported on DUT.
    private boolean isBleSupported() {
        return getContext().getPackageManager()
                .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
    }

    private static void sleep(long t) {
        try {
            Thread.sleep(t);
        } catch (InterruptedException e) {}
    }
}
