Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,16 @@ class PermissionsActivity : ComponentActivity() {
}
}

// Only handle bundle params on first creation, not on config changes
// ViewModel retains state across config changes, so permission state survives rotation
if (savedInstanceState == null) {
lifecycleScope.launch {
// Handle bundle params if ViewModel is not already initialized
// This covers:
// 1. Process death: savedInstanceState == null, ViewModel is recreated, needs initialization
// 2. Config change: savedInstanceState != null, ViewModel survives, but we check if already initialized
// 3. Race condition: onRequestPermissionsResult might arrive before initialization completes
// (handled by null check in executeCallback)
lifecycleScope.launch {
// Only initialize if ViewModel is not already initialized
// On config changes, ViewModel survives with its state, so we skip re-initialization
if (viewModel.permissionRequestType == null) {
handleBundleParams(intent.extras)
}
}
Expand Down Expand Up @@ -84,19 +90,22 @@ class PermissionsActivity : ComponentActivity() {
return
}

reregisterCallbackHandlers(extras)
extras?.let { bundle ->
reregisterCallbackHandlers(bundle)
val permissionType = bundle.getString(INTENT_EXTRA_PERMISSION_TYPE)
val androidPermissionString = bundle.getString(INTENT_EXTRA_ANDROID_PERMISSION_STRING)

val permissionType = extras!!.getString(INTENT_EXTRA_PERMISSION_TYPE)
val androidPermissionString = extras.getString(INTENT_EXTRA_ANDROID_PERMISSION_STRING)
// Initialize OneSignal and ViewModel (handles initialization in one place)
if (!viewModel.initialize(this, permissionType, androidPermissionString)) {
finishActivity()
return@let
}

// Initialize OneSignal and ViewModel (handles initialization in one place)
if (!viewModel.initialize(this, permissionType, androidPermissionString)) {
finishActivity()
return
// Request permission - this is Activity-layer logic
androidPermissionString?.let { permission ->
requestPermission(permission)
}
}

// Request permission - this is Activity-layer logic
requestPermission(androidPermissionString!!)
}

// Required if the app was killed while this prompt was showing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.onesignal.core.internal.permissions.impl.RequestPermissionService
import com.onesignal.core.internal.preferences.IPreferencesService
import com.onesignal.core.internal.preferences.PreferenceOneSignalKeys
import com.onesignal.core.internal.preferences.PreferenceStores
import com.onesignal.debug.internal.logging.Logging
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
Expand Down Expand Up @@ -149,14 +150,21 @@ class PermissionsViewModel : ViewModel() {
granted: Boolean,
showSettings: Boolean,
) {
val callback =
requestPermissionService.getCallback(permissionRequestType!!)
?: throw RuntimeException("Missing handler for permissionRequestType: $permissionRequestType")

if (granted) {
callback.onAccept()
} else {
callback.onReject(showSettings)
permissionRequestType?.let { type ->
val callback =
requestPermissionService.getCallback(type)
?: throw RuntimeException("Missing handler for permissionRequestType: $type")

if (granted) {
callback.onAccept()
} else {
callback.onReject(showSettings)
}
} ?: run {
// There is a small chance ViewModel was never fully initialized (e.g. process death or OneSignal init hanging while prompting).
// We can't safely resolve a callback in this state, so just finish the flow.
Logging.error("PermissionsViewModel: Cannot resolve callback because permissionRequestType is null. Ending permission flow.")
_shouldFinish.value = true
}
}

Expand Down
Loading
Loading