Эх сурвалжийг харах

remove effortlessPermissions lib

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Marcel Hibbe 2 жил өмнө
parent
commit
80af04be9a

+ 0 - 1
app/build.gradle

@@ -239,7 +239,6 @@ dependencies {
     implementation 'net.orange-box.storebox:storebox-lib:1.4.0'
     implementation 'eu.davidea:flexible-adapter:5.1.0'
     implementation 'eu.davidea:flexible-adapter-ui:1.0.0'
-    implementation 'me.zhanghai.android.effortlesspermissions:library:1.1.0'
     implementation 'org.apache.commons:commons-lang3:3.12.0'
     implementation 'com.github.wooplr:Spotlight:1.3'
     implementation 'com.google.code.findbugs:jsr305:3.0.2'

+ 157 - 123
app/src/main/java/com/nextcloud/talk/activities/CallActivity.java

@@ -34,7 +34,6 @@ import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Color;
 import android.graphics.drawable.Icon;
@@ -151,12 +150,9 @@ import javax.inject.Inject;
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.content.ContextCompat;
 import androidx.core.graphics.drawable.DrawableCompat;
 import androidx.lifecycle.ViewModelProvider;
 import autodagger.AutoInjector;
@@ -165,11 +161,7 @@ import io.reactivex.Observer;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.disposables.Disposable;
 import io.reactivex.schedulers.Schedulers;
-import me.zhanghai.android.effortlesspermissions.AfterPermissionDenied;
-import me.zhanghai.android.effortlesspermissions.EffortlessPermissions;
-import me.zhanghai.android.effortlesspermissions.OpenAppDetailsDialogFragment;
 import okhttp3.Cache;
-import pub.devrel.easypermissions.AfterPermissionGranted;
 
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY;
@@ -220,11 +212,6 @@ public class CallActivity extends CallBaseActivity {
     public CallRecordingViewModel callRecordingViewModel;
     public RaiseHandViewModel raiseHandViewModel;
 
-    private static final String[] PERMISSIONS_CALL = {
-        Manifest.permission.CAMERA,
-        Manifest.permission.RECORD_AUDIO
-    };
-
     private static final String[] PERMISSIONS_CAMERA = {
         Manifest.permission.CAMERA
     };
@@ -362,13 +349,62 @@ public class CallActivity extends CallBaseActivity {
     private AudioOutputDialog audioOutputDialog;
     private MoreCallActionsDialog moreCallActionsDialog;
 
-    private final ActivityResultLauncher<String> requestBluetoothPermissionLauncher =
-        registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
-            if (isGranted) {
-                enableBluetoothManager();
+    ActivityResultLauncher<String[]> requestPermissionLauncher =
+        registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissionMap -> {
+
+            List<String> rationaleList = new ArrayList<>();
+
+            Boolean audioPermission = permissionMap.get(Manifest.permission.RECORD_AUDIO);
+            if (audioPermission != null) {
+                if (Boolean.TRUE.equals(audioPermission)) {
+                    if (!microphoneOn) {
+                        onMicrophoneClick();
+                    }
+                } else {
+                    rationaleList.add((getResources().getString(R.string.nc_microphone_permission_hint)));
+                }
+            }
+
+            Boolean cameraPermission = permissionMap.get(Manifest.permission.CAMERA);
+            if (cameraPermission != null) {
+                if (Boolean.TRUE.equals(cameraPermission)) {
+                    if (!videoOn) {
+                        onCameraClick();
+                    }
+
+                    if (cameraEnumerator.getDeviceNames().length == 0) {
+                        binding.cameraButton.setVisibility(View.GONE);
+                    }
+
+                    if (cameraEnumerator.getDeviceNames().length > 1) {
+                        binding.switchSelfVideoButton.setVisibility(View.VISIBLE);
+                    }
+                } else {
+                    rationaleList.add((getResources().getString(R.string.nc_camera_permission_hint)));
+                }
+            }
+
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                Boolean bluetoothPermission = permissionMap.get(Manifest.permission.BLUETOOTH_CONNECT);
+                if (bluetoothPermission != null) {
+                    if (Boolean.TRUE.equals(bluetoothPermission)) {
+                        enableBluetoothManager();
+                    } else {
+                        // Only ask for bluetooth when already asking to grant microphone or camera access. Asking
+                        // for bluetooth solely is not important enough here and would most likely annoy the user.
+                        if (!rationaleList.isEmpty()) {
+                            rationaleList.add((getResources().getString(R.string.nc_bluetooth_permission_hint)));
+                        }
+                    }
+                }
+            }
+
+            if (!rationaleList.isEmpty()) {
+                showRationaleDialogForSettings(rationaleList);
             }
         });
 
+
     private boolean canPublishAudioStream;
     private boolean canPublishVideoStream;
 
@@ -502,16 +538,15 @@ public class CallActivity extends CallBaseActivity {
             .setRepeatCount(PulseAnimation.INFINITE)
             .setRepeatMode(PulseAnimation.REVERSE);
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
-            requestBluetoothPermission();
-        }
         basicInitialization();
         callParticipants = new HashMap<>();
         participantDisplayItems = new HashMap<>();
         initViews();
+
         if (!isConnectionEstablished()) {
             initiateCall();
         }
+
         updateSelfVideoViewPosition();
 
         reactionAnimator = new ReactionAnimator(context, binding.reactionAnimationWrapper, viewThemeUtils);
@@ -546,15 +581,6 @@ public class CallActivity extends CallBaseActivity {
         active = false;
     }
 
-    @RequiresApi(api = Build.VERSION_CODES.S)
-    private void requestBluetoothPermission() {
-        if (ContextCompat.checkSelfPermission(
-            getContext(), Manifest.permission.BLUETOOTH_CONNECT) ==
-            PackageManager.PERMISSION_DENIED) {
-            requestBluetoothPermissionLauncher.launch(Manifest.permission.BLUETOOTH_CONNECT);
-        }
-    }
-
     private void enableBluetoothManager() {
         if (audioManager != null) {
             audioManager.startBluetoothManager();
@@ -936,36 +962,28 @@ public class CallActivity extends CallBaseActivity {
         }
     }
 
-
     private void checkDevicePermissions() {
-        if (isVoiceOnlyCall) {
-            onMicrophoneClick();
-        } else {
-            if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CALL)) {
-                onPermissionsGranted();
-            } else {
-                requestPermissions(PERMISSIONS_CALL, 100);
-            }
-        }
-
-    }
-
-    private boolean isConnectionEstablished() {
-        return (currentCallStatus == CallStatus.JOINED || currentCallStatus == CallStatus.IN_CONVERSATION);
-    }
-
-    @AfterPermissionGranted(100)
-    private void onPermissionsGranted() {
-        if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CALL)) {
-            if (!videoOn && !isVoiceOnlyCall) {
-                onCameraClick();
-            }
+        List<String> permissionsToRequest = new ArrayList<>();
+        List<String> rationaleList = new ArrayList<>();
 
+        if (permissionUtil.isMicrophonePermissionGranted()) {
             if (!microphoneOn) {
                 onMicrophoneClick();
             }
 
-            if (!isVoiceOnlyCall) {
+        } else if (shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO)) {
+            permissionsToRequest.add(Manifest.permission.RECORD_AUDIO);
+            rationaleList.add((getResources().getString(R.string.nc_microphone_permission_hint)));
+        } else {
+            permissionsToRequest.add(Manifest.permission.RECORD_AUDIO);
+        }
+
+        if (!isVoiceOnlyCall) {
+            if (permissionUtil.isCameraPermissionGranted()) {
+                if (!videoOn) {
+                    onCameraClick();
+                }
+
                 if (cameraEnumerator.getDeviceNames().length == 0) {
                     binding.cameraButton.setVisibility(View.GONE);
                 }
@@ -973,44 +991,32 @@ public class CallActivity extends CallBaseActivity {
                 if (cameraEnumerator.getDeviceNames().length > 1) {
                     binding.switchSelfVideoButton.setVisibility(View.VISIBLE);
                 }
+            } else if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
+                permissionsToRequest.add(Manifest.permission.CAMERA);
+                rationaleList.add((getResources().getString(R.string.nc_camera_permission_hint)));
+            } else {
+                permissionsToRequest.add(Manifest.permission.CAMERA);
             }
-
-            if (!isConnectionEstablished()) {
-                fetchSignalingSettings();
-            }
-        } else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_CALL)) {
-            checkIfSomeAreApproved();
         }
 
-    }
-
-    private void checkIfSomeAreApproved() {
-        if (!isVoiceOnlyCall) {
-            if (cameraEnumerator.getDeviceNames().length == 0) {
-                binding.cameraButton.setVisibility(View.GONE);
-            }
-
-            if (cameraEnumerator.getDeviceNames().length > 1) {
-                binding.switchSelfVideoButton.setVisibility(View.VISIBLE);
-            }
 
-            if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) && canPublishVideoStream) {
-                if (!videoOn) {
-                    onCameraClick();
-                }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+            if (permissionUtil.isBluetoothPermissionGranted()) {
+                enableBluetoothManager();
+            } else if (shouldShowRequestPermissionRationale(Manifest.permission.BLUETOOTH_CONNECT)) {
+                permissionsToRequest.add(Manifest.permission.BLUETOOTH_CONNECT);
+                rationaleList.add((getResources().getString(R.string.nc_bluetooth_permission_hint)));
             } else {
-                binding.cameraButton.setImageResource(R.drawable.ic_videocam_off_white_24px);
-                binding.cameraButton.setAlpha(0.7f);
-                binding.switchSelfVideoButton.setVisibility(View.GONE);
+                permissionsToRequest.add(Manifest.permission.BLUETOOTH_CONNECT);
             }
         }
 
-        if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE) && canPublishAudioStream) {
-            if (!microphoneOn) {
-                onMicrophoneClick();
+        if (!permissionsToRequest.isEmpty()) {
+            if (!rationaleList.isEmpty()) {
+                showRationaleDialog(permissionsToRequest, rationaleList);
+            } else {
+                requestPermissionLauncher.launch(permissionsToRequest.toArray(new String[permissionsToRequest.size()]));
             }
-        } else {
-            binding.microphoneButton.setImageResource(R.drawable.ic_mic_off_white_24px);
         }
 
         if (!isConnectionEstablished()) {
@@ -1018,22 +1024,63 @@ public class CallActivity extends CallBaseActivity {
         }
     }
 
-    @AfterPermissionDenied(100)
-    private void onPermissionsDenied() {
-        if (!isVoiceOnlyCall) {
-            if (cameraEnumerator.getDeviceNames().length == 0) {
-                binding.cameraButton.setVisibility(View.GONE);
-            } else if (cameraEnumerator.getDeviceNames().length == 1) {
-                binding.switchSelfVideoButton.setVisibility(View.GONE);
-            }
+    private void showRationaleDialog(String permissionToRequest, String rationale) {
+        List<String> rationaleList = new ArrayList<String>();
+        List<String> permissionsToRequest = new ArrayList<String>();
+
+        rationaleList.add(rationale);
+        permissionsToRequest.add(permissionToRequest);
+
+        showRationaleDialog(permissionsToRequest, rationaleList);
+    }
+
+    private void showRationaleDialog(List<String> permissionsToRequest, List<String> rationaleList) {
+        StringBuilder rationalesWithLineBreaks = new StringBuilder();
+
+        for (String rationale : rationaleList) {
+            rationalesWithLineBreaks.append(rationale).append("\n\n");
         }
 
-        if ((EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) ||
-            EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE))) {
-            checkIfSomeAreApproved();
-        } else if (!isConnectionEstablished()) {
-            fetchSignalingSettings();
+        MaterialAlertDialogBuilder dialogBuilder = new MaterialAlertDialogBuilder(this)
+            .setTitle(R.string.nc_permissions_rationale_dialog_title)
+            .setMessage(rationalesWithLineBreaks)
+            .setPositiveButton(R.string.nc_permissions_ask, (dialog, which) ->
+                                   requestPermissionLauncher.launch(
+                                       permissionsToRequest.toArray(new String[permissionsToRequest.size()])
+                                                                   )
+                              )
+            .setNegativeButton(R.string.nc_common_dismiss, null);
+        viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, dialogBuilder);
+        dialogBuilder.show();
+    }
+
+    private void showRationaleDialogForSettings(List<String> rationaleList) {
+        StringBuilder rationalesWithLineBreaks = new StringBuilder();
+        rationalesWithLineBreaks.append(getResources().getString(R.string.nc_permissions_denied));
+        rationalesWithLineBreaks.append('\n');
+        rationalesWithLineBreaks.append(getResources().getString(R.string.nc_permissions_settings_hint));
+        rationalesWithLineBreaks.append("\n\n");
+
+        for (String rationale : rationaleList) {
+            rationalesWithLineBreaks.append(rationale).append("\n\n");
         }
+
+        MaterialAlertDialogBuilder dialogBuilder = new MaterialAlertDialogBuilder(this)
+            .setTitle(R.string.nc_permissions_rationale_dialog_title)
+            .setMessage(rationalesWithLineBreaks)
+            .setPositiveButton(R.string.nc_permissions_settings, (dialog, which) -> {
+                Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+                intent.setData(Uri.fromParts("package", getPackageName(), null));
+                startActivity(intent);
+            })
+            .setNegativeButton(R.string.nc_common_dismiss, null);
+        viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, dialogBuilder);
+        dialogBuilder.show();
+    }
+
+
+    private boolean isConnectionEstablished() {
+        return (currentCallStatus == CallStatus.JOINED || currentCallStatus == CallStatus.IN_CONVERSATION);
     }
 
     private void onAudioManagerDevicesChanged(
@@ -1118,7 +1165,6 @@ public class CallActivity extends CallBaseActivity {
     }
 
     public void onMicrophoneClick() {
-
         if (!canPublishAudioStream) {
             microphoneOn = false;
             binding.microphoneButton.setImageResource(R.drawable.ic_mic_off_white_24px);
@@ -1134,7 +1180,7 @@ public class CallActivity extends CallBaseActivity {
             return;
         }
 
-        if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) {
+        if (permissionUtil.isMicrophonePermissionGranted()) {
 
             if (!appPreferences.getPushToTalkIntroShown()) {
                 int primary = viewThemeUtils.getScheme(binding.audioOutputButton.getContext()).getPrimary();
@@ -1182,19 +1228,17 @@ public class CallActivity extends CallBaseActivity {
                 pulseAnimation.start();
                 toggleMedia(true, false);
             }
-        } else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_MICROPHONE)) {
-            // Microphone permission is permanently denied so we cannot request it normally.
-
-            OpenAppDetailsDialogFragment.show(
-                R.string.nc_microphone_permission_permanently_denied,
-                R.string.nc_permissions_settings, (AppCompatActivity) this);
+        } else if (shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO)) {
+            showRationaleDialog(
+                Manifest.permission.RECORD_AUDIO,
+                getResources().getString(R.string.nc_microphone_permission_hint)
+                               );
         } else {
-            requestPermissions(PERMISSIONS_MICROPHONE, 100);
+            requestPermissionLauncher.launch(PERMISSIONS_MICROPHONE);
         }
     }
 
     public void onCameraClick() {
-
         if (!canPublishVideoStream) {
             videoOn = false;
             binding.cameraButton.setImageResource(R.drawable.ic_videocam_off_white_24px);
@@ -1202,7 +1246,7 @@ public class CallActivity extends CallBaseActivity {
             return;
         }
 
-        if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) {
+        if (permissionUtil.isCameraPermissionGranted()) {
             videoOn = !videoOn;
 
             if (videoOn) {
@@ -1216,15 +1260,14 @@ public class CallActivity extends CallBaseActivity {
             }
 
             toggleMedia(videoOn, true);
-        } else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_CAMERA)) {
-            // Camera permission is permanently denied so we cannot request it normally.
-            OpenAppDetailsDialogFragment.show(
-                R.string.nc_camera_permission_permanently_denied,
-                R.string.nc_permissions_settings, (AppCompatActivity) this);
+        } else if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
+            showRationaleDialog(
+                Manifest.permission.CAMERA,
+                getResources().getString(R.string.nc_camera_permission_hint)
+                               );
         } else {
-            requestPermissions(PERMISSIONS_CAMERA, 100);
+            requestPermissionLauncher.launch(PERMISSIONS_CAMERA);
         }
-
     }
 
     public void switchCamera() {
@@ -2411,7 +2454,7 @@ public class CallActivity extends CallBaseActivity {
         if (!isVoiceOnlyCall) {
             boolean enableVideo = proximitySensorEvent.getProximitySensorEventType() ==
                 ProximitySensorEvent.ProximitySensorEventType.SENSOR_FAR && videoOn;
-            if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) &&
+            if (permissionUtil.isCameraPermissionGranted() &&
                 (currentCallStatus == CallStatus.CONNECTING || isConnectionEstablished()) && videoOn
                 && enableVideo != localVideoTrack.enabled()) {
                 toggleMedia(enableVideo, true);
@@ -2459,15 +2502,6 @@ public class CallActivity extends CallBaseActivity {
         }
     }
 
-    @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
-                                           @NonNull int[] grantResults) {
-        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-
-        EffortlessPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults,
-                                                         this);
-    }
-
     private void addParticipantDisplayItem(CallParticipantModel callParticipantModel, String videoStreamType) {
         if (callParticipantModel.isInternal() != null && callParticipantModel.isInternal()) {
             return;

+ 2 - 1
app/src/main/java/com/nextcloud/talk/utils/permissions/PlatformPermissionUtil.kt

@@ -24,6 +24,7 @@ package com.nextcloud.talk.utils.permissions
 interface PlatformPermissionUtil {
     val privateBroadcastPermission: String
     fun isCameraPermissionGranted(): Boolean
-
+    fun isMicrophonePermissionGranted(): Boolean
+    fun isBluetoothPermissionGranted(): Boolean
     fun isFilesPermissionGranted(): Boolean
 }

+ 16 - 0
app/src/main/java/com/nextcloud/talk/utils/permissions/PlatformPermissionUtilImpl.kt

@@ -25,6 +25,7 @@ import android.Manifest
 import android.content.Context
 import android.os.Build
 import android.util.Log
+import androidx.annotation.RequiresApi
 import androidx.core.content.PermissionChecker
 import com.nextcloud.talk.BuildConfig
 
@@ -39,6 +40,21 @@ class PlatformPermissionUtilImpl(private val context: Context) : PlatformPermiss
         ) == PermissionChecker.PERMISSION_GRANTED
     }
 
+    @RequiresApi(Build.VERSION_CODES.S)
+    override fun isBluetoothPermissionGranted(): Boolean {
+        return PermissionChecker.checkSelfPermission(
+            context,
+            Manifest.permission.BLUETOOTH_CONNECT
+        ) == PermissionChecker.PERMISSION_GRANTED
+    }
+
+    override fun isMicrophonePermissionGranted(): Boolean {
+        return PermissionChecker.checkSelfPermission(
+            context,
+            Manifest.permission.RECORD_AUDIO
+        ) == PermissionChecker.PERMISSION_GRANTED
+    }
+
     override fun isFilesPermissionGranted(): Boolean {
         return when {
             Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {

+ 8 - 3
app/src/main/res/values/strings.xml

@@ -28,7 +28,7 @@
 How to work with translations as a developer:
 - Only add new translations to values/stings.xml, don't do this for other languages (it will be done via transifex).
 - Never change the key of a translation. If it really has to be changed, delete it and create a new entry instead.
-- If you change a value in values/stings.xml, also backport this to all stable branches.
+- If you change a value in values/strings.xml, also backport this to all stable branches.
 - Translations are synced every night (or when manually triggered):
    - New entries are added to transifex.com
    - Updated translations from transifex are added via Nextcloud bot to this repo.
@@ -216,9 +216,14 @@ How to translate with transifex:
     <string name="nc_contacts_done">Done</string>
 
     <!-- Permissions -->
-    <string name="nc_camera_permission_permanently_denied">To enable video communication please grant \"Camera\" permission in the system settings.</string>
-    <string name="nc_microphone_permission_permanently_denied">To enable voice communication please grant \"Microphone\" permission in the system settings.</string>
+    <string name="nc_permissions_rationale_dialog_title">Please allow permissions</string>
+    <string name="nc_permissions_denied">Some permissions were denied.</string>
+    <string name="nc_permissions_settings_hint">Please grant permissions at Settings > Permissions</string>
     <string name="nc_permissions_settings">Open settings</string>
+    <string name="nc_permissions_ask">Set permissions</string>
+    <string name="nc_camera_permission_hint">To enable video communication please grant \"Camera\" permission.</string>
+    <string name="nc_microphone_permission_hint">To enable voice communication please grant \"Microphone\" permission.</string>
+    <string name="nc_bluetooth_permission_hint">To enable bluetooth speakers please grant \"Nearby devices\" permission.</string>
 
     <!-- Call -->
     <string name="nc_call_voice">%s voice call</string>