feat: partage d'écran Android 5+ (MediaProjection) et blocage des installations

- Partage d'écran par MediaProjection (ScreenCaptureService + ScreenConsentActivity)
  quand la capture par accessibilité n'est pas possible (Android < 11 ou service coupé).
  En mode propriétaire, le service d'accessibilité valide seul le consentement système.
- Blocage de l'installation d'applications (Play Store compris) piloté par le parent
  (policy block_installs → OwnerPolicy DISALLOW_INSTALL_APPS en mode propriétaire).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R9CBCVP5oDu2sfoYPisNCQ
This commit is contained in:
tuxgyverandClaude Opus 4.8 committed 2026-10-25 22:28:16 +01:00
1 parent 665d6e2cb3
commit d4aa0e1962
14 files changed
+328 -17

No files matched your search

@@ -25,6 +25,8 @@ data class AppSettings(
val serverMode: String = "open",
val serverModeReason: String = "",
val policyVersion: Long = 0L,
/** Bloque l'installation d'applications (Play Store compris) — appliqué en mode propriétaire. */
val blockInstalls: Boolean = false,
/** Téléphone verrouillé à distance par le parent : un code du serveur est exigé pour le déverrouiller. */
val parentalLocked: Boolean = false
) {
@@ -58,6 +58,7 @@ class SettingsRepository @Inject constructor(
val LINK_TOKEN_ENC = stringPreferencesKey("link_token_enc")
val WG_PRIVATE_ENC = stringPreferencesKey("wg_private_enc")
val SERVER_MODE = stringPreferencesKey("server_mode")
val BLOCK_INSTALLS = booleanPreferencesKey("block_installs")
val SERVER_MODE_REASON = stringPreferencesKey("server_mode_reason")
val POLICY_VERSION = longPreferencesKey("policy_version")
val EVENT_QUEUE = stringPreferencesKey("event_queue")
@@ -103,7 +104,8 @@ class SettingsRepository @Inject constructor(
serverMode = prefs[Keys.SERVER_MODE] ?: defaults.serverMode,
serverModeReason = prefs[Keys.SERVER_MODE_REASON] ?: defaults.serverModeReason,
policyVersion = prefs[Keys.POLICY_VERSION] ?: defaults.policyVersion,
parentalLocked = prefs[Keys.PARENTAL_LOCKED] ?: defaults.parentalLocked
parentalLocked = prefs[Keys.PARENTAL_LOCKED] ?: defaults.parentalLocked,
blockInstalls = prefs[Keys.BLOCK_INSTALLS] ?: defaults.blockInstalls
)
}
@@ -324,11 +326,12 @@ class SettingsRepository @Inject constructor(
suspend fun wgPrivateKey(): String? = SecretBox.decrypt(context.dataStore.data.first()[Keys.WG_PRIVATE_ENC])
/** Consigne reçue du serveur (mode réseau en cours et règles d'applications). */
suspend fun applyServerPolicy(version: Long, mode: String, reason: String, rulesJson: String?) {
suspend fun applyServerPolicy(version: Long, mode: String, reason: String, rulesJson: String?, blockInstalls: Boolean) {
context.dataStore.edit {
it[Keys.POLICY_VERSION] = version
it[Keys.SERVER_MODE] = mode
it[Keys.SERVER_MODE_REASON] = reason
it[Keys.BLOCK_INSTALLS] = blockInstalls
if (rulesJson.isNullOrBlank() || rulesJson == "{}") it.remove(Keys.RULES_JSON) else it[Keys.RULES_JSON] = rulesJson
}
}