From fd7cb85feff517f3cc94384102933aa4485e1fc5 Mon Sep 17 00:00:00 2001 From: Paul McLean Date: Fri, 7 Jul 2017 08:14:52 -0600 Subject: [PATCH] Adding USB audio-class 2.0 spec descriptors. Added USB audio-class 2.0 format type descriptors. Added Tree parsing. Rearchitected reporting (again) to better support reuse and scale. Bug: 64301464 Test: Run code against representative USB audio peripherals and verify that each correctly handles or ignores all descriptors and the correct device semantics (headset / not-headset) are still calculated. Change-Id: I1b3b01ab1cd804ed876bf6427c3afba15eea6a6e --- .../android/server/usb/descriptors/ByteStream.java | 52 +- .../{UsbACHeader.java => Usb10ACHeader.java} | 51 +- ...nputTerminal.java => Usb10ACInputTerminal.java} | 22 +- .../server/usb/descriptors/Usb10ACMixerUnit.java | 108 ++++ ...putTerminal.java => Usb10ACOutputTerminal.java} | 17 +- .../{UsbASFormatI.java => Usb10ASFormatI.java} | 45 +- .../{UsbASFormatII.java => Usb10ASFormatII.java} | 37 +- .../{UsbASGeneral.java => Usb10ASGeneral.java} | 23 +- .../server/usb/descriptors/Usb20ACHeader.java | 62 +++ .../usb/descriptors/Usb20ACInputTerminal.java | 86 ++++ .../server/usb/descriptors/Usb20ACMixerUnit.java | 56 ++ .../usb/descriptors/Usb20ACOutputTerminal.java | 79 +++ .../server/usb/descriptors/Usb20ASFormatI.java | 69 +++ .../server/usb/descriptors/Usb20ASFormatII.java | 72 +++ .../server/usb/descriptors/Usb20ASFormatIIEx.java | 78 +++ .../server/usb/descriptors/Usb20ASFormatIII.java | 63 +++ .../server/usb/descriptors/Usb20ASGeneral.java | 104 ++++ .../usb/descriptors/UsbACAudioControlEndpoint.java | 4 +- .../usb/descriptors/UsbACAudioStreamEndpoint.java | 2 +- .../server/usb/descriptors/UsbACEndpoint.java | 4 +- .../server/usb/descriptors/UsbACFeatureUnit.java | 4 +- .../usb/descriptors/UsbACHeaderInterface.java | 56 ++ .../server/usb/descriptors/UsbACInterface.java | 91 +++- .../usb/descriptors/UsbACInterfaceUnparsed.java | 28 + .../server/usb/descriptors/UsbACMidiEndpoint.java | 19 +- .../server/usb/descriptors/UsbACMixerUnit.java | 54 +- .../server/usb/descriptors/UsbACSelectorUnit.java | 13 +- .../server/usb/descriptors/UsbACTerminal.java | 19 +- .../server/usb/descriptors/UsbASFormat.java | 73 ++- .../server/usb/descriptors/UsbBinaryParser.java | 6 +- .../usb/descriptors/UsbConfigDescriptor.java | 20 +- .../server/usb/descriptors/UsbDescriptor.java | 63 ++- .../usb/descriptors/UsbDescriptorParser.java | 71 ++- .../usb/descriptors/UsbDeviceDescriptor.java | 51 +- .../usb/descriptors/UsbEndpointDescriptor.java | 119 ++++- .../server/usb/descriptors/UsbHIDDescriptor.java | 23 +- .../server/usb/descriptors/UsbInterfaceAssoc.java | 13 +- .../usb/descriptors/UsbInterfaceDescriptor.java | 29 +- .../server/usb/descriptors/UsbMSMidiHeader.java | 15 +- .../server/usb/descriptors/UsbMSMidiInputJack.java | 15 +- .../usb/descriptors/UsbMSMidiOutputJack.java | 15 +- .../server/usb/descriptors/UsbTerminalTypes.java | 4 +- .../android/server/usb/descriptors/UsbUnknown.java | 4 +- .../usb/descriptors/report/HTMLReportCanvas.java | 97 ++++ .../usb/descriptors/report/HTMLReporter.java | 572 --------------------- .../usb/descriptors/report/ReportCanvas.java | 174 +++++++ .../server/usb/descriptors/report/Reporter.java | 40 -- .../server/usb/descriptors/report/Reporting.java | 12 +- .../usb/descriptors/report/TextReportCanvas.java | 108 ++++ .../server/usb/descriptors/report/UsbStrings.java | 42 +- .../tree/UsbDescriptorsACInterfaceNode.java | 46 ++ .../descriptors/tree/UsbDescriptorsConfigNode.java | 63 +++ .../descriptors/tree/UsbDescriptorsDeviceNode.java | 56 ++ .../tree/UsbDescriptorsEndpointNode.java | 42 ++ .../tree/UsbDescriptorsInterfaceNode.java | 83 +++ .../usb/descriptors/tree/UsbDescriptorsTree.java | 145 ++++++ .../descriptors/tree/UsbDescriptorsTreeNode.java | 41 ++ 57 files changed, 2533 insertions(+), 827 deletions(-) rename services/usb/java/com/android/server/usb/descriptors/{UsbACHeader.java => Usb10ACHeader.java} (60%) rename services/usb/java/com/android/server/usb/descriptors/{UsbACInputTerminal.java => Usb10ACInputTerminal.java} (70%) create mode 100644 services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java rename services/usb/java/com/android/server/usb/descriptors/{UsbACOutputTerminal.java => Usb10ACOutputTerminal.java} (71%) rename services/usb/java/com/android/server/usb/descriptors/{UsbASFormatI.java => Usb10ASFormatI.java} (62%) rename services/usb/java/com/android/server/usb/descriptors/{UsbASFormatII.java => Usb10ASFormatII.java} (66%) rename services/usb/java/com/android/server/usb/descriptors/{UsbASGeneral.java => Usb10ASGeneral.java} (68%) create mode 100644 services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIIEx.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java delete mode 100644 services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java delete mode 100644 services/usb/java/com/android/server/usb/descriptors/report/Reporter.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsACInterfaceNode.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsConfigNode.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsDeviceNode.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsEndpointNode.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsInterfaceNode.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTree.java create mode 100644 services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTreeNode.java 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 d678931fd01a..1e823b63d5b2 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 */ @@ -104,6 +108,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 * 0, essentially making the returned value *unsigned*. @@ -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,16 +149,32 @@ 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. * @throws IndexOutOfBoundsException 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 e31438c58e06..a35b46318e23 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 653a7de5457e..2363c4dd8009 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 000000000000..d3486643ede2 --- /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 f957e3dbe217..9f2f09ec146c 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 347a6cffb525..1523bb528a03 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,11 +53,24 @@ 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(); mSubframeSize = 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 abdc62145aa2..b1e7680ee1b9 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 c4f42d318213..2d4f604ed1a1 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 000000000000..eefae3d51b3f --- /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 000000000000..3e2ac39c0aca --- /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 000000000000..1b267a67752b --- /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 000000000000..67478aad8a59 --- /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 000000000000..c03199619e74 --- /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 000000000000..dc44ff063964 --- /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 000000000000..d7dfba396984 --- /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 000000000000..b44a216703f8 --- /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 000000000000..18d48a009098 --- /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 96fcc6a0b8db..6e1ce07536c5 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 d387883d3049..d35190298df6 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 223496ab016e..4a6839d943ff 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 739fe5503a1d..ab3903b402d9 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 000000000000..01a355e2c6e4 --- /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 0ab7fccd2c3b..df6c53fa9f52 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 000000000000..9e00a7976dfd --- /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 9c072426cc49..9c314575ccc4 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 552b5ae308d6..88faed962a54 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 b1f60bdcf6ed..b16bc575e806 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 ea80208ee3f3..2836508581d8 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 d7c84c6a0965..305ae2f27372 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. + int acInterfaceSpec = parser.getACInterfaceSpec(); + 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); + 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 185cee20b090..9710ac67870f 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) + "
"); 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 8ae6d0f1ee7e..75279c61c4f0 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 63b2d7f6aed7..8c7565b790d2 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 d4a0ac4a0da3..ad7bde5c275e 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 mDescriptors = new ArrayList(); @@ -32,9 +32,35 @@ public class UsbDescriptorParser { private UsbDeviceDescriptor mDeviceDescriptor; private UsbInterfaceDescriptor mCurInterfaceDescriptor; + // The AudioClass spec implemented by the AudioClass Interfaces + // This may well be different than the overall USB Spec. + // Obtained from the first AudioClass Header descriptor. + private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0; + public UsbDescriptorParser() {} /** + * @return the USB Spec value associated with the Device descriptor for the + * descriptors stream being parsed. + * + * @throws IllegalArgumentException + */ + public int getUsbSpec() { + if (mDeviceDescriptor != null) { + return mDeviceDescriptor.getSpec(); + } else { + throw new IllegalArgumentException(); + } + } + + public void setACInterfaceSpec(int spec) { + mACInterfacesSpec = spec; + } + + public int getACInterfaceSpec() { + return mACInterfacesSpec; + } + /** * The probability (as returned by getHeadsetProbability() at which we conclude * the peripheral is a headset. */ @@ -44,7 +70,7 @@ public class UsbDescriptorParser { private UsbDescriptor allocDescriptor(ByteStream stream) { stream.resetReadCount(); - int length = (int) stream.getByte() & 0x000000FF; + int length = stream.getUnsignedByte(); byte type = stream.getByte(); UsbDescriptor descriptor = null; @@ -99,7 +125,7 @@ public class UsbDescriptorParser { if (descriptor == null) { // Unknown Descriptor - Log.i(TAG, "Unknown Descriptor len:" + length + " type:0x" + Log.i(TAG, "Unknown Descriptor len: " + length + " type:0x" + Integer.toHexString(type)); descriptor = new UsbUnknown(length, type); } @@ -135,14 +161,15 @@ public class UsbDescriptorParser { try { descriptor.parseRawDescriptors(stream); - // Its OK to add the invalid descriptor as the postParse() - // routine will mark it as invalid. - mDescriptors.add(descriptor); - // Clean up descriptor.postParse(stream); } catch (Exception ex) { Log.e(TAG, "Exception parsing USB descriptors.", ex); + + // Clean up + descriptor.setStatus(UsbDescriptor.STATUS_PARSE_EXCEPTION); + } finally { + mDescriptors.add(descriptor); } } } @@ -197,7 +224,7 @@ public class UsbDescriptorParser { list.add(descriptor); } } else { - Log.w(TAG, "Unrecognized Interface l:" + descriptor.getLength() + Log.w(TAG, "Unrecognized Interface l: " + descriptor.getLength() + " t:0x" + Integer.toHexString(descriptor.getType())); } } @@ -220,7 +247,7 @@ public class UsbDescriptorParser { list.add(descriptor); } } else { - Log.w(TAG, "Unrecognized Audio Interface l:" + descriptor.getLength() + Log.w(TAG, "Unrecognized Audio Interface l: " + descriptor.getLength() + " t:0x" + Integer.toHexString(descriptor.getType())); } } @@ -251,7 +278,7 @@ public class UsbDescriptorParser { return true; } } else { - Log.w(TAG, "Undefined Audio Class Interface l:" + descriptor.getLength() + Log.w(TAG, "Undefined Audio Class Interface l: " + descriptor.getLength() + " t:0x" + Integer.toHexString(descriptor.getType())); } } @@ -274,8 +301,8 @@ public class UsbDescriptorParser { acDescriptors = getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL, UsbACInterface.AUDIO_AUDIOCONTROL); for (UsbDescriptor descriptor : acDescriptors) { - if (descriptor instanceof UsbACInputTerminal) { - UsbACInputTerminal inDescr = (UsbACInputTerminal) descriptor; + if (descriptor instanceof UsbACTerminal) { + UsbACTerminal inDescr = (UsbACTerminal) descriptor; if (inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_IN_MIC || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED @@ -284,7 +311,7 @@ public class UsbDescriptorParser { break; } } else { - Log.w(TAG, "Undefined Audio Input terminal l:" + descriptor.getLength() + Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength() + " t:0x" + Integer.toHexString(descriptor.getType())); } } @@ -295,8 +322,8 @@ public class UsbDescriptorParser { getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL, UsbACInterface.AUDIO_AUDIOCONTROL); for (UsbDescriptor descriptor : acDescriptors) { - if (descriptor instanceof UsbACOutputTerminal) { - UsbACOutputTerminal outDescr = (UsbACOutputTerminal) descriptor; + if (descriptor instanceof UsbACTerminal) { + UsbACTerminal outDescr = (UsbACTerminal) descriptor; if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES @@ -305,7 +332,7 @@ public class UsbDescriptorParser { break; } } else { - Log.w(TAG, "Undefined Audio Output terminal l:" + descriptor.getLength() + Log.w(TAG, "Undefined Audio Output terminal l: " + descriptor.getLength() + " t:0x" + Integer.toHexString(descriptor.getType())); } } @@ -328,6 +355,8 @@ public class UsbDescriptorParser { * to count on the peripheral being a headset. */ public boolean isInputHeadset() { + // TEMP + Log.i(TAG, "---- isInputHeadset() prob:" + (getInputHeadsetProbability() * 100f) + "%"); return getInputHeadsetProbability() >= IN_HEADSET_TRIGGER; } @@ -348,8 +377,8 @@ public class UsbDescriptorParser { getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL, UsbACInterface.AUDIO_AUDIOCONTROL); for (UsbDescriptor descriptor : acDescriptors) { - if (descriptor instanceof UsbACOutputTerminal) { - UsbACOutputTerminal outDescr = (UsbACOutputTerminal) descriptor; + if (descriptor instanceof UsbACTerminal) { + UsbACTerminal outDescr = (UsbACTerminal) descriptor; if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES @@ -358,7 +387,7 @@ public class UsbDescriptorParser { break; } } else { - Log.w(TAG, "Undefined Audio Output terminal l:" + descriptor.getLength() + Log.w(TAG, "Undefined Audio Output terminal l: " + descriptor.getLength() + " t:0x" + Integer.toHexString(descriptor.getType())); } } @@ -381,6 +410,8 @@ public class UsbDescriptorParser { * to count on the peripheral being a headset. */ public boolean isOutputHeadset() { + // TEMP + Log.i(TAG, "---- isOutputHeadset() prob:" + (getOutputHeadsetProbability() * 100f) + "%"); return getOutputHeadsetProbability() >= OUT_HEADSET_TRIGGER; } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java index 90848caba852..c8fa69451ac8 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java @@ -15,13 +15,20 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; +import com.android.server.usb.descriptors.report.UsbStrings; + /** * @hide * A USB Device Descriptor. * see usb11.pdf section 9.6.1 */ -/* public */ public class UsbDeviceDescriptor extends UsbDescriptor { - private static final String TAG = "Device"; +public final class UsbDeviceDescriptor extends UsbDescriptor { + private static final String TAG = "UsbDeviceDescriptor"; + + public static final int USBSPEC_1_0 = 0x0100; + public static final int USBSPEC_1_1 = 0x0110; + public static final int USBSPEC_2_0 = 0x0200; private int mSpec; // 2:2 bcdUSB 2 BCD USB Specification Number - BCD private byte mDevClass; // 4:1 class code @@ -39,6 +46,7 @@ package com.android.server.usb.descriptors; UsbDeviceDescriptor(int length, byte type) { super(length, type); + mHierarchyLevel = 1; } public int getSpec() { @@ -91,14 +99,14 @@ package com.android.server.usb.descriptors; @Override public int parseRawDescriptors(ByteStream stream) { - mSpec = stream.unpackUsbWord(); + mSpec = stream.unpackUsbShort(); mDevClass = stream.getByte(); mDevSubClass = stream.getByte(); mProtocol = stream.getByte(); mPacketSize = stream.getByte(); - mVendorID = stream.unpackUsbWord(); - mProductID = stream.unpackUsbWord(); - mDeviceRelease = stream.unpackUsbWord(); + mVendorID = stream.unpackUsbShort(); + mProductID = stream.unpackUsbShort(); + mDeviceRelease = stream.unpackUsbShort(); mMfgIndex = stream.getByte(); mProductIndex = stream.getByte(); mSerialNum = stream.getByte(); @@ -106,4 +114,35 @@ package com.android.server.usb.descriptors; return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + + int spec = getSpec(); + canvas.writeListItem("Spec: " + ReportCanvas.getBCDString(spec)); + + byte devClass = getDevClass(); + String classStr = UsbStrings.getClassName(devClass); + byte devSubClass = getDevSubClass(); + String subClasStr = UsbStrings.getClassName(devSubClass); + canvas.writeListItem("Class " + devClass + ": " + classStr + " Subclass" + + devSubClass + ": " + subClasStr); + canvas.writeListItem("Vendor ID: " + getVendorID() + + " Product ID: " + getProductID() + + " Product Release: " + ReportCanvas.getBCDString(getDeviceRelease())); + + byte mfgIndex = getMfgIndex(); + String manufacturer = + UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), mfgIndex); + byte productIndex = getProductIndex(); + String product = + UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), productIndex); + + canvas.writeListItem("Manufacturer " + mfgIndex + ": " + manufacturer + + " Product " + productIndex + ": " + product); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java index def670093e6e..6322fbe8b45b 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java @@ -15,36 +15,38 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; + /** * @hide * A Usb Endpoint Descriptor. * see usb11.pdf section 9.6.4 */ public class UsbEndpointDescriptor extends UsbDescriptor { - private static final String TAG = "EndPoint"; + private static final String TAG = "UsbEndpointDescriptor"; - public static final byte MASK_ENDPOINT_ADDRESS = 0b0001111; - public static final byte MASK_ENDPOINT_DIRECTION = (byte) 0b10000000; - public static final byte DIRECTION_OUTPUT = 0x00; - public static final byte DIRECTION_INPUT = (byte) 0x80; + public static final byte MASK_ENDPOINT_ADDRESS = 0b0001111; + public static final byte MASK_ENDPOINT_DIRECTION = (byte) 0b10000000; + public static final byte DIRECTION_OUTPUT = 0x00; + public static final byte DIRECTION_INPUT = (byte) 0x80; public static final byte MASK_ATTRIBS_TRANSTYPE = 0b00000011; - public static final byte TRANSTYPE_CONTROL = 0x00; - public static final byte TRANSTYPE_ISO = 0x01; - public static final byte TRANSTYPE_BULK = 0x02; - public static final byte TRANSTYPE_INTERRUPT = 0x03; - - public static final byte MASK_ATTRIBS_SYNCTYPE = 0b00001100; - public static final byte SYNCTYPE_NONE = 0b00000000; - public static final byte SYNCTYPE_ASYNC = 0b00000100; - public static final byte SYNCTYPE_ADAPTSYNC = 0b00001000; - public static final byte SYNCTYPE_RESERVED = 0b00001100; - - public static final byte MASK_ATTRIBS_USEAGE = 0b00110000; - public static final byte USEAGE_DATA = 0b00000000; - public static final byte USEAGE_FEEDBACK = 0b00010000; - public static final byte USEAGE_EXPLICIT = 0b00100000; - public static final byte USEAGE_RESERVED = 0b00110000; + public static final byte TRANSTYPE_CONTROL = 0x00; + public static final byte TRANSTYPE_ISO = 0x01; + public static final byte TRANSTYPE_BULK = 0x02; + public static final byte TRANSTYPE_INTERRUPT = 0x03; + + public static final byte MASK_ATTRIBS_SYNCTYPE = 0b00001100; + public static final byte SYNCTYPE_NONE = 0b00000000; + public static final byte SYNCTYPE_ASYNC = 0b00000100; + public static final byte SYNCTYPE_ADAPTSYNC = 0b00001000; + public static final byte SYNCTYPE_RESERVED = 0b00001100; + + public static final byte MASK_ATTRIBS_USEAGE = 0b00110000; + public static final byte USEAGE_DATA = 0b00000000; + public static final byte USEAGE_FEEDBACK = 0b00010000; + public static final byte USEAGE_EXPLICIT = 0b00100000; + public static final byte USEAGE_RESERVED = 0b00110000; private byte mEndpointAddress; // 2:1 Endpoint Address // Bits 0..3b Endpoint Number. @@ -76,6 +78,7 @@ public class UsbEndpointDescriptor extends UsbDescriptor { public UsbEndpointDescriptor(int length, byte type) { super(length, type); + mHierarchyLevel = 4; } public byte getEndpointAddress() { @@ -106,7 +109,7 @@ public class UsbEndpointDescriptor extends UsbDescriptor { public int parseRawDescriptors(ByteStream stream) { mEndpointAddress = stream.getByte(); mAttributes = stream.getByte(); - mPacketSize = stream.unpackUsbWord(); + mPacketSize = stream.unpackUsbShort(); mInterval = stream.getByte(); if (mLength == 9) { mRefresh = stream.getByte(); @@ -114,4 +117,76 @@ public class UsbEndpointDescriptor extends UsbDescriptor { } return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + + byte address = getEndpointAddress(); + canvas.writeListItem("Address: " + + ReportCanvas.getHexString(address & UsbEndpointDescriptor.MASK_ENDPOINT_ADDRESS) + + ((address & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION) + == UsbEndpointDescriptor.DIRECTION_OUTPUT ? " [out]" : " [in]")); + + byte attributes = getAttributes(); + canvas.openListItem(); + canvas.write("Attributes: " + ReportCanvas.getHexString(attributes) + " "); + switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE) { + case UsbEndpointDescriptor.TRANSTYPE_CONTROL: + canvas.write("Control"); + break; + case UsbEndpointDescriptor.TRANSTYPE_ISO: + canvas.write("Iso"); + break; + case UsbEndpointDescriptor.TRANSTYPE_BULK: + canvas.write("Bulk"); + break; + case UsbEndpointDescriptor.TRANSTYPE_INTERRUPT: + canvas.write("Interrupt"); + break; + } + canvas.closeListItem(); + + // These flags are only relevant for ISO transfer type + if ((attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE) + == UsbEndpointDescriptor.TRANSTYPE_ISO) { + canvas.openListItem(); + canvas.write("Aync: "); + switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_SYNCTYPE) { + case UsbEndpointDescriptor.SYNCTYPE_NONE: + canvas.write("NONE"); + break; + case UsbEndpointDescriptor.SYNCTYPE_ASYNC: + canvas.write("ASYNC"); + break; + case UsbEndpointDescriptor.SYNCTYPE_ADAPTSYNC: + canvas.write("ADAPTIVE ASYNC"); + break; + } + canvas.closeListItem(); + + canvas.openListItem(); + canvas.write("Useage: "); + switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_USEAGE) { + case UsbEndpointDescriptor.USEAGE_DATA: + canvas.write("DATA"); + break; + case UsbEndpointDescriptor.USEAGE_FEEDBACK: + canvas.write("FEEDBACK"); + break; + case UsbEndpointDescriptor.USEAGE_EXPLICIT: + canvas.write("EXPLICIT FEEDBACK"); + break; + case UsbEndpointDescriptor.USEAGE_RESERVED: + canvas.write("RESERVED"); + break; + } + canvas.closeListItem(); + } + canvas.writeListItem("Package Size: " + getPacketSize()); + canvas.writeListItem("Interval: " + getInterval()); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java index 56c07ec9a071..b4cc87e096df 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java @@ -15,13 +15,15 @@ */ package com.android.server.usb.descriptors; +import com.android.server.usb.descriptors.report.ReportCanvas; + /** * @hide * A USB HID (Human Interface Descriptor). * see HID1_11.pdf - 6.2.1 */ -public class UsbHIDDescriptor extends UsbDescriptor { - private static final String TAG = "HID"; +public final class UsbHIDDescriptor extends UsbDescriptor { + private static final String TAG = "UsbHIDDescriptor"; private int mRelease; // 2:2 the HID Class Specification release. private byte mCountryCode; // 4:1 country code of the localized hardware. @@ -35,6 +37,7 @@ public class UsbHIDDescriptor extends UsbDescriptor { public UsbHIDDescriptor(int length, byte type) { super(length, type); + mHierarchyLevel = 3; } public int getRelease() { @@ -59,12 +62,24 @@ public class UsbHIDDescriptor extends UsbDescriptor { @Override public int parseRawDescriptors(ByteStream stream) { - mRelease = stream.unpackUsbWord(); + mRelease = stream.unpackUsbShort(); mCountryCode = stream.getByte(); mNumDescriptors = stream.getByte(); mDescriptorType = stream.getByte(); - mDescriptorLen = stream.unpackUsbWord(); + mDescriptorLen = stream.unpackUsbShort(); return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.openList(); + canvas.writeListItem("Spec: " + ReportCanvas.getBCDString(getRelease())); + canvas.writeListItem("Type: " + ReportCanvas.getBCDString(getDescriptorType())); + canvas.writeListItem("" + getNumDescriptors() + " Descriptors Len: " + + getDescriptorLen()); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java index 4b18a01b1c8b..d680e543693a 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java @@ -15,14 +15,16 @@ */ package com.android.server.usb.descriptors; +// import com.android.server.usb.descriptors.report.ReportCanvas; + /** * @hide * A USB Interface Association Descriptor. * found this one here: http://www.usb.org/developers/docs/whitepapers/iadclasscode_r10.pdf * also: https://msdn.microsoft.com/en-us/library/windows/hardware/ff540054(v=vs.85).aspx */ -public class UsbInterfaceAssoc extends UsbDescriptor { - private static final String TAG = "InterfaceAssoc"; +public final class UsbInterfaceAssoc extends UsbDescriptor { + private static final String TAG = "UsbInterfaceAssoc"; private byte mFirstInterface; private byte mInterfaceCount; @@ -70,4 +72,11 @@ public class UsbInterfaceAssoc extends UsbDescriptor { return mLength; } + + // TODO - Report fields +// @Override +// public void report(ReportCanvas canvas) { +// super.report(canvas); +// +// } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java index 21b5e0cbaa1b..4eef6caf5a60 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.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 * A common super-class for all USB Interface Descritor subtypes. * see usb11.pdf section 9.6.3 */ public class UsbInterfaceDescriptor extends UsbDescriptor { - private static final String TAG = "Interface"; + private static final String TAG = "UsbInterfaceDescriptor"; protected byte mInterfaceNumber; // 2:1 Number of Interface protected byte mAlternateSetting; // 3:1 Value used to select alternative setting @@ -33,6 +36,7 @@ public class UsbInterfaceDescriptor extends UsbDescriptor { UsbInterfaceDescriptor(int length, byte type) { super(length, type); + mHierarchyLevel = 3; } @Override @@ -75,4 +79,27 @@ public class UsbInterfaceDescriptor extends UsbDescriptor { public byte getDescrIndex() { return mDescrIndex; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + byte usbClass = getUsbClass(); + byte usbSubclass = getUsbSubclass(); + byte protocol = getProtocol(); + String className = UsbStrings.getClassName(usbClass); + String subclassName = ""; + if (usbClass == UsbDescriptor.CLASSID_AUDIO) { + subclassName = UsbStrings.getAudioSubclassName(usbSubclass); + } + + canvas.openList(); + canvas.writeListItem("Interface #" + getInterfaceNumber()); + canvas.writeListItem("Class: " + ReportCanvas.getHexString(usbClass) + ": " + className); + canvas.writeListItem("Subclass: " + + ReportCanvas.getHexString(usbSubclass) + ": " + subclassName); + canvas.writeListItem("Protocol: " + protocol + ": " + ReportCanvas.getHexString(protocol)); + canvas.writeListItem("Endpoints: " + getNumEndpoints()); + canvas.closeList(); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java index 4452b23cb6ae..85a3e6802ff7 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.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 Streaming Interface. * see midi10.pdf section 6.1.2.1 */ -public class UsbMSMidiHeader extends UsbACInterface { - private static final String TAG = "MSMidiHeader"; +public final class UsbMSMidiHeader extends UsbACInterface { + private static final String TAG = "UsbMSMidiHeader"; public UsbMSMidiHeader(int length, byte type, byte subtype, byte subclass) { super(length, type, subtype, subclass); @@ -33,4 +35,13 @@ public class UsbMSMidiHeader extends UsbACInterface { stream.advance(mLength - stream.getReadCount()); return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.writeHeader(3, "MS Midi Header: " + ReportCanvas.getHexString(getType()) + + " SubType: " + ReportCanvas.getHexString(getSubclass()) + + " Length: " + getLength()); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java index 2d33ba7727dd..1d5cbf2b5c99 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.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 Input Jack Interface. * see midi10.pdf section B.4.3 */ -public class UsbMSMidiInputJack extends UsbACInterface { - private static final String TAG = "MSMidiInputJack"; +public final class UsbMSMidiInputJack extends UsbACInterface { + private static final String TAG = "UsbMSMidiInputJack"; UsbMSMidiInputJack(int length, byte type, byte subtype, byte subclass) { super(length, type, subtype, subclass); @@ -33,4 +35,13 @@ public class UsbMSMidiInputJack extends UsbACInterface { stream.advance(mLength - stream.getReadCount()); return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.writeHeader(3, "MS Midi Input Jack: " + ReportCanvas.getHexString(getType()) + + " SubType: " + ReportCanvas.getHexString(getSubclass()) + + " Length: " + getLength()); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java index bd2dc11d57df..9f50240a94ca 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.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 Output Jack Interface. * see midi10.pdf section B.4.4 */ -public class UsbMSMidiOutputJack extends UsbACInterface { - private static final String TAG = "MSMidiOutputJack"; +public final class UsbMSMidiOutputJack extends UsbACInterface { + private static final String TAG = "UsbMSMidiOutputJack"; public UsbMSMidiOutputJack(int length, byte type, byte subtype, byte subclass) { super(length, type, subtype, subclass); @@ -33,4 +35,13 @@ public class UsbMSMidiOutputJack extends UsbACInterface { stream.advance(mLength - stream.getReadCount()); return mLength; } + + @Override + public void report(ReportCanvas canvas) { + super.report(canvas); + + canvas.writeHeader(3, "MS Midi Output Jack: " + ReportCanvas.getHexString(getType()) + + " SubType: " + ReportCanvas.getHexString(getSubclass()) + + " Length: " + getLength()); + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java b/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java index b5214625126a..9bd6cb942888 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java @@ -20,8 +20,8 @@ package com.android.server.usb.descriptors; * A class for decoding information in Terminal Descriptors. * see termt10.pdf */ -public class UsbTerminalTypes { - private static final String TAG = "TerminalTypes"; +public final class UsbTerminalTypes { + private static final String TAG = "UsbTerminalTypes"; // USB public static final int TERMINAL_USB_STREAMING = 0x0101; diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java b/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java index a6fe8bba3508..6e6dccf00613 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java @@ -19,8 +19,8 @@ package com.android.server.usb.descriptors; * @hide * A holder for any unrecognized descriptor encountered in the descriptor stream. */ -public class UsbUnknown extends UsbDescriptor { - static final String TAG = "Unknown"; +public final class UsbUnknown extends UsbDescriptor { + static final String TAG = "UsbUnknown"; public UsbUnknown(int length, byte type) { super(length, type); diff --git a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java new file mode 100644 index 000000000000..99ebccade735 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java @@ -0,0 +1,97 @@ +/* + * 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 HTML. + */ +public final class HTMLReportCanvas extends ReportCanvas { + private static final String TAG = "HTMLReportCanvas"; + + private final StringBuilder mStringBuilder; + + /** + * Constructor. Connects HTML 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 HTMLReportCanvas(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("'); + } + + @Override + public void closeHeader(int level) { + mStringBuilder.append("'); + } + + // we can be cleverer (more clever?) with styles, but this will do for now. + @Override + public void openParagraph(boolean emphasis) { + if (emphasis) { + mStringBuilder.append("

"); + } else { + mStringBuilder.append("

"); + } + } + + @Override + public void closeParagraph() { + mStringBuilder.append("

"); + } + + @Override + public void writeParagraph(String text, boolean inRed) { + openParagraph(inRed); + mStringBuilder.append(text); + closeParagraph(); + } + + @Override + public void openList() { + mStringBuilder.append(""); + } + + @Override + public void openListItem() { + mStringBuilder.append("
  • "); + } + + @Override + public void closeListItem() { + mStringBuilder.append("
  • "); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java deleted file mode 100644 index c98789d880a0..000000000000 --- a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java +++ /dev/null @@ -1,572 +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 android.hardware.usb.UsbDeviceConnection; - -import com.android.server.usb.descriptors.UsbACAudioControlEndpoint; -import com.android.server.usb.descriptors.UsbACAudioStreamEndpoint; -import com.android.server.usb.descriptors.UsbACFeatureUnit; -import com.android.server.usb.descriptors.UsbACHeader; -import com.android.server.usb.descriptors.UsbACInputTerminal; -import com.android.server.usb.descriptors.UsbACInterface; -import com.android.server.usb.descriptors.UsbACMidiEndpoint; -import com.android.server.usb.descriptors.UsbACMixerUnit; -import com.android.server.usb.descriptors.UsbACOutputTerminal; -import com.android.server.usb.descriptors.UsbACSelectorUnit; -import com.android.server.usb.descriptors.UsbACTerminal; -import com.android.server.usb.descriptors.UsbASFormat; -import com.android.server.usb.descriptors.UsbASFormatI; -import com.android.server.usb.descriptors.UsbASFormatII; -import com.android.server.usb.descriptors.UsbASGeneral; -import com.android.server.usb.descriptors.UsbConfigDescriptor; -import com.android.server.usb.descriptors.UsbDescriptor; -import com.android.server.usb.descriptors.UsbDeviceDescriptor; -import com.android.server.usb.descriptors.UsbEndpointDescriptor; -import com.android.server.usb.descriptors.UsbHIDDescriptor; -import com.android.server.usb.descriptors.UsbInterfaceAssoc; -import com.android.server.usb.descriptors.UsbInterfaceDescriptor; -import com.android.server.usb.descriptors.UsbMSMidiHeader; -import com.android.server.usb.descriptors.UsbMSMidiInputJack; -import com.android.server.usb.descriptors.UsbMSMidiOutputJack; -import com.android.server.usb.descriptors.UsbUnknown; - -/** - * Implements the Reporter inteface to provide HTML reporting for UsbDescriptor subclasses. - */ -public class HTMLReporter implements Reporter { - private final StringBuilder mStringBuilder; - private final UsbDeviceConnection mConnection; - - public HTMLReporter(StringBuilder stringBuilder, UsbDeviceConnection connection) { - mStringBuilder = stringBuilder; - mConnection = connection; - } - - /* - * HTML Helpers - */ - private void writeHeader(int level, String text) { - mStringBuilder - .append("') - .append(text) - .append("'); - } - - private void openParagraph() { - mStringBuilder.append("

    "); - } - - private void closeParagraph() { - mStringBuilder.append("

    "); - } - - private void writeParagraph(String text) { - openParagraph(); - mStringBuilder.append(text); - closeParagraph(); - } - - private void openList() { - mStringBuilder.append(""); - } - - private void openListItem() { - mStringBuilder.append("
  • "); - } - - private void closeListItem() { - mStringBuilder.append("
  • "); - } - - private void writeListItem(String text) { - openListItem(); - mStringBuilder.append(text); - closeListItem(); - } - - /* - * Data Formating Helpers - */ - private static String getHexString(byte value) { - return "0x" + Integer.toHexString(((int) value) & 0xFF).toUpperCase(); - } - - private static String getBCDString(int value) { - int major = value >> 8; - int minor = (value >> 4) & 0x0F; - int subminor = value & 0x0F; - - return "" + major + "." + minor + subminor; - } - - private static String getHexString(int value) { - int intValue = value & 0xFFFF; - return "0x" + Integer.toHexString(intValue).toUpperCase(); - } - - private void dumpHexArray(byte[] rawData, StringBuilder builder) { - if (rawData != null) { - // Assume the type and Length and perhaps sub-type have been displayed - openParagraph(); - for (int index = 0; index < rawData.length; index++) { - builder.append(getHexString(rawData[index]) + " "); - } - closeParagraph(); - } - } - - /** - * Decode ACTUAL UsbDescriptor sub classes and call type-specific report methods. - */ - @Override - public void report(UsbDescriptor descriptor) { - if (descriptor instanceof UsbDeviceDescriptor) { - tsReport((UsbDeviceDescriptor) descriptor); - } else if (descriptor instanceof UsbConfigDescriptor) { - tsReport((UsbConfigDescriptor) descriptor); - } else if (descriptor instanceof UsbInterfaceDescriptor) { - tsReport((UsbInterfaceDescriptor) descriptor); - } else if (descriptor instanceof UsbEndpointDescriptor) { - tsReport((UsbEndpointDescriptor) descriptor); - } else if (descriptor instanceof UsbHIDDescriptor) { - tsReport((UsbHIDDescriptor) descriptor); - } else if (descriptor instanceof UsbACAudioControlEndpoint) { - tsReport((UsbACAudioControlEndpoint) descriptor); - } else if (descriptor instanceof UsbACAudioStreamEndpoint) { - tsReport((UsbACAudioStreamEndpoint) descriptor); - } else if (descriptor instanceof UsbACHeader) { - tsReport((UsbACHeader) descriptor); - } else if (descriptor instanceof UsbACFeatureUnit) { - tsReport((UsbACFeatureUnit) descriptor); - } else if (descriptor instanceof UsbACInputTerminal) { - tsReport((UsbACInputTerminal) descriptor); - } else if (descriptor instanceof UsbACOutputTerminal) { - tsReport((UsbACOutputTerminal) descriptor); - } else if (descriptor instanceof UsbACMidiEndpoint) { - tsReport((UsbACMidiEndpoint) descriptor); - } else if (descriptor instanceof UsbACMixerUnit) { - tsReport((UsbACMixerUnit) descriptor); - } else if (descriptor instanceof UsbACSelectorUnit) { - tsReport((UsbACSelectorUnit) descriptor); - } else if (descriptor instanceof UsbASFormatI) { - tsReport((UsbASFormatI) descriptor); - } else if (descriptor instanceof UsbASFormatII) { - tsReport((UsbASFormatII) descriptor); - } else if (descriptor instanceof UsbASFormat) { - tsReport((UsbASFormat) descriptor); - } else if (descriptor instanceof UsbASGeneral) { - tsReport((UsbASGeneral) descriptor); - } else if (descriptor instanceof UsbInterfaceAssoc) { - tsReport((UsbInterfaceAssoc) descriptor); - } else if (descriptor instanceof UsbMSMidiHeader) { - tsReport((UsbMSMidiHeader) descriptor); - } else if (descriptor instanceof UsbMSMidiInputJack) { - tsReport((UsbMSMidiInputJack) descriptor); - } else if (descriptor instanceof UsbMSMidiOutputJack) { - tsReport((UsbMSMidiOutputJack) descriptor); - } else if (descriptor instanceof UsbUnknown) { - tsReport((UsbUnknown) descriptor); - } else if (descriptor instanceof UsbACInterface) { - tsReport((UsbACInterface) descriptor); - } else if (descriptor instanceof UsbDescriptor) { - tsReport((UsbDescriptor) descriptor); - } - } - - // - // Type-specific report() implementations - // - private void tsReport(UsbDescriptor descriptor) { - int length = descriptor.getLength(); - byte type = descriptor.getType(); - int status = descriptor.getStatus(); - - String descTypeStr = UsbStrings.getDescriptorName(type); - writeParagraph(descTypeStr + ":" + type + " l:" + length + " s:" + status); - } - - private void tsReport(UsbDeviceDescriptor descriptor) { - writeHeader(1, "Device len:" + descriptor.getLength()); - openList(); - - int spec = descriptor.getSpec(); - writeListItem("spec:" + getBCDString(spec)); - - byte devClass = descriptor.getDevClass(); - String classStr = UsbStrings.getClassName(devClass); - byte devSubClass = descriptor.getDevSubClass(); - String subClasStr = UsbStrings.getClassName(devSubClass); - writeListItem("class " + devClass + ":" + classStr + " subclass" - + devSubClass + ":" + subClasStr); - writeListItem("vendorID:" + descriptor.getVendorID() - + " prodID:" + descriptor.getProductID() - + " prodRel:" + getBCDString(descriptor.getDeviceRelease())); - - byte mfgIndex = descriptor.getMfgIndex(); - String manufacturer = UsbDescriptor.getUsbDescriptorString(mConnection, mfgIndex); - byte productIndex = descriptor.getProductIndex(); - String product = UsbDescriptor.getUsbDescriptorString(mConnection, productIndex); - - writeListItem("mfg " + mfgIndex + ":" + manufacturer - + " prod " + productIndex + ":" + product); - closeList(); - } - - private void tsReport(UsbConfigDescriptor descriptor) { - writeHeader(2, "Config #" + descriptor.getConfigValue() - + " len:" + descriptor.getLength()); - - openList(); - writeListItem(descriptor.getNumInterfaces() + " interfaces."); - writeListItem("attribs:" + getHexString(descriptor.getAttribs())); - closeList(); - } - - private void tsReport(UsbInterfaceDescriptor descriptor) { - byte usbClass = descriptor.getUsbClass(); - byte usbSubclass = descriptor.getUsbSubclass(); - String descr = UsbStrings.getDescriptorName(descriptor.getType()); - String className = UsbStrings.getClassName(usbClass); - String subclassName = ""; - if (usbClass == UsbDescriptor.CLASSID_AUDIO) { - subclassName = UsbStrings.getAudioSubclassName(usbSubclass); - } - - writeHeader(2, descr + " #" + descriptor.getInterfaceNumber() - + " len:" + descriptor.getLength()); - String descrStr = - UsbDescriptor.getUsbDescriptorString(mConnection, descriptor.getDescrIndex()); - if (descrStr.length() > 0) { - 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 000000000000..9e0adf55d87b --- /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 2944c10796f6..000000000000 --- 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 c13111b3e81c..be7c12e4a521 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 000000000000..33746ba82bc6 --- /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 0461150abd27..ff58a2672b3f 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 sDescriptorNames; @@ -35,6 +36,7 @@ public class UsbStrings { private static HashMap sAudioSubclassNames; private static HashMap sAudioEncodingNames; private static HashMap sTerminalNames; + private static HashMap sFormatNames; private static void initDescriptorNames() { sDescriptorNames = new HashMap(); @@ -70,6 +72,11 @@ public class UsbStrings { sACControlInterfaceNames.put(UsbACInterface.ACI_FEATURE_UNIT, "Feature Unit"); sACControlInterfaceNames.put(UsbACInterface.ACI_PROCESSING_UNIT, "Processing Unit"); sACControlInterfaceNames.put(UsbACInterface.ACI_EXTENSION_UNIT, "Extension Unit"); + sACControlInterfaceNames.put(UsbACInterface.ACI_CLOCK_SOURCE, "Clock Source"); + sACControlInterfaceNames.put(UsbACInterface.ACI_CLOCK_SELECTOR, "Clock Selector"); + sACControlInterfaceNames.put(UsbACInterface.ACI_CLOCK_MULTIPLIER, "Clock Multiplier"); + sACControlInterfaceNames.put(UsbACInterface.ACI_SAMPLE_RATE_CONVERTER, + "Sample Rate Converter"); } private static void initACStreamingInterfaceNames() { @@ -213,6 +220,29 @@ public class UsbStrings { ? name : "Unknown Terminal Type 0x" + Integer.toHexString(terminalType); } + + private static void initFormatNames() { + sFormatNames = new HashMap(); + + sFormatNames.put((int) UsbASFormat.FORMAT_TYPE_I, "FORMAT_TYPE_I"); + sFormatNames.put((int) UsbASFormat.FORMAT_TYPE_II, "FORMAT_TYPE_II"); + sFormatNames.put((int) UsbASFormat.FORMAT_TYPE_III, "FORMAT_TYPE_III"); + sFormatNames.put((int) UsbASFormat.FORMAT_TYPE_IV, "FORMAT_TYPE_IV"); + sFormatNames.put((int) UsbASFormat.EXT_FORMAT_TYPE_I, "EXT_FORMAT_TYPE_I"); + sFormatNames.put((int) UsbASFormat.EXT_FORMAT_TYPE_II, "EXT_FORMAT_TYPE_II"); + sFormatNames.put((int) UsbASFormat.EXT_FORMAT_TYPE_III, "EXT_FORMAT_TYPE_III"); + } + + /** + * Retrieves the name for the specified format (encoding) type ID. + */ + public static String getFormatName(int format) { + String name = sFormatNames.get(format); + return name != null + ? name + : "Unknown Format Type 0x" + Integer.toHexString(format); + } + /** * Initializes string tables. */ @@ -224,10 +254,11 @@ public class UsbStrings { initAudioSubclassNames(); initAudioEncodingNames(); initTerminalNames(); + initFormatNames(); } /** - * Initializes string tables. + * Deinitializes string tables. */ public static void releaseUsbStrings() { sDescriptorNames = null; @@ -309,4 +340,11 @@ public class UsbStrings { : "Unknown Format (encoding) ID [0x" + Integer.toHexString(formatID) + ":" + formatID + "]"; } + + /** + * Retrieves the name for the specified USB audio interface subclass ID. + */ + public static String getACInterfaceSubclassName(byte subClassID) { + return subClassID == UsbDescriptor.AUDIO_AUDIOCONTROL ? "AC Control" : "AC Streaming"; + } } diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsACInterfaceNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsACInterfaceNode.java new file mode 100644 index 000000000000..49caca5c8dd0 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsACInterfaceNode.java @@ -0,0 +1,46 @@ +/* + * 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.tree; + +import com.android.server.usb.descriptors.UsbACInterface; +import com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * A tree node containing some sort-of Audio Class Descriptor. + */ +public final class UsbDescriptorsACInterfaceNode extends UsbDescriptorsTreeNode { + private static final String TAG = "UsbDescriptorsACInterfaceNode"; + + private final UsbACInterface mACInterface; + + /** + * Constructor. + * @param acInterface The Audio Class Inteface object wrapped by this tree node. + */ + public UsbDescriptorsACInterfaceNode(UsbACInterface acInterface) { + mACInterface = acInterface; + } + + @Override + public void report(ReportCanvas canvas) { + canvas.openListItem(); + canvas.writeParagraph("AC Interface type:0x" + + Integer.toHexString(mACInterface.getSubtype()), false); + mACInterface.report(canvas); + canvas.closeListItem(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsConfigNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsConfigNode.java new file mode 100644 index 000000000000..64f9496ae7c8 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsConfigNode.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.tree; + +import com.android.server.usb.descriptors.UsbConfigDescriptor; +import com.android.server.usb.descriptors.report.ReportCanvas; + +import java.util.ArrayList; + +/** + * @hide + * Represents a configuration in the descriptors tree. + */ +public final class UsbDescriptorsConfigNode extends UsbDescriptorsTreeNode { + private static final String TAG = "UsbDescriptorsConfigNode"; + + private final UsbConfigDescriptor mConfigDescriptor; + + private final ArrayList mInterfaceNodes = new ArrayList<>(); + + /** + * Constructor. + * @param configDescriptor The Config Descriptor object wrapped by this tree node. + */ + public UsbDescriptorsConfigNode(UsbConfigDescriptor configDescriptor) { + mConfigDescriptor = configDescriptor; + } + + /** + * Adds the inteface node logical contained in this configuration. + * @param interfaceNode The inteface treenode to assocate with this configuration. + */ + public void addInterfaceNode(UsbDescriptorsInterfaceNode interfaceNode) { + mInterfaceNodes.add(interfaceNode); + } + + @Override + public void report(ReportCanvas canvas) { + mConfigDescriptor.report(canvas); + + canvas.openList(); + + // Interfaces + for (UsbDescriptorsInterfaceNode node : mInterfaceNodes) { + node.report(canvas); + } + + canvas.closeList(); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsDeviceNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsDeviceNode.java new file mode 100644 index 000000000000..898a06ecdafc --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsDeviceNode.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.tree; + +import com.android.server.usb.descriptors.UsbDeviceDescriptor; +import com.android.server.usb.descriptors.report.ReportCanvas; + +import java.util.ArrayList; + +/** + * @hide + * A class to contain THE device descriptor at the root of the tree. + */ +public final class UsbDescriptorsDeviceNode extends UsbDescriptorsTreeNode { + private static final String TAG = "UsbDescriptorsDeviceNode"; + + private final UsbDeviceDescriptor mDeviceDescriptor; + + private final ArrayList mConfigNodes = new ArrayList<>(); + + /** + * Constructor. + * @param deviceDescriptor The Device Descriptor object wrapped by this tree node. + */ + public UsbDescriptorsDeviceNode(UsbDeviceDescriptor deviceDescriptor) { + mDeviceDescriptor = deviceDescriptor; + } + + /** + * Adds a Configuration node to the assocated device node. + */ + public void addConfigDescriptorNode(UsbDescriptorsConfigNode configNode) { + mConfigNodes.add(configNode); + } + + @Override + public void report(ReportCanvas canvas) { + mDeviceDescriptor.report(canvas); + for (UsbDescriptorsConfigNode node : mConfigNodes) { + node.report(canvas); + } + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsEndpointNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsEndpointNode.java new file mode 100644 index 000000000000..72864172147e --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsEndpointNode.java @@ -0,0 +1,42 @@ +/* + * 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.tree; + +import com.android.server.usb.descriptors.UsbEndpointDescriptor; +import com.android.server.usb.descriptors.report.ReportCanvas; + +/** + * @hide + * Represents an endpoint in the descriptors tree. + */ +public final class UsbDescriptorsEndpointNode extends UsbDescriptorsTreeNode { + private static final String TAG = "UsbDescriptorsEndpointNode"; + + private final UsbEndpointDescriptor mEndpointDescriptor; + + /** + * Constructor. + * @param endpointDescriptor The Device Descriptor object wrapped by this tree node. + */ + public UsbDescriptorsEndpointNode(UsbEndpointDescriptor endpointDescriptor) { + mEndpointDescriptor = endpointDescriptor; + } + + @Override + public void report(ReportCanvas canvas) { + mEndpointDescriptor.report(canvas); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsInterfaceNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsInterfaceNode.java new file mode 100644 index 000000000000..d49d88db9882 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsInterfaceNode.java @@ -0,0 +1,83 @@ +/* + * 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.tree; + +import com.android.server.usb.descriptors.UsbInterfaceDescriptor; +import com.android.server.usb.descriptors.report.ReportCanvas; + +import java.util.ArrayList; + +/** + * @hide + * Represents an interface in the descriptors tree. + */ +public final class UsbDescriptorsInterfaceNode extends UsbDescriptorsTreeNode { + private static final String TAG = "UsbDescriptorsInterfaceNode"; + + private final UsbInterfaceDescriptor mInterfaceDescriptor; + + private final ArrayList mEndpointNodes = new ArrayList<>(); + private final ArrayList mACInterfaceNodes = new ArrayList<>(); + + /** + * Constructor. + * @param interfaceDescriptor The Interface Descriptor object wrapped by this tree node. + */ + public UsbDescriptorsInterfaceNode(UsbInterfaceDescriptor interfaceDescriptor) { + mInterfaceDescriptor = interfaceDescriptor; + } + + /** + * Adds an endpoint descriptor as a child of this interface node. + * @param endpointNode The endpoint descriptor node to add to this interface node. + */ + public void addEndpointNode(UsbDescriptorsEndpointNode endpointNode) { + mEndpointNodes.add(endpointNode); + } + + /** + * Adds an Audio-class interface descriptor as a child of this interface node. + * @param acInterfaceNode The audio-class descriptor node to add to this interface node. + */ + public void addACInterfaceNode(UsbDescriptorsACInterfaceNode acInterfaceNode) { + mACInterfaceNodes.add(acInterfaceNode); + } + + @Override + public void report(ReportCanvas canvas) { + mInterfaceDescriptor.report(canvas); + + // Audio Class Interfaces + if (mACInterfaceNodes.size() > 0) { + canvas.writeParagraph("Audio Class Interfaces", false); + canvas.openList(); + for (UsbDescriptorsACInterfaceNode node : mACInterfaceNodes) { + node.report(canvas); + } + canvas.closeList(); + } + + // Endpoints + if (mEndpointNodes.size() > 0) { + canvas.writeParagraph("Endpoints", false); + canvas.openList(); + for (UsbDescriptorsEndpointNode node : mEndpointNodes) { + node.report(canvas); + } + canvas.closeList(); + } + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTree.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTree.java new file mode 100644 index 000000000000..1aa30fa94f42 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTree.java @@ -0,0 +1,145 @@ +/* + * 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.tree; + +import com.android.server.usb.descriptors.UsbACInterface; +import com.android.server.usb.descriptors.UsbConfigDescriptor; +import com.android.server.usb.descriptors.UsbDescriptor; +import com.android.server.usb.descriptors.UsbDescriptorParser; +import com.android.server.usb.descriptors.UsbDeviceDescriptor; +import com.android.server.usb.descriptors.UsbEndpointDescriptor; +import com.android.server.usb.descriptors.UsbInterfaceDescriptor; +import com.android.server.usb.descriptors.report.ReportCanvas; + +import java.util.ArrayList; + +/* + * The general layout of the tree looks like this, though no guarentee about + * ordering of descriptors beyond the Device -> Config -> Interface. + * + * Device Descriptor + * +- Config Descriptor + * +- Interface Descriptor + * | +- Audio Class Interface + * | +- Audio Class Interface + * | +- Audio Class Interface + * | +- Endpoint Descriptor + * | +- Endpoint Descriptor + * +- Interface Descriptor + * +- Endpoint Descriptor + */ +/** + * @hide + * + * A class which builds a tree representation from the results of a (linear) + * parse of USB descriptors. + * + * @see {@link com.android.server.usb.descriptors.UsbDescriptorsParser UsbDescriptorsParser} + */ +public final class UsbDescriptorsTree { + private static final String TAG = "UsbDescriptorsTree"; + + private UsbDescriptorsDeviceNode mDeviceNode; + private UsbDescriptorsConfigNode mConfigNode; // being parsed + private UsbDescriptorsInterfaceNode mInterfaceNode; // being parsed + + /** + * Adds THE device descriptor as the root of the tree. + */ + private void addDeviceDescriptor(UsbDeviceDescriptor deviceDescriptor) { + mDeviceNode = new UsbDescriptorsDeviceNode(deviceDescriptor); + } + + /** + * Adds A config descriptor to the tree. + */ + private void addConfigDescriptor(UsbConfigDescriptor configDescriptor) { + mConfigNode = new UsbDescriptorsConfigNode(configDescriptor); + mDeviceNode.addConfigDescriptorNode(mConfigNode); + } + + /** + * Adds AN interface descriptor to the current configuration in the tree. + */ + private void addInterfaceDescriptor(UsbInterfaceDescriptor interfaceDescriptor) { + mInterfaceNode = new UsbDescriptorsInterfaceNode(interfaceDescriptor); + mConfigNode.addInterfaceNode(mInterfaceNode); + } + + /** + * Adds an endpoint descriptor to the current interface in the tree. + */ + private void addEndpointDescriptor(UsbEndpointDescriptor endpointDescriptor) { + mInterfaceNode.addEndpointNode(new UsbDescriptorsEndpointNode(endpointDescriptor)); + } + + /** + * Adds an audio-class interface descriptor to the current interface in the tree. + */ + private void addACInterface(UsbACInterface acInterface) { + mInterfaceNode.addACInterfaceNode(new UsbDescriptorsACInterfaceNode(acInterface)); + } + + /** + * Parses the linear descriptor list contained in the parser argument, into a tree + * representation corresponding to the logical structure of the USB descriptors. + */ + public void parse(UsbDescriptorParser parser) { + + ArrayList descriptors = parser.getDescriptors(); + + for (int descrIndex = 0; descrIndex < descriptors.size(); descrIndex++) { + UsbDescriptor descriptor = descriptors.get(descrIndex); + switch (descriptor.getType()) { + // + // Basic Descriptors + // + case UsbDescriptor.DESCRIPTORTYPE_DEVICE: + addDeviceDescriptor((UsbDeviceDescriptor) descriptor); + break; + + case UsbDescriptor.DESCRIPTORTYPE_CONFIG: + addConfigDescriptor((UsbConfigDescriptor) descriptor); + break; + + case UsbDescriptor.DESCRIPTORTYPE_INTERFACE: + addInterfaceDescriptor((UsbInterfaceDescriptor) descriptor); + break; + + case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT: + addEndpointDescriptor((UsbEndpointDescriptor) descriptor); + break; + + // + // Audio Class Descriptors + // + case UsbDescriptor.DESCRIPTORTYPE_AUDIO_INTERFACE: + addACInterface((UsbACInterface) descriptor); + break; + + case UsbDescriptor.DESCRIPTORTYPE_AUDIO_ENDPOINT: + break; + } + } + } + + /** + * Generate a report of the descriptors tree. + */ + public void report(ReportCanvas canvas) { + mDeviceNode.report(canvas); + } +} diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTreeNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTreeNode.java new file mode 100644 index 000000000000..aca3cd907372 --- /dev/null +++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTreeNode.java @@ -0,0 +1,41 @@ +/* + * 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.tree; + +import com.android.server.usb.descriptors.report.ReportCanvas; +import com.android.server.usb.descriptors.report.Reporting; + +/** + * @hide + * A shared super class for UsbDescriptor tree nodes. + */ +public class UsbDescriptorsTreeNode implements Reporting { + private static final String TAG = "UsbDescriptorsTreeNode"; + + /** + * Implements generate a comprehehensive report of descriptor. + */ + @Override + public void report(ReportCanvas canvas) { + } + + /** + * Implements generate an abreviated report of descriptor. + */ + @Override + public void shortReport(ReportCanvas canvas) { + } +} -- 2.11.0