PermissionsAndroid.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @format
  8. * @flow strict-local
  9. */
  10. 'use strict';
  11. const Platform = require('../Utilities/Platform');
  12. import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid';
  13. import NativePermissionsAndroid from './NativePermissionsAndroid';
  14. import type {
  15. PermissionStatus,
  16. PermissionType,
  17. } from './NativePermissionsAndroid';
  18. import invariant from 'invariant';
  19. export type Rationale = {
  20. title: string,
  21. message: string,
  22. buttonPositive?: string,
  23. buttonNegative?: string,
  24. buttonNeutral?: string,
  25. ...
  26. };
  27. const PERMISSION_REQUEST_RESULT = Object.freeze({
  28. GRANTED: 'granted',
  29. DENIED: 'denied',
  30. NEVER_ASK_AGAIN: 'never_ask_again',
  31. });
  32. const PERMISSIONS = Object.freeze({
  33. READ_CALENDAR: 'android.permission.READ_CALENDAR',
  34. WRITE_CALENDAR: 'android.permission.WRITE_CALENDAR',
  35. CAMERA: 'android.permission.CAMERA',
  36. READ_CONTACTS: 'android.permission.READ_CONTACTS',
  37. WRITE_CONTACTS: 'android.permission.WRITE_CONTACTS',
  38. GET_ACCOUNTS: 'android.permission.GET_ACCOUNTS',
  39. ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION',
  40. ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION',
  41. ACCESS_BACKGROUND_LOCATION: 'android.permission.ACCESS_BACKGROUND_LOCATION',
  42. RECORD_AUDIO: 'android.permission.RECORD_AUDIO',
  43. READ_PHONE_STATE: 'android.permission.READ_PHONE_STATE',
  44. CALL_PHONE: 'android.permission.CALL_PHONE',
  45. READ_CALL_LOG: 'android.permission.READ_CALL_LOG',
  46. WRITE_CALL_LOG: 'android.permission.WRITE_CALL_LOG',
  47. ADD_VOICEMAIL: 'com.android.voicemail.permission.ADD_VOICEMAIL',
  48. USE_SIP: 'android.permission.USE_SIP',
  49. PROCESS_OUTGOING_CALLS: 'android.permission.PROCESS_OUTGOING_CALLS',
  50. BODY_SENSORS: 'android.permission.BODY_SENSORS',
  51. SEND_SMS: 'android.permission.SEND_SMS',
  52. RECEIVE_SMS: 'android.permission.RECEIVE_SMS',
  53. READ_SMS: 'android.permission.READ_SMS',
  54. RECEIVE_WAP_PUSH: 'android.permission.RECEIVE_WAP_PUSH',
  55. RECEIVE_MMS: 'android.permission.RECEIVE_MMS',
  56. READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE',
  57. WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE',
  58. });
  59. /**
  60. * `PermissionsAndroid` provides access to Android M's new permissions model.
  61. *
  62. * See https://reactnative.dev/docs/permissionsandroid.html
  63. */
  64. class PermissionsAndroid {
  65. PERMISSIONS: {|
  66. ACCESS_BACKGROUND_LOCATION: string,
  67. ACCESS_COARSE_LOCATION: string,
  68. ACCESS_FINE_LOCATION: string,
  69. ADD_VOICEMAIL: string,
  70. BODY_SENSORS: string,
  71. CALL_PHONE: string,
  72. CAMERA: string,
  73. GET_ACCOUNTS: string,
  74. PROCESS_OUTGOING_CALLS: string,
  75. READ_CALENDAR: string,
  76. READ_CALL_LOG: string,
  77. READ_CONTACTS: string,
  78. READ_EXTERNAL_STORAGE: string,
  79. READ_PHONE_STATE: string,
  80. READ_SMS: string,
  81. RECEIVE_MMS: string,
  82. RECEIVE_SMS: string,
  83. RECEIVE_WAP_PUSH: string,
  84. RECORD_AUDIO: string,
  85. SEND_SMS: string,
  86. USE_SIP: string,
  87. WRITE_CALENDAR: string,
  88. WRITE_CALL_LOG: string,
  89. WRITE_CONTACTS: string,
  90. WRITE_EXTERNAL_STORAGE: string,
  91. |} = PERMISSIONS;
  92. RESULTS: {|
  93. DENIED: $TEMPORARY$string<'denied'>,
  94. GRANTED: $TEMPORARY$string<'granted'>,
  95. NEVER_ASK_AGAIN: $TEMPORARY$string<'never_ask_again'>,
  96. |} = PERMISSION_REQUEST_RESULT;
  97. /**
  98. * DEPRECATED - use check
  99. *
  100. * Returns a promise resolving to a boolean value as to whether the specified
  101. * permissions has been granted
  102. *
  103. * @deprecated
  104. */
  105. checkPermission(permission: PermissionType): Promise<boolean> {
  106. console.warn(
  107. '"PermissionsAndroid.checkPermission" is deprecated. Use "PermissionsAndroid.check" instead',
  108. );
  109. if (Platform.OS !== 'android') {
  110. console.warn(
  111. '"PermissionsAndroid" module works only for Android platform.',
  112. );
  113. return Promise.resolve(false);
  114. }
  115. invariant(
  116. NativePermissionsAndroid,
  117. 'PermissionsAndroid is not installed correctly.',
  118. );
  119. return NativePermissionsAndroid.checkPermission(permission);
  120. }
  121. /**
  122. * Returns a promise resolving to a boolean value as to whether the specified
  123. * permissions has been granted
  124. *
  125. * See https://reactnative.dev/docs/permissionsandroid.html#check
  126. */
  127. check(permission: PermissionType): Promise<boolean> {
  128. if (Platform.OS !== 'android') {
  129. console.warn(
  130. '"PermissionsAndroid" module works only for Android platform.',
  131. );
  132. return Promise.resolve(false);
  133. }
  134. invariant(
  135. NativePermissionsAndroid,
  136. 'PermissionsAndroid is not installed correctly.',
  137. );
  138. return NativePermissionsAndroid.checkPermission(permission);
  139. }
  140. /**
  141. * DEPRECATED - use request
  142. *
  143. * Prompts the user to enable a permission and returns a promise resolving to a
  144. * boolean value indicating whether the user allowed or denied the request
  145. *
  146. * If the optional rationale argument is included (which is an object with a
  147. * `title` and `message`), this function checks with the OS whether it is
  148. * necessary to show a dialog explaining why the permission is needed
  149. * (https://developer.android.com/training/permissions/requesting.html#explain)
  150. * and then shows the system permission dialog
  151. *
  152. * @deprecated
  153. */
  154. async requestPermission(
  155. permission: PermissionType,
  156. rationale?: Rationale,
  157. ): Promise<boolean> {
  158. console.warn(
  159. '"PermissionsAndroid.requestPermission" is deprecated. Use "PermissionsAndroid.request" instead',
  160. );
  161. if (Platform.OS !== 'android') {
  162. console.warn(
  163. '"PermissionsAndroid" module works only for Android platform.',
  164. );
  165. return Promise.resolve(false);
  166. }
  167. const response = await this.request(permission, rationale);
  168. return response === this.RESULTS.GRANTED;
  169. }
  170. /**
  171. * Prompts the user to enable a permission and returns a promise resolving to a
  172. * string value indicating whether the user allowed or denied the request
  173. *
  174. * See https://reactnative.dev/docs/permissionsandroid.html#request
  175. */
  176. async request(
  177. permission: PermissionType,
  178. rationale?: Rationale,
  179. ): Promise<PermissionStatus> {
  180. if (Platform.OS !== 'android') {
  181. console.warn(
  182. '"PermissionsAndroid" module works only for Android platform.',
  183. );
  184. return Promise.resolve(this.RESULTS.DENIED);
  185. }
  186. invariant(
  187. NativePermissionsAndroid,
  188. 'PermissionsAndroid is not installed correctly.',
  189. );
  190. if (rationale) {
  191. const shouldShowRationale = await NativePermissionsAndroid.shouldShowRequestPermissionRationale(
  192. permission,
  193. );
  194. if (shouldShowRationale && !!NativeDialogManagerAndroid) {
  195. return new Promise((resolve, reject) => {
  196. const options = {
  197. ...rationale,
  198. };
  199. NativeDialogManagerAndroid.showAlert(
  200. /* $FlowFixMe(>=0.111.0 site=react_native_fb) This comment
  201. * suppresses an error found when Flow v0.111 was deployed. To see
  202. * the error, delete this comment and run Flow. */
  203. options,
  204. () => reject(new Error('Error showing rationale')),
  205. () =>
  206. resolve(NativePermissionsAndroid.requestPermission(permission)),
  207. );
  208. });
  209. }
  210. }
  211. return NativePermissionsAndroid.requestPermission(permission);
  212. }
  213. /**
  214. * Prompts the user to enable multiple permissions in the same dialog and
  215. * returns an object with the permissions as keys and strings as values
  216. * indicating whether the user allowed or denied the request
  217. *
  218. * See https://reactnative.dev/docs/permissionsandroid.html#requestmultiple
  219. */
  220. requestMultiple(
  221. permissions: Array<PermissionType>,
  222. ): Promise<{[permission: PermissionType]: PermissionStatus, ...}> {
  223. if (Platform.OS !== 'android') {
  224. console.warn(
  225. '"PermissionsAndroid" module works only for Android platform.',
  226. );
  227. return Promise.resolve({});
  228. }
  229. invariant(
  230. NativePermissionsAndroid,
  231. 'PermissionsAndroid is not installed correctly.',
  232. );
  233. return NativePermissionsAndroid.requestMultiplePermissions(permissions);
  234. }
  235. }
  236. const PermissionsAndroidInstance: PermissionsAndroid = new PermissionsAndroid();
  237. module.exports = PermissionsAndroidInstance;