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

Commit a837864c authored by David Duarte's avatar David Duarte Committed by Android (Google) Code Review
Browse files

Merge changes from topics "6326381a-82a5-49b2-96a2-6f2e6ae4f7a1",...

Merge changes from topics "6326381a-82a5-49b2-96a2-6f2e6ae4f7a1", "cherrypicker-L53000000958338808:N07100001331979735" into tm-qpr-dev

* changes:
  tbs: Re-register for notifications from cache
  mcs: Re-register for notifications from cache
  Extend Metadata Database with GMCS, GTBS CCC data
  Add missing migration 115_116 to database builder
  Add APIs to set and get the preferred audio mode
  Bluetooth Audio Policy APIs and HFP support integration
parents 5fd663e3 028a300c
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -879,6 +879,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},
@@ -903,6 +934,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;
@@ -3669,6 +3670,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) {
@@ -5508,6 +5576,68 @@ public class AdapterService extends Service {
        }
    }

    /**
     * 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
@@ -22,6 +22,7 @@ import static android.Manifest.permission.BLUETOOTH_SCAN;
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;
@@ -312,6 +313,7 @@ final class RemoteDevices {
        @VisibleForTesting int mBondState;
        @VisibleForTesting int mDeviceType;
        @VisibleForTesting ParcelUuid[] mUuids;
        private BluetoothAudioPolicy mAudioPolicy;

        DeviceProperties() {
            mBondState = BluetoothDevice.BOND_NONE;
@@ -499,6 +501,14 @@ final class RemoteDevices {
                return mIsCoordinatedSetMember;
            }
        }

        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