Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Sign in
Toggle navigation
T
testCallkeep
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Container Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Yuri Bondarenko
testCallkeep
Commits
0ee17cc7
Commit
0ee17cc7
authored
Jan 20, 2022
by
Yuri Bondarenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
up
parent
5fd20849
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
157 additions
and
322 deletions
+157
-322
App.js
App.js
+0
-322
App.tsx
App.tsx
+150
-0
README.md
README.md
+5
-0
android/app/src/main/AndroidManifest.xml
android/app/src/main/AndroidManifest.xml
+2
-0
No files found.
App.js
deleted
100644 → 0
View file @
5fd20849
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
{
Platform
,
StyleSheet
,
Text
,
View
,
TouchableOpacity
,
ScrollView
,
}
from
'
react-native
'
;
import
{
v4
as
uuidv4
}
from
'
uuid
'
;
import
RNCallKeep
from
'
react-native-callkeep
'
;
import
BackgroundTimer
from
'
react-native-background-timer
'
;
import
DeviceInfo
from
'
react-native-device-info
'
;
BackgroundTimer
.
start
();
const
hitSlop
=
{
top
:
10
,
left
:
10
,
right
:
10
,
bottom
:
10
};
const
styles
=
StyleSheet
.
create
({
container
:
{
flex
:
1
,
marginTop
:
20
,
backgroundColor
:
'
#fff
'
,
alignItems
:
'
center
'
,
justifyContent
:
'
center
'
,
},
button
:
{
marginTop
:
20
,
marginBottom
:
20
,
},
callButtons
:
{
flexDirection
:
'
row
'
,
justifyContent
:
'
space-between
'
,
paddingHorizontal
:
30
,
width
:
'
100%
'
,
},
logContainer
:
{
flex
:
3
,
width
:
'
100%
'
,
backgroundColor
:
'
#D9D9D9
'
,
},
log
:
{
fontSize
:
10
,
},
});
RNCallKeep
.
setup
({
ios
:
{
appName
:
'
CallKeepDemo
'
,
},
android
:
{
alertTitle
:
'
Permissions required
'
,
alertDescription
:
'
This application needs to access your phone accounts
'
,
cancelButton
:
'
Cancel
'
,
okButton
:
'
ok
'
,
},
});
const
getNewUuid
=
()
=>
uuidv4
().
toLowerCase
();
const
format
=
uuid
=>
uuid
.
split
(
'
-
'
)[
0
];
const
getRandomNumber
=
()
=>
String
(
Math
.
floor
(
Math
.
random
()
*
100000
));
const
isIOS
=
Platform
.
OS
===
'
ios
'
;
export
default
function
App
()
{
const
[
logText
,
setLog
]
=
useState
(
''
);
const
[
heldCalls
,
setHeldCalls
]
=
useState
({});
// callKeep uuid: held
const
[
mutedCalls
,
setMutedCalls
]
=
useState
({});
// callKeep uuid: muted
const
[
calls
,
setCalls
]
=
useState
({});
// callKeep uuid: number
const
log
=
text
=>
{
console
.
info
(
text
);
setLog
(
logText
+
'
\n
'
+
text
);
};
const
addCall
=
(
callUUID
,
number
)
=>
{
setHeldCalls
({...
heldCalls
,
[
callUUID
]:
false
});
setCalls
({...
calls
,
[
callUUID
]:
number
});
};
const
removeCall
=
callUUID
=>
{
const
{[
callUUID
]:
_
,
...
updated
}
=
calls
;
const
{[
callUUID
]:
__
,
...
updatedHeldCalls
}
=
heldCalls
;
setCalls
(
updated
);
setCalls
(
updatedHeldCalls
);
};
const
setCallHeld
=
(
callUUID
,
held
)
=>
{
setHeldCalls
({...
heldCalls
,
[
callUUID
]:
held
});
};
const
setCallMuted
=
(
callUUID
,
muted
)
=>
{
setMutedCalls
({...
mutedCalls
,
[
callUUID
]:
muted
});
};
const
displayIncomingCall
=
number
=>
{
const
callUUID
=
getNewUuid
();
addCall
(
callUUID
,
number
);
log
(
`[displayIncomingCall]
${
format
(
callUUID
)}
, number:
${
number
}
`
);
RNCallKeep
.
displayIncomingCall
(
callUUID
,
number
,
number
,
'
number
'
,
false
);
};
const
displayIncomingCallNow
=
()
=>
{
displayIncomingCall
(
getRandomNumber
());
};
const
displayIncomingCallDelayed
=
()
=>
{
BackgroundTimer
.
setTimeout
(()
=>
{
displayIncomingCall
(
getRandomNumber
());
},
3000
);
};
const
answerCall
=
({
callUUID
})
=>
{
const
number
=
calls
[
callUUID
];
log
(
`[answerCall]
${
format
(
callUUID
)}
, number:
${
number
}
`
);
RNCallKeep
.
startCall
(
callUUID
,
number
,
number
);
BackgroundTimer
.
setTimeout
(()
=>
{
log
(
`[setCurrentCallActive]
${
format
(
callUUID
)}
, number:
${
number
}
`
);
RNCallKeep
.
setCurrentCallActive
(
callUUID
);
},
1000
);
};
const
didPerformDTMFAction
=
({
callUUID
,
digits
})
=>
{
const
number
=
calls
[
callUUID
];
log
(
`[didPerformDTMFAction]
${
format
(
callUUID
,
)}
, number:
${
number
}
(
${
digits
}
)`
,
);
};
const
didReceiveStartCallAction
=
({
handle
})
=>
{
if
(
!
handle
)
{
// @TODO: sometime we receive `didReceiveStartCallAction` with handle` undefined`
return
;
}
const
callUUID
=
getNewUuid
();
addCall
(
callUUID
,
handle
);
log
(
`[didReceiveStartCallAction]
${
callUUID
}
, number:
${
handle
}
`
);
RNCallKeep
.
startCall
(
callUUID
,
handle
,
handle
);
BackgroundTimer
.
setTimeout
(()
=>
{
log
(
`[setCurrentCallActive]
${
format
(
callUUID
)}
, number:
${
handle
}
`
);
RNCallKeep
.
setCurrentCallActive
(
callUUID
);
},
1000
);
};
const
didPerformSetMutedCallAction
=
({
muted
,
callUUID
})
=>
{
const
number
=
calls
[
callUUID
];
log
(
`[didPerformSetMutedCallAction]
${
format
(
callUUID
,
)}
, number:
${
number
}
(
${
muted
}
)`
,
);
setCallMuted
(
callUUID
,
muted
);
};
const
didToggleHoldCallAction
=
({
hold
,
callUUID
})
=>
{
const
number
=
calls
[
callUUID
];
log
(
`[didToggleHoldCallAction]
${
format
(
callUUID
,
)}
, number:
${
number
}
(
${
hold
}
)`
,
);
setCallHeld
(
callUUID
,
hold
);
};
const
endCall
=
({
callUUID
})
=>
{
const
handle
=
calls
[
callUUID
];
log
(
`[endCall]
${
format
(
callUUID
)}
, number:
${
handle
}
`
);
removeCall
(
callUUID
);
};
const
hangup
=
callUUID
=>
{
RNCallKeep
.
endCall
(
callUUID
);
removeCall
(
callUUID
);
};
const
setOnHold
=
(
callUUID
,
held
)
=>
{
const
handle
=
calls
[
callUUID
];
RNCallKeep
.
setOnHold
(
callUUID
,
held
);
log
(
`[setOnHold:
${
held
}
]
${
format
(
callUUID
)}
, number:
${
handle
}
`
);
setCallHeld
(
callUUID
,
held
);
};
const
setOnMute
=
(
callUUID
,
muted
)
=>
{
const
handle
=
calls
[
callUUID
];
RNCallKeep
.
setMutedCall
(
callUUID
,
muted
);
log
(
`[setMutedCall:
${
muted
}
]
${
format
(
callUUID
)}
, number:
${
handle
}
`
);
setCallMuted
(
callUUID
,
muted
);
};
const
updateDisplay
=
callUUID
=>
{
const
number
=
calls
[
callUUID
];
// Workaround because Android doesn't display well displayName, se we have to switch ...
if
(
isIOS
)
{
RNCallKeep
.
updateDisplay
(
callUUID
,
'
New Name
'
,
number
);
}
else
{
RNCallKeep
.
updateDisplay
(
callUUID
,
number
,
'
New Name
'
);
}
log
(
`[updateDisplay:
${
number
}
]
${
format
(
callUUID
)}
`
);
};
useEffect
(()
=>
{
RNCallKeep
.
addEventListener
(
'
answerCall
'
,
answerCall
);
RNCallKeep
.
addEventListener
(
'
didPerformDTMFAction
'
,
didPerformDTMFAction
);
RNCallKeep
.
addEventListener
(
'
didReceiveStartCallAction
'
,
didReceiveStartCallAction
,
);
RNCallKeep
.
addEventListener
(
'
didPerformSetMutedCallAction
'
,
didPerformSetMutedCallAction
,
);
RNCallKeep
.
addEventListener
(
'
didToggleHoldCallAction
'
,
didToggleHoldCallAction
,
);
RNCallKeep
.
addEventListener
(
'
endCall
'
,
endCall
);
return
()
=>
{
RNCallKeep
.
removeEventListener
(
'
answerCall
'
,
answerCall
);
RNCallKeep
.
removeEventListener
(
'
didPerformDTMFAction
'
,
didPerformDTMFAction
,
);
RNCallKeep
.
removeEventListener
(
'
didReceiveStartCallAction
'
,
didReceiveStartCallAction
,
);
RNCallKeep
.
removeEventListener
(
'
didPerformSetMutedCallAction
'
,
didPerformSetMutedCallAction
,
);
RNCallKeep
.
removeEventListener
(
'
didToggleHoldCallAction
'
,
didToggleHoldCallAction
,
);
RNCallKeep
.
removeEventListener
(
'
endCall
'
,
endCall
);
};
},
[]);
if
(
isIOS
&&
DeviceInfo
.
isEmulator
())
{
return
(
<
Text
style
=
{
styles
.
container
}
>
CallKeep
doesn
'
t work on iOS emulator
</Text>
);
}
return (
<View style={styles.container}>
<TouchableOpacity
onPress={displayIncomingCallNow}
style={styles.button}
hitSlop={hitSlop}>
<Text>Display incoming call now</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={displayIncomingCallDelayed}
style={styles.button}
hitSlop={hitSlop}>
<Text>Display incoming call now in 3s</Text>
</TouchableOpacity>
{Object.keys(calls).map(callUUID => (
<View key={callUUID} style={styles.callButtons}>
<TouchableOpacity
onPress={() => setOnHold(callUUID, !heldCalls[callUUID])}
style={styles.button}
hitSlop={hitSlop}>
<Text>
{heldCalls[callUUID] ?
'
Unhold
'
:
'
Hold
'
} {calls[callUUID]}
</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => updateDisplay(callUUID)}
style={styles.button}
hitSlop={hitSlop}>
<Text>Update display</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => setOnMute(callUUID, !mutedCalls[callUUID])}
style={styles.button}
hitSlop={hitSlop}>
<Text>
{mutedCalls[callUUID] ?
'
Unmute
'
:
'
Mute
'
} {calls[callUUID]}
</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => hangup(callUUID)}
style={styles.button}
hitSlop={hitSlop}>
<Text>Hangup {calls[callUUID]}</Text>
</TouchableOpacity>
</View>
))}
<ScrollView style={styles.logContainer}>
<Text style={styles.log}>{logText}</Text>
</ScrollView>
</View>
);
}
App.tsx
0 → 100644
View file @
0ee17cc7
import
React
,
{
useState
,
useEffect
,
useRef
}
from
'
react
'
;
import
{
Platform
,
StyleSheet
,
Text
,
View
,
TouchableOpacity
,
ScrollView
,
}
from
'
react-native
'
;
import
RNCallKeep
,
{
AnswerCallPayload
,
Events
}
from
'
react-native-callkeep
'
;
const
EVENTS
:
Events
[]
=
[
'
didReceiveStartCallAction
'
,
'
answerCall
'
,
'
endCall
'
,
'
didActivateAudioSession
'
,
'
didDeactivateAudioSession
'
,
'
didDisplayIncomingCall
'
,
'
didToggleHoldCallAction
'
,
'
didPerformDTMFAction
'
,
'
didResetProvider
'
,
'
checkReachability
'
,
'
didPerformSetMutedCallAction
'
,
'
didLoadWithEvents
'
,
'
showIncomingCallUi
'
,
'
silenceIncomingCall
'
,
];
type
DidDisplayIncomingCallArgs
=
{
error
:
string
;
callUUID
:
string
;
handle
:
string
;
localizedCallerName
:
string
;
hasVideo
:
string
;
fromPushKit
:
string
;
payload
:
string
;
};
export
default
function
App
()
{
const
[
readyCK
,
setReadyCK
]
=
useState
(
false
);
const
[
supportCS
,
setSupportCS
]
=
useState
(
false
);
const
[
hasPhoneAccount
,
setHasPhoneAccount
]
=
useState
(
false
);
const
[
callId
,
setCallId
]
=
useState
(
''
);
const
[
callerName
,
setCallerName
]
=
useState
(
''
);
const
[
callerId
,
setCallerId
]
=
useState
(
''
);
const
isRinging
=
useRef
(
false
);
const
removeEventListeners
=
()
=>
{
RNCallKeep
.
removeEventListener
(
'
endCall
'
);
RNCallKeep
.
removeEventListener
(
'
didDisplayIncomingCall
'
);
};
const
endCall
=
()
=>
{
RNCallKeep
.
endCall
(
callId
);
removeEventListeners
();
};
const
displayCallAndroid
=
()
=>
{
isRinging
.
current
=
true
;
RNCallKeep
.
displayIncomingCall
(
callId
,
callerName
,
callerName
,
'
generic
'
);
setTimeout
(()
=>
{
if
(
isRinging
.
current
)
{
isRinging
.
current
=
false
;
// 6 = MissedCall
// https://github.com/react-native-webrtc/react-native-callkeep#constants
RNCallKeep
.
reportEndCallWithUUID
(
callId
,
6
);
}
},
15000
);
};
const
answerCall
=
({
callUUID
}:
AnswerCallPayload
)
=>
{
isRinging
.
current
=
false
;
console
.
log
(
'
somewhere
'
);
// navigated to call screen in our app
};
const
didDisplayIncomingCall
=
(
args
:
DidDisplayIncomingCallArgs
)
=>
{
if
(
args
.
error
)
{
console
.
log
(
`Callkeep didDisplayIncomingCall error:
${
args
.
error
}
`
);
}
isRinging
.
current
=
true
;
RNCallKeep
.
updateDisplay
(
callId
,
`
${
callerName
}
`
,
callerId
);
setTimeout
(()
=>
{
if
(
isRinging
.
current
)
{
isRinging
.
current
=
false
;
// 6 = MissedCall
// https://github.com/react-native-webrtc/react-native-callkeep#constants
RNCallKeep
.
reportEndCallWithUUID
(
callId
,
6
);
}
},
15000
);
};
const
setupEventListeners
=
()
=>
{
RNCallKeep
.
addEventListener
(
'
endCall
'
,
endCall
);
RNCallKeep
.
addEventListener
(
'
didDisplayIncomingCall
'
,
didDisplayIncomingCall
,
);
};
const
initCK
=
async
()
=>
{
try
{
RNCallKeep
.
setup
({
ios
:
{
appName
:
'
WazoReactNativeDemo
'
,
},
android
:
{
alertTitle
:
'
Permissions required
'
,
alertDescription
:
'
This application needs to access your phone accounts
'
,
cancelButton
:
'
Cancel
'
,
okButton
:
'
ok
'
,
selfManaged
:
true
,
additionalPermissions
:
[],
foregroundService
:
{
channelId
:
'
com.company.my
'
,
channelName
:
'
Foreground service for my app
'
,
notificationTitle
:
'
My app is running on background
'
,
notificationIcon
:
'
Path to the resource icon of the notification
'
,
},
},
});
RNCallKeep
.
setAvailable
(
true
);
setupEventListeners
();
setSupportCS
(
RNCallKeep
.
supportConnectionService
());
const
hasPA
=
await
RNCallKeep
.
hasPhoneAccount
();
setHasPhoneAccount
(
hasPA
);
setReadyCK
(
true
);
}
catch
(
err
)
{
console
.
error
(
'
initializeCallKeep error:
'
,
(
err
as
Error
).
message
);
}
};
useEffect
(()
=>
{
initCK
();
return
()
=>
{
removeEventListeners
();
};
},
[]);
return
(
<
View
>
<
Text
>
CallKeep Demo:
{
readyCK
?
'
Ready
'
:
'
Waiting...
'
}
</
Text
>
<
Text
>
Support Connection Service:
{
supportCS
?
'
Yes
'
:
'
No
'
}
</
Text
>
<
Text
>
Has Phone account:
{
hasPhoneAccount
?
'
Yes
'
:
'
No
'
}
</
Text
>
</
View
>
);
}
README.md
0 → 100644
View file @
0ee17cc7
# CallKeep
-
[
CallKeep React Native
](
https://github.com/react-native-webrtc/react-native-callkeep
)
-
[
Статья с нативным модулем
](
https://blog.theodo.com/2021/03/react-native-incoming-call-ui-callkeep/
)
-
[
Дока от Гугла про selfManaged
](
https://developer.android.com/guide/topics/connectivity/telecom/selfManaged
)
android/app/src/main/AndroidManifest.xml
View file @
0ee17cc7
...
@@ -8,6 +8,8 @@
...
@@ -8,6 +8,8 @@
<uses-permission
android:name=
"android.permission.FOREGROUND_SERVICE"
/>
<uses-permission
android:name=
"android.permission.FOREGROUND_SERVICE"
/>
<uses-permission
android:name=
"android.permission.READ_PHONE_STATE"
/>
<uses-permission
android:name=
"android.permission.READ_PHONE_STATE"
/>
<uses-permission
android:name=
"android.permission.CALL_PHONE"
/>
<uses-permission
android:name=
"android.permission.CALL_PHONE"
/>
<uses-permission
android:name=
"android.permission.MANAGE_OWN_CALLS"
/>
<uses-permission
android:name=
"android.permission.READ_CALL_LOG"
/>
<!-- OPTIONAL PERMISSIONS, REMOVE WHATEVER YOU DO NOT NEED -->
<!-- OPTIONAL PERMISSIONS, REMOVE WHATEVER YOU DO NOT NEED -->
<uses-permission
android:name=
"android.permission.MANAGE_DOCUMENTS"
/>
<uses-permission
android:name=
"android.permission.MANAGE_DOCUMENTS"
/>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment