- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
408 lines
13 KiB
Python
408 lines
13 KiB
Python
"""
|
|
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",
|
|
] |