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

Commit 168f2e55 authored by Sanket Agarwal's avatar Sanket Agarwal Committed by Gerrit Code Review
Browse files

Merge "Add support for AVRCP 1.3."

parents 2c2b5e85 ba12af51
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
@@ -370,6 +370,89 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
        return null;
    }

    /**
     * Set priority of the profile
     *
     * <p> The device should already be paired.
     *  Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
     * {@link #PRIORITY_OFF},
     *
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
     * permission.
     *
     * @param device Paired bluetooth device
     * @param priority
     * @return true if priority is set, false on error
     * @hide
     */
    public boolean setPriority(BluetoothDevice device, int priority) {
        if (DBG) log("setPriority(" + device + ", " + priority + ")");
        if (mService != null && isEnabled()
            && isValidDevice(device)) {
            if (priority != BluetoothProfile.PRIORITY_OFF &&
                priority != BluetoothProfile.PRIORITY_ON){
                return false;
            }
            try {
                return mService.setPriority(device, priority);
            } catch (RemoteException e) {
                   Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                   return false;
            }
        }
        if (mService == null) Log.w(TAG, "Proxy not attached to service");
            return false;
    }

    /**
     * Get the priority of the profile.
     *
     * <p> The priority can be any of:
     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
     *
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
     *
     * @param device Bluetooth device
     * @return priority of the device
     * @hide
     */
    public int getPriority(BluetoothDevice device) {
        if (VDBG) log("getPriority(" + device + ")");
        if (mService != null && isEnabled()
            && isValidDevice(device)) {
            try {
                return mService.getPriority(device);
            } catch (RemoteException e) {
                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                return BluetoothProfile.PRIORITY_OFF;
            }
        }
        if (mService == null) Log.w(TAG, "Proxy not attached to service");
        return BluetoothProfile.PRIORITY_OFF;
    }

    /**
     * Check if A2DP profile is streaming music.
     *
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
     *
     * @param device BluetoothDevice device
     */
    public boolean isA2dpPlaying(BluetoothDevice device) {
        if (mService != null && isEnabled()
            && isValidDevice(device)) {
            try {
                return mService.isA2dpPlaying(device);
            } catch (RemoteException e) {
                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                return false;
            }
        }
        if (mService == null) Log.w(TAG, "Proxy not attached to service");
        return false;
    }

    /**
     * Helper for converting a state to a string.
     *
+182 −26
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.MediaMetadata;
import android.media.session.PlaybackState;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -28,8 +30,8 @@ import java.util.ArrayList;
import java.util.List;

/**
 * This class provides the public APIs to control the Bluetooth AVRCP Controller
 * profile.
 * This class provides the public APIs to control the Bluetooth AVRCP Controller. It currently
 * supports player information, playback support and track metadata.
 *
 *<p>BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP
 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
@@ -39,7 +41,7 @@ import java.util.List;
 */
public final class BluetoothAvrcpController implements BluetoothProfile {
    private static final String TAG = "BluetoothAvrcpController";
    private static final boolean DBG = true;
    private static final boolean DBG = false;
    private static final boolean VDBG = false;

    /**
@@ -61,7 +63,63 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
     * receive.
     */
    public static final String ACTION_CONNECTION_STATE_CHANGED =
        "android.bluetooth.acrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
        "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED";

    /**
     * Intent used to broadcast the change in metadata state of playing track on the AVRCP
     * AG.
     *
     * <p>This intent will have the two extras:
     * <ul>
     *    <li> {@link #EXTRA_METADATA} - {@link MediaMetadata} containing the current metadata.</li>
     *    <li> {@link #EXTRA_PLAYBACK} - {@link PlaybackState} containing the current playback
     *    state. </li>
     * </ul>
     */
    public static final String ACTION_TRACK_EVENT =
        "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT";


    /**
     * Intent used to broadcast the change in player application setting state on AVRCP AG.
     *
     * <p>This intent will have the following extras:
     * <ul>
     *    <li> {@link #EXTRA_PLAYER_SETTING} - {@link BluetoothAvrcpPlayerSettings} containing the
     *    most recent player setting. </li>
     * </ul>
     */
    public static final String ACTION_PLAYER_SETTING =
        "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING";

    public static final String EXTRA_METADATA =
            "android.bluetooth.avrcp-controller.profile.extra.METADATA";

    public static final String EXTRA_PLAYBACK =
            "android.bluetooth.avrcp-controller.profile.extra.PLAYBACK";

    public static final String EXTRA_PLAYER_SETTING =
            "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING";

    /*
     * KeyCoded for Pass Through Commands
     */
    public static final int PASS_THRU_CMD_ID_PLAY = 0x44;
    public static final int PASS_THRU_CMD_ID_PAUSE = 0x46;
    public static final int PASS_THRU_CMD_ID_VOL_UP = 0x41;
    public static final int PASS_THRU_CMD_ID_VOL_DOWN = 0x42;
    public static final int PASS_THRU_CMD_ID_STOP = 0x45;
    public static final int PASS_THRU_CMD_ID_FF = 0x49;
    public static final int PASS_THRU_CMD_ID_REWIND = 0x48;
    public static final int PASS_THRU_CMD_ID_FORWARD = 0x4B;
    public static final int PASS_THRU_CMD_ID_BACKWARD = 0x4C;
    /* Key State Variables */
    public static final int KEY_STATE_PRESSED = 0;
    public static final int KEY_STATE_RELEASED = 1;
    /* Group Navigation Key Codes */
    public static final int PASS_THRU_CMD_ID_NEXT_GRP = 0x00;
    public static final int PASS_THRU_CMD_ID_PREV_GRP = 0x01;


    private Context mContext;
    private ServiceListener mServiceListener;
@@ -223,6 +281,104 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
        if (mService == null) Log.w(TAG, "Proxy not attached to service");
    }

    /**
     * Gets the player application settings.
     *
     * @return the {@link BluetoothAvrcpPlayerSettings} or {@link null} if there is an error.
     */
    public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) {
        if (DBG) Log.d(TAG, "getPlayerSettings");
        BluetoothAvrcpPlayerSettings settings = null;
        if (mService != null && isEnabled()) {
            try {
                settings = mService.getPlayerSettings(device);
            } catch (RemoteException e) {
                Log.e(TAG, "Error talking to BT service in getMetadata() " + e);
                return null;
            }
        }
        return settings;
    }

    /**
     * Gets the metadata for the current track.
     *
     * This should be usually called when application UI needs to be updated, eg. when the track
     * changes or immediately after connecting and getting the current state.
     * @return the {@link MediaMetadata} or {@link null} if there is an error.
     */
    public MediaMetadata getMetadata(BluetoothDevice device) {
        if (DBG) Log.d(TAG, "getMetadata");
        MediaMetadata metadata = null;
        if (mService != null && isEnabled()) {
            try {
                metadata = mService.getMetadata(device);
            } catch (RemoteException e) {
                Log.e(TAG, "Error talking to BT service in getMetadata() " + e);
                return null;
            }
        }
        return metadata;
    }

    /**
     * Gets the playback state for current track.
     *
     * When the application is first connecting it can use current track state to get playback info.
     * For all further updates it should listen to notifications.
     * @return the {@link PlaybackState} or {@link null} if there is an error.
     */
    public PlaybackState getPlaybackState(BluetoothDevice device) {
        if (DBG) Log.d(TAG, "getPlaybackState");
        PlaybackState playbackState = null;
        if (mService != null && isEnabled()) {
            try {
                playbackState = mService.getPlaybackState(device);
            } catch (RemoteException e) {
                Log.e(TAG,
                    "Error talking to BT service in getPlaybackState() " + e);
                return null;
            }
        }
        return playbackState;
    }

    /**
     * Sets the player app setting for current player.
     * returns true in case setting is supported by remote, false otherwise
     */
    public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) {
        if (DBG) Log.d(TAG, "setPlayerApplicationSetting");
        if (mService != null && isEnabled()) {
            try {
                return mService.setPlayerApplicationSetting(plAppSetting);
            } catch (RemoteException e) {
                Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting() " + e);
                return false;
            }
        }
        if (mService == null) Log.w(TAG, "Proxy not attached to service");
        return false;
    }

    /*
     * Send Group Navigation Command to Remote.
     * possible keycode values: next_grp, previous_grp defined above
     */
    public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) {
        Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + keyState);
        if (mService != null && isEnabled()) {
            try {
                mService.sendGroupNavigationCmd(device, keyCode, keyState);
                return;
            } catch (RemoteException e) {
                Log.e(TAG, "Error talking to BT service in sendGroupNavigationCmd()", e);
                return;
            }
        }
        if (mService == null) Log.w(TAG, "Proxy not attached to service");
    }

    private final ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            if (DBG) Log.d(TAG, "Proxy object connected");
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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 android.bluetooth;

parcelable BluetoothAvrcpPlayerSettings;
+189 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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 android.bluetooth;

import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

import java.util.HashMap;
import java.util.Map;

/**
 * Class used to identify settings associated with the player on AG.
 *
 * {@hide}
 */
public final class BluetoothAvrcpPlayerSettings implements Parcelable {
    public static final String TAG = "BluetoothAvrcpPlayerSettings";

    /**
     * Equalizer setting.
     */
    public static final int SETTING_EQUALIZER    = 0x01;

    /**
     * Repeat setting.
     */
    public static final int SETTING_REPEAT       = 0x02;

    /**
     * Shuffle setting.
     */
    public static final int SETTING_SHUFFLE      = 0x04;

    /**
     * Scan mode setting.
     */
    public static final int SETTING_SCAN         = 0x08;

    /**
     * Invalid state.
     *
     * Used for returning error codes.
     */
    public static final int STATE_INVALID = -1;

    /**
     * OFF state.
     *
     * Denotes a general OFF state. Applies to all settings.
     */
    public static final int STATE_OFF = 0x00;

    /**
     * ON state.
     *
     * Applies to {@link SETTING_EQUALIZER}.
     */
    public static final int STATE_ON = 0x01;

    /**
     * Single track repeat.
     *
     * Applies only to {@link SETTING_REPEAT}.
     */
    public static final int STATE_SINGLE_TRACK = 0x02;

    /**
     * All track repeat/shuffle.
     *
     * Applies to {@link SETTING_REPEAT}, {@link SETTING_SHUFFLE} and {@link SETTING_SCAN}.
     */
    public static final int STATE_ALL_TRACK    = 0x03;

    /**
     * Group repeat/shuffle.
     *
     * Applies to {@link SETTING_REPEAT}, {@link SETTING_SHUFFLE} and {@link SETTING_SCAN}.
     */
    public static final int STATE_GROUP        = 0x04;

    /**
     * List of supported settings ORed.
     */
    private int mSettings;

    /**
     * Hash map of current capability values.
     */
    private Map<Integer, Integer> mSettingsValue = new HashMap<Integer, Integer>();

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(mSettings);
        out.writeInt(mSettingsValue.size());
        for (int k : mSettingsValue.keySet()) {
            out.writeInt(k);
            out.writeInt(mSettingsValue.get(k));
        }
    }

    public static final Parcelable.Creator<BluetoothAvrcpPlayerSettings> CREATOR
            = new Parcelable.Creator<BluetoothAvrcpPlayerSettings>() {
        public BluetoothAvrcpPlayerSettings createFromParcel(Parcel in) {
            return new BluetoothAvrcpPlayerSettings(in);
        }

        public BluetoothAvrcpPlayerSettings[] newArray(int size) {
            return new BluetoothAvrcpPlayerSettings[size];
        }
    };

    private BluetoothAvrcpPlayerSettings(Parcel in) {
        mSettings = in.readInt();
        int numSettings = in.readInt();
        for (int i = 0; i < numSettings; i++) {
            mSettingsValue.put(in.readInt(), in.readInt());
        }
    }

    /**
     * Create a new player settings object.
     *
     * @param settings a ORed value of SETTINGS_* defined above.
     */
    public BluetoothAvrcpPlayerSettings(int settings) {
        mSettings = settings;
    }

    /**
     * Get the supported settings.
     *
     * @return int ORed value of supported settings.
     */
    public int getSettings() {
        return mSettings;
    }

    /**
     * Add a setting value.
     *
     * The setting must be part of possible settings in {@link getSettings()}.
     * @param setting setting config.
     * @param value value for the setting.
     * @throws IllegalStateException if the setting is not supported.
     */
    public void addSettingValue(int setting, int value) {
        if ((setting & mSettings) == 0) {
            Log.e(TAG, "Setting not supported: " + setting + " " + mSettings);
            throw new IllegalStateException("Setting not supported: " + setting);
        }
        mSettingsValue.put(setting, value);
    }

    /**
     * Get a setting value.
     *
     * The setting must be part of possible settings in {@link getSettings()}.
     * @param setting setting config.
     * @return value value for the setting.
     * @throws IllegalStateException if the setting is not supported.
     */
    public int getSettingValue(int setting) {
        if ((setting & mSettings) == 0) {
            Log.e(TAG, "Setting not supported: " + setting + " " + mSettings);
            throw new IllegalStateException("Setting not supported: " + setting);
        }
        Integer i = mSettingsValue.get(setting);
        if (i == null) return -1;
        return i;
    }
}
+17 −0
Original line number Diff line number Diff line
@@ -283,6 +283,8 @@ public final class BluetoothClass implements Parcelable {
    public static final int PROFILE_PANU = 4;
    /** @hide */
    public static final int PROFILE_NAP = 5;
    /** @hide */
    public static final int PROFILE_A2DP_SINK = 6;

    /**
     * Check class bits for possible bluetooth profile support.
@@ -310,6 +312,21 @@ public final class BluetoothClass implements Parcelable {
                default:
                    return false;
            }
        } else if (profile == PROFILE_A2DP_SINK) {
            if (hasService(Service.CAPTURE)) {
                return true;
            }
            // By the A2DP spec, srcs must indicate the CAPTURE service.
            // However if some device that do not, we try to
            // match on some other class bits.
            switch (getDeviceClass()) {
                case Device.AUDIO_VIDEO_HIFI_AUDIO:
                case Device.AUDIO_VIDEO_SET_TOP_BOX:
                case Device.AUDIO_VIDEO_VCR :
                    return true;
                default:
                    return false;
            }
        } else if (profile == PROFILE_HEADSET) {
            // The render service class is required by the spec for HFP, so is a
            // pretty good signal
Loading