diff --git a/services/usb/java/com/android/server/usb/descriptors/ByteStream.java b/services/usb/java/com/android/server/usb/descriptors/ByteStream.java index d678931fd01a4..1e823b63d5b2c 100644 --- a/services/usb/java/com/android/server/usb/descriptors/ByteStream.java +++ b/services/usb/java/com/android/server/usb/descriptors/ByteStream.java @@ -15,7 +15,11 @@ */ package com.android.server.usb.descriptors; +// Framework builds and Android Studio builds use different imports for NonNull. +// This one for Framework builds import android.annotation.NonNull; +// this one in the AndroidStudio project +// import android.support.annotation.NonNull; /** * @hide @@ -23,7 +27,7 @@ import android.annotation.NonNull; * but with the capability to "back up" in situations where the parser discovers that a * UsbDescriptor has overrun its length. */ -public class ByteStream { +public final class ByteStream { private static final String TAG = "ByteStream"; /** The byte array being wrapped */ @@ -103,6 +107,20 @@ public class ByteStream { } } + /** + * @return the next byte from the stream and advances the stream and the read count. Note + * that this is an unsigned byte encoded in a Java int. + * @throws IndexOutOfBoundsException + */ + public int getUnsignedByte() { + if (available() > 0) { + mReadCount++; + return mBytes[mIndex++] & 0x000000FF; + } 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 @@ -111,11 +129,11 @@ public class ByteStream { * next 2 bytes in the stream. * @throws IndexOutOfBoundsException */ - public int unpackUsbWord() { + public int unpackUsbShort() { if (available() >= 2) { - int b0 = getByte(); - int b1 = getByte(); - return ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF); + int b0 = getUnsignedByte(); + int b1 = getUnsignedByte(); + return (b1 << 8) | b0; } else { throw new IndexOutOfBoundsException(); } @@ -131,15 +149,31 @@ public class ByteStream { */ public int unpackUsbTriple() { if (available() >= 3) { - int b0 = getByte(); - int b1 = getByte(); - int b2 = getByte(); - return ((b2 << 16) & 0x00FF0000) | ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF); + int b0 = getUnsignedByte(); + int b1 = getUnsignedByte(); + int b2 = getUnsignedByte(); + return (b2 << 16) | (b1 << 8) | b0; } else { throw new IndexOutOfBoundsException(); } } + /** + * Reads 4 bytes in *little endian format* from the stream and composes a 32-bit integer. + * @return The 32-bit integer encoded by the next 4 bytes in the stream. + * @throws IndexOutOfBoundsException + */ + public int unpackUsbInt() { + if (available() >= 4) { + int b0 = getUnsignedByte(); + int b1 = getUnsignedByte(); + int b2 = getUnsignedByte(); + int b3 = getUnsignedByte(); + return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; + } else { + throw new IndexOutOfBoundsException(); + } + } /** * Advances the logical position in the stream. Affects the running count also. * @param numBytes The number of bytes to advance. diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACHeader.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACHeader.java similarity index 60% rename from services/usb/java/com/android/server/usb/descriptors/UsbACHeader.java rename to services/usb/java/com/android/server/usb/descriptors/Usb10ACHeader.java index e31438c58e06f..a35b46318e23b 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACHeader.java +++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACHeader.java @@ -15,18 +15,16 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; + /** * @hide * An audio class-specific Interface Header. * see audio10.pdf section 4.3.2 */ -public class UsbACHeader extends UsbACInterface { - private static final String TAG = "ACHeader"; +public final class Usb10ACHeader extends UsbACHeaderInterface { + private static final String TAG = "Usb10ACHeader"; - private int mADCRelease; // 3:2 Audio Device Class Specification Release (BCD). - private int mTotalLength; // 5:2 Total number of bytes returned for the class-specific - // AudioControl interface descriptor. Includes the combined length - // of this descriptor header and all Unit and Terminal descriptors. private byte mNumInterfaces = 0; // 7:1 The number of AudioStreaming and MIDIStreaming // interfaces in the Audio Interface Collection to which this // AudioControl interface belongs: n @@ -34,16 +32,8 @@ public class UsbACHeader extends UsbACInterface { // numbers associate with this endpoint private byte mControls; // Vers 2.0 thing - public UsbACHeader(int length, byte type, byte subtype, byte subclass) { - super(length, type, subtype, subclass); - } - - public int getADCRelease() { - return mADCRelease; - } - - public int getTotalLength() { - return mTotalLength; + public Usb10ACHeader(int length, byte type, byte subtype, byte subclass, int spec) { + super(length, type, subtype, subclass, spec); } public byte getNumInterfaces() { @@ -60,9 +50,8 @@ public class UsbACHeader extends UsbACInterface { @Override public int parseRawDescriptors(ByteStream stream) { - mADCRelease = stream.unpackUsbWord(); - mTotalLength = stream.unpackUsbWord(); + mTotalLength = stream.unpackUsbShort(); if (mADCRelease >= 0x200) { mControls = stream.getByte(); } else { @@ -75,4 +64,30 @@ public class UsbACHeader extends UsbACInterface { return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + int numInterfaces = getNumInterfaces(); + StringBuilder sb = new StringBuilder(); + sb.append("" + numInterfaces + " Interfaces"); + if (numInterfaces > 0) { + sb.append(" ["); + byte[] interfaceNums = getInterfaceNums(); + if (interfaceNums != null) { + for (int index = 0; index < numInterfaces; index++) { + sb.append("" + interfaceNums[index]); + if (index < numInterfaces - 1) { + sb.append(" "); + } + } + } + sb.append("]"); + } + canvas.writeListItem(sb.toString()); + canvas.writeListItem("Controls: " + ReportCanvas.getHexString(getControls())); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACInputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACInputTerminal.java similarity index 70% rename from services/usb/java/com/android/server/usb/descriptors/UsbACInputTerminal.java rename to services/usb/java/com/android/server/usb/descriptors/Usb10ACInputTerminal.java index 653a7de5457e6..2363c4dd8009b 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACInputTerminal.java +++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACInputTerminal.java @@ -15,13 +15,15 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; + /** * @hide * An audio class-specific Input Terminal interface. * see audio10.pdf section 4.3.2.1 */ -public class UsbACInputTerminal extends UsbACTerminal { - private static final String TAG = "ACInputTerminal"; +public final class Usb10ACInputTerminal extends UsbACTerminal { + private static final String TAG = "Usb10ACInputTerminal"; private byte mNrChannels; // 7:1 1 Channel (0x01) // Number of logical output channels in the @@ -30,7 +32,7 @@ public class UsbACInputTerminal extends UsbACTerminal { private byte mChannelNames; // 10:1 Unused (0x00) private byte mTerminal; // 11:1 Unused (0x00) - public UsbACInputTerminal(int length, byte type, byte subtype, byte subclass) { + public Usb10ACInputTerminal(int length, byte type, byte subtype, byte subclass) { super(length, type, subtype, subclass); } @@ -55,10 +57,22 @@ public class UsbACInputTerminal extends UsbACTerminal { super.parseRawDescriptors(stream); mNrChannels = stream.getByte(); - mChannelConfig = stream.unpackUsbWord(); + mChannelConfig = stream.unpackUsbShort(); mChannelNames = stream.getByte(); mTerminal = stream.getByte(); return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Associated Terminal: " + + ReportCanvas.getHexString(getAssocTerminal())); + canvas.writeListItem("" + getNrChannels() + " Chans. Config: " + + ReportCanvas.getHexString(getChannelConfig())); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java new file mode 100644 index 0000000000000..d3486643ede2f --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java @@ -0,0 +1,108 @@ +/* + * 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 com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * An audio class-specific Mixer Interface. + * see audio10.pdf section 4.3.2.3 + */ +public final class Usb10ACMixerUnit extends UsbACMixerUnit { + private static final String TAG = "Usb10ACMixerUnit"; + + private int mChannelConfig; // Spatial location of output channels + private byte mChanNameID; // First channel name string descriptor ID + private byte[] mControls; // bitmasks of which controls are present for each channel + private byte mNameID; // string descriptor ID of mixer name + + public Usb10ACMixerUnit(int length, byte type, byte subtype, byte subClass) { + super(length, type, subtype, subClass); + } + + public int getChannelConfig() { + return mChannelConfig; + } + + public byte getChanNameID() { + return mChanNameID; + } + + public byte[] getControls() { + return mControls; + } + + public byte getNameID() { + return mNameID; + } + + @Override + public int parseRawDescriptors(ByteStream stream) { + super.parseRawDescriptors(stream); + + mChannelConfig = stream.unpackUsbShort(); + mChanNameID = stream.getByte(); + + int controlArraySize = calcControlArraySize(mNumInputs, mNumOutputs); + mControls = new byte[controlArraySize]; + for (int index = 0; index < controlArraySize; index++) { + mControls[index] = stream.getByte(); + } + + mNameID = stream.getByte(); + + return mLength; + } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.writeParagraph("Mixer Unit", false); + canvas.openList(); + + canvas.writeListItem("Unit ID: " + ReportCanvas.getHexString(getUnitID())); + byte numInputs = getNumInputs(); + byte[] inputIDs = getInputIDs(); + canvas.openListItem(); + canvas.write("Num Inputs: " + numInputs + " ["); + for (int input = 0; input < numInputs; input++) { + canvas.write("" + ReportCanvas.getHexString(inputIDs[input])); + if (input < numInputs - 1) { + canvas.write(" "); + } + } + canvas.write("]"); + canvas.closeListItem(); + + canvas.writeListItem("Num Outputs: " + getNumOutputs()); + canvas.writeListItem("Channel Config: " + ReportCanvas.getHexString(getChannelConfig())); + + byte[] controls = getControls(); + canvas.openListItem(); + canvas.write("Controls: " + controls.length + " ["); + for (int ctrl = 0; ctrl < controls.length; ctrl++) { + canvas.write("" + controls[ctrl]); + if (ctrl < controls.length - 1) { + canvas.write(" "); + } + } + canvas.write("]"); + canvas.closeListItem(); + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACOutputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACOutputTerminal.java similarity index 71% rename from services/usb/java/com/android/server/usb/descriptors/UsbACOutputTerminal.java rename to services/usb/java/com/android/server/usb/descriptors/Usb10ACOutputTerminal.java index f957e3dbe217b..9f2f09ec146cc 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACOutputTerminal.java +++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACOutputTerminal.java @@ -15,18 +15,20 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; + /** * @hide * An audio class-specific Output Terminal Interface. * see audio10.pdf section 4.3.2.2 */ -public class UsbACOutputTerminal extends UsbACTerminal { - private static final String TAG = "ACOutputTerminal"; +public final class Usb10ACOutputTerminal extends UsbACTerminal { + private static final String TAG = "Usb10ACOutputTerminal"; private byte mSourceID; // 7:1 From Input Terminal. (0x01) private byte mTerminal; // 8:1 Unused. - public UsbACOutputTerminal(int length, byte type, byte subtype, byte subClass) { + public Usb10ACOutputTerminal(int length, byte type, byte subtype, byte subClass) { super(length, type, subtype, subClass); } @@ -46,4 +48,13 @@ public class UsbACOutputTerminal extends UsbACTerminal { mTerminal = stream.getByte(); return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Source ID: " + ReportCanvas.getHexString(getSourceID())); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASFormatI.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatI.java similarity index 62% rename from services/usb/java/com/android/server/usb/descriptors/UsbASFormatI.java rename to services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatI.java index 347a6cffb525f..1523bb528a03d 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbASFormatI.java +++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatI.java @@ -15,13 +15,15 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; + /** * @hide * An audio class-specific Format I interface. * see Frmts10.pdf section 2.2 */ -public class UsbASFormatI extends UsbASFormat { - private static final String TAG = "ASFormatI"; +public final class Usb10ASFormatI extends UsbASFormat { + private static final String TAG = "Usb10ASFormatI"; private byte mNumChannels; // 4:1 private byte mSubframeSize; // 5:1 frame size in bytes @@ -31,7 +33,7 @@ public class UsbASFormatI extends UsbASFormat { // min & max rates otherwise mSamFreqType rates. // All 3-byte values. All rates in Hz - public UsbASFormatI(int length, byte type, byte subtype, byte formatType, byte subclass) { + public Usb10ASFormatI(int length, byte type, byte subtype, byte formatType, byte subclass) { super(length, type, subtype, formatType, subclass); } @@ -51,10 +53,23 @@ public class UsbASFormatI extends UsbASFormat { return mSampleFreqType; } + @Override public int[] getSampleRates() { return mSampleRates; } + @Override + public int[] getBitDepths() { + int[] depths = {mBitResolution}; + return depths; + } + + @Override + public int[] getChannelCounts() { + int[] counts = {mNumChannels}; + return counts; + } + @Override public int parseRawDescriptors(ByteStream stream) { mNumChannels = stream.getByte(); @@ -74,4 +89,28 @@ public class UsbASFormatI extends UsbASFormat { return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("" + getNumChannels() + " Channels."); + canvas.writeListItem("Subframe Size: " + getSubframeSize()); + canvas.writeListItem("Bit Resolution: " + getBitResolution()); + byte sampleFreqType = getSampleFreqType(); + int[] sampleRates = getSampleRates(); + canvas.writeListItem("Sample Freq Type: " + sampleFreqType); + canvas.openList(); + if (sampleFreqType == 0) { + canvas.writeListItem("min: " + sampleRates[0]); + canvas.writeListItem("max: " + sampleRates[1]); + } else { + for (int index = 0; index < sampleFreqType; index++) { + canvas.writeListItem("" + sampleRates[index]); + } + } + canvas.closeList(); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASFormatII.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatII.java similarity index 66% rename from services/usb/java/com/android/server/usb/descriptors/UsbASFormatII.java rename to services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatII.java index abdc62145aa27..b1e7680ee1b9b 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbASFormatII.java +++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatII.java @@ -15,13 +15,15 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; + /** * @hide * An audio class-specific Format II interface. * see Frmts10.pdf section 2.3 */ -public class UsbASFormatII extends UsbASFormat { - private static final String TAG = "ASFormatII"; +public final class Usb10ASFormatII extends UsbASFormat { + private static final String TAG = "Usb10ASFormatII"; private int mMaxBitRate; // 4:2 Indicates the maximum number of bits per second this // interface can handle. Expressed in kbits/s. @@ -36,7 +38,7 @@ public class UsbASFormatII extends UsbASFormat { // the min & max rates. otherwise mSamFreqType rates. // All 3-byte values. All rates in Hz - public UsbASFormatII(int length, byte type, byte subtype, byte formatType, byte subclass) { + public Usb10ASFormatII(int length, byte type, byte subtype, byte formatType, byte subclass) { super(length, type, subtype, formatType, subclass); } @@ -58,8 +60,8 @@ public class UsbASFormatII extends UsbASFormat { @Override public int parseRawDescriptors(ByteStream stream) { - mMaxBitRate = stream.unpackUsbWord(); - mSamplesPerFrame = stream.unpackUsbWord(); + mMaxBitRate = stream.unpackUsbShort(); + mSamplesPerFrame = stream.unpackUsbShort(); mSamFreqType = stream.getByte(); int numFreqs = mSamFreqType == 0 ? 2 : mSamFreqType; mSampleRates = new int[numFreqs]; @@ -69,4 +71,29 @@ public class UsbASFormatII extends UsbASFormat { return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Max Bit Rate: " + getMaxBitRate()); + canvas.writeListItem("Samples Per Frame: " + getMaxBitRate()); + byte sampleFreqType = getSamFreqType(); + int[] sampleRates = getSampleRates(); + canvas.writeListItem("Sample Freq Type: " + sampleFreqType); + canvas.openList(); + if (sampleFreqType == 0) { + canvas.writeListItem("min: " + sampleRates[0]); + canvas.writeListItem("max: " + sampleRates[1]); + } else { + for (int index = 0; index < sampleFreqType; index++) { + canvas.writeListItem("" + sampleRates[index]); + } + } + canvas.closeList(); + + canvas.closeList(); + } + } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASGeneral.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ASGeneral.java similarity index 68% rename from services/usb/java/com/android/server/usb/descriptors/UsbASGeneral.java rename to services/usb/java/com/android/server/usb/descriptors/Usb10ASGeneral.java index c4f42d3182138..2d4f604ed1a19 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbASGeneral.java +++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ASGeneral.java @@ -15,13 +15,16 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; +import com.android.server.usb.descriptors.report.UsbStrings; + /** * @hide * An audio class-specific General interface. * see audio10.pdf section 4.5.2 */ -public class UsbASGeneral extends UsbACInterface { - private static final String TAG = "ACGeneral"; +public final class Usb10ASGeneral extends UsbACInterface { + private static final String TAG = "Usb10ASGeneral"; // audio10.pdf - section 4.5.2 private byte mTerminalLink; // 3:1 The Terminal ID of the Terminal to which the endpoint @@ -31,7 +34,7 @@ public class UsbASGeneral extends UsbACInterface { private int mFormatTag; // 5:2 The Audio Data Format that has to be used to communicate // with this interface. - public UsbASGeneral(int length, byte type, byte subtype, byte subclass) { + public Usb10ASGeneral(int length, byte type, byte subtype, byte subclass) { super(length, type, subtype, subclass); } @@ -51,8 +54,20 @@ public class UsbASGeneral extends UsbACInterface { public int parseRawDescriptors(ByteStream stream) { mTerminalLink = stream.getByte(); mDelay = stream.getByte(); - mFormatTag = stream.unpackUsbWord(); + mFormatTag = stream.unpackUsbShort(); return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Delay: " + mDelay); + canvas.writeListItem("Terminal Link: " + mTerminalLink); + canvas.writeListItem("Format: " + UsbStrings.getAudioFormatName(mFormatTag) + " - " + + ReportCanvas.getHexString(mFormatTag)); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java new file mode 100644 index 0000000000000..eefae3d51b3fa --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java @@ -0,0 +1,62 @@ +/* + * 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 com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * An audio class-specific Header descriptor. + * see Audio20.pdf section 4.7.2 Class-Specific AC Interface Descriptor + */ +public final class Usb20ACHeader extends UsbACHeaderInterface { + private static final String TAG = "Usb20ACHeader"; + + private byte mCategory; // 5:1 Constant, indicating the primary use of this audio function. + // See audio20.pdf Appendix A.7, “Audio Function Category Codes.” + private byte mControls; // 8:1 See audio20.pdf Table 4-5. + + public Usb20ACHeader(int length, byte type, byte subtype, byte subclass, int spec) { + super(length, type, subtype, subclass, spec); + } + + public byte getCategory() { + return mCategory; + } + + public byte getControls() { + return mControls; + } + + @Override + public int parseRawDescriptors(ByteStream stream) { + mCategory = stream.getByte(); + mTotalLength = stream.unpackUsbShort(); + mControls = stream.getByte(); + + return mLength; + } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Category: " + ReportCanvas.getHexString(getCategory())); + canvas.writeListItem("Controls: " + ReportCanvas.getHexString(getControls())); + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java new file mode 100644 index 0000000000000..3e2ac39c0aca1 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java @@ -0,0 +1,86 @@ +/* + * 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 com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * An audio class-specific Input Terminal interface. + * see Audio20.pdf section 3.13.2 Input Terminal + */ +public final class Usb20ACInputTerminal extends UsbACTerminal { + private static final String TAG = "Usb20ACInputTerminal"; + + // See Audio20.pdf - Table 4-9 + // Always 17 bytes + private byte mClkSourceID; // 7:1 - ID of the Clock Entity to which this Input + // Terminal is connected. + private byte mNumChannels; // 8:1 - Number of logical output channels in the + // Terminal’s output audio channel cluster. + private int mChanConfig; // 9:4 - Describes the spatial location of the + // logical channels. + private byte mChanNames; // 13:1 - Index of a string descriptor, describing the + // name of the first logical channel. + private int mControls; // 14:2 - Bitmask (see Audio20.pdf Table 4-9) + private byte mTerminalName; // 16:1 - Index of a string descriptor, describing the + // Input Terminal. + + public Usb20ACInputTerminal(int length, byte type, byte subtype, byte subclass) { + super(length, type, subtype, subclass); + } + + public byte getClkSourceID() { + return mClkSourceID; + } + + public byte getNumChannels() { + return mNumChannels; + } + + public int getChanConfig() { + return mChanConfig; + } + + public int getControls() { + return mControls; + } + + @Override + public int parseRawDescriptors(ByteStream stream) { + super.parseRawDescriptors(stream); + + mClkSourceID = stream.getByte(); + mNumChannels = stream.getByte(); + mChanConfig = stream.unpackUsbInt(); + mChanNames = stream.getByte(); + mControls = stream.unpackUsbShort(); + mTerminalName = stream.getByte(); + + return mLength; + } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Clock Source: " + getClkSourceID()); + canvas.writeListItem("" + getNumChannels() + " Channels. Config: " + + ReportCanvas.getHexString(getChanConfig())); + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java new file mode 100644 index 0000000000000..1b267a67752b4 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java @@ -0,0 +1,56 @@ +/* + * 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; + +/** + * @hide + * An audio class-specific Mixer Unit interface. + * see Audio20.pdf section 4.7.2.6 Mixer Unit Descriptor + */ +public final class Usb20ACMixerUnit extends UsbACMixerUnit { + private static final String TAG = "Usb20ACMixerUnit"; + + private int mChanConfig; // 6+p:4 Describes the spatial location of the + // logical channels. + private byte mChanNames; // 10+p:1 Index of a string descriptor, describing the + // name of the first logical channel. + private byte[] mControls; // 11+p:N bitmasks of which controls are present for each channel + // for N, see UsbACMixerUnit.calcControlArraySize() + private byte mControlsMask; // 11+p+N:1 bitmasks of which controls are present for each channel + private byte mNameID; // 12+p+N:1 Index of a string descriptor, describing the + // Mixer Unit. + + public Usb20ACMixerUnit(int length, byte type, byte subtype, byte subClass) { + super(length, type, subtype, subClass); + } + + @Override + public int parseRawDescriptors(ByteStream stream) { + super.parseRawDescriptors(stream); + + mChanConfig = stream.unpackUsbInt(); + mChanNames = stream.getByte(); + int controlArraySize = calcControlArraySize(mNumInputs, mNumOutputs); + mControls = new byte[controlArraySize]; + for (int index = 0; index < controlArraySize; index++) { + mControls[index] = stream.getByte(); + } + mControlsMask = stream.getByte(); + mNameID = stream.getByte(); + + return mLength; + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java new file mode 100644 index 0000000000000..67478aad8a598 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java @@ -0,0 +1,79 @@ +/* + * 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 com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * An audio class-specific Output Terminal interface. + * see Audio20.pdf section 3.13.3 Output Terminal + */ +public final class Usb20ACOutputTerminal extends UsbACTerminal { + private static final String TAG = "Usb20ACOutputTerminal"; + + // Audio20.pdf - section 4.7.2.5, Table 4-10 + // Always 12 bytes + private byte mSourceID; // 7:1 - ID of the Unit or Terminal to which this + // Terminal is connected. + private byte mClkSoureID; // 8:1 - ID of the Clock Entity to which this Output + // Terminal is connected. + private int mControls; // 9:2 - see Audio20.pdf Table 4-10 + private byte mTerminalID; // 11:1 - Index of a string descriptor, describing the + + public Usb20ACOutputTerminal(int length, byte type, byte subtype, byte subClass) { + super(length, type, subtype, subClass); + } + + public byte getSourceID() { + return mSourceID; + } + + public byte getClkSourceID() { + return mClkSoureID; + } + + public int getControls() { + return mControls; + } + + public byte getTerminalID() { + return mTerminalID; + } + + @Override + public int parseRawDescriptors(ByteStream stream) { + super.parseRawDescriptors(stream); + + mSourceID = stream.getByte(); + mClkSoureID = stream.getByte(); + mControls = stream.unpackUsbShort(); + mTerminalID = stream.getByte(); + + return mLength; + } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Clock Source ID: " + getClkSourceID()); + canvas.writeListItem("Controls: " + ReportCanvas.getHexString(getControls())); + canvas.writeListItem("Terminal Name ID: " + getTerminalID()); + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java new file mode 100644 index 0000000000000..c03199619e749 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java @@ -0,0 +1,69 @@ +/* + * 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 com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * An audio class-specific Format I interface. + * see Frmts20.pdf section 2.3.1.6 Type I Format Type Descriptor + */ +public final class Usb20ASFormatI extends UsbASFormat { + private static final String TAG = "Usb20ASFormatI"; + + // Frmts20.pdf Table 2-2: Type I Format Type Descriptor + private byte mSubSlotSize; // 4:1 The number of bytes occupied by one + // audio subslot. Can be 1, 2, 3 or 4. + private byte mBitResolution; // 5:1 The number of effectively used bits from + // the available bits in an audio subslot. + + public Usb20ASFormatI(int length, byte type, byte subtype, byte formatType, byte subclass) { + super(length, type, subtype, formatType, subclass); + } + + /** + * TBD + */ + public byte getSubSlotSize() { + return mSubSlotSize; + } + + /** + * TBD + */ + public byte getBitResolution() { + return mBitResolution; + } + + @Override + public int parseRawDescriptors(ByteStream stream) { + mSubSlotSize = stream.getByte(); + mBitResolution = stream.getByte(); + + return mLength; + } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Subslot Size: " + getSubSlotSize()); + canvas.writeListItem("Bit Resolution: " + getBitResolution()); + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java new file mode 100644 index 0000000000000..dc44ff063964d --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java @@ -0,0 +1,72 @@ +/* + * 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 com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * An audio class-specific Format II interface. + * see Frmts20.pdf section 2.3.2.6 Type II Format Type Descriptor + */ +public final class Usb20ASFormatII extends UsbASFormat { + private static final String TAG = "Usb20ASFormatII"; + + // Frmts20.pdf Table 2-3: Type II Format Type Descriptor + private int mMaxBitRate; // 4:2 Indicates the maximum number of bits per + // second this interface can handle in kbits/s. + private int mSlotsPerFrame; // 6:2 Indicates the number of PCM audio slots + // contained in one encoded audio frame. + + /** + * TBD + */ + public Usb20ASFormatII(int length, byte type, byte subtype, byte formatType, byte subclass) { + super(length, type, subtype, formatType, subclass); + } + + /** + * TBD + */ + public int getmaxBitRate() { + return mMaxBitRate; + } + + /** + * TBD + */ + public int getSlotsPerFrame() { + return mSlotsPerFrame; + } + + @Override + public int parseRawDescriptors(ByteStream stream) { + mMaxBitRate = stream.unpackUsbShort(); + mSlotsPerFrame = stream.unpackUsbShort(); + + return mLength; + } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Max Bit Rate: " + getmaxBitRate()); + canvas.writeListItem("slots Per Frame: " + getSlotsPerFrame()); + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIIEx.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIIEx.java new file mode 100644 index 0000000000000..d7dfba396984c --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIIEx.java @@ -0,0 +1,78 @@ +/* + * 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 com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * An audio class-specific Format II interface. + * see Frmts20.pdf section 2.4.2.1 Extended Type II Format Type Descriptor + */ +public final class Usb20ASFormatIIEx extends UsbASFormat { + private static final String TAG = "Usb20ASFormatIIEx"; + + // Frmts20.pdf Table 2-7: Extended Type II Format Type Descriptor + private int mMaxBitRate; // 4:2 Indicates the maximum number of bits per + // second this interface can handle in kbits/s + private int mSamplesPerFrame; // 6:2 Indicates the number of PCM audio + // samples contained in one encoded audio frame. + private byte mHeaderLength; // 8:1 Size of the Packet Header, in bytes. + private byte mSidebandProtocol; // 9:1 Constant, identifying the Side Band + // Protocol used for the Packet Header content. + + public Usb20ASFormatIIEx(int length, byte type, byte subtype, byte formatType, byte subclass) { + super(length, type, subtype, formatType, subclass); + } + + public int getMaxBitRate() { + return mMaxBitRate; + } + + public int getSamplesPerFrame() { + return mSamplesPerFrame; + } + + public byte getHeaderLength() { + return mHeaderLength; + } + + public byte getSidebandProtocol() { + return mSidebandProtocol; + } + + @Override + public int parseRawDescriptors(ByteStream stream) { + mMaxBitRate = stream.unpackUsbShort(); + mSamplesPerFrame = stream.unpackUsbShort(); + mHeaderLength = stream.getByte(); + mSidebandProtocol = stream.getByte(); + + return mLength; + } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Max Bit Rate: " + getMaxBitRate()); + canvas.writeListItem("Samples Per Frame: " + getSamplesPerFrame()); + canvas.writeListItem("Header Length: " + getHeaderLength()); + canvas.writeListItem("Sideband Protocol: " + getSidebandProtocol()); + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java new file mode 100644 index 0000000000000..b44a216703f83 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java @@ -0,0 +1,63 @@ +/* + * 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 com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * An audio class-specific Format III interface. + * see Frmts20.pdf section 2.3.1.6 2.3.3.1 Type III Format Type Descriptor + */ +public final class Usb20ASFormatIII extends UsbASFormat { + private static final String TAG = "Usb20ASFormatIII"; + + // frmts20.pdf Table 2-4: Type III Format Type Descriptor + private byte mSubslotSize; // 4:1 The number of bytes occupied by one + // audio subslot. Must be set to two. + private byte mBitResolution; // 5:1 The number of effectively used bits from + // the available bits in an audio subframe. + + public Usb20ASFormatIII(int length, byte type, byte subtype, byte formatType, byte subclass) { + super(length, type, subtype, formatType, subclass); + } + + public byte getSubslotSize() { + return mSubslotSize; + } + + public byte getBitResolution() { + return mBitResolution; + } + + @Override + public int parseRawDescriptors(ByteStream stream) { + mSubslotSize = stream.getByte(); + mBitResolution = stream.getByte(); + + return mLength; + } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Subslot Size: " + getSubslotSize()); + canvas.writeListItem("Bit Resolution: " + getBitResolution()); + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java new file mode 100644 index 0000000000000..18d48a0090988 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java @@ -0,0 +1,104 @@ +/* + * 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 com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * Audio20.pdf - 4.9.2 Class-Specific AS Interface Descriptor + * 16 bytes + */ +public final class Usb20ASGeneral extends UsbACInterface { + private static final String TAG = "Usb20ASGeneral"; + + // Audio20.pdf - Table 4-27 + private byte mTerminalLink; // 3:1 The Terminal ID of the Terminal to which + // this interface is connected. + private byte mControls; // 4:1 see audio20.pdf Table 4-27 + private byte mFormatType; // 5:1 Constant identifying the Format Type the + // AudioStreaming interface is using. + private int mFormats; // 6:4 The Audio Data Format(s) that can be + // used to communicate with this interface. + // See the USB Audio Data Formats + // document for further details. + private byte mNumChannels; // 10:1 Number of physical channels in the AS + // Interface audio channel cluster. + private int mChannelConfig; // 11:4 Describes the spatial location of the + // physical channels. + private byte mChannelNames; // 15:1 Index of a string descriptor, describing the + // name of the first physical channel. + + public Usb20ASGeneral(int length, byte type, byte subtype, byte subclass) { + super(length, type, subtype, subclass); + } + + public byte getTerminalLink() { + return mTerminalLink; + } + + public byte getControls() { + return mControls; + } + + public byte getFormatType() { + return mFormatType; + } + + public int getFormats() { + return mFormats; + } + + public byte getNumChannels() { + return mNumChannels; + } + + public int getChannelConfig() { + return mChannelConfig; + } + + public byte getChannelNames() { + return mChannelNames; + } + + @Override + public int parseRawDescriptors(ByteStream stream) { + + mTerminalLink = stream.getByte(); + mControls = stream.getByte(); + mFormatType = stream.getByte(); + mFormats = stream.unpackUsbInt(); + mNumChannels = stream.getByte(); + mChannelConfig = stream.unpackUsbInt(); + mChannelNames = stream.getByte(); + + return mLength; + } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Terminal Link: " + getTerminalLink()); + canvas.writeListItem("Controls: " + ReportCanvas.getHexString(getControls())); + canvas.writeListItem("Format Type: " + ReportCanvas.getHexString(getFormatType())); + canvas.writeListItem("Formats: " + ReportCanvas.getHexString(getFormats())); + canvas.writeListItem("Num Channels: " + getNumChannels()); + canvas.writeListItem("Channel Config: " + ReportCanvas.getHexString(getChannelConfig())); + canvas.writeListItem("Channel Names String ID: " + getChannelNames()); + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java index 96fcc6a0b8db9..6e1ce07536c57 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java @@ -21,7 +21,7 @@ package com.android.server.usb.descriptors; * audio10.pdf section 4.4.2.1 */ public class UsbACAudioControlEndpoint extends UsbACEndpoint { - private static final String TAG = "ACAudioControlEndpoint"; + private static final String TAG = "UsbACAudioControlEndpoint"; private byte mAddress; // 2:1 The address of the endpoint on the USB device. // D7: Direction. 1 = IN endpoint @@ -64,7 +64,7 @@ public class UsbACAudioControlEndpoint extends UsbACEndpoint { mAddress = stream.getByte(); mAttribs = stream.getByte(); - mMaxPacketSize = stream.unpackUsbWord(); + mMaxPacketSize = stream.unpackUsbShort(); mInterval = stream.getByte(); return mLength; diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java index d387883d30499..d35190298df66 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java @@ -21,7 +21,7 @@ package com.android.server.usb.descriptors; * see audio10.pdf section 3.7.2 */ public class UsbACAudioStreamEndpoint extends UsbACEndpoint { - private static final String TAG = "ACAudioStreamEndpoint"; + private static final String TAG = "UsbACAudioStreamEndpoint"; //TODO data fields... public UsbACAudioStreamEndpoint(int length, byte type, byte subclass) { diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java index 223496ab016e8..4a6839d943ff3 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java @@ -23,7 +23,7 @@ import android.util.Log; * see audio10.pdf section 4.4.1.2 */ abstract class UsbACEndpoint extends UsbDescriptor { - private static final String TAG = "ACEndpoint"; + private static final String TAG = "UsbACEndpoint"; protected final byte mSubclass; // from the mSubclass member of the "enclosing" // Interface Descriptor, not the stream. @@ -50,7 +50,7 @@ abstract class UsbACEndpoint extends UsbDescriptor { } public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser, - int length, byte type) { + int length, byte type) { UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface(); byte subClass = interfaceDesc.getUsbSubclass(); switch (subClass) { diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java index 739fe5503a1d6..ab3903b402d9a 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java @@ -20,8 +20,8 @@ package com.android.server.usb.descriptors; * An audio class-specific Feature Unit Interface * see audio10.pdf section 3.5.5 */ -public class UsbACFeatureUnit extends UsbACInterface { - private static final String TAG = "ACFeatureUnit"; +public final class UsbACFeatureUnit extends UsbACInterface { + private static final String TAG = "UsbACFeatureUnit"; // audio10.pdf section 4.3.2.5 public static final int CONTROL_MASK_MUTE = 0x0001; diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java b/services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java new file mode 100644 index 0000000000000..01a355e2c6e49 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java @@ -0,0 +1,56 @@ +/* + * 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 com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * An audio class-specific Interface Header super class. + * see audio10.pdf section 4.3.2 & Audio20.pdf section 4.7.2 + */ +public abstract class UsbACHeaderInterface extends UsbACInterface { + private static final String TAG = "UsbACHeaderInterface"; + + protected int mADCRelease; // Audio Device Class Specification Release (BCD). + protected int mTotalLength; // Total number of bytes returned for the class-specific + // AudioControl interface descriptor. Includes the combined length + // of this descriptor header and all Unit and Terminal descriptors. + + public UsbACHeaderInterface( + int length, byte type, byte subtype, byte subclass, int adcRelease) { + super(length, type, subtype, subclass); + mADCRelease = adcRelease; + } + + public int getADCRelease() { + return mADCRelease; + } + + public int getTotalLength() { + return mTotalLength; + } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Release: " + ReportCanvas.getBCDString(getADCRelease())); + canvas.writeListItem("Total Length: " + getTotalLength()); + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java b/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java index 0ab7fccd2c3ba..df6c53fa9f524 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java @@ -17,13 +17,16 @@ package com.android.server.usb.descriptors; import android.util.Log; +import com.android.server.usb.descriptors.report.ReportCanvas; +import com.android.server.usb.descriptors.report.UsbStrings; + /** * @hide * An audio class-specific Interface. * see audio10.pdf section 4.3.2 */ public abstract class UsbACInterface extends UsbDescriptor { - private static final String TAG = "ACInterface"; + private static final String TAG = "UsbACInterface"; // Audio Control Subtypes public static final byte ACI_UNDEFINED = 0; @@ -35,6 +38,11 @@ public abstract class UsbACInterface extends UsbDescriptor { public static final byte ACI_FEATURE_UNIT = 6; public static final byte ACI_PROCESSING_UNIT = 7; public static final byte ACI_EXTENSION_UNIT = 8; + // Not handled yet + public static final byte ACI_CLOCK_SOURCE = 0x0A; + public static final byte ACI_CLOCK_SELECTOR = 0x0B; + public static final byte ACI_CLOCK_MULTIPLIER = 0x0C; + public static final byte ACI_SAMPLE_RATE_CONVERTER = 0x0D; // Audio Streaming Subtypes public static final byte ASI_UNDEFINED = 0; @@ -87,17 +95,39 @@ public abstract class UsbACInterface extends UsbDescriptor { return mSubclass; } - private static UsbDescriptor allocAudioControlDescriptor(ByteStream stream, - int length, byte type, byte subtype, byte subClass) { + private static UsbDescriptor allocAudioControlDescriptor(UsbDescriptorParser parser, + ByteStream stream, int length, byte type, byte subtype, byte subClass) { switch (subtype) { case ACI_HEADER: - return new UsbACHeader(length, type, subtype, subClass); + { + int acInterfaceSpec = stream.unpackUsbShort(); + parser.setACInterfaceSpec(acInterfaceSpec); + if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) { + return new Usb20ACHeader(length, type, subtype, subClass, acInterfaceSpec); + } else { + return new Usb10ACHeader(length, type, subtype, subClass, acInterfaceSpec); + } + } case ACI_INPUT_TERMINAL: - return new UsbACInputTerminal(length, type, subtype, subClass); + { + int acInterfaceSpec = parser.getACInterfaceSpec(); + if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) { + return new Usb20ACInputTerminal(length, type, subtype, subClass); + } else { + return new Usb10ACInputTerminal(length, type, subtype, subClass); + } + } case ACI_OUTPUT_TERMINAL: - return new UsbACOutputTerminal(length, type, subtype, subClass); + { + int acInterfaceSpec = parser.getACInterfaceSpec(); + if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) { + return new Usb20ACOutputTerminal(length, type, subtype, subClass); + } else { + return new Usb10ACOutputTerminal(length, type, subtype, subClass); + } + } case ACI_SELECTOR_UNIT: return new UsbACSelectorUnit(length, type, subtype, subClass); @@ -106,7 +136,14 @@ public abstract class UsbACInterface extends UsbDescriptor { return new UsbACFeatureUnit(length, type, subtype, subClass); case ACI_MIXER_UNIT: - return new UsbACMixerUnit(length, type, subtype, subClass); + { + int acInterfaceSpec = parser.getACInterfaceSpec(); + if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) { + return new Usb20ACMixerUnit(length, type, subtype, subClass); + } else { + return new Usb10ACMixerUnit(length, type, subtype, subClass); + } + } case ACI_PROCESSING_UNIT: case ACI_EXTENSION_UNIT: @@ -115,18 +152,24 @@ public abstract class UsbACInterface extends UsbDescriptor { default: Log.w(TAG, "Unknown Audio Class Interface subtype:0x" + Integer.toHexString(subtype)); - return null; + return new UsbACInterfaceUnparsed(length, type, subtype, subClass); } } - private static UsbDescriptor allocAudioStreamingDescriptor(ByteStream stream, - int length, byte type, byte subtype, byte subClass) { + private static UsbDescriptor allocAudioStreamingDescriptor(UsbDescriptorParser parser, + ByteStream stream, int length, byte type, byte subtype, byte subClass) { + //int spec = parser.getUsbSpec(); + int acInterfaceSpec = parser.getACInterfaceSpec(); switch (subtype) { case ASI_GENERAL: - return new UsbASGeneral(length, type, subtype, subClass); + if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) { + return new Usb20ASGeneral(length, type, subtype, subClass); + } else { + return new Usb10ASGeneral(length, type, subtype, subClass); + } case ASI_FORMAT_TYPE: - return UsbASFormat.allocDescriptor(stream, length, type, subtype, subClass); + return UsbASFormat.allocDescriptor(parser, stream, length, type, subtype, subClass); case ASI_FORMAT_SPECIFIC: case ASI_UNDEFINED: @@ -155,7 +198,6 @@ public abstract class UsbACInterface extends UsbDescriptor { // Fall through until we implement that descriptor case MSI_UNDEFINED: - // break; Fall through until we implement this descriptor default: Log.w(TAG, "Unknown MIDI Streaming Interface subtype:0x" + Integer.toHexString(subtype)); @@ -173,10 +215,12 @@ public abstract class UsbACInterface extends UsbDescriptor { byte subClass = interfaceDesc.getUsbSubclass(); switch (subClass) { case AUDIO_AUDIOCONTROL: - return allocAudioControlDescriptor(stream, length, type, subtype, subClass); + return allocAudioControlDescriptor( + parser, stream, length, type, subtype, subClass); case AUDIO_AUDIOSTREAMING: - return allocAudioStreamingDescriptor(stream, length, type, subtype, subClass); + return allocAudioStreamingDescriptor( + parser, stream, length, type, subtype, subClass); case AUDIO_MIDISTREAMING: return allocMidiStreamingDescriptor(length, type, subtype, subClass); @@ -187,4 +231,21 @@ public abstract class UsbACInterface extends UsbDescriptor { return null; } } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + byte subClass = getSubclass(); + String subClassName = UsbStrings.getACInterfaceSubclassName(subClass); + + byte subtype = getSubtype(); + String subTypeName = UsbStrings.getACControlInterfaceName(subtype); + + canvas.openList(); + canvas.writeListItem("Subclass: " + ReportCanvas.getHexString(subClass) + + " " + subClassName); + canvas.writeListItem("Subtype: " + ReportCanvas.getHexString(subtype) + " " + subTypeName); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java b/services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java new file mode 100644 index 0000000000000..9e00a7976dfd4 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java @@ -0,0 +1,28 @@ +/* + * 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; + +/** + * @hide + * A holder class for as yet unparsed audio-class interfaces. + */ +public final class UsbACInterfaceUnparsed extends UsbACInterface { + private static final String TAG = "UsbACInterfaceUnparsed"; + + public UsbACInterfaceUnparsed(int length, byte type, byte subtype, byte subClass) { + super(length, type, subtype, subClass); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java index 9c072426cc497..9c314575ccc4d 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java @@ -15,13 +15,15 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; + /** * @hide * An audio class-specific Midi Endpoint. * see midi10.pdf section 6.2.2 */ -public class UsbACMidiEndpoint extends UsbACEndpoint { - private static final String TAG = "ACMidiEndpoint"; +public final class UsbACMidiEndpoint extends UsbACEndpoint { + private static final String TAG = "UsbACMidiEndpoint"; private byte mNumJacks; private byte[] mJackIds; @@ -49,4 +51,15 @@ public class UsbACMidiEndpoint extends UsbACEndpoint { } return mLength; } -} + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.writeHeader(3, "AC Midi Endpoint: " + ReportCanvas.getHexString(getType()) + + " Length: " + getLength()); + canvas.openList(); + canvas.writeListItem("" + getNumJacks() + " Jacks."); + canvas.closeList(); + } +} \ No newline at end of file diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java index 552b5ae308d68..88faed962a545 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java @@ -15,23 +15,14 @@ */ package com.android.server.usb.descriptors; -/** - * @hide - * An audio class-specific Mixer Interface. - * see audio10.pdf section 4.3.2.3 - */ public class UsbACMixerUnit extends UsbACInterface { - private static final String TAG = "ACMixerUnit"; + private static final String TAG = "UsbACMixerUnit"; - private byte mUnitID; // 3:1 - private byte mNumInputs; // 4:1 Number of Input Pins of this Unit. - private byte[] mInputIDs; // 5...:1 ID of the Unit or Terminal to which the Input Pins - // are connected. - private byte mNumOutputs; // The number of output channels - private int mChannelConfig; // Spacial location of output channels - private byte mChanNameID; // First channel name string descriptor ID - private byte[] mControls; // bitmasks of which controls are present for each channel - private byte mNameID; // string descriptor ID of mixer name + protected byte mUnitID; // 3:1 + protected byte mNumInputs; // 4:1 Number of Input Pins of this Unit. + protected byte[] mInputIDs; // 5...:1 ID of the Unit or Terminal to which the Input Pins + // are connected. + protected byte mNumOutputs; // The number of output channels public UsbACMixerUnit(int length, byte type, byte subtype, byte subClass) { super(length, type, subtype, subClass); @@ -53,20 +44,9 @@ public class UsbACMixerUnit extends UsbACInterface { return mNumOutputs; } - public int getChannelConfig() { - return mChannelConfig; - } - - public byte getChanNameID() { - return mChanNameID; - } - - public byte[] getControls() { - return mControls; - } - - public byte getNameID() { - return mNameID; + protected static int calcControlArraySize(int numInputs, int numOutputs) { + int totalChannels = numInputs * numOutputs; + return (totalChannels + 7) / 8; } @Override @@ -78,22 +58,6 @@ public class UsbACMixerUnit extends UsbACInterface { mInputIDs[input] = stream.getByte(); } mNumOutputs = stream.getByte(); - mChannelConfig = stream.unpackUsbWord(); - mChanNameID = stream.getByte(); - - int controlArraySize; - int totalChannels = mNumInputs * mNumOutputs; - if (totalChannels % 8 == 0) { - controlArraySize = totalChannels / 8; - } else { - controlArraySize = totalChannels / 8 + 1; - } - mControls = new byte[controlArraySize]; - for (int index = 0; index < controlArraySize; index++) { - mControls[index] = stream.getByte(); - } - - mNameID = stream.getByte(); return mLength; } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java index b1f60bdcf6ed0..b16bc575e806b 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java @@ -15,13 +15,15 @@ */ package com.android.server.usb.descriptors; +// import com.android.server.usb.descriptors.report.ReportCanvas; + /** * @hide * An audio class-specific Selector Unit Interface. * see audio10.pdf section 4.3.2.4 */ -public class UsbACSelectorUnit extends UsbACInterface { - private static final String TAG = "ACSelectorUnit"; +public final class UsbACSelectorUnit extends UsbACInterface { + private static final String TAG = "UsbACSelectorUnit"; private byte mUnitID; // 3:1 Constant uniquely identifying the Unit within the audio function. // This value is used in all requests to address this Unit. @@ -62,4 +64,11 @@ public class UsbACSelectorUnit extends UsbACInterface { return mLength; } + +// @Override +// public void report(ReportCanvas canvas) { +// super.report(canvas); +// +// //TODO +// } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java b/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java index ea80208ee3f37..2836508581d8b 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java @@ -15,10 +15,15 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; +import com.android.server.usb.descriptors.report.UsbStrings; + /** * @hide */ public abstract class UsbACTerminal extends UsbACInterface { + private static final String TAG = "UsbACTerminal"; + // Note that these fields are the same for both the // audio class-specific Output Terminal Interface.(audio10.pdf section 4.3.2.2) // and audio class-specific Input Terminal interface.(audio10.pdf section 4.3.2.1) @@ -46,9 +51,21 @@ public abstract class UsbACTerminal extends UsbACInterface { @Override public int parseRawDescriptors(ByteStream stream) { mTerminalID = stream.getByte(); - mTerminalType = stream.unpackUsbWord(); + mTerminalType = stream.unpackUsbShort(); mAssocTerminal = stream.getByte(); return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + int terminalType = getTerminalType(); + canvas.writeListItem("Type: " + ReportCanvas.getHexString(terminalType) + ": " + + UsbStrings.getTerminalName(terminalType)); + canvas.writeListItem("ID: " + ReportCanvas.getHexString(getTerminalID())); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java b/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java index d7c84c6a0965b..305ae2f273724 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java @@ -15,19 +15,30 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; +import com.android.server.usb.descriptors.report.UsbStrings; + /** * @hide * An audio class-specific Format Interface. * Subclasses: UsbACFormatI and UsbACFormatII. * see audio10.pdf section 4.5.3 & & Frmts10.pdf */ -public abstract class UsbASFormat extends UsbACInterface { - private static final String TAG = "ASFormat"; +public class UsbASFormat extends UsbACInterface { + private static final String TAG = "UsbASFormat"; private final byte mFormatType; // 3:1 FORMAT_TYPE_* - public static final byte FORMAT_TYPE_I = 1; - public static final byte FORMAT_TYPE_II = 2; + public static final byte FORMAT_TYPE_I = 1; + public static final byte FORMAT_TYPE_II = 2; + // these showed up in USB 2.0 + public static final byte FORMAT_TYPE_III = 3; + public static final byte FORMAT_TYPE_IV = 4; + + // "extended" formats + public static final byte EXT_FORMAT_TYPE_I = (byte) 0x81; + public static final byte EXT_FORMAT_TYPE_II = (byte) 0x82; + public static final byte EXT_FORMAT_TYPE_III = (byte) 0x83; public UsbASFormat(int length, byte type, byte subtype, byte formatType, byte mSubclass) { super(length, type, subtype, mSubclass); @@ -38,27 +49,59 @@ public abstract class UsbASFormat extends UsbACInterface { return mFormatType; } + public int[] getSampleRates() { + return null; + } + + public int[] getBitDepths() { + return null; + } + + public int[] getChannelCounts() { + return null; + } + /** * Allocates the audio-class format subtype associated with the format type read from the * stream. */ - public static UsbDescriptor allocDescriptor(ByteStream stream, int length, byte type, + public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser, + ByteStream stream, int length, byte type, byte subtype, byte subclass) { byte formatType = stream.getByte(); - //TODO - // There is an issue parsing format descriptors on (some) USB 2.0 pro-audio interfaces - // Since we don't need this info for headset detection, just skip these descriptors - // for now to avoid the (low) possibility of an IndexOutOfBounds exception. - switch (formatType) { -// case FORMAT_TYPE_I: -// return new UsbASFormatI(length, type, subtype, formatType, subclass); -// -// case FORMAT_TYPE_II: -// return new UsbASFormatII(length, type, subtype, formatType, subclass); + int acInterfaceSpec = parser.getACInterfaceSpec(); + switch (formatType) { + case FORMAT_TYPE_I: + if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) { + return new Usb20ASFormatI(length, type, subtype, formatType, subclass); + } else { + return new Usb10ASFormatI(length, type, subtype, formatType, subclass); + } + + case FORMAT_TYPE_II: + if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) { + return new Usb20ASFormatII(length, type, subtype, formatType, subclass); + } else { + return new Usb10ASFormatII(length, type, subtype, formatType, subclass); + } + + // USB 2.0 Exclusive Format Types + case FORMAT_TYPE_III: + return new Usb20ASFormatIII(length, type, subtype, formatType, subclass); + + case FORMAT_TYPE_IV: + //TODO - implement this type. default: - return null; + return new UsbASFormat(length, type, subtype, formatType, subclass); } } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.write(UsbStrings.getFormatName(getFormatType())); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java index 185cee20b0901..9710ac67870f3 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java @@ -25,7 +25,7 @@ import com.android.server.usb.descriptors.report.UsbStrings; * A class that just walks the descriptors and does a hex dump of the contained values. * Usefull as a debugging tool. */ -public class UsbBinaryParser { +public final class UsbBinaryParser { private static final String TAG = "UsbBinaryParser"; private static final boolean LOGGING = false; @@ -33,7 +33,7 @@ public class UsbBinaryParser { // Log if (LOGGING) { - Log.i(TAG, "l:" + length + " t:" + Integer.toHexString(type) + " " + Log.i(TAG, "l: " + length + " t: " + Integer.toHexString(type) + " " + UsbStrings.getDescriptorName(type)); StringBuilder sb = new StringBuilder(); for (int index = 2; index < length; index++) { @@ -43,7 +43,7 @@ public class UsbBinaryParser { } else { // Screen Dump builder.append("
");
- builder.append(" l:" + length
+ builder.append(" l: " + length
+ " t:0x" + Integer.toHexString(type) + " "
+ UsbStrings.getDescriptorName(type) + " ");
+ } else {
+ mStringBuilder.append(" ");
+ }
+ }
+
+ @Override
+ public void closeParagraph() {
+ mStringBuilder.append(" ");
- }
-
- private void closeParagraph() {
- mStringBuilder.append("
");
for (int index = 2; index < length; index++) {
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
index 8ae6d0f1ee7e8..75279c61c4f02 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An USB Config Descriptor.
* see usb11.pdf section 9.6.2
*/
-public class UsbConfigDescriptor extends UsbDescriptor {
- private static final String TAG = "Config";
+public final class UsbConfigDescriptor extends UsbDescriptor {
+ private static final String TAG = "UsbConfigDescriptor";
private int mTotalLength; // 2:2 Total length in bytes of data returned
private byte mNumInterfaces; // 4:1 Number of Interfaces
@@ -35,6 +37,7 @@ public class UsbConfigDescriptor extends UsbDescriptor {
UsbConfigDescriptor(int length, byte type) {
super(length, type);
+ mHierarchyLevel = 2;
}
public int getTotalLength() {
@@ -63,7 +66,7 @@ public class UsbConfigDescriptor extends UsbDescriptor {
@Override
public int parseRawDescriptors(ByteStream stream) {
- mTotalLength = stream.unpackUsbWord();
+ mTotalLength = stream.unpackUsbShort();
mNumInterfaces = stream.getByte();
mConfigValue = stream.getByte();
mConfigIndex = stream.getByte();
@@ -72,4 +75,15 @@ public class UsbConfigDescriptor extends UsbDescriptor {
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Config # " + getConfigValue());
+ canvas.writeListItem(getNumInterfaces() + " Interfaces.");
+ canvas.writeListItem("Attributes: " + ReportCanvas.getHexString(getAttribs()));
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java
index 63b2d7f6aed7a..8c7565b790d24 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java
@@ -19,6 +19,10 @@ import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDeviceConnection;
import android.util.Log;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+import com.android.server.usb.descriptors.report.Reporting;
+import com.android.server.usb.descriptors.report.UsbStrings;
+
/*
* Some notes about UsbDescriptor and its subclasses.
*
@@ -33,8 +37,10 @@ import android.util.Log;
* @hide
* Common superclass for all USB Descriptors.
*/
-public abstract class UsbDescriptor {
- private static final String TAG = "Descriptor";
+public abstract class UsbDescriptor implements Reporting {
+ private static final String TAG = "UsbDescriptor";
+
+ protected int mHierarchyLevel;
protected final int mLength; // 0:1 bLength Number Size of the Descriptor in Bytes (18 bytes)
// we store this as an int because Java bytes are SIGNED.
@@ -50,11 +56,15 @@ public abstract class UsbDescriptor {
public static final int STATUS_PARSED_OK = 1;
public static final int STATUS_PARSED_UNDERRUN = 2;
public static final int STATUS_PARSED_OVERRUN = 3;
+ public static final int STATUS_PARSE_EXCEPTION = 4;
+
private int mStatus = STATUS_UNPARSED;
private static String[] sStatusStrings = {
"UNPARSED", "PARSED - OK", "PARSED - UNDERRUN", "PARSED - OVERRUN"};
+ private int mOverUnderRunCount;
+
// Descriptor Type IDs
public static final byte DESCRIPTORTYPE_DEVICE = 0x01; // 1
public static final byte DESCRIPTORTYPE_CONFIG = 0x02; // 2
@@ -147,6 +157,10 @@ public abstract class UsbDescriptor {
mStatus = status;
}
+ public int getOverUnderRunCount() {
+ return mOverUnderRunCount;
+ }
+
public String getStatusString() {
return sStatusStrings[mStatus];
}
@@ -165,14 +179,16 @@ public abstract class UsbDescriptor {
// Too cold...
stream.advance(mLength - bytesRead);
mStatus = STATUS_PARSED_UNDERRUN;
+ mOverUnderRunCount = mLength - bytesRead;
Log.w(TAG, "UNDERRUN t:0x" + Integer.toHexString(mType)
- + " r:" + bytesRead + " < l:" + mLength);
+ + " r: " + bytesRead + " < l: " + mLength);
} else if (bytesRead > mLength) {
// Too hot...
stream.reverse(bytesRead - mLength);
mStatus = STATUS_PARSED_OVERRUN;
+ mOverUnderRunCount = bytesRead - mLength;
Log.w(TAG, "OVERRRUN t:0x" + Integer.toHexString(mType)
- + " r:" + bytesRead + " > l:" + mLength);
+ + " r: " + bytesRead + " > l: " + mLength);
} else {
// Just right!
mStatus = STATUS_PARSED_OK;
@@ -220,4 +236,43 @@ public abstract class UsbDescriptor {
}
return usbStr;
}
+
+ private void reportParseStatus(ReportCanvas canvas) {
+ int status = getStatus();
+ switch (status) {
+ case UsbDescriptor.STATUS_PARSED_OK:
+ break; // no need to report
+
+ case UsbDescriptor.STATUS_UNPARSED:
+ case UsbDescriptor.STATUS_PARSED_UNDERRUN:
+ case UsbDescriptor.STATUS_PARSED_OVERRUN:
+ canvas.writeParagraph("status: " + getStatusString()
+ + " [" + getOverUnderRunCount() + "]", true);
+ break;
+ }
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ String descTypeStr = UsbStrings.getDescriptorName(getType());
+ String text = descTypeStr + ": " + ReportCanvas.getHexString(getType())
+ + " Len: " + getLength();
+ if (mHierarchyLevel != 0) {
+ canvas.writeHeader(mHierarchyLevel, text);
+ } else {
+ canvas.writeParagraph(text, false);
+ }
+
+ if (getStatus() != STATUS_PARSED_OK) {
+ reportParseStatus(canvas);
+ }
+ }
+
+ @Override
+ public void shortReport(ReportCanvas canvas) {
+ String descTypeStr = UsbStrings.getDescriptorName(getType());
+ String text = descTypeStr + ": " + ReportCanvas.getHexString(getType())
+ + " Len: " + getLength();
+ canvas.writeParagraph(text, false);
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index d4a0ac4a0da37..ad7bde5c275e8 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -23,8 +23,8 @@ import java.util.ArrayList;
* @hide
* Class for parsing a binary stream of USB Descriptors.
*/
-public class UsbDescriptorParser {
- private static final String TAG = "DescriptorParser";
+public final class UsbDescriptorParser {
+ private static final String TAG = "UsbDescriptorParser";
// Descriptor Objects
private ArrayList");
+ }
+
+ @Override
+ public void closeList() {
+ mStringBuilder.append("
");
+ }
+
+ @Override
+ public void openListItem() {
+ mStringBuilder.append("");
- }
-
- private void closeList() {
- mStringBuilder.append("
");
- }
-
- private void openListItem() {
- mStringBuilder.append("
" + descrStr);
- }
- openList();
- writeListItem("class " + getHexString(usbClass) + ":" + className
- + " subclass " + getHexString(usbSubclass) + ":" + subclassName);
- writeListItem("" + descriptor.getNumEndpoints() + " endpoints");
- closeList();
- }
-
- private void tsReport(UsbEndpointDescriptor descriptor) {
- writeHeader(3, "Endpoint " + getHexString(descriptor.getType())
- + " len:" + descriptor.getLength());
- openList();
-
- byte address = descriptor.getEndpointAddress();
- writeListItem("address:"
- + getHexString(address & UsbEndpointDescriptor.MASK_ENDPOINT_ADDRESS)
- + ((address & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION)
- == UsbEndpointDescriptor.DIRECTION_OUTPUT ? " [out]" : " [in]"));
-
- byte attributes = descriptor.getAttributes();
- openListItem();
- mStringBuilder.append("attribs:" + getHexString(attributes) + " ");
- switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE) {
- case UsbEndpointDescriptor.TRANSTYPE_CONTROL:
- mStringBuilder.append("Control");
- break;
- case UsbEndpointDescriptor.TRANSTYPE_ISO:
- mStringBuilder.append("Iso");
- break;
- case UsbEndpointDescriptor.TRANSTYPE_BULK:
- mStringBuilder.append("Bulk");
- break;
- case UsbEndpointDescriptor.TRANSTYPE_INTERRUPT:
- mStringBuilder.append("Interrupt");
- break;
- }
- closeListItem();
-
- // These flags are only relevant for ISO transfer type
- if ((attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE)
- == UsbEndpointDescriptor.TRANSTYPE_ISO) {
- openListItem();
- mStringBuilder.append("sync:");
- switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_SYNCTYPE) {
- case UsbEndpointDescriptor.SYNCTYPE_NONE:
- mStringBuilder.append("NONE");
- break;
- case UsbEndpointDescriptor.SYNCTYPE_ASYNC:
- mStringBuilder.append("ASYNC");
- break;
- case UsbEndpointDescriptor.SYNCTYPE_ADAPTSYNC:
- mStringBuilder.append("ADAPTIVE ASYNC");
- break;
- }
- closeListItem();
-
- openListItem();
- mStringBuilder.append("useage:");
- switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_USEAGE) {
- case UsbEndpointDescriptor.USEAGE_DATA:
- mStringBuilder.append("DATA");
- break;
- case UsbEndpointDescriptor.USEAGE_FEEDBACK:
- mStringBuilder.append("FEEDBACK");
- break;
- case UsbEndpointDescriptor.USEAGE_EXPLICIT:
- mStringBuilder.append("EXPLICIT FEEDBACK");
- break;
- case UsbEndpointDescriptor.USEAGE_RESERVED:
- mStringBuilder.append("RESERVED");
- break;
- }
- closeListItem();
- }
- writeListItem("package size:" + descriptor.getPacketSize());
- writeListItem("interval:" + descriptor.getInterval());
- closeList();
- }
-
- private void tsReport(UsbHIDDescriptor descriptor) {
- String descr = UsbStrings.getDescriptorName(descriptor.getType());
- writeHeader(2, descr + " len:" + descriptor.getLength());
- openList();
- writeListItem("spec:" + getBCDString(descriptor.getRelease()));
- writeListItem("type:" + getBCDString(descriptor.getDescriptorType()));
- writeListItem("descriptor.getNumDescriptors() descriptors len:"
- + descriptor.getDescriptorLen());
- closeList();
- }
-
- private void tsReport(UsbACAudioControlEndpoint descriptor) {
- writeHeader(3, "AC Audio Control Endpoint:" + getHexString(descriptor.getType())
- + " length:" + descriptor.getLength());
- }
-
- private void tsReport(UsbACAudioStreamEndpoint descriptor) {
- writeHeader(3, "AC Audio Streaming Endpoint:"
- + getHexString(descriptor.getType())
- + " length:" + descriptor.getLength());
- }
-
- private void tsReport(UsbACHeader descriptor) {
- tsReport((UsbACInterface) descriptor);
-
- openList();
- writeListItem("spec:" + getBCDString(descriptor.getADCRelease()));
- int numInterfaces = descriptor.getNumInterfaces();
- writeListItem("" + numInterfaces + " interfaces");
- if (numInterfaces > 0) {
- openListItem();
- mStringBuilder.append("[");
- byte[] interfaceNums = descriptor.getInterfaceNums();
- if (numInterfaces != 0 && interfaceNums != null) {
- for (int index = 0; index < numInterfaces; index++) {
- mStringBuilder.append("" + interfaceNums[index]);
- if (index < numInterfaces - 1) {
- mStringBuilder.append(" ");
- }
- }
- }
- mStringBuilder.append("]");
- closeListItem();
- }
- writeListItem("controls:" + getHexString(descriptor.getControls()));
- closeList();
- }
-
- private void tsReport(UsbACFeatureUnit descriptor) {
- tsReport((UsbACInterface) descriptor);
- }
-
- private void tsReport(UsbACInterface descriptor) {
- String subClassName =
- descriptor.getSubclass() == UsbDescriptor.AUDIO_AUDIOCONTROL
- ? "AC Control"
- : "AC Streaming";
- byte subtype = descriptor.getSubtype();
- String subTypeStr = UsbStrings.getACControlInterfaceName(subtype);
- writeHeader(4, subClassName + " - " + getHexString(subtype)
- + ":" + subTypeStr + " len:" + descriptor.getLength());
- }
-
- private void tsReport(UsbACTerminal descriptor) {
- tsReport((UsbACInterface) descriptor);
- }
-
- private void tsReport(UsbACInputTerminal descriptor) {
- tsReport((UsbACTerminal) descriptor);
-
- openList();
- writeListItem("ID:" + getHexString(descriptor.getTerminalID()));
- int terminalType = descriptor.getTerminalType();
- writeListItem("Type:" + getHexString(terminalType) + ":"
- + UsbStrings.getTerminalName(terminalType) + "");
- writeListItem("AssocTerminal:" + getHexString(descriptor.getAssocTerminal()));
- writeListItem("" + descriptor.getNrChannels() + " chans. config:"
- + getHexString(descriptor.getChannelConfig()));
- closeList();
- }
-
- private void tsReport(UsbACOutputTerminal descriptor) {
- tsReport((UsbACTerminal) descriptor);
-
- openList();
- writeListItem("ID:" + getHexString(descriptor.getTerminalID()));
- int terminalType = descriptor.getTerminalType();
- writeListItem("Type:" + getHexString(terminalType) + ":"
- + UsbStrings.getTerminalName(terminalType) + "");
- writeListItem("AssocTerminal:" + getHexString(descriptor.getAssocTerminal()));
- writeListItem("Source:" + getHexString(descriptor.getSourceID()));
- closeList();
- }
-
- private void tsReport(UsbACMidiEndpoint descriptor) {
- writeHeader(3, "AC Midi Endpoint:" + getHexString(descriptor.getType())
- + " length:" + descriptor.getLength());
- openList();
- writeListItem("" + descriptor.getNumJacks() + " jacks.");
- closeList();
- }
-
- private void tsReport(UsbACMixerUnit descriptor) {
- tsReport((UsbACInterface) descriptor);
- openList();
-
- writeListItem("Unit ID:" + getHexString(descriptor.getUnitID()));
- byte numInputs = descriptor.getNumInputs();
- byte[] inputIDs = descriptor.getInputIDs();
- openListItem();
- mStringBuilder.append("Num Inputs:" + numInputs + " [");
- for (int input = 0; input < numInputs; input++) {
- mStringBuilder.append("" + getHexString(inputIDs[input]));
- if (input < numInputs - 1) {
- mStringBuilder.append(" ");
- }
- }
- mStringBuilder.append("]");
- closeListItem();
-
- writeListItem("Num Outputs:" + descriptor.getNumOutputs());
- writeListItem("Chan Config:" + getHexString(descriptor.getChannelConfig()));
-
- byte[] controls = descriptor.getControls();
- openListItem();
- mStringBuilder.append("controls:" + controls.length + " [");
- for (int ctrl = 0; ctrl < controls.length; ctrl++) {
- mStringBuilder.append("" + controls[ctrl]);
- if (ctrl < controls.length - 1) {
- mStringBuilder.append(" ");
- }
- }
- mStringBuilder.append("]");
- closeListItem();
- closeList();
- // byte mChanNameID; // First channel name string descriptor ID
- // byte mNameID; // string descriptor ID of mixer name
- }
-
- private void tsReport(UsbACSelectorUnit descriptor) {
- tsReport((UsbACInterface) descriptor);
- }
-
- private void tsReport(UsbASFormat descriptor) {
- writeHeader(4, "AC Streaming Format "
- + (descriptor.getFormatType() == UsbASFormat.FORMAT_TYPE_I ? "I" : "II")
- + " - " + getHexString(descriptor.getSubtype()) + ":"
- + " len:" + descriptor.getLength());
- }
-
- private void tsReport(UsbASFormatI descriptor) {
- tsReport((UsbASFormat) descriptor);
- openList();
- writeListItem("chans:" + descriptor.getNumChannels());
- writeListItem("subframe size:" + descriptor.getSubframeSize());
- writeListItem("bit resolution:" + descriptor.getBitResolution());
- byte sampleFreqType = descriptor.getSampleFreqType();
- int[] sampleRates = descriptor.getSampleRates();
- writeListItem("sample freq type:" + sampleFreqType);
- if (sampleFreqType == 0) {
- openList();
- writeListItem("min:" + sampleRates[0]);
- writeListItem("max:" + sampleRates[1]);
- closeList();
- } else {
- openList();
- for (int index = 0; index < sampleFreqType; index++) {
- writeListItem("" + sampleRates[index]);
- }
- closeList();
- }
- closeList();
- }
-
- private void tsReport(UsbASFormatII descriptor) {
- tsReport((UsbASFormat) descriptor);
- openList();
- writeListItem("max bit rate:" + descriptor.getMaxBitRate());
- writeListItem("samples per frame:" + descriptor.getMaxBitRate());
- byte sampleFreqType = descriptor.getSamFreqType();
- int[] sampleRates = descriptor.getSampleRates();
- writeListItem("sample freq type:" + sampleFreqType);
- if (sampleFreqType == 0) {
- openList();
- writeListItem("min:" + sampleRates[0]);
- writeListItem("max:" + sampleRates[1]);
- closeList();
- } else {
- openList();
- for (int index = 0; index < sampleFreqType; index++) {
- writeListItem("" + sampleRates[index]);
- }
- closeList();
- }
-
- closeList();
- }
-
- private void tsReport(UsbASGeneral descriptor) {
- tsReport((UsbACInterface) descriptor);
- openList();
- int formatTag = descriptor.getFormatTag();
- writeListItem("fmt:" + UsbStrings.getAudioFormatName(formatTag) + " - "
- + getHexString(formatTag));
- closeList();
- }
-
- private void tsReport(UsbInterfaceAssoc descriptor) {
- tsReport((UsbDescriptor) descriptor);
- }
-
- private void tsReport(UsbMSMidiHeader descriptor) {
- writeHeader(3, "MS Midi Header:" + getHexString(descriptor.getType())
- + " subType:" + getHexString(descriptor.getSubclass())
- + " length:" + descriptor.getSubclass());
- }
-
- private void tsReport(UsbMSMidiInputJack descriptor) {
- writeHeader(3, "MS Midi Input Jack:" + getHexString(descriptor.getType())
- + " subType:" + getHexString(descriptor.getSubclass())
- + " length:" + descriptor.getSubclass());
- }
-
- private void tsReport(UsbMSMidiOutputJack descriptor) {
- writeHeader(3, "MS Midi Output Jack:" + getHexString(descriptor.getType())
- + " subType:" + getHexString(descriptor.getSubclass())
- + " length:" + descriptor.getSubclass());
- }
-
- private void tsReport(UsbUnknown descriptor) {
- writeParagraph("Unknown Descriptor " + getHexString(descriptor.getType())
- + " len:" + descriptor.getLength() + "");
- dumpHexArray(descriptor.getRawData(), mStringBuilder);
- }
-}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
new file mode 100644
index 0000000000000..9e0adf55d87bc
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
@@ -0,0 +1,174 @@
+/*
+ * 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.report;
+
+import android.hardware.usb.UsbDeviceConnection;
+
+/**
+ * @hide
+ * Defines a class for generating report data in a variety of potential formats.
+ */
+public abstract class ReportCanvas {
+ private static final String TAG = "ReportCanvas";
+
+ private final UsbDeviceConnection mConnection;
+
+ /**
+ * Constructor.
+ * @param connection The USB connection object used to retrieve strings
+ * from the USB device.
+ */
+ public ReportCanvas(UsbDeviceConnection connection) {
+ mConnection = connection;
+ }
+
+ /**
+ * @returns the UsbDeviceConnection member (mConnection).
+ */
+ public UsbDeviceConnection getConnection() {
+ return mConnection;
+ }
+
+ /**
+ * Writes a plain string to the output.
+ */
+ public abstract void write(String text);
+
+ /**
+ * Opens a "header" formatted section in the output.
+ * @param level Specifies the logical level of the header.
+ */
+ public abstract void openHeader(int level);
+
+ /**
+ * Closes a "header" formatted section in the output.
+ * @param level Specifies the logical level of the header.
+ */
+ public abstract void closeHeader(int level);
+
+ /**
+ * Writes a "header" formatted string to the output.
+ * @param level Specifies the logical level of the header.
+ * @param text Specifies the text to display in the header.
+ */
+ public void writeHeader(int level, String text) {
+ openHeader(level);
+ write(text);
+ closeHeader(level);
+ }
+
+ /**
+ * Opens a paragraph construct in the output.
+ * @param emphasis Specifies whether the text in the paragraph should
+ * be displayed with "emphasis" formatting.
+ */
+ public abstract void openParagraph(boolean emphasis);
+
+ /**
+ * Closes a paragraph construct in the output.
+ */
+ public abstract void closeParagraph();
+
+ /**
+ * Writes a paragraph construct to the output.
+ * @param text The text to display with "paragraph" formatting.
+ * @param emphasis Specifies whether the text in the paragraph should
+ * be displayed with "emphasis" formatting.
+ */
+ public abstract void writeParagraph(String text, boolean emphasis);
+
+ /**
+ * Opens a "list" formatted section in the output.
+ */
+ public abstract void openList();
+
+ /**
+ * Closes a "list" formatted section in the output.
+ */
+ public abstract void closeList();
+
+ /**
+ * Opens a "list item" formatted section in the output.
+ */
+ public abstract void openListItem();
+
+ /**
+ * Closes a "list item" formatted section in the output.
+ */
+ public abstract void closeListItem();
+
+ /**
+ * Writes a "list item" formatted section in the output.
+ * @param text Specifies the text of the list item.
+ */
+ public void writeListItem(String text) {
+ openListItem();
+ write(text);
+ closeListItem();
+ }
+
+ /*
+ * Data Formating Helpers
+ */
+ /**
+ * Generates a hex representation of the specified byte value.
+ * @param value The value to format.
+ */
+ //TODO Look into renaming the "getHexString()" functions to be more
+ // representative of the types they handle.
+ public static String getHexString(byte value) {
+ return "0x" + Integer.toHexString(((int) value) & 0xFF).toUpperCase();
+ }
+
+ /**
+ * Generates a string representing a USB Binary-Coded Decimal value.
+ * @param valueBCD The value to format.
+ */
+ public static String getBCDString(int valueBCD) {
+ int major = (valueBCD >> 8) & 0x0F;
+ int minor = (valueBCD >> 4) & 0x0F;
+ int subminor = valueBCD & 0x0F;
+
+ return "" + major + "." + minor + subminor;
+ }
+
+ /**
+ * Generates a hex representation of the specified 16-bit integer value.
+ * @param value The value to format.
+ */
+ //TODO Look into renaming the "getHexString()" functions to be more
+ // representative of the types they handle.
+ public static String getHexString(int value) {
+ int intValue = value & 0xFFFF;
+ return "0x" + Integer.toHexString(intValue).toUpperCase();
+ }
+
+ /**
+ * Writes out the specified byte array to the provided StringBuilder.
+ * @param rawData The byte values.
+ * @param builder The StringBuilder to write text into.
+ */
+ public void dumpHexArray(byte[] rawData, StringBuilder builder) {
+ if (rawData != null) {
+ // Assume the type and Length and perhaps sub-type have been displayed
+ openParagraph(false);
+ for (int index = 0; index < rawData.length; index++) {
+ builder.append(getHexString(rawData[index]) + " ");
+ }
+ closeParagraph();
+ }
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/Reporter.java b/services/usb/java/com/android/server/usb/descriptors/report/Reporter.java
deleted file mode 100644
index 2944c10796f6a..0000000000000
--- a/services/usb/java/com/android/server/usb/descriptors/report/Reporter.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.report;
-
-import com.android.server.usb.descriptors.UsbDescriptor;
-
-/**
- * Declares the Reporter interface to provide HTML reporting for UsbDescriptor (sub)classes.
- *
- * NOTE: It is the responsibility of the implementor of this interface to correctly
- * interpret/decode the SPECIFIC UsbDescriptor subclass (perhaps with 'instanceof') that is
- * passed and handle that in the appropriate manner. This appears to be a
- * not very object-oriented approach, and that is true. This approach DOES however move the
- * complexity and 'plumbing' of reporting into the Reporter implementation and avoids needing
- * a (trivial) type-specific call to 'report()' in each UsbDescriptor (sub)class, instead
- * having just one in the top-level UsbDescriptor class. It also removes the need to add new
- * type-specific 'report()' methods to be added to Reporter interface whenever a
- * new UsbDescriptor subclass is defined. This seems like a pretty good trade-off.
- *
- * See HTMLReporter.java in this package for an example of type decoding.
- */
-public interface Reporter {
- /**
- * Generate report for this UsbDescriptor descriptor
- */
- void report(UsbDescriptor descriptor);
-}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java b/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java
index c13111b3e81c0..be7c12e4a5213 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java
@@ -16,12 +16,16 @@
package com.android.server.usb.descriptors.report;
/**
- * Declares the interface for classes that provide reporting functionality.
- * (This is the double-indirection aspect of the "Visitor" pattern.
+ * @hide
*/
public interface Reporting {
/**
- * Declares the report method that UsbDescriptor subclasses call.
+ * TBD
*/
- void report(Reporter reporter);
+ void report(ReportCanvas canvas);
+
+ /**
+ * TBD
+ */
+ void shortReport(ReportCanvas canvas);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
new file mode 100644
index 0000000000000..33746ba82bc6d
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
@@ -0,0 +1,108 @@
+/*
+ * 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.report;
+
+import android.hardware.usb.UsbDeviceConnection;
+
+/**
+ * @hide
+ * A concrete implementation of ReportCanvas class which generates "Plain Text" output.
+ */
+public final class TextReportCanvas extends ReportCanvas {
+ private static final String TAG = "TextReportCanvas";
+
+ private final StringBuilder mStringBuilder;
+ private int mListIndent;
+ private static final int LIST_INDENT_AMNT = 2;
+
+ /**
+ * Constructor. Connects plain-text output to the provided StringBuilder.
+ * @param connection The USB connection object used to retrieve strings
+ * from the USB device.
+ * @param stringBuilder Generated output gets written into this object.
+ */
+ public TextReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
+ super(connection);
+
+ mStringBuilder = stringBuilder;
+ }
+
+ @Override
+ public void write(String text) {
+ mStringBuilder.append(text);
+ }
+
+ @Override
+ public void openHeader(int level) {
+ mStringBuilder.append("[" + level + " - ");
+ }
+
+ @Override
+ public void closeHeader(int level) {
+ mStringBuilder.append("]\n");
+ }
+
+ @Override
+ public void openParagraph(boolean inRed) {
+ }
+
+ @Override
+ public void closeParagraph() {
+ mStringBuilder.append("\n");
+ }
+
+ @Override
+ public void writeParagraph(String text, boolean inRed) {
+ openParagraph(inRed);
+ if (inRed) {
+ mStringBuilder.append("*" + text + "*");
+ } else {
+ mStringBuilder.append(text);
+ }
+ closeParagraph();
+ }
+
+ private void writeListIndent() {
+ for (int space = 0; space < mListIndent; space++) {
+ mStringBuilder.append(" ");
+ }
+ }
+
+ @Override
+ public void openList() {
+ mListIndent += LIST_INDENT_AMNT;
+ writeListIndent();
+ mStringBuilder.append("---->\n");
+ }
+
+ @Override
+ public void closeList() {
+ writeListIndent();
+ mListIndent -= LIST_INDENT_AMNT;
+ mStringBuilder.append("<----\n");
+ }
+
+ @Override
+ public void openListItem() {
+ writeListIndent();
+ mStringBuilder.append(" - ");
+ }
+
+ @Override
+ public void closeListItem() {
+ mStringBuilder.append("\n");
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java b/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
index 0461150abd275..ff58a2672b3fb 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
@@ -16,6 +16,7 @@
package com.android.server.usb.descriptors.report;
import com.android.server.usb.descriptors.UsbACInterface;
+import com.android.server.usb.descriptors.UsbASFormat;
import com.android.server.usb.descriptors.UsbDescriptor;
import com.android.server.usb.descriptors.UsbTerminalTypes;
@@ -25,7 +26,7 @@ import java.util.HashMap;
* @hide
* A class to provide human-readable strings for various USB constants.
*/
-public class UsbStrings {
+public final class UsbStrings {
private static final String TAG = "UsbStrings";
private static HashMap