diff --git a/app/src/main/kotlin/com/google/ai/sample/MainActivity.kt b/app/src/main/kotlin/com/google/ai/sample/MainActivity.kt index 510bc0a0..0a0a7c93 100644 --- a/app/src/main/kotlin/com/google/ai/sample/MainActivity.kt +++ b/app/src/main/kotlin/com/google/ai/sample/MainActivity.kt @@ -657,21 +657,52 @@ class MainActivity : ComponentActivity() { } } else { Log.i(TAG, "queryActiveSubscriptions: User has no active subscription for $subscriptionProductId. Re-evaluating trial logic.") + // --- START: MODIFICATION --- + if (TrialManager.isPurchased(this@MainActivity)) { + Log.w(TAG, "queryActiveSubscriptions: No active subscription found by Google Play Billing, but app was previously marked as purchased. Clearing purchase mark.") + TrialManager.clearPurchaseMark(this@MainActivity) + } + // --- END: MODIFICATION --- if (TrialManager.getTrialState(this, null) != TrialManager.TrialState.PURCHASED) { Log.d(TAG, "queryActiveSubscriptions: No active sub, and TrialManager confirms not purchased. Re-evaluating trial state and starting service if needed.") updateTrialState(TrialManager.getTrialState(this, null)) + // --- START: MODIFICATION --- + if (currentTrialState == TrialManager.TrialState.EXPIRED_INTERNET_TIME_CONFIRMED) { + Log.i(TAG, "queryActiveSubscriptions: Subscription deactivated (no active sub and trial expired). Showing Toast.") + Toast.makeText(this@MainActivity, "Subscription is deactivated", Toast.LENGTH_LONG).show() + } + // --- END: MODIFICATION --- startTrialServiceIfNeeded() } else { Log.w(TAG, "queryActiveSubscriptions: No active sub from Google, but TrialManager says PURCHASED. This could be due to restored SharedPreferences without active subscription. Re-evaluating trial logic based on no internet time.") - updateTrialState(TrialManager.getTrialState(this, null)) + updateTrialState(TrialManager.getTrialState(this, null)) + // --- START: MODIFICATION --- + if (currentTrialState == TrialManager.TrialState.EXPIRED_INTERNET_TIME_CONFIRMED) { + Log.i(TAG, "queryActiveSubscriptions: Subscription deactivated (no active sub, was purchased, now trial expired). Showing Toast.") + Toast.makeText(this@MainActivity, "Subscription is deactivated", Toast.LENGTH_LONG).show() + } + // --- END: MODIFICATION --- startTrialServiceIfNeeded() } } } else { Log.e(TAG, "Failed to query active subscriptions: ${billingResult.debugMessage}") Log.d(TAG, "queryActiveSubscriptions: Query failed. Re-evaluating trial state based on no internet time and starting service if needed.") + // --- START: MODIFICATION --- + // It's important to also check/clear purchase mark here if query fails but app thought it was purchased + if (TrialManager.isPurchased(this@MainActivity)) { + Log.w(TAG, "queryActiveSubscriptions: Failed to query active subscriptions, but app was previously marked as purchased. Clearing purchase mark.") + TrialManager.clearPurchaseMark(this@MainActivity) + } + // --- END: MODIFICATION --- if (TrialManager.getTrialState(this, null) != TrialManager.TrialState.PURCHASED) { updateTrialState(TrialManager.getTrialState(this, null)) + // --- START: MODIFICATION --- + if (currentTrialState == TrialManager.TrialState.EXPIRED_INTERNET_TIME_CONFIRMED) { + Log.i(TAG, "queryActiveSubscriptions: Subscription deactivated (query failed, trial expired). Showing Toast.") + Toast.makeText(this@MainActivity, "Subscription is deactivated", Toast.LENGTH_LONG).show() + } + // --- END: MODIFICATION --- startTrialServiceIfNeeded() } } diff --git a/app/src/main/kotlin/com/google/ai/sample/TrialManager.kt b/app/src/main/kotlin/com/google/ai/sample/TrialManager.kt index e1ddd9d6..bcc54787 100644 --- a/app/src/main/kotlin/com/google/ai/sample/TrialManager.kt +++ b/app/src/main/kotlin/com/google/ai/sample/TrialManager.kt @@ -235,7 +235,7 @@ object TrialManager { Log.i(TAG, "App marked as purchased. Trial data (including obfuscated end time and confirmed expired flag) cleared. Purchase status stored in KEY_FEATURE_ACCESS_FLAG.") } - private fun isPurchased(context: Context): Boolean { + internal fun isPurchased(context: Context): Boolean { // Comment for future AI: KEY_FEATURE_ACCESS_FLAG indicates the app has been purchased. Log.d(TAG, "isPurchased called, checking KEY_FEATURE_ACCESS_FLAG") val purchased = getSharedPreferences(context).getBoolean(KEY_FEATURE_ACCESS_FLAG, false) @@ -243,6 +243,21 @@ object TrialManager { return purchased } + fun clearPurchaseMark(context: Context) { + Log.d(TAG, "clearPurchaseMark called") + val editor = getSharedPreferences(context).edit() + // Comment for future AI: KEY_FEATURE_ACCESS_FLAG is set to false to indicate the feature is no longer accessed via purchase. + Log.d(TAG, "Setting KEY_FEATURE_ACCESS_FLAG to false") + editor.putBoolean(KEY_FEATURE_ACCESS_FLAG, false) + // Comment for future AI: KEY_INITIAL_SETUP_FLAG is reset to true to allow trial re-evaluation. + Log.d(TAG, "Setting KEY_INITIAL_SETUP_FLAG to true") + editor.putBoolean(KEY_INITIAL_SETUP_FLAG, true) + // IMPORTANT: KEY_CFG_TS (obfuscated trial end time) and KEY_CFG_ST (obfuscated confirmed expired flag) + // are intentionally NOT cleared here. The original trial period might still be relevant. + editor.apply() + Log.i(TAG, "Purchase mark cleared. Feature access flag set to false, initial setup flag reset to true. Trial end time and expired flag preserved.") + } + fun initializeTrialStateFlagsIfNecessary(context: Context) { Log.d(TAG, "initializeTrialStateFlagsIfNecessary called") val prefs = getSharedPreferences(context)