18f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown/*
28f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Copyright (C) 2013 The Android Open Source Project
38f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown *
48f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
58f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * you may not use this file except in compliance with the License.
68f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * You may obtain a copy of the License at
78f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown *
88f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
98f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown *
108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Unless required by applicable law or agreed to in writing, software
118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * See the License for the specific language governing permissions and
148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * limitations under the License.
158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */
168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown
178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownpackage com.android.accessorydisplay.sink;
188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown
198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport java.nio.ByteBuffer;
208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown
218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown/**
228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Helper for creating USB HID descriptors and reports.
238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */
248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownfinal class UsbHid {
258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown    private UsbHid() {
268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown    }
278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown
288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown    /**
298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown     * Generates basic Windows 7 compatible HID multitouch descriptors and reports
308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown     * that should be supported by recent versions of the Linux hid-multitouch driver.
318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown     */
328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown    public static final class Multitouch {
338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        private final int mReportId;
348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        private final int mMaxContacts;
358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        private final int mWidth;
368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        private final int mHeight;
378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown
388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        public Multitouch(int reportId, int maxContacts, int width, int height) {
398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            mReportId = reportId;
408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            mMaxContacts = maxContacts;
418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            mWidth = width;
428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            mHeight = height;
438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        }
448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown
458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        public void generateDescriptor(ByteBuffer buffer) {
468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            buffer.put(new byte[] {
478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x05, 0x0d,                         // USAGE_PAGE (Digitizers)
488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x09, 0x04,                         // USAGE (Touch Screen)
498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0xa1, 0x01,                   // COLLECTION (Application)
508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0x85, (byte)mReportId,        //   REPORT_ID (Touch)
518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x09, 0x22,                         //   USAGE (Finger)
528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0xa1, 0x00,                   //   COLLECTION (Physical)
538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x09, 0x55,                         //     USAGE (Contact Count Maximum)
548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x15, 0x00,                         //     LOGICAL_MINIMUM (0)
558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x25, (byte)mMaxContacts,           //     LOGICAL_MAXIMUM (...)
568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x75, 0x08,                         //     REPORT_SIZE (8)
578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0x95, 0x01,                   //     REPORT_COUNT (1)
588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0xb1, (byte)mMaxContacts,     //     FEATURE (Data,Var,Abs)
598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x09, 0x54,                         //     USAGE (Contact Count)
608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0x81, 0x02,                   //     INPUT (Data,Var,Abs)
618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            });
628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            byte maxXLsb = (byte)(mWidth - 1);
638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            byte maxXMsb = (byte)((mWidth - 1) >> 8);
648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            byte maxYLsb = (byte)(mHeight - 1);
658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            byte maxYMsb = (byte)((mHeight - 1) >> 8);
668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            byte[] collection = new byte[] {
678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x05, 0x0d,                         //     USAGE_PAGE (Digitizers)
688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x09, 0x22,                         //     USAGE (Finger)
698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0xa1, 0x02,                   //     COLLECTION (Logical)
708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x09, 0x42,                         //       USAGE (Tip Switch)
718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x15, 0x00,                         //       LOGICAL_MINIMUM (0)
728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x25, 0x01,                         //       LOGICAL_MAXIMUM (1)
738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x75, 0x01,                         //       REPORT_SIZE (1)
748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0x81, 0x02,                   //       INPUT (Data,Var,Abs)
758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x09, 0x32,                         //       USAGE (In Range)
768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0x81, 0x02,                   //       INPUT (Data,Var,Abs)
778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x09, 0x51,                         //       USAGE (Contact Identifier)
788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x25, 0x3f,                         //       LOGICAL_MAXIMUM (63)
798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x75, 0x06,                         //       REPORT_SIZE (6)
808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0x81, 0x02,                   //       INPUT (Data,Var,Abs)
818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x05, 0x01,                         //       USAGE_PAGE (Generic Desktop)
828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x09, 0x30,                         //       USAGE (X)
838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x26, maxXLsb, maxXMsb,             //       LOGICAL_MAXIMUM (...)
848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x75, 0x10,                         //       REPORT_SIZE (16)
858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0x81, 0x02,                   //       INPUT (Data,Var,Abs)
868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x09, 0x31,                         //       USAGE (Y)
878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                0x26, maxYLsb, maxYMsb,             //       LOGICAL_MAXIMUM (...)
888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0x81, 0x02,                   //       INPUT (Data,Var,Abs)
898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0xc0,                         //     END_COLLECTION
908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            };
918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            for (int i = 0; i < mMaxContacts; i++) {
928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                buffer.put(collection);
938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            }
948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            buffer.put(new byte[] {
958f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0xc0,                         //   END_COLLECTION
968f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                (byte)0xc0,                         // END_COLLECTION
978f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            });
988f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        }
998f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown
1008f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        public void generateReport(ByteBuffer buffer, Contact[] contacts, int contactCount) {
1018f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            // Report Id
1028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            buffer.put((byte)mReportId);
1038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            // Contact Count
1048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            buffer.put((byte)contactCount);
1058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown
1068f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            for (int i = 0; i < contactCount; i++) {
1078f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                final Contact contact = contacts[i];
1088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                // Tip Switch, In Range, Contact Identifier
1098f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                buffer.put((byte)((contact.id << 2) | 0x03));
1108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                // X
1118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                buffer.put((byte)contact.x).put((byte)(contact.x >> 8));
1128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                // Y
1138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                buffer.put((byte)contact.y).put((byte)(contact.y >> 8));
1148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            }
1158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            for (int i = contactCount; i < mMaxContacts; i++) {
1168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown                buffer.put((byte)0).put((byte)0).put((byte)0).put((byte)0).put((byte)0);
1178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            }
1188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        }
1198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown
1208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        public int getReportSize() {
1218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            return 2 + mMaxContacts * 5;
1228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        }
1238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown
1248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        public static final class Contact {
1258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            public int id; // range 0..63
1268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            public int x;
1278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown            public int y;
1288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown        }
1298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown    }
1308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown}
131