Initial work on better permissions handling

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2017-12-27 14:46:56 +01:00
parent d7c7d34a62
commit df462a00b9
3 changed files with 138 additions and 47 deletions

View File

@ -121,6 +121,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.BooleanSupplier;
import io.reactivex.schedulers.Schedulers;
import me.zhanghai.android.effortlesspermissions.AfterPermissionDenied;
import me.zhanghai.android.effortlesspermissions.EffortlessPermissions;
import me.zhanghai.android.effortlesspermissions.OpenAppDetailsDialogFragment;
import pub.devrel.easypermissions.AfterPermissionGranted;
@ -131,8 +132,16 @@ public class CallActivity extends AppCompatActivity {
private static final String[] PERMISSIONS_CALL = {
android.Manifest.permission.CAMERA,
android.Manifest.permission.RECORD_AUDIO,
Manifest.permission.MODIFY_AUDIO_SETTINGS
};
private static final String[] PERMISSIONS_CAMERA = {
Manifest.permission.CAMERA
};
private static final String[] PERMISSIONS_MICROPHONE = {
Manifest.permission.RECORD_AUDIO
};
@BindView(R.id.pip_video_view)
SurfaceViewRenderer pipVideoView;
@BindView(R.id.full_screen_surface_view)
@ -173,6 +182,7 @@ public class CallActivity extends AppCompatActivity {
VideoRenderer localRenderer;
EglBase rootEglBase;
boolean leavingCall = false;
boolean inCall = false;
BooleanSupplier booleanSupplier = () -> leavingCall;
Disposable signalingDisposable;
Disposable pingDisposable;
@ -185,8 +195,11 @@ public class CallActivity extends AppCompatActivity {
private String credentials;
private List<MagicPeerConnectionWrapper> magicPeerConnectionWrapperList = new ArrayList<>();
private boolean videoOn = true;
private boolean audioOn = true;
private boolean videoOn = false;
private boolean audioOn = false;
private boolean cameraInitialized = false;
private boolean microphoneInitialized = false;
private static int getSystemUiVisibility() {
int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
@ -214,6 +227,8 @@ public class CallActivity extends AppCompatActivity {
callSession = "0";
credentials = ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken());
basicInitialization();
if (userUtils.getCurrentUser() != null && userUtils.getCurrentUser() != userEntity) {
userUtils.createOrUpdateUser(userEntity.getUsername(),
userEntity.getToken(), userEntity.getBaseUrl(), null,
@ -265,7 +280,9 @@ public class CallActivity extends AppCompatActivity {
}
}
if (localMediaStream.videoTracks.size() > 0) {
localMediaStream.videoTracks.get(0).setEnabled(enable);
}
if (enable) {
pipVideoView.setVisibility(View.VISIBLE);
@ -278,8 +295,10 @@ public class CallActivity extends AppCompatActivity {
message = "audioOn";
}
if (localMediaStream.audioTracks.size() > 0) {
localMediaStream.audioTracks.get(0).setEnabled(enable);
}
}
for (int i = 0; i < magicPeerConnectionWrapperList.size(); i++) {
magicPeerConnectionWrapperList.get(i).sendChannelData(new DataChannelMessage(message));
@ -288,6 +307,7 @@ public class CallActivity extends AppCompatActivity {
@OnClick(R.id.call_control_microphone)
public void onMicrophoneClick() {
if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) {
audioOn = !audioOn;
if (audioOn) {
@ -297,6 +317,15 @@ public class CallActivity extends AppCompatActivity {
}
toggleMedia(audioOn, false);
} else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_MICROPHONE)) {
// Some permission is permanently denied so we cannot request them normally.
OpenAppDetailsDialogFragment.show(
R.string.nc_microphone_permission_permanently_denied,
R.string.nc_permissions_settings, this);
} else {
EffortlessPermissions.requestPermissions(this, R.string.nc_permissions_audio,
100, PERMISSIONS_MICROPHONE);
}
}
@OnClick(R.id.call_control_hangup)
@ -307,6 +336,7 @@ public class CallActivity extends AppCompatActivity {
@OnClick(R.id.call_control_camera)
public void onCameraClick() {
if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) {
videoOn = !videoOn;
if (videoOn) {
@ -316,6 +346,16 @@ public class CallActivity extends AppCompatActivity {
}
toggleMedia(videoOn, true);
} else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_CAMERA)) {
// Some permission is permanently denied so we cannot request them normally.
OpenAppDetailsDialogFragment.show(
R.string.nc_camera_permission_permanently_denied,
R.string.nc_permissions_settings, this);
} else {
EffortlessPermissions.requestPermissions(this, R.string.nc_permissions_video,
100, PERMISSIONS_CAMERA);
}
}
@ -391,20 +431,53 @@ public class CallActivity extends AppCompatActivity {
@AfterPermissionGranted(100)
private void checkPermissions() {
if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CALL)) {
initializeEverything();
if (!cameraInitialized) {
cameraInitialization();
}
if (!microphoneInitialized) {
microphoneInitialization();
}
if (!inCall) {
startCall();
}
} else if (EffortlessPermissions.somePermissionPermanentlyDenied(this,
PERMISSIONS_CALL)) {
// Some permission is permanently denied so we cannot request them normally.
OpenAppDetailsDialogFragment.show(
R.string.nc_permissions_permanently_denied,
R.string.nc_permissions_settings, this);
if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) {
cameraInitialization();
onCameraClick();
} else if (!EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) {
cameraControlButton.setImageResource(R.drawable.ic_videocam_off_white_24px);
cameraSwitchButton.setEnabled(false);
cameraSwitchButton.setAlpha(0.5f);
}
if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) {
microphoneInitialization();
onMicrophoneClick();
} else if (!EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) {
microphoneControlButton.setImageResource(R.drawable.ic_mic_off_white_24px);
}
if (!inCall) {
startCall();
}
} else {
EffortlessPermissions.requestPermissions(this, R.string.nc_permissions,
100, PERMISSIONS_CALL);
}
}
private void initializeEverything() {
@AfterPermissionDenied(100)
private void onPermissionsDenied() {
if (!inCall) {
startCall();
}
}
private void basicInitialization() {
//Initialize PeerConnectionFactory globals.
PeerConnectionFactory.InitializationOptions initializationOptions = PeerConnectionFactory.InitializationOptions
.builder(this)
@ -416,23 +489,11 @@ public class CallActivity extends AppCompatActivity {
PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
peerConnectionFactory = new PeerConnectionFactory(options);
videoCapturer = createCameraCapturer(cameraEnumerator);
//Create MediaConstraints - Will be useful for specifying video and audio constraints.
audioConstraints = new MediaConstraints();
videoConstraints = new MediaConstraints();
//Create a VideoSource instance
videoSource = peerConnectionFactory.createVideoSource(videoCapturer);
localVideoTrack = peerConnectionFactory.createVideoTrack("NCv0", videoSource);
//create an AudioSource instance
audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
localAudioTrack = peerConnectionFactory.createAudioTrack("NCa0", audioSource);
localMediaStream = peerConnectionFactory.createLocalMediaStream("NCMS");
localMediaStream.addTrack(localAudioTrack);
localMediaStream.addTrack(localVideoTrack);
// Create and audio manager that will take care of audio routing,
// audio modes, audio device enumeration etc.
@ -448,14 +509,6 @@ public class CallActivity extends AppCompatActivity {
}
});
startVideoCapture();
//create a videoRenderer based on SurfaceViewRenderer instance
localRenderer = new VideoRenderer(fullScreenVideoView);
// And finally, with our VideoRenderer ready, we
// can add our renderer to the VideoTrack.
localVideoTrack.addRenderer(localRenderer);
iceServers = new ArrayList<>();
//create sdpConstraints
@ -464,13 +517,41 @@ public class CallActivity extends AppCompatActivity {
sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("internalSctpDataChannels", "true"));
sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
}
private void cameraInitialization() {
videoCapturer = createCameraCapturer(cameraEnumerator);
//Create a VideoSource instance
videoSource = peerConnectionFactory.createVideoSource(videoCapturer);
localVideoTrack = peerConnectionFactory.createVideoTrack("NCv0", videoSource);
localMediaStream.addTrack(localVideoTrack);
//create a videoRenderer based on SurfaceViewRenderer instance
localRenderer = new VideoRenderer(fullScreenVideoView);
// And finally, with our VideoRenderer ready, we
// can add our renderer to the VideoTrack.
localVideoTrack.addRenderer(localRenderer);
cameraInitialized = true;
}
private void microphoneInitialization() {
//create an AudioSource instance
audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
localAudioTrack = peerConnectionFactory.createAudioTrack("NCa0", audioSource);
localMediaStream.addTrack(localAudioTrack);
microphoneInitialized = true;
}
private void startCall() {
inCall = true;
animateCallControls(false, 5000);
startPullingSignalingMessages(false);
registerNetworkReceiver();
}
@OnClick({R.id.full_screen_surface_view, R.id.remote_renderers_layout})
public void showCallControls() {
if (callControls.getVisibility() != View.VISIBLE) {
@ -810,6 +891,7 @@ public class CallActivity extends AppCompatActivity {
private void hangup(boolean dueToNetworkChange) {
leavingCall = true;
inCall = false;
dispose(null);
for (int i = 0; i < magicPeerConnectionWrapperList.size(); i++) {

View File

@ -74,7 +74,7 @@
android:layout_marginEnd="@dimen/margin_between_elements"
android:layout_toEndOf="@id/call_control_hangup"
android:background="?android:selectableItemBackgroundBorderless"
android:src="@drawable/ic_videocam_white_24px"/>
android:src="@drawable/ic_videocam_off_white_24px"/>
<ImageButton
android:id="@+id/call_control_microphone"
@ -83,7 +83,7 @@
android:layout_marginEnd="@dimen/margin_between_elements"
android:layout_toEndOf="@id/call_control_camera"
android:background="?android:selectableItemBackgroundBorderless"
android:src="@drawable/ic_mic_white_24px"/>
android:src="@drawable/ic_mic_off_white_24px"/>
<ImageButton
android:id="@+id/call_control_switch_camera"

View File

@ -80,9 +80,18 @@
<string name="nc_more_contacts_selected">contacts selected</string>
<!-- Permissions -->
<string name="nc_permissions">Permissions may need to be granted to establish a video call. Please click \"ALLOW\" in
the upcoming system dialog.</string>
<string name="nc_permissions">Permissions need to be granted to establish a video and/or audio call. Please
click \"ALLOW\" in the upcoming system dialog.</string>
<string name="nc_permissions_audio">Microphone permission needs to be granted to enable audio calls. Please
click \"ALLOW\" in the upcoming system dialog.</string>
<string name="nc_permissions_video">Camera permission needs to be granted to enable video calls. Please
click \"ALLOW\" in the upcoming system dialog.</string>
<string name="nc_permissions_permanently_denied">To make video calls, grant \"Camera\" and \"Microphone\" permissions in the system settings.</string>
<string name="nc_camera_permission_permanently_denied">To enable video communication, grant \"Camera\" permission
the system
settings.</string>
<string name="nc_microphone_permission_permanently_denied">To enable voice communication, grant \"Microphone\"
permission the system settings.</string>
<string name="nc_permissions_settings">Open settings</string>
</resources>