From 2b2d480069c574ae375f906813fd1109248332d0 Mon Sep 17 00:00:00 2001 From: Sneh Date: Tue, 24 Dec 2024 14:28:07 +0530 Subject: [PATCH 1/5] Phase-I Make app work-full for Power Saving Mode. --- app/src/main/AndroidManifest.xml | 10 +++ .../canopas/yourspace/YourSpaceApplication.kt | 8 +- .../receiver/PowerSavingModeObserver.kt | 57 +++++++++++++ .../domain/utils/PowerSavingObserver.kt | 56 +++++++++++++ .../com/canopas/yourspace/ui/MainActivity.kt | 44 +++++++++++ .../com/canopas/yourspace/ui/MainViewModel.kt | 11 ++- .../home/activity/NavigateToDeviceSetting.kt | 79 +++++++++++++++++++ .../ui/flow/home/map/MapViewModel.kt | 4 +- .../home/map/component/SelectedUserDetail.kt | 30 ++++--- .../permission/EnablePermissionsScreen.kt | 32 ++++++++ app/src/main/res/values/strings.xml | 13 +++ .../yourspace/data/models/user/ApiUser.kt | 1 + .../data/service/auth/AuthService.kt | 5 ++ .../data/service/user/ApiUserService.kt | 12 +++ 14 files changed, 349 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/com/canopas/yourspace/domain/receiver/PowerSavingModeObserver.kt create mode 100644 app/src/main/java/com/canopas/yourspace/domain/utils/PowerSavingObserver.kt create mode 100644 app/src/main/java/com/canopas/yourspace/ui/flow/home/activity/NavigateToDeviceSetting.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 932f54bd..c23f6f35 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,6 +9,7 @@ + + + + + + + diff --git a/app/src/main/java/com/canopas/yourspace/YourSpaceApplication.kt b/app/src/main/java/com/canopas/yourspace/YourSpaceApplication.kt index 280911f1..a1c54d5b 100644 --- a/app/src/main/java/com/canopas/yourspace/YourSpaceApplication.kt +++ b/app/src/main/java/com/canopas/yourspace/YourSpaceApplication.kt @@ -20,6 +20,7 @@ import com.canopas.yourspace.domain.fcm.YOURSPACE_CHANNEL_GEOFENCE import com.canopas.yourspace.domain.fcm.YOURSPACE_CHANNEL_MESSAGES import com.canopas.yourspace.domain.fcm.YOURSPACE_CHANNEL_PLACES import com.canopas.yourspace.domain.receiver.BatteryBroadcastReceiver +import com.canopas.yourspace.domain.receiver.PowerSavingModeObserver import com.google.android.libraries.places.api.Places import com.google.firebase.crashlytics.FirebaseCrashlytics import dagger.hilt.android.HiltAndroidApp @@ -48,14 +49,18 @@ class YourSpaceApplication : @Inject lateinit var notificationManager: NotificationManager + @Inject + lateinit var powerSavingModeObserver: PowerSavingModeObserver + override fun onCreate() { Places.initializeWithNewPlacesApiEnabled(this, BuildConfig.PLACE_API_KEY) super.onCreate() Timber.plant(Timber.DebugTree()) - FirebaseCrashlytics.getInstance().isCrashlyticsCollectionEnabled = !BuildConfig.DEBUG + FirebaseCrashlytics.getInstance().isCrashlyticsCollectionEnabled = false ProcessLifecycleOwner.get().lifecycle.addObserver(this) authService.addListener(this) + powerSavingModeObserver.initReceiver(this) setNotificationChannel() registerBatteryBroadcastReceiver() @@ -68,6 +73,7 @@ class YourSpaceApplication : override fun onDestroy(owner: LifecycleOwner) { super.onDestroy(owner) unregisterReceiver(BatteryBroadcastReceiver(authService)) + powerSavingModeObserver.unregisterReceiver() } private fun registerBatteryBroadcastReceiver() { diff --git a/app/src/main/java/com/canopas/yourspace/domain/receiver/PowerSavingModeObserver.kt b/app/src/main/java/com/canopas/yourspace/domain/receiver/PowerSavingModeObserver.kt new file mode 100644 index 00000000..6b3a955d --- /dev/null +++ b/app/src/main/java/com/canopas/yourspace/domain/receiver/PowerSavingModeObserver.kt @@ -0,0 +1,57 @@ +package com.canopas.yourspace.domain.receiver + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.PowerManager +import com.canopas.yourspace.data.service.auth.AuthService +import com.canopas.yourspace.domain.utils.cancelPowerSavingNotification +import com.canopas.yourspace.domain.utils.sendPowerSavingNotification +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import timber.log.Timber +import javax.inject.Inject + +@AndroidEntryPoint +class PowerSavingModeObserver @Inject constructor( + private val authService: AuthService +) : BroadcastReceiver() { + + private var context: Context? = null + + fun initReceiver(context: Context) { + this.context = context + val filter = IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED) + context.registerReceiver(this, filter) + } + + override fun onReceive(context: Context?, intent: Intent?) { + Timber.e("Received Power Saving Mode change") + val powerManager = context?.getSystemService(Context.POWER_SERVICE) as PowerManager + val isPowerSaving = powerManager.isPowerSaveMode + Timber.e("Power Saving Mode is $isPowerSaving") + + if (isPowerSaving) { + sendPowerSavingNotification(context) + } else { + cancelPowerSavingNotification(context) + } + + if (intent?.action == PowerManager.ACTION_POWER_SAVE_MODE_CHANGED) { + CoroutineScope(Dispatchers.IO).launch { + try { + authService.updatePowerSaveModeStatus(isPowerSaving) + } catch (e: Exception) { + Timber.e(e, "Failed to update battery status") + } + } + } + } + + fun unregisterReceiver() { + context?.unregisterReceiver(this) + } +} diff --git a/app/src/main/java/com/canopas/yourspace/domain/utils/PowerSavingObserver.kt b/app/src/main/java/com/canopas/yourspace/domain/utils/PowerSavingObserver.kt new file mode 100644 index 00000000..af2b4ed6 --- /dev/null +++ b/app/src/main/java/com/canopas/yourspace/domain/utils/PowerSavingObserver.kt @@ -0,0 +1,56 @@ +package com.canopas.yourspace.domain.utils + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.os.Build +import androidx.core.app.NotificationCompat +import com.canopas.yourspace.R +import com.canopas.yourspace.ui.MainActivity +import timber.log.Timber + +const val YOURSPACE_CHANNEL_POWER_SAVING = "your_space_notification_channel_power_saving" +const val NOTIFICATION_ID_POWER_SAVING = 102 + +fun sendPowerSavingNotification(context: Context) { + val notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + val intent = Intent(context, MainActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + } + val pendingIntent = PendingIntent.getActivity( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + + val notificationBuilder = NotificationCompat.Builder(context, YOURSPACE_CHANNEL_POWER_SAVING) + .setSmallIcon(R.drawable.app_logo) + .setContentTitle("Battery Save is on, disabling GroupTrack") + .setContentText("Your phone is in power saving mode, and some features might be limited. Turn off Battery Saver in Settings to reconnect GroupTrack.") + .setAutoCancel(true) + .setContentIntent(pendingIntent) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + YOURSPACE_CHANNEL_POWER_SAVING, + context.getString(R.string.notification_channel_power_saving), + NotificationManager.IMPORTANCE_HIGH + ) + notificationManager.createNotificationChannel(channel) + } + + Timber.e("Power saving notification sent") + notificationManager.notify(NOTIFICATION_ID_POWER_SAVING, notificationBuilder.build()) +} + +fun cancelPowerSavingNotification(context: Context) { + val notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.cancel(NOTIFICATION_ID_POWER_SAVING) + Timber.e("Power saving notification canceled") +} diff --git a/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt b/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt index fb6a1c13..a954632c 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt @@ -1,9 +1,13 @@ package com.canopas.yourspace.ui +import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle +import android.os.PowerManager +import android.provider.Settings import android.view.Window +import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.viewModels @@ -16,6 +20,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.window.DialogProperties import androidx.hilt.navigation.compose.hiltViewModel @@ -72,6 +77,11 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) + val isPowerSavingEnabled = isPowerSavingModeEnabled() + if (isPowerSavingEnabled) { + viewModel.showPowerSavingDialog() + } + setContent { CatchMeTheme { // A surface container using the 'background' color from the theme @@ -95,6 +105,11 @@ class MainActivity : ComponentActivity() { viewModel.handleIntentData(intent) intent.extras?.clear() } + + private fun isPowerSavingModeEnabled(): Boolean { + val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager + return powerManager.isPowerSaveMode + } } @OptIn(ExperimentalAnimationApi::class) @@ -103,6 +118,10 @@ fun MainApp(viewModel: MainViewModel) { val navController = rememberNavController() val state by viewModel.state.collectAsState() + if (state.isPowerSavingEnabled) { + PowerSavingAlertPopup() + } + if (state.isSessionExpired) { SessionExpiredAlertPopup() } @@ -287,3 +306,28 @@ fun SpaceNotFoundPopup() { properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) ) } + +@Composable +fun PowerSavingAlertPopup() { + val viewModel = hiltViewModel() + val context = LocalContext.current + + AppAlertDialog( + title = "Turn off Battery Saver Mode", + subTitle = "When Battery Saver is on, GroupTrack cannot access location data, preventing the app from working correctly. Please turn off the power saving mode.", + confirmBtnText = "Turn Off", + dismissBtnText = stringResource(R.string.common_btn_cancel), + onConfirmClick = { + try { + val intent = Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS) + context.startActivity(intent) + } catch (e: Exception) { + Toast.makeText(context, "Unable to navigate to settings", Toast.LENGTH_SHORT).show() + } + }, + onDismissClick = { + viewModel.dismissPowerSavingDialog() + }, + properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) + ) +} diff --git a/app/src/main/java/com/canopas/yourspace/ui/MainViewModel.kt b/app/src/main/java/com/canopas/yourspace/ui/MainViewModel.kt index 022d55e3..12c584c3 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/MainViewModel.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/MainViewModel.kt @@ -143,6 +143,14 @@ class MainViewModel @Inject constructor( fun dismissSpaceNotFoundPopup() { _state.value = state.value.copy(showSpaceNotFoundPopup = false) } + + fun showPowerSavingDialog() { + _state.value = state.value.copy(isPowerSavingEnabled = true) + } + + fun dismissPowerSavingDialog() { + _state.value = state.value.copy(isPowerSavingEnabled = false) + } } data class MainScreenState( @@ -150,5 +158,6 @@ data class MainScreenState( val initialRoute: String? = null, val verifyingSpace: Boolean = false, val showSpaceNotFoundPopup: Boolean = false, - val isInitialRouteSet: Boolean = false + val isInitialRouteSet: Boolean = false, + val isPowerSavingEnabled: Boolean = false ) diff --git a/app/src/main/java/com/canopas/yourspace/ui/flow/home/activity/NavigateToDeviceSetting.kt b/app/src/main/java/com/canopas/yourspace/ui/flow/home/activity/NavigateToDeviceSetting.kt new file mode 100644 index 00000000..dece2298 --- /dev/null +++ b/app/src/main/java/com/canopas/yourspace/ui/flow/home/activity/NavigateToDeviceSetting.kt @@ -0,0 +1,79 @@ +package com.canopas.yourspace.ui.flow.home.activity + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.provider.Settings +import timber.log.Timber + +fun navigateToSettings(context: Context) { + val packageManager = context.packageManager + val intent = Intent() + + when (Build.MANUFACTURER.lowercase()) { + "xiaomi" -> { + intent.component = ComponentName( + "com.miui.powerkeeper", + "com.miui.powerkeeper.ui.HiddenAppsConfigActivity" + ) + } + + "huawei" -> { + intent.component = ComponentName( + "com.huawei.systemmanager", + "com.huawei.systemmanager.optimize.process.ProtectActivity" + ) + } + + "oppo" -> { + intent.component = ComponentName( + "com.coloros.oppoguardelf", + "com.coloros.powermanager.fuelgaue.PowerUsageModelActivity" + ) + } + + "vivo" -> { + intent.component = ComponentName( + "com.vivo.abe", + "com.vivo.applicationbehaviorengine.ui.ExcessivePowerManagerActivity" + ) + } + + "realme" -> { + intent.component = ComponentName( + "com.coloros.oppoguardelf", + "com.coloros.powermanager.fuelgaue.PowerUsageModelActivity" + ) + } + + "oneplus" -> { + intent.component = ComponentName( + "com.oneplus.security", + "com.oneplus.security.chainlaunch.view.ChainLaunchAppListActivity" + ) + } + + else -> { + val packageName = context.packageName + intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS + intent.data = Uri.parse("package:$packageName") + } + } + + Timber.e("Navigating to settings: ${intent.component}") + + try { + val activities = packageManager.queryIntentActivities(intent, 0) + if (activities.isNotEmpty()) { + context.startActivity(intent) + } else { + Timber.e("Activity not found. Falling back to general settings.") + context.startActivity(Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS)) + } + } catch (e: Exception) { + Timber.e("Error launching settings: ${e.localizedMessage}") + context.startActivity(Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)) + } +} diff --git a/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/MapViewModel.kt b/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/MapViewModel.kt index 31e766ea..137b0138 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/MapViewModel.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/MapViewModel.kt @@ -119,7 +119,8 @@ class MapViewModel @Inject constructor( _state.value.copy( selectedUser = userInfo, defaultCameraPosition = selectedLocation, - showUserDetails = true + showUserDetails = true, + batterySaveModeValue = userInfo.session?.power_save_mode_enabled ?: false ) ) @@ -229,5 +230,6 @@ data class MapScreenState( var isStyleSheetVisible: Boolean = false, var selectedMapStyle: String = "", val error: Exception? = null, + val batterySaveModeValue: Boolean = false, var errorMessage: String? = null ) diff --git a/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/component/SelectedUserDetail.kt b/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/component/SelectedUserDetail.kt index 2ce30946..9d337438 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/component/SelectedUserDetail.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/component/SelectedUserDetail.kt @@ -55,6 +55,7 @@ import com.google.android.gms.maps.model.LatLng import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext +import timber.log.Timber @Composable fun SelectedUserDetail( @@ -160,19 +161,28 @@ private fun MemberInfoView( var address by remember { mutableStateOf("") } val time = timeAgo(location?.created_at ?: 0) - val userStateText = if (user.noNetwork) { - stringResource(R.string.map_selected_user_item_no_network_state) - } else if (user.locationPermissionDenied) { - stringResource(R.string.map_selected_user_item_location_off_state) + Timber.e("XXX Value of battery save mode is ${state.batterySaveModeValue}") + val userStateText = if (!state.batterySaveModeValue) { + if (user.noNetwork) { + stringResource(R.string.map_selected_user_item_no_network_state) + } else if (user.locationPermissionDenied) { + stringResource(R.string.map_selected_user_item_location_off_state) + } else { + stringResource(R.string.map_selected_user_item_online_state) + } } else { - stringResource(R.string.map_selected_user_item_online_state) + "Battery saver mode is on" } - val userStateTextColor = if (user.noNetwork) { - AppTheme.colorScheme.textSecondary - } else if (user.locationPermissionDenied) { - AppTheme.colorScheme.alertColor + val userStateTextColor = if (!state.batterySaveModeValue) { + if (user.noNetwork) { + AppTheme.colorScheme.textSecondary + } else if (user.locationPermissionDenied) { + AppTheme.colorScheme.alertColor + } else { + AppTheme.colorScheme.successColor + } } else { - AppTheme.colorScheme.successColor + AppTheme.colorScheme.alertColor } LaunchedEffect(location) { diff --git a/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt b/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt index dcee427c..de903898 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt @@ -22,6 +22,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material3.AlertDialog import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold @@ -39,6 +40,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -48,6 +50,7 @@ import com.canopas.yourspace.R import com.canopas.yourspace.data.utils.openAppSettings import com.canopas.yourspace.ui.component.AppBanner import com.canopas.yourspace.ui.component.ShowBackgroundLocationRequestDialog +import com.canopas.yourspace.ui.flow.home.activity.navigateToSettings import com.canopas.yourspace.ui.theme.AppTheme import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.PermissionStatus @@ -187,6 +190,29 @@ fun EnablePermissionsContent(modifier: Modifier) { } ) + val chineseDeviceList = stringArrayResource(R.array.chinese_devices_name) + val manufacturer = Build.MANUFACTURER.lowercase() + val isChineseDevice = chineseDeviceList.contains(manufacturer) + + val subtitle1 = if (isChineseDevice) { + "To ensure uninterrupted performance, please make this app to Don't optimize in power-saving settings." + } else { + "To ensure uninterrupted performance, please make this app unrestricted in your power-saving settings." + } + + val subTitle2 = if (isChineseDevice) { + "Battery > Advanced Settings > Optimize battery Use > GroupTrack > Make it Don't optimize" + } else { + "App Info > Battery > Make it Unrestricted" + } + + PermissionContent( + title = "Battery Optimization", + description = "$subtitle1\n\n$subTitle2", + isGranted = false, + onClick = { navigateToSettings(context) } + ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { PermissionContent( title = stringResource(R.string.enable_permission_notification_access_title), @@ -201,6 +227,12 @@ fun EnablePermissionsContent(modifier: Modifier) { } Spacer(modifier = Modifier.weight(1f)) + + HorizontalDivider( + color = AppTheme.colorScheme.outline, + thickness = 1.dp, + modifier = Modifier.padding(8.dp) + ) Text( text = stringResource(R.string.enable_permission_footer), style = AppTheme.appTypography.caption.copy(color = AppTheme.colorScheme.textDisabled), diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b488f1e9..b6d8a62e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -304,4 +304,17 @@ Add members to add places At least one member needs to join your group to be able to add places. + + Power saving notification + + + huawei + xiaomi + oppo + vivo + realme + lenovo + asus + oneplus + \ No newline at end of file diff --git a/data/src/main/java/com/canopas/yourspace/data/models/user/ApiUser.kt b/data/src/main/java/com/canopas/yourspace/data/models/user/ApiUser.kt index e35e5e98..9aaf1443 100644 --- a/data/src/main/java/com/canopas/yourspace/data/models/user/ApiUser.kt +++ b/data/src/main/java/com/canopas/yourspace/data/models/user/ApiUser.kt @@ -48,6 +48,7 @@ data class ApiUserSession( val device_name: String? = "", val platform: Int = LOGIN_DEVICE_TYPE_ANDROID, val session_active: Boolean = true, + val power_save_mode_enabled: Boolean = false, val app_version: Long? = 0, val created_at: Long? = System.currentTimeMillis() ) { diff --git a/data/src/main/java/com/canopas/yourspace/data/service/auth/AuthService.kt b/data/src/main/java/com/canopas/yourspace/data/service/auth/AuthService.kt index 311e74b5..3f9eb364 100644 --- a/data/src/main/java/com/canopas/yourspace/data/service/auth/AuthService.kt +++ b/data/src/main/java/com/canopas/yourspace/data/service/auth/AuthService.kt @@ -134,6 +134,11 @@ class AuthService @Inject constructor( val currentUser = currentUser ?: return apiUserService.updateSessionState(currentUser.id, state) } + + suspend fun updatePowerSaveModeStatus(powerSavingEnabled: Boolean) { + val currentUser = currentUser ?: return + apiUserService.updatePowerSaveModeStatus(currentUser.id, powerSavingEnabled) + } } interface AuthStateChangeListener { diff --git a/data/src/main/java/com/canopas/yourspace/data/service/user/ApiUserService.kt b/data/src/main/java/com/canopas/yourspace/data/service/user/ApiUserService.kt index 9f52f4ab..036283d9 100644 --- a/data/src/main/java/com/canopas/yourspace/data/service/user/ApiUserService.kt +++ b/data/src/main/java/com/canopas/yourspace/data/service/user/ApiUserService.kt @@ -166,4 +166,16 @@ class ApiUserService @Inject constructor( } } } + + suspend fun updatePowerSaveModeStatus(currentUserId: String, powerSavingEnabled: Boolean) { + val activeSession = getUserSession(currentUserId) + try { + if (activeSession != null) { + val updatedSession = activeSession.copy(power_save_mode_enabled = powerSavingEnabled) + sessionRef(currentUserId).document(activeSession.id).set(updatedSession).await() + } + } catch (e: Exception) { + Timber.e(e, "Failed to update power-saving mode status for user $currentUserId") + } + } } From 610f81f7476ea4e66267148c7b1d8ae3426ef3c4 Mon Sep 17 00:00:00 2001 From: Sneh Date: Tue, 24 Dec 2024 17:05:46 +0530 Subject: [PATCH 2/5] minor changes. --- .../com/canopas/yourspace/ui/MainActivity.kt | 10 +++--- .../home/activity/NavigateToDeviceSetting.kt | 4 ++- .../permission/EnablePermissionViewModel.kt | 33 ++++++++++++++++++- .../permission/EnablePermissionsScreen.kt | 9 +++-- app/src/main/res/values/strings.xml | 3 ++ .../EnablePermissionViewModelTest.kt | 6 +++- .../yourspace/data/storage/UserPreferences.kt | 11 +++++++ 7 files changed, 66 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt b/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt index a954632c..f5c150c8 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt @@ -7,7 +7,6 @@ import android.os.Bundle import android.os.PowerManager import android.provider.Settings import android.view.Window -import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.viewModels @@ -66,6 +65,7 @@ import com.canopas.yourspace.ui.navigation.slideComposable import com.canopas.yourspace.ui.theme.CatchMeTheme import com.google.gson.Gson import dagger.hilt.android.AndroidEntryPoint +import timber.log.Timber @AndroidEntryPoint class MainActivity : ComponentActivity() { @@ -313,16 +313,16 @@ fun PowerSavingAlertPopup() { val context = LocalContext.current AppAlertDialog( - title = "Turn off Battery Saver Mode", - subTitle = "When Battery Saver is on, GroupTrack cannot access location data, preventing the app from working correctly. Please turn off the power saving mode.", - confirmBtnText = "Turn Off", + title = stringResource(R.string.battery_saver_dialog_title), + subTitle = stringResource(R.string.battery_saver_dialog_description), + confirmBtnText = stringResource(R.string.btn_turn_off), dismissBtnText = stringResource(R.string.common_btn_cancel), onConfirmClick = { try { val intent = Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS) context.startActivity(intent) } catch (e: Exception) { - Toast.makeText(context, "Unable to navigate to settings", Toast.LENGTH_SHORT).show() + Timber.e("PowerSavingAlertPopup", "Failed to open battery saver settings", e) } }, onDismissClick = { diff --git a/app/src/main/java/com/canopas/yourspace/ui/flow/home/activity/NavigateToDeviceSetting.kt b/app/src/main/java/com/canopas/yourspace/ui/flow/home/activity/NavigateToDeviceSetting.kt index dece2298..7ca17c9c 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/flow/home/activity/NavigateToDeviceSetting.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/flow/home/activity/NavigateToDeviceSetting.kt @@ -6,9 +6,10 @@ import android.content.Intent import android.net.Uri import android.os.Build import android.provider.Settings +import com.canopas.yourspace.ui.flow.permission.EnablePermissionViewModel import timber.log.Timber -fun navigateToSettings(context: Context) { +fun navigateToSettings(context: Context, viewModel: EnablePermissionViewModel) { val packageManager = context.packageManager val intent = Intent() @@ -76,4 +77,5 @@ fun navigateToSettings(context: Context) { Timber.e("Error launching settings: ${e.localizedMessage}") context.startActivity(Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)) } + viewModel.changeBatteryOptimizationValue(true) } diff --git a/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionViewModel.kt b/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionViewModel.kt index 62d93647..c0473b5e 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionViewModel.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionViewModel.kt @@ -1,16 +1,47 @@ package com.canopas.yourspace.ui.flow.permission import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.canopas.yourspace.data.storage.UserPreferences +import com.canopas.yourspace.data.utils.AppDispatcher import com.canopas.yourspace.ui.navigation.AppNavigator import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class EnablePermissionViewModel @Inject constructor( - private val appNavigator: AppNavigator + private val appNavigator: AppNavigator, + private val userPreferences: UserPreferences, + private val appDispatcher: AppDispatcher ) : ViewModel() { + private val _state = MutableStateFlow(EnablePermissionState()) + val state = _state.asStateFlow() + + init { + viewModelScope.launch(appDispatcher.IO) { + _state.emit( + state.value.copy( + isBatteryOptimized = userPreferences.isBatteryOptimizationEnabled + ) + ) + } + } + + fun changeBatteryOptimizationValue(value: Boolean) { + viewModelScope.launch(appDispatcher.IO) { + state.value.isBatteryOptimized = value + } + } + fun popBack() { appNavigator.navigateBack() } } + +data class EnablePermissionState( + var isBatteryOptimized: Boolean = false +) diff --git a/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt b/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt index de903898..1fccfb06 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt @@ -31,6 +31,7 @@ import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -57,6 +58,7 @@ import com.google.accompanist.permissions.PermissionStatus import com.google.accompanist.permissions.rememberMultiplePermissionsState import com.google.accompanist.permissions.rememberPermissionState import com.google.accompanist.permissions.shouldShowRationale +import timber.log.Timber @Composable fun EnablePermissionsScreen() { @@ -101,6 +103,8 @@ private fun EnablePermissionsAppBar() { @Composable fun EnablePermissionsContent(modifier: Modifier) { val viewModel = hiltViewModel() + val state by viewModel.state.collectAsState() + val context = LocalContext.current val locationPermissionStates = rememberMultiplePermissionsState( listOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION) @@ -206,11 +210,12 @@ fun EnablePermissionsContent(modifier: Modifier) { "App Info > Battery > Make it Unrestricted" } + Timber.e("Screen Value ${state.isBatteryOptimized}") PermissionContent( title = "Battery Optimization", description = "$subtitle1\n\n$subTitle2", - isGranted = false, - onClick = { navigateToSettings(context) } + isGranted = state.isBatteryOptimized, + onClick = { navigateToSettings(context,viewModel) } ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b6d8a62e..97e6c5b0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -306,6 +306,9 @@ At least one member needs to join your group to be able to add places. Power saving notification + Turn Off + Turn off Battery Saver Mode + When Battery Saver is on, GroupTrack cannot access location data, preventing the app from working correctly. Please turn off the power saving mode. huawei diff --git a/app/src/test/java/com/canopas/yourspace/ui/flow/auth/permission/EnablePermissionViewModelTest.kt b/app/src/test/java/com/canopas/yourspace/ui/flow/auth/permission/EnablePermissionViewModelTest.kt index 2882ff9f..b501498f 100644 --- a/app/src/test/java/com/canopas/yourspace/ui/flow/auth/permission/EnablePermissionViewModelTest.kt +++ b/app/src/test/java/com/canopas/yourspace/ui/flow/auth/permission/EnablePermissionViewModelTest.kt @@ -1,5 +1,7 @@ package com.canopas.yourspace.ui.flow.auth.permission +import com.canopas.yourspace.data.storage.UserPreferences +import com.canopas.yourspace.data.utils.AppDispatcher import com.canopas.yourspace.ui.flow.permission.EnablePermissionViewModel import com.canopas.yourspace.ui.navigation.AppNavigator import org.junit.Test @@ -9,8 +11,10 @@ import org.mockito.kotlin.verify class EnablePermissionViewModelTest { private val appNavigator = mock() + private val userPreferences = mock() + private val appDispatcher = mock() - private val viewModel = EnablePermissionViewModel(appNavigator) + private val viewModel = EnablePermissionViewModel(appNavigator, userPreferences, appDispatcher) @Test fun `popBack should call navigate back`() { diff --git a/data/src/main/java/com/canopas/yourspace/data/storage/UserPreferences.kt b/data/src/main/java/com/canopas/yourspace/data/storage/UserPreferences.kt index 108ef7f0..6301fba8 100644 --- a/data/src/main/java/com/canopas/yourspace/data/storage/UserPreferences.kt +++ b/data/src/main/java/com/canopas/yourspace/data/storage/UserPreferences.kt @@ -45,6 +45,7 @@ class UserPreferences @Inject constructor( val LAST_BATTERY_DIALOG_DATE = stringPreferencesKey("last_battery_dialog_date") val KEY_USER_MAP_STYLE = stringPreferencesKey("user_map_style") + val KEY_BATTERY_OPTIMIZATION = booleanPreferencesKey("battery_optimization_enabled") } suspend fun isIntroShown(): Boolean { @@ -165,4 +166,14 @@ class UserPreferences @Inject constructor( } } } + + var isBatteryOptimizationEnabled: Boolean + get() = runBlocking { + preferencesDataStore.data.first()[PreferencesKey.KEY_BATTERY_OPTIMIZATION] ?: false + } + set(value) = runBlocking { + preferencesDataStore.edit { preferences -> + preferences[PreferencesKey.KEY_BATTERY_OPTIMIZATION] = value + } + } } From d5ca10589d99ac3f8d066631cc4e823dc1d07caf Mon Sep 17 00:00:00 2001 From: Sneh Date: Wed, 25 Dec 2024 10:51:19 +0530 Subject: [PATCH 3/5] Add functionality to check and make app restricted for powerSavingMode. --- .../receiver/PowerSavingModeObserver.kt | 2 -- .../domain/utils/PowerSavingObserver.kt | 4 +-- .../com/canopas/yourspace/ui/MainActivity.kt | 26 ++++++++++++------- .../com/canopas/yourspace/ui/MainViewModel.kt | 11 ++++++-- .../home/map/component/SelectedUserDetail.kt | 5 ++-- .../permission/EnablePermissionViewModel.kt | 5 ++-- .../permission/EnablePermissionsScreen.kt | 19 ++++++++------ app/src/main/res/values/strings.xml | 9 +++++++ 8 files changed, 53 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/canopas/yourspace/domain/receiver/PowerSavingModeObserver.kt b/app/src/main/java/com/canopas/yourspace/domain/receiver/PowerSavingModeObserver.kt index 6b3a955d..8712fbe6 100644 --- a/app/src/main/java/com/canopas/yourspace/domain/receiver/PowerSavingModeObserver.kt +++ b/app/src/main/java/com/canopas/yourspace/domain/receiver/PowerSavingModeObserver.kt @@ -29,10 +29,8 @@ class PowerSavingModeObserver @Inject constructor( } override fun onReceive(context: Context?, intent: Intent?) { - Timber.e("Received Power Saving Mode change") val powerManager = context?.getSystemService(Context.POWER_SERVICE) as PowerManager val isPowerSaving = powerManager.isPowerSaveMode - Timber.e("Power Saving Mode is $isPowerSaving") if (isPowerSaving) { sendPowerSavingNotification(context) diff --git a/app/src/main/java/com/canopas/yourspace/domain/utils/PowerSavingObserver.kt b/app/src/main/java/com/canopas/yourspace/domain/utils/PowerSavingObserver.kt index af2b4ed6..339adcd0 100644 --- a/app/src/main/java/com/canopas/yourspace/domain/utils/PowerSavingObserver.kt +++ b/app/src/main/java/com/canopas/yourspace/domain/utils/PowerSavingObserver.kt @@ -30,8 +30,8 @@ fun sendPowerSavingNotification(context: Context) { val notificationBuilder = NotificationCompat.Builder(context, YOURSPACE_CHANNEL_POWER_SAVING) .setSmallIcon(R.drawable.app_logo) - .setContentTitle("Battery Save is on, disabling GroupTrack") - .setContentText("Your phone is in power saving mode, and some features might be limited. Turn off Battery Saver in Settings to reconnect GroupTrack.") + .setContentTitle(context.getString(R.string.battery_saving_notification_title)) + .setContentText(context.getString(R.string.battery_saving_notification_description)) .setAutoCancel(true) .setContentIntent(pendingIntent) diff --git a/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt b/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt index f5c150c8..8126f55a 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt @@ -1,7 +1,9 @@ package com.canopas.yourspace.ui +import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import android.content.IntentFilter import android.net.Uri import android.os.Bundle import android.os.PowerManager @@ -72,15 +74,20 @@ class MainActivity : ComponentActivity() { private val viewModel: MainViewModel by viewModels() + private val powerSaveReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + val isPowerSavingMode = viewModel.isPowerSavingModeEnabled(context ?: return) + viewModel.updatePowerSavingState(isPowerSavingMode) + } + } + override fun onCreate(savedInstanceState: Bundle?) { requestWindowFeature(Window.FEATURE_NO_TITLE) super.onCreate(savedInstanceState) - val isPowerSavingEnabled = isPowerSavingModeEnabled() - if (isPowerSavingEnabled) { - viewModel.showPowerSavingDialog() - } + val filter = IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED) + registerReceiver(powerSaveReceiver, filter) setContent { CatchMeTheme { @@ -89,10 +96,14 @@ class MainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { + val context = LocalContext.current + MainApp(viewModel) LaunchedEffect(Unit) { viewModel.handleIntentData(intent) + val isPowerSavingEnable = viewModel.isPowerSavingModeEnabled(context) + viewModel.updatePowerSavingState(isPowerSavingEnable) // Ensure initial state is set } } } @@ -105,11 +116,6 @@ class MainActivity : ComponentActivity() { viewModel.handleIntentData(intent) intent.extras?.clear() } - - private fun isPowerSavingModeEnabled(): Boolean { - val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager - return powerManager.isPowerSaveMode - } } @OptIn(ExperimentalAnimationApi::class) @@ -312,6 +318,8 @@ fun PowerSavingAlertPopup() { val viewModel = hiltViewModel() val context = LocalContext.current + Timber.d("XXX :- PowerSavingAlertPopup: Displaying power saving dialog") + AppAlertDialog( title = stringResource(R.string.battery_saver_dialog_title), subTitle = stringResource(R.string.battery_saver_dialog_description), diff --git a/app/src/main/java/com/canopas/yourspace/ui/MainViewModel.kt b/app/src/main/java/com/canopas/yourspace/ui/MainViewModel.kt index 12c584c3..2ecac421 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/MainViewModel.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/MainViewModel.kt @@ -1,6 +1,8 @@ package com.canopas.yourspace.ui +import android.content.Context import android.content.Intent +import android.os.PowerManager import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.canopas.yourspace.data.models.user.ApiUserSession @@ -144,13 +146,18 @@ class MainViewModel @Inject constructor( _state.value = state.value.copy(showSpaceNotFoundPopup = false) } - fun showPowerSavingDialog() { - _state.value = state.value.copy(isPowerSavingEnabled = true) + fun updatePowerSavingState(isEnabled: Boolean) { + _state.value = state.value.copy(isPowerSavingEnabled = isEnabled) } fun dismissPowerSavingDialog() { _state.value = state.value.copy(isPowerSavingEnabled = false) } + + fun isPowerSavingModeEnabled(context: Context): Boolean { + val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager + return powerManager.isPowerSaveMode + } } data class MainScreenState( diff --git a/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/component/SelectedUserDetail.kt b/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/component/SelectedUserDetail.kt index 9d337438..b8fef6c2 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/component/SelectedUserDetail.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/flow/home/map/component/SelectedUserDetail.kt @@ -55,7 +55,6 @@ import com.google.android.gms.maps.model.LatLng import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext -import timber.log.Timber @Composable fun SelectedUserDetail( @@ -161,7 +160,7 @@ private fun MemberInfoView( var address by remember { mutableStateOf("") } val time = timeAgo(location?.created_at ?: 0) - Timber.e("XXX Value of battery save mode is ${state.batterySaveModeValue}") + val userStateText = if (!state.batterySaveModeValue) { if (user.noNetwork) { stringResource(R.string.map_selected_user_item_no_network_state) @@ -171,7 +170,7 @@ private fun MemberInfoView( stringResource(R.string.map_selected_user_item_online_state) } } else { - "Battery saver mode is on" + stringResource(R.string.battery_saver_text) } val userStateTextColor = if (!state.batterySaveModeValue) { if (user.noNetwork) { diff --git a/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionViewModel.kt b/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionViewModel.kt index c0473b5e..70428fd6 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionViewModel.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionViewModel.kt @@ -21,7 +21,7 @@ class EnablePermissionViewModel @Inject constructor( private val _state = MutableStateFlow(EnablePermissionState()) val state = _state.asStateFlow() - init { + fun refreshBatteryOptimizationState() { viewModelScope.launch(appDispatcher.IO) { _state.emit( state.value.copy( @@ -33,7 +33,8 @@ class EnablePermissionViewModel @Inject constructor( fun changeBatteryOptimizationValue(value: Boolean) { viewModelScope.launch(appDispatcher.IO) { - state.value.isBatteryOptimized = value + _state.value = _state.value.copy(isBatteryOptimized = value) + userPreferences.isBatteryOptimizationEnabled = value } } diff --git a/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt b/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt index 1fccfb06..1ff4ab3e 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/flow/permission/EnablePermissionsScreen.kt @@ -31,6 +31,7 @@ import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -58,7 +59,6 @@ import com.google.accompanist.permissions.PermissionStatus import com.google.accompanist.permissions.rememberMultiplePermissionsState import com.google.accompanist.permissions.rememberPermissionState import com.google.accompanist.permissions.shouldShowRationale -import timber.log.Timber @Composable fun EnablePermissionsScreen() { @@ -110,6 +110,10 @@ fun EnablePermissionsContent(modifier: Modifier) { listOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION) ) + LaunchedEffect(Unit) { + viewModel.refreshBatteryOptimizationState() + } + val bgLocationPermissionStates = rememberPermissionState(Manifest.permission.ACCESS_BACKGROUND_LOCATION) @@ -199,23 +203,22 @@ fun EnablePermissionsContent(modifier: Modifier) { val isChineseDevice = chineseDeviceList.contains(manufacturer) val subtitle1 = if (isChineseDevice) { - "To ensure uninterrupted performance, please make this app to Don't optimize in power-saving settings." + stringResource(R.string.battery_optimization_permission_subtitle_chinese) } else { - "To ensure uninterrupted performance, please make this app unrestricted in your power-saving settings." + stringResource(R.string.battery_optimization_permission_subtitle_other) } val subTitle2 = if (isChineseDevice) { - "Battery > Advanced Settings > Optimize battery Use > GroupTrack > Make it Don't optimize" + stringResource(R.string.battery_optimization_permission_path_chinese) } else { - "App Info > Battery > Make it Unrestricted" + stringResource(R.string.battery_optimization_permission_path_other) } - Timber.e("Screen Value ${state.isBatteryOptimized}") PermissionContent( - title = "Battery Optimization", + title = stringResource(R.string.battery_optimization_permission_title), description = "$subtitle1\n\n$subTitle2", isGranted = state.isBatteryOptimized, - onClick = { navigateToSettings(context,viewModel) } + onClick = { navigateToSettings(context, viewModel) } ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 97e6c5b0..7832fb92 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -107,6 +107,12 @@ To receive timely updates, check-ins, and alerts from GroupTrack, grant notification access. We respect your privacy and will only use notifications to enhance your experience. Enable now for seamless communication! Enable Notification Access + Battery Optimization + To ensure uninterrupted performance, please make this app to Don\'t optimize in power-saving settings. + To ensure uninterrupted performance, please make this app unrestricted in your power-saving settings. + Advanced Settings > Optimize battery Use > GroupTrack > Make it Don\'t optimize]]> + Battery > Make it Unrestricted]]> + Home Activities Places @@ -309,6 +315,9 @@ Turn Off Turn off Battery Saver Mode When Battery Saver is on, GroupTrack cannot access location data, preventing the app from working correctly. Please turn off the power saving mode. + Battery Save is on, disabling GroupTrack + Your phone is in power saving mode, and some features might be limited. Turn off Battery Saver in Settings to reconnect GroupTrack. + Battery saver mode is on huawei From 82fb011d04a00600cb190a198799d213a56648ec Mon Sep 17 00:00:00 2001 From: Sneh Date: Wed, 25 Dec 2024 11:01:51 +0530 Subject: [PATCH 4/5] minor change. --- app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt b/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt index 8126f55a..9a970d8b 100644 --- a/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt +++ b/app/src/main/java/com/canopas/yourspace/ui/MainActivity.kt @@ -116,6 +116,11 @@ class MainActivity : ComponentActivity() { viewModel.handleIntentData(intent) intent.extras?.clear() } + + override fun onDestroy() { + super.onDestroy() + unregisterReceiver(powerSaveReceiver) + } } @OptIn(ExperimentalAnimationApi::class) From 6c9509963d11ddfc87d2628bb9950d624d668008 Mon Sep 17 00:00:00 2001 From: Sneh Date: Tue, 31 Dec 2024 14:36:10 +0530 Subject: [PATCH 5/5] minor changes. --- app/src/main/res/values/strings.xml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cb671a76..4b929ec5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -107,6 +107,12 @@ To receive timely updates, check-ins, and alerts from GroupTrack, grant notification access. We respect your privacy and will only use notifications to enhance your experience. Enable now for seamless communication! Enable Notification Access + Battery Optimization + To ensure uninterrupted performance, please make this app to Don\'t optimize in power-saving settings. + To ensure uninterrupted performance, please make this app unrestricted in your power-saving settings. + Advanced Settings > Optimize battery Use > GroupTrack > Make it Don\'t optimize]]> + Battery > Make it Unrestricted]]> + Home Activities Places @@ -306,6 +312,25 @@ Add members to add places At least one member needs to join your group to be able to add places. + Power saving notification + Turn Off + Turn off Battery Saver Mode + When Battery Saver is on, GroupTrack cannot access location data, preventing the app from working correctly. Please turn off the power saving mode. + Battery Save is on, disabling GroupTrack + Your phone is in power saving mode, and some features might be limited. Turn off Battery Saver in Settings to reconnect GroupTrack. + Battery saver mode is on + + + huawei + xiaomi + oppo + vivo + realme + lenovo + asus + oneplus + + Reassign Admin Before Deletion Please assign a new admin before proceeding with the account deletion to avoid data loss. \nYou are an admin of the following groups :\n%1$s \ No newline at end of file