rebreak-monorepo/apps/rebreak-native/lib/onboardingAssets.ts
chahinebrini 4a013bc43b feat(android-protection): präzise Tamper-Lock + a11y-Onboarding-Guide
Tamper-Lock von Keyword-Scanning auf präzise Einzel-Surfaces umgebaut:
blockt nur ReBreaks eigene Screens (Admin-Deaktivierung via DeviceAdminAdd,
a11y-Ausschalten, VPN-Trennen/Surface), nie Listen oder fremde Apps.

- Deny-Removal = Admin-only: OS graut Uninstall+Force-Stop für aktiven
  Device-Admin aus; einziger Bypass (Admin deaktivieren) bleibt a11y-gesperrt.
  Andere Apps verwalten/force-stoppen/deinstallieren bleibt komplett frei.
- a11y-Onboarding: passiver Bottom-Overlay-Hinweis + Settings-Reset auf
  Startseite nach Aktivierung + 1s-Delay vor App-Rückkehr.
- VPN-Trennen-Dialog + a11y-Ausschalten neu abgedeckt.
- a11y-Service-Icon im Plugin (klar als ReBreak erkennbar).

Verifiziert auf A50 per logcat: alle 4 Surfaces blocken, Listen + fremde
Apps frei, keine False-Positives.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 04:05:41 +02:00

100 lines
4.3 KiB
TypeScript

/**
* Permission-Dialog-Screenshots für den Onboarding-Pre-Explainer.
*
* Pro Sprache liegen die Screenshots in `assets/onboarding/<lang>/`. Falls
* eine Sprache nicht (oder noch nicht) verfügbar ist, fällt der Resolver auf
* `de` zurück.
*
* Dialog-Typen:
* iOS:
* - `url_filter` → NEFilter-System-Dialog ("Erlauben"-Button)
* - `screen_time` → Family-Controls-/Screen-Time-Dialog ("Fortfahren")
* Android:
* - `android_vpn` → VpnService-System-Dialog ("OK"-Button)
* - `android_a11y` → Bedienungshilfen-Settings mit ReBreak-Eintrag
*
* Diese Maps explizit mit `require(...)` deklarieren — RN/Metro kann keine
* dynamischen Pfade auflösen.
*/
type Dialog = 'url_filter' | 'screen_time' | 'android_vpn' | 'android_a11y' | 'android_a11y_overview';
type Lang = 'de' | 'en' | 'fr' | 'ar';
/* eslint-disable @typescript-eslint/no-require-imports */
const URL_FILTER_DE = require('../assets/onboarding/de/url_filter_permission.jpeg');
const URL_FILTER_EN = require('../assets/onboarding/en/url_filter_permission.jpeg');
const URL_FILTER_FR = require('../assets/onboarding/fr/url_filter_permission.jpeg');
const URL_FILTER_AR = require('../assets/onboarding/ar/url_filter_permission.jpeg');
const SCREEN_TIME_DE = require('../assets/onboarding/de/screen_time_permission.jpeg');
const SCREEN_TIME_EN = require('../assets/onboarding/en/screen_time_permission.jpeg');
const SCREEN_TIME_FR = require('../assets/onboarding/fr/screen_time_permission.jpeg');
const SCREEN_TIME_AR = require('../assets/onboarding/ar/screen_time_permission.jpeg');
// Android — VpnService-Permission-Dialog ("Verbindungsanforderung")
const ANDROID_VPN_DE = require('../assets/onboarding/de/android-vpn-permission-001.png');
const ANDROID_VPN_EN = require('../assets/onboarding/en/android-vpn-permission-001.png');
const ANDROID_VPN_FR = require('../assets/onboarding/fr/android-vpn-permission-001.png');
const ANDROID_VPN_AR = require('../assets/onboarding/ar/android-vpn-permission-001.png');
// Android — Accessibility-Settings, ReBreak-Row sichtbar
const ANDROID_A11Y_DE = require('../assets/onboarding/de/android-a11y-rebreak-row-001.png');
const ANDROID_A11Y_EN = require('../assets/onboarding/en/android-a11y-rebreak-row-001.png');
const ANDROID_A11Y_FR = require('../assets/onboarding/fr/android-a11y-rebreak-row-001.png');
const ANDROID_A11Y_AR = require('../assets/onboarding/ar/android-a11y-rebreak-row-001.png');
// Android — a11y-Übersicht (Samsung Homepage) mit „Installierte Dienste". Das ist
// der Screen, auf dem der Deep-Link landet (tiefer kommt eine normale App nicht —
// Detail-Page + Dienste-Liste sind signature-gesperrt). Hier zeigen wir dem User,
// wo er auf „Installierte Dienste" tippen muss.
const ANDROID_A11Y_OVERVIEW_DE = require('../assets/onboarding/de/android-a11y-overview-001.png');
const ANDROID_A11Y_OVERVIEW_EN = require('../assets/onboarding/en/android-a11y-overview-001.png');
const ANDROID_A11Y_OVERVIEW_FR = require('../assets/onboarding/fr/android-a11y-overview-001.png');
const ANDROID_A11Y_OVERVIEW_AR = require('../assets/onboarding/ar/android-a11y-overview-001.png');
/* eslint-enable @typescript-eslint/no-require-imports */
const SCREENSHOTS: Record<Dialog, Partial<Record<Lang, number>>> = {
url_filter: {
de: URL_FILTER_DE,
en: URL_FILTER_EN,
fr: URL_FILTER_FR,
ar: URL_FILTER_AR,
},
screen_time: {
de: SCREEN_TIME_DE,
en: SCREEN_TIME_EN,
fr: SCREEN_TIME_FR,
ar: SCREEN_TIME_AR,
},
android_vpn: {
de: ANDROID_VPN_DE,
en: ANDROID_VPN_EN,
fr: ANDROID_VPN_FR,
ar: ANDROID_VPN_AR,
},
android_a11y: {
de: ANDROID_A11Y_DE,
en: ANDROID_A11Y_EN,
fr: ANDROID_A11Y_FR,
ar: ANDROID_A11Y_AR,
},
android_a11y_overview: {
de: ANDROID_A11Y_OVERVIEW_DE,
en: ANDROID_A11Y_OVERVIEW_EN,
fr: ANDROID_A11Y_OVERVIEW_FR,
ar: ANDROID_A11Y_OVERVIEW_AR,
},
};
/**
* Resolves the right screenshot for the current language, with de-fallback.
* Returns the result of `require(...)` (an opaque module-handle for Metro).
*/
export function getPermissionScreenshot(dialog: Dialog, lang: string): number {
const normalized = (
lang === 'de' || lang === 'en' || lang === 'fr' || lang === 'ar' ? lang : 'de'
) as Lang;
const map = SCREENSHOTS[dialog];
return map[normalized] ?? map.de!;
}