8115955d572970025e31eced13f92a0a02bc8493
[hqbeamer.git] / src / de / bongo / android / hqbeamer / HQBeamerActivity.java
1 package de.bongo.android.hqbeamer;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.OutputStream;
6 import java.lang.reflect.InvocationTargetException;
7 import java.lang.reflect.Method;
8 import java.util.ArrayList;
9 import java.util.List;
10 import java.util.Set;
11
12 import android.app.Activity;
13 import android.app.AlertDialog;
14 import android.app.Dialog;
15 import android.app.ProgressDialog;
16 import android.bluetooth.BluetoothAdapter;
17 import android.bluetooth.BluetoothDevice;
18 import android.bluetooth.BluetoothSocket;
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.DialogInterface;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.Message;
27 import android.util.Log;
28 import android.widget.CompoundButton;
29 import android.widget.Toast;
30 import android.widget.CompoundButton.OnCheckedChangeListener;
31 import android.widget.ToggleButton;
32
33 public class HQBeamerActivity extends Activity {
34     ToggleButton powerToggle = (ToggleButton) findViewById(R.id.powerToggle);
35         private static final int REQUEST_ENABLE_BT = 0;
36         private static final int CHOOSE_DEVICE_DIALOG = 0;
37         private static final int WARN_CHOOSE_DEVICE = 1;
38         private Boolean isBluetoothEnabled = false;
39         private BluetoothAdapter mBluetoothAdapter;
40         private ArrayList<String> availableDevices;
41         private int deviceChosen = 0;
42         private ConnectThread connectThread;
43         private ConnectedThread connectedThread;
44         /* BEGIN Bluetooth / Beamer Messages */
45                 /* Begin IDs */
46                 private static final int MESSAGE_READ = 0;
47                 private static final int MESSAGE_WRITE = 1;
48                 /* end IDs */
49         private static final String POWER_ON = "!";
50         private static final String POWER_OFF = Character.toString((char)0x22);
51         /* END Bluetooth / Beamer Messages */
52
53         // Create a BroadcastReceiver for ACTION_FOUND
54     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
55             public void onReceive(Context context, Intent intent) {
56                 String action = intent.getAction();
57                 // When discovery finds a device
58                 if (BluetoothDevice.ACTION_FOUND.equals(action)) {
59                     // Get the BluetoothDevice object from the Intent
60                     BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
61                     // Add the name and address to an array adapter to show in a ListView
62                     availableDevices.add(device.getName() + "\n" + device.getAddress());
63                 }
64             }
65         };
66         
67     @Override
68     public void onCreate(Bundle savedInstanceState) {
69         super.onCreate(savedInstanceState);
70         setContentView(R.layout.main);
71        
72         /* Start Bluetooth Initialization */
73         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
74                 if (mBluetoothAdapter == null) {
75                         this.isBluetoothEnabled = false;
76                         new AlertDialog.Builder(this).setTitle("Error")
77                                            .setMessage("Your device seems not to support Bluetooth :(")
78                                            .setIcon(android.R.drawable.stat_notify_error)
79                                        .setCancelable(false)
80                                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
81                                            public void onClick(DialogInterface dialog, int id) {
82                                                    dialog.dismiss();
83                                            }
84                                        })
85                                 .create().show();
86                 }
87                 else {
88                         if (!mBluetoothAdapter.isEnabled()) {
89                             Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
90                             startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
91                         }
92                         else {
93                                 this.isBluetoothEnabled = true;
94                         }
95                 }
96                 /* Bluetooth is guaranteed to be avaliable now */
97         
98                 /* Prepare blouetooth connection */
99         if (connectThread != null) {connectThread.cancel(); connectThread = null;}
100                 while(doBluetoothInquiry());
101                  // TODO
102                 
103                 /* UI Element Setup */
104                 this.powerToggle.setOnCheckedChangeListener(new OnCheckedChangeListener() {
105                         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
106
107                         }
108                 });
109     }
110     
111     private boolean doBluetoothInquiry() {
112         availableDevices = new ArrayList<String>();
113                 ProgressDialog dialog = ProgressDialog.show(this, "", 
114                 "Scanning for bluetooth devices...", true);
115                 dialog.show();
116                 Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
117                 // If there are paired devices
118                 if (pairedDevices.size() > 0) {
119                     // Loop through paired devices
120                     for (BluetoothDevice device : pairedDevices) {
121                         // Add the name and address to an array adapter to show in a ListView
122                         availableDevices.add(device.getName() + "\n" + device.getAddress());
123                     }
124                 }
125                 showDialog(CHOOSE_DEVICE_DIALOG);
126                 if(deviceChosen == 0){ 
127                         availableDevices.clear();
128                         // user hasn't chosen any of the paired devs, trying to actively scan for some
129                         // Register the BroadcastReceiver
130                         IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
131                         registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
132                         showDialog(CHOOSE_DEVICE_DIALOG);
133                         if(deviceChosen != 0){
134                                 return true;
135                         }
136                         else {
137                                 showDialog(WARN_CHOOSE_DEVICE);
138                                 return false;
139                         }
140                 }
141                 else {
142                         return true;
143                 }
144     } 
145     
146     private class ConnectThread extends Thread {
147         private final BluetoothSocket mmSocket;
148         private final BluetoothDevice mmDevice;
149      
150         public ConnectThread(BluetoothDevice device) {
151             // Use a temporary object that is later assigned to mmSocket,
152             // because mmSocket is final
153             BluetoothSocket tmp = null;
154             mmDevice = device;
155      
156             // Get a BluetoothSocket to connect with the given BluetoothDevice
157             try {
158                 // MY_UUID is the app's UUID string, also used by the server code
159                 //FIXME may be not avail in later vers better would be API >=10 http://stackoverflow.com/questions/5308373/how-to-create-insecure-rfcomm-socket-in-android
160                 Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
161                 tmp = (BluetoothSocket) m.invoke(device, 1);
162             } catch (SecurityException e) {
163                                 e.printStackTrace();
164                         } catch (NoSuchMethodException e) {
165                                 e.printStackTrace();
166                         } catch (IllegalArgumentException e) {
167                                 e.printStackTrace();
168                         } catch (IllegalAccessException e) {
169                                 e.printStackTrace();
170                         } catch (InvocationTargetException e) {
171                                 e.printStackTrace();
172                         }
173             mmSocket = tmp;
174         }
175      
176         public void run() {
177             // Cancel discovery because it will slow down the connection
178             mBluetoothAdapter.cancelDiscovery();
179      
180             try {
181                 // Connect the device through the socket. This will block
182                 // until it succeeds or throws an exception
183                 mmSocket.connect();
184             } catch (IOException connectException) {
185                 // Unable to connect; close the socket and get out
186                 try {
187                     mmSocket.close();
188                 } catch (IOException closeException) { }
189                 return;
190             }
191      
192             // Do work to manage the connection (in a separate thread)
193             manageConnectedSocket(mmSocket);
194         }
195      
196         /** Will cancel an in-progress connection, and close the socket */
197         public void cancel() {
198             try {
199                 mmSocket.close();
200             } catch (IOException e) { }
201         }
202     }
203     
204     private class ConnectedThread extends Thread {
205         private final BluetoothSocket mmSocket;
206         private final InputStream mmInStream;
207         private final OutputStream mmOutStream;
208      
209         public ConnectedThread(BluetoothSocket socket) {
210             mmSocket = socket;
211             InputStream tmpIn = null;
212             OutputStream tmpOut = null;
213      
214             // Get the input and output streams, using temp objects because
215             // member streams are final
216             try {
217                 tmpIn = socket.getInputStream();
218                 tmpOut = socket.getOutputStream();
219             } catch (IOException e) { }
220      
221             mmInStream = tmpIn;
222             mmOutStream = tmpOut;
223         }
224      
225         public void run() {
226             byte[] buffer = new byte[1024];  // buffer store for the stream
227             int bytes; // bytes returned from read()
228      
229             // Keep listening to the InputStream until an exception occurs
230             while (true) {
231                 try {
232                     // Read from the InputStream
233                     bytes = mmInStream.read(buffer);
234                     // Send the obtained bytes to the UI Activity
235                     mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
236                             .sendToTarget();
237                 } catch (IOException e) {
238                     break;
239                 }
240             }
241         }
242      
243         /* Call this from the main Activity to send data to the remote device */
244         public void write(byte[] bytes) {
245             try {
246                 mmOutStream.write(bytes);
247             } catch (IOException e) { }
248         }
249      
250         /* Call this from the main Activity to shutdown the connection */
251         public void cancel() {
252             try {
253                 mmSocket.close();
254             } catch (IOException e) { }
255         }
256     }
257     
258     private final Handler mHandler = new Handler() {
259         @Override
260         public void handleMessage(Message msg) {
261             switch (msg.what) {
262             case MESSAGE_WRITE:
263                 byte[] writeBuf = (byte[]) msg.obj;
264                 break;
265             case MESSAGE_READ:
266                 byte[] readBuf = (byte[]) msg.obj;
267                 // FIXME check if correct code comes back
268                 break;
269             }
270         }
271     };
272
273     private void manageConnectedSocket(BluetoothSocket socket){
274         this.connectedThread = new ConnectedThread(socket);
275         connectedThread.start(); // FIXME run()?
276         // FIXME stub
277     }
278     
279 protected Dialog onCreateDialog(int id){
280         Dialog dialog;
281         switch(id){
282         case CHOOSE_DEVICE_DIALOG:
283                 dialog = new AlertDialog.Builder(HQBeamerActivity.this)
284                                                                 .setTitle("Pick a RFCOMM Device")
285                                                                 .setItems((String[])availableDevices.toArray(), new DialogInterface.OnClickListener() {
286                                                                     public void onClick(DialogInterface dialog, int item) {
287                                                                         HQBeamerActivity.this.deviceChosen = item;
288                                                                     }
289                                                                 }).create();
290                 return dialog;
291         case WARN_CHOOSE_DEVICE:
292                 dialog = new AlertDialog.Builder(HQBeamerActivity.this)
293                                                                 .setTitle("Warning")
294                                                                 .setMessage("It's required to choose a device!")
295                                                                 .setPositiveButton("Rescan", new DialogInterface.OnClickListener() {
296                                                                                 @Override
297                                                                                 public void onClick(DialogInterface arg0, int arg1) {
298                                                                                         doBluetoothInquiry();                                                                                   
299                                                                                 }
300                                                                         }).create();
301                 
302                 return dialog;
303         default:
304                 return null;
305         }
306     }
307     
308     protected void onActivityResult(int requestCode, int resultCode, Intent data){
309         if(requestCode == REQUEST_ENABLE_BT){
310                 if(resultCode != RESULT_OK){
311                         new AlertDialog.Builder(this).setTitle("Error")
312                                    .setMessage("Bluetooth not enabled")
313                                    .setIcon(android.R.drawable.stat_notify_error)
314                                .setCancelable(false)
315                                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
316                                    public void onClick(DialogInterface dialog, int id) {
317                                            dialog.dismiss();
318                                    }
319                                })
320                                .setPositiveButton("Retry", new DialogInterface.OnClickListener() {
321                                    public void onClick(DialogInterface dialog, int id) {
322                                                         if (!mBluetoothAdapter.isEnabled()) {
323                                                                 HQBeamerActivity.this.isBluetoothEnabled = true;
324                                                                 dialog.dismiss();
325                                                         }
326                                    }
327                                }).create().show();
328                 }
329         }       
330     }
331     
332     protected void onDestroy(){
333         unregisterReceiver(mReceiver);
334         super.onDestroy();
335     }
336 }