""" Android os UserManager 组件 — UserManager, UserHandle, UserInfo 等 方法签名完全对齐 Android SDK """ from __future__ import annotations import os import threading import uuid from typing import Any, Dict, List, Optional, Set from .._core import Stub, AndroidOnlyError, _sdcard_root from ..java.lang import RuntimeException IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {}) # ═══════════════════════════════════════════════════════════════ # UserHandle # ═══════════════════════════════════════════════════════════════ class UserHandle(Stub): """UserHandle — 用户句柄""" MY_USER_ID = 0 USER_OWNER = 0 USER_CURRENT = -2 USER_CURRENT_OR_SELF = -3 USER_NULL = -10000 USER_ALL = -1 USER_SYSTEM = 0 USER_SERIAL_NUMBER_SYSTEM = 0 PER_USER_RANGE = 100000 def __init__(self, userId: int = MY_USER_ID): super().__init__() self._userId = userId def getUserId(self) -> int: return self._userId def getAppId(self, uid: int) -> int: return uid % self.PER_USER_RANGE def getUserId(self, uid: int) -> int: return uid // self.PER_USER_RANGE @staticmethod def myUserId() -> int: return 0 @staticmethod def isIsolated(uid: int) -> bool: return False @staticmethod def isApp(uid: int) -> bool: return 10000 <= (uid % 100000) < 20000 @staticmethod def isSameUser(uid1: int, uid2: int) -> bool: return (uid1 // 100000) == (uid2 // 100000) @staticmethod def isSystem(uid: int) -> bool: return uid == 1000 def toString(self) -> str: return f"UserHandle{{{self._userId}}}" def hashCode(self) -> int: return hash(self._userId) & 0x7FFFFFFF def equals(self, other) -> bool: if not isinstance(other, UserHandle): return False return self._userId == other._userId # ═══════════════════════════════════════════════════════════════ # UserInfo # ═══════════════════════════════════════════════════════════════ class UserInfo(Stub): """UserInfo — 用户信息""" FLAG_PRIMARY = 0x00000001 FLAG_ADMIN = 0x00000002 FLAG_GUEST = 0x00000004 FLAG_RESTRICTED = 0x00000008 FLAG_MANAGED_PROFILE = 0x00000010 FLAG_PROFILE = 0x00000020 FLAG_DEMO = 0x00000200 FLAG_SYSTEM = 0x00001000 def __init__(self, id_: int = 0, name: str = "System User", icon_path: str = "", flags: int = FLAG_PRIMARY | FLAG_ADMIN | FLAG_SYSTEM): super().__init__() self.id: int = id_ self.name: str = name self.iconPath: str = icon_path self.flags: int = flags def isPrimary(self) -> bool: return bool(self.flags & self.FLAG_PRIMARY) def isAdmin(self) -> bool: return bool(self.flags & self.FLAG_ADMIN) def isGuest(self) -> bool: return bool(self.flags & self.FLAG_GUEST) def isDemo(self) -> bool: return bool(self.flags & self.FLAG_DEMO) def isManagedProfile(self) -> bool: return bool(self.flags & self.FLAG_MANAGED_PROFILE) def isRestricted(self) -> bool: return bool(self.flags & self.FLAG_RESTRICTED) def isSystemOnly(self) -> bool: return bool(self.flags & self.FLAG_SYSTEM) def isProfile(self) -> bool: return bool(self.flags & self.FLAG_PROFILE) def toString(self) -> str: return f"UserInfo{{id={self.id}, name={self.name}, flags={self.flags}}}" def hashCode(self) -> int: return hash(self.id) & 0x7FFFFFFF def equals(self, other) -> bool: if not isinstance(other, UserInfo): return False return self.id == other.id # ═══════════════════════════════════════════════════════════════ # UserManager # ═══════════════════════════════════════════════════════════════ class UserManager(Stub): """UserManager — 用户管理器""" USER_CREATION_FAILED_NOT_PERMITTED = -1 USER_CREATION_FAILED_NO_MORE_USERS = -2 # DISALLOW_* restrictions DISALLOW_CONFIG_WIFI = "no_config_wifi" DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth" DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks" DISALLOW_CONFIG_TETHERING = "no_config_tethering" DISALLOW_CONFIG_SMS = "no_config_sms" DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials" DISALLOW_CONFIG_VPN = "no_config_vpn" DISALLOW_CONFIG_LOCALE = "no_config_locale" DISALLOW_CONFIG_DATE_TIME = "no_config_date_time" DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness" DISALLOW_FACTORY_RESET = "no_factory_reset" DISALLOW_APPS_CONTROL = "no_control_apps" DISALLOW_CREATE_WINDOWS = "no_create_windows" DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste" DISALLOW_DEBUGGING_FEATURES = "no_debugging_features" DISALLOW_INSTALL_APPS = "no_install_apps" DISALLOW_UNINSTALL_APPS = "no_uninstall_apps" DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts" DISALLOW_OUTGOING_CALLS = "no_outgoing_calls" DISALLOW_REMOVE_USER = "no_remove_user" DISALLOW_SAFE_BOOT = "no_safe_boot" DISALLOW_SET_USER_RESTRICTIONS = "no_set_user_restrictions" DISALLOW_SHARE_LOCATION = "no_share_location" DISALLOW_SMS = "no_sms" DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone" DISALLOW_UNMUTE_DEVICE = "no_unmute_device" DISALLOW_ADJUST_VOLUME = "no_adjust_volume" KEY_RESTRICTIONS_PENDING = "restrictions_pending" PIN_VERIFICATION_FAILURE_INVALID = -3 PIN_VERIFICATION_FAILURE_NOT_SET = -2 PIN_VERIFICATION_SUCCESS = 0 MAX_SUPPORTED_USERS = 4 def __init__(self): super().__init__() self._lock = threading.Lock() self._next_user_id = 10 self._users: Dict[int, UserInfo] = {0: UserInfo(0, "System User")} self._serial_numbers: Dict[int, int] = {0: 0} self._next_serial = 1 self._restrictions: Dict[str, Set[str]] = {} self._quiet_mode: Set[int] = set() # ── User counting ── def getUserCount(self) -> int: with self._lock: return len(self._users) def getUsers(self) -> List[UserInfo]: with self._lock: return list(self._users.values()) def getSystemUser(self) -> UserInfo: return self._users.get(0, UserInfo(0, "System User")) def getForegroundUser(self) -> UserHandle: return UserHandle(0) def getMaxSupportedUsers(self) -> int: return self.MAX_SUPPORTED_USERS def supportsMultipleUsers(self) -> bool: return True # ── Serial numbers ── def getSerialNumberForUser(self, user: UserHandle) -> int: return self._serial_numbers.get(user.getUserId(), -1) def getUserForSerialNumber(self, serialNumber: int) -> Optional[UserHandle]: for uid, sn in self._serial_numbers.items(): if sn == serialNumber: return UserHandle(uid) return None # ── Profiles ── def getUserProfiles(self) -> List[UserInfo]: with self._lock: return list(self._users.values()) def getProfileIds(self, userId: int, enabledOnly: bool = False) -> List[int]: return [0, userId] if enabledOnly else [uid for uid in self._users] def getProfileIdsWithDisabled(self, userId: int) -> List[int]: return self.getProfileIds(userId, enabledOnly=False) def getEnabledProfileIds(self, userId: int) -> List[int]: return self.getProfileIds(userId, enabledOnly=True) def getUserProfileIds(self, userId: int) -> List[int]: return self.getProfileIds(userId) def getProfileParent(self, userId: int) -> Optional[UserHandle]: return None def getProfileParentId(self, userId: int) -> int: return 0 # ── User state ── def isUserRunning(self, user: UserHandle) -> bool: return True def isUserRunningOrStopped(self, user: UserHandle) -> bool: return True def isUserUnlocked(self, user: UserHandle) -> bool: return True def isUserUnlocked(self, userId: int) -> bool: return True def isUserSwitcherEnabled(self) -> bool: return True # ── User type checks ── def isManagedProfile(self, userId: int) -> bool: with self._lock: user = self._users.get(userId) return user.isManagedProfile() if user else False def isManagedProfile(self) -> bool: return False def isSystemUser(self) -> bool: return True def isPrimaryUser(self) -> bool: return True def isDemoUser(self) -> bool: return False def isGuestUser(self) -> bool: return False def isAdminUser(self) -> bool: return True def isRestrictedProfile(self) -> bool: return False def isLinkedUser(self) -> bool: return False def isUserOfType(self, userHandle: UserHandle, userType: str) -> bool: return userHandle.getUserId() == 0 # ── Restrictions ── def hasUserRestriction(self, restrictionKey: str, userHandle: UserHandle) -> bool: uid = userHandle.getUserId() with self._lock: user_restrictions = self._restrictions.get(str(uid), set()) return restrictionKey in user_restrictions def getUserRestrictions(self, userHandle: UserHandle) -> Dict[str, bool]: uid = userHandle.getUserId() with self._lock: user_restrictions = self._restrictions.get(str(uid), set()) return {r: True for r in user_restrictions} def setUserRestriction(self, restrictionKey: str, value: bool, userHandle: UserHandle): uid = str(userHandle.getUserId()) with self._lock: if uid not in self._restrictions: self._restrictions[uid] = set() if value: self._restrictions[uid].add(restrictionKey) else: self._restrictions[uid].discard(restrictionKey) # ── Quiet mode ── def isQuietModeEnabled(self, userHandle: UserHandle) -> bool: return userHandle.getUserId() in self._quiet_mode def setQuietModeEnabled(self, userHandle: UserHandle, enable: bool) -> bool: uid = userHandle.getUserId() with self._lock: if enable: self._quiet_mode.add(uid) else: self._quiet_mode.discard(uid) return True # ── User switching ── def canSwitchUsers(self) -> bool: return True def switchUser(self, userHandle: UserHandle) -> bool: return True def removeUser(self, userId: int) -> bool: with self._lock: if userId in self._users and userId != 0: del self._users[userId] self._serial_numbers.pop(userId, None) return True return False # ── User creation ── def createUser(self, name: str, flags: int = 0) -> UserInfo: with self._lock: uid = self._next_user_id self._next_user_id += 1 user = UserInfo(uid, name, flags=flags) self._users[uid] = user self._serial_numbers[uid] = self._next_serial self._next_serial += 1 return user def createProfile(self, name: str, profileFlags: int, userId: int) -> UserInfo: return self.createUser(name, profileFlags) def createGuest(self, context: Any = None) -> UserInfo: return self.createUser("Guest", UserInfo.FLAG_GUEST) # ── User name ── def setUserName(self, userId: int, name: str): with self._lock: if userId in self._users: self._users[userId].name = name def getUserName(self) -> Optional[str]: return "System User" # ── User info ── def getUserInfo(self, userId: int) -> Optional[UserInfo]: with self._lock: return self._users.get(userId) def toString(self) -> str: return f"UserManager@{hex(id(self))}" # ═══════════════════════════════════════════════════════════════ # __all__ # ═══════════════════════════════════════════════════════════════ __all__ = [ "UserManager", "UserHandle", "UserInfo", ]