diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a664cc1..1df4bcb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -10,6 +10,7 @@
+
= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
ProgramakerBridgeService.BridgeUserNotificationChannel,
ProgramakerBridgeService.BridgeUserNotificationChannelName,
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
+
+ NotificationChannel vibrationChannel = new NotificationChannel(
+ ProgramakerBridgeService.BridgeUserVibrationNotificationChannel,
+ ProgramakerBridgeService.BridgeUserVibrationNotificationChannelName,
+ NotificationManager.IMPORTANCE_DEFAULT);
+
+ // Vibration is manually handled for Android O (or superior) devices
+ vibrationChannel.setVibrationPattern(null);
+ notificationManager.createNotificationChannel(vibrationChannel);
}
@@ -70,6 +89,61 @@ public class DefaultAndroidBlocks {
(List> params) -> {
notificationManager.cancelAll();
}
- );
+ )
+ .addOperation(
+ "vibration_start",
+ "Vibrate %1 times",
+ new LinkedList() {{
+ add(new BlockArgumentDefinition(BlockArgumentDefinition.Type.INT, "3"));
+ }},
+ (List> params) -> {
+ if (params.size() != 1) {
+ throw new Exception("Expected one (1) argument1, found " + params.size());
+ }
+
+ int userTimes = Integer.parseInt(params.get(0).toString());
+ final int times = Math.max(1, Math.min(MAX_VIBRATION_CYCLES, userTimes));
+
+ long[] pattern = new long[times * 2];
+ for (int i = 0; i < times; i++) {
+ pattern[i * 2] = VIBRATION_ACTIVE_TIME;
+ pattern[i * 2 + 1] = VIBRATION_REST_TIME;
+ }
+ // pattern[0] = 0; // Start immediately
+
+ Notification notif = new NotificationCompat
+ .Builder(ctx, ProgramakerBridgeService.BridgeUserVibrationNotificationChannel)
+ .setContentTitle(ctx.getString(R.string.vibration_activated))
+ .setSmallIcon(R.drawable.ic_center_focus_weak_black) // TODO: Change icon
+ .setPriority(NotificationCompat.PRIORITY_DEFAULT)
+ .setAutoCancel(true)
+ .setVibrate(pattern)
+ .build();
+
+ int notificationId = notificationRandom.nextInt();
+ notificationManager.notify(notificationId, notif);
+
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ // Manually handle vibration if notification channels are in use
+ vibrator.vibrate(VibrationEffect.createWaveform(pattern, -1));
+ }
+
+ new Thread( () -> {
+ // Wait the activation time
+ for (int i = 0; i < times; i++) {
+ try {
+ Thread.sleep(pattern[i * 2]);
+ Thread.sleep(pattern[i * 2 + 1]);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // Remove notification
+ notificationManager.cancel(notificationId);
+ }).start();
+ }
+ )
+ ;
}
}
diff --git a/app/src/main/java/com/programaker/bridge/ProgramakerBridge.kt b/app/src/main/java/com/programaker/bridge/ProgramakerBridge.kt
index 9e094f9..fa05cf7 100644
--- a/app/src/main/java/com/programaker/bridge/ProgramakerBridge.kt
+++ b/app/src/main/java/com/programaker/bridge/ProgramakerBridge.kt
@@ -80,7 +80,7 @@ class ProgramakerBridge(
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
Log.e(LogTag, "Error: $t", t)
- webSocket.close(1000, null)
+ onComplete.run()
}
// Protocol handling
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 63f8b22..29aa7be 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -25,4 +25,5 @@
Programaker bridge stopped
Stop bridge
Start bridge
+ Vibration activated