3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BleUARTPeripheral
2 | Android App for running UART GATT Server (Peripheral) on phone
3 |
4 |
5 | #Logo
6 | Based on [Serial Port image by Dalpat Prajapati](https://thenounproject.com/DalpatPrajapati/)
7 |
8 | #Install
9 | You can install from [Playstore](https://play.google.com/store/apps/details?id=thejeshgn.com.bleuartperipheral) or from Release on GH.
10 |
11 |
12 | #TODOs
13 | - Give a start and stop button for the GATT server
14 | - Add an about page with credits
15 | - NRF Loggger display
16 | - Ability to recieive and show Sensor Data Sent using [Adafruit UART Controller](https://learn.adafruit.com/bluefruit-le-connect-for-ios/controller)
17 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/apk_01.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thejeshgn/BleUARTPeripheral/e1f89708368c382207f35b834070b90dcb4db8f0/app/apk_01.apk
--------------------------------------------------------------------------------
/app/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thejeshgn/BleUARTPeripheral/e1f89708368c382207f35b834070b90dcb4db8f0/app/app-release.apk
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "24.0.2"
6 | defaultConfig {
7 | applicationId "thejeshgn.com.bleuartperipheral"
8 | minSdkVersion 21
9 | targetSdkVersion 24
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:24.2.1'
28 | compile 'no.nordicsemi.android:log:2.0.0'
29 | compile 'com.android.support:design:24.2.1'
30 | testCompile 'junit:junit:4.12'
31 | }
32 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/thej/Android/Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thejeshgn/BleUARTPeripheral/e1f89708368c382207f35b834070b90dcb4db8f0/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/thejeshgn/com/bleuartperipheral/AboutActivity.java:
--------------------------------------------------------------------------------
1 | package thejeshgn.com.bleuartperipheral;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.design.widget.FloatingActionButton;
6 | import android.support.design.widget.Snackbar;
7 | import android.support.v4.app.NavUtils;
8 | import android.support.v4.app.TaskStackBuilder;
9 | import android.support.v7.app.ActionBar;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.support.v7.widget.Toolbar;
12 | import android.text.Html;
13 | import android.text.method.LinkMovementMethod;
14 | import android.text.util.Linkify;
15 | import android.view.MenuItem;
16 | import android.view.View;
17 | import android.widget.TextView;
18 |
19 | public class AboutActivity extends AppCompatActivity {
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_about);
25 | setTitle("About");
26 | ActionBar actionBar = getSupportActionBar();
27 | actionBar.setDisplayHomeAsUpEnabled(true);
28 |
29 |
30 |
31 | TextView text = new TextView(this);
32 | text.setPadding(20, 20, 20, 10);
33 | text.setMovementMethod(LinkMovementMethod.getInstance());
34 | setContentView(text);
35 | StringBuilder content =new StringBuilder("BleUARTPeripheral is an Android app that simulates the UART Peripheral on phone. This is for developers to test their client app.
");
36 | content.append(" Its a UART simple server, once connected it responds to commands like whoami or date etc. If it can’t figure then it just echos whatever client has sent.
");
37 | content.append(" Its Free and Open Source App. You can use the app as is or use the code in your project. More details on GitHub
");
38 | content.append(" Logo is based on Serial Port image by Dalpat Prajapati.
");
39 | content.append(" Thejesh GN
");
40 | text.setText(Html.fromHtml(content.toString()));
41 | }
42 |
43 |
44 | @Override
45 | public boolean onOptionsItemSelected(MenuItem item) {
46 | switch (item.getItemId()) {
47 | case android.R.id.home:
48 | // This is called when the Home (Up) button is pressed in the action bar.
49 | // Create a simple intent that starts the hierarchical parent activity and
50 | // use NavUtils in the Support Package to ensure proper handling of Up.
51 | Intent upIntent = new Intent(this, MainActivity.class);
52 | if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
53 | // This activity is not part of the application's task, so create a new task
54 | // with a synthesized back stack.
55 | TaskStackBuilder.from(this)
56 | // If there are ancestor activities, they should be added here.
57 | .addNextIntent(upIntent)
58 | .startActivities();
59 | finish();
60 | } else {
61 | // This activity is part of the application's task, so simply
62 | // navigate up to the hierarchical parent activity.
63 | NavUtils.navigateUpTo(this, upIntent);
64 | }
65 | return true;
66 | }
67 | return super.onOptionsItemSelected(item);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/thejeshgn/com/bleuartperipheral/MainActivity.java:
--------------------------------------------------------------------------------
1 | package thejeshgn.com.bleuartperipheral;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import android.os.ParcelUuid;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.os.Bundle;
8 |
9 | import java.text.DateFormat;
10 | import java.text.SimpleDateFormat;
11 | import java.util.ArrayList;
12 | import java.util.Date;
13 | import java.util.List;
14 |
15 | import android.bluetooth.BluetoothAdapter;
16 | import android.bluetooth.BluetoothDevice;
17 | import android.bluetooth.BluetoothGatt;
18 | import android.bluetooth.BluetoothGattCharacteristic;
19 | import android.bluetooth.BluetoothGattDescriptor;
20 | import android.bluetooth.BluetoothGattServer;
21 | import android.bluetooth.BluetoothGattServerCallback;
22 | import android.bluetooth.BluetoothGattService;
23 | import android.bluetooth.BluetoothManager;
24 | import android.bluetooth.BluetoothProfile;
25 | import android.bluetooth.le.AdvertiseCallback;
26 | import android.bluetooth.le.AdvertiseData;
27 | import android.bluetooth.le.AdvertiseSettings;
28 | import android.bluetooth.le.BluetoothLeAdvertiser;
29 | import android.content.Context;
30 | import android.content.pm.PackageManager;
31 | import android.os.Handler;
32 | import android.util.Log;
33 | import android.view.Menu;
34 | import android.view.MenuItem;
35 | import android.widget.ArrayAdapter;
36 | import android.widget.ListView;
37 | import android.widget.Toast;
38 |
39 | import no.nordicsemi.android.log.ILogSession;
40 | import no.nordicsemi.android.log.LogContract;
41 | import no.nordicsemi.android.log.Logger;
42 | import thejeshgn.com.bleuartperipheral.data.DataManager;
43 | import thejeshgn.com.bleuartperipheral.data.Util;
44 |
45 | /**
46 | * It has everything that is needed by GattServer to respond
47 | * MIT Licnese
48 | * 2016 - Thejesh GN - https://hejeshgn.com
49 | */
50 |
51 |
52 | public class MainActivity extends AppCompatActivity {
53 | private static final String TAG = "MainActivity";
54 | private ILogSession mLogSession;
55 | private DataManager dataManager = DataManager.getInstance();
56 | private BluetoothManager mBluetoothManager;
57 | private BluetoothAdapter mBluetoothAdapter;
58 | private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
59 | private BluetoothGattServer mGattServer;
60 |
61 | private ArrayList mConnectedDevices;
62 | private ArrayAdapter mConnectedDevicesAdapter;
63 |
64 | @Override
65 | protected void onCreate(Bundle savedInstanceState) {
66 | super.onCreate(savedInstanceState);
67 | mLogSession = Logger.newSession(this, "Hello", "BleUARTPeripheral");
68 |
69 | setContentView(R.layout.activity_main);
70 |
71 | ListView list = new ListView(this);
72 | setContentView(list);
73 |
74 | mConnectedDevices = new ArrayList();
75 | mConnectedDevicesAdapter = new ArrayAdapter(this,
76 | android.R.layout.simple_list_item_1, mConnectedDevices);
77 | list.setAdapter(mConnectedDevicesAdapter);
78 |
79 | mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
80 | mBluetoothAdapter = mBluetoothManager.getAdapter();
81 | Logger.log(mLogSession, LogContract.Log.Level.DEBUG, "In on create");
82 |
83 | }
84 |
85 | @Override
86 | public boolean onCreateOptionsMenu(Menu menu) {
87 | // Inflate the menu; this adds items to the action bar if it is present.
88 | getMenuInflater().inflate(R.menu.main_tool_bar, menu);
89 | return true;
90 | }
91 |
92 |
93 | @Override
94 | public boolean onOptionsItemSelected(MenuItem item) {
95 | Toast.makeText(this, "Inside menu item.", Toast.LENGTH_SHORT).show();
96 | Logger.log(mLogSession, LogContract.Log.Level.INFO, "Inside onOptionsItemSelected");
97 | switch (item.getItemId()) {
98 | case R.id.action_about:
99 | Intent myIntent = new Intent(MainActivity.this, AboutActivity.class);
100 | startActivity(myIntent);
101 | return true;
102 |
103 | case R.id.action_log:
104 | return true;
105 |
106 | case R.id.action_start_stop:
107 | // User chose the "Favorite" action, mark the current item
108 | // as a favorite...
109 | return true;
110 |
111 | default:
112 | // If we got here, the user's action was not recognized.
113 | // Invoke the superclass to handle it.
114 | return super.onOptionsItemSelected(item);
115 |
116 | }
117 | }
118 |
119 | protected void onResume() {
120 | super.onResume();
121 | /*
122 | * Make sure bluettoth is enabled
123 | */
124 | if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
125 | //Bluetooth is disabled
126 | Logger.log(mLogSession, LogContract.Log.Level.DEBUG, "Bluetooth is disabled. Request enable");
127 | Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
128 | startActivity(enableBtIntent);
129 | finish();
130 | return;
131 | }
132 |
133 | /*
134 | * Check for Bluetooth LE Support
135 | */
136 | if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
137 | Toast.makeText(this, "No LE Support.", Toast.LENGTH_SHORT).show();
138 | finish();
139 | return;
140 | }
141 |
142 | /*
143 | * Check for advertising support.
144 | */
145 | if (!mBluetoothAdapter.isMultipleAdvertisementSupported()) {
146 | Toast.makeText(this, "No Advertising Support.", Toast.LENGTH_SHORT).show();
147 | finish();
148 | return;
149 | }
150 | Logger.log(mLogSession, LogContract.Log.Level.DEBUG, "Get Advertiser");
151 | mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
152 | Logger.log(mLogSession, LogContract.Log.Level.DEBUG, "Open GattServer");
153 | mGattServer = mBluetoothManager.openGattServer(this, mGattServerCallback);
154 |
155 | // If everything is okay then start
156 | initServer();
157 | startAdvertising();
158 | }
159 |
160 | /*
161 | * Callback handles events from the framework describing
162 | * if we were successful in starting the advertisement requests.
163 | */
164 | private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
165 | @Override
166 | public void onStartSuccess(AdvertiseSettings settingsInEffect) {
167 | Log.i(TAG, "Peripheral Advertise Started.");
168 | postStatusMessage("GATT Server Ready");
169 | }
170 |
171 | @Override
172 | public void onStartFailure(int errorCode) {
173 | Log.w(TAG, "Peripheral Advertise Failed: " + errorCode);
174 | postStatusMessage("GATT Server Error " + errorCode);
175 | }
176 | };
177 |
178 | private Handler mHandler = new Handler();
179 |
180 | private void postStatusMessage(final String message) {
181 | mHandler.post(new Runnable() {
182 | @Override
183 | public void run() {
184 | setTitle(message);
185 | }
186 | });
187 | }
188 |
189 | /*
190 | * Create the GATT server instance, attaching all services and
191 | * characteristics that should be exposed
192 | */
193 | private void initServer() {
194 | BluetoothGattService UART_SERVICE = new BluetoothGattService(UARTProfile.UART_SERVICE,
195 | BluetoothGattService.SERVICE_TYPE_PRIMARY);
196 |
197 | BluetoothGattCharacteristic TX_READ_CHAR =
198 | new BluetoothGattCharacteristic(UARTProfile.TX_READ_CHAR,
199 | //Read-only characteristic, supports notifications
200 | BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
201 | BluetoothGattCharacteristic.PERMISSION_READ);
202 |
203 | //Descriptor for read notifications
204 | BluetoothGattDescriptor TX_READ_CHAR_DESC = new BluetoothGattDescriptor(UARTProfile.TX_READ_CHAR_DESC, UARTProfile.DESCRIPTOR_PERMISSION);
205 | TX_READ_CHAR.addDescriptor(TX_READ_CHAR_DESC);
206 |
207 |
208 | BluetoothGattCharacteristic RX_WRITE_CHAR =
209 | new BluetoothGattCharacteristic(UARTProfile.RX_WRITE_CHAR,
210 | //write permissions
211 | BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE);
212 |
213 |
214 | UART_SERVICE.addCharacteristic(TX_READ_CHAR);
215 | UART_SERVICE.addCharacteristic(RX_WRITE_CHAR);
216 |
217 | mGattServer.addService(UART_SERVICE);
218 | }
219 |
220 |
221 | /*
222 | * Initialize the advertiser
223 | */
224 | private void startAdvertising() {
225 | if (mBluetoothLeAdvertiser == null) return;
226 |
227 | AdvertiseSettings settings = new AdvertiseSettings.Builder()
228 | .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
229 | .setConnectable(true)
230 | .setTimeout(0)
231 | .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
232 | .build();
233 |
234 | AdvertiseData data = new AdvertiseData.Builder()
235 | .setIncludeDeviceName(true)
236 | .addServiceUuid(new ParcelUuid(UARTProfile.UART_SERVICE))
237 | .build();
238 |
239 | mBluetoothLeAdvertiser.startAdvertising(settings, data, mAdvertiseCallback);
240 | }
241 |
242 |
243 | private void postDeviceChange(final BluetoothDevice device, final boolean toAdd) {
244 | mHandler.post(new Runnable() {
245 | @Override
246 | public void run() {
247 | //This will add the item to our list and update the adapter at the same time.
248 | if (toAdd) {
249 | if (mConnectedDevicesAdapter.getPosition(device) < 0) {
250 | mConnectedDevicesAdapter.add(device);
251 | }
252 |
253 | } else {
254 | mConnectedDevicesAdapter.remove(device);
255 | }
256 |
257 | }
258 | });
259 | }
260 |
261 |
262 | /*
263 | * Terminate the server and any running callbacks
264 | */
265 | private void shutdownServer() {
266 | //mHandler.removeCallbacks(mNotifyRunnable);
267 |
268 | if (mGattServer == null) return;
269 |
270 | mGattServer.close();
271 | }
272 |
273 | // private Runnable mNotifyRunnable = new Runnable() {
274 | // @Override
275 | // public void run() {
276 | // mHandler.postDelayed(this, 2000);
277 | // }
278 | // };
279 |
280 |
281 | /* Callback handles all incoming requests from GATT clients.
282 | * From connections to read/write requests.
283 | */
284 | private BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() {
285 | @Override
286 | public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
287 | super.onConnectionStateChange(device, status, newState);
288 | Log.i(TAG, "onConnectionStateChange "
289 | + UARTProfile.getStatusDescription(status) + " "
290 | + UARTProfile.getStateDescription(newState));
291 |
292 | if (newState == BluetoothProfile.STATE_CONNECTED) {
293 | postDeviceChange(device, true);
294 |
295 | } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
296 | postDeviceChange(device, false);
297 | }
298 | }
299 |
300 | @Override
301 | public void onServiceAdded(int status, BluetoothGattService service) {
302 | Log.d("Start", "Our gatt server service was added.");
303 | super.onServiceAdded(status, service);
304 | }
305 |
306 |
307 | @Override
308 | public void onCharacteristicReadRequest(BluetoothDevice device,
309 | int requestId,
310 | int offset,
311 | BluetoothGattCharacteristic characteristic) {
312 | super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
313 | Log.d(TAG, "READ called onCharacteristicReadRequest " + characteristic.getUuid().toString());
314 |
315 | if (UARTProfile.TX_READ_CHAR.equals(characteristic.getUuid())) {
316 | mGattServer.sendResponse(device,
317 | requestId,
318 | BluetoothGatt.GATT_SUCCESS,
319 | 0,
320 | storage);
321 | }
322 |
323 | }
324 |
325 |
326 | @Override
327 | public void onCharacteristicWriteRequest(BluetoothDevice device,
328 | int requestId,
329 | BluetoothGattCharacteristic characteristic,
330 | boolean preparedWrite,
331 | boolean responseNeeded,
332 | int offset,
333 | byte[] value) {
334 | super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
335 | Log.i(TAG, "onCharacteristicWriteRequest " + characteristic.getUuid().toString());
336 |
337 | if (UARTProfile.RX_WRITE_CHAR.equals(characteristic.getUuid())) {
338 |
339 | //IMP: Copy the received value to storage
340 | if (responseNeeded) {
341 | mGattServer.sendResponse(device,
342 | requestId,
343 | BluetoothGatt.GATT_SUCCESS,
344 | 0,
345 | value);
346 | Log.d(TAG, "Received data on " + characteristic.getUuid().toString());
347 | Log.d(TAG, "Received data" + bytesToHex(value));
348 |
349 | }
350 |
351 | dataManager.addPacket(value);
352 | if (dataManager.isMessageComplete()){
353 | storage = dataManager.getTheCompleteMesssage();
354 | dataManager.clear();
355 | //IMP: Respond
356 | sendOurResponse();
357 |
358 | }
359 |
360 |
361 |
362 | mHandler.post(new Runnable() {
363 | @Override
364 | public void run() {
365 | Toast.makeText(MainActivity.this, "We received data", Toast.LENGTH_SHORT).show();
366 | }
367 | });
368 |
369 |
370 | }
371 | }
372 |
373 |
374 | @Override
375 | public void onNotificationSent(BluetoothDevice device, int status) {
376 | Log.d("GattServer", "onNotificationSent");
377 | super.onNotificationSent(device, status);
378 | }
379 |
380 |
381 | @Override
382 | public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
383 | Log.d("HELLO", "Our gatt server descriptor was read.");
384 | super.onDescriptorReadRequest(device, requestId, offset, descriptor);
385 | Log.d("DONE", "Our gatt server descriptor was read.");
386 | }
387 |
388 | @Override
389 | public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
390 | Log.d("HELLO", "Our gatt server descriptor was written.");
391 | super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
392 | Log.d("DONE", "Our gatt server descriptor was written.");
393 |
394 | //NOTE: Its important to send response. It expects response else it will disconnect
395 | if (responseNeeded) {
396 | mGattServer.sendResponse(device,
397 | requestId,
398 | BluetoothGatt.GATT_SUCCESS,
399 | 0,
400 | value);
401 |
402 | }
403 |
404 | }
405 |
406 | //end of gatt server
407 | };
408 |
409 |
410 | //Send notification to all the devices once you write
411 | private void sendOurResponse() {
412 | for (BluetoothDevice device : mConnectedDevices) {
413 | BluetoothGattCharacteristic readCharacteristic = mGattServer.getService(UARTProfile.UART_SERVICE)
414 | .getCharacteristic(UARTProfile.TX_READ_CHAR);
415 |
416 | byte[] notify_msg = storage;
417 | String hexStorage = bytesToHex(storage);
418 | Log.d(TAG, "received string = " + bytesToHex(storage));
419 |
420 |
421 | if (hexStorage.equals("77686F616D69")) {
422 |
423 | notify_msg = "I am echo an machine".getBytes();
424 |
425 | } else if (bytesToHex(storage).equals("64617465")) {
426 | DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
427 | Date date = new Date();
428 | notify_msg = dateFormat.format(date).getBytes();
429 |
430 | } else {
431 | //TODO: Do nothing send what you received. Basically echo
432 | }
433 |
434 | List messages = Util.createPacketsToSend(notify_msg);
435 | for(int i =0; i < messages.size(); i++){
436 | byte[] message =(byte[]) messages.get(i);
437 | readCharacteristic.setValue(message);
438 | Log.d(TAG, "Sending Notifications" + message);
439 | boolean is_notified = mGattServer.notifyCharacteristicChanged(device, readCharacteristic, false);
440 | Log.d(TAG, "Notifications =" + is_notified);
441 | }
442 | }
443 | }
444 |
445 |
446 | private byte[] storage = hexStringToByteArray("1111");
447 |
448 | final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
449 |
450 | //Helper function converts byte array to hex string
451 | //for priting
452 | public static String bytesToHex(byte[] bytes) {
453 | char[] hexChars = new char[bytes.length * 2];
454 | for (int j = 0; j < bytes.length; j++) {
455 | int v = bytes[j] & 0xFF;
456 | hexChars[j * 2] = hexArray[v >>> 4];
457 | hexChars[j * 2 + 1] = hexArray[v & 0x0F];
458 | }
459 | return new String(hexChars);
460 | }
461 |
462 |
463 | //Helper function converts hex string into
464 | //byte array
465 | public static byte[] hexStringToByteArray(String s) {
466 | int len = s.length();
467 | byte[] data = new byte[len / 2];
468 | for (int i = 0; i < len; i += 2) {
469 | data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
470 | + Character.digit(s.charAt(i + 1), 16));
471 | }
472 | return data;
473 | }
474 |
475 |
476 | }
477 |
--------------------------------------------------------------------------------
/app/src/main/java/thejeshgn/com/bleuartperipheral/UARTProfile.java:
--------------------------------------------------------------------------------
1 | package thejeshgn.com.bleuartperipheral;
2 |
3 |
4 | import android.bluetooth.BluetoothGatt;
5 | import android.bluetooth.BluetoothGattDescriptor;
6 | import android.bluetooth.BluetoothProfile;
7 |
8 | import java.nio.ByteBuffer;
9 | import java.nio.ByteOrder;
10 | import java.util.UUID;
11 |
12 | /**
13 | * UART Profile details
14 | * MIT Licnese
15 | * 2016 - Thejesh GN - https://hejeshgn.com
16 | */
17 |
18 |
19 | public class UARTProfile {
20 | //Service UUID to expose our UART characteristics
21 | public static UUID UART_SERVICE = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
22 |
23 | //RX, Write characteristic
24 | public static UUID RX_WRITE_CHAR = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
25 |
26 | //TX READ Notify
27 | public static UUID TX_READ_CHAR = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");
28 | public static UUID TX_READ_CHAR_DESC = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
29 | public final static int DESCRIPTOR_PERMISSION = BluetoothGattDescriptor.PERMISSION_WRITE;
30 |
31 | public static String getStateDescription(int state) {
32 | switch (state) {
33 | case BluetoothProfile.STATE_CONNECTED:
34 | return "Connected";
35 | case BluetoothProfile.STATE_CONNECTING:
36 | return "Connecting";
37 | case BluetoothProfile.STATE_DISCONNECTED:
38 | return "Disconnected";
39 | case BluetoothProfile.STATE_DISCONNECTING:
40 | return "Disconnecting";
41 | default:
42 | return "Unknown State " + state;
43 | }
44 | }
45 |
46 |
47 | public static String getStatusDescription(int status) {
48 | switch (status) {
49 | case BluetoothGatt.GATT_SUCCESS:
50 | return "SUCCESS";
51 | default:
52 | return "Unknown Status " + status;
53 | }
54 | }
55 |
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/thejeshgn/com/bleuartperipheral/data/DataManager.java:
--------------------------------------------------------------------------------
1 | package thejeshgn.com.bleuartperipheral.data;
2 |
3 |
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | /**
8 | * Created by thej on 15/12/16.
9 | */
10 |
11 |
12 | public class DataManager {
13 | private final static String TAG = DataManager.class.getSimpleName();
14 | private static DataManager instance;
15 | private static List allPackets = new ArrayList();
16 | private static boolean final_packet_received = false;
17 |
18 | private DataManager(){
19 |
20 | }
21 |
22 | public static DataManager getInstance() {
23 | if (null == instance) {
24 | instance = new DataManager();
25 | }
26 | return instance;
27 | }
28 |
29 | public static void addPacket(byte[] packet){
30 | allPackets.add(packet);
31 | //if its last packet by checking if the last byte is \n
32 | if (packet[packet.length-2] == Util.packet_indicator_last[0] && packet[packet.length-1] == Util.packet_indicator_last[1]){
33 | final_packet_received = true;
34 | }
35 | }
36 |
37 | public static boolean isMessageComplete(){
38 | return final_packet_received;
39 | }
40 |
41 |
42 |
43 | public static byte[] getTheCompleteMesssage(){
44 | byte[] final_message={};
45 | for (int time = 0; time < allPackets.size(); time++) {
46 | byte[] packet = (byte[])allPackets.get(time);
47 | final_message = Util.appendData(final_message,packet);
48 | }
49 | return final_message;
50 | }
51 |
52 | public static void clear(){
53 | allPackets = new ArrayList();
54 | final_packet_received = false;
55 | }
56 |
57 |
58 |
59 |
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/thejeshgn/com/bleuartperipheral/data/Util.java:
--------------------------------------------------------------------------------
1 | package thejeshgn.com.bleuartperipheral.data;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.IOException;
5 | import java.util.ArrayList;
6 | import java.util.Arrays;
7 | import java.util.List;
8 |
9 | /**
10 | * Created by thej on 15/12/16.
11 | */
12 |
13 | public class Util {
14 | public static byte[] packet_indicator_last ={0x5c, 0x6e};
15 | public static int packet_size = 20;
16 |
17 | public static byte[] appendData(byte[] firstObject,byte[] secondObject){
18 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
19 | try {
20 | if (firstObject!=null && firstObject.length!=0)
21 | outputStream.write(firstObject);
22 | if (secondObject!=null && secondObject.length!=0)
23 | outputStream.write(secondObject);
24 | } catch (IOException e) {
25 | e.printStackTrace();
26 | }
27 | return outputStream.toByteArray();
28 | }
29 |
30 |
31 | public static List createPacketsToSend(byte[] message){
32 | List allPackets = new ArrayList();
33 | message = appendData(message, packet_indicator_last);
34 |
35 | int times = message.length/packet_size;
36 |
37 |
38 | for (short time = 0; time <= times; time++) {
39 | byte[] packet = Arrays.copyOfRange(message, time*packet_size, (time+1)*packet_size);
40 | allPackets.add(packet);
41 | }
42 | return allPackets;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/thejeshgn/com/bleuartperipheral/log/LogProvider.java:
--------------------------------------------------------------------------------
1 | package thejeshgn.com.bleuartperipheral.log;
2 |
3 | import no.nordicsemi.android.log.localprovider.LocalLogContentProvider;
4 | import android.net.Uri;
5 |
6 | /**
7 | * Created by thej on 11/12/16.
8 | */
9 |
10 | public class LogProvider extends LocalLogContentProvider {
11 | /** The authority for the contacts provider. */
12 | public static final String AUTHORITY = "thejeshgn.com.bleuartperipheral";
13 | /** A content:// style uri to the authority for the log provider. */
14 | public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
15 |
16 | @Override
17 | protected Uri getAuthorityUri() {
18 | return AUTHORITY_URI;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main_tool_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thejeshgn/BleUARTPeripheral/e1f89708368c382207f35b834070b90dcb4db8f0/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thejeshgn/BleUARTPeripheral/e1f89708368c382207f35b834070b90dcb4db8f0/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thejeshgn/BleUARTPeripheral/e1f89708368c382207f35b834070b90dcb4db8f0/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thejeshgn/BleUARTPeripheral/e1f89708368c382207f35b834070b90dcb4db8f0/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thejeshgn/BleUARTPeripheral/e1f89708368c382207f35b834070b90dcb4db8f0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | BleUARTPeripheral
3 | AboutActivity
4 | StartActivity
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.1'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thejeshgn/BleUARTPeripheral/e1f89708368c382207f35b834070b90dcb4db8f0/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------