Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f60b5e4 authored by Md Shahriar Hossain Sajib's avatar Md Shahriar Hossain Sajib Committed by Automerger Merge Worker
Browse files

Merge "Bluetooth Audio Policy APIs and HFP support integration" am: 21d1538f

parents 9a07156b 21d1538f
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -880,6 +880,37 @@ static jboolean sendATCmdNative(JNIEnv* env, jobject object, jbyteArray address,
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static jboolean sendAndroidAtNative(JNIEnv* env, jobject object,
                                    jbyteArray address, jstring arg_str) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
  if (!addr) {
    jniThrowIOException(env, EINVAL);
    return JNI_FALSE;
  }

  const char* arg = NULL;
  if (arg_str != NULL) {
    arg = env->GetStringUTFChars(arg_str, NULL);
  }

  bt_status_t status = sBluetoothHfpClientInterface->send_android_at(
      (const RawAddress*)addr, arg);

  if (status != BT_STATUS_SUCCESS) {
    ALOGE("FAILED to control volume, status: %d", status);
  }

  if (arg != NULL) {
    env->ReleaseStringUTFChars(arg_str, arg);
  }

  env->ReleaseByteArrayElements(address, addr, 0);
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static JNINativeMethod sMethods[] = {
    {"classInitNative", "()V", (void*)classInitNative},
    {"initializeNative", "()V", (void*)initializeNative},
@@ -904,6 +935,8 @@ static JNINativeMethod sMethods[] = {
    {"requestLastVoiceTagNumberNative", "([B)Z",
     (void*)requestLastVoiceTagNumberNative},
    {"sendATCmdNative", "([BIIILjava/lang/String;)Z", (void*)sendATCmdNative},
    {"sendAndroidAtNative", "([BLjava/lang/String;)Z",
     (void*)sendAndroidAtNative},
};

int register_com_android_bluetooth_hfpclient(JNIEnv* env) {
+8 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHeadset;
@@ -689,11 +690,15 @@ class ActiveDeviceManager {
        if (headsetService == null) {
            return;
        }
        BluetoothAudioPolicy audioPolicy = headsetService.getHfpCallAudioPolicy(device);
        if (audioPolicy == null || audioPolicy.getConnectingTimePolicy()
                != BluetoothAudioPolicy.POLICY_NOT_ALLOWED) {
            if (!headsetService.setActiveDevice(device)) {
                return;
            }
            mHfpActiveDevice = device;
        }
    }

    private void setHearingAidActiveDevice(BluetoothDevice device) {
        if (DBG) {
+130 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.bluetooth.BluetoothActivityEnergyInfo;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter.ActiveDeviceProfile;
import android.bluetooth.BluetoothAdapter.ActiveDeviceUse;
import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothFrameworkInitializer;
@@ -3792,6 +3793,73 @@ public class AdapterService extends Service {
            return service.mDatabaseManager.getCustomMeta(device, key);
        }

        @Override
        public void getAudioPolicyRemoteSupported(BluetoothDevice device,
                AttributionSource source, SynchronousResultReceiver receiver) {
            try {
                receiver.send(getAudioPolicyRemoteSupported(device, source));
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }
        private int getAudioPolicyRemoteSupported(BluetoothDevice device,
                AttributionSource source) {
            AdapterService service = getService();
            if (service == null
                    || !callerIsSystemOrActiveOrManagedUser(service, TAG,
                        "getAudioPolicyRemoteSupported")
                    || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) {
                return BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE;
            }
            enforceBluetoothPrivilegedPermission(service);
            return service.getAudioPolicyRemoteSupported(device);
        }

        @Override
        public void setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies,
                AttributionSource source, SynchronousResultReceiver receiver) {
            try {
                receiver.send(setAudioPolicy(device, policies, source));
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }
        private int setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies,
                AttributionSource source) {
            AdapterService service = getService();
            if (service == null) {
                return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
            } else if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "setAudioPolicy")) {
                return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED;
            } else if (!Utils.checkConnectPermissionForDataDelivery(
                    service, source, TAG)) {
                return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
            }
            enforceBluetoothPrivilegedPermission(service);
            return service.setAudioPolicy(device, policies);
        }

        @Override
        public void getAudioPolicy(BluetoothDevice device,
                AttributionSource source, SynchronousResultReceiver receiver) {
            try {
                receiver.send(getAudioPolicy(device, source));
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }
        private BluetoothAudioPolicy getAudioPolicy(BluetoothDevice device,
                AttributionSource source) {
            AdapterService service = getService();
            if (service == null
                    || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getAudioPolicy")
                    || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) {
                return null;
            }
            enforceBluetoothPrivilegedPermission(service);
            return service.getAudioPolicy(device);
        }

        @Override
        public void requestActivityInfo(IBluetoothActivityEnergyInfoListener listener,
                    AttributionSource source) {
@@ -5648,6 +5716,68 @@ public class AdapterService extends Service {
        return getMetricIdNative(Utils.getByteAddress(device));
    }

    /**
     * Get audio policy feature support status
     *
     * @param device Bluetooth device to be checked for audio policy support
     * @return int status of the remote support for audio policy feature
     */
    public int getAudioPolicyRemoteSupported(BluetoothDevice device) {
        if (mHeadsetClientService != null) {
            return mHeadsetClientService.getAudioPolicyRemoteSupported(device);
        } else {
            Log.e(TAG, "No audio transport connected");
            return BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE;
        }
    }

    /**
     * Set audio policy for remote device
     *
     * @param device Bluetooth device to be set policy for
     * @return int result status for setAudioPolicy API
     */
    public int setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies) {
        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
        if (deviceProp == null) {
            return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED;
        }

        if (mHeadsetClientService != null) {
            if (getAudioPolicyRemoteSupported(device)
                    != BluetoothAudioPolicy.FEATURE_SUPPORTED_BY_REMOTE) {
                Log.w(TAG, "Audio Policy feature not supported by AG");
                return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
            }
            deviceProp.setHfAudioPolicyForRemoteAg(policies);
            mHeadsetClientService.setAudioPolicy(device, policies);
            return BluetoothStatusCodes.SUCCESS;
        } else {
            Log.e(TAG, "HeadsetClient not connected");
            return BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED;
        }
    }

    /**
     * Get audio policy for remote device
     *
     * @param device Bluetooth device to be set policy for
     * @return {@link BluetoothAudioPolicy} policy stored for the device
     */
    public BluetoothAudioPolicy getAudioPolicy(BluetoothDevice device) {
        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
        if (deviceProp == null) {
            return null;
        }

        if (mHeadsetClientService != null) {
            return deviceProp.getHfAudioPolicyForRemoteAg();
        } else {
            Log.e(TAG, "HeadsetClient not connected");
            return null;
        }
    }

    /**
     *  Allow audio low latency
     *
+10 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.RequiresPermission;
import android.app.admin.SecurityLog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAssignedNumbers;
import android.bluetooth.BluetoothAudioPolicy;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
@@ -314,6 +315,7 @@ final class RemoteDevices {
        @VisibleForTesting int mBondState;
        @VisibleForTesting int mDeviceType;
        @VisibleForTesting ParcelUuid[] mUuids;
        private BluetoothAudioPolicy mAudioPolicy;

        DeviceProperties() {
            mBondState = BluetoothDevice.BOND_NONE;
@@ -595,6 +597,14 @@ final class RemoteDevices {
                this.mIsCoordinatedSetMember = isCoordinatedSetMember;
            }
        }

        public void setHfAudioPolicyForRemoteAg(BluetoothAudioPolicy policies) {
            mAudioPolicy = policies;
        }

        public BluetoothAudioPolicy getHfAudioPolicyForRemoteAg() {
            return mAudioPolicy;
        }
    }

    private void sendUuidIntent(BluetoothDevice device, DeviceProperties prop) {
+61 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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 com.android.bluetooth.btservice.storage;

import android.bluetooth.BluetoothAudioPolicy;

import androidx.room.ColumnInfo;
import androidx.room.Entity;

@Entity
class AudioPolicyEntity {
    @ColumnInfo(name = "call_establish_audio_policy")
    public int callEstablishAudioPolicy;
    @ColumnInfo(name = "connecting_time_audio_policy")
    public int connectingTimeAudioPolicy;
    @ColumnInfo(name = "in_band_ringtone_audio_policy")
    public int inBandRingtoneAudioPolicy;

    AudioPolicyEntity() {
        callEstablishAudioPolicy = BluetoothAudioPolicy.POLICY_UNCONFIGURED;
        connectingTimeAudioPolicy = BluetoothAudioPolicy.POLICY_UNCONFIGURED;
        inBandRingtoneAudioPolicy = BluetoothAudioPolicy.POLICY_UNCONFIGURED;
    }

    AudioPolicyEntity(int callEstablishAudioPolicy, int connectingTimeAudioPolicy,
            int inBandRingtoneAudioPolicy) {
        this.callEstablishAudioPolicy = callEstablishAudioPolicy;
        this.connectingTimeAudioPolicy = connectingTimeAudioPolicy;
        this.inBandRingtoneAudioPolicy = inBandRingtoneAudioPolicy;
    }

    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("callEstablishAudioPolicy=")
                .append(metadataToString(callEstablishAudioPolicy))
                .append("|connectingTimeAudioPolicy=")
                .append(metadataToString(connectingTimeAudioPolicy))
                .append("|inBandRingtoneAudioPolicy=")
                .append(metadataToString(inBandRingtoneAudioPolicy));

        return builder.toString();
    }

    private String metadataToString(int metadata) {
        return String.valueOf(metadata);
    }
}
Loading