1717
1818package io .wazo .callkeep ;
1919
20+ import android .Manifest ;
21+ import android .app .Activity ;
22+ import android .content .BroadcastReceiver ;
2023import android .content .ComponentName ;
2124import android .content .Context ;
22- import android .content .BroadcastReceiver ;
25+ import android .content .Intent ;
26+ import android .content .IntentFilter ;
2327import android .content .pm .ApplicationInfo ;
2428import android .content .pm .PackageManager ;
25- import android .content .IntentFilter ;
26- import android .content .Intent ;
29+ import android .net .Uri ;
30+ import android .os .Build ;
31+ import android .os .Bundle ;
32+ import android .support .annotation .Nullable ;
2733import android .support .v4 .app .ActivityCompat ;
2834import android .support .v4 .content .ContextCompat ;
2935import android .support .v4 .content .LocalBroadcastManager ;
30- import android .support .annotation .Nullable ;
31-
32- import android .accounts .AccountManager ;
33- import android .accounts .Account ;
34- import android .telecom .DisconnectCause ;
3536import android .telecom .Connection ;
36- import android .telecom .PhoneAccountHandle ;
37+ import android .telecom .DisconnectCause ;
3738import android .telecom .PhoneAccount ;
39+ import android .telecom .PhoneAccountHandle ;
3840import android .telecom .TelecomManager ;
3941
40- import com .facebook .react .bridge .NativeModule ;
42+ import com .facebook .react .bridge .Arguments ;
43+ import com .facebook .react .bridge .Promise ;
4144import com .facebook .react .bridge .ReactApplicationContext ;
42- import com .facebook .react .bridge .ReactContext ;
4345import com .facebook .react .bridge .ReactContextBaseJavaModule ;
4446import com .facebook .react .bridge .ReactMethod ;
4547import com .facebook .react .bridge .WritableMap ;
46- import com .facebook .react .bridge .Arguments ;
47- import com .facebook .react .bridge .Promise ;
4848import com .facebook .react .modules .core .DeviceEventManagerModule .RCTDeviceEventEmitter ;
4949
50- import android .os .Bundle ;
51- import android .os .Build ;
52- import android .net .Uri ;
53- import android .app .Activity ;
54- import android .Manifest ;
55-
56- import java .util .Map ;
57- import java .util .HashMap ;
58- import java .util .List ;
59- import java .lang .SecurityException ;
60-
6150// @see https://github.com/kbagchiGWC/voice-quickstart-android/blob/9a2aff7fbe0d0a5ae9457b48e9ad408740dfb968/exampleConnectionService/src/main/java/com/twilio/voice/examples/connectionservice/VoiceConnectionServiceActivity.java
6251public class RNCallKeepModule extends ReactContextBaseJavaModule {
6352 public static final int REQUEST_READ_PHONE_STATE = 394858 ;
@@ -73,14 +62,15 @@ public class RNCallKeepModule extends ReactContextBaseJavaModule {
7362 public static final String ACTION_HOLD_CALL = "ACTION_HOLD_CALL" ;
7463 public static final String ACTION_UNHOLD_CALL = "ACTION_UNHOLD_CALL" ;
7564 public static final String ACTION_ONGOING_CALL = "ACTION_ONGOING_CALL" ;
65+ public static final String ACTION_AUDIO_SESSION = "ACTION_AUDIO_SESSION" ;
7666
7767 private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST" ;
7868 private static final String REACT_NATIVE_MODULE_NAME = "RNCallKeep" ;
7969
8070 private static TelecomManager telecomManager ;
8171 private static Promise hasPhoneAccountPromise ;
8272 private ReactApplicationContext reactContext ;
83- private PhoneAccountHandle pah ;
73+ private static PhoneAccountHandle handle ;
8474 private boolean isReceiverRegistered = false ;
8575 private VoiceBroadcastReceiver voiceBroadcastReceiver ;
8676
@@ -115,7 +105,7 @@ public String getName() {
115105
116106 @ ReactMethod
117107 public void displayIncomingCall (String number , String callerName ) {
118- if (!this . hasPhoneAccount ()) {
108+ if (!isAvailable () || ! hasPhoneAccount ()) {
119109 return ;
120110 }
121111
@@ -125,12 +115,30 @@ public void displayIncomingCall(String number, String callerName) {
125115 extras .putParcelable (TelecomManager .EXTRA_INCOMING_CALL_ADDRESS , uri );
126116 extras .putString (EXTRA_CALLER_NAME , callerName );
127117
128- telecomManager .addNewIncomingCall (this .pah , extras );
118+ telecomManager .addNewIncomingCall (handle , extras );
119+ }
120+
121+ @ ReactMethod
122+ public void startCall (String number , String callerName ) {
123+ if (!isAvailable () || !hasPhoneAccount ()) {
124+ return ;
125+ }
126+
127+ Bundle extras = new Bundle ();
128+ Uri uri = Uri .fromParts (PhoneAccount .SCHEME_TEL , number , null );
129+
130+ Bundle callExtras = new Bundle ();
131+ callExtras .putString (EXTRA_CALLER_NAME , callerName );
132+
133+ extras .putParcelable (TelecomManager .EXTRA_PHONE_ACCOUNT_HANDLE , handle );
134+ extras .putParcelable (TelecomManager .EXTRA_OUTGOING_CALL_EXTRAS , callExtras );
135+
136+ telecomManager .placeCall (uri , extras );
129137 }
130138
131139 @ ReactMethod
132140 public void endCall () {
133- if (!hasPhoneAccount ()) {
141+ if (!isAvailable () || ! hasPhoneAccount ()) {
134142 return ;
135143 }
136144
@@ -156,7 +164,8 @@ public void checkPhoneAccountPermission(Promise promise) {
156164 }
157165
158166 hasPhoneAccountPromise = promise ;
159- if (!this .checkPermission (Manifest .permission .READ_PHONE_STATE , REQUEST_READ_PHONE_STATE )) {
167+ String [] permissions = { Manifest .permission .READ_PHONE_STATE , Manifest .permission .CALL_PHONE };
168+ if (!this .checkPermissions (permissions , REQUEST_READ_PHONE_STATE )) {
160169 return ;
161170 }
162171
@@ -201,17 +210,19 @@ public static Boolean isAvailable() {
201210 }
202211
203212 private void registerPhoneAccount (Context appContext ) {
213+ if (!isAvailable ()) {
214+ return ;
215+ }
216+
204217 ComponentName cName = new ComponentName (this .getAppContext (), VoiceConnectionService .class );
205218 String appName = this .getApplicationName (appContext );
206219
207- this . pah = new PhoneAccountHandle (cName , appName );
220+ handle = new PhoneAccountHandle (cName , appName );
208221
209- PhoneAccount account = new PhoneAccount .Builder (pah , appName )
222+ PhoneAccount account = new PhoneAccount .Builder (handle , appName )
210223 .setCapabilities (PhoneAccount .CAPABILITY_CALL_PROVIDER )
211224 .build ();
212225
213- PhoneAccountHandle handle = new PhoneAccountHandle (cName , appName );
214-
215226 telecomManager = (TelecomManager ) this .getAppContext ().getSystemService (this .getAppContext ().TELECOM_SERVICE );
216227 telecomManager .registerPhoneAccount (account );
217228 }
@@ -227,32 +238,30 @@ private String getApplicationName(Context appContext) {
227238 return stringId == 0 ? applicationInfo .nonLocalizedLabel .toString () : appContext .getString (stringId );
228239 }
229240
230- private Boolean checkPermission (String name , int id ) {
241+ private Boolean checkPermissions (String [] permissions , int id ) {
231242 Activity currentActivity = this .getCurrentActivity ();
232- int permissionCheck = ContextCompat .checkSelfPermission (currentActivity , name );
233243
234- if (permissionCheck != PackageManager .PERMISSION_GRANTED ) {
235- ActivityCompat .requestPermissions (currentActivity , new String []{name }, id );
236- return false ;
244+ boolean hasPermissions = true ;
245+ for (String permission : permissions ) {
246+ int permissionCheck = ContextCompat .checkSelfPermission (currentActivity , permission );
247+ if (permissionCheck != PackageManager .PERMISSION_GRANTED ) {
248+ hasPermissions = false ;
249+ }
237250 }
238251
239- return true ;
252+ if (!hasPermissions ) {
253+ ActivityCompat .requestPermissions (currentActivity , permissions , id );
254+ }
255+
256+ return hasPermissions ;
240257 }
241258
242259 private static boolean hasPhoneAccount () {
243260 if (!isAvailable ()) {
244261 return false ;
245262 }
246263
247- List <PhoneAccountHandle > enabledAccounts = telecomManager .getCallCapablePhoneAccounts ();
248-
249- for (PhoneAccountHandle account : enabledAccounts ) {
250- if (account .getComponentName ().getClassName ().equals (VoiceConnectionService .class .getCanonicalName ())) {
251- return true ;
252- }
253- }
254-
255- return false ;
264+ return telecomManager .getPhoneAccount (handle ).isEnabled ();
256265 }
257266
258267 private void registerReceiver () {
@@ -266,6 +275,7 @@ private void registerReceiver() {
266275 intentFilter .addAction (ACTION_UNHOLD_CALL );
267276 intentFilter .addAction (ACTION_HOLD_CALL );
268277 intentFilter .addAction (ACTION_ONGOING_CALL );
278+ intentFilter .addAction (ACTION_AUDIO_SESSION );
269279 LocalBroadcastManager .getInstance (this .reactContext ).registerReceiver (voiceBroadcastReceiver , intentFilter );
270280 isReceiverRegistered = true ;
271281 }
@@ -313,6 +323,9 @@ public void onReceive(Context context, Intent intent) {
313323
314324 sendEventToJS ("RNCallKeepDidReceiveStartCallAction" , args );
315325 break ;
326+ case ACTION_AUDIO_SESSION :
327+ sendEventToJS ("RNCallKeepDidActivateAudioSession" , null );
328+ break ;
316329 }
317330 }
318331 }
0 commit comments