Skip to content

Commit 3927e91

Browse files
committed
android: add record permission at runtime
currently, RN does not support android api 23. so it will always return "granted" in checkPermission() and requestPermission() even when Android M user revoke permissions manually on settings.
1 parent 953f83e commit 3927e91

File tree

2 files changed

+121
-21
lines changed

2 files changed

+121
-21
lines changed

android/src/main/java/com/zxcpoiu/incallmanager/InCallManagerModule.java

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
import android.content.Intent;
66
import android.content.IntentFilter;
77
import android.content.BroadcastReceiver;
8+
import android.content.pm.PackageManager;
89
import android.hardware.Sensor;
910
import android.hardware.SensorEvent;
1011
import android.hardware.SensorEventListener;
1112
import android.hardware.SensorManager;
13+
import android.Manifest.permission;
1214
import android.media.AudioAttributes;
1315
import android.media.AudioManager;
1416
import android.media.MediaPlayer;
@@ -19,14 +21,18 @@
1921
import android.os.Build;
2022
import android.provider.Settings;
2123
import android.support.annotation.Nullable;
24+
import android.support.v4.app.ActivityCompat;
25+
import android.support.v4.content.ContextCompat;
2226
import android.util.Log;
27+
import android.util.SparseArray;
2328
import android.view.KeyEvent;
2429
import android.view.Window;
2530
import android.view.WindowManager;
2631

2732
import com.facebook.react.bridge.Arguments;
2833
import com.facebook.react.bridge.LifecycleEventListener;
2934
import com.facebook.react.bridge.NativeModule;
35+
import com.facebook.react.bridge.Promise;
3036
import com.facebook.react.bridge.ReactApplicationContext;
3137
import com.facebook.react.bridge.ReactContext;
3238
import com.facebook.react.bridge.ReactContextBaseJavaModule;
@@ -40,11 +46,13 @@
4046
import java.io.File;
4147
import java.util.Map;
4248
import java.util.HashMap;
49+
import java.util.Random;
4350

4451
public class InCallManagerModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
4552
private static final String REACT_NATIVE_MODULE_NAME = "InCallManager";
4653
private static final String TAG = REACT_NATIVE_MODULE_NAME;
4754
private static ReactApplicationContext reactContext;
55+
private final SparseArray<Promise> mRequestPermissionCodePromises;
4856

4957
// --- Screen Manager
5058
private PowerManager mPowerManager;
@@ -89,6 +97,8 @@ public class InCallManagerModule extends ReactContextBaseJavaModule implements L
8997
private MyPlayerInterface mRingtone;
9098
private MyPlayerInterface mRingback;
9199
private MyPlayerInterface mBusytone;
100+
private String media = "audio";
101+
private String recordPermission = "unknow";
92102

93103
interface MyPlayerInterface {
94104
public boolean isPlaying();
@@ -119,6 +129,7 @@ public InCallManagerModule(ReactApplicationContext _reactContext) {
119129
audioUriMap.put("bundleRingtoneUri", bundleRingtoneUri);
120130
audioUriMap.put("bundleRingbackUri", bundleRingbackUri);
121131
audioUriMap.put("bundleBusytoneUri", bundleBusytoneUri);
132+
mRequestPermissionCodePromises = new SparseArray<Promise>();
122133
Log.d(TAG, "InCallManager initialized");
123134
}
124135

@@ -570,7 +581,8 @@ private static void sendEvent(final String eventName, @Nullable WritableMap para
570581

571582
@ReactMethod
572583
public void start(final String media, final boolean auto, final String ringbackUriType) {
573-
if (media.equals("video")) {
584+
this.media = media;
585+
if (this.media.equals("video")) {
574586
defaultSpeakerOn = true;
575587
} else {
576588
defaultSpeakerOn = false;
@@ -748,7 +760,7 @@ public void setSpeakerphoneOn(final boolean enable) {
748760
* flag: Int
749761
* 0: use default action
750762
* 1: force speaker on
751-
* 2: force speaker off
763+
* -1: force speaker off
752764
*/
753765
@ReactMethod
754766
public void setForceSpeakerphoneOn(final int flag) {
@@ -1311,6 +1323,105 @@ public boolean isPlaying() {
13111323
}
13121324
}
13131325

1326+
@ReactMethod
1327+
public void checkRecordPermission(Promise promise) {
1328+
Log.d(TAG, "RNInCallManager.checkRecordPermission(): enter");
1329+
this._checkRecordPermission();
1330+
if (this.recordPermission.equals("unknow")) {
1331+
Log.d(TAG, "RNInCallManager.checkRecordPermission(): failed");
1332+
promise.reject(new Exception("checkRecordPermission failed"));
1333+
} else {
1334+
promise.resolve(this.recordPermission);
1335+
}
1336+
}
1337+
1338+
public void _checkRecordPermission() {
1339+
String recordPermission = "unknow";
1340+
if (ContextCompat.checkSelfPermission(this.reactContext, permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
1341+
recordPermission = "granted";
1342+
} else {
1343+
recordPermission = "denied";
1344+
}
1345+
this.recordPermission = recordPermission;
1346+
Log.d(TAG, String.format("RNInCallManager.checkRecordPermission(): recordPermission=%s", this.recordPermission));
1347+
}
1348+
1349+
@ReactMethod
1350+
public void requestRecordPermission(Promise promise) {
1351+
Log.d(TAG, "RNInCallManager.requestRecordPermission(): enter");
1352+
this._checkRecordPermission();
1353+
if (!this.recordPermission.equals("granted")) {
1354+
Activity currentActivity = getCurrentActivity();
1355+
if (currentActivity == null) {
1356+
this.recordPermission = recordPermission;
1357+
Log.d(TAG, "RNInCallManager.requestRecordPermission(): ReactContext doesn't hava any Activity attached.");
1358+
promise.reject(new Exception("requestRecordPermission(): currentActivity is not attached"));
1359+
}
1360+
int requestPermissionCode = getRandomInteger(1, 99999999);
1361+
while (mRequestPermissionCodePromises.get(requestPermissionCode, null) != null) {
1362+
requestPermissionCode = getRandomInteger(1, 99999999);
1363+
}
1364+
mRequestPermissionCodePromises.put(requestPermissionCode, promise);
1365+
/*
1366+
if (ActivityCompat.shouldShowRequestPermissionRationale(currentActivity, permission.RECORD_AUDIO)) {
1367+
showMessageOKCancel("You need to allow access to microphone for making call", new DialogInterface.OnClickListener() {
1368+
@Override
1369+
public void onClick(DialogInterface dialog, int which) {
1370+
ActivityCompat.requestPermissions(currentActivity, new String[] {permission.RECORD_AUDIO}, requestPermissionCode);
1371+
}
1372+
});
1373+
return;
1374+
}
1375+
*/
1376+
ActivityCompat.requestPermissions(currentActivity, new String[] {permission.RECORD_AUDIO}, requestPermissionCode);
1377+
} else {
1378+
// --- already granted
1379+
promise.resolve(this.recordPermission);
1380+
}
1381+
}
1382+
1383+
private static int getRandomInteger(int min, int max) {
1384+
if (min >= max) {
1385+
throw new IllegalArgumentException("max must be greater than min");
1386+
}
1387+
Random random = new Random();
1388+
return random.nextInt((max - min) + 1) + min;
1389+
}
1390+
1391+
//@Override
1392+
protected void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
1393+
Log.d(TAG, "RNInCallManager.onRequestPermissionsResult(): enter");
1394+
Promise promise = mRequestPermissionCodePromises.get(requestCode, null);
1395+
mRequestPermissionCodePromises.delete(requestCode);
1396+
if (promise != null) {
1397+
1398+
Map<String, Integer> permissionResultMap = new HashMap<String, Integer>();
1399+
1400+
for (int i = 0; i < permissions.length; i++) {
1401+
permissionResultMap.put(permissions[i], grantResults[i]);
1402+
}
1403+
1404+
if (!permissionResultMap.containsKey(permission.RECORD_AUDIO)) {
1405+
Log.wtf(TAG, "RNInCallManager.onRequestPermissionsResult(): requested permission RECORD_AUDIO but did not appear");
1406+
promise.reject("RECORD_AUDIO_PERMISSION_NOT_FOUND", "requested permission RECORD_AUDIO but did not appear");
1407+
return;
1408+
}
1409+
1410+
String recordPermission = "unknow";
1411+
if (permissionResultMap.get(permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
1412+
recordPermission = "granted";
1413+
} else {
1414+
recordPermission = "denied";
1415+
}
1416+
this.recordPermission = recordPermission;
1417+
promise.resolve(recordPermission);
1418+
} else {
1419+
//super.onRequestPermissionsResult(requestCode, permissions, grantResults);
1420+
Log.wtf(TAG, "RNInCallManager.onRequestPermissionsResult(): request code not found");
1421+
promise.reject("PERMISSION_REQUEST_CODE_NOT_FOUND", "request code not found");
1422+
}
1423+
}
1424+
13141425
@Override
13151426
public void onHostResume() {
13161427
Log.d(TAG, "onResume()");

index.js

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict';
22
var _InCallManager = require('react-native').NativeModules.InCallManager;
3-
import { Platform } from 'react-native';
43

54
class InCallManager {
65
constructor() {
@@ -66,27 +65,17 @@ class InCallManager {
6665
}
6766

6867
async checkRecordPermission() {
69-
if (Platform.OS === 'android') {
70-
console.log('react-native-incall-manager: android does not support checkRecordPermission() yet.');
71-
this.recordPermission = 'unknow';
72-
return 'unknow';
73-
} else {
74-
let result = await _InCallManager.checkRecordPermission();
75-
this.recordPermission = result;
76-
return result;
77-
}
68+
// --- on android which api < 23, it will always be "granted"
69+
let result = await _InCallManager.checkRecordPermission();
70+
this.recordPermission = result;
71+
return result;
7872
}
7973

8074
async requestRecordPermission() {
81-
if (Platform.OS === 'android') {
82-
console.log('react-native-incall-manager: android does not support requestRecordPermission() yet.');
83-
this.recordPermission = 'unknow';
84-
return 'unknow';
85-
} else {
86-
let result = await _InCallManager.requestRecordPermission();
87-
this.recordPermission = result;
88-
return result;
89-
}
75+
// --- on android which api < 23, it will always be "granted"
76+
let result = await _InCallManager.requestRecordPermission();
77+
this.recordPermission = result;
78+
return result;
9079
}
9180
}
9281

0 commit comments

Comments
 (0)