| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- import Build from 'android.os.Build'
- import Intent from 'android.content.Intent'
- import Settings from 'android.provider.Settings'
- import Uri from 'android.net.Uri'
- import ContextCompat from 'androidx.core.content.ContextCompat'
- import ActivityCompat from 'androidx.core.app.ActivityCompat'
- import PackageManager from 'android.content.pm.PackageManager'
- import BluetoothAdapter from 'android.bluetooth.BluetoothAdapter'
- import { UTSAndroid } from 'io.dcloud.uts'
- import {
- BluetoothDemoInfo,
- CheckPermission,
- CheckPermissionOptions,
- CheckPermissions,
- CheckPermissionsOptions,
- CheckPermissionsResult,
- CheckPermissionsSync,
- CheckPermissionSync,
- GetSupportedPermissionsResult,
- GetSupportedPermissionsSync,
- GetBluetoothDemoInfoSync,
- OpenAppSettings,
- OpenAppSettingsOptions,
- PermissionCheckResult,
- PermissionFail,
- PermissionKey,
- PermissionGrantResult,
- PermissionStatus,
- RequestPermission,
- RequestPermissionOptions,
- RequestPermissions,
- RequestPermissionsOptions,
- RequestPermissionsResult,
- } from '../interface.uts'
- import { PermissionFailImpl } from '../unierror'
- const ANDROID_API_TIRAMISU : Int = 33
- const ANDROID_API_S : Int = 31
- function getAppTargetSdkVersion() : Int {
- const activity = UTSAndroid.getUniActivity()
- if (activity == null) {
- return 0
- }
- return activity.getApplicationInfo().targetSdkVersion
- }
- /** 设备 API 与宿主 targetSdkVersion 均满足时才使用 READ_MEDIA_*(UTS 运行时强校验 targetSdk) */
- function shouldUseReadMediaPermissions() : boolean {
- if (Build.VERSION.SDK_INT < ANDROID_API_TIRAMISU) {
- return false
- }
- return getAppTargetSdkVersion() >= ANDROID_API_TIRAMISU
- }
- /** 设备 API 与宿主 targetSdkVersion 均满足时才使用 BLUETOOTH_CONNECT / BLUETOOTH_SCAN */
- function shouldUseBluetoothRuntimePermissions() : boolean {
- if (Build.VERSION.SDK_INT < ANDROID_API_S) {
- return false
- }
- return getAppTargetSdkVersion() >= ANDROID_API_S
- }
- const SUPPORTED_PERMISSIONS : PermissionKey[] = [
- 'camera',
- 'photoLibrary',
- 'storage',
- 'readStorage',
- 'location',
- 'coarseLocation',
- 'microphone',
- 'contacts',
- 'writeContacts',
- 'bluetooth',
- 'phone',
- 'phoneState',
- 'sms',
- 'readSms',
- 'receiveSms',
- 'overlay',
- 'writeSettings',
- ]
- function createCheckResult(permission : PermissionKey, status : PermissionStatus) : PermissionCheckResult {
- return {
- permission: permission,
- status: status,
- granted: status == 'granted',
- }
- }
- function createRequestResult(permission : PermissionKey, status : PermissionStatus) : PermissionGrantResult {
- return {
- permission: permission,
- status: status,
- granted: status == 'granted',
- }
- }
- function resolveAndroidPermissions(permission : PermissionKey) : string[] | null {
- switch (permission) {
- case 'camera':
- return ['android.permission.CAMERA']
- case 'photoLibrary':
- if (shouldUseReadMediaPermissions()) {
- return ['android.permission.READ_MEDIA_IMAGES']
- }
- return ['android.permission.READ_EXTERNAL_STORAGE']
- case 'storage':
- if (shouldUseReadMediaPermissions()) {
- return ['android.permission.READ_MEDIA_IMAGES', 'android.permission.READ_MEDIA_VIDEO']
- }
- return ['android.permission.WRITE_EXTERNAL_STORAGE', 'android.permission.READ_EXTERNAL_STORAGE']
- case 'readStorage':
- if (shouldUseReadMediaPermissions()) {
- return ['android.permission.READ_MEDIA_IMAGES', 'android.permission.READ_MEDIA_VIDEO']
- }
- return ['android.permission.READ_EXTERNAL_STORAGE']
- case 'location':
- return ['android.permission.ACCESS_FINE_LOCATION']
- case 'coarseLocation':
- return ['android.permission.ACCESS_COARSE_LOCATION']
- case 'microphone':
- return ['android.permission.RECORD_AUDIO']
- case 'contacts':
- return ['android.permission.READ_CONTACTS']
- case 'writeContacts':
- return ['android.permission.WRITE_CONTACTS']
- case 'bluetooth':
- if (shouldUseBluetoothRuntimePermissions()) {
- return ['android.permission.BLUETOOTH_CONNECT', 'android.permission.BLUETOOTH_SCAN']
- }
- return ['android.permission.BLUETOOTH', 'android.permission.BLUETOOTH_ADMIN']
- case 'phone':
- return ['android.permission.CALL_PHONE']
- case 'phoneState':
- return ['android.permission.READ_PHONE_STATE']
- case 'sms':
- return ['android.permission.SEND_SMS']
- case 'readSms':
- return ['android.permission.READ_SMS']
- case 'receiveSms':
- return ['android.permission.RECEIVE_SMS']
- case 'overlay':
- case 'writeSettings':
- return []
- default:
- return null
- }
- }
- function isPermissionGranted(permission : PermissionKey) : boolean {
- const activity = UTSAndroid.getUniActivity()
- if (activity == null) {
- return false
- }
- if (permission == 'overlay') {
- return Settings.canDrawOverlays(activity)
- }
- if (permission == 'writeSettings') {
- return Settings.System.canWrite(activity)
- }
- const androidPermissions = resolveAndroidPermissions(permission)
- if (androidPermissions == null) {
- return false
- }
- if (androidPermissions.length == 0) {
- return false
- }
- return UTSAndroid.checkSystemPermissionGranted(activity, androidPermissions)
- }
- function resolvePermissionStatus(permission : PermissionKey) : PermissionStatus {
- const androidPermissions = resolveAndroidPermissions(permission)
- if (androidPermissions == null) {
- return 'unsupported'
- }
- if (permission == 'overlay' || permission == 'writeSettings') {
- return isPermissionGranted(permission) ? 'granted' : 'notDetermined'
- }
- const activity = UTSAndroid.getUniActivity()
- if (activity == null) {
- return 'denied'
- }
- let allGranted = true
- let hasDenied = false
- for (let i = 0; i < androidPermissions.length; i++) {
- const androidPermission = androidPermissions[i]
- const granted = ContextCompat.checkSelfPermission(activity, androidPermission) == PackageManager.PERMISSION_GRANTED
- if (granted) {
- continue
- }
- allGranted = false
- if (ActivityCompat.shouldShowRequestPermissionRationale(activity, androidPermission)) {
- hasDenied = true
- }
- }
- if (allGranted) {
- return 'granted'
- }
- if (hasDenied) {
- return 'denied'
- }
- 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 succeedOpenAppSettings(options : OpenAppSettingsOptions, res : PermissionCheckResult) {
- const successCallback = options.success
- if (successCallback != null) {
- successCallback(res)
- }
- const completeCallback = options.complete
- if (completeCallback != null) {
- completeCallback(res)
- }
- }
- function failRequestPermission(options : RequestPermissionOptions, err : PermissionFail) {
- const failCallback = options.fail
- if (failCallback != null) {
- failCallback(err)
- }
- const completeCallback = options.complete
- if (completeCallback != null) {
- completeCallback(err)
- }
- }
- function failRequestPermissions(options : RequestPermissionsOptions, err : PermissionFail) {
- const failCallback = options.fail
- if (failCallback != null) {
- failCallback(err)
- }
- const completeCallback = options.complete
- if (completeCallback != null) {
- completeCallback(err)
- }
- }
- function failOpenAppSettings(options : OpenAppSettingsOptions, err : PermissionFail) {
- const failCallback = options.fail
- if (failCallback != null) {
- failCallback(err)
- }
- const completeCallback = options.complete
- if (completeCallback != null) {
- completeCallback(err)
- }
- }
- function requestOverlayPermission(options : RequestPermissionOptions) {
- const activity = UTSAndroid.getUniActivity()
- if (activity == null) {
- failRequestPermission(options, new PermissionFailImpl(9020006, 'Activity 不可用'))
- return
- }
- if (Settings.canDrawOverlays(activity)) {
- succeedRequestPermission(options, createRequestResult(options.permission, 'granted'))
- return
- }
- const intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
- intent.setData(Uri.parse('package:' + activity.getPackageName()))
- activity.startActivity(intent)
- succeedRequestPermission(options, createRequestResult(options.permission, 'notDetermined'))
- }
- function requestWriteSettingsPermission(options : RequestPermissionOptions) {
- const activity = UTSAndroid.getUniActivity()
- if (activity == null) {
- failRequestPermission(options, new PermissionFailImpl(9020006, 'Activity 不可用'))
- return
- }
- if (Settings.System.canWrite(activity)) {
- succeedRequestPermission(options, createRequestResult(options.permission, 'granted'))
- return
- }
- const intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
- intent.setData(Uri.parse('package:' + activity.getPackageName()))
- activity.startActivity(intent)
- succeedRequestPermission(options, createRequestResult(options.permission, 'notDetermined'))
- }
- function requestRuntimePermission(options : RequestPermissionOptions) {
- const activity = UTSAndroid.getUniActivity()
- const androidPermissions = resolveAndroidPermissions(options.permission)
- if (activity == null) {
- failRequestPermission(options, new PermissionFailImpl(9020006, 'Activity 不可用'))
- return
- }
- if (androidPermissions == null) {
- failRequestPermission(options, new PermissionFailImpl(9020003))
- return
- }
- if (androidPermissions.length == 0) {
- failRequestPermission(options, new PermissionFailImpl(9020003))
- return
- }
- if (UTSAndroid.checkSystemPermissionGranted(activity, androidPermissions)) {
- succeedRequestPermission(options, createRequestResult(options.permission, 'granted'))
- return
- }
- try {
- UTSAndroid.requestSystemPermission(
- activity,
- androidPermissions,
- (allGranted : boolean, _ : string[]) => {
- if (allGranted) {
- succeedRequestPermission(options, createRequestResult(options.permission, 'granted'))
- return
- }
- succeedRequestPermission(options, createRequestResult(options.permission, 'denied'))
- },
- (_ : boolean, _grantedList : string[]) => {
- succeedRequestPermission(options, createRequestResult(options.permission, 'denied'))
- },
- )
- } catch (ignored) {
- failRequestPermission(options, new PermissionFailImpl(9020006, '权限申请失败,请确认 manifest 已声明对应权限且 targetSdkVersion 满足要求'))
- }
- }
- export const checkPermissionSync : CheckPermissionSync = function (permission : PermissionKey) : PermissionCheckResult {
- const status = resolvePermissionStatus(permission)
- return createCheckResult(permission, status)
- }
- 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) {
- const result = checkPermissionSync(options.permission)
- succeedCheckPermission(options, result)
- }
- export const checkPermissions : CheckPermissions = function (options : CheckPermissionsOptions) {
- const result = checkPermissionsSync(options.permissions)
- succeedCheckPermissions(options, result)
- }
- export const requestPermission : RequestPermission = function (options : RequestPermissionOptions) {
- if (options.permission == 'overlay') {
- requestOverlayPermission(options)
- return
- }
- if (options.permission == 'writeSettings') {
- requestWriteSettingsPermission(options)
- return
- }
- requestRuntimePermission(options)
- }
- 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
- }
- let currentIndex = 0
- const collectedResults : PermissionGrantResult[] = []
- function requestNext() {
- if (currentIndex >= permissions.length) {
- let allGranted = true
- for (let i = 0; i < collectedResults.length; i++) {
- if (!collectedResults[i].granted) {
- allGranted = false
- break
- }
- }
- const finalResult : RequestPermissionsResult = {
- results: collectedResults,
- allGranted: allGranted,
- }
- succeedRequestPermissions(options, finalResult)
- return
- }
- const permission = permissions[currentIndex]
- currentIndex += 1
- requestPermission({
- permission: permission,
- success: (res : PermissionGrantResult) => {
- collectedResults.push(res)
- requestNext()
- },
- fail: (err : PermissionFail) => {
- collectedResults.push(createRequestResult(permission, 'denied'))
- failRequestPermissions(options, err)
- },
- })
- }
- requestNext()
- }
- export const openAppSettings : OpenAppSettings = function (options : OpenAppSettingsOptions) {
- const activity = UTSAndroid.getUniActivity()
- if (activity == null) {
- failOpenAppSettings(options, new PermissionFailImpl(9020004, 'Activity 不可用'))
- return
- }
- try {
- const permission = options.permission
- let intent : Intent
- if (permission == 'overlay') {
- intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
- intent.setData(Uri.parse('package:' + activity.getPackageName()))
- } else if (permission == 'writeSettings') {
- intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
- intent.setData(Uri.parse('package:' + activity.getPackageName()))
- } else {
- intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
- intent.setData(Uri.parse('package:' + activity.getPackageName()))
- }
- activity.startActivity(intent)
- const resultPermission = permission != null ? permission : 'camera'
- succeedOpenAppSettings(options, createCheckResult(resultPermission, 'granted'))
- } catch (ignored) {
- failOpenAppSettings(options, new PermissionFailImpl(9020004))
- }
- }
- export const getSupportedPermissionsSync : GetSupportedPermissionsSync = function () : GetSupportedPermissionsResult {
- return {
- permissions: SUPPORTED_PERMISSIONS,
- }
- }
- function mapAndroidBluetoothState(state : Int) : string {
- switch (state) {
- case BluetoothAdapter.STATE_OFF:
- return '已关闭'
- case BluetoothAdapter.STATE_TURNING_ON:
- return '正在打开'
- case BluetoothAdapter.STATE_ON:
- return '已开启'
- case BluetoothAdapter.STATE_TURNING_OFF:
- return '正在关闭'
- default:
- return '未知'
- }
- }
- export const getBluetoothDemoInfoSync : GetBluetoothDemoInfoSync = function () : BluetoothDemoInfo {
- const adapter = BluetoothAdapter.getDefaultAdapter()
- if (adapter == null) {
- return {
- available: false,
- enabled: false,
- stateText: '设备不支持蓝牙',
- stateCode: -1,
- }
- }
- const state = adapter.getState()
- return {
- available: true,
- enabled: state == BluetoothAdapter.STATE_ON,
- stateText: mapAndroidBluetoothState(state),
- stateCode: state,
- }
- }
|