diff --git a/android/app/src/main/java/com/vernu/sms/AppConstants.java b/android/app/src/main/java/com/vernu/sms/AppConstants.java index f7d0d2e..f3f6cb7 100644 --- a/android/app/src/main/java/com/vernu/sms/AppConstants.java +++ b/android/app/src/main/java/com/vernu/sms/AppConstants.java @@ -18,4 +18,5 @@ public class AppConstants { public static final String SHARED_PREFS_TRACK_SENT_SMS_STATUS_KEY = "TRACK_SENT_SMS_STATUS"; public static final String SHARED_PREFS_LAST_VERSION_CODE_KEY = "LAST_VERSION_CODE"; public static final String SHARED_PREFS_LAST_VERSION_NAME_KEY = "LAST_VERSION_NAME"; + public static final String SHARED_PREFS_STICKY_NOTIFICATION_ENABLED_KEY = "STICKY_NOTIFICATION_ENABLED"; } diff --git a/android/app/src/main/java/com/vernu/sms/TextBeeUtils.java b/android/app/src/main/java/com/vernu/sms/TextBeeUtils.java index db6264b..6e708de 100644 --- a/android/app/src/main/java/com/vernu/sms/TextBeeUtils.java +++ b/android/app/src/main/java/com/vernu/sms/TextBeeUtils.java @@ -14,6 +14,7 @@ import androidx.core.content.ContextCompat; import com.google.firebase.crashlytics.FirebaseCrashlytics; import com.vernu.sms.services.StickyNotificationService; +import com.vernu.sms.helpers.SharedPreferenceHelper; import java.util.ArrayList; import java.util.List; @@ -38,22 +39,34 @@ public class TextBeeUtils { } public static void startStickyNotificationService(Context context) { - if(!isPermissionGranted(context, Manifest.permission.RECEIVE_SMS)){ return; } - - Intent notificationIntent = new Intent(context, StickyNotificationService.class); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(notificationIntent); + + // Only start service if user has enabled sticky notification + boolean stickyNotificationEnabled = SharedPreferenceHelper.getSharedPreferenceBoolean( + context, + AppConstants.SHARED_PREFS_STICKY_NOTIFICATION_ENABLED_KEY, + false + ); + + if (stickyNotificationEnabled) { + Intent notificationIntent = new Intent(context, StickyNotificationService.class); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(notificationIntent); + } else { + context.startService(notificationIntent); + } + Log.i(TAG, "Starting sticky notification service"); } else { - context.startService(notificationIntent); + Log.i(TAG, "Sticky notification disabled by user, not starting service"); } } public static void stopStickyNotificationService(Context context) { Intent notificationIntent = new Intent(context, StickyNotificationService.class); context.stopService(notificationIntent); + Log.i(TAG, "Stopping sticky notification service"); } /** diff --git a/android/app/src/main/java/com/vernu/sms/activities/MainActivity.java b/android/app/src/main/java/com/vernu/sms/activities/MainActivity.java index 6cf93bd..0e43052 100644 --- a/android/app/src/main/java/com/vernu/sms/activities/MainActivity.java +++ b/android/app/src/main/java/com/vernu/sms/activities/MainActivity.java @@ -42,7 +42,7 @@ import retrofit2.Response; public class MainActivity extends AppCompatActivity { private Context mContext; - private Switch gatewaySwitch, receiveSMSSwitch; + private Switch gatewaySwitch, receiveSMSSwitch, stickyNotificationSwitch; private EditText apiKeyEditText, fcmTokenEditText, deviceIdEditText; private Button registerDeviceBtn, grantSMSPermissionBtn, scanQRBtn, checkUpdatesBtn; private ImageButton copyDeviceIdImgBtn; @@ -62,6 +62,7 @@ public class MainActivity extends AppCompatActivity { setContentView(R.layout.activity_main); gatewaySwitch = findViewById(R.id.gatewaySwitch); receiveSMSSwitch = findViewById(R.id.receiveSMSSwitch); + stickyNotificationSwitch = findViewById(R.id.stickyNotificationSwitch); apiKeyEditText = findViewById(R.id.apiKeyEditText); fcmTokenEditText = findViewById(R.id.fcmTokenEditText); deviceIdEditText = findViewById(R.id.deviceIdEditText); @@ -98,6 +99,14 @@ public class MainActivity extends AppCompatActivity { crashlytics.setCustomKey("app_version", versionName); crashlytics.setCustomKey("app_version_code", BuildConfig.VERSION_CODE); + // Start sticky notification service if enabled + boolean gatewayEnabled = SharedPreferenceHelper.getSharedPreferenceBoolean(mContext, AppConstants.SHARED_PREFS_GATEWAY_ENABLED_KEY, false); + boolean stickyNotificationEnabled = SharedPreferenceHelper.getSharedPreferenceBoolean(mContext, AppConstants.SHARED_PREFS_STICKY_NOTIFICATION_ENABLED_KEY, false); + if (gatewayEnabled && stickyNotificationEnabled) { + TextBeeUtils.startStickyNotificationService(mContext); + Log.d(TAG, "Starting sticky notification service on app start"); + } + if (deviceId == null || deviceId.isEmpty()) { registerDeviceBtn.setText("Register"); } else { @@ -150,11 +159,14 @@ public class MainActivity extends AppCompatActivity { SharedPreferenceHelper.setSharedPreferenceBoolean(mContext, AppConstants.SHARED_PREFS_GATEWAY_ENABLED_KEY, isCheked); boolean enabled = Boolean.TRUE.equals(Objects.requireNonNull(response.body()).data.get("enabled")); compoundButton.setChecked(enabled); -// if (enabled) { -// TextBeeUtils.startStickyNotificationService(mContext); -// } else { -// TextBeeUtils.stopStickyNotificationService(mContext); -// } + if (enabled) { + // Check if sticky notification is enabled + if (SharedPreferenceHelper.getSharedPreferenceBoolean(mContext, AppConstants.SHARED_PREFS_STICKY_NOTIFICATION_ENABLED_KEY, false)) { + TextBeeUtils.startStickyNotificationService(mContext); + } + } else { + TextBeeUtils.stopStickyNotificationService(mContext); + } compoundButton.setEnabled(true); } @Override @@ -176,6 +188,21 @@ public class MainActivity extends AppCompatActivity { Snackbar.make(view, "Receive SMS " + (isCheked ? "enabled" : "disabled"), Snackbar.LENGTH_LONG).show(); }); + // Setup sticky notification switch + stickyNotificationSwitch.setChecked(SharedPreferenceHelper.getSharedPreferenceBoolean(mContext, AppConstants.SHARED_PREFS_STICKY_NOTIFICATION_ENABLED_KEY, false)); + stickyNotificationSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> { + View view = compoundButton.getRootView(); + SharedPreferenceHelper.setSharedPreferenceBoolean(mContext, AppConstants.SHARED_PREFS_STICKY_NOTIFICATION_ENABLED_KEY, isChecked); + + if (isChecked) { + TextBeeUtils.startStickyNotificationService(mContext); + Snackbar.make(view, "Background service enabled - app will be more reliable", Snackbar.LENGTH_LONG).show(); + } else { + TextBeeUtils.stopStickyNotificationService(mContext); + Snackbar.make(view, "Background service disabled - app may be killed when in background", Snackbar.LENGTH_LONG).show(); + } + }); + // TODO: check gateway status/api key/device validity and update UI accordingly registerDeviceBtn.setOnClickListener(view -> { String _deviceId = SharedPreferenceHelper.getSharedPreferenceString(mContext, AppConstants.SHARED_PREFS_DEVICE_ID_KEY, ""); diff --git a/android/app/src/main/java/com/vernu/sms/services/StickyNotificationService.java b/android/app/src/main/java/com/vernu/sms/services/StickyNotificationService.java index b320563..6a82579 100644 --- a/android/app/src/main/java/com/vernu/sms/services/StickyNotificationService.java +++ b/android/app/src/main/java/com/vernu/sms/services/StickyNotificationService.java @@ -15,6 +15,8 @@ import androidx.core.app.NotificationCompat; import com.vernu.sms.R; import com.vernu.sms.activities.MainActivity; import com.vernu.sms.receivers.SMSBroadcastReceiver; +import com.vernu.sms.AppConstants; +import com.vernu.sms.helpers.SharedPreferenceHelper; public class StickyNotificationService extends Service { @@ -32,15 +34,25 @@ public class StickyNotificationService extends Service { super.onCreate(); Log.i(TAG, "Service Started"); + // Only register receiver and show notification if enabled in preferences + boolean stickyNotificationEnabled = SharedPreferenceHelper.getSharedPreferenceBoolean( + getApplicationContext(), + AppConstants.SHARED_PREFS_STICKY_NOTIFICATION_ENABLED_KEY, + false + ); -// IntentFilter filter = new IntentFilter(); -// filter.addAction(Telephony.Sms.Intents.SMS_RECEIVED_ACTION); -// filter.addAction(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED); -// registerReceiver(receiver, filter); -// -// Notification notification = createNotification(); -// startForeground(1, notification); + if (stickyNotificationEnabled) { + IntentFilter filter = new IntentFilter(); + filter.addAction(Telephony.Sms.Intents.SMS_RECEIVED_ACTION); + filter.addAction(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED); + registerReceiver(receiver, filter); + Notification notification = createNotification(); + startForeground(1, notification); + Log.i(TAG, "Started foreground service with sticky notification"); + } else { + Log.i(TAG, "Sticky notification disabled by user preference"); + } } @Override @@ -52,9 +64,19 @@ public class StickyNotificationService extends Service { @Override public void onDestroy() { super.onDestroy(); -// unregisterReceiver(receiver); + + // Only unregister if we had registered in the first place + boolean stickyNotificationEnabled = SharedPreferenceHelper.getSharedPreferenceBoolean( + getApplicationContext(), + AppConstants.SHARED_PREFS_STICKY_NOTIFICATION_ENABLED_KEY, + false + ); + + if (stickyNotificationEnabled) { + unregisterReceiver(receiver); + } + Log.i(TAG, "StickyNotificationService destroyed"); -// Toast.makeText(this, "Service destroyed", Toast.LENGTH_SHORT).show(); } private Notification createNotification() { @@ -72,10 +94,19 @@ public class StickyNotificationService extends Service { PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); Notification.Builder builder = new Notification.Builder(this, notificationChannelId); - return builder.setContentTitle("TextBee is running").setContentText("TextBee is running in the background.").setContentIntent(pendingIntent).setOngoing(true).setSmallIcon(R.drawable.ic_launcher_foreground).build(); + return builder.setContentTitle("TextBee Active") + .setContentText("SMS gateway service is active") + .setContentIntent(pendingIntent) + .setOngoing(true) + .setSmallIcon(R.mipmap.ic_launcher) + .build(); } else { NotificationCompat.Builder builder = new NotificationCompat.Builder(this, notificationChannelId); - return builder.setContentTitle("TextBee is running").setContentText("TextBee is running in the background.").setOngoing(true).setSmallIcon(R.drawable.ic_launcher_foreground).build(); + return builder.setContentTitle("TextBee Active") + .setContentText("SMS gateway service is active") + .setOngoing(true) + .setSmallIcon(R.mipmap.ic_launcher) + .build(); } } diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml index 55d25ae..7cd04fb 100644 --- a/android/app/src/main/res/layout/activity_main.xml +++ b/android/app/src/main/res/layout/activity_main.xml @@ -371,6 +371,57 @@ android:minHeight="32dp" /> + + + + + + + + + + + + + + + + + +