diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js new file mode 100644 index 00000000000000..1c018ed6966996 --- /dev/null +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -0,0 +1,57 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export type PermissionStatus = 'granted' | 'denied' | 'never_ask_again'; +export type PermissionType = + | 'android.permission.READ_CALENDAR' + | 'android.permission.WRITE_CALENDAR' + | 'android.permission.CAMERA' + | 'android.permission.READ_CONTACTS' + | 'android.permission.WRITE_CONTACTS' + | 'android.permission.GET_ACCOUNTS' + | 'android.permission.ACCESS_FINE_LOCATION' + | 'android.permission.ACCESS_COARSE_LOCATION' + | 'android.permission.RECORD_AUDIO' + | 'android.permission.READ_PHONE_STATE' + | 'android.permission.CALL_PHONE' + | 'android.permission.READ_CALL_LOG' + | 'android.permission.WRITE_CALL_LOG' + | 'com.android.voicemail.permission.ADD_VOICEMAIL' + | 'android.permission.USE_SIP' + | 'android.permission.PROCESS_OUTGOING_CALLS' + | 'android.permission.BODY_SENSORS' + | 'android.permission.SEND_SMS' + | 'android.permission.RECEIVE_SMS' + | 'android.permission.READ_SMS' + | 'android.permission.RECEIVE_WAP_PUSH' + | 'android.permission.RECEIVE_MMS' + | 'android.permission.READ_EXTERNAL_STORAGE' + | 'android.permission.WRITE_EXTERNAL_STORAGE'; + +export interface Spec extends TurboModule { + +checkPermission: (permission: PermissionType) => Promise; + + +requestPermission: (permission: PermissionType) => Promise; + + +shouldShowRequestPermissionRationale: ( + permission: string, + ) => Promise; + + +requestMultiplePermissions: ( + permissions: Array, + ) => Promise<{[permission: PermissionType]: PermissionStatus}>; +} + +export default TurboModuleRegistry.getEnforcing('PermissionsAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index ae35e07cac6073..789168b15c385e 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -11,6 +11,13 @@ 'use strict'; const NativeModules = require('../BatchedBridge/NativeModules'); +const Platform = require('../Utilities/Platform'); +import NativePermissionsAndroid from './NativePermissionsAndroid'; + +import type { + PermissionStatus, + PermissionType, +} from './NativePermissionsAndroid'; export type Rationale = { title: string, @@ -20,7 +27,39 @@ export type Rationale = { buttonNeutral?: string, }; -type PermissionStatus = 'granted' | 'denied' | 'never_ask_again'; +const PERMISSION_REQUEST_RESULT = Object.freeze({ + GRANTED: 'granted', + DENIED: 'denied', + NEVER_ASK_AGAIN: 'never_ask_again', +}); + +const PERMISSIONS = Object.freeze({ + READ_CALENDAR: 'android.permission.READ_CALENDAR', + WRITE_CALENDAR: 'android.permission.WRITE_CALENDAR', + CAMERA: 'android.permission.CAMERA', + READ_CONTACTS: 'android.permission.READ_CONTACTS', + WRITE_CONTACTS: 'android.permission.WRITE_CONTACTS', + GET_ACCOUNTS: 'android.permission.GET_ACCOUNTS', + ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION', + ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION', + RECORD_AUDIO: 'android.permission.RECORD_AUDIO', + READ_PHONE_STATE: 'android.permission.READ_PHONE_STATE', + CALL_PHONE: 'android.permission.CALL_PHONE', + READ_CALL_LOG: 'android.permission.READ_CALL_LOG', + WRITE_CALL_LOG: 'android.permission.WRITE_CALL_LOG', + ADD_VOICEMAIL: 'com.android.voicemail.permission.ADD_VOICEMAIL', + USE_SIP: 'android.permission.USE_SIP', + PROCESS_OUTGOING_CALLS: 'android.permission.PROCESS_OUTGOING_CALLS', + BODY_SENSORS: 'android.permission.BODY_SENSORS', + SEND_SMS: 'android.permission.SEND_SMS', + RECEIVE_SMS: 'android.permission.RECEIVE_SMS', + READ_SMS: 'android.permission.READ_SMS', + RECEIVE_WAP_PUSH: 'android.permission.RECEIVE_WAP_PUSH', + RECEIVE_MMS: 'android.permission.RECEIVE_MMS', + READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE', + WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE', +}); + /** * `PermissionsAndroid` provides access to Android M's new permissions model. * @@ -28,46 +67,8 @@ type PermissionStatus = 'granted' | 'denied' | 'never_ask_again'; */ class PermissionsAndroid { - PERMISSIONS: Object; - RESULTS: Object; - - constructor() { - /** - * A list of specified "dangerous" permissions that require prompting the user - */ - this.PERMISSIONS = { - READ_CALENDAR: 'android.permission.READ_CALENDAR', - WRITE_CALENDAR: 'android.permission.WRITE_CALENDAR', - CAMERA: 'android.permission.CAMERA', - READ_CONTACTS: 'android.permission.READ_CONTACTS', - WRITE_CONTACTS: 'android.permission.WRITE_CONTACTS', - GET_ACCOUNTS: 'android.permission.GET_ACCOUNTS', - ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION', - ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION', - RECORD_AUDIO: 'android.permission.RECORD_AUDIO', - READ_PHONE_STATE: 'android.permission.READ_PHONE_STATE', - CALL_PHONE: 'android.permission.CALL_PHONE', - READ_CALL_LOG: 'android.permission.READ_CALL_LOG', - WRITE_CALL_LOG: 'android.permission.WRITE_CALL_LOG', - ADD_VOICEMAIL: 'com.android.voicemail.permission.ADD_VOICEMAIL', - USE_SIP: 'android.permission.USE_SIP', - PROCESS_OUTGOING_CALLS: 'android.permission.PROCESS_OUTGOING_CALLS', - BODY_SENSORS: 'android.permission.BODY_SENSORS', - SEND_SMS: 'android.permission.SEND_SMS', - RECEIVE_SMS: 'android.permission.RECEIVE_SMS', - READ_SMS: 'android.permission.READ_SMS', - RECEIVE_WAP_PUSH: 'android.permission.RECEIVE_WAP_PUSH', - RECEIVE_MMS: 'android.permission.RECEIVE_MMS', - READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE', - WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE', - }; - - this.RESULTS = { - GRANTED: 'granted', - DENIED: 'denied', - NEVER_ASK_AGAIN: 'never_ask_again', - }; - } + PERMISSIONS = PERMISSIONS; + RESULTS = PERMISSION_REQUEST_RESULT; /** * DEPRECATED - use check @@ -77,11 +78,18 @@ class PermissionsAndroid { * * @deprecated */ - checkPermission(permission: string): Promise { + checkPermission(permission: PermissionType): Promise { console.warn( '"PermissionsAndroid.checkPermission" is deprecated. Use "PermissionsAndroid.check" instead', ); - return NativeModules.PermissionsAndroid.checkPermission(permission); + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(false); + } + + return NativePermissionsAndroid.checkPermission(permission); } /** @@ -90,8 +98,14 @@ class PermissionsAndroid { * * See https://facebook.github.io/react-native/docs/permissionsandroid.html#check */ - check(permission: string): Promise { - return NativeModules.PermissionsAndroid.checkPermission(permission); + check(permission: PermissionType): Promise { + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(false); + } + return NativePermissionsAndroid.checkPermission(permission); } /** @@ -109,12 +123,19 @@ class PermissionsAndroid { * @deprecated */ async requestPermission( - permission: string, + permission: PermissionType, rationale?: Rationale, ): Promise { console.warn( '"PermissionsAndroid.requestPermission" is deprecated. Use "PermissionsAndroid.request" instead', ); + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(false); + } + const response = await this.request(permission, rationale); return response === this.RESULTS.GRANTED; } @@ -126,11 +147,18 @@ class PermissionsAndroid { * See https://facebook.github.io/react-native/docs/permissionsandroid.html#request */ async request( - permission: string, + permission: PermissionType, rationale?: Rationale, ): Promise { + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(this.RESULTS.DENIED); + } + if (rationale) { - const shouldShowRationale = await NativeModules.PermissionsAndroid.shouldShowRequestPermissionRationale( + const shouldShowRationale = await NativePermissionsAndroid.shouldShowRequestPermissionRationale( permission, ); @@ -140,14 +168,12 @@ class PermissionsAndroid { rationale, () => reject(new Error('Error showing rationale')), () => - resolve( - NativeModules.PermissionsAndroid.requestPermission(permission), - ), + resolve(NativePermissionsAndroid.requestPermission(permission)), ); }); } } - return NativeModules.PermissionsAndroid.requestPermission(permission); + return NativePermissionsAndroid.requestPermission(permission); } /** @@ -158,11 +184,16 @@ class PermissionsAndroid { * See https://facebook.github.io/react-native/docs/permissionsandroid.html#requestmultiple */ requestMultiple( - permissions: Array, - ): Promise<{[permission: string]: PermissionStatus}> { - return NativeModules.PermissionsAndroid.requestMultiplePermissions( - permissions, - ); + permissions: Array, + ): Promise<{[permission: PermissionType]: PermissionStatus}> { + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve({}); + } + + return NativePermissionsAndroid.requestMultiplePermissions(permissions); } }