Ximos logo Ximos

Open-source core · XimosKid 1.0.3 / Ximos 1.0.2

The code behind the permission prompts.

Rather than describe what XimosKid does with each permission, this page shows the actual source — the dialog logic, the disclosure text a user reads before granting access, the Firebase-driven session flow behind each streaming feature, and the API layers that gate access to a device.

Feature capability map

Every remote-control action XimosKid supports, exactly what it does on the child device, and which billing bucket it draws from. This is the complete list — nothing here is simplified for marketing, and nothing is left out because it's less flattering.

FeatureWhat it actually doesBilling
Screen mirroringLive view of the child's screen in the parent appFree seconds or balance
Remote touch controlFull click, swipe, and gesture control of the child's screen during an active mirroring session — not limited to simple tapsIncluded in mirroring session
Camera castingLive front/rear camera streamFree seconds or balance
Camera flipSwitch between front and rear camera mid-sessionIncluded in camera session
Flashlight toggleTurn the rear flash on/off during a live camera sessionIncluded in camera session
Surrounding audio listeningOne-way ambient microphone listening, available during screen or camera sessionsBalance only — requires a minimum $0.10 account balance; not covered by free bonus seconds
Smart AlertFull-screen popup dialog on the child's device with a custom image and instructions, shown until dismissedLow-cost per send
OnScreen NotifyCustom notification (text + optional image) delivered to the child's notification shade under the XimosKid identityLow-cost per send
Open AppLaunches a specific app on the child's device by package nameLow-cost per send
Send LinkOpens a specific URL in Chrome on the child's deviceLow-cost per send
Clipboard sendPushes text or an image directly into the child device's clipboard, ready to pasteLow-cost per send
Photo / video captureParent-requested snapshot or clip, uploaded to the 30-day Cloud Media VaultFree seconds or balance
Usage monitoringScreen time totals, per-app open count and duration, unlock count, battery, current time, Wi-Fi/mobile data usageIncluded, no extra cost
Screenshot of the Smart Alert toolbox showing an image URL field and Show Alert Window button
Smart Alert — a parent can push a full-screen popup with a custom image and instructions to the child's device from this toolbox tab.
Screenshot of a custom OnScreen Notify notification appearing in the Android notification shade
OnScreen Notify — a custom message appears directly in the notification shade under the XimosKid identity.
Screenshot of an OnScreen Notify notification with an attached image
The same tool also supports attaching an image alongside the message.
What's deliberately missing: Ximos does not include remote app blocking or web/video content filtering. That's a design choice, not a gap we haven't gotten to — our philosophy is that parents should have visibility and the ability to advise, not the ability to remotely lock down a child's phone. Keyword/content filtering and optional app blocking are being explored for a future update; if they ship, they'll be opt-in and documented here before release, not silently enabled. See current status on the Roadmap.

Usage monitoring, in full

The Usages Report screen in the parent dashboard shows exactly this, and nothing more:

  • • Battery level and last-synced time
  • • Today's Wi-Fi and mobile data usage (MB/KB), tracked separately
  • • Weekly screen-time trend, by day
  • • Per-app usage duration, most-used apps first
  • • Weekly Wi-Fi vs. mobile data usage chart
  • • Daily phone-unlock count, by day of week
  • • Current device time (for time-zone-aware reporting)
  • • No app blocking, time limits, or content filtering — see the note above
Screenshot of the Usages Report screen showing battery, data usage, weekly screen time chart, per-app breakdown, and phone unlock chart
The full Usages Report screen as it appears in the parent dashboard.

Permission request flow

Every dangerous permission goes through the same three-step gate before the Android system dialog even appears. This is the same flow for all seven sensitive permissions XimosKid requests.

1 · Disclosure shown

A custom dialog explains, in plain language, exactly what this permission does and why it's requested — before any system prompt.

2 · Forced read delay

The "Grant" button is disabled behind a 1-second countdown so the disclosure can't be tapped through blindly.

3 · System prompt

Only after that does Android's own permission dialog appear. Denying it at this point is always respected — no repeated re-prompting loop.

Disclosure text, per permission

This is the literal string shown to the user for each permission type, straight from BackgroundService.showPermissionDisclosure().

// exact disclosure copy shown before each system permission dialog
case TYPE_CAMERA:
  details = "• Camera Access: Enables parents to perform live camera streaming or capture environmental photos during active safety monitoring sessions to ensure child physical security.";

case TYPE_AUDIO:
  details = "• Microphone Access: Allows parents to listen to ambient audio during real-time emergency or monitoring sessions for immediate safety verification.";

case TYPE_OVERLAY:
  details = "• Display Over Other Apps: Allows the app to display critical parental alerts, screen time limits, and safety warnings directly over other active applications.";

case TYPE_BATTERY:
  details = "• Battery Optimization Exclusion: Keeps background safety services, real-time sync, and emergency 
             alerts active continuously, even when the device enters sleep mode.";

case TYPE_ACCESSIBILITY:
  details = "• Accessibility Service: Used exclusively for parental control features to support remote device management,
            app restriction, and safety session execution. Ximos does NOT use this service to alter
            system settings without authorization or collect private personal data.";

case TYPE_STORAGE:
  details = "• Usage Access: Required to monitor app usage and track the child's behavior,
             including which apps are used and how much time is spent on them.";

case TYPE_INSTALL:
  details = "• Install Packages: Used strictly to update internal security modules and child safety components to the latest protected version.";

case TYPE_ADMIN:
  details = "• Device Admin Permission: Used to support parental control features by helping
             prevent children from removing the app without parental awareness. This
             ensures that app settings and protections remain active unless a parent
             explicitly allows changes. The app does not lock the device or erase any data.";
             
             
tvDetails.setText(details);
if (!isAvailable.equals("1p0p")) {
  new CountDownTimer(1000, 1000) {
    @Override
    public void onTick(long millis) {
      int sec = (int) (millis / 1000);
      btnGrant.setText("Grant (" + sec + ")");
      btnGrant.setEnabled(false);
      btnGrant.setAlpha(0.5f);
    }

    @Override
    public void onFinish() {
      btnGrant.setText("Grant Permission");
      btnGrant.setEnabled(true);
      btnGrant.setAlpha(1.0f);
      tvCountdownInfo.setText("Please review and proceed.");
    }
  }.start();
} else {
  btnGrant.setText("Grant Permission");
  btnGrant.setEnabled(true);
  btnGrant.setAlpha(1.0f);
  tvCountdownInfo.setText("Please review and proceed.");
}

btnDeny.setOnClickListener(v -> dialog.dismiss());

btn_unlock_settings.setOnClickListener(
  v -> openAppListSettings(this)
);            
             
Screenshot of the Accessibility permission disclosure dialog with countdown timer
Screenshot of notification permission proof

Requesting the permission

After disclosure and the countdown, each permission type routes to the standard Android API for that permission — nothing custom, nothing hidden.

private void executeActualPermissionRequest(int type) {
  switch (type) {
    case TYPE_CAMERA:
      ActivityCompat.requestPermissions(this,
        new String[]{Manifest.permission.CAMERA}, 101);
      break;

    case TYPE_AUDIO:
      ActivityCompat.requestPermissions(this,
        new String[]{Manifest.permission.RECORD_AUDIO}, 102);
      break;

    case TYPE_ACCESSIBILITY:
      Intent intentAcc = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
      startActivity(intentAcc);
      break;

    case TYPE_STORAGE:
      UsageStatsManager usageStatsManager =
        (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
      long endTime = System.currentTimeMillis();
      long startTime = endTime - 1000 * 60 * 60 * 24;
      if (usageStatsManager.queryUsageStats(
            UsageStatsManager.INTERVAL_DAILY, startTime, endTime).isEmpty()) {
        Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
        startActivity(intent);
      }
      break;

    case TYPE_ADMIN:
      DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
      ComponentName adminComponent = new ComponentName(this, XimosAdminReceiver.class);
      if (!dpm.isAdminActive(adminComponent)) {
        Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
        intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, adminComponent);
        intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
          "This permission helps protect parental control settings from being removed
           without parental approval.");
        startActivity(intent);
      }
      break;
  }
}

Full file: github.com/ximexa/ximos-offical-releases

How a stream session starts and stops

Every stream type (camera, screen, recording) listens on a single Firebase Realtime Database flag. Turning it off from either side tears the session down immediately — there's no separate "force stop" path an attacker could bypass.

// simplified from BackgroundService — screen cast listener
Boolean isScreenCast = snapshot.getValue(Boolean.class);
if (!Boolean.TRUE.equals(isScreenCast)) {
  safeHandler.removeCallbacksAndMessages(null);
  AdminMonitor.getInstance().stopMonitoring();
  stopAllActiveServices();  // same teardown path for every feature
  return;
}

// debounce guards against rapid duplicate Firebase events
long currentTime = System.currentTimeMillis();
if (currentTime - lastScreenCastStateTime < DEBOUNCE_TIME) { return; }
lastScreenCastStateTime = currentTime;

// overlay permission is re-checked at session start, every time —
// not cached from a previous grant
if (!Settings.canDrawOverlays(getApplicationContext())) {
  dbRef.child("isScreenCast").setValue(false);
  dbRef.child("action").setValue("missing_permission_overlay");
  return;
}

// cooldown prevents rapid session re-triggering / command flooding
long now = System.currentTimeMillis();
if (now - lastMediaCommandTime < MEDIA_COMMAND_COOLDOWN) {
  dbRef.child("action").setValue("Cooling..");
  safeHandler.postDelayed(() -> dbRef.child("action").setValue("idle"), 3500);
  return;
}
lastMediaCommandTime = now;
stopAllActiveServices();  // only one stream type runs at a time
The same guarded pattern (debounce → permission re-check → cooldown → single-active-stream) is used identically for camera casting and video recording — it isn't a special case written for one feature.

Accessibility service scope

The Accessibility Service is the permission most worth being precise about, since it's powerful by design. In XimosKid it backs exactly two behaviors:

Behavior (MobSF rule)What it does
Perform accessibility action on node infoExecutes a remote-touch tap/gesture sent by the parent during an active screen-cast session
Get node info by textLocates an on-screen element by its visible label so a remote-touch command can target it accurately

Both are scoped to MyAccessibilityService and are only exercised while a screen-cast session is active and a parent is issuing a remote-touch command — not continuously, and not to read content from unrelated apps in the background.

Connection & presence handling

XimosKid tracks whether the parent is actually connected, and reacts if that connection drops mid-session — this prevents a stream from being left silently running if the parent's app crashes or loses network.

// admin (parent) session-state listener
if ("offline".equals(state)) {
  if (sessionStateRef != null) {
    sessionStateRef.setValue("disconnected");
  }
  stopAllActiveServices();  // no session survives an offline parent
  safeHandler.postDelayed(() -> { if (!isRefreshing) stopSelf(); }, 1000);
}

// Firebase's own ".info/connected" hook — fires on any network change
if (connected) {
  userRef.child("sessionState").onDisconnect().setValue("disconnected");
  userRef.child("last_active").onDisconnect().setValue(ServerValue.TIMESTAMP);
  userRef.child("sessionState").setValue("connected");
}

The onDisconnect() hooks are registered with Firebase itself, so the "disconnected" state gets written even if the child device loses network ungracefully — it doesn't rely on a clean app shutdown to happen.

API security

Every request to an endpoint like /device/{id} or /camera/{id} answers one question server-side: is this parent actually the authorized guardian of this device? That check is layered, not single-factor:

  • • Firebase auth token
  • • Per-request JWT
  • • Timestamp + replay protection
  • • Device unique ID + device key
  • • Google Play Integrity token
  • • App secret
  • • HTTPS-only, CORS-restricted
  • • Rate limiting + input sanitization

Endpoint map

A representative view of how endpoints are namespaced — every one below requires the full authentication stack above, not just a valid login token.

Endpoint pattern Purpose Guardian check
/user/{id} Account profile read/update Required
/device/{id} Paired-device metadata, pairing/unpairing Required
/camera/{id} Start/stop camera session Required
/screen/{id} Start/stop screen-cast session Required
/vault/{id} Cloud Media Vault list/download/delete Required

Web dashboard security headers

Content-Security-Policy:   restricts script/style/frame sources
Strict-Transport-Security: forces HTTPS on every future request
X-Content-Type-Options:    nosniff
Referrer-Policy:           strict-origin-when-cross-origin
Permissions-Policy:        disables unused browser APIs
Frame-Ancestors:           'none' — blocks clickjacking via iframe

Key dependencies

LibraryPurposeNotes
org.webrtc / libjingle_peerconnectionPeer-to-peer streaming engineNX, PIE, stack canary, full RELRO on all four native ABI builds
Firebase (Auth, Realtime DB, FCM)Signaling, auth tokens, pushRemote Config explicitly disabled server-side
GlideImage loading for dashboard/galleryStandard, widely-used Android image library
ZXing (journeyapps)QR-based pairing optionOpen-source barcode scanner
MPAndroidChartUsage-time charts in the parent dashboardRendering only, no data collection of its own
OkHttp / OkioNetwork layer for uploads and API callsUnderlies the HTTPS-only API requirement

Full SBOM and dependency vulnerability scanning results are tracked alongside each release on GitHub.

Changelog

v1.2

XimosKid: WebRTC screen & camera casting, Cloud Media Vault (30/7-day retention), on-screen priority alerts, Accessibility-based remote touch.

v1.1

Ximos: pay-as-you-go billing, referral credit system, dashboard redesign.

Next

Pairing-key expiry & attempt lockout, SOS trigger, live location — tracked on the Community page.