import abilityAccessCtrl from '@ohos.abilityAccessCtrl' import { Permissions, PermissionRequestResult as AtManagerPermissionResult } from '@ohos.abilityAccessCtrl' import { BusinessError } from '@ohos.base' import common from '@ohos.app.ability.common' import Want from '@ohos.app.ability.Want' import access from '@ohos.bluetooth.access' import bundleManager from '@ohos.bundle.bundleManager' import { BluetoothDemoInfo, CheckPermission, CheckPermissionOptions, CheckPermissions, CheckPermissionsOptions, CheckPermissionsResult, CheckPermissionsSync, CheckPermissionSync, GetSupportedPermissionsResult, GetSupportedPermissionsSync, GetBluetoothDemoInfoSync, OpenAppSettings, OpenAppSettingsOptions, PermissionCheckResult, PermissionGrantResult, PermissionKey, PermissionStatus, RequestPermission, RequestPermissionOptions, RequestPermissions, RequestPermissionsOptions, RequestPermissionsResult, } from '../interface.uts' import { PermissionFailImpl } from '../unierror' const SUPPORTED_PERMISSIONS : PermissionKey[] = [ 'camera', 'photoLibrary', 'storage', 'readStorage', 'location', 'coarseLocation', 'microphone', 'contacts', 'writeContacts', 'bluetooth', ] /** 鸿蒙无对应系统能力的权限(Android 专属等) */ const HARMONY_UNSUPPORTED : PermissionKey[] = [ 'phone', 'phoneState', 'sms', 'readSms', 'receiveSms', 'overlay', 'writeSettings', ] function createCheckResult(permission : PermissionKey, status : PermissionStatus) : PermissionCheckResult { return { permission: permission, status: status, granted: status == 'granted', } } function createGrantResult(permission : PermissionKey, status : PermissionStatus) : PermissionGrantResult { return { permission: permission, status: status, granted: status == 'granted', } } /** 需在 module.json5 声明且 ACL 签名的权限 */ const HARMONY_ACL_PERMISSION_KEYS : PermissionKey[] = [ 'photoLibrary', 'readStorage', 'storage', 'contacts', 'writeContacts', ] function isHarmonyAclPermission(permission : PermissionKey) : boolean { for (let i = 0; i < HARMONY_ACL_PERMISSION_KEYS.length; i++) { if (HARMONY_ACL_PERMISSION_KEYS[i] == permission) { return true } } return false } function isHarmonyPermissionDeclared(harmonyPermission : Permissions) : boolean { try { const bundleInfo = bundleManager.getBundleInfoForSelfSync( bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION, ) const declared = bundleInfo.reqPermissionDetails for (let i = 0; i < declared.length; i++) { const item = declared[i] if (item.name == harmonyPermission) { return true } } return false } catch (ignored) { return false } } function createAclUndeclaredMessage(permission : PermissionKey) : string { if (permission == 'photoLibrary' || permission == 'readStorage' || permission == 'storage') { return '当前包未声明相册/媒体权限,系统设置无对应开关。选图请用系统相册选择器;完整权限需 module.full.json5 + ACL' } return '当前包未声明该权限,系统设置无对应开关。请使用 module.full.json5 并配置 ACL 后重签安装' } function isHarmonyAclUndeclared(permission : PermissionKey) : boolean { if (!isHarmonyAclPermission(permission)) { return false } const harmonyPermission = resolveHarmonyPermission(permission) if (harmonyPermission == null) { return false } return !isHarmonyPermissionDeclared(harmonyPermission) } function isHarmonyUnsupported(permission : PermissionKey) : boolean { for (let i = 0; i < HARMONY_UNSUPPORTED.length; i++) { if (HARMONY_UNSUPPORTED[i] == permission) { return true } } return false } function resolveHarmonyPermission(permission : PermissionKey) : Permissions | null { switch (permission) { case 'camera': return 'ohos.permission.CAMERA' case 'photoLibrary': case 'readStorage': return 'ohos.permission.READ_IMAGEVIDEO' case 'storage': return 'ohos.permission.WRITE_IMAGEVIDEO' case 'location': return 'ohos.permission.LOCATION' case 'coarseLocation': return 'ohos.permission.APPROXIMATELY_LOCATION' case 'microphone': return 'ohos.permission.MICROPHONE' case 'contacts': return 'ohos.permission.READ_CONTACTS' case 'writeContacts': return 'ohos.permission.WRITE_CONTACTS' case 'bluetooth': return 'ohos.permission.ACCESS_BLUETOOTH' default: return null } } function getAbilityContext() : common.UIAbilityContext | null { try { return getContext() as common.UIAbilityContext } catch (ignored) { return null } } function checkHarmonyPermissionStatus(permission : PermissionKey) : PermissionStatus { if (isHarmonyUnsupported(permission)) { return 'unsupported' } const harmonyPermission = resolveHarmonyPermission(permission) if (harmonyPermission == null) { return 'unsupported' } if (isHarmonyAclUndeclared(permission)) { return 'restricted' } const context = getAbilityContext() if (context == null) { return 'denied' } const atManager = abilityAccessCtrl.createAtManager() const tokenId = context.applicationInfo.accessTokenId const status = atManager.checkAccessTokenSync(tokenId, harmonyPermission) if (status == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { return 'granted' } return 'notDetermined' } function succeedCheckPermission(options : CheckPermissionOptions, res : PermissionCheckResult) { const successCallback = options.success if (successCallback != null) { successCallback(res) } const completeCallback = options.complete if (completeCallback != null) { completeCallback(res) } } function succeedCheckPermissions(options : CheckPermissionsOptions, res : CheckPermissionsResult) { const successCallback = options.success if (successCallback != null) { successCallback(res) } const completeCallback = options.complete if (completeCallback != null) { completeCallback(res) } } function succeedRequestPermission(options : RequestPermissionOptions, res : PermissionGrantResult) { const successCallback = options.success if (successCallback != null) { successCallback(res) } const completeCallback = options.complete if (completeCallback != null) { completeCallback(res) } } function succeedRequestPermissions(options : RequestPermissionsOptions, res : RequestPermissionsResult) { const successCallback = options.success if (successCallback != null) { successCallback(res) } const completeCallback = options.complete if (completeCallback != null) { completeCallback(res) } } function failRequestPermission(options : RequestPermissionOptions, err : PermissionFailImpl) { const failCallback = options.fail if (failCallback != null) { failCallback(err) } const completeCallback = options.complete if (completeCallback != null) { completeCallback(err) } } function failRequestPermissions(options : RequestPermissionsOptions, err : PermissionFailImpl) { const failCallback = options.fail if (failCallback != null) { failCallback(err) } const completeCallback = options.complete if (completeCallback != null) { completeCallback(err) } } function failOpenAppSettings(options : OpenAppSettingsOptions, err : PermissionFailImpl) { const failCallback = options.fail if (failCallback != null) { failCallback(err) } const completeCallback = options.complete if (completeCallback != null) { completeCallback(err) } } function succeedOpenAppSettings(options : OpenAppSettingsOptions, res : PermissionCheckResult) { const successCallback = options.success if (successCallback != null) { successCallback(res) } const completeCallback = options.complete if (completeCallback != null) { completeCallback(res) } } export const checkPermissionSync : CheckPermissionSync = function (permission : PermissionKey) : PermissionCheckResult { return createCheckResult(permission, checkHarmonyPermissionStatus(permission)) } export const checkPermissionsSync : CheckPermissionsSync = function (permissions : PermissionKey[]) : CheckPermissionsResult { const results : PermissionCheckResult[] = [] let allGranted = true for (let i = 0; i < permissions.length; i++) { const item = checkPermissionSync(permissions[i]) results.push(item) if (!item.granted) { allGranted = false } } return { results: results, allGranted: allGranted, } } export const checkPermission : CheckPermission = function (options : CheckPermissionOptions) { succeedCheckPermission(options, checkPermissionSync(options.permission)) } export const checkPermissions : CheckPermissions = function (options : CheckPermissionsOptions) { succeedCheckPermissions(options, checkPermissionsSync(options.permissions)) } export const requestPermission : RequestPermission = function (options : RequestPermissionOptions) { if (isHarmonyUnsupported(options.permission)) { failRequestPermission(options, new PermissionFailImpl(9020003)) return } if (isHarmonyAclUndeclared(options.permission)) { failRequestPermission(options, new PermissionFailImpl(9020003, createAclUndeclaredMessage(options.permission))) return } const currentStatus = checkHarmonyPermissionStatus(options.permission) if (currentStatus == 'granted') { succeedRequestPermission(options, createGrantResult(options.permission, 'granted')) return } const harmonyPermission = resolveHarmonyPermission(options.permission) if (harmonyPermission == null) { failRequestPermission(options, new PermissionFailImpl(9020003)) return } const context = getAbilityContext() if (context == null) { failRequestPermission(options, new PermissionFailImpl(9020006, 'UIAbilityContext 不可用')) return } const atManager = abilityAccessCtrl.createAtManager() const permissionList : Array = [harmonyPermission] atManager.requestPermissionsFromUser(context, permissionList, (err : BusinessError, result : AtManagerPermissionResult) => { if (err != null) { succeedRequestPermission(options, createGrantResult(options.permission, 'denied')) return } if (result.authResults.length > 0 && result.authResults[0] == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { succeedRequestPermission(options, createGrantResult(options.permission, 'granted')) return } succeedRequestPermission(options, createGrantResult(options.permission, 'denied')) }) } export const requestPermissions : RequestPermissions = function (options : RequestPermissionsOptions) { const permissions = options.permissions if (permissions.length == 0) { const emptyResult : RequestPermissionsResult = { results: [], allGranted: true, } succeedRequestPermissions(options, emptyResult) return } const context = getAbilityContext() if (context == null) { failRequestPermissions(options, new PermissionFailImpl(9020006, 'UIAbilityContext 不可用')) return } const harmonyPermissions : Array = [] const permissionKeys : PermissionKey[] = [] for (let i = 0; i < permissions.length; i++) { const key = permissions[i] if (isHarmonyUnsupported(key)) { continue } const harmonyPermission = resolveHarmonyPermission(key) if (harmonyPermission != null) { harmonyPermissions.push(harmonyPermission) permissionKeys.push(key) } } if (harmonyPermissions.length == 0) { failRequestPermissions(options, new PermissionFailImpl(9020003)) return } const atManager = abilityAccessCtrl.createAtManager() atManager.requestPermissionsFromUser(context, harmonyPermissions, (err : BusinessError, result : AtManagerPermissionResult) => { const collectedResults : PermissionGrantResult[] = [] let allGranted = true if (err != null) { for (let i = 0; i < permissionKeys.length; i++) { collectedResults.push(createGrantResult(permissionKeys[i], 'denied')) } allGranted = false } else { for (let i = 0; i < permissionKeys.length; i++) { const granted = i < result.authResults.length && result.authResults[i] == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED const status : PermissionStatus = granted ? 'granted' : 'denied' collectedResults.push(createGrantResult(permissionKeys[i], status)) if (!granted) { allGranted = false } } } const finalResult : RequestPermissionsResult = { results: collectedResults, allGranted: allGranted, } succeedRequestPermissions(options, finalResult) }) } export const openAppSettings : OpenAppSettings = function (options : OpenAppSettingsOptions) { const context = getAbilityContext() if (context == null) { failOpenAppSettings(options, new PermissionFailImpl(9020004, 'UIAbilityContext 不可用')) return } const wantInfo : Want = { bundleName: 'com.huawei.hmos.settings', abilityName: 'com.huawei.hmos.settings.MainAbility', uri: 'application_info_entry', parameters: { pushParams: context.abilityInfo.bundleName, }, } context.startAbility(wantInfo).then(() => { const resultPermission = options.permission != null ? options.permission! : 'camera' succeedOpenAppSettings(options, createCheckResult(resultPermission, 'granted')) }).catch((_err : BusinessError) => { failOpenAppSettings(options, new PermissionFailImpl(9020004)) }) } export const getSupportedPermissionsSync : GetSupportedPermissionsSync = function () : GetSupportedPermissionsResult { return { permissions: SUPPORTED_PERMISSIONS, } } function mapHarmonyBluetoothState(state : access.BluetoothState) : string { switch (state) { case access.BluetoothState.STATE_OFF: return '已关闭' case access.BluetoothState.STATE_TURNING_ON: return '正在打开' case access.BluetoothState.STATE_ON: return '已开启' case access.BluetoothState.STATE_TURNING_OFF: return '正在关闭' case access.BluetoothState.STATE_BLE_TURNING_ON: return 'BLE 正在打开' case access.BluetoothState.STATE_BLE_ON: return 'BLE 已开启' case access.BluetoothState.STATE_BLE_TURNING_OFF: return 'BLE 正在关闭' default: return '未知' } } function isHarmonyBluetoothEnabled(state : access.BluetoothState) : boolean { return state == access.BluetoothState.STATE_ON || state == access.BluetoothState.STATE_BLE_ON } export const getBluetoothDemoInfoSync : GetBluetoothDemoInfoSync = function () : BluetoothDemoInfo { try { const state = access.getState() return { available: true, enabled: isHarmonyBluetoothEnabled(state), stateText: mapHarmonyBluetoothState(state), stateCode: state as number, } } catch (err) { let message = '读取蓝牙状态失败' if (err != null && typeof err === 'object') { const errObj = err as BusinessError if (errObj.message != null && errObj.message.length > 0) { message = errObj.message } } return { available: false, enabled: false, stateText: message, stateCode: -1, } } }