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

Commit b88837c4 authored by Treehugger Robot's avatar Treehugger Robot
Browse files

Merge "Avrcp log enhancement" am: 1b97dd0c am: 32dc7341

Change-Id: I7fba33003a6d4eae8f4ec735e79381d1517d916a
parents d74215f3 32dc7341
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
/*
 * Copyright 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 com.android.bluetooth.avrcp;

import android.util.Log;

import com.android.bluetooth.Utils;

import com.google.common.collect.EvictingQueue;


// This class is to store logs for Avrcp for given size.
public class AvrcpEventLogger {
    private final String mTitle;
    private final EvictingQueue<Event> mEvents;

    // Event class contain timestamp and log context.
    private class Event {
        private final String mTimeStamp;
        private final String mMsg;

        Event(String msg) {
            mTimeStamp = Utils.getLocalTimeString();
            mMsg = msg;
        }

        public String toString() {
            return (new StringBuilder(mTimeStamp)
                    .append(" ").append(mMsg).toString());
        }
    }

    AvrcpEventLogger(int size, String title) {
        mEvents = EvictingQueue.create(size);
        mTitle = title;
    }

    synchronized void add(String msg) {
        Event event = new Event(msg);
        mEvents.add(event);
    }

    synchronized void logv(String tag, String msg) {
        add(msg);
        Log.v(tag, msg);
    }

    synchronized void logd(String tag, String msg) {
        logd(true, tag, msg);
    }

    synchronized void logd(boolean debug, String tag, String msg) {
        add(msg);
        if (debug) {
            Log.d(tag, msg);
        }
    }

    synchronized void dump(StringBuilder sb) {
        sb.append("Avrcp ").append(mTitle).append(":\n");
        for (Event event : mEvents) {
            sb.append("  ").append(event.toString()).append("\n");
        }
    }
}
+11 −1
Original line number Diff line number Diff line
@@ -50,7 +50,11 @@ public class AvrcpTargetService extends ProfileService {
    private static final String AVRCP_ENABLE_PROPERTY = "persist.bluetooth.enablenewavrcp";

    private static final int AVRCP_MAX_VOL = 127;
    private static final int MEDIA_KEY_EVENT_LOGGER_SIZE = 20;
    private static final String MEDIA_KEY_EVENT_LOGGER_TITLE = "Media Key Events";
    private static int sDeviceMaxVolume = 0;
    private final AvrcpEventLogger mMediaKeyEventLogger = new AvrcpEventLogger(
            MEDIA_KEY_EVENT_LOGGER_SIZE, MEDIA_KEY_EVENT_LOGGER_TITLE);

    private MediaPlayerList mMediaPlayerList;
    private AudioManager mAudioManager;
@@ -365,7 +369,11 @@ public class AvrcpTargetService extends ProfileService {
    // TODO (apanicke): Handle key events here in the service. Currently it was more convenient to
    // handle them there but logically they make more sense handled here.
    void sendMediaKeyEvent(int event, boolean pushed) {
        if (DEBUG) Log.d(TAG, "getMediaKeyEvent: event=" + event + " pushed=" + pushed);
        BluetoothDevice activeDevice = getA2dpActiveDevice();
        MediaPlayerWrapper player = mMediaPlayerList.getActivePlayer();
        mMediaKeyEventLogger.logd(DEBUG, TAG, "getMediaKeyEvent:" + " device=" + activeDevice
                + " event=" + event + " pushed=" + pushed
                + " to " + (player == null ? null : player.getPackageName()));
        mMediaPlayerList.sendMediaKeyEvent(event, pushed);
    }

@@ -394,6 +402,8 @@ public class AvrcpTargetService extends ProfileService {
            tempBuilder.append("\nMedia Player List is empty\n");
        }

        mMediaKeyEventLogger.dump(tempBuilder);
        tempBuilder.append("\n");
        mVolumeManager.dump(tempBuilder);

        // Tab everything over by two spaces
+26 −14
Original line number Diff line number Diff line
@@ -38,10 +38,14 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
    // All volumes are stored at system volume values, not AVRCP values
    private static final String VOLUME_MAP = "bluetooth_volume_map";
    private static final String VOLUME_BLACKLIST = "absolute_volume_blacklist";
    private static final String VOLUME_CHANGE_LOG_TITLE = "Volume Events";
    private static final int AVRCP_MAX_VOL = 127;
    private static final int STREAM_MUSIC = AudioManager.STREAM_MUSIC;
    private static final int VOLUME_CHANGE_LOGGER_SIZE = 30;
    private static int sDeviceMaxVolume = 0;
    private static int sNewDeviceVolume = 0;
    private final AvrcpEventLogger mVolumeEventLogger = new AvrcpEventLogger(
            VOLUME_CHANGE_LOGGER_SIZE, VOLUME_CHANGE_LOG_TITLE);

    Context mContext;
    AudioManager mAudioManager;
@@ -80,7 +84,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
        // If absolute volume for the device is supported, set the volume for the device
        if (mDeviceMap.get(device)) {
            int avrcpVolume = systemToAvrcpVolume(savedVolume);
            Log.i(TAG, "switchVolumeDevice: Updating device volume: avrcpVolume=" + avrcpVolume);
            mVolumeEventLogger.logd(TAG,
                    "switchVolumeDevice: Updating device volume: avrcpVolume=" + avrcpVolume);
            mNativeInterface.sendVolumeChanged(device.getAddress(), avrcpVolume);
        }
    }
@@ -120,8 +125,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
            return;
        }
        SharedPreferences.Editor pref = getVolumeMap().edit();
        Log.i(TAG, "storeVolume: Storing stream volume level for device " + device
                + " : " + storeVolume);
        mVolumeEventLogger.logd(TAG, "storeVolume: Storing stream volume level for device "
                        + device + " : " + storeVolume);
        mVolumeMap.put(device, storeVolume);
        pref.putInt(device.getAddress(), storeVolume);
        // Always use apply() since it is asynchronous, otherwise the call can hang waiting for
@@ -139,7 +144,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
            return;
        }
        SharedPreferences.Editor pref = getVolumeMap().edit();
        Log.i(TAG, "RemoveStoredVolume: Remove stored stream volume level for device " + device);
        mVolumeEventLogger.logd(TAG,
                    "RemoveStoredVolume: Remove stored stream volume level for device " + device);
        mVolumeMap.remove(device);
        pref.remove(device.getAddress());
        // Always use apply() since it is asynchronous, otherwise the call can hang waiting for
@@ -164,11 +170,11 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
    void setVolume(@NonNull BluetoothDevice device, int avrcpVolume) {
        int deviceVolume =
                (int) Math.floor((double) avrcpVolume * sDeviceMaxVolume / AVRCP_MAX_VOL);
        if (DEBUG) {
            Log.d(TAG, "setVolume: avrcpVolume=" + avrcpVolume
        mVolumeEventLogger.logd(DEBUG, TAG, "setVolume:"
                        + " device=" + device
                        + " avrcpVolume=" + avrcpVolume
                        + " deviceVolume=" + deviceVolume
                        + " sDeviceMaxVolume=" + sDeviceMaxVolume);
        }
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, deviceVolume,
                AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
        storeVolumeForDevice(device);
@@ -178,11 +184,11 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
        int avrcpVolume =
                (int) Math.floor((double) deviceVolume * AVRCP_MAX_VOL / sDeviceMaxVolume);
        if (avrcpVolume > 127) avrcpVolume = 127;
        if (DEBUG) {
            Log.d(TAG, "sendVolumeChanged: avrcpVolume=" + avrcpVolume
        mVolumeEventLogger.logd(DEBUG, TAG, "sendVolumeChanged:"
                        + " device=" + device
                        + " avrcpVolume=" + avrcpVolume
                        + " deviceVolume=" + deviceVolume
                        + " sDeviceMaxVolume=" + sDeviceMaxVolume);
        }
        mNativeInterface.sendVolumeChanged(device.getAddress(), avrcpVolume);
        storeVolumeForDevice(device);
    }
@@ -290,6 +296,12 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
                        d.getAddress(), deviceName, (Integer) value, absoluteVolume));
            }
        }

        StringBuilder tempBuilder = new StringBuilder();
        mVolumeEventLogger.dump(tempBuilder);
        // Tab volume event logs over by two spaces
        sb.append(tempBuilder.toString().replaceAll("(?m)^", "  "));
        tempBuilder.append("\n");
    }

    static void d(String msg) {
+26 −12
Original line number Diff line number Diff line
@@ -69,6 +69,10 @@ public class MediaPlayerList {
    private static final int NO_ACTIVE_PLAYER = 0;
    private static final int BLUETOOTH_PLAYER_ID = 0;
    private static final String BLUETOOTH_PLAYER_NAME = "Bluetooth Player";
    private static final int ACTIVE_PLAYER_LOGGER_SIZE = 5;
    private static final String ACTIVE_PLAYER_LOGGER_TITLE = "Active Player Events";
    private static final int AUDIO_PLAYBACK_STATE_LOGGER_SIZE = 15;
    private static final String AUDIO_PLAYBACK_STATE_LOGGER_TITLE = "Audio Playback State Events";

    // mediaId's for the now playing list will be in the form of "NowPlayingId[XX]" where [XX]
    // is the Queue ID for the requested item.
@@ -85,6 +89,10 @@ public class MediaPlayerList {
    private MediaSessionManager mMediaSessionManager;
    private MediaData mCurrMediaData = null;
    private final AudioManager mAudioManager;
    private final AvrcpEventLogger mActivePlayerLogger = new AvrcpEventLogger(
            ACTIVE_PLAYER_LOGGER_SIZE, ACTIVE_PLAYER_LOGGER_TITLE);
    private final AvrcpEventLogger mAudioPlaybackStateLogger = new AvrcpEventLogger(
            AUDIO_PLAYBACK_STATE_LOGGER_SIZE, AUDIO_PLAYBACK_STATE_LOGGER_TITLE);

    private Map<Integer, MediaPlayerWrapper> mMediaPlayers =
            Collections.synchronizedMap(new HashMap<Integer, MediaPlayerWrapper>());
@@ -240,8 +248,6 @@ public class MediaPlayerList {
        return mMediaPlayers.get(mActivePlayerId);
    }



    // In this case the displayed player is the Bluetooth Player, the number of items is equal
    // to the number of players. The root ID will always be empty string in this case as well.
    void getPlayerRoot(int playerId, GetPlayerRootCallback cb) {
@@ -527,7 +533,8 @@ public class MediaPlayerList {

        mActivePlayerId = playerId;
        getActivePlayer().registerCallback(mMediaPlayerCallback);
        Log.i(TAG, "setActivePlayer(): setting player to " + getActivePlayer().getPackageName());
        mActivePlayerLogger.logd(TAG, "setActivePlayer(): setting player to "
                + getActivePlayer().getPackageName());

        // Ensure that metadata is synced on the new player
        if (!getActivePlayer().isMetadataSynced()) {
@@ -674,7 +681,8 @@ public class MediaPlayerList {
                        1.0f);
            currMediaData.state = builder.build();
        }
        Log.i(TAG, "updateMediaForAudioPlayback: update state=" + currMediaData.state);
        mAudioPlaybackStateLogger.logd(TAG, "updateMediaForAudioPlayback: update state="
                + currMediaData.state);
        sendMediaUpdate(currMediaData);
    }

@@ -692,21 +700,24 @@ public class MediaPlayerList {
                return;
            }
            boolean isActive = false;
            Log.v(TAG, "onPlaybackConfigChanged(): Configs list size=" + configs.size());
            AudioPlaybackConfiguration activeConfig = null;
            for (AudioPlaybackConfiguration config : configs) {
                if (config.isActive() && (config.getAudioAttributes().getUsage()
                            == AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
                        && (config.getAudioAttributes().getContentType()
                            == AudioAttributes.CONTENT_TYPE_SPEECH)) {
                    if (DEBUG) {
                        Log.d(TAG, "onPlaybackConfigChanged(): config=" + config);
                    }
                    activeConfig = config;
                    isActive = true;
                }
            }
            if (isActive != mAudioPlaybackIsActive) {
                Log.d(TAG, "onPlaybackConfigChanged isActive=" + isActive
                        + ", mAudioPlaybackIsActive=" + mAudioPlaybackIsActive);
                mAudioPlaybackStateLogger.logd(DEBUG, TAG, "onPlaybackConfigChanged: "
                        + (mAudioPlaybackIsActive ? "Active" : "Non-active") + " -> "
                        + (isActive ? "Active" : "Non-active"));
                if (isActive) {
                    mAudioPlaybackStateLogger.logd(DEBUG, TAG, "onPlaybackConfigChanged: "
                            + "active config: " + activeConfig);
                }
                mAudioPlaybackIsActive = isActive;
                updateMediaForAudioPlayback();
            }
@@ -803,9 +814,12 @@ public class MediaPlayerList {
            sb.append(player.toString().replaceAll("(?m)^", "  "));
            sb.append("\n");
        }
        // TODO (apanicke): Add media key events

        mActivePlayerLogger.dump(sb);
        sb.append("\n");
        mAudioPlaybackStateLogger.dump(sb);
        sb.append("\n");
        // TODO (apanicke): Add last sent data
        // TODO (apanicke): Add addressed player history
    }

    private static void e(String message) {
+9 −1
Original line number Diff line number Diff line
@@ -42,10 +42,14 @@ class MediaPlayerWrapper {
    private static final String TAG = "AvrcpMediaPlayerWrapper";
    private static final boolean DEBUG = false;
    static boolean sTesting = false;
    private static final int PLAYBACK_STATE_CHANGE_EVENT_LOGGER_SIZE = 5;
    private static final String PLAYBACK_STATE_CHANGE_LOGGER_EVENT_TITLE =
            "Playback State change Event";

    private MediaController mMediaController;
    private String mPackageName;
    private Looper mLooper;
    private final AvrcpEventLogger mPlaybackStateChangeEventLogger;

    private MediaData mCurrentData;

@@ -81,6 +85,8 @@ class MediaPlayerWrapper {
        mMediaController = controller;
        mPackageName = controller.getPackageName();
        mLooper = looper;
        mPlaybackStateChangeEventLogger = new AvrcpEventLogger(
                PLAYBACK_STATE_CHANGE_EVENT_LOGGER_SIZE, PLAYBACK_STATE_CHANGE_LOGGER_EVENT_TITLE);

        mCurrentData = new MediaData(null, null, null);
        mCurrentData.queue = Util.toMetadataList(getQueue());
@@ -399,7 +405,8 @@ class MediaPlayerWrapper {
                return;
            }

            Log.v(TAG, "onPlaybackStateChanged(): " + mPackageName + " : " + state.toString());
            mPlaybackStateChangeEventLogger.logv(TAG, "onPlaybackStateChanged(): "
                    + mPackageName + " : " + state.toString());

            if (!playstateEquals(state, getPlaybackState())) {
                e("The callback playback state doesn't match the current state");
@@ -513,6 +520,7 @@ class MediaPlayerWrapper {
        for (Metadata data : mCurrentData.queue) {
            sb.append("    " + data + "\n");
        }
        mPlaybackStateChangeEventLogger.dump(sb);
        return sb.toString();
    }
}