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

Commit c15fd838 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 4765094 from 28cb393d to pi-release

Change-Id: Ied5fbf77c82b198e38a6a79f230130b66217c6af
parents 67889364 28cb393d
Loading
Loading
Loading
Loading
+64 −12
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

#include <base/bind.h>
#include <map>
#include <mutex>
#include <shared_mutex>
#include <vector>

#include "android_runtime/AndroidRuntime.h"
@@ -33,6 +35,8 @@ namespace android {
static MediaCallbacks* mServiceCallbacks;
static ServiceInterface* sServiceInterface;
static jobject mJavaInterface;
static std::shared_timed_mutex interface_mutex;
static std::shared_timed_mutex callbacks_mutex;

// Forward Declarations
static void sendMediaKeyEvent(int, int);
@@ -204,6 +208,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) {

static void initNative(JNIEnv* env, jobject object) {
  ALOGD("%s", __func__);
  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
  std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
  mJavaInterface = env->NewGlobalRef(object);

  sServiceInterface = getBluetoothInterface()->get_avrcp_service();
@@ -214,7 +220,12 @@ static void sendMediaUpdateNative(JNIEnv* env, jobject object,
                                  jboolean metadata, jboolean state,
                                  jboolean queue) {
  ALOGD("%s", __func__);
  CHECK(mServiceCallbacks);
  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
  if (mServiceCallbacks == nullptr) {
    ALOGW("%s: Service not loaded.", __func__);
    return;
  }

  mServiceCallbacks->SendMediaUpdate(metadata == JNI_TRUE, state == JNI_TRUE,
                                     queue == JNI_TRUE);
}
@@ -223,13 +234,21 @@ static void sendFolderUpdateNative(JNIEnv* env, jobject object,
                                   jboolean available_players,
                                   jboolean addressed_player, jboolean uids) {
  ALOGD("%s", __func__);
  CHECK(mServiceCallbacks);
  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
  if (mServiceCallbacks == nullptr) {
    ALOGW("%s: Service not loaded.", __func__);
    return;
  }

  mServiceCallbacks->SendFolderUpdate(available_players == JNI_TRUE,
                                      addressed_player == JNI_TRUE,
                                      uids == JNI_TRUE);
}

static void cleanupNative(JNIEnv* env, jobject object) {
  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
  std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);

  sServiceInterface->Cleanup();
  env->DeleteGlobalRef(mJavaInterface);
  mJavaInterface = nullptr;
@@ -239,7 +258,11 @@ static void cleanupNative(JNIEnv* env, jobject object) {

jboolean connectDeviceNative(JNIEnv* env, jobject object, jstring address) {
  ALOGD("%s", __func__);
  if (!sServiceInterface) return JNI_FALSE;
  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
  if (mServiceCallbacks == nullptr) {
    ALOGW("%s: Service not loaded.", __func__);
    return JNI_FALSE;
  }

  const char* tmp_addr = env->GetStringUTFChars(address, 0);
  RawAddress bdaddr;
@@ -254,7 +277,11 @@ jboolean connectDeviceNative(JNIEnv* env, jobject object, jstring address) {

jboolean disconnectDeviceNative(JNIEnv* env, jobject object, jstring address) {
  ALOGD("%s", __func__);
  if (!sServiceInterface) return JNI_FALSE;
  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
  if (mServiceCallbacks == nullptr) {
    ALOGW("%s: Service not loaded.", __func__);
    return JNI_FALSE;
  }

  const char* tmp_addr = env->GetStringUTFChars(address, 0);
  RawAddress bdaddr;
@@ -269,8 +296,9 @@ jboolean disconnectDeviceNative(JNIEnv* env, jobject object, jstring address) {

static void sendMediaKeyEvent(int key, int state) {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || !mJavaInterface) return;
  sCallbackEnv->CallVoidMethod(mJavaInterface, method_sendMediaKeyEvent, key,
                               state);
}
@@ -393,7 +421,10 @@ static FolderInfo getFolderInfoFromJavaObj(JNIEnv* env, jobject folder) {

static SongInfo getSongInfo() {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface) return SongInfo();

  jobject metadata =
      sCallbackEnv->CallObjectMethod(mJavaInterface, method_getCurrentSongInfo);
  return getSongInfoFromJavaObj(sCallbackEnv.get(), metadata);
@@ -401,11 +432,11 @@ static SongInfo getSongInfo() {

static PlayStatus getCurrentPlayStatus() {
  ALOGD("%s", __func__);

  PlayStatus status;
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return status;
  if (!sCallbackEnv.valid() || !mJavaInterface) return PlayStatus();

  PlayStatus status;
  jobject playStatus =
      sCallbackEnv->CallObjectMethod(mJavaInterface, method_getPlaybackStatus);
  jclass class_playStatus = sCallbackEnv->GetObjectClass(playStatus);
@@ -425,8 +456,9 @@ static PlayStatus getCurrentPlayStatus() {

static std::string getCurrentMediaId() {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return "";
  if (!sCallbackEnv.valid() || !mJavaInterface) return "";

  jstring media_id = (jstring)sCallbackEnv->CallObjectMethod(
      mJavaInterface, method_getCurrentMediaId);
@@ -440,8 +472,9 @@ static std::string getCurrentMediaId() {

static std::vector<SongInfo> getNowPlayingList() {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return std::vector<SongInfo>();
  if (!sCallbackEnv.valid() || !mJavaInterface) return std::vector<SongInfo>();

  jobject song_list =
      sCallbackEnv->CallObjectMethod(mJavaInterface, method_getNowPlayingList);
@@ -468,9 +501,9 @@ static std::vector<SongInfo> getNowPlayingList() {

static uint16_t getCurrentPlayerId() {
  ALOGD("%s", __func__);

  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return 0u;
  if (!sCallbackEnv.valid() || !mJavaInterface) return 0u;

  jint id =
      sCallbackEnv->CallIntMethod(mJavaInterface, method_getCurrentPlayerId);
@@ -480,7 +513,10 @@ static uint16_t getCurrentPlayerId() {

static std::vector<MediaPlayerInfo> getMediaPlayerList() {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface)
    return std::vector<MediaPlayerInfo>();

  jobject player_list = (jobject)sCallbackEnv->CallObjectMethod(
      mJavaInterface, method_getMediaPlayerList);
@@ -535,7 +571,9 @@ SetBrowsedPlayerCb set_browsed_player_cb;

static void setBrowsedPlayer(uint16_t player_id, SetBrowsedPlayerCb cb) {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface) return;

  set_browsed_player_cb = cb;
  sCallbackEnv->CallVoidMethod(mJavaInterface, method_setBrowsedPlayer,
@@ -631,7 +669,9 @@ static void getFolderItemsResponseNative(JNIEnv* env, jobject object,
static void getFolderItems(uint16_t player_id, std::string media_id,
                           GetFolderItemsCb cb) {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface) return;

  // TODO (apanicke): Fix a potential media_id collision if two media players
  // use the same media_id scheme or two devices browse the same content.
@@ -645,7 +685,9 @@ static void getFolderItems(uint16_t player_id, std::string media_id,
static void playItem(uint16_t player_id, bool now_playing,
                     std::string media_id) {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface) return;

  jstring j_media_id = sCallbackEnv->NewStringUTF(media_id.c_str());
  sCallbackEnv->CallVoidMethod(mJavaInterface, method_playItem, player_id,
@@ -654,7 +696,9 @@ static void playItem(uint16_t player_id, bool now_playing,

static void setActiveDevice(const RawAddress& address) {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface) return;

  jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
  sCallbackEnv->CallVoidMethod(mJavaInterface, method_setActiveDevice,
@@ -663,7 +707,9 @@ static void setActiveDevice(const RawAddress& address) {

static void volumeDeviceConnected(const RawAddress& address) {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface) return;

  jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
  sCallbackEnv->CallVoidMethod(mJavaInterface, method_volumeDeviceConnected,
@@ -677,7 +723,9 @@ static void volumeDeviceConnected(
    const RawAddress& address,
    ::bluetooth::avrcp::VolumeInterface::VolumeChangedCb cb) {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface) return;

  volumeCallbackMap.emplace(address, cb);

@@ -688,7 +736,9 @@ static void volumeDeviceConnected(

static void volumeDeviceDisconnected(const RawAddress& address) {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface) return;

  volumeCallbackMap.erase(address);

@@ -706,7 +756,9 @@ static void sendVolumeChangedNative(JNIEnv* env, jobject object, jint volume) {

static void setVolume(int8_t volume) {
  ALOGD("%s", __func__);
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface) return;

  sCallbackEnv->CallVoidMethod(mJavaInterface, method_setVolume, volume);
}
+10 −0
Original line number Diff line number Diff line
@@ -81,6 +81,12 @@ public class HeadsetClientService extends ProfileService {
        // Setup the JNI service
        NativeInterface.initializeNative();
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        if (mAudioManager == null) {
            Log.e(TAG, "AudioManager service doesn't exist?");
        } else {
            // start AudioManager in a known state
            mAudioManager.setParameters("hfp_enable=false");
        }

        mSmFactory = new HeadsetClientStateMachineFactory();
        mStateMachineMap.clear();
@@ -923,4 +929,8 @@ public class HeadsetClientService extends ProfileService {
    protected void setSMFactory(HeadsetClientStateMachineFactory factory) {
        mSmFactory = factory;
    }

    AudioManager getAudioManager() {
        return mAudioManager;
    }
}
+54 −23
Original line number Diff line number Diff line
@@ -39,8 +39,9 @@ import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHeadsetClientCall;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.Intent;
import android.media.AudioAttributes;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Looper;
@@ -156,7 +157,6 @@ public class HeadsetClientStateMachine extends StateMachine {
    // indicator
    private Pair<Integer, Object> mPendingAction;

    private static AudioManager sAudioManager;
    private int mAudioState;
    private boolean mAudioWbs;
    private int mVoiceRecognitionActive;
@@ -169,6 +169,11 @@ public class HeadsetClientStateMachine extends StateMachine {
    private int mPeerFeatures;
    private int mChldFeatures;

    // This is returned when requesting focus from AudioManager
    private AudioFocusRequest mAudioFocusRequest;

    private AudioManager mAudioManager;

    // Accessor for the states, useful for reusing the state machines
    public IState getDisconnectedState() {
        return mDisconnected;
@@ -690,13 +695,9 @@ public class HeadsetClientStateMachine extends StateMachine {
    HeadsetClientStateMachine(HeadsetClientService context, Looper looper) {
        super(TAG, looper);
        mService = context;
        mAudioManager = mService.getAudioManager();

        mAdapter = BluetoothAdapter.getDefaultAdapter();
        if (sAudioManager == null) {
            sAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
            // Initialize hfp_enable into a known state.
            routeHfpAudio(false);
        }
        mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
        mAudioWbs = false;
        mVoiceRecognitionActive = HeadsetClientHalConstants.VR_STATE_STOPPED;
@@ -706,8 +707,8 @@ public class HeadsetClientStateMachine extends StateMachine {
        mIndicatorNetworkSignal = 0;
        mIndicatorBatteryLevel = 0;

        sMaxAmVcVol = sAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);
        sMinAmVcVol = sAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL);
        sMaxAmVcVol = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);
        sMinAmVcVol = mAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL);

        mOperatorName = null;
        mSubscriberInfo = null;
@@ -740,26 +741,53 @@ public class HeadsetClientStateMachine extends StateMachine {
        return hfcsm;
    }

    static synchronized void routeHfpAudio(boolean enable) {
    synchronized void routeHfpAudio(boolean enable) {
        if (mAudioManager == null) {
            Log.e(TAG, "AudioManager is null!");
            return;
        }
        if (DBG) {
            Log.d(TAG, "hfp_enable=" + enable);
        }
        if (enable && !sAudioIsRouted) {
            sAudioManager.setParameters("hfp_enable=true");
            mAudioManager.setParameters("hfp_enable=true");
        } else if (!enable) {
            sAudioManager.setParameters("hfp_enable=false");
            mAudioManager.setParameters("hfp_enable=false");
        }
        sAudioIsRouted = enable;
    }

    private AudioFocusRequest requestAudioFocus() {
        AudioAttributes streamAttributes =
                new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                        .build();
        AudioFocusRequest focusRequest =
                new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
                        .setAudioAttributes(streamAttributes)
                        .build();
        int focusRequestStatus = mAudioManager.requestAudioFocus(focusRequest);
        if (DBG) {
            String s = (focusRequestStatus == AudioManager.AUDIOFOCUS_REQUEST_GRANTED)
                    ? "AudioFocus granted" : "AudioFocus NOT granted";
            Log.d(TAG, "AudioManager requestAudioFocus returned: " + s);
        }
        return focusRequest;
    }

    public void doQuit() {
        Log.d(TAG, "doQuit");
        if (sAudioManager != null) {
        routeHfpAudio(false);
        }
        returnAudioFocusIfNecessary();
        quitNow();
    }

    private void returnAudioFocusIfNecessary() {
        if (mAudioFocusRequest == null) return;
        mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest);
        mAudioFocusRequest = null;
    }

    static int hfToAmVol(int hfVol) {
        int amRange = sMaxAmVcVol - sMinAmVcVol;
        int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME;
@@ -1025,13 +1053,13 @@ public class HeadsetClientStateMachine extends StateMachine {
                        }
                    }

                    int amVol = sAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
                    int amVol = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
                    deferMessage(
                            obtainMessage(HeadsetClientStateMachine.SET_SPEAKER_VOLUME, amVol, 0));
                    // Mic is either in ON state (full volume) or OFF state. There is no way in
                    // Android to change the MIC volume.
                    deferMessage(obtainMessage(HeadsetClientStateMachine.SET_MIC_VOLUME,
                            sAudioManager.isMicrophoneMute() ? 0 : 15, 0));
                            mAudioManager.isMicrophoneMute() ? 0 : 15, 0));
                    // query subscriber info
                    deferMessage(obtainMessage(HeadsetClientStateMachine.SUBSCRIBER_INFO));
                    transitionTo(mConnected);
@@ -1361,11 +1389,11 @@ public class HeadsetClientStateMachine extends StateMachine {
                            if (event.valueInt == HeadsetClientHalConstants.VOLUME_TYPE_SPK) {
                                mCommandedSpeakerVolume = hfToAmVol(event.valueInt2);
                                Log.d(TAG, "AM volume set to " + mCommandedSpeakerVolume);
                                sAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
                                mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
                                        +mCommandedSpeakerVolume, AudioManager.FLAG_SHOW_UI);
                            } else if (event.valueInt
                                    == HeadsetClientHalConstants.VOLUME_TYPE_MIC) {
                                sAudioManager.setMicrophoneMute(event.valueInt2 == 0);
                                mAudioManager.setMicrophoneMute(event.valueInt2 == 0);
                            }
                            break;
                        case StackEvent.EVENT_TYPE_CMD_RESULT:
@@ -1495,7 +1523,7 @@ public class HeadsetClientStateMachine extends StateMachine {

                    // We need to set the volume after switching into HFP mode as some Audio HALs
                    // reset the volume to a known-default on mode switch.
                    final int amVol = sAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
                    final int amVol = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
                    final int hfVol = amToHfVol(amVol);

                    if (DBG) {
@@ -1505,18 +1533,19 @@ public class HeadsetClientStateMachine extends StateMachine {
                        if (DBG) {
                            Log.d(TAG, "Setting sampling rate as 16000");
                        }
                        sAudioManager.setParameters("hfp_set_sampling_rate=16000");
                        mAudioManager.setParameters("hfp_set_sampling_rate=16000");
                    } else {
                        if (DBG) {
                            Log.d(TAG, "Setting sampling rate as 8000");
                        }
                        sAudioManager.setParameters("hfp_set_sampling_rate=8000");
                        mAudioManager.setParameters("hfp_set_sampling_rate=8000");
                    }
                    if (DBG) {
                        Log.d(TAG, "hf_volume " + hfVol);
                    }
                    routeHfpAudio(true);
                    sAudioManager.setParameters("hfp_volume=" + hfVol);
                    mAudioFocusRequest = requestAudioFocus();
                    mAudioManager.setParameters("hfp_volume=" + hfVol);
                    transitionTo(mAudioOn);
                    break;

@@ -1590,6 +1619,7 @@ public class HeadsetClientStateMachine extends StateMachine {
                     */
                    if (NativeInterface.disconnectAudioNative(getByteAddress(mCurrentDevice))) {
                        routeHfpAudio(false);
                        returnAudioFocusIfNecessary();
                    }
                    break;

@@ -1661,6 +1691,7 @@ public class HeadsetClientStateMachine extends StateMachine {
                    // is not much we can do here since dropping the call without user consent
                    // even if the audio connection snapped may not be a good idea.
                    routeHfpAudio(false);
                    returnAudioFocusIfNecessary();
                    transitionTo(mConnected);
                    break;