├── .gitignore
├── LICENSE
├── README.md
├── RemoteBluetooth
├── .classpath
├── .project
├── AndroidManifest.xml
├── default.properties
├── proguard.cfg
├── res
│ ├── drawable-hdpi
│ │ └── icon.png
│ ├── drawable-ldpi
│ │ └── icon.png
│ ├── drawable-mdpi
│ │ └── icon.png
│ ├── drawable
│ │ └── icon.png
│ ├── layout
│ │ ├── custom_title.xml
│ │ ├── device_list.xml
│ │ ├── device_name.xml
│ │ └── main.xml
│ ├── menu
│ │ └── option_menu.xml
│ └── values
│ │ └── strings.xml
└── src
│ └── com
│ └── luugiathuy
│ └── apps
│ └── remotebluetooth
│ ├── BluetoothCommandService.java
│ ├── DeviceListActivity.java
│ └── RemoteBluetooth.java
└── RemoteBluetoothServer
├── .classpath
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── lib
├── bluecove-2.1.0.jar
└── bluecove-gpl-2.1.0.jar
└── src
└── com
└── luugiathuy
└── apps
└── remotebluetooth
├── ProcessConnectionThread.java
├── RemoteBluetoothServer.java
└── WaitThread.java
/.gitignore:
--------------------------------------------------------------------------------
1 | bin*
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) [year] [fullname]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Java and Android Bluetooth
2 | =====================
3 |
4 | This project makes your Android phone as a remote for your computer by connecting via Bluetooth
5 |
6 | ##Usage
7 |
8 | Run the RemoteBluetoothServer project in your PC and install the RemoteBluetooth app in your Android phone.
9 |
10 | ##Notes
11 |
12 | If you have to run the server in linux, then make sure you install the libbluetooth-dev package.
13 |
14 | If you have to run the server in mac, configure eclipse to pass the -d32 JVM argument.
15 |
16 | ##Contact
17 | [@luugiathuy](http://twitter.com/luugiathuy)
18 |
--------------------------------------------------------------------------------
/RemoteBluetooth/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RemoteBluetooth/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | RemoteBluetooth
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/RemoteBluetooth/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/RemoteBluetooth/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-7
12 |
--------------------------------------------------------------------------------
/RemoteBluetooth/proguard.cfg:
--------------------------------------------------------------------------------
1 | -optimizationpasses 5
2 | -dontusemixedcaseclassnames
3 | -dontskipnonpubliclibraryclasses
4 | -dontpreverify
5 | -verbose
6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
7 |
8 | -keep public class * extends android.app.Activity
9 | -keep public class * extends android.app.Application
10 | -keep public class * extends android.app.Service
11 | -keep public class * extends android.content.BroadcastReceiver
12 | -keep public class * extends android.content.ContentProvider
13 | -keep public class com.android.vending.licensing.ILicensingService
14 |
15 | -keepclasseswithmembernames class * {
16 | native ;
17 | }
18 |
19 | -keepclasseswithmembernames class * {
20 | public (android.content.Context, android.util.AttributeSet);
21 | }
22 |
23 | -keepclasseswithmembernames class * {
24 | public (android.content.Context, android.util.AttributeSet, int);
25 | }
26 |
27 | -keepclassmembers enum * {
28 | public static **[] values();
29 | public static ** valueOf(java.lang.String);
30 | }
31 |
32 | -keep class * implements android.os.Parcelable {
33 | public static final android.os.Parcelable$Creator *;
34 | }
35 |
--------------------------------------------------------------------------------
/RemoteBluetooth/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luugiathuy/Remote-Bluetooth-Android/f7fea1d9640a10208c08a5197e5321d1f1082250/RemoteBluetooth/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/RemoteBluetooth/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luugiathuy/Remote-Bluetooth-Android/f7fea1d9640a10208c08a5197e5321d1f1082250/RemoteBluetooth/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/RemoteBluetooth/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luugiathuy/Remote-Bluetooth-Android/f7fea1d9640a10208c08a5197e5321d1f1082250/RemoteBluetooth/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/RemoteBluetooth/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luugiathuy/Remote-Bluetooth-Android/f7fea1d9640a10208c08a5197e5321d1f1082250/RemoteBluetooth/res/drawable/icon.png
--------------------------------------------------------------------------------
/RemoteBluetooth/res/layout/custom_title.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
21 |
30 |
39 |
--------------------------------------------------------------------------------
/RemoteBluetooth/res/layout/device_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
16 |
22 |
31 |
37 |
42 |
--------------------------------------------------------------------------------
/RemoteBluetooth/res/layout/device_name.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
--------------------------------------------------------------------------------
/RemoteBluetooth/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/RemoteBluetooth/res/menu/option_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/RemoteBluetooth/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World, RemoteBluetooth!
4 | RemoteBluetooth
5 | Find Device
6 | Bluetooth was not enabled. Leaving Remote Bluetooth
7 | Paired Devices
8 | Other Available Devices
9 | Scan for devices
10 | No devices have been paired
11 | scanning for devices...
12 | No devices found
13 | select a device to connect
14 | Connect a device
15 | Make discoverable
16 | connected:
17 | connecting...
18 | not connected
19 |
20 |
--------------------------------------------------------------------------------
/RemoteBluetooth/src/com/luugiathuy/apps/remotebluetooth/BluetoothCommandService.java:
--------------------------------------------------------------------------------
1 | package com.luugiathuy.apps.remotebluetooth;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.util.UUID;
7 |
8 | import android.bluetooth.BluetoothAdapter;
9 | import android.bluetooth.BluetoothDevice;
10 | import android.bluetooth.BluetoothSocket;
11 | import android.content.Context;
12 | import android.os.Bundle;
13 | import android.os.Handler;
14 | import android.os.Message;
15 | import android.util.Log;
16 |
17 | public class BluetoothCommandService {
18 | // Debugging
19 | private static final String TAG = "BluetoothCommandService";
20 | private static final boolean D = true;
21 |
22 | // Unique UUID for this application
23 | private static final UUID MY_UUID = UUID.fromString("04c6093b-0000-1000-8000-00805f9b34fb");
24 |
25 |
26 | // Member fields
27 | private final BluetoothAdapter mAdapter;
28 | private final Handler mHandler;
29 | private ConnectThread mConnectThread;
30 | private ConnectedThread mConnectedThread;
31 | private int mState;
32 | // private BluetoothDevice mSavedDevice;
33 | // private int mConnectionLostCount;
34 |
35 | // Constants that indicate the current connection state
36 | public static final int STATE_NONE = 0; // we're doing nothing
37 | public static final int STATE_LISTEN = 1; // now listening for incoming connections
38 | public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
39 | public static final int STATE_CONNECTED = 3; // now connected to a remote device
40 |
41 | // Constants that indicate command to computer
42 | public static final int EXIT_CMD = -1;
43 | public static final int VOL_UP = 1;
44 | public static final int VOL_DOWN = 2;
45 | public static final int MOUSE_MOVE = 3;
46 |
47 | /**
48 | * Constructor. Prepares a new BluetoothChat session.
49 | * @param context The UI Activity Context
50 | * @param handler A Handler to send messages back to the UI Activity
51 | */
52 | public BluetoothCommandService(Context context, Handler handler) {
53 | mAdapter = BluetoothAdapter.getDefaultAdapter();
54 | mState = STATE_NONE;
55 | //mConnectionLostCount = 0;
56 | mHandler = handler;
57 | }
58 |
59 | /**
60 | * Set the current state of the chat connection
61 | * @param state An integer defining the current connection state
62 | */
63 | private synchronized void setState(int state) {
64 | if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
65 | mState = state;
66 |
67 | // Give the new state to the Handler so the UI Activity can update
68 | mHandler.obtainMessage(RemoteBluetooth.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
69 | }
70 |
71 | /**
72 | * Return the current connection state. */
73 | public synchronized int getState() {
74 | return mState;
75 | }
76 |
77 | /**
78 | * Start the chat service. Specifically start AcceptThread to begin a
79 | * session in listening (server) mode. Called by the Activity onResume() */
80 | public synchronized void start() {
81 | if (D) Log.d(TAG, "start");
82 |
83 | // Cancel any thread attempting to make a connection
84 | if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
85 |
86 | // Cancel any thread currently running a connection
87 | if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
88 |
89 | setState(STATE_LISTEN);
90 | }
91 |
92 | /**
93 | * Start the ConnectThread to initiate a connection to a remote device.
94 | * @param device The BluetoothDevice to connect
95 | */
96 | public synchronized void connect(BluetoothDevice device) {
97 | if (D) Log.d(TAG, "connect to: " + device);
98 |
99 | // Cancel any thread attempting to make a connection
100 | if (mState == STATE_CONNECTING) {
101 | if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
102 | }
103 |
104 | // Cancel any thread currently running a connection
105 | if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
106 |
107 | // Start the thread to connect with the given device
108 | mConnectThread = new ConnectThread(device);
109 | mConnectThread.start();
110 | setState(STATE_CONNECTING);
111 | }
112 |
113 | /**
114 | * Start the ConnectedThread to begin managing a Bluetooth connection
115 | * @param socket The BluetoothSocket on which the connection was made
116 | * @param device The BluetoothDevice that has been connected
117 | */
118 | public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
119 | if (D) Log.d(TAG, "connected");
120 |
121 | // Cancel the thread that completed the connection
122 | if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
123 |
124 | // Cancel any thread currently running a connection
125 | if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
126 |
127 | // Start the thread to manage the connection and perform transmissions
128 | mConnectedThread = new ConnectedThread(socket);
129 | mConnectedThread.start();
130 |
131 | // Send the name of the connected device back to the UI Activity
132 | Message msg = mHandler.obtainMessage(RemoteBluetooth.MESSAGE_DEVICE_NAME);
133 | Bundle bundle = new Bundle();
134 | bundle.putString(RemoteBluetooth.DEVICE_NAME, device.getName());
135 | msg.setData(bundle);
136 | mHandler.sendMessage(msg);
137 |
138 | // save connected device
139 | //mSavedDevice = device;
140 | // reset connection lost count
141 | //mConnectionLostCount = 0;
142 |
143 | setState(STATE_CONNECTED);
144 | }
145 |
146 | /**
147 | * Stop all threads
148 | */
149 | public synchronized void stop() {
150 | if (D) Log.d(TAG, "stop");
151 | if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
152 | if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
153 |
154 | setState(STATE_NONE);
155 | }
156 |
157 | /**
158 | * Write to the ConnectedThread in an unsynchronized manner
159 | * @param out The bytes to write
160 | * @see ConnectedThread#write(byte[])
161 | */
162 | public void write(byte[] out) {
163 | // Create temporary object
164 | ConnectedThread r;
165 | // Synchronize a copy of the ConnectedThread
166 | synchronized (this) {
167 | if (mState != STATE_CONNECTED) return;
168 | r = mConnectedThread;
169 | }
170 | // Perform the write unsynchronized
171 | r.write(out);
172 | }
173 |
174 | public void write(int out) {
175 | // Create temporary object
176 | ConnectedThread r;
177 | // Synchronize a copy of the ConnectedThread
178 | synchronized (this) {
179 | if (mState != STATE_CONNECTED) return;
180 | r = mConnectedThread;
181 | }
182 | // Perform the write unsynchronized
183 | r.write(out);
184 | }
185 |
186 | /**
187 | * Indicate that the connection attempt failed and notify the UI Activity.
188 | */
189 | private void connectionFailed() {
190 | setState(STATE_LISTEN);
191 |
192 | // Send a failure message back to the Activity
193 | Message msg = mHandler.obtainMessage(RemoteBluetooth.MESSAGE_TOAST);
194 | Bundle bundle = new Bundle();
195 | bundle.putString(RemoteBluetooth.TOAST, "Unable to connect device");
196 | msg.setData(bundle);
197 | mHandler.sendMessage(msg);
198 | }
199 |
200 | /**
201 | * Indicate that the connection was lost and notify the UI Activity.
202 | */
203 | private void connectionLost() {
204 | // mConnectionLostCount++;
205 | // if (mConnectionLostCount < 3) {
206 | // // Send a reconnect message back to the Activity
207 | // Message msg = mHandler.obtainMessage(RemoteBluetooth.MESSAGE_TOAST);
208 | // Bundle bundle = new Bundle();
209 | // bundle.putString(RemoteBluetooth.TOAST, "Device connection was lost. Reconnecting...");
210 | // msg.setData(bundle);
211 | // mHandler.sendMessage(msg);
212 | //
213 | // connect(mSavedDevice);
214 | // } else {
215 | setState(STATE_LISTEN);
216 | // Send a failure message back to the Activity
217 | Message msg = mHandler.obtainMessage(RemoteBluetooth.MESSAGE_TOAST);
218 | Bundle bundle = new Bundle();
219 | bundle.putString(RemoteBluetooth.TOAST, "Device connection was lost");
220 | msg.setData(bundle);
221 | mHandler.sendMessage(msg);
222 | // }
223 | }
224 |
225 | /**
226 | * This thread runs while attempting to make an outgoing connection
227 | * with a device. It runs straight through; the connection either
228 | * succeeds or fails.
229 | */
230 | private class ConnectThread extends Thread {
231 | private final BluetoothSocket mmSocket;
232 | private final BluetoothDevice mmDevice;
233 |
234 | public ConnectThread(BluetoothDevice device) {
235 | mmDevice = device;
236 | BluetoothSocket tmp = null;
237 |
238 | // Get a BluetoothSocket for a connection with the
239 | // given BluetoothDevice
240 | try {
241 | tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
242 | } catch (IOException e) {
243 | Log.e(TAG, "create() failed", e);
244 | }
245 | mmSocket = tmp;
246 | }
247 |
248 | public void run() {
249 | Log.i(TAG, "BEGIN mConnectThread");
250 | setName("ConnectThread");
251 |
252 | // Always cancel discovery because it will slow down a connection
253 | mAdapter.cancelDiscovery();
254 |
255 | // Make a connection to the BluetoothSocket
256 | try {
257 | // This is a blocking call and will only return on a
258 | // successful connection or an exception
259 | mmSocket.connect();
260 | } catch (IOException e) {
261 | connectionFailed();
262 | // Close the socket
263 | try {
264 | mmSocket.close();
265 | } catch (IOException e2) {
266 | Log.e(TAG, "unable to close() socket during connection failure", e2);
267 | }
268 | // Start the service over to restart listening mode
269 | BluetoothCommandService.this.start();
270 | return;
271 | }
272 |
273 | // Reset the ConnectThread because we're done
274 | synchronized (BluetoothCommandService.this) {
275 | mConnectThread = null;
276 | }
277 |
278 | // Start the connected thread
279 | connected(mmSocket, mmDevice);
280 | }
281 |
282 | public void cancel() {
283 | try {
284 | mmSocket.close();
285 | } catch (IOException e) {
286 | Log.e(TAG, "close() of connect socket failed", e);
287 | }
288 | }
289 | }
290 |
291 | /**
292 | * This thread runs during a connection with a remote device.
293 | * It handles all incoming and outgoing transmissions.
294 | */
295 | private class ConnectedThread extends Thread {
296 | private final BluetoothSocket mmSocket;
297 | private final InputStream mmInStream;
298 | private final OutputStream mmOutStream;
299 |
300 | public ConnectedThread(BluetoothSocket socket) {
301 | Log.d(TAG, "create ConnectedThread");
302 | mmSocket = socket;
303 | InputStream tmpIn = null;
304 | OutputStream tmpOut = null;
305 |
306 | // Get the BluetoothSocket input and output streams
307 | try {
308 | tmpIn = socket.getInputStream();
309 | tmpOut = socket.getOutputStream();
310 | } catch (IOException e) {
311 | Log.e(TAG, "temp sockets not created", e);
312 | }
313 |
314 | mmInStream = tmpIn;
315 | mmOutStream = tmpOut;
316 | }
317 |
318 | public void run() {
319 | Log.i(TAG, "BEGIN mConnectedThread");
320 | byte[] buffer = new byte[1024];
321 |
322 | // Keep listening to the InputStream while connected
323 | while (true) {
324 | try {
325 | // Read from the InputStream
326 | int bytes = mmInStream.read(buffer);
327 |
328 | // Send the obtained bytes to the UI Activity
329 | mHandler.obtainMessage(RemoteBluetooth.MESSAGE_READ, bytes, -1, buffer)
330 | .sendToTarget();
331 | } catch (IOException e) {
332 | Log.e(TAG, "disconnected", e);
333 | connectionLost();
334 | break;
335 | }
336 | }
337 | }
338 |
339 | /**
340 | * Write to the connected OutStream.
341 | * @param buffer The bytes to write
342 | */
343 | public void write(byte[] buffer) {
344 | try {
345 | mmOutStream.write(buffer);
346 |
347 | // Share the sent message back to the UI Activity
348 | // mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
349 | // .sendToTarget();
350 | } catch (IOException e) {
351 | Log.e(TAG, "Exception during write", e);
352 | }
353 | }
354 |
355 | public void write(int out) {
356 | try {
357 | mmOutStream.write(out);
358 |
359 | // Share the sent message back to the UI Activity
360 | // mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
361 | // .sendToTarget();
362 | } catch (IOException e) {
363 | Log.e(TAG, "Exception during write", e);
364 | }
365 | }
366 |
367 | public void cancel() {
368 | try {
369 | mmOutStream.write(EXIT_CMD);
370 | mmSocket.close();
371 | } catch (IOException e) {
372 | Log.e(TAG, "close() of connect socket failed", e);
373 | }
374 | }
375 | }
376 | }
--------------------------------------------------------------------------------
/RemoteBluetooth/src/com/luugiathuy/apps/remotebluetooth/DeviceListActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 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.luugiathuy.apps.remotebluetooth;
18 |
19 | import java.util.Set;
20 |
21 | import android.app.Activity;
22 | import android.bluetooth.BluetoothAdapter;
23 | import android.bluetooth.BluetoothDevice;
24 | import android.content.BroadcastReceiver;
25 | import android.content.Context;
26 | import android.content.Intent;
27 | import android.content.IntentFilter;
28 | import android.os.Bundle;
29 | import android.util.Log;
30 | import android.view.View;
31 | import android.view.Window;
32 | import android.view.View.OnClickListener;
33 | import android.widget.AdapterView;
34 | import android.widget.ArrayAdapter;
35 | import android.widget.Button;
36 | import android.widget.ListView;
37 | import android.widget.TextView;
38 | import android.widget.AdapterView.OnItemClickListener;
39 |
40 | /**
41 | * This Activity appears as a dialog. It lists any paired devices and
42 | * devices detected in the area after discovery. When a device is chosen
43 | * by the user, the MAC address of the device is sent back to the parent
44 | * Activity in the result Intent.
45 | */
46 | public class DeviceListActivity extends Activity {
47 | // Debugging
48 | private static final String TAG = "DeviceListActivity";
49 | private static final boolean D = true;
50 |
51 | // Return Intent extra
52 | public static String EXTRA_DEVICE_ADDRESS = "device_address";
53 |
54 | // Member fields
55 | private BluetoothAdapter mBtAdapter;
56 | private ArrayAdapter mPairedDevicesArrayAdapter;
57 | private ArrayAdapter mNewDevicesArrayAdapter;
58 |
59 | @Override
60 | protected void onCreate(Bundle savedInstanceState) {
61 | super.onCreate(savedInstanceState);
62 |
63 | // Setup the window
64 | requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
65 | setContentView(R.layout.device_list);
66 |
67 | // Set result CANCELED incase the user backs out
68 | setResult(Activity.RESULT_CANCELED);
69 |
70 | // Initialize the button to perform device discovery
71 | Button scanButton = (Button) findViewById(R.id.button_scan);
72 | scanButton.setOnClickListener(new OnClickListener() {
73 | public void onClick(View v) {
74 | doDiscovery();
75 | v.setVisibility(View.GONE);
76 | }
77 | });
78 |
79 | // Initialize array adapters. One for already paired devices and
80 | // one for newly discovered devices
81 | mPairedDevicesArrayAdapter = new ArrayAdapter(this, R.layout.device_name);
82 | mNewDevicesArrayAdapter = new ArrayAdapter(this, R.layout.device_name);
83 |
84 | // Find and set up the ListView for paired devices
85 | ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
86 | pairedListView.setAdapter(mPairedDevicesArrayAdapter);
87 | pairedListView.setOnItemClickListener(mDeviceClickListener);
88 |
89 | // Find and set up the ListView for newly discovered devices
90 | ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
91 | newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
92 | newDevicesListView.setOnItemClickListener(mDeviceClickListener);
93 |
94 | // Register for broadcasts when a device is discovered
95 | IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
96 | this.registerReceiver(mReceiver, filter);
97 |
98 | // Register for broadcasts when discovery has finished
99 | filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
100 | this.registerReceiver(mReceiver, filter);
101 |
102 | // Get the local Bluetooth adapter
103 | mBtAdapter = BluetoothAdapter.getDefaultAdapter();
104 |
105 | // Get a set of currently paired devices
106 | Set pairedDevices = mBtAdapter.getBondedDevices();
107 |
108 | // If there are paired devices, add each one to the ArrayAdapter
109 | if (pairedDevices.size() > 0) {
110 | findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
111 | for (BluetoothDevice device : pairedDevices) {
112 | mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
113 | }
114 | } else {
115 | String noDevices = getResources().getText(R.string.none_paired).toString();
116 | mPairedDevicesArrayAdapter.add(noDevices);
117 | }
118 | }
119 |
120 | @Override
121 | protected void onDestroy() {
122 | super.onDestroy();
123 |
124 | // Make sure we're not doing discovery anymore
125 | if (mBtAdapter != null) {
126 | mBtAdapter.cancelDiscovery();
127 | }
128 |
129 | // Unregister broadcast listeners
130 | this.unregisterReceiver(mReceiver);
131 | }
132 |
133 | /**
134 | * Start device discover with the BluetoothAdapter
135 | */
136 | private void doDiscovery() {
137 | if (D) Log.d(TAG, "doDiscovery()");
138 |
139 | // Indicate scanning in the title
140 | setProgressBarIndeterminateVisibility(true);
141 | setTitle(R.string.scanning);
142 |
143 | // Turn on sub-title for new devices
144 | findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
145 |
146 | // If we're already discovering, stop it
147 | if (mBtAdapter.isDiscovering()) {
148 | mBtAdapter.cancelDiscovery();
149 | }
150 |
151 | // Request discover from BluetoothAdapter
152 | mBtAdapter.startDiscovery();
153 | }
154 |
155 | // The on-click listener for all devices in the ListViews
156 | private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
157 | public void onItemClick(AdapterView> av, View v, int arg2, long arg3) {
158 | // Cancel discovery because it's costly and we're about to connect
159 | mBtAdapter.cancelDiscovery();
160 |
161 | // Get the device MAC address, which is the last 17 chars in the View
162 | String info = ((TextView) v).getText().toString();
163 | String address = info.substring(info.length() - 17);
164 |
165 | // Create the result Intent and include the MAC address
166 | Intent intent = new Intent();
167 | intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
168 |
169 | // Set result and finish this Activity
170 | setResult(Activity.RESULT_OK, intent);
171 | finish();
172 | }
173 | };
174 |
175 | // The BroadcastReceiver that listens for discovered devices and
176 | // changes the title when discovery is finished
177 | private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
178 | @Override
179 | public void onReceive(Context context, Intent intent) {
180 | String action = intent.getAction();
181 |
182 | // When discovery finds a device
183 | if (BluetoothDevice.ACTION_FOUND.equals(action)) {
184 | // Get the BluetoothDevice object from the Intent
185 | BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
186 | // If it's already paired, skip it, because it's been listed already
187 | if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
188 | mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
189 | }
190 | // When discovery is finished, change the Activity title
191 | } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
192 | setProgressBarIndeterminateVisibility(false);
193 | setTitle(R.string.select_device);
194 | if (mNewDevicesArrayAdapter.getCount() == 0) {
195 | String noDevices = getResources().getText(R.string.none_found).toString();
196 | mNewDevicesArrayAdapter.add(noDevices);
197 | }
198 | }
199 | }
200 | };
201 |
202 | }
--------------------------------------------------------------------------------
/RemoteBluetooth/src/com/luugiathuy/apps/remotebluetooth/RemoteBluetooth.java:
--------------------------------------------------------------------------------
1 | package com.luugiathuy.apps.remotebluetooth;
2 |
3 | import android.app.Activity;
4 | import android.bluetooth.BluetoothAdapter;
5 | import android.bluetooth.BluetoothDevice;
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import android.os.Handler;
9 | import android.os.Message;
10 | import android.view.KeyEvent;
11 | import android.view.Menu;
12 | import android.view.MenuInflater;
13 | import android.view.MenuItem;
14 | import android.view.Window;
15 | import android.widget.TextView;
16 | import android.widget.Toast;
17 |
18 | public class RemoteBluetooth extends Activity {
19 |
20 | // Layout view
21 | private TextView mTitle;
22 |
23 | // Intent request codes
24 | private static final int REQUEST_CONNECT_DEVICE = 1;
25 | private static final int REQUEST_ENABLE_BT = 2;
26 |
27 | // Message types sent from the BluetoothChatService Handler
28 | public static final int MESSAGE_STATE_CHANGE = 1;
29 | public static final int MESSAGE_READ = 2;
30 | public static final int MESSAGE_WRITE = 3;
31 | public static final int MESSAGE_DEVICE_NAME = 4;
32 | public static final int MESSAGE_TOAST = 5;
33 |
34 | // Key names received from the BluetoothCommandService Handler
35 | public static final String DEVICE_NAME = "device_name";
36 | public static final String TOAST = "toast";
37 |
38 | // Name of the connected device
39 | private String mConnectedDeviceName = null;
40 | // Local Bluetooth adapter
41 | private BluetoothAdapter mBluetoothAdapter = null;
42 | // Member object for Bluetooth Command Service
43 | private BluetoothCommandService mCommandService = null;
44 |
45 | /** Called when the activity is first created. */
46 | @Override
47 | public void onCreate(Bundle savedInstanceState) {
48 | super.onCreate(savedInstanceState);
49 |
50 | // Set up the window layout
51 | requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
52 | setContentView(R.layout.main);
53 | getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);
54 |
55 | // Set up the custom title
56 | mTitle = (TextView) findViewById(R.id.title_left_text);
57 | mTitle.setText(R.string.app_name);
58 | mTitle = (TextView) findViewById(R.id.title_right_text);
59 |
60 | // Get local Bluetooth adapter
61 | mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
62 |
63 | // If the adapter is null, then Bluetooth is not supported
64 | if (mBluetoothAdapter == null) {
65 | Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
66 | finish();
67 | return;
68 | }
69 | }
70 |
71 | @Override
72 | protected void onStart() {
73 | super.onStart();
74 |
75 | // If BT is not on, request that it be enabled.
76 | // setupCommand() will then be called during onActivityResult
77 | if (!mBluetoothAdapter.isEnabled()) {
78 | Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
79 | startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
80 | }
81 | // otherwise set up the command service
82 | else {
83 | if (mCommandService==null)
84 | setupCommand();
85 | }
86 | }
87 |
88 | @Override
89 | protected void onResume() {
90 | super.onResume();
91 |
92 | // Performing this check in onResume() covers the case in which BT was
93 | // not enabled during onStart(), so we were paused to enable it...
94 | // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
95 | if (mCommandService != null) {
96 | if (mCommandService.getState() == BluetoothCommandService.STATE_NONE) {
97 | mCommandService.start();
98 | }
99 | }
100 | }
101 |
102 | private void setupCommand() {
103 | // Initialize the BluetoothChatService to perform bluetooth connections
104 | mCommandService = new BluetoothCommandService(this, mHandler);
105 | }
106 |
107 | @Override
108 | protected void onDestroy() {
109 | super.onDestroy();
110 |
111 | if (mCommandService != null)
112 | mCommandService.stop();
113 | }
114 |
115 | private void ensureDiscoverable() {
116 | if (mBluetoothAdapter.getScanMode() !=
117 | BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
118 | Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
119 | discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
120 | startActivity(discoverableIntent);
121 | }
122 | }
123 |
124 | // The Handler that gets information back from the BluetoothChatService
125 | private final Handler mHandler = new Handler() {
126 | @Override
127 | public void handleMessage(Message msg) {
128 | switch (msg.what) {
129 | case MESSAGE_STATE_CHANGE:
130 | switch (msg.arg1) {
131 | case BluetoothCommandService.STATE_CONNECTED:
132 | mTitle.setText(R.string.title_connected_to);
133 | mTitle.append(mConnectedDeviceName);
134 | break;
135 | case BluetoothCommandService.STATE_CONNECTING:
136 | mTitle.setText(R.string.title_connecting);
137 | break;
138 | case BluetoothCommandService.STATE_LISTEN:
139 | case BluetoothCommandService.STATE_NONE:
140 | mTitle.setText(R.string.title_not_connected);
141 | break;
142 | }
143 | break;
144 | case MESSAGE_DEVICE_NAME:
145 | // save the connected device's name
146 | mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
147 | Toast.makeText(getApplicationContext(), "Connected to "
148 | + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
149 | break;
150 | case MESSAGE_TOAST:
151 | Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
152 | Toast.LENGTH_SHORT).show();
153 | break;
154 | }
155 | }
156 | };
157 |
158 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
159 | switch (requestCode) {
160 | case REQUEST_CONNECT_DEVICE:
161 | // When DeviceListActivity returns with a device to connect
162 | if (resultCode == Activity.RESULT_OK) {
163 | // Get the device MAC address
164 | String address = data.getExtras()
165 | .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
166 | // Get the BLuetoothDevice object
167 | BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
168 | // Attempt to connect to the device
169 | mCommandService.connect(device);
170 | }
171 | break;
172 | case REQUEST_ENABLE_BT:
173 | // When the request to enable Bluetooth returns
174 | if (resultCode == Activity.RESULT_OK) {
175 | // Bluetooth is now enabled, so set up a chat session
176 | setupCommand();
177 | } else {
178 | // User did not enable Bluetooth or an error occured
179 | Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
180 | finish();
181 | }
182 | }
183 | }
184 |
185 | @Override
186 | public boolean onCreateOptionsMenu(Menu menu) {
187 | MenuInflater inflater = getMenuInflater();
188 | inflater.inflate(R.menu.option_menu, menu);
189 | return true;
190 | }
191 |
192 | @Override
193 | public boolean onOptionsItemSelected(MenuItem item) {
194 | switch (item.getItemId()) {
195 | case R.id.scan:
196 | // Launch the DeviceListActivity to see devices and do scan
197 | Intent serverIntent = new Intent(this, DeviceListActivity.class);
198 | startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
199 | return true;
200 | case R.id.discoverable:
201 | // Ensure this device is discoverable by others
202 | ensureDiscoverable();
203 | return true;
204 | }
205 | return false;
206 | }
207 |
208 | @Override
209 | public boolean onKeyDown(int keyCode, KeyEvent event) {
210 | if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
211 | mCommandService.write(BluetoothCommandService.VOL_UP);
212 | return true;
213 | }
214 | else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN){
215 | mCommandService.write(BluetoothCommandService.VOL_DOWN);
216 | return true;
217 | }
218 |
219 | return super.onKeyDown(keyCode, event);
220 | }
221 | }
--------------------------------------------------------------------------------
/RemoteBluetoothServer/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/RemoteBluetoothServer/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | RemoteBluetoothServer
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/RemoteBluetoothServer/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Thu Feb 24 14:31:31 SGT 2011
2 | eclipse.preferences.version=1
3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
6 | org.eclipse.jdt.core.compiler.compliance=1.6
7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
12 | org.eclipse.jdt.core.compiler.source=1.6
13 |
--------------------------------------------------------------------------------
/RemoteBluetoothServer/lib/bluecove-2.1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luugiathuy/Remote-Bluetooth-Android/f7fea1d9640a10208c08a5197e5321d1f1082250/RemoteBluetoothServer/lib/bluecove-2.1.0.jar
--------------------------------------------------------------------------------
/RemoteBluetoothServer/lib/bluecove-gpl-2.1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luugiathuy/Remote-Bluetooth-Android/f7fea1d9640a10208c08a5197e5321d1f1082250/RemoteBluetoothServer/lib/bluecove-gpl-2.1.0.jar
--------------------------------------------------------------------------------
/RemoteBluetoothServer/src/com/luugiathuy/apps/remotebluetooth/ProcessConnectionThread.java:
--------------------------------------------------------------------------------
1 | package com.luugiathuy.apps.remotebluetooth;
2 |
3 | import java.awt.Robot;
4 | import java.awt.event.KeyEvent;
5 | import java.io.InputStream;
6 |
7 | import javax.microedition.io.StreamConnection;
8 |
9 | public class ProcessConnectionThread implements Runnable{
10 |
11 | private StreamConnection mConnection;
12 |
13 | // Constant that indicate command from devices
14 | private static final int EXIT_CMD = -1;
15 | private static final int KEY_RIGHT = 1;
16 | private static final int KEY_LEFT = 2;
17 |
18 | public ProcessConnectionThread(StreamConnection connection)
19 | {
20 | mConnection = connection;
21 | }
22 |
23 | @Override
24 | public void run() {
25 | try {
26 |
27 | // prepare to receive data
28 | InputStream inputStream = mConnection.openInputStream();
29 |
30 | System.out.println("waiting for input");
31 |
32 | while (true) {
33 | int command = inputStream.read();
34 |
35 | if (command == EXIT_CMD)
36 | {
37 | System.out.println("finish process");
38 | break;
39 | }
40 |
41 | processCommand(command);
42 | }
43 | } catch (Exception e) {
44 | e.printStackTrace();
45 | }
46 | }
47 |
48 | /**
49 | * Process the command from client
50 | * @param command the command code
51 | */
52 | private void processCommand(int command) {
53 | try {
54 | Robot robot = new Robot();
55 | switch (command) {
56 | case KEY_RIGHT:
57 | robot.keyPress(KeyEvent.VK_RIGHT);
58 | System.out.println("Right");
59 | // release the key after it is pressed. Otherwise the event just keeps getting trigged
60 | robot.keyRelease(KeyEvent.VK_RIGHT);
61 | break;
62 | case KEY_LEFT:
63 | robot.keyPress(KeyEvent.VK_LEFT);
64 | System.out.println("Left");
65 | // release the key after it is pressed. Otherwise the event just keeps getting trigged
66 | robot.keyRelease(KeyEvent.VK_LEFT);
67 | break;
68 | }
69 | } catch (Exception e) {
70 | e.printStackTrace();
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/RemoteBluetoothServer/src/com/luugiathuy/apps/remotebluetooth/RemoteBluetoothServer.java:
--------------------------------------------------------------------------------
1 | package com.luugiathuy.apps.remotebluetooth;
2 |
3 | public class RemoteBluetoothServer{
4 |
5 | public static void main(String[] args) {
6 | Thread waitThread = new Thread(new WaitThread());
7 | waitThread.start();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/RemoteBluetoothServer/src/com/luugiathuy/apps/remotebluetooth/WaitThread.java:
--------------------------------------------------------------------------------
1 | package com.luugiathuy.apps.remotebluetooth;
2 |
3 | import java.io.IOException;
4 |
5 | import javax.bluetooth.BluetoothStateException;
6 | import javax.bluetooth.DiscoveryAgent;
7 | import javax.bluetooth.LocalDevice;
8 | import javax.bluetooth.UUID;
9 | import javax.microedition.io.Connector;
10 | import javax.microedition.io.StreamConnection;
11 | import javax.microedition.io.StreamConnectionNotifier;
12 |
13 | public class WaitThread implements Runnable{
14 |
15 | /** Constructor */
16 | public WaitThread() {
17 | }
18 |
19 | @Override
20 | public void run() {
21 | waitForConnection();
22 | }
23 |
24 | /** Waiting for connection from devices */
25 | private void waitForConnection() {
26 | // retrieve the local Bluetooth device object
27 | LocalDevice local = null;
28 |
29 | StreamConnectionNotifier notifier;
30 | StreamConnection connection = null;
31 |
32 | // setup the server to listen for connection
33 | try {
34 | local = LocalDevice.getLocalDevice();
35 | local.setDiscoverable(DiscoveryAgent.GIAC);
36 |
37 | UUID uuid = new UUID("04c6093b00001000800000805f9b34fb", false);
38 | System.out.println(uuid.toString());
39 |
40 | String url = "btspp://localhost:" + uuid.toString() + ";name=RemoteBluetooth";
41 | notifier = (StreamConnectionNotifier)Connector.open(url);
42 | } catch (BluetoothStateException e) {
43 | System.out.println("Bluetooth is not turned on.");
44 | e.printStackTrace();
45 | return;
46 | } catch (IOException e) {
47 | e.printStackTrace();
48 | return;
49 | }
50 |
51 | // waiting for connection
52 | while(true) {
53 | try {
54 | System.out.println("waiting for connection...");
55 | connection = notifier.acceptAndOpen();
56 |
57 | Thread processThread = new Thread(new ProcessConnectionThread(connection));
58 | processThread.start();
59 |
60 | } catch (Exception e) {
61 | e.printStackTrace();
62 | return;
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------