1 /*
2  * Copyright (C) 2011 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 com.android.missilelauncher;
18 
19 import java.nio.ByteBuffer;
20 
21 import android.app.Activity;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.hardware.Sensor;
25 import android.hardware.SensorEvent;
26 import android.hardware.SensorEventListener;
27 import android.hardware.SensorManager;
28 import android.hardware.usb.UsbConstants;
29 import android.hardware.usb.UsbDevice;
30 import android.hardware.usb.UsbDeviceConnection;
31 import android.hardware.usb.UsbEndpoint;
32 import android.hardware.usb.UsbInterface;
33 import android.hardware.usb.UsbManager;
34 import android.hardware.usb.UsbRequest;
35 import android.os.Bundle;
36 import android.util.Log;
37 import android.view.View;
38 import android.widget.Button;
39 
40 public class MissileLauncherActivity extends Activity
41         implements View.OnClickListener, Runnable {
42 
43     private static final String TAG = "MissileLauncherActivity";
44 
45     private Button mFire;
46     private UsbManager mUsbManager;
47     private UsbDevice mDevice;
48     private UsbDeviceConnection mConnection;
49     private UsbEndpoint mEndpointIntr;
50     private SensorManager mSensorManager;
51     private Sensor mGravitySensor;
52 
53     // USB control commands
54     private static final int COMMAND_UP = 1;
55     private static final int COMMAND_DOWN = 2;
56     private static final int COMMAND_RIGHT = 4;
57     private static final int COMMAND_LEFT = 8;
58     private static final int COMMAND_FIRE = 16;
59     private static final int COMMAND_STOP = 32;
60     private static final int COMMAND_STATUS = 64;
61 
62     // constants for accelerometer orientation
63     private static final int TILT_LEFT = 1;
64     private static final int TILT_RIGHT = 2;
65     private static final int TILT_UP = 4;
66     private static final int TILT_DOWN = 8;
67     private static final double THRESHOLD = 5.0;
68 
69     @Override
onCreate(Bundle savedInstanceState)70     public void onCreate(Bundle savedInstanceState) {
71         super.onCreate(savedInstanceState);
72 
73         setContentView(R.layout.launcher);
74         mFire = (Button)findViewById(R.id.fire);
75         mFire.setOnClickListener(this);
76 
77         mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
78 
79         mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
80         mGravitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
81     }
82 
83     @Override
onPause()84     public void onPause() {
85         super.onPause();
86         mSensorManager.unregisterListener(mGravityListener);
87     }
88 
89     @Override
onResume()90     public void onResume() {
91         super.onResume();
92         mSensorManager.registerListener(mGravityListener, mGravitySensor,
93                 SensorManager.SENSOR_DELAY_NORMAL);
94 
95         Intent intent = getIntent();
96         Log.d(TAG, "intent: " + intent);
97         String action = intent.getAction();
98 
99         UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
100         if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
101             setDevice(device);
102         } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
103             if (mDevice != null && mDevice.equals(device)) {
104                 setDevice(null);
105             }
106         }
107     }
108 
109     @Override
onDestroy()110     public void onDestroy() {
111         super.onDestroy();
112     }
113 
setDevice(UsbDevice device)114     private void setDevice(UsbDevice device) {
115         Log.d(TAG, "setDevice " + device);
116         if (device.getInterfaceCount() != 1) {
117             Log.e(TAG, "could not find interface");
118             return;
119         }
120         UsbInterface intf = device.getInterface(0);
121         // device should have one endpoint
122         if (intf.getEndpointCount() != 1) {
123             Log.e(TAG, "could not find endpoint");
124             return;
125         }
126         // endpoint should be of type interrupt
127         UsbEndpoint ep = intf.getEndpoint(0);
128         if (ep.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) {
129             Log.e(TAG, "endpoint is not interrupt type");
130             return;
131         }
132         mDevice = device;
133         mEndpointIntr = ep;
134         if (device != null) {
135             UsbDeviceConnection connection = mUsbManager.openDevice(device);
136             if (connection != null && connection.claimInterface(intf, true)) {
137                 Log.d(TAG, "open SUCCESS");
138                 mConnection = connection;
139                 Thread thread = new Thread(this);
140                 thread.start();
141 
142             } else {
143                 Log.d(TAG, "open FAIL");
144                 mConnection = null;
145             }
146          }
147     }
148 
sendCommand(int control)149     private void sendCommand(int control) {
150         synchronized (this) {
151             if (control != COMMAND_STATUS) {
152                 Log.d(TAG, "sendMove " + control);
153             }
154             if (mConnection != null) {
155                 byte[] message = new byte[1];
156                 message[0] = (byte)control;
157                 // Send command via a control request on endpoint zero
158                 mConnection.controlTransfer(0x21, 0x9, 0x200, 0, message, message.length, 0);
159             }
160         }
161     }
162 
onClick(View v)163     public void onClick(View v) {
164         if (v == mFire) {
165             sendCommand(COMMAND_FIRE);
166         }
167     }
168 
169     private int mLastValue = 0;
170 
171     SensorEventListener mGravityListener = new SensorEventListener() {
172         public void onSensorChanged(SensorEvent event) {
173 
174             // compute current tilt
175             int value = 0;
176             if (event.values[0] < -THRESHOLD) {
177                 value += TILT_LEFT;
178             } else if (event.values[0] > THRESHOLD) {
179                 value += TILT_RIGHT;
180             }
181             if (event.values[1] < -THRESHOLD) {
182                 value += TILT_UP;
183             } else if (event.values[1] > THRESHOLD) {
184                 value += TILT_DOWN;
185             }
186 
187             if (value != mLastValue) {
188                 mLastValue = value;
189                 // send motion command if the tilt changed
190                 switch (value) {
191                     case TILT_LEFT:
192                         sendCommand(COMMAND_LEFT);
193                         break;
194                     case TILT_RIGHT:
195                        sendCommand(COMMAND_RIGHT);
196                         break;
197                     case TILT_UP:
198                         sendCommand(COMMAND_UP);
199                         break;
200                     case TILT_DOWN:
201                         sendCommand(COMMAND_DOWN);
202                         break;
203                     default:
204                         sendCommand(COMMAND_STOP);
205                         break;
206                 }
207             }
208         }
209 
210         public void onAccuracyChanged(Sensor sensor, int accuracy) {
211             // ignore
212         }
213     };
214 
215     @Override
run()216     public void run() {
217         ByteBuffer buffer = ByteBuffer.allocate(1);
218         UsbRequest request = new UsbRequest();
219         request.initialize(mConnection, mEndpointIntr);
220         byte status = -1;
221         while (true) {
222             // queue a request on the interrupt endpoint
223             request.queue(buffer, 1);
224             // send poll status command
225             sendCommand(COMMAND_STATUS);
226             // wait for status event
227             if (mConnection.requestWait() == request) {
228                 byte newStatus = buffer.get(0);
229                 if (newStatus != status) {
230                     Log.d(TAG, "got status " + newStatus);
231                     status = newStatus;
232                     if ((status & COMMAND_FIRE) != 0) {
233                         // stop firing
234                         sendCommand(COMMAND_STOP);
235                     }
236                 }
237                 try {
238                     Thread.sleep(100);
239                 } catch (InterruptedException e) {
240                 }
241             } else {
242                 Log.e(TAG, "requestWait failed, exiting");
243                 break;
244             }
245         }
246     }
247 }
248 
249 
250