Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: react-native-webrtc/react-native-incall-manager
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1.5.0
Choose a base ref
...
head repository: react-native-webrtc/react-native-incall-manager
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on Aug 23, 2016

  1. do not unregister event when app goes to background.

    since VoIP app switch focosed activity oftenly
    we should allow incall manager to manage audio route during background
    and incall manager's life cycle should controled by app logic
    zxcpoiu committed Aug 23, 2016
    Copy the full SHA
    bd03595 View commit details
  2. release 1.5.1

    bd03595 do not unregister event when app goes to background.  ( zxcpoiu 2016-08-23 13:05:41 +0800)
    zxcpoiu committed Aug 23, 2016
    Copy the full SHA
    8a91500 View commit details

Commits on Oct 26, 2016

  1. uint cast

    Scott Baar committed Oct 26, 2016
    Copy the full SHA
    7fa4301 View commit details
  2. uint cast

    Scott Baar committed Oct 26, 2016
    Copy the full SHA
    9853b02 View commit details

Commits on Oct 31, 2016

  1. Merge pull request #11 from scottbMedl/master

    Fix uint cast for audio event listener
    zxcpoiu authored Oct 31, 2016
    Copy the full SHA
    5303693 View commit details

Commits on Nov 1, 2016

  1. release 1.5.2

    9853b02 uint cast  ( Scott Baar 2016-10-26 15:12:49 -0700)
    7fa4301 uint cast  ( Scott Baar 2016-10-26 15:08:48 -0700)
    zxcpoiu committed Nov 1, 2016
    Copy the full SHA
    9453fcd View commit details
  2. android: add limit seconds when play ringtone

    in some cases, app will into infinite loop to play ringtone.
    add `seconds` argument to startRingtone to limit it
    zxcpoiu committed Nov 1, 2016
    Copy the full SHA
    3a31f9a View commit details
  3. release 1.5.3

    3a31f9a android: add limit seconds when play ringtone  ( zxcpoiu 2016-11-01 20:11:30 +0800)
    zxcpoiu committed Nov 1, 2016
    Copy the full SHA
    27f10a3 View commit details

Commits on Nov 4, 2016

  1. Swift 2.3 compatibility change

    David Perrenoud authored Nov 4, 2016
    Copy the full SHA
    9a76ba5 View commit details

Commits on Nov 6, 2016

  1. Merge pull request #14 from davidperrenoud/patch-1

    Swift 2.3 compatibility change
    zxcpoiu authored Nov 6, 2016
    Copy the full SHA
    33c6b43 View commit details
  2. release 1.5.4

    9a76ba5 Swift 2.3 compatibility change  ( David Perrenoud 2016-11-04 14:38:13 +0100)
    zxcpoiu committed Nov 6, 2016
    Copy the full SHA
    d1a9b94 View commit details

Commits on Nov 30, 2016

  1. remove dup filenames

    sagivo authored Nov 30, 2016
    Copy the full SHA
    78ab6c2 View commit details

Commits on Dec 1, 2016

  1. update to ringtome

    sagivo authored Dec 1, 2016
    Copy the full SHA
    be16124 View commit details

Commits on Dec 2, 2016

  1. Merge pull request #16 from sagivo/patch-1

    remove dup filenames
    zxcpoiu authored Dec 2, 2016
    Copy the full SHA
    3b31bd6 View commit details

Commits on Dec 5, 2016

  1. Update index.js

    fix typo
    blackneck authored Dec 5, 2016
    Copy the full SHA
    3b91525 View commit details

Commits on Dec 7, 2016

  1. Merge pull request #17 from blackneck/patch-1

    Update index.js
    zxcpoiu authored Dec 7, 2016
    Copy the full SHA
    fd2bd14 View commit details

Commits on Jan 25, 2017

  1. RN 0.4.0 support

    jjdp committed Jan 25, 2017
    Copy the full SHA
    23aa455 View commit details
  2. Merge pull request #23 from jjdp/master

    RN 0.4.0 support for IOS
    zxcpoiu authored Jan 25, 2017
    Copy the full SHA
    e5fb732 View commit details

Commits on Jan 26, 2017

  1. refactor to new swift version

    sagivo committed Jan 26, 2017
    Copy the full SHA
    f474a35 View commit details
  2. reverse order of nil param

    sagivo committed Jan 26, 2017
    Copy the full SHA
    2089148 View commit details
  3. update readme and bump version

    sagivo committed Jan 26, 2017
    Copy the full SHA
    6e96f99 View commit details
  4. update readme old version

    sagivo committed Jan 26, 2017
    Copy the full SHA
    0c0caf8 View commit details
  5. Merge pull request #24 from sagivo/master

    1. support for RN 0.40
    2. refactor to new swift 3
    zxcpoiu authored Jan 26, 2017
    Copy the full SHA
    08785a4 View commit details
  6. Copy the full SHA
    095c820 View commit details
  7. add vibration support ios

    zxcpoiu committed Jan 26, 2017
    Copy the full SHA
    7116c24 View commit details
  8. use specific vibration pattern instead repeat

    use repeat will cause infinite loop in some cases.
    ex: network interrupted, did not receive hangup signal, ...etc
    zxcpoiu committed Jan 26, 2017
    Copy the full SHA
    3bae639 View commit details
  9. Update README.md

    zxcpoiu authored Jan 26, 2017
    Copy the full SHA
    179b99a View commit details
  10. Copy the full SHA
    8fa8fa4 View commit details
  11. release 2.1.0

    8fa8fa4 Update README for swift 3 migration  ( zxcpoiu 2017-01-26 17:33:45 +0800)
    179b99a Update README.md  ( zxcpoiu 2017-01-26 17:22:59 +0800)
    3bae639 use specific vibration pattern instead repeat  ( zxcpoiu 2016-11-01 17:57:19 +0800)
    7116c24 add vibration support ios  ( zxcpoiu 2016-08-01 14:12:10 +0800)
    095c820 bump react-native dependency to 0.40.0  ( zxcpoiu 2017-01-26 16:58:53 +0800)
    0c0caf8 update readme old version  ( Sagiv Ofek 2017-01-25 22:10:57 -0500)
    6e96f99 update readme and bump version  ( Sagiv Ofek 2017-01-25 21:12:33 -0500)
    2089148 reverse order of nil param  ( Sagiv Ofek 2017-01-25 20:59:52 -0500)
    f474a35 refactor to new swift version  ( Sagiv Ofek 2017-01-25 20:54:44 -0500)
    23aa455 RN 0.4.0 support  ( Jan 2017-01-25 15:19:58 +0800)
    3b91525 Update index.js  ( Alexander Chernoshej 2016-12-05 19:01:48 +0300)
    be16124 update to ringtome  ( Sagiv Ofek 2016-12-01 11:06:09 -0500)
    78ab6c2 remove dup filenames  ( Sagiv Ofek 2016-11-30 17:32:06 -0500)
    zxcpoiu committed Jan 26, 2017
    Copy the full SHA
    ace23c4 View commit details

Commits on Feb 23, 2017

  1. Added iOS support for controlling system flash

    Added iOS support for controlling system flash with configurable
    brightness
    stepanvotava committed Feb 23, 2017
    Copy the full SHA
    b24eeab View commit details

Commits on Feb 27, 2017

  1. Merge pull request #25 from stepanvotava/set-flash-on-ios

    Added iOS support for controlling system flash
    zxcpoiu authored Feb 27, 2017
    Copy the full SHA
    9386eba View commit details

Commits on Apr 16, 2017

  1. Copy the full SHA
    1564c32 View commit details

Commits on Apr 23, 2017

  1. Merge pull request #31 from bryant1410/master

    Fix broken headings in Markdown files
    zxcpoiu authored Apr 23, 2017
    Copy the full SHA
    8d0ccce View commit details

Commits on May 25, 2017

  1. Copy the full SHA
    9370858 View commit details

Commits on May 31, 2017

  1. Merge pull request #35 from tsugitta/update_to_swift3_syntax

    Update some codes syntax to swift3 which cause errors
    zxcpoiu authored May 31, 2017
    Copy the full SHA
    00c8af1 View commit details

Commits on Aug 2, 2017

  1. Copy the full SHA
    29f748b View commit details

Commits on Aug 3, 2017

  1. Merge pull request #43 from brunsy/master

    Handle RN 0.47 breaking change (createJSModules)
    zxcpoiu authored Aug 3, 2017
    Copy the full SHA
    7e41276 View commit details

Commits on Aug 8, 2017

  1. Added getIsWiredHeadsetPluggedIn to bridge methods (#42)

    * Added native method so can know initial state of isWiredHeadsetPluggedIn
    
    * Changed Impelementation to async style and restrict only ios
    masaori authored and zxcpoiu committed Aug 8, 2017
    Copy the full SHA
    dd6a4f7 View commit details
  2. wakelock: acquire lock during whole ringtone and start process

    some buggy devices would enter sleep/power saving mode while screen is
    turned of by proximity sensor. it may cause unexpected disconnection
    when user using earpiece to talk.
    
    so there is no need to acquire/release on every manualTurnScreen On/Off
    zxcpoiu committed Aug 8, 2017
    Copy the full SHA
    a2d710e View commit details
  3. release 2.2.0

    a2d710e wakelock: acquire lock during whole ringtone and start process  ( zxcpoiu 2017-08-08 20:33:48 +0800)
    dd6a4f7 Added getIsWiredHeadsetPluggedIn to bridge methods (#42)  ( Masaori Hirono 2017-08-08 22:05:53 +0900)
    29f748b handle RN 0.47 breaking change (createJSModules removed from ReactPackage)  ( Pete 2017-08-02 12:54:10 +1200)
    9370858 Update some codes syntax to swift3 which causes errors  ( Toshinori Tsugita 2017-05-25 14:20:06 +0900)
    1564c32 Fix broken Markdown headings  ( Santiago Castro 2017-04-16 16:40:34 -0300)
    b24eeab Added iOS support for controlling system flash  ( Stepan Votava 2017-02-23 14:23:31 +0100)
    zxcpoiu committed Aug 8, 2017
    Copy the full SHA
    3a79c04 View commit details
  4. Update README for new API

    zxcpoiu authored Aug 8, 2017
    Copy the full SHA
    71dde43 View commit details
  5. Copy the full SHA
    53e37c4 View commit details

Commits on Sep 27, 2017

  1. Copy the full SHA
    93fd78b View commit details

Commits on Nov 30, 2017

  1. LICENSE: add title (#51)

    The title is not legally mandated, but it's recommended in the license template text (see http://choosealicense.com/licenses/isc/ and https://opensource.org/licenses/isc-license).
    waldyrious authored and zxcpoiu committed Nov 30, 2017
    Copy the full SHA
    e98d670 View commit details

Commits on Dec 3, 2017

  1. Copy the full SHA
    0625fa4 View commit details

Commits on Dec 8, 2017

  1. Rewrite using Obj-C

    ianlin committed Dec 8, 2017
    Copy the full SHA
    80aeeb3 View commit details
  2. Copy the full SHA
    b5a8f14 View commit details
  3. Update README

    For linking Obj-C project and some nit-picking on words
    ianlin authored Dec 8, 2017
    Copy the full SHA
    0af789f View commit details
  4. Merge pull request #57 from zxcpoiu/convert-objc

    iOS: rewrite using Obj-C
    zxcpoiu authored Dec 8, 2017
    Copy the full SHA
    81741ad View commit details
  5. Merge pull request #58 from zxcpoiu/bluetooth

    [REFACTOR] android: support bluetooth / combined with AppRTC Demo's
    zxcpoiu authored Dec 8, 2017
    Copy the full SHA
    84b2285 View commit details
Showing with 4,215 additions and 1,843 deletions.
  1. +2 −0 LICENSE
  2. +130 −133 README.md
  3. +22 −0 ReactNativeIncallManager.podspec
  4. +15 −5 android/build.gradle
  5. +634 −0 android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/AppRTCBluetoothManager.java
  6. +142 −0 android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/AppRTCProximitySensor.java
  7. +29 −0 android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/LICENSE
  8. +12 −0 android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/README
  9. +64 −0 android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/diff/AppRTCBluetoothManager.java.diff
  10. +31 −0 android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/diff/AppRTCProximitySensor.java.diff
  11. +11 −0 android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/diff/AppRTCUtils.java.diff
  12. +176 −0 android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/diff/ThreadUtils.java.diff
  13. +41 −0 android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/util/AppRTCUtils.java
  14. +39 −0 android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/util/ThreadUtils.java
  15. +865 −642 android/src/main/java/com/zxcpoiu/incallmanager/InCallManagerModule.java
  16. +17 −4 android/src/main/java/com/zxcpoiu/incallmanager/InCallManagerPackage.java
  17. +162 −0 android/src/main/java/com/zxcpoiu/incallmanager/InCallProximityManager.java
  18. +116 −0 android/src/main/java/com/zxcpoiu/incallmanager/InCallWakeLockUtils.java
  19. +64 −0 index.d.ts
  20. +54 −43 index.js
  21. +283 −0 ios/RNInCallManager.xcodeproj/project.pbxproj
  22. +0 −13 ios/RNInCallManager/RNInCallManager-Bridging-Header.h
  23. +17 −0 ios/RNInCallManager/RNInCallManager.h
  24. +1,284 −0 ios/RNInCallManager/RNInCallManager.m
  25. +0 −969 ios/RNInCallManager/RNInCallManager.swift
  26. +0 −29 ios/RNInCallManager/RNInCallManagerBridge.m
  27. +5 −5 package.json
2 changes: 2 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
ISC License

Copyright (c) 2016, zxcpoiu

Permission to use, copy, modify, and/or distribute this software for any
263 changes: 130 additions & 133 deletions README.md
Original file line number Diff line number Diff line change
@@ -7,84 +7,138 @@
Handling media-routes/sensors/events during a audio/video chat on React Native

## Purpose:
The purpose of this module is to handle actions/events during a phone call (audio/video) on `react-native`, ex:
* manage devices events like wired-headset plugged, proximity sensors and expose to javascript.
* automatically route audio to proper device based on events and platform API.
* toggle speaker or microphone on/off, toggle flash light on/off (not implemented yes)
* play ringtone/ringback/dtmftone

basically, it is a telecommunication module which handle most of requirements when making/receiving/talking to a call.
The purpose of this module is to handle actions/events during a phone call (audio/video) on `react-native`, ex:

This module is desinged to work with [react-native-webrtc](https://github.com/oney/react-native-webrtc)
you can find demo here: https://github.com/oney/RCTWebRTCDemo
* Manage devices events like wired-headset plugged-in state, proximity sensors and expose functionalities to javascript.
* Automatically route audio to proper devices based on events and platform API.
* Toggle speaker or microphone on/off, toggle flashlight on/off
* Play ringtone/ringback/dtmftone

Basically, it is a telecommunication module which handles most of the requirements when making/receiving/talking with a call.

This module is designed to work with [react-native-webrtc](https://github.com/oney/react-native-webrtc)

## TODO / Contribution Wanted:

* Make operations run on the main thread. ( iOS/Android )
* Fix iOS audio shared instance singleton conflict with internal webrtc.
* Detect hardware button press event and react to it.
ex: press bluetooth button, send an event to JS to answer/hangup.
ex: press power button to mute incoming ringtone.
* Use config-based to decide which event should start and report. maybe control behavior as well.
* Flash API on Android.

## Installation:

**from npm package**: `npm install react-native-incall-manager`
**from git package**: `npm install git://github.com/zxcpoiu/react-native-incall-manager.git`
**From npm package**: `npm install react-native-incall-manager`
**From git package**: `npm install git://github.com/zxcpoiu/react-native-incall-manager.git`

===================================================
####android:

### Android:

note: you might need `android.permission.BLUETOOTH` permisions for Bluetooth to work.

After install, you can use `rnpm` (`npm install rnpm -g`) to link android.
use `rnpm link react-native-incall-manager` to link or manually if you like.
use `react-native link react-native-incall-manager` to link or manually if you like.

**optional sound files on android**
if you want to use bundled ringtone/ringback/busytone sound instead of system sound

We use android support library v4 to check/request permissions.
You should add `compile "com.android.support:support-v4:23.0.1"` in `$your_project/android/app/build.gradle` dependencies on android.

put files in `android/app/src/main/res/raw`
and rename file correspond to sound type:
You should add `compile "com.android.support:support-v4:$YOUR_VERSION"` in `$YOUR_PROJECT/android/app/build.gradle` dependencies on android.

#### Manually Linking

If `react-native link` doesn't work, ( see: https://github.com/zxcpoiu/react-native-incall-manager/issues/21#issuecomment-279575516 ) please add it manually in your main project:

1. In `android/app/build.gradle`
Should have a line `compile(project(':react-native-incall-manager'))` in `dependencies {}` section

2. In `android/settings.gradle`
Should have:
```
include ':react-native-incall-manager'
project(':react-native-incall-manager').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-incall-manager/android')
```
3. In `MainApplication.java`
```java
import com.zxcpoiu.incallmanager.InCallManagerPackage;
private static List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new InCallManagerPackage(),
);
}
```
#### Optional sound files on android
If you want to use bundled ringtone/ringback/busytone sound instead of system sound,
put files in `android/app/src/main/res/raw`
and rename file correspond to sound type:
```
incallmanager_busytone.mp3
incallmanager_ringback.mp3
incallmanager_ringback.mp3
incallmanager_ringtone.mp3
```
on android, as long as your file extension supported by android, this module will load it.

On android, as long as your file extension supported by android, this module will load it.
===================================================
####ios:
### ios:
`react-native link react-native-incall-manager`
#### Using CocoaPods
since ios part written in swift and it doesn't support static library yet.
before that, you should add this project manually:
Update the following line with your path to node_modules/ and add it to your Podfile:
- **Add files in to your project:**
`pod 'ReactNativeIncallManager', :path => '../node_modules/react-native-incall-manager'`
1. Open your project in xcode
2. find your_project directory under your project's xcodeproject root. ( it's a sub-directoory, not root xcodeproject itself )
3. you can do either:
* directly drag your node_modules/react-native-incall-manager/ios/RNInCallManager/ into it.
* right click on your_project directory, `add files` to your project and add `node_modules/react-native-incall-manager/ios/RNInCallManager/`
4. on the pou-up window, uncheck `Copy items if needed` and select `Added folders: Create groups` then add it. you will see a new directory named `RNInCallmanager under your_project` directory.
#### Manually Linking
- **Setup Objective-C Bridging Header:**
1. click your `project's xcodeproject root`, go to `build setting` and search `Objective-C Bridging Header`
2. set you header location, the default path is: `ReactNativeProjectRoot/ios/`, in this case, you should set `../node_modules/react-native-incall-manager/ios/RNInCallManager/RNInCallManager-Bridging-Header.h`
In case `react-native link` doesn't work,
**optional sound files on android**
if you want to use bundled ringtone/ringback/busytone sound instead of system sound
- Drag `node_modules/react-native-incall-manager/ios/RNInCallManager.xcodeproj` under `<your_xcode_project>/Libraries`
- Select `<your_xcode_project>` --> `Build Phases` --> `Link Binary With Libraries`
- Drag `Libraries/RNInCallManager.xcodeproj/Products/libRNInCallManager.a` to `Link Binary With Libraries`
- Select `<your_xcode_project>` --> `Build Settings`
- In `Header Search Paths`, add `$(SRCROOT)/../node_modules/react-native-incall-manager/ios/RNInCallManager`
1. add files into your_project directory under your project's xcodeproject root. ( or drag into it as described above. )
2. check `copy file if needed`
3. make sure filename correspond to sound type:
#### Clean project if messed up:
The installation steps are a bit complex, it might be related your xcode version, xcode cache, converting swift version, and your own path configurations. if something messed up, please follow steps below to clean this project, then do it again steps by steps.
1. Delete all project/directory in xcode related to incall-manager
2. Delete `react-native-incall-manager` in node_modules ( rm -rf )
3. Xcode -> Product -> clean
4. Close xcode
5. Run `npm install` again
6. Open xcode and try the install process again steps by steps
If someone knows a simpler way to set this project up, let me know plz.
#### Optional sound files on iOS
If you want to use bundled ringtone/ringback/busytone sound instead of system sound
1. Add files into your_project directory under your project's xcodeproject root. ( or drag into it as described above. )
2. Check `copy file if needed`
3. Make sure filename correspond to sound type:
```
incallmanager_busytone.mp3
incallmanager_ringback.mp3
incallmanager_ringback.mp3
incallmanager_ringback.mp3
incallmanager_ringtone.mp3
```
on ios, we only support mp3 files currently.
On ios, we only support mp3 files currently.
## Usage:
This module implement a basic handle logic automatically, just:
This module implements a basic handle logic automatically, just:
```javascript
import InCallManager from 'react-native-incall-manager';
@@ -97,10 +151,10 @@ InCallManager.start({media: 'audio'}); // audio/video, default: audio
// --- On Call Hangup:
InCallManager.stop();
// ... it will also remote event listeners ...
// ... it will also remove event listeners ...
```

if you want to use ringback:
If you want to use ringback:

```javascript
// ringback is basically for OUTGOING call. and is part of start().
@@ -110,7 +164,7 @@ InCallManager.start({media: 'audio', ringback: '_BUNDLE_'}); // or _DEFAULT_ or
InCallManager.stopRingback();
```

if you want to use busytone:
If you want to use busytone:

```javascript
// busytone is basically for OUTGOING call. and is part of stop()
@@ -119,7 +173,7 @@ if you want to use busytone:
InCallManager.stop({busytone: '_DTMF_'}); // or _BUNDLE_ or _DEFAULT_
```

if you want to use ringtone:
If you want to use ringtone:

```javascript
// ringtone is basically for INCOMING call. it's independent to start() and stop()
@@ -137,8 +191,8 @@ InCallManager.stop();

```

also can interact with events if you want:
see API section.
Also can interact with events if you want:
See API section.

```javascript
import { DeviceEventEmitter } from 'react-native';
@@ -149,89 +203,28 @@ DeviceEventEmitter.addListener('Proximity', function (data) {

```

## About Permission:


since version 1.2.0, two functions and a property were added:

```javascript
// --- function
async checkRecordPermission() // return promise
async requestRecordPermission() // return promise

// --- property
recordPermission = 'unknow' or 'granted' or 'denied', default is 'unknow'
```

After incall-manager initialized, it will check current state of record permission and set to `recordPermission` property.
so you can just write below code in your `ComponentDidMount` like:

```javascript
if (InCallManager.recordPermission !== 'granted') {
InCallManager.requestRecordPermission()
.then((requestedRecordPermissionResult) => {
console.log("InCallManager.requestRecordPermission() requestedRecordPermissionResult: ", requestedRecordPermissionResult);
})
.catch((err) => {
console.log("InCallManager.requestRecordPermission() catch: ", err);
});
}
```

We use android support library v4 to check/request permissions.
You should add `compile "com.android.support:support-v4:23.0.1"` in `$your_project/android/app/build.gradle` dependencies on android.


**NOTE for android:**

React Native does not officially support api 23 currently ( it is on api 22 now. see: [RN known issues](https://facebook.github.io/react-native/docs/known-issues.html#android-m-permissions)) and android supports request permission at runtime since api 23, so it will always return 'granted' immediately after calling `checkRecordPermission()` or `requestRecordPermission()`.

If you really need the functionality, you can do the following to make them work but at your own risk:
( I've tested it though, but who knows :) )

Step 1: change your `targetSdkVersion` to 23 in `$your_project/android/app/build.gradle`
Step 2: override `onRequestPermissionsResult` in your `MainActivity.java` like:

```
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
InCallManagerPackage.onRequestPermissionsResult(requestCode, permissions, grantResults);
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
```

then you can test it on android 6 now.

**Another thing you should know is:**

If you change targetSdkVersion to 23, the `red box` which React Native used to display errors in development mode requires permission `Draw Over Other Apps`.
So in **development mode**, you should manually grant permission in `app settings` on your device or declare `android.permission.SYSTEM_ALERT_WINDOW` in your manifest.
You don't have to do this in **release mode** since there are no red box.


checkout this awesome project: [react-native-android-permissions](https://github.com/lucasferreira/react-native-android-permissions) by @lucasferreira for more information.


## Automatic Basic Behavior:

**on start:**
* store current settings, set KeepScreenOn flag = true, and register some event listeners.
* if media type is `audio`, route voice to earpiece, otherwise route to speaker.
* audio will enable proximity sensor which is disabled by default if media=video
* when proximity detect user closed to screen, turn off screen to avoid accident touch and route voice to earpiece.
* when newly external device plugged, such as wired-headset, route audio to external device.
* optional play ringback
**On start:**
* Store current settings, set KeepScreenOn flag = true, and register some event listeners.
* If media type is `audio`, route voice to earpiece, otherwise route to speaker.
* Audio will enable proximity sensor which is disabled by default if media=video
* When proximity detects user close to screen, turn off screen to avoid accident touch and route voice to the earpiece.
* When newly external device plugged, such as wired-headset, route audio to an external device.
* Optional play ringback

**on stop:**
**On stop:**

* set KeepScreenOn flag = false, remote event listeners, restore original user settings.
* optional play busytone
* Set KeepScreenOn flag = false, remote event listeners, restore original user settings.
* Optionally play busytone

## Custom Behavior:

you can custom behavior use API/events exposed by this module. see `API` section.
You can customize behavior using API/events exposed by this module. See `API` section.

note: ios only supports `auto` currently.
Note: iOS only supports `auto` currently.

## API:

@@ -247,27 +240,31 @@ note: ios only supports `auto` currently.
| setSpeakerphoneOn(`enable: ?boolean`) | :smile: | :rage: | toggle speaker ON/OFF once. but not force</br>default: false |
| setForceSpeakerphoneOn(`flag: ?boolean`) | :smile: | :smile: | true -> force speaker on</br> false -> force speaker off</br> null -> use default behavior according to media type</br>default: null |
| setMicrophoneMute(`enable: ?boolean`) | :smile: | :rage: | mute/unmute micophone</br>default: false</br>p.s. if you use webrtc, you can just use `track.enabled = false` to mute |
| async checkRecordPermission() | :smile: | :smile: | check record permission without promt. return Promise. see **about permission** section above |
| async requestRecordPermission() | :smile: | :smile: | request record permission to user. return Promise. see **about permission** section above |
| async getAudioUriJS() | :smile: | :smile: | get audio Uri path. this would be useful when you want to pass Uri into another module. |
| startRingtone(`ringtone: string, ?vibrate_pattern: array, ?ios_category: string, ?seconds: number`) | :smile: | :smile: | play ringtone. </br>`ringtone`: '_DEFAULT_' or '_BUNDLE_'</br>`vibrate_pattern`: same as RN, but does not support repeat</br>`ios_category`: ios only, if you want to use specific audio category</br>`seconds`: android only, specify how long do you want to play rather than play once nor repeat. in sec.|
| stopRingtone() | :smile: | :smile: | stop play ringtone if previous started via `startRingtone()` |
| stopRingback() | :smile: | :smile: | stop play ringback if previous started via `start()` |
| setFlashOn(`enable: ?boolean, brightness: ?number`) | :rage: | :smile: | set flash light on/off |
| async getIsWiredHeadsetPluggedIn() | :rage: | :smile: | return wired headset plugged in state |



**Events**

| Event | android | ios | description |
| :--- | :---: | :---: | :--- |
| 'Proximity' | :smile: | :smile: | proximity sensor detected changes.<br>data: `{'isNear': boolean}` |
| 'WiredHeadset'| :smile: | :smile: | fire when wired headset plug/unplug<br>data: `{'isPlugged': boolean, 'hasMic': boolean, 'deviceName': string }` |
| 'NoisyAudio' | :smile: | :rage: | see [andriod doc](http://developer.android.com/reference/android/media/AudioManager.html#ACTION_AUDIO_BECOMING_NOISY).<br>data: `null` |
| 'NoisyAudio' | :smile: | :rage: | see [android doc](http://developer.android.com/reference/android/media/AudioManager.html#ACTION_AUDIO_BECOMING_NOISY).<br>data: `null` |
| 'MediaButton' | :smile: | :rage: | when external device controler pressed button. see [android doc](http://developer.android.com/reference/android/content/Intent.html#ACTION_MEDIA_BUTTON) <br>data: `{'eventText': string, 'eventCode': number }` |
| 'onAudioFocusChange' | :smile: | :rage: | see [andriod doc](http://developer.android.com/reference/android/media/AudioManager.OnAudioFocusChangeListener.html#onAudioFocusChange(int)) <br>data: `{'eventText': string, 'eventCode': number }` |
| 'onAudioFocusChange' | :smile: | :rage: | see [android doc](http://developer.android.com/reference/android/media/AudioManager.OnAudioFocusChangeListener.html#onAudioFocusChange(int)) <br>data: `{'eventText': string, 'eventCode': number }` |

**NOTE: platform OS always has the final decision, so some toggle api may not work in some case
be care when customize your own behavior**
**NOTE: platform OS always has the final decision, so some toggle API may not work in some cases
be careful when customizing your own behavior**

## LICENSE:

**[ISC License](https://opensource.org/licenses/ISC)** ( functionality equivalent to **MIT License** )

## Contributing:

I'm not expert neither on ios nor android, any suggestions, pull request, corrections are really appreciated and welcome.
## Original Author:
[![zxcpoiu](https://github.com/zxcpoiu.png)](https://github.com/zxcpoiu)
22 changes: 22 additions & 0 deletions ReactNativeIncallManager.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'json'

package = JSON.parse(File.read(File.join(__dir__, 'package.json')))

Pod::Spec.new do |s|
s.name = 'ReactNativeIncallManager'
s.version = package['version']
s.summary = package['description']
s.description = package['description']
s.homepage = package['homepage']
s.license = package['license']
s.author = package['author']
s.source = { :git => 'https://github.com/zxcpoiu/react-native-incall-manager.git', :tag => s.version }

s.platform = :ios, '9.0'
s.ios.deployment_target = '8.0'

s.preserve_paths = 'LICENSE', 'package.json'
s.source_files = '**/*.{h,m}'
s.exclude_files = 'example/**/*'
s.dependency 'React-Core'
end
20 changes: 15 additions & 5 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
apply plugin: 'com.android.library'

def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
if (agpVersion.tokenize('.')[0].toInteger() >= 7) {
namespace "com.zxcpoiu.incallmanager"
}

compileSdkVersion safeExtGet('compileSdkVersion', 33)
buildToolsVersion safeExtGet('buildToolsVersion', "30.0.2")

defaultConfig {
minSdkVersion 16
targetSdkVersion 22
minSdkVersion safeExtGet('minSdkVersion', 21)
targetSdkVersion safeExtGet('targetSdkVersion', 30)
versionCode 1
versionName "1.0"
}
}

dependencies {
compile 'com.facebook.react:react-native:+'
implementation 'com.facebook.react:react-native:+'
implementation "androidx.media:media:1.4.3"
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright 2014 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package com.zxcpoiu.incallmanager.AppRTC;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.util.Log;
import androidx.annotation.Nullable;
import com.zxcpoiu.incallmanager.AppRTC.AppRTCUtils;
import com.zxcpoiu.incallmanager.AppRTC.ThreadUtils;
/**
* AppRTCProximitySensor manages functions related to the proximity sensor in
* the AppRTC demo.
* On most device, the proximity sensor is implemented as a boolean-sensor.
* It returns just two values "NEAR" or "FAR". Thresholding is done on the LUX
* value i.e. the LUX value of the light sensor is compared with a threshold.
* A LUX-value more than the threshold means the proximity sensor returns "FAR".
* Anything less than the threshold value and the sensor returns "NEAR".
*/
public class AppRTCProximitySensor implements SensorEventListener {
private static final String TAG = "AppRTCProximitySensor";
// This class should be created, started and stopped on one thread
// (e.g. the main thread). We use `nonThreadSafe` to ensure that this is
// the case. Only active when `DEBUG` is set to true.
private final ThreadUtils.ThreadChecker threadChecker = new ThreadUtils.ThreadChecker();
private final Runnable onSensorStateListener;
private final SensorManager sensorManager;
@Nullable private Sensor proximitySensor;
private boolean lastStateReportIsNear;
/** Construction */
public static AppRTCProximitySensor create(Context context, Runnable sensorStateListener) {
return new AppRTCProximitySensor(context, sensorStateListener);
}
private AppRTCProximitySensor(Context context, Runnable sensorStateListener) {
Log.d(TAG, "AppRTCProximitySensor" + AppRTCUtils.getThreadInfo());
onSensorStateListener = sensorStateListener;
sensorManager = ((SensorManager) context.getSystemService(Context.SENSOR_SERVICE));
}
/**
* Activate the proximity sensor. Also do initialization if called for the
* first time.
*/
public boolean start() {
threadChecker.checkIsOnValidThread();
Log.d(TAG, "start" + AppRTCUtils.getThreadInfo());
if (!initDefaultSensor()) {
// Proximity sensor is not supported on this device.
return false;
}
sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
return true;
}
/** Deactivate the proximity sensor. */
public void stop() {
threadChecker.checkIsOnValidThread();
Log.d(TAG, "stop" + AppRTCUtils.getThreadInfo());
if (proximitySensor == null) {
return;
}
sensorManager.unregisterListener(this, proximitySensor);
}
/** Getter for last reported state. Set to true if "near" is reported. */
public boolean sensorReportsNearState() {
threadChecker.checkIsOnValidThread();
return lastStateReportIsNear;
}
@Override
public final void onAccuracyChanged(Sensor sensor, int accuracy) {
threadChecker.checkIsOnValidThread();
AppRTCUtils.assertIsTrue(sensor.getType() == Sensor.TYPE_PROXIMITY);
if (accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
Log.e(TAG, "The values returned by this sensor cannot be trusted");
}
}
@Override
public final void onSensorChanged(SensorEvent event) {
threadChecker.checkIsOnValidThread();
AppRTCUtils.assertIsTrue(event.sensor.getType() == Sensor.TYPE_PROXIMITY);
// As a best practice; do as little as possible within this method and
// avoid blocking.
float distanceInCentimeters = event.values[0];
if (distanceInCentimeters < proximitySensor.getMaximumRange()) {
Log.d(TAG, "Proximity sensor => NEAR state");
lastStateReportIsNear = true;
} else {
Log.d(TAG, "Proximity sensor => FAR state");
lastStateReportIsNear = false;
}
// Report about new state to listening client. Client can then call
// sensorReportsNearState() to query the current state (NEAR or FAR).
if (onSensorStateListener != null) {
onSensorStateListener.run();
}
Log.d(TAG, "onSensorChanged" + AppRTCUtils.getThreadInfo() + ": "
+ "accuracy=" + event.accuracy + ", timestamp=" + event.timestamp + ", distance="
+ event.values[0]);
}
/**
* Get default proximity sensor if it exists. Tablet devices (e.g. Nexus 7)
* does not support this type of sensor and false will be returned in such
* cases.
*/
private boolean initDefaultSensor() {
if (proximitySensor != null) {
return true;
}
proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (proximitySensor == null) {
return false;
}
logProximitySensorInfo();
return true;
}
/** Helper method for logging information about the proximity sensor. */
private void logProximitySensorInfo() {
if (proximitySensor == null) {
return;
}
StringBuilder info = new StringBuilder("Proximity sensor: ");
info.append("name=").append(proximitySensor.getName());
info.append(", vendor: ").append(proximitySensor.getVendor());
info.append(", power: ").append(proximitySensor.getPower());
info.append(", resolution: ").append(proximitySensor.getResolution());
info.append(", max range: ").append(proximitySensor.getMaximumRange());
info.append(", min delay: ").append(proximitySensor.getMinDelay());
info.append(", type: ").append(proximitySensor.getStringType());
info.append(", max delay: ").append(proximitySensor.getMaxDelay());
info.append(", reporting mode: ").append(proximitySensor.getReportingMode());
info.append(", isWakeUpSensor: ").append(proximitySensor.isWakeUpSensor());
Log.d(TAG, info.toString());
}
}
29 changes: 29 additions & 0 deletions android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Copyright (c) 2011, The WebRTC project authors. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.

* Neither the name of Google nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 changes: 12 additions & 0 deletions android/src/main/java/com/zxcpoiu/incallmanager/AppRTC/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
From WebRTC Source
M64

Files in this library with prefix "AppRTC" are all get from webrtc source.
The license / patents remain it's original. see LICENSE in this directory

This library slightly modified original class/package name to get compiled in.
You can find diffs in `diff` directory as well.

- examples/androidapp/src/org/appspot/apprtc:
* AppRTCBluetoothManager.java
* AppRTCProximitySensor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
--- AppRTCBluetoothManager.orig.java
+++ AppRTCBluetoothManager.java
@@ -7,7 +7,7 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-package org.appspot.apprtc;
+package com.zxcpoiu.incallmanager.AppRTC;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -19,6 +19,7 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.AudioManager;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
@@ -26,8 +27,9 @@
import androidx.annotation.Nullable;
import java.util.List;
import java.util.Set;
-import org.appspot.apprtc.util.AppRTCUtils;
-import org.webrtc.ThreadUtils;
+import com.zxcpoiu.incallmanager.AppRTC.AppRTCUtils;
+import com.zxcpoiu.incallmanager.AppRTC.ThreadUtils;
+import com.zxcpoiu.incallmanager.InCallManagerModule;
/**
* AppRTCProximitySensor manages functions related to Bluetoth devices in the
* AppRTC demo.
@@ -58,7 +60,7 @@
SCO_CONNECTED
}
private final Context apprtcContext;
- private final AppRTCAudioManager apprtcAudioManager;
+ private final InCallManagerModule apprtcAudioManager;
@Nullable
private final AudioManager audioManager;
private final Handler handler;
@@ -183,11 +185,11 @@
}
}
/** Construction. */
- static AppRTCBluetoothManager create(Context context, AppRTCAudioManager audioManager) {
+ public static AppRTCBluetoothManager create(Context context, InCallManagerModule audioManager) {
Log.d(TAG, "create" + AppRTCUtils.getThreadInfo());
return new AppRTCBluetoothManager(context, audioManager);
}
- protected AppRTCBluetoothManager(Context context, AppRTCAudioManager audioManager) {
+ protected AppRTCBluetoothManager(Context context, InCallManagerModule audioManager) {
Log.d(TAG, "ctor");
ThreadUtils.checkIsOnMainThread();
apprtcContext = context;
@@ -219,7 +221,8 @@
public void start() {
ThreadUtils.checkIsOnMainThread();
Log.d(TAG, "start");
- if (!hasPermission(apprtcContext, android.Manifest.permission.BLUETOOTH)) {
+ String p = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? android.Manifest.permission.BLUETOOTH_CONNECT : android.Manifest.permission.BLUETOOTH;
+ if (!hasPermission(apprtcContext, p)) {
Log.w(TAG, "Process (pid=" + Process.myPid() + ") lacks BLUETOOTH permission");
return;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--- AppRTCProximitySensor.orig.java
+++ AppRTCProximitySensor.java
@@ -7,7 +7,7 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-package org.appspot.apprtc;
+package com.zxcpoiu.incallmanager.AppRTC;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
@@ -16,8 +16,8 @@
import android.os.Build;
import android.util.Log;
import androidx.annotation.Nullable;
-import org.appspot.apprtc.util.AppRTCUtils;
-import org.webrtc.ThreadUtils;
+import com.zxcpoiu.incallmanager.AppRTC.AppRTCUtils;
+import com.zxcpoiu.incallmanager.AppRTC.ThreadUtils;
/**
* AppRTCProximitySensor manages functions related to the proximity sensor in
* the AppRTC demo.
@@ -38,7 +38,7 @@
@Nullable private Sensor proximitySensor;
private boolean lastStateReportIsNear;
/** Construction */
- static AppRTCProximitySensor create(Context context, Runnable sensorStateListener) {
+ public static AppRTCProximitySensor create(Context context, Runnable sensorStateListener) {
return new AppRTCProximitySensor(context, sensorStateListener);
}
private AppRTCProximitySensor(Context context, Runnable sensorStateListener) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--- AppRTCUtils.orig.java 2022-05-26 06:35:49.532008067 +0800
+++ AppRTCUtils.java 2022-05-26 06:36:31.007700973 +0800
@@ -7,7 +7,7 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-package org.appspot.apprtc.util;
+package com.zxcpoiu.incallmanager.AppRTC;
import android.os.Build;
import android.util.Log;
/**
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
--- ThreadUtils.orig.java 2022-05-26 06:50:16.889507506 +0800
+++ ThreadUtils.java 2022-05-26 06:49:53.697682611 +0800
@@ -7,14 +7,9 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-package org.webrtc;
-import android.os.Handler;
+package com.zxcpoiu.incallmanager.AppRTC;
import android.os.Looper;
-import android.os.SystemClock;
import androidx.annotation.Nullable;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
public class ThreadUtils {
/**
* Utility class to be used for checking that a method is called on the correct thread.
@@ -41,157 +36,4 @@
throw new IllegalStateException("Not on main thread!");
}
}
- /**
- * Utility interface to be used with executeUninterruptibly() to wait for blocking operations
- * to complete without getting interrupted..
- */
- public interface BlockingOperation { void run() throws InterruptedException; }
- /**
- * Utility method to make sure a blocking operation is executed to completion without getting
- * interrupted. This should be used in cases where the operation is waiting for some critical
- * work, e.g. cleanup, that must complete before returning. If the thread is interrupted during
- * the blocking operation, this function will re-run the operation until completion, and only then
- * re-interrupt the thread.
- */
- public static void executeUninterruptibly(BlockingOperation operation) {
- boolean wasInterrupted = false;
- while (true) {
- try {
- operation.run();
- break;
- } catch (InterruptedException e) {
- // Someone is asking us to return early at our convenience. We can't cancel this operation,
- // but we should preserve the information and pass it along.
- wasInterrupted = true;
- }
- }
- // Pass interruption information along.
- if (wasInterrupted) {
- Thread.currentThread().interrupt();
- }
- }
- public static boolean joinUninterruptibly(final Thread thread, long timeoutMs) {
- final long startTimeMs = SystemClock.elapsedRealtime();
- long timeRemainingMs = timeoutMs;
- boolean wasInterrupted = false;
- while (timeRemainingMs > 0) {
- try {
- thread.join(timeRemainingMs);
- break;
- } catch (InterruptedException e) {
- // Someone is asking us to return early at our convenience. We can't cancel this operation,
- // but we should preserve the information and pass it along.
- wasInterrupted = true;
- final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs;
- timeRemainingMs = timeoutMs - elapsedTimeMs;
- }
- }
- // Pass interruption information along.
- if (wasInterrupted) {
- Thread.currentThread().interrupt();
- }
- return !thread.isAlive();
- }
- public static void joinUninterruptibly(final Thread thread) {
- executeUninterruptibly(new BlockingOperation() {
- @Override
- public void run() throws InterruptedException {
- thread.join();
- }
- });
- }
- public static void awaitUninterruptibly(final CountDownLatch latch) {
- executeUninterruptibly(new BlockingOperation() {
- @Override
- public void run() throws InterruptedException {
- latch.await();
- }
- });
- }
- public static boolean awaitUninterruptibly(CountDownLatch barrier, long timeoutMs) {
- final long startTimeMs = SystemClock.elapsedRealtime();
- long timeRemainingMs = timeoutMs;
- boolean wasInterrupted = false;
- boolean result = false;
- do {
- try {
- result = barrier.await(timeRemainingMs, TimeUnit.MILLISECONDS);
- break;
- } catch (InterruptedException e) {
- // Someone is asking us to return early at our convenience. We can't cancel this operation,
- // but we should preserve the information and pass it along.
- wasInterrupted = true;
- final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs;
- timeRemainingMs = timeoutMs - elapsedTimeMs;
- }
- } while (timeRemainingMs > 0);
- // Pass interruption information along.
- if (wasInterrupted) {
- Thread.currentThread().interrupt();
- }
- return result;
- }
- /**
- * Post `callable` to `handler` and wait for the result.
- */
- public static <V> V invokeAtFrontUninterruptibly(
- final Handler handler, final Callable<V> callable) {
- if (handler.getLooper().getThread() == Thread.currentThread()) {
- try {
- return callable.call();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- // Place-holder classes that are assignable inside nested class.
- class CaughtException {
- Exception e;
- }
- class Result {
- public V value;
- }
- final Result result = new Result();
- final CaughtException caughtException = new CaughtException();
- final CountDownLatch barrier = new CountDownLatch(1);
- handler.post(new Runnable() {
- @Override
- public void run() {
- try {
- result.value = callable.call();
- } catch (Exception e) {
- caughtException.e = e;
- }
- barrier.countDown();
- }
- });
- awaitUninterruptibly(barrier);
- // Re-throw any runtime exception caught inside the other thread. Since this is an invoke, add
- // stack trace for the waiting thread as well.
- if (caughtException.e != null) {
- final RuntimeException runtimeException = new RuntimeException(caughtException.e);
- runtimeException.setStackTrace(
- concatStackTraces(caughtException.e.getStackTrace(), runtimeException.getStackTrace()));
- throw runtimeException;
- }
- return result.value;
- }
- /**
- * Post `runner` to `handler`, at the front, and wait for completion.
- */
- public static void invokeAtFrontUninterruptibly(final Handler handler, final Runnable runner) {
- invokeAtFrontUninterruptibly(handler, new Callable<Void>() {
- @Override
- public Void call() {
- runner.run();
- return null;
- }
- });
- }
- static StackTraceElement[] concatStackTraces(
- StackTraceElement[] inner, StackTraceElement[] outer) {
- final StackTraceElement[] combined = new StackTraceElement[inner.length + outer.length];
- System.arraycopy(inner, 0, combined, 0, inner.length);
- System.arraycopy(outer, 0, combined, inner.length, outer.length);
- return combined;
- }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2014 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package com.zxcpoiu.incallmanager.AppRTC;
import android.os.Build;
import android.util.Log;
/**
* AppRTCUtils provides helper functions for managing thread safety.
*/
public final class AppRTCUtils {
private AppRTCUtils() {}
/** Helper method which throws an exception when an assertion has failed. */
public static void assertIsTrue(boolean condition) {
if (!condition) {
throw new AssertionError("Expected condition to be true");
}
}
/** Helper method for building a string of thread information.*/
public static String getThreadInfo() {
return "@[name=" + Thread.currentThread().getName() + ", id=" + Thread.currentThread().getId()
+ "]";
}
/** Information about the current build, taken from system properties. */
public static void logDeviceInfo(String tag) {
Log.d(tag, "Android SDK: " + Build.VERSION.SDK_INT + ", "
+ "Release: " + Build.VERSION.RELEASE + ", "
+ "Brand: " + Build.BRAND + ", "
+ "Device: " + Build.DEVICE + ", "
+ "Id: " + Build.ID + ", "
+ "Hardware: " + Build.HARDWARE + ", "
+ "Manufacturer: " + Build.MANUFACTURER + ", "
+ "Model: " + Build.MODEL + ", "
+ "Product: " + Build.PRODUCT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package com.zxcpoiu.incallmanager.AppRTC;
import android.os.Looper;
import androidx.annotation.Nullable;
public class ThreadUtils {
/**
* Utility class to be used for checking that a method is called on the correct thread.
*/
public static class ThreadChecker {
@Nullable private Thread thread = Thread.currentThread();
public void checkIsOnValidThread() {
if (thread == null) {
thread = Thread.currentThread();
}
if (Thread.currentThread() != thread) {
throw new IllegalStateException("Wrong thread");
}
}
public void detachThread() {
thread = null;
}
}
/**
* Throws exception if called from other than main thread.
*/
public static void checkIsOnMainThread() {
if (Thread.currentThread() != Looper.getMainLooper().getThread()) {
throw new IllegalStateException("Not on main thread!");
}
}
}
1,507 changes: 865 additions & 642 deletions android/src/main/java/com/zxcpoiu/incallmanager/InCallManagerModule.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* Copyright (c) 2017 Henry Lin @zxcpoiu
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

package com.zxcpoiu.incallmanager;

import com.facebook.react.ReactPackage;
@@ -16,7 +32,7 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
return Collections.<NativeModule>singletonList(new InCallManagerModule(reactContext));
}

@Override
// Deprecated RN 0.47
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@@ -26,7 +42,4 @@ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext
return Collections.emptyList();
}

public static void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
InCallManagerModule.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* Copyright (c) 2017 Henry Lin @zxcpoiu
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

package com.zxcpoiu.incallmanager;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.Runnable;

import com.facebook.react.bridge.UiThreadUtil;

import com.zxcpoiu.incallmanager.AppRTC.AppRTCProximitySensor;

public class InCallProximityManager {
private static final String TAG = "InCallProximityManager";

private WakeLock mProximityLock = null;
private Method mPowerManagerRelease;
private boolean proximitySupported = false;
private AppRTCProximitySensor proximitySensor = null;

/** Construction */
static InCallProximityManager create(Context context, final InCallManagerModule inCallManager) {
return new InCallProximityManager(context, inCallManager);
}

private InCallProximityManager(Context context, final InCallManagerModule inCallManager) {
Log.d(TAG, "InCallProximityManager");
checkProximitySupport(context);
if (proximitySupported) {
UiThreadUtil.runOnUiThread(() -> {
proximitySensor = AppRTCProximitySensor.create(context, () -> {
inCallManager.onProximitySensorChangedState(proximitySensor.sensorReportsNearState());
});
});
}
}

private void checkProximitySupport(Context context) {
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) == null) {
proximitySupported = false;
return;
}

PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);

proximitySupported = true;

// --- Check if PROXIMITY_SCREEN_OFF_WAKE_LOCK is implemented.
try {
boolean _proximitySupported = false;
Field field = PowerManager.class.getDeclaredField("PROXIMITY_SCREEN_OFF_WAKE_LOCK");
int proximityScreenOffWakeLock = (Integer) field.get(null);

if (android.os.Build.VERSION.SDK_INT < 17) {
Method method = powerManager.getClass().getDeclaredMethod("getSupportedWakeLockFlags");
int powerManagerSupportedFlags = (Integer) method.invoke(powerManager);
_proximitySupported = ((powerManagerSupportedFlags & proximityScreenOffWakeLock) != 0x0);
} else {
// --- android 4.2+
Method method = powerManager.getClass().getDeclaredMethod("isWakeLockLevelSupported", int.class);
_proximitySupported = (Boolean) method.invoke(powerManager, proximityScreenOffWakeLock);
}

if (_proximitySupported) {
mProximityLock = powerManager.newWakeLock(proximityScreenOffWakeLock, TAG);
mProximityLock.setReferenceCounted(false);
}
} catch (Exception e) {
Log.d(TAG, "Failed to get proximity screen locker. exception: ", e);
}

if (mProximityLock != null) {
Log.d(TAG, "use native screen locker...");
try {
mPowerManagerRelease = mProximityLock.getClass().getDeclaredMethod("release", int.class);
} catch (Exception e) {
Log.d(TAG, "failed to get proximity screen locker: `release()`. exception: ", e);
}
} else {
Log.d(TAG, "fallback to old school screen locker...");
}
}

public boolean start() {
if (!proximitySupported) {
return false;
}
UiThreadUtil.runOnUiThread(() -> {
proximitySensor.start();
});
return true;
}

public void stop() {
UiThreadUtil.runOnUiThread(() -> {
proximitySensor.stop();
});
}

public boolean isProximitySupported() {
return proximitySupported;
}

public boolean isProximityWakeLockSupported() {
return mProximityLock != null;
}

public boolean getProximityIsNear() {
return (proximitySupported) ? proximitySensor.sensorReportsNearState() : false;
}

public void acquireProximityWakeLock() {
if (!isProximityWakeLockSupported()) {
return;
}
synchronized (mProximityLock) {
if (!mProximityLock.isHeld()) {
Log.d(TAG, "acquireProximityWakeLock()");
mProximityLock.acquire();
}
}
}

public void releaseProximityWakeLock(final boolean waitForNoProximity) {
if (!isProximityWakeLockSupported()) {
return;
}
synchronized (mProximityLock) {
if (mProximityLock.isHeld()) {
try {
int flags = waitForNoProximity ? PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY : 0;
mPowerManagerRelease.invoke(mProximityLock, flags);
Log.d(TAG, "releaseProximityWakeLock()");
} catch (Exception e) {
Log.e(TAG, "failed to release proximity lock. e: ", e);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright (c) 2017 Henry Lin @zxcpoiu
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

package com.zxcpoiu.incallmanager;

import android.content.Context;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;

public class InCallWakeLockUtils {
private static final String TAG = "InCallWakeLockUtils";

private PowerManager mPowerManager;

private WakeLock mFullLock = null;
private WakeLock mPokeFullLock = null;
private WakeLock mPartialLock = null;


public InCallWakeLockUtils(Context context) {
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);

mFullLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, TAG);
mFullLock.setReferenceCounted(false);

mPartialLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mPartialLock.setReferenceCounted(false);

mPokeFullLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, TAG);
mPokeFullLock.setReferenceCounted(false);
}

private boolean _acquireWakeLock(WakeLock lock) {
return _acquireWakeLock(lock, 0);
}

private boolean _acquireWakeLock(WakeLock lock, long timeout) {
synchronized (lock) {
if (!lock.isHeld()) {
if (timeout > 0) {
lock.acquire(timeout);
} else {
lock.acquire();
}
return true;
}
}
return false;
}

private boolean _releaseWakeLock(WakeLock lock) {
synchronized (lock) {
if (lock.isHeld()) {
lock.release();
return true;
}
}
return false;
}

public boolean acquireFullWakeLock() {
boolean sta = _acquireWakeLock(mFullLock);
Log.d(TAG, "acquireFullWakeLock(). sta=" + sta);
return sta;
}

public boolean releaseFullWakeLock() {
boolean sta = _releaseWakeLock(mFullLock);
Log.d(TAG, "releaseFullWakeLock(). sta=" + sta);
return sta;
}

public boolean acquirePokeFullWakeLock() {
boolean sta = _acquireWakeLock(mPokeFullLock);
Log.d(TAG, "acquirePokeFullWakeLock(). sta=" + sta);
return sta;
}

public boolean releasePokeFullWakeLock() {
boolean sta = _releaseWakeLock(mPokeFullLock);
Log.d(TAG, "releasePokeFullWakeLock(). sta=" + sta);
return sta;
}

public boolean acquirePartialWakeLock() {
boolean sta = _acquireWakeLock(mPartialLock);
Log.d(TAG, "acquirePartialWakeLock(). sta=" + sta);
return sta;
}

public boolean releasePartialWakeLock() {
boolean sta = _releaseWakeLock(mPartialLock);
Log.d(TAG, "releasePartialWakeLock(). sta=" + sta);
return sta;
}

public boolean acquirePokeFullWakeLockReleaseAfter(long timeout) {
boolean sta = _acquireWakeLock(mPokeFullLock, timeout);
Log.d(TAG, String.format("acquirePokeFullWakeLockReleaseAfter() timeout=%s, sta=%s", timeout, sta));
return sta;
}
}
64 changes: 64 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
declare class InCallManager {
vibrate: boolean;
audioUriMap: {
ringtone: { _BUNDLE_: null; _DEFAULT_: null };
ringback: { _BUNDLE_: null; _DEFAULT_: null };
busytone: { _BUNDLE_: null; _DEFAULT_: null };
};

constructor();

start(setup?: {
auto?: boolean;
media?: "video" | "audio";
ringback?: string;
}): void;

stop(setup?: { busytone?: string }): void;

turnScreenOff(): void;

turnScreenOn(): void;

getIsWiredHeadsetPluggedIn(): Promise<{ isWiredHeadsetPluggedIn: boolean }>;

setFlashOn(enable: boolean, brightness: number): void;

setKeepScreenOn(enable: boolean): void;

setSpeakerphoneOn(enable: boolean): void;

setForceSpeakerphoneOn(flag: boolean): void;

setMicrophoneMute(enable: boolean): void;

startRingtone(
ringtone: string,
vibrate_pattern: number | number[],
ios_category: string,
seconds: number
): void;

stopRingtone(): void;

startProximitySensor(): void;

stopProximitySensor(): void;

startRingback(ringback: string): void;

stopRingback(): void;

pokeScreen(timeout: number): void;

getAudioUri(audioType: string, fileType: string): Promise<string | null>;

chooseAudioRoute(route: string): Promise<any>;

requestAudioFocus(): Promise<any>;

abandonAudioFocus(): Promise<any>;
}

declare const inCallManager: InCallManager;
export default inCallManager;
97 changes: 54 additions & 43 deletions index.js
Original file line number Diff line number Diff line change
@@ -8,19 +8,11 @@ import {
class InCallManager {
constructor() {
this.vibrate = false;
this.recordPermission = 'unknow';
this.caeraPermission = 'unknow';
this.audioUriMap = {
ringtone: { _BUNDLE_: null, _DEFAULT_: null},
ringback: { _BUNDLE_: null, _DEFAULT_: null},
busytone: { _BUNDLE_: null, _DEFAULT_: null},
};
this.checkRecordPermission = this.checkRecordPermission.bind(this);
this.requestRecordPermission = this.requestRecordPermission.bind(this);
this.checkCameraPermission = this.checkCameraPermission.bind(this);
this.requestCameraPermission = this.requestCameraPermission.bind(this);
this.checkRecordPermission();
this.checkCameraPermission();
}

start(setup) {
@@ -45,6 +37,22 @@ class InCallManager {
_InCallManager.turnScreenOn();
}

async getIsWiredHeadsetPluggedIn() {
let isPluggedIn = await _InCallManager.getIsWiredHeadsetPluggedIn();
return { isWiredHeadsetPluggedIn: isPluggedIn };
}

setFlashOn(enable, brightness) {
if (Platform.OS === 'ios') {
enable = (enable === true) ? true : false;
brightness = (typeof brightness === 'number') ? brightness : 0;
_InCallManager.setFlashOn(enable, brightness);
} else {
console.log("Android doesn't support setFlashOn(enable, brightness)");
}
}


setKeepScreenOn(enable) {
enable = (enable === true) ? true : false;
_InCallManager.setKeepScreenOn(enable);
@@ -65,24 +73,21 @@ class InCallManager {
_InCallManager.setMicrophoneMute(enable);
}

startRingtone(ringtone, vibrate, ios_category) {
startRingtone(ringtone, vibrate_pattern, ios_category, seconds) {
ringtone = (typeof ringtone === 'string') ? ringtone : "_DEFAULT_";
vibrate = (vibrate === true) ? true : false;
this.vibrate = (Array.isArray(vibrate_pattern)) ? true : false;
ios_category = (ios_category === 'playback') ? 'playback' : "default";
seconds = (typeof seconds === 'number' && seconds > 0) ? parseInt(seconds) : -1; // --- android only, default looping

if (Platform.OS === 'android') {
_InCallManager.startRingtone(ringtone);
_InCallManager.startRingtone(ringtone, seconds);
} else {
_InCallManager.startRingtone(ringtone, ios_category);
}

this.vibrate = vibrate;
// --- should not use repeat, it may cause infinite loop in some cases.
if (this.vibrate) {
if (Platform.OS === 'android') {
Vibration.vibrate([0, 1000, 3000], true);
} else {
this.vibrate = false;
}
Vibration.vibrate(vibrate_pattern, false); // --- ios needs RN 0.34 to support vibration pattern
}
}

@@ -93,41 +98,26 @@ class InCallManager {
_InCallManager.stopRingtone();
}

stopRingback() {
_InCallManager.stopRingback();
}

async checkRecordPermission() {
// --- on android which api < 23, it will always be "granted"
let result = await _InCallManager.checkRecordPermission();
this.recordPermission = result;
return result;
startProximitySensor() {
_InCallManager.startProximitySensor();
}

async requestRecordPermission() {
// --- on android which api < 23, it will always be "granted"
let result = await _InCallManager.requestRecordPermission();
this.recordPermission = result;
return result;

stopProximitySensor() {
_InCallManager.stopProximitySensor();
}

async checkCameraPermission() {
// --- on android which api < 23, it will always be "granted"
let result = await _InCallManager.checkCameraPermission();
this.cameraPermission = result;
return result;
startRingback(ringback) {
ringback = (typeof ringback === 'string') ? ringback : "_DTMF_";
_InCallManager.startRingback(ringback);
}

async requestCameraPermission() {
// --- on android which api < 23, it will always be "granted"
let result = await _InCallManager.requestCameraPermission();
this.cameraPermission = result;
return result;
stopRingback() {
_InCallManager.stopRingback();
}

pokeScreen(_timeout) {
if (Platform.OS === 'android') {
let timeout = (typeof _timeout === "number" && _timeout > 0) ? _timeout : 0;
let timeout = (typeof _timeout === "number" && _timeout > 0) ? _timeout : 3000; // --- default 3000 ms
_InCallManager.pokeScreen(timeout);
} else {
console.log("ios doesn't support pokeScreen()");
@@ -154,6 +144,27 @@ class InCallManager {
}
}
}

async chooseAudioRoute(route) {
let result = await _InCallManager.chooseAudioRoute(route);
return result;
}

async requestAudioFocus() {
if (Platform.OS === 'android') {
return await _InCallManager.requestAudioFocusJS();
} else {
console.log("ios doesn't support requestAudioFocus()");
}
}

async abandonAudioFocus() {
if (Platform.OS === 'android') {
return await _InCallManager.abandonAudioFocusJS();
} else {
console.log("ios doesn't support requestAudioFocus()");
}
}
}

export default new InCallManager();
283 changes: 283 additions & 0 deletions ios/RNInCallManager.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 48;
objects = {

/* Begin PBXBuildFile section */
231CD25B1FD68A17004DD25D /* RNInCallManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 231CD25A1FD68A17004DD25D /* RNInCallManager.m */; };
231CD25C1FD68A17004DD25D /* RNInCallManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 231CD2591FD68A17004DD25D /* RNInCallManager.h */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
231CD2541FD68A17004DD25D /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
231CD25C1FD68A17004DD25D /* RNInCallManager.h in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
231CD2561FD68A17004DD25D /* libRNInCallManager.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNInCallManager.a; sourceTree = BUILT_PRODUCTS_DIR; };
231CD2591FD68A17004DD25D /* RNInCallManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNInCallManager.h; sourceTree = "<group>"; };
231CD25A1FD68A17004DD25D /* RNInCallManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNInCallManager.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
231CD2531FD68A17004DD25D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
231CD24D1FD68A17004DD25D = {
isa = PBXGroup;
children = (
231CD2581FD68A17004DD25D /* RNInCallManager */,
231CD2571FD68A17004DD25D /* Products */,
);
sourceTree = "<group>";
};
231CD2571FD68A17004DD25D /* Products */ = {
isa = PBXGroup;
children = (
231CD2561FD68A17004DD25D /* libRNInCallManager.a */,
);
name = Products;
sourceTree = "<group>";
};
231CD2581FD68A17004DD25D /* RNInCallManager */ = {
isa = PBXGroup;
children = (
231CD2591FD68A17004DD25D /* RNInCallManager.h */,
231CD25A1FD68A17004DD25D /* RNInCallManager.m */,
);
path = RNInCallManager;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
231CD2551FD68A17004DD25D /* RNInCallManager */ = {
isa = PBXNativeTarget;
buildConfigurationList = 231CD25F1FD68A17004DD25D /* Build configuration list for PBXNativeTarget "RNInCallManager" */;
buildPhases = (
231CD2521FD68A17004DD25D /* Sources */,
231CD2531FD68A17004DD25D /* Frameworks */,
231CD2541FD68A17004DD25D /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = RNInCallManager;
productName = RNInCallManager;
productReference = 231CD2561FD68A17004DD25D /* libRNInCallManager.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
231CD24E1FD68A17004DD25D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = zxcpoiu;
TargetAttributes = {
231CD2551FD68A17004DD25D = {
CreatedOnToolsVersion = 9.1;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 231CD2511FD68A17004DD25D /* Build configuration list for PBXProject "RNInCallManager" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 231CD24D1FD68A17004DD25D;
productRefGroup = 231CD2571FD68A17004DD25D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
231CD2551FD68A17004DD25D /* RNInCallManager */,
);
};
/* End PBXProject section */

/* Begin PBXSourcesBuildPhase section */
231CD2521FD68A17004DD25D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
231CD25B1FD68A17004DD25D /* RNInCallManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */

/* Begin XCBuildConfiguration section */
231CD25D1FD68A17004DD25D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
231CD25E1FD68A17004DD25D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
231CD2601FD68A17004DD25D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
231CD2611FD68A17004DD25D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
231CD2511FD68A17004DD25D /* Build configuration list for PBXProject "RNInCallManager" */ = {
isa = XCConfigurationList;
buildConfigurations = (
231CD25D1FD68A17004DD25D /* Debug */,
231CD25E1FD68A17004DD25D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
231CD25F1FD68A17004DD25D /* Build configuration list for PBXNativeTarget "RNInCallManager" */ = {
isa = XCConfigurationList;
buildConfigurations = (
231CD2601FD68A17004DD25D /* Debug */,
231CD2611FD68A17004DD25D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 231CD24E1FD68A17004DD25D /* Project object */;
}
13 changes: 0 additions & 13 deletions ios/RNInCallManager/RNInCallManager-Bridging-Header.h

This file was deleted.

17 changes: 17 additions & 0 deletions ios/RNInCallManager/RNInCallManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// RNInCallManager.h
// RNInCallManager
//
// Created by Ian Yu-Hsun Lin (@ianlin) on 05/12/2017.
// Copyright © 2017 zxcpoiu. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>

#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

@interface RNInCallManager : RCTEventEmitter <RCTBridgeModule, AVAudioPlayerDelegate>

@end
1,284 changes: 1,284 additions & 0 deletions ios/RNInCallManager/RNInCallManager.m

Large diffs are not rendered by default.

969 changes: 0 additions & 969 deletions ios/RNInCallManager/RNInCallManager.swift

This file was deleted.

29 changes: 0 additions & 29 deletions ios/RNInCallManager/RNInCallManagerBridge.m

This file was deleted.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"name": "react-native-incall-manager",
"version": "1.5.0",
"version": "4.2.0",
"description": "Handling media-routes/sensors/events during a audio/video chat on React Native",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/zxcpoiu/react-native-incall-manager.git"
"url": "git+https://github.com/react-native-webrtc/react-native-incall-manager.git"
},
"keywords": [
"React",
@@ -24,10 +24,10 @@
"author": "Henry Lin <zxcpoiu@gmail.com>",
"license": "ISC",
"bugs": {
"url": "https://github.com/zxcpoiu/react-native-incall-manager/issues"
"url": "https://github.com/react-native-webrtc/react-native-incall-manager/issues"
},
"homepage": "https://github.com/zxcpoiu/react-native-incall-manager#readme",
"homepage": "https://github.com/react-native-webrtc/react-native-incall-manager#readme",
"peerDependencies": {
"react-native": ">=0.19.0"
"react-native": ">=0.40.0"
}
}