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