Make AlarmModule work
This commit is contained in:
parent
c6a43b7c83
commit
00a801b44a
|
@ -4,26 +4,30 @@
|
|||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:allowBackup="false"
|
||||
android:theme="@style/AppTheme">
|
||||
<meta-data android:name="com.dieam.reactnativepushnotification.notification_foreground" android:value="false"/>
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/AppTheme"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules">
|
||||
<meta-data
|
||||
android:name="com.dieam.reactnativepushnotification.notification_foreground"
|
||||
android:value="false" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<receiver android:exported="true" android:process=":remote" android:name=".MyBroadcastReceiver" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
package com.massive; // replace com.your-app-name with your app’s name
|
||||
|
||||
import static android.content.Context.ALARM_SERVICE;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
@ -24,6 +31,8 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|||
import com.facebook.react.bridge.ReactMethod;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -42,12 +51,15 @@ public class AlarmModule extends ReactContextBaseJavaModule {
|
|||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public void timer(int milliseconds) {
|
||||
WorkRequest request = new PeriodicWorkRequest.Builder(
|
||||
AlarmWorker.class, milliseconds, TimeUnit.MILLISECONDS
|
||||
)
|
||||
.build();
|
||||
Log.d("AlarmModule", "Queue alarm for " + milliseconds + " delay");
|
||||
WorkManager.getInstance(getReactApplicationContext())
|
||||
.enqueue(request);
|
||||
Intent intent = new Intent(getReactApplicationContext(), MyBroadcastReceiver.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(
|
||||
getReactApplicationContext(), 69, intent, PendingIntent.FLAG_IMMUTABLE);
|
||||
AlarmManager alarmManager = (AlarmManager) getReactApplicationContext().getSystemService(ALARM_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
Log.d("AlarmModule", "Can schedule: " + alarmManager.canScheduleExactAlarms());
|
||||
}
|
||||
AlarmManager.AlarmClockInfo info = new AlarmManager.AlarmClockInfo(System.currentTimeMillis() + milliseconds, pendingIntent);
|
||||
alarmManager.setAlarmClock(info, pendingIntent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
package com.massive;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Build;
|
||||
import android.os.Vibrator;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
public class AlarmWorker extends Worker {
|
||||
private static final String CHANNEL_ID = "MassiveAlarms";
|
||||
|
||||
public AlarmWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
||||
super(context, workerParams);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
Log.d("AlarmWorker", "Doing work...");
|
||||
createNotificationChannel();
|
||||
Intent intent = new Intent(getApplicationContext(), AlarmModule.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE);
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.autofill_inline_suggestion_chip_background)
|
||||
.setContentTitle("Rest complete.")
|
||||
.setContentText("Break time is over!")
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
|
||||
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext());
|
||||
notificationManager.notify(1, builder.build());
|
||||
MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.argon);
|
||||
mediaPlayer.start(); // no need to call prepare(); create() does that for you
|
||||
Vibrator vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vibrator.vibrate(400);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private void createNotificationChannel() {
|
||||
Log.d("AlarmWorker", "Creating notification channel...");
|
||||
// Create the NotificationChannel, but only on API 26+ because
|
||||
// the NotificationChannel class is new and not in the support library
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
int importance = NotificationManager.IMPORTANCE_DEFAULT;
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "MassiveAlarms", importance);
|
||||
channel.setDescription("Alarms for the Massive application");
|
||||
// Register the channel with the system; you can't change the importance
|
||||
// or other notification behaviors after this
|
||||
NotificationManager notificationManager = getApplicationContext().getSystemService(NotificationManager.class);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.massive;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Build;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
public class MyBroadcastReceiver extends BroadcastReceiver {
|
||||
private static final String CHANNEL_ID = "MassiveAlarm";
|
||||
private static final int ALARM_ID = 59;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d("MyBroadcastReceiver", "Received intent for BroadcastReceiver.");
|
||||
long[] pattern = {0, 300, 200, 300, 200};
|
||||
int[] amplitudes = {VibrationEffect.DEFAULT_AMPLITUDE, VibrationEffect.DEFAULT_AMPLITUDE, VibrationEffect.DEFAULT_AMPLITUDE, VibrationEffect.DEFAULT_AMPLITUDE, VibrationEffect.DEFAULT_AMPLITUDE};
|
||||
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
vibrator.vibrate(VibrationEffect.createWaveform(pattern, amplitudes, 0));
|
||||
} else {
|
||||
//deprecated in API 26
|
||||
vibrator.vibrate(500);
|
||||
}
|
||||
createNotificationChannel(context);
|
||||
|
||||
Intent contentIntent = new Intent(context.getApplicationContext(), MainActivity.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, contentIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.rn_edit_text_material)
|
||||
.setContentTitle("Rest")
|
||||
.setContentText("Break times over!")
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true)
|
||||
.setCategory(NotificationCompat.CATEGORY_ALARM)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||
notificationManager.notify(ALARM_ID, builder.build());
|
||||
MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.argon);
|
||||
mediaPlayer.start();
|
||||
}
|
||||
|
||||
private void createNotificationChannel(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
int importance = NotificationManager.IMPORTANCE_HIGH;
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID, importance);
|
||||
channel.setDescription("Alarms for rest timings.");
|
||||
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
36
android/app/src/main/res/xml/data_extraction_rules.xml
Normal file
36
android/app/src/main/res/xml/data_extraction_rules.xml
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Sample data extraction rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||
for details.
|
||||
-->
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<!--
|
||||
TODO: Use <include> and <exclude> to control what is backed up.
|
||||
The domain can be file, database, sharedpref, external or root.
|
||||
Examples:
|
||||
|
||||
<include domain="file" path="file_to_include"/>
|
||||
<exclude domain="file" path="file_to_exclude"/>
|
||||
<include domain="file" path="include_folder"/>
|
||||
<exclude domain="file" path="include_folder/file_to_exclude"/>
|
||||
<exclude domain="file" path="exclude_folder"/>
|
||||
<include domain="file" path="exclude_folder/file_to_include"/>
|
||||
|
||||
<include domain="sharedpref" path="include_shared_pref1.xml"/>
|
||||
<include domain="database" path="db_name/file_to_include"/>
|
||||
<exclude domain="database" path="db_name/include_folder/file_to_exclude"/>
|
||||
<include domain="external" path="file_to_include"/>
|
||||
<exclude domain="external" path="file_to_exclude"/>
|
||||
<include domain="root" path="file_to_include"/>
|
||||
<exclude domain="root" path="file_to_exclude"/>
|
||||
-->
|
||||
</cloud-backup>
|
||||
<!--
|
||||
<device-transfer>
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
</device-transfer>
|
||||
-->
|
||||
</data-extraction-rules>
|
|
@ -14,6 +14,7 @@
|
|||
"@react-native-async-storage/async-storage": "^1.17.7",
|
||||
"@react-native-community/push-notification-ios": "^1.10.1",
|
||||
"@react-navigation/bottom-tabs": "^6.3.1",
|
||||
"@react-navigation/material-top-tabs": "^6.2.1",
|
||||
"@react-navigation/native": "^6.0.10",
|
||||
"@react-navigation/native-stack": "^6.6.2",
|
||||
"@types/react-native-background-timer": "^2.0.0",
|
||||
|
@ -25,6 +26,7 @@
|
|||
"react-native": "0.69.1",
|
||||
"react-native-background-timer": "^2.4.1",
|
||||
"react-native-gesture-handler": "^2.5.0",
|
||||
"react-native-pager-view": "^5.4.24",
|
||||
"react-native-paper": "^4.12.2",
|
||||
"react-native-push-notification": "^8.1.1",
|
||||
"react-native-reanimated": "^2.9.0",
|
||||
|
@ -32,6 +34,7 @@
|
|||
"react-native-screens": "^3.14.0",
|
||||
"react-native-sound": "^0.11.2",
|
||||
"react-native-sqlite-storage": "^6.0.1",
|
||||
"react-native-tab-view": "^3.1.1",
|
||||
"react-native-vector-icons": "^9.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
18
yarn.lock
18
yarn.lock
|
@ -1650,6 +1650,14 @@
|
|||
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.3.tgz#9f56b650a9a1a8263a271628be7342c8121d1788"
|
||||
integrity sha512-Lv2lR7si5gNME8dRsqz57d54m4FJtrwHRjNQLOyQO546ZxO+g864cSvoLC6hQedQU0+IJnPTsZiEI2hHqfpEpw==
|
||||
|
||||
"@react-navigation/material-top-tabs@^6.2.1":
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/material-top-tabs/-/material-top-tabs-6.2.1.tgz#747d17bd0138a7d50c791e9cce1adc350904f67d"
|
||||
integrity sha512-fGy2+/7cUAyrZUPUhzKUttA4avK5Z2FrNk0LRI04hRlAVqs5DYpnaQGkegGeOGwKmnxaVCjCVPr+KoEroyqduw==
|
||||
dependencies:
|
||||
color "^3.1.3"
|
||||
warn-once "^0.1.0"
|
||||
|
||||
"@react-navigation/native-stack@^6.6.2":
|
||||
version "6.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.6.2.tgz#09e696ad72299872f4c5c1e5b1ad309869853628"
|
||||
|
@ -6676,6 +6684,11 @@ react-native-iphone-x-helper@^1.3.1:
|
|||
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010"
|
||||
integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==
|
||||
|
||||
react-native-pager-view@^5.4.24:
|
||||
version "5.4.24"
|
||||
resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-5.4.24.tgz#8626e757ddc55e41eca66d2f8a8a75aec54591ee"
|
||||
integrity sha512-dRMB7i3B+mu4NCeIN6gqbR/kC/rr2wzqO0gisXDdJwJr78G24sWoTNpLEDFo3G8TFHY9nTMutVl5CUvkN2dp6g==
|
||||
|
||||
react-native-paper@^4.12.2:
|
||||
version "4.12.2"
|
||||
resolved "https://registry.yarnpkg.com/react-native-paper/-/react-native-paper-4.12.2.tgz#31ed8011afd994d54dd403ed0099295fc1616d26"
|
||||
|
@ -6727,6 +6740,11 @@ react-native-sqlite-storage@^6.0.1:
|
|||
resolved "https://registry.yarnpkg.com/react-native-sqlite-storage/-/react-native-sqlite-storage-6.0.1.tgz#ce6a6b852f07abbea68658d5363818c8bef45dfb"
|
||||
integrity sha512-1tDFjrint6X6qSYKf3gDyz+XB+X79jfiL6xTugKHPRtF0WvqMtVgdLuNqZunIXjNEvNtNVEbXaeZ6MsguFu00A==
|
||||
|
||||
react-native-tab-view@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-3.1.1.tgz#1f8d7a835ab4f5b1b1407ec8dddc1053b53fa3c6"
|
||||
integrity sha512-M5pRN6utQfytKWoKlKVzg5NbkYu308qNoW1khGTtEOTs1k14p2dHJ/BWOJoJYHKbPVUyZldbG9MFT7gUl4YHnw==
|
||||
|
||||
react-native-vector-icons@^9.2.0:
|
||||
version "9.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz#3c0c82e95defd274d56363cbe8fead8d53167ebd"
|
||||
|
|
Loading…
Reference in New Issue
Block a user