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

Commit 57679d53 authored by William Escande's avatar William Escande
Browse files

VCP: Split nativeInterface from nativeCallback

One is going down to the native, the other from. This allow to have a
couple final method in the nativeCallback and remove the need for null
pointer check (by design)
Similar as HAP implementation
https://r.android.com/2953314 -> direct use of native interface
https://r.android.com/3199943 -> callback split

Bug: 311772251
Bug: 361263965
Test: atest BluetoothInstrumentationTests
Test: atest VolumeControlNativeCallbackTest
Flag: com.android.bluetooth.flags.leaudio_add_aics_support
Change-Id: Ia167c8db9f5de5f9dd6508abde1bf9b8e4b0cbb8
parent 3db6da76
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -165,6 +165,7 @@ java_defaults {
            "-Xep:UnusedMethod:ERROR",
            "-Xep:UnusedNestedClass:ERROR",
            "-Xep:UnusedVariable:ERROR",
            "-Xep:VariableNameSameAsType:ERROR",
            "-Xep:WaitNotInLoop:ERROR",
            "-Xep:WakelockReleasedDangerously:ERROR",

@@ -172,8 +173,8 @@ java_defaults {
            "-XepExcludedPaths:.*/srcjars/.*",

            // The @InlineMe annotation could be made available, but it would
            // apply on external facing API. This is not desired. For more
            // context, see https://r.android.com/3303475
            // apply on external facing API. This is not desired.
            // For more context, see https://r.android.com/3303475
            "-Xep:InlineMeSuggester:OFF",
        ],
    },
+11 −2
Original line number Diff line number Diff line
@@ -62,6 +62,8 @@ static std::shared_timed_mutex interface_mutex;
static jobject mCallbacksObj = nullptr;
static std::shared_timed_mutex callbacks_mutex;

static jfieldID sCallbacksField;

class VolumeControlCallbacksImpl : public VolumeControlCallbacks {
public:
  ~VolumeControlCallbacksImpl() = default;
@@ -362,7 +364,8 @@ static void initNative(JNIEnv* env, jobject object) {
    mCallbacksObj = nullptr;
  }

  if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
  if ((mCallbacksObj = env->NewGlobalRef(env->GetObjectField(object, sCallbacksField))) ==
      nullptr) {
    log::error("Failed to allocate Global Ref for Volume control Callbacks");
    return;
  }
@@ -888,6 +891,12 @@ int register_com_android_bluetooth_vc(JNIEnv* env) {
    return result;
  }

  jclass jniVolumeControlNativeInterfaceClass =
          env->FindClass("com/android/bluetooth/vc/VolumeControlNativeInterface");
  sCallbacksField = env->GetFieldID(jniVolumeControlNativeInterfaceClass, "mNativeCallback",
                                    "Lcom/android/bluetooth/vc/VolumeControlNativeCallback;");
  env->DeleteLocalRef(jniVolumeControlNativeInterfaceClass);

  const JNIJavaMethod javaMethods[] = {
          {"onConnectionStateChanged", "(I[B)V", &method_onConnectionStateChanged},
          {"onVolumeStateChanged", "(IZI[BZ)V", &method_onVolumeStateChanged},
@@ -904,7 +913,7 @@ int register_com_android_bluetooth_vc(JNIEnv* env) {
          {"onExtAudioInDescriptionChanged", "(ILjava/lang/String;[B)V",
           &method_onExtAudioInDescriptionChanged},
  };
  GET_JAVA_METHODS(env, "com/android/bluetooth/vc/VolumeControlNativeInterface", javaMethods);
  GET_JAVA_METHODS(env, "com/android/bluetooth/vc/VolumeControlNativeCallback", javaMethods);

  return 0;
}
+208 −0
Original line number Diff line number Diff line
/*
 * Copyright 2024 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.vc;

import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED;
import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_DEVICE_AVAILABLE;
import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_EXT_AUDIO_IN_DESCR_CHANGED;
import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_EXT_AUDIO_IN_GAIN_PROPS_CHANGED;
import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_EXT_AUDIO_IN_STATE_CHANGED;
import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_EXT_AUDIO_IN_STATUS_CHANGED;
import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_EXT_AUDIO_IN_TYPE_CHANGED;
import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_EXT_AUDIO_OUT_DESCRIPTION_CHANGED;
import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_EXT_AUDIO_OUT_LOCATION_CHANGED;
import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_EXT_AUDIO_OUT_VOL_OFFSET_CHANGED;
import static com.android.bluetooth.vc.VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED;

import static java.util.Objects.requireNonNull;

import android.bluetooth.BluetoothDevice;
import android.util.Log;

import com.android.bluetooth.btservice.AdapterService;
import com.android.internal.annotations.VisibleForTesting;

class VolumeControlNativeCallback {
    private static final String TAG = VolumeControlNativeCallback.class.getSimpleName();

    private final AdapterService mAdapterService;
    private final VolumeControlService mVolumeControlService;

    VolumeControlNativeCallback(
            AdapterService adapterService, VolumeControlService volumeControlService) {
        mAdapterService = requireNonNull(adapterService);
        mVolumeControlService = requireNonNull(volumeControlService);
    }

    private BluetoothDevice getDevice(byte[] address) {
        return mAdapterService.getDeviceFromByte(address);
    }

    @VisibleForTesting
    void onConnectionStateChanged(int state, byte[] address) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_CONNECTION_STATE_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = state;

        Log.d(TAG, "onConnectionStateChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onVolumeStateChanged(
            int volume, boolean mute, int flags, byte[] address, boolean isAutonomous) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_VOLUME_STATE_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = -1;
        event.valueInt2 = volume;
        event.valueInt3 = flags;
        event.valueBool1 = mute;
        event.valueBool2 = isAutonomous;

        Log.d(TAG, "onVolumeStateChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onGroupVolumeStateChanged(int volume, boolean mute, int groupId, boolean isAutonomous) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_VOLUME_STATE_CHANGED);
        event.device = null;
        event.valueInt1 = groupId;
        event.valueInt2 = volume;
        event.valueBool1 = mute;
        event.valueBool2 = isAutonomous;

        Log.d(TAG, "onGroupVolumeStateChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onDeviceAvailable(int numOfExternalOutputs, int numOfExternalInputs, byte[] address) {
        VolumeControlStackEvent event = new VolumeControlStackEvent(EVENT_TYPE_DEVICE_AVAILABLE);
        event.device = getDevice(address);
        event.valueInt1 = numOfExternalOutputs;
        event.valueInt2 = numOfExternalInputs;

        Log.d(TAG, "onDeviceAvailable: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onExtAudioOutVolumeOffsetChanged(int externalOutputId, int offset, byte[] address) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_EXT_AUDIO_OUT_VOL_OFFSET_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = externalOutputId;
        event.valueInt2 = offset;

        Log.d(TAG, "onExtAudioOutVolumeOffsetChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onExtAudioOutLocationChanged(int externalOutputId, int location, byte[] address) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_EXT_AUDIO_OUT_LOCATION_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = externalOutputId;
        event.valueInt2 = location;

        Log.d(TAG, "onExtAudioOutLocationChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onExtAudioOutDescriptionChanged(int externalOutputId, String descr, byte[] address) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_EXT_AUDIO_OUT_DESCRIPTION_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = externalOutputId;
        event.valueString1 = descr;

        Log.d(TAG, "onExtAudioOutLocationChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onExtAudioInStateChanged(
            int externalInputId, int gainValue, int gainMode, int mute, byte[] address) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_EXT_AUDIO_IN_STATE_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = externalInputId;
        event.valueInt2 = gainValue;
        event.valueInt3 = gainMode;
        event.valueInt4 = mute;

        Log.d(TAG, "onExtAudioInStateChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onExtAudioInStatusChanged(int externalInputId, int status, byte[] address) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_EXT_AUDIO_IN_STATUS_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = externalInputId;
        event.valueInt2 = status;

        Log.d(TAG, "onExtAudioInStatusChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onExtAudioInTypeChanged(int externalInputId, int type, byte[] address) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_EXT_AUDIO_IN_TYPE_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = externalInputId;
        event.valueInt2 = type;

        Log.d(TAG, "onExtAudioInTypeChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onExtAudioInDescriptionChanged(int externalInputId, String descr, byte[] address) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_EXT_AUDIO_IN_DESCR_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = externalInputId;
        event.valueString1 = descr;

        Log.d(TAG, "onExtAudioInDescriptionChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }

    @VisibleForTesting
    void onExtAudioInGainPropsChanged(
            int externalInputId, int unit, int min, int max, byte[] address) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(EVENT_TYPE_EXT_AUDIO_IN_GAIN_PROPS_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = externalInputId;
        event.valueInt2 = unit;
        event.valueInt3 = min;
        event.valueInt4 = max;

        Log.d(TAG, "onExtAudioInGainPropsChanged: " + event);
        mVolumeControlService.messageFromNative(event);
    }
}
+41 −418

File changed.

Preview size limit exceeded, changes collapsed.

+12 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;

import static java.util.Objects.requireNonNull;
import static java.util.Objects.requireNonNullElseGet;

import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothDevice;
@@ -114,7 +115,7 @@ public class VolumeControlService extends ProfileService {
    @VisibleForTesting ServiceFactory mFactory = new ServiceFactory();

    public VolumeControlService(AdapterService adapterService) {
        this(adapterService, null, VolumeControlNativeInterface.getInstance());
        this(adapterService, null, null);
    }

    @VisibleForTesting
@@ -125,7 +126,12 @@ public class VolumeControlService extends ProfileService {
        super(requireNonNull(adapterService));
        mAdapterService = adapterService;
        mDatabaseManager = requireNonNull(mAdapterService.getDatabase());
        mNativeInterface = requireNonNull(nativeInterface);
        mNativeInterface =
                requireNonNullElseGet(
                        nativeInterface,
                        () ->
                                new VolumeControlNativeInterface(
                                        new VolumeControlNativeCallback(adapterService, this)));
        mAudioManager = requireNonNull(getSystemService(AudioManager.class));
        if (looper == null) {
            mHandler = new Handler(requireNonNull(Looper.getMainLooper()));
@@ -1135,6 +1141,10 @@ public class VolumeControlService extends ProfileService {
    }

    void messageFromNative(VolumeControlStackEvent stackEvent) {
        if (!isAvailable()) {
            Log.e(TAG, "Event ignored, service not available: " + stackEvent);
            return;
        }
        Log.d(TAG, "messageFromNative: " + stackEvent);

        if (stackEvent.type == VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED) {
Loading