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

Commit f56b5778 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Adding USB Headset awareness." into oc-dr1-dev

parents e54ad58a b5eaa809
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@ LOCAL_SRC_FILES += \
    $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
    $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
    $(LOCAL_REL_DIR)/com_android_server_vr_VrManagerService.cpp \
    $(LOCAL_REL_DIR)/com_android_server_vr_VrManagerService.cpp \
    $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
    $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
    $(LOCAL_REL_DIR)/com_android_server_UsbDescriptorParser.cpp \
    $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \
    $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \
    $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
    $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
    $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
    $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
+62 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 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.
 */

#define LOG_TAG "UsbHostManagerJNI"
#include "utils/Log.h"

#include "jni.h"
#include "JNIHelp.h"

#include <usbhost/usbhost.h>

#define MAX_DESCRIPTORS_LENGTH 16384

// com.android.server.usb.descriptors
extern "C" {
jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors(
        JNIEnv* env, jobject thiz, jstring deviceAddr) {
    const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL);
    struct usb_device* device = usb_device_open(deviceAddrStr);
    env->ReleaseStringUTFChars(deviceAddr, deviceAddrStr);

    if (!device) {
        ALOGE("usb_device_open failed");
        return NULL;
    }

    int fd = usb_device_get_fd(device);
    if (fd < 0) {
        return NULL;
    }

    // from android_hardware_UsbDeviceConnection_get_desc()
    jbyte buffer[MAX_DESCRIPTORS_LENGTH];
    lseek(fd, 0, SEEK_SET);
    int numBytes = read(fd, buffer, sizeof(buffer));

    usb_device_close(device);

    jbyteArray ret = NULL;
    if (numBytes != 0) {
        ret = env->NewByteArray(numBytes);
        env->SetByteArrayRegion(ret, 0, numBytes, buffer);
    }
    return ret;
}

} // extern "C"

+27 −10
Original line number Original line Diff line number Diff line
@@ -65,6 +65,9 @@ public final class UsbAlsaManager {
    private final HashMap<UsbDevice,UsbAudioDevice>
    private final HashMap<UsbDevice,UsbAudioDevice>
        mAudioDevices = new HashMap<UsbDevice,UsbAudioDevice>();
        mAudioDevices = new HashMap<UsbDevice,UsbAudioDevice>();


    private boolean mIsInputHeadset; // as reported by UsbDescriptorParser
    private boolean mIsOutputHeadset; // as reported by UsbDescriptorParser

    private final HashMap<UsbDevice,UsbMidiDevice>
    private final HashMap<UsbDevice,UsbMidiDevice>
        mMidiDevices = new HashMap<UsbDevice,UsbMidiDevice>();
        mMidiDevices = new HashMap<UsbDevice,UsbMidiDevice>();


@@ -184,9 +187,14 @@ public final class UsbAlsaManager {
        try {
        try {
            // Playback Device
            // Playback Device
            if (audioDevice.mHasPlayback) {
            if (audioDevice.mHasPlayback) {
                int device = (audioDevice == mAccessoryAudioDevice ?
                int device;
                        AudioSystem.DEVICE_OUT_USB_ACCESSORY :
                if (mIsOutputHeadset) {
                        AudioSystem.DEVICE_OUT_USB_DEVICE);
                    device = AudioSystem.DEVICE_OUT_USB_HEADSET;
                } else {
                    device = (audioDevice == mAccessoryAudioDevice
                        ? AudioSystem.DEVICE_OUT_USB_ACCESSORY
                        : AudioSystem.DEVICE_OUT_USB_DEVICE);
                }
                if (DEBUG) {
                if (DEBUG) {
                    Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
                    Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
                            " addr:" + address + " name:" + audioDevice.getDeviceName());
                            " addr:" + address + " name:" + audioDevice.getDeviceName());
@@ -197,9 +205,14 @@ public final class UsbAlsaManager {


            // Capture Device
            // Capture Device
            if (audioDevice.mHasCapture) {
            if (audioDevice.mHasCapture) {
               int device = (audioDevice == mAccessoryAudioDevice ?
                int device;
                        AudioSystem.DEVICE_IN_USB_ACCESSORY :
                if (mIsInputHeadset) {
                        AudioSystem.DEVICE_IN_USB_DEVICE);
                    device = AudioSystem.DEVICE_IN_USB_HEADSET;
                } else {
                    device = (audioDevice == mAccessoryAudioDevice
                        ? AudioSystem.DEVICE_IN_USB_ACCESSORY
                        : AudioSystem.DEVICE_IN_USB_DEVICE);
                }
                mAudioService.setWiredDeviceConnectionState(
                mAudioService.setWiredDeviceConnectionState(
                        device, state, address, audioDevice.getDeviceName(), TAG);
                        device, state, address, audioDevice.getDeviceName(), TAG);
            }
            }
@@ -343,12 +356,16 @@ public final class UsbAlsaManager {
        return selectAudioCard(mCardsParser.getDefaultCard());
        return selectAudioCard(mCardsParser.getDefaultCard());
    }
    }


    /* package */ void usbDeviceAdded(UsbDevice usbDevice) {
    /* package */ void usbDeviceAdded(UsbDevice usbDevice,
            boolean isInputHeadset, boolean isOutputHeadset) {
        if (DEBUG) {
        if (DEBUG) {
          Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() +
            Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName()
                  " nm:" + usbDevice.getProductName());
                    + " nm:" + usbDevice.getProductName());
        }
        }


        mIsInputHeadset = isInputHeadset;
        mIsOutputHeadset = isOutputHeadset;

        // Is there an audio interface in there?
        // Is there an audio interface in there?
        boolean isAudioDevice = false;
        boolean isAudioDevice = false;


+9 −2
Original line number Original line Diff line number Diff line
@@ -16,7 +16,6 @@


package com.android.server.usb;
package com.android.server.usb;


import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
@@ -32,6 +31,7 @@ import android.util.Slog;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.usb.descriptors.UsbDescriptorParser;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashMap;
@@ -259,7 +259,14 @@ public class UsbHostManager {
                    getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice,
                    getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice,
                            usbDeviceConnectionHandler);
                            usbDeviceConnectionHandler);
                }
                }
                mUsbAlsaManager.usbDeviceAdded(mNewDevice);
                // deviceName is something like: "/dev/bus/usb/001/001"
                UsbDescriptorParser parser = new UsbDescriptorParser();
                if (parser.parseDevice(mNewDevice.getDeviceName())) {
                    Slog.i(TAG, "---- isHeadset[in:" + parser.isInputHeadset()
                            + " , out:" + parser.isOutputHeadset() + "]");
                    mUsbAlsaManager.usbDeviceAdded(mNewDevice,
                            parser.isInputHeadset(), parser.isOutputHeadset());
                }
            } else {
            } else {
                Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
                Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
            }
            }
+189 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 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.server.usb.descriptors;

import android.annotation.NonNull;

/**
 * @hide
 * A stream interface wrapping a byte array. Very much like a java.io.ByteArrayInputStream
 * but with the capability to "back up" in situations where the parser discovers that a
 * UsbDescriptor has overrun its length.
 */
public class ByteStream {
    private static final String TAG = "ByteStream";

    /** The byte array being wrapped */
    @NonNull
    private final byte[] mBytes; // this is never null.

    /**
     * The index into the byte array to be read next.
     * This value is altered by reading data out of the stream
     * (using either the getByte() or unpack*() methods), or alternatively
     * by explicitly offseting the stream position with either
     * advance() or reverse().
     */
    private int mIndex;

    /*
     * This member used with resetReadCount() & getReadCount() can be used to determine how many
     * bytes a UsbDescriptor subclass ACTUALLY reads (as opposed to what its length field says).
     * using this info, the parser can mark a descriptor as valid or invalid and correct the stream
     * position with advance() & reverse() to keep from "getting lost" in the descriptor stream.
     */
    private int mReadCount;

    /**
     * Create a ByteStream object wrapping the specified byte array.
     *
     * @param bytes The byte array containing the raw descriptor information retrieved from
     *              the USB device.
     * @throws IllegalArgumentException
     */
    public ByteStream(@NonNull byte[] bytes) {
        if (bytes == null) {
            throw new IllegalArgumentException();
        }
        mBytes = bytes;
    }

    /**
     * Resets the running count of bytes read so that later we can see how much more has been read.
     */
    public void resetReadCount() {
        mReadCount = 0;
    }

    /**
     * Retrieves the running count of bytes read from the stream.
     */
    public int getReadCount() {
        return mReadCount;
    }

    /**
     * @return The value of the next byte in the stream without advancing the stream.
     * Does not affect the running count as the byte hasn't been "consumed".
     * @throws IndexOutOfBoundsException
     */
    public byte peekByte() {
        if (available() > 0) {
            return mBytes[mIndex + 1];
        } else {
            throw new IndexOutOfBoundsException();
        }
    }

    /**
     * @return the next byte from the stream and advances the stream and the read count. Note
     * that this is a signed byte (as is the case of byte in Java). The user may need to understand
     * from context if it should be interpreted as an unsigned value.
     * @throws IndexOutOfBoundsException
     */
    public byte getByte() {
        if (available() > 0) {
            mReadCount++;
            return mBytes[mIndex++];
        } else {
            throw new IndexOutOfBoundsException();
        }
    }

    /**
     * Reads 2 bytes in *little endian format* from the stream and composes a 16-bit integer.
     * As we are storing the 2-byte value in a 4-byte integer, the upper 2 bytes are always
     * 0, essentially making the returned value *unsigned*.
     * @return The 16-bit integer (packed into the lower 2 bytes of an int) encoded by the
     * next 2 bytes in the stream.
     * @throws IndexOutOfBoundsException
     */
    public int unpackUsbWord() {
        if (available() >= 2) {
            int b0 = getByte();
            int b1 = getByte();
            return ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF);
        } else {
            throw new IndexOutOfBoundsException();
        }
    }

    /**
     * Reads 3 bytes in *little endian format* from the stream and composes a 24-bit integer.
     * As we are storing the 3-byte value in a 4-byte integer, the upper byte is always
     * 0, essentially making the returned value *unsigned*.
     * @return The 24-bit integer (packed into the lower 3 bytes of an int) encoded by the
     * next 3 bytes in the stream.
     * @throws IndexOutOfBoundsException
     */
    public int unpackUsbTriple() {
        if (available() >= 3) {
            int b0 = getByte();
            int b1 = getByte();
            int b2 = getByte();
            return ((b2 << 16) & 0x00FF0000) | ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF);
        } else {
            throw new IndexOutOfBoundsException();
        }
    }

    /**
     * Advances the logical position in the stream. Affects the running count also.
     * @param numBytes The number of bytes to advance.
     * @throws IndexOutOfBoundsException
     * @throws IllegalArgumentException
     */
    public void advance(int numBytes) {
        if (numBytes < 0) {
            // Positive offsets only
            throw new IllegalArgumentException();
        }
        // do arithmetic and comparison in long to ovoid potention integer overflow
        long longNewIndex = (long) mIndex + (long) numBytes;
        if (longNewIndex < (long) mBytes.length) {
            mReadCount += numBytes;
            mIndex += numBytes;
        } else {
            throw new IndexOutOfBoundsException();
        }
    }

    /**
     * Reverse the logical position in the stream. Affects the running count also.
     * @param numBytes The (positive) number of bytes to reverse.
     * @throws IndexOutOfBoundsException
     * @throws IllegalArgumentException
     */
    public void reverse(int numBytes) {
        if (numBytes < 0) {
            // Positive (reverse) offsets only
            throw new IllegalArgumentException();
        }
        if (mIndex >= numBytes) {
            mReadCount -= numBytes;
            mIndex -= numBytes;
        } else {
            throw new IndexOutOfBoundsException();
        }
    }

    /**
     * @return The number of bytes available to be read in the stream.
     */
    public int available() {
        return mBytes.length - mIndex;
    }
}
Loading