Add block to vibrate phone.

This commit is contained in:
Sergio Martínez Portela 2020-05-27 20:32:42 +02:00
parent c60ec32e05
commit d0f4a82043
5 changed files with 83 additions and 5 deletions

View File

@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- For Programaker bridge -->
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:allowBackup="true"

View File

@ -24,6 +24,8 @@ import com.programaker.api.ProgramakerApi;
public class ProgramakerBridgeService extends Service {
public static final String BridgeUserNotificationChannel = "PROGRAMAKER_BRIDGE_USER_NOTIFICATION";
public static final CharSequence BridgeUserNotificationChannelName = "User notifications";
public static String BridgeUserVibrationNotificationChannel = "PROGRAMAKER_BRIDGE_USER_VIBRATION_NOTIFICATIONS";
public static CharSequence BridgeUserVibrationNotificationChannelName = "User-triggered vibration";
private static String BridgeStatusNotificationChannel = "PROGRAMAKER_BRIDGE_STATUS_NOTIFICATION";
private static CharSequence BridgeStatusNotificationChannelName = "Programaker bridge status";

View File

@ -4,6 +4,9 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
import androidx.core.app.NotificationCompat;
@ -17,21 +20,37 @@ import java.util.Random;
public class DefaultAndroidBlocks {
private static long VIBRATION_REST_TIME = 1000; // Ms
private static long VIBRATION_ACTIVE_TIME = 500; // Ms
// This means that will take at most ~15 seconds
private static int MAX_VIBRATION_CYCLES = 10;
public static BridgeBlockListBuilder GetBuilder(Context ctx) {
// System services
String notifServiceId = Context.NOTIFICATION_SERVICE;
NotificationManager notificationManager = (NotificationManager) ctx.getSystemService(notifServiceId);
NotificationManager notificationManager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
Vibrator vibrator = (Vibrator) ctx.getSystemService(Context.VIBRATOR_SERVICE);
assert notificationManager != null;
assert vibrator != null;
Random notificationRandom = new Random();
String notificationChannelId = ProgramakerBridgeService.BridgeUserNotificationChannel;
if (android.os.Build.VERSION.SDK_INT >= 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<BlockArgumentDefinition>() {{
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();
}
)
;
}
}

View File

@ -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

View File

@ -25,4 +25,5 @@
<string name="bridge_service_failed_stopping">Programaker bridge stopped</string>
<string name="stop_bridge">Stop bridge</string>
<string name="start_bridge">Start bridge</string>
<string name="vibration_activated">Vibration activated</string>
</resources>