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