• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.hardware.cts.accessories;
18 
19 import static org.junit.Assert.*;
20 
21 import com.android.cts.input.HidResultData;
22 
23 /** Declares virtual head trackers for SensorHeadTrackerTest registered through /dev/uhid/ */
24 public class VirtualHeadTracker extends HidCommand {
25     private static final String TAG = "VirtualHeadTracker";
26     private boolean mIsHeadTrackerEnabled = false;
27     private VirtualHtRunnable mVirtualHtRunnable = new VirtualHtRunnable();
28 
29     /*
30         The orientation, angular velocity and discontinuity
31         count for the virtual head tracker.
32         In C++ this would be:
33                 struct __attribute__((packed)) {
34                     int16_t orientation[3];
35                     int16_t angularVelocity[3];
36                     uint8_t discontinuityCount;
37                 };
38     */
39     private static final float[] ORIENTATION = {
40         (float) Math.PI / 2, (float) -Math.PI / 3, (float) Math.PI / 4
41     };
42     private static final float[] ANGULAR_VELOCITY = {
43         (float) Math.PI, (float) -Math.PI * 2, (float) Math.PI * 3
44     };
45     private byte mDiscontinuityCount = 0x00;
46     public static final float[] HEAD_TRACKER_VALUES = {
47         ORIENTATION[0],
48         ORIENTATION[1],
49         ORIENTATION[2],
50         ANGULAR_VELOCITY[0],
51         ANGULAR_VELOCITY[1],
52         ANGULAR_VELOCITY[2]
53     };
54 
incDiscontinuityCount()55     public void incDiscontinuityCount() {
56         mDiscontinuityCount++;
57     }
58 
generateReport()59     private String generateReport() {
60         byte report = 1;
61 
62         // HEAD_TRACKER_VALUES is the end results when it goes through sendHidReport.
63         return "["
64                 + String.format("0x%02x,", report)
65                 + orientationFloatToStr(ORIENTATION)
66                 + angularVelocityFloatToStr(ANGULAR_VELOCITY)
67                 + String.format("0x%02x", mDiscontinuityCount)
68                 + "]";
69     }
70 
71     /**
72      * Convert an orientation array from float to the int16 HID format as a String of bytes.
73      *
74      * @param orientation a rotation vector represented as float[3] of x, y, z in radians with range
75      *     [-pi, pi]; magnitude must be in range [0, pi]
76      */
orientationFloatToStr(float[] orientation)77     private static String orientationFloatToStr(float[] orientation) {
78         String stringOfBytes = new String();
79         for (float orient : orientation) {
80             int hidValue = (int) Math.round(orient / Math.PI * Short.MAX_VALUE);
81             stringOfBytes += intToShortByteStr(hidValue);
82         }
83         return stringOfBytes;
84     }
85 
86     /**
87      * Convert an orientation array from float to the int16 HID format as a String of bytes.
88      *
89      * @param angularVelocity is radians per second, in range [-32, 32]
90      */
angularVelocityFloatToStr(float[] angularVelocity)91     private static String angularVelocityFloatToStr(float[] angularVelocity) {
92         String stringOfBytes = new String();
93         for (float angle : angularVelocity) {
94             int hidValue = Math.round(angle / 32 * Short.MAX_VALUE);
95             stringOfBytes += intToShortByteStr(hidValue);
96         }
97         return stringOfBytes;
98     }
99 
100     /** Clamps an int to short range and returns it as a string in little endian order */
intToShortByteStr(int hidValue)101     private static String intToShortByteStr(int hidValue) {
102         hidValue = Math.max(Short.MIN_VALUE, Math.min(Short.MAX_VALUE, hidValue));
103         return String.format("0x%02x,0x%02x,", hidValue & 0xff, (hidValue & 0xff00) >> 8);
104     }
105 
106     @Override
processResults(HidResultData results)107     protected void processResults(HidResultData results) {
108         if (mIsHeadTrackerEnabled) {
109             mVirtualHtRunnable.stop();
110         }
111         mIsHeadTrackerEnabled = (results.reportData[1] & 0x03) == 0x03;
112         setGetReportResponse(results);
113         sendSetReportReply(true);
114         if (mIsHeadTrackerEnabled) {
115             mVirtualHtRunnable.start();
116         }
117     }
118 
119     private class VirtualHtRunnable implements Runnable {
120         private Thread mVirtualHeadTrackerThread;
121 
start()122         public void start() {
123             if (mVirtualHeadTrackerThread != null) {
124                 fail("mVirtualHeadTrackerThread should be null");
125             } else {
126                 mVirtualHeadTrackerThread = new Thread(this);
127             }
128             mVirtualHeadTrackerThread.start();
129         }
130 
stop()131         public void stop() {
132             mVirtualHeadTrackerThread.interrupt();
133             try {
134                 mVirtualHeadTrackerThread.join();
135             } catch (InterruptedException ex) {
136 
137             }
138             mVirtualHeadTrackerThread = null;
139         }
140 
run()141         public void run() {
142             int count = 0;
143             while (!mVirtualHeadTrackerThread.isInterrupted()) {
144                 try {
145                     Thread.sleep(10);
146                     sendHidReport(generateReport());
147                 } catch (InterruptedException ex) {
148                     return;
149                 }
150             }
151         }
152     }
153 }
154