Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e11902b0 authored by 2bllw8's avatar 2bllw8
Browse files

Recorder: move permissions management code to its own class

Change-Id: I979cfdd0cd37a49a62668d83abdc8f9269895c06
parent 40983990
Loading
Loading
Loading
Loading
+17 −47
Original line number Diff line number Diff line
@@ -15,8 +15,6 @@
 */
package org.lineageos.recorder;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;

import androidx.annotation.NonNull;
@@ -25,17 +23,19 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SwitchCompat;

import org.lineageos.recorder.utils.PermissionManager;
import org.lineageos.recorder.utils.Utils;

public class DialogActivity extends AppCompatActivity {
    private static final int REQUEST_LOCATION_PERMS = 214;

    private PermissionManager mPermissionManager;
    private SwitchCompat mLocationSwitch;

    @Override
    protected void onCreate(@Nullable Bundle savedInstance) {
        super.onCreate(savedInstance);

        mPermissionManager = new PermissionManager(this);

        setFinishOnTouchOutside(true);

        final AlertDialog dialog = new AlertDialog.Builder(this)
@@ -62,33 +62,15 @@ public class DialogActivity extends AppCompatActivity {
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] results) {
        super.onRequestPermissionsResult(requestCode, permissions, results);
        if (hasLocationPermission()) {
            toggleAfterPermissionRequest(requestCode);
            return;
        }

        if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
            new AlertDialog.Builder(this)
                    .setTitle(R.string.dialog_permissions_title)
                    .setMessage(getString(R.string.dialog_permissions_location))
                    .setPositiveButton(R.string.dialog_permissions_ask,
                            (dialog, position) -> {
                                dialog.dismiss();
                                askLocationPermission();
                            })
                    .setNegativeButton(R.string.dialog_permissions_dismiss,
                            (dialog, position) -> mLocationSwitch.setChecked(false))
                    .show();
        if (requestCode == PermissionManager.REQUEST_CODE) {
            if (mPermissionManager.hasLocationPermission()) {
                toggleAfterPermissionRequest();
            } else {
            // User has denied all the required permissions "forever"
            new AlertDialog.Builder(this)
                    .setTitle(R.string.dialog_permissions_title)
                    .setMessage(R.string.snack_permissions_no_permission_location)
                    .setPositiveButton(R.string.dialog_permissions_dismiss, null)
                    .show();
                mPermissionManager.onLocationPermissionDenied();
                mLocationSwitch.setChecked(false);
            }
        }
    }

    @Override
    public void onBackPressed() {
@@ -105,7 +87,7 @@ public class DialogActivity extends AppCompatActivity {
                                     boolean isRecording) {
        final boolean tagWithLocation;
        if (Utils.getTagWithLocation(this)) {
            if (hasLocationPermission()) {
            if (mPermissionManager.hasLocationPermission()) {
                tagWithLocation = true;
            } else {
                // Permission revoked -> disabled feature
@@ -123,10 +105,10 @@ public class DialogActivity extends AppCompatActivity {
        } else {
            locationSwitch.setOnCheckedChangeListener((button, isChecked) -> {
                if (isChecked) {
                    if (hasLocationPermission()) {
                    if (mPermissionManager.hasLocationPermission()) {
                        Utils.setTagWithLocation(this, true);
                    } else {
                        askLocationPermission();
                        mPermissionManager.requestLocationPermission();
                    }
                } else {
                    Utils.setTagWithLocation(this, false);
@@ -148,20 +130,8 @@ public class DialogActivity extends AppCompatActivity {
        }
    }

    private boolean hasLocationPermission() {
        int result = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
        return result == PackageManager.PERMISSION_GRANTED;
    }

    private void askLocationPermission() {
        requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                REQUEST_LOCATION_PERMS);
    }

    private void toggleAfterPermissionRequest(int requestCode) {
        if (requestCode == REQUEST_LOCATION_PERMS) {
    private void toggleAfterPermissionRequest() {
        mLocationSwitch.setChecked(true);
        Utils.setTagWithLocation(this, true);
    }
}
}
+15 −96
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@ package org.lineageos.recorder;

import static android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -25,7 +24,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -52,21 +50,11 @@ import org.lineageos.recorder.ui.WaveFormView;
import org.lineageos.recorder.utils.LastRecordHelper;
import org.lineageos.recorder.utils.LocationHelper;
import org.lineageos.recorder.utils.OnBoardingHelper;
import org.lineageos.recorder.utils.PermissionManager;
import org.lineageos.recorder.utils.Utils;

import java.util.ArrayList;

public class RecorderActivity extends AppCompatActivity implements
        SharedPreferences.OnSharedPreferenceChangeListener {
    private static final int REQUEST_SOUND_REC_PERMS = 440;

    private static final int[] PERMISSION_ERROR_MESSAGE_RES_IDS = {
            0,
            R.string.dialog_permissions_mic,
            R.string.dialog_permissions_phone,
            R.string.dialog_permissions_mic_phone,
    };

    private ServiceConnection mConnection;
    private SoundRecorderService mSoundService;
    private SharedPreferences mPrefs;
@@ -78,6 +66,7 @@ public class RecorderActivity extends AppCompatActivity implements
    private WaveFormView mRecordingVisualizer;

    private LocationHelper mLocationHelper;
    private PermissionManager mPermissionManager;
    private TaskExecutor mTaskExecutor;

    private boolean mReturnAudio;
@@ -121,6 +110,7 @@ public class RecorderActivity extends AppCompatActivity implements
        mPrefs.registerOnSharedPreferenceChangeListener(this);

        mLocationHelper = new LocationHelper(this);
        mPermissionManager = new PermissionManager(this);

        mTaskExecutor = new TaskExecutor();
        getLifecycle().addObserver(mTaskExecutor);
@@ -170,42 +160,12 @@ public class RecorderActivity extends AppCompatActivity implements
                                           @NonNull int[] results) {

        super.onRequestPermissionsResult(requestCode, permissions, results);
        if (hasAllAudioRecorderPermissions()) {
            toggleAfterPermissionRequest(requestCode);
            return;
        }

        if (shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO) ||
                shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE)) {
            // Explain the user why the denied permission is needed
            int error = 0;

            if (!hasAudioPermission()) {
                error |= 1;
            }
            if (!hasPhoneReaderPermission()) {
                error |= 1 << 1;
            }

            String message = getString(PERMISSION_ERROR_MESSAGE_RES_IDS[error]);

            new AlertDialog.Builder(this)
                    .setTitle(R.string.dialog_permissions_title)
                    .setMessage(message)
                    .setPositiveButton(R.string.dialog_permissions_ask,
                            (dialog, position) -> {
                                dialog.dismiss();
                                askPermissionsAgain(requestCode);
                            })
                    .setNegativeButton(R.string.dialog_permissions_dismiss, null)
                    .show();
        if (requestCode == PermissionManager.REQUEST_CODE) {
            if (mPermissionManager.hasEssentialPermissions()) {
                toggleAfterPermissionRequest();
            } else {
            // User has denied all the required permissions "forever"
            new AlertDialog.Builder(this)
                    .setTitle(R.string.dialog_permissions_title)
                    .setMessage(R.string.snack_permissions_no_permission)
                    .setPositiveButton(R.string.dialog_permissions_dismiss, null)
                    .show();
                mPermissionManager.onEssentialPermissionsDenied();
            }
        }
    }

@@ -221,21 +181,13 @@ public class RecorderActivity extends AppCompatActivity implements
    }


    private void toggleAfterPermissionRequest(int requestCode) {
        if (requestCode == REQUEST_SOUND_REC_PERMS) {
    private void toggleAfterPermissionRequest() {
        bindSoundRecService();
        new Handler(Looper.getMainLooper()).postDelayed(this::toggleSoundRecorder, 500);
    }
    }

    private void askPermissionsAgain(int requestCode) {
        if (requestCode == REQUEST_SOUND_REC_PERMS) {
            checkSoundRecPermissions();
        }
    }

    private void toggleSoundRecorder() {
        if (checkSoundRecPermissions()) {
        if (mPermissionManager.requestEssentialPermissions()) {
            return;
        }

@@ -305,42 +257,9 @@ public class RecorderActivity extends AppCompatActivity implements
        }
    }

    private boolean hasAudioPermission() {
        int result = checkSelfPermission(Manifest.permission.RECORD_AUDIO);
        return result == PackageManager.PERMISSION_GRANTED;
    }

    private boolean hasPhoneReaderPermission() {
        int result = checkSelfPermission(Manifest.permission.READ_PHONE_STATE);
        return result == PackageManager.PERMISSION_GRANTED;
    }

    private boolean hasAllAudioRecorderPermissions() {
        return hasAudioPermission() && hasPhoneReaderPermission();
    }

    private boolean checkSoundRecPermissions() {
        ArrayList<String> permissions = new ArrayList<>();

        if (!hasAudioPermission()) {
            permissions.add(Manifest.permission.RECORD_AUDIO);
        }

        if (!hasPhoneReaderPermission()) {
            permissions.add(Manifest.permission.READ_PHONE_STATE);
        }

        if (permissions.isEmpty()) {
            return false;
        }

        String[] permissionArray = permissions.toArray(new String[0]);
        requestPermissions(permissionArray, REQUEST_SOUND_REC_PERMS);
        return true;
    }

    private void setupConnection() {
        checkSoundRecPermissions();
        mPermissionManager.requestEssentialPermissions();

        mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder binder) {
@@ -356,7 +275,7 @@ public class RecorderActivity extends AppCompatActivity implements
    }

    private void bindSoundRecService() {
        if (mSoundService == null && hasAllAudioRecorderPermissions()) {
        if (mSoundService == null && mPermissionManager.hasEssentialPermissions()) {
            setupConnection();
            bindService(new Intent(this, SoundRecorderService.class),
                    mConnection, BIND_AUTO_CREATE);
+142 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The LineageOS Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.lineageos.recorder.utils;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;

import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;

import org.lineageos.recorder.R;

import java.util.ArrayList;
import java.util.List;

public final class PermissionManager {
    public static final int REQUEST_CODE = 440;

    private static final int[] PERMISSION_ERROR_MESSAGE_RES_IDS = {
            0,
            R.string.dialog_permissions_mic,
            R.string.dialog_permissions_phone,
            R.string.dialog_permissions_mic_phone,
    };

    private final Activity activity;

    public PermissionManager(Activity activity) {
        this.activity = activity;
    }

    public boolean requestEssentialPermissions() {
        final List<String> missingPermissions = new ArrayList<>();
        if (!hasRecordAudioPermission()) {
            missingPermissions.add(Manifest.permission.RECORD_AUDIO);
        }
        if (!hasPhoneReadStatusPermission()) {
            missingPermissions.add(Manifest.permission.READ_PHONE_STATE);
        }

        if (missingPermissions.isEmpty()) {
            return false;
        } else {
            final String[] requestArray = missingPermissions.toArray(new String[0]);
            activity.requestPermissions(requestArray, REQUEST_CODE);
            return true;
        }
    }

    public void requestLocationPermission() {
        if (!hasLocationPermission()) {
            final String[] requestArray = {Manifest.permission.ACCESS_FINE_LOCATION};
            activity.requestPermissions(requestArray, REQUEST_CODE);
        }
    }

    public boolean hasEssentialPermissions() {
        return hasRecordAudioPermission() && hasPhoneReadStatusPermission();
    }

    public boolean hasRecordAudioPermission() {
        return activity.checkSelfPermission(Manifest.permission.RECORD_AUDIO)
                == PackageManager.PERMISSION_GRANTED;
    }

    public boolean hasPhoneReadStatusPermission() {
        return activity.checkSelfPermission(Manifest.permission.READ_PHONE_STATE)
                == PackageManager.PERMISSION_GRANTED;
    }

    public boolean hasLocationPermission() {
        return activity.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED;
    }

    public void onEssentialPermissionsDenied() {
        if (activity.shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE) ||
                activity.shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO)) {
            // Explain the user why the denied permission is needed
            int error = 0;

            if (!hasRecordAudioPermission()) {
                error |= 1;
            }
            if (!hasPhoneReadStatusPermission()) {
                error |= 1 << 1;
            }

            showPermissionRationale(PERMISSION_ERROR_MESSAGE_RES_IDS[error],
                    this::requestEssentialPermissions);
        } else {
            // User has denied all the required permissions "forever"
            showPermissionError(R.string.snack_permissions_no_permission);
        }
    }

    public void onLocationPermissionDenied() {
        if (activity.shouldShowRequestPermissionRationale(
                Manifest.permission.ACCESS_FINE_LOCATION)) {
            showPermissionRationale(R.string.dialog_permissions_location,
                    this::requestLocationPermission);
        } else {
            showPermissionError(R.string.snack_permissions_no_permission_location);
        }
    }

    private void showPermissionRationale(@StringRes int messageRes,
                                         Runnable requestAgain) {
        new AlertDialog.Builder(activity)
                .setTitle(R.string.dialog_permissions_title)
                .setMessage(messageRes)
                .setPositiveButton(R.string.dialog_permissions_ask,
                        (dialog, position) -> {
                            dialog.dismiss();
                            requestAgain.run();
                        })
                .setNegativeButton(R.string.dialog_permissions_dismiss, null)
                .show();
    }

    private void showPermissionError(@StringRes int messageRes) {
        new AlertDialog.Builder(activity)
                .setTitle(R.string.dialog_permissions_title)
                .setMessage(messageRes)
                .setPositiveButton(R.string.dialog_permissions_dismiss, null)
                .show();
    }
}