mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 20:47:03 +01:00
setApplicationHidden drops a package from the default PackageManager enumeration even though it stays installed=true, so a sweep querying with flags 0 could never see anything it had already hidden. That made packagesToShow permanently empty: measured on device, a pass following one that hid three apps reported "hid 0, restored 0" and left them hidden with no way back. Query with MATCH_UNINSTALLED_PACKAGES instead. Hiding the enforcer itself is the other unrecoverable case, since it takes the escape hatch and the trigger with it. The exporter now injects com.kuhy.focus_owner into both the day and night allowlists so the decision layer cannot propose it, and the runner keeps its point-of-use skip to cover a policy asset rendered before this fix or hand-edited. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YQLwdquDCNmWtvgi3Lk72J
71 lines
2.8 KiB
Python
71 lines
2.8 KiB
Python
"""Render a :class:`FocusPolicy` into a backend-neutral JSON document.
|
|
|
|
The Device Owner app is written in Kotlin and cannot read ``config.sh`` or
|
|
import this package. It reads this JSON instead, so both enforcement backends
|
|
stay driven by one policy definition.
|
|
|
|
Sorted keys and sorted lists keep the output stable, so committing a rendered
|
|
policy produces a meaningful diff when the policy actually changes rather than
|
|
noise from set iteration order.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
if TYPE_CHECKING:
|
|
from python_pkg.focus_policy.model import FocusPolicy
|
|
|
|
SCHEMA_VERSION = 1
|
|
|
|
# The enforcing app itself, which must never appear in the hide set. Hiding it
|
|
# removes both the escape hatch and the control that triggers the next pass,
|
|
# leaving no way back short of a factory reset. The Kotlin runner does check
|
|
# this at the point of use, but that check is the *only* protection unless the
|
|
# package is also allowed here -- so it is injected into the exported allowlists
|
|
# rather than left to a hand-edit of the rendered asset.
|
|
ENFORCER_PACKAGE = "com.kuhy.focus_owner"
|
|
|
|
|
|
def policy_to_dict(policy: FocusPolicy) -> dict[str, Any]:
|
|
"""Return a JSON-serialisable representation of ``policy``."""
|
|
curfew: dict[str, str] | None = None
|
|
if policy.curfew is not None:
|
|
curfew = {
|
|
"start": policy.curfew.start.strftime("%H:%M"),
|
|
"end": policy.curfew.end.strftime("%H:%M"),
|
|
}
|
|
|
|
return {
|
|
"schema_version": SCHEMA_VERSION,
|
|
"home": {
|
|
"latitude": policy.home.latitude,
|
|
"longitude": policy.home.longitude,
|
|
"radius_m": policy.home.radius_m,
|
|
"hysteresis_m": policy.home.hysteresis_m,
|
|
},
|
|
"curfew": curfew,
|
|
"launcher_package": policy.launcher_package,
|
|
"allowed_packages": sorted({*policy.allowed_packages, ENFORCER_PACKAGE}),
|
|
"night_allowed_packages": sorted(
|
|
{*policy.night_allowed_packages, ENFORCER_PACKAGE},
|
|
),
|
|
"never_disable_prefixes": sorted(policy.never_disable_prefixes),
|
|
"workout_unblock_domains": sorted(policy.workout_unblock_domains),
|
|
"browser_packages": sorted(policy.browser_packages),
|
|
}
|
|
|
|
|
|
def policy_to_json(policy: FocusPolicy, *, redact_home: bool = False) -> str:
|
|
"""Return ``policy`` as pretty-printed JSON.
|
|
|
|
``redact_home`` blanks the coordinates so a rendered policy can be attached
|
|
to a bug report or committed as a fixture without disclosing where the user
|
|
lives. The radius and hysteresis are kept, since they carry no location.
|
|
"""
|
|
payload = policy_to_dict(policy)
|
|
if redact_home:
|
|
payload["home"] = dict(payload["home"], latitude=None, longitude=None)
|
|
return json.dumps(payload, indent=2, sort_keys=True, ensure_ascii=False)
|