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

Commit b3502b4e authored by Joey's avatar Joey Committed by Michael W
Browse files

Recorder: Add support for tagging records with location name



[BadDaemon]
Also show rationale and modify state of switch according to
the actual granted status

Change-Id: I0d9372c6b229e1500c224d59e1322881af9a8bde
Signed-off-by: default avatarJoey <joey@lineageos.org>
parent 1a936288
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:tools="http://schemas.android.com/tools"
    package="org.lineageos.recorder">
    package="org.lineageos.recorder">


    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <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.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+99 −1
Original line number Original line Diff line number Diff line
@@ -15,9 +15,13 @@
 */
 */
package org.lineageos.recorder;
package org.lineageos.recorder;


import android.Manifest;
import android.content.Intent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.net.Uri;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup;
@@ -30,17 +34,25 @@ import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SwitchCompat;


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


public class DialogActivity extends AppCompatActivity {
public class DialogActivity extends AppCompatActivity {
    public static final String EXTRA_TITLE = "dialogTitle";
    public static final String EXTRA_TITLE = "dialogTitle";
    public static final String EXTRA_DELETE_LAST_RECORDING = "deleteLastItem";
    public static final String EXTRA_DELETE_LAST_RECORDING = "deleteLastItem";
    public static final String EXTRA_SETTINGS_SCREEN = "settingsScreen";
    private static final int REQUEST_LOCATION_PERMS = 214;
    private static final String TYPE_AUDIO = "audio/wav";
    private static final String TYPE_AUDIO = "audio/wav";


    private LinearLayout mRootView;
    private LinearLayout mRootView;
    private FrameLayout mContent;
    private FrameLayout mContent;


    private SwitchCompat mLocationSwitch;

    private SharedPreferences mPrefs;

    @Override
    @Override
    protected void onCreate(Bundle savedInstance) {
    protected void onCreate(Bundle savedInstance) {
        super.onCreate(savedInstance);
        super.onCreate(savedInstance);
@@ -52,8 +64,11 @@ public class DialogActivity extends AppCompatActivity {
        TextView title = findViewById(R.id.dialog_title);
        TextView title = findViewById(R.id.dialog_title);
        mContent = findViewById(R.id.dialog_content);
        mContent = findViewById(R.id.dialog_content);


        mPrefs = getSharedPreferences(Utils.PREFS, 0);

        Intent intent = getIntent();
        Intent intent = getIntent();
        int dialogTitle = intent.getIntExtra(EXTRA_TITLE, 0);
        int dialogTitle = intent.getIntExtra(EXTRA_TITLE, 0);
        boolean isSettingsScreen = intent.getBooleanExtra(EXTRA_SETTINGS_SCREEN, false);


        getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
        getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
                ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -62,7 +77,12 @@ public class DialogActivity extends AppCompatActivity {
            title.setText(dialogTitle);
            title.setText(dialogTitle);
        }
        }


        if (isSettingsScreen) {
            setupAsSettingsScreen();
        } else {
            setupAsLastItem();
            setupAsLastItem();
        }

        animateAppearance();
        animateAppearance();


        boolean deleteLastRecording = intent.getBooleanExtra(EXTRA_DELETE_LAST_RECORDING, false);
        boolean deleteLastRecording = intent.getBooleanExtra(EXTRA_DELETE_LAST_RECORDING, false);
@@ -80,6 +100,32 @@ public class DialogActivity extends AppCompatActivity {
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] results) {
                                           @NonNull int[] results) {
        super.onRequestPermissionsResult(requestCode, permissions, 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();
        } 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();
            mLocationSwitch.setChecked(false);
        }
    }
    }


    @Override
    @Override
@@ -129,8 +175,60 @@ public class DialogActivity extends AppCompatActivity {
        startActivity(LastRecordHelper.getShareIntent(uri, TYPE_AUDIO));
        startActivity(LastRecordHelper.getShareIntent(uri, TYPE_AUDIO));
    }
    }


    private void setupAsSettingsScreen() {
        final View view = createContentView(R.layout.dialog_content_settings);
        mLocationSwitch = view.findViewById(R.id.dialog_content_settings_location_switch);
        boolean hasLocationPerm = hasLocationPermission();
        boolean tagWithLocation = getTagWithLocation();
        if (tagWithLocation && !hasLocationPerm) {
            setTagWithLocation(false);
            tagWithLocation = false;
        }
        mLocationSwitch.setChecked(tagWithLocation);
        mLocationSwitch.setOnCheckedChangeListener((button, isChecked) -> {
            if (isChecked) {
                if (hasLocationPermission()) {
                    setTagWithLocation(true);
                } else {
                    askLocationPermission();
                }
            } else {
                setTagWithLocation(false);
            }
        });

        if (Utils.isRecording(this)) {
            mLocationSwitch.setEnabled(false);
        }
    }

    private View createContentView(@LayoutRes int layout) {
    private View createContentView(@LayoutRes int layout) {
        LayoutInflater inflater = getLayoutInflater();
        LayoutInflater inflater = getLayoutInflater();
        return inflater.inflate(layout, mContent);
        return inflater.inflate(layout, mContent);
    }
    }

    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 setTagWithLocation(boolean enabled) {
        mPrefs.edit().putBoolean(Utils.PREF_TAG_WITH_LOCATION, enabled).apply();
    }

    private boolean getTagWithLocation() {
        return mPrefs.getBoolean(Utils.PREF_TAG_WITH_LOCATION, false);
    }

    private void toggleAfterPermissionRequest(int requestCode) {
        if (requestCode == REQUEST_LOCATION_PERMS) {
            mLocationSwitch.setChecked(true);
            setTagWithLocation(true);
        }
    }
}
}
+16 −1
Original line number Original line Diff line number Diff line
@@ -45,6 +45,7 @@ import org.lineageos.recorder.sounds.RecorderBinder;
import org.lineageos.recorder.sounds.SoundRecorderService;
import org.lineageos.recorder.sounds.SoundRecorderService;
import org.lineageos.recorder.ui.WaveFormView;
import org.lineageos.recorder.ui.WaveFormView;
import org.lineageos.recorder.utils.LastRecordHelper;
import org.lineageos.recorder.utils.LastRecordHelper;
import org.lineageos.recorder.utils.LocationHelper;
import org.lineageos.recorder.utils.OnBoardingHelper;
import org.lineageos.recorder.utils.OnBoardingHelper;
import org.lineageos.recorder.utils.Utils;
import org.lineageos.recorder.utils.Utils;


@@ -68,10 +69,13 @@ public class RecorderActivity extends AppCompatActivity implements


    private FloatingActionButton mSoundFab;
    private FloatingActionButton mSoundFab;
    private ImageView mSoundLast;
    private ImageView mSoundLast;
    private ImageView mSettings;


    private TextView mRecordingText;
    private TextView mRecordingText;
    private WaveFormView mRecordingVisualizer;
    private WaveFormView mRecordingVisualizer;


    private LocationHelper mLocationHelper;

    private final BroadcastReceiver mTelephonyReceiver = new BroadcastReceiver() {
    private final BroadcastReceiver mTelephonyReceiver = new BroadcastReceiver() {
        @Override
        @Override
        public void onReceive(Context context, Intent intent) {
        public void onReceive(Context context, Intent intent) {
@@ -92,16 +96,20 @@ public class RecorderActivity extends AppCompatActivity implements


        mSoundFab = findViewById(R.id.sound_fab);
        mSoundFab = findViewById(R.id.sound_fab);
        mSoundLast = findViewById(R.id.sound_last_icon);
        mSoundLast = findViewById(R.id.sound_last_icon);
        mSettings = findViewById(R.id.sound_settings);


        mRecordingText = findViewById(R.id.main_title);
        mRecordingText = findViewById(R.id.main_title);
        mRecordingVisualizer = findViewById(R.id.main_recording_visualizer);
        mRecordingVisualizer = findViewById(R.id.main_recording_visualizer);


        mSoundFab.setOnClickListener(v -> toggleSoundRecorder());
        mSoundFab.setOnClickListener(v -> toggleSoundRecorder());
        mSoundLast.setOnClickListener(v -> openLastSound());
        mSoundLast.setOnClickListener(v -> openLastSound());
        mSettings.setOnClickListener(v -> openSettings());


        mPrefs = getSharedPreferences(Utils.PREFS, 0);
        mPrefs = getSharedPreferences(Utils.PREFS, 0);
        mPrefs.registerOnSharedPreferenceChangeListener(this);
        mPrefs.registerOnSharedPreferenceChangeListener(this);


        mLocationHelper = new LocationHelper(this);

        bindSoundRecService();
        bindSoundRecService();
    }
    }


@@ -215,7 +223,7 @@ public class RecorderActivity extends AppCompatActivity implements
        } else {
        } else {
            // Start
            // Start
            startService(new Intent(this, SoundRecorderService.class));
            startService(new Intent(this, SoundRecorderService.class));
            mSoundService.startRecording();
            mSoundService.startRecording(mLocationHelper.getCurrentLocationName());
            Utils.setStatus(this, Utils.UiStatus.SOUND);
            Utils.setStatus(this, Utils.UiStatus.SOUND);
        }
        }
        refresh();
        refresh();
@@ -322,6 +330,13 @@ public class RecorderActivity extends AppCompatActivity implements
                REQUEST_DIALOG_ACTIVITY, options.toBundle());
                REQUEST_DIALOG_ACTIVITY, options.toBundle());
    }
    }


    private void openSettings() {
        Intent intent = new Intent(this, DialogActivity.class);
        intent.putExtra(DialogActivity.EXTRA_TITLE, R.string.settings_title);
        intent.putExtra(DialogActivity.EXTRA_SETTINGS_SCREEN, true);
        showDialog(intent, mSettings);
    }

    private void openLastSound() {
    private void openLastSound() {
        Intent intent = new Intent(this, DialogActivity.class);
        Intent intent = new Intent(this, DialogActivity.class);
        intent.putExtra(DialogActivity.EXTRA_TITLE, R.string.sound_last_title);
        intent.putExtra(DialogActivity.EXTRA_TITLE, R.string.sound_last_title);
+8 −9
Original line number Original line Diff line number Diff line
@@ -99,7 +99,7 @@ public class SoundRecorderService extends Service implements MediaProviderHelper
    public int onStartCommand(Intent intent, int flags, int startId) {
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
        if (intent != null) {
            if (ACTION_STARTED.equals(intent.getAction())) {
            if (ACTION_STARTED.equals(intent.getAction())) {
                startRecording();
                startRecording(intent.getStringExtra(EXTRA_FILE));
            } else if (ACTION_STOPPED.equals(intent.getAction())) {
            } else if (ACTION_STOPPED.equals(intent.getAction())) {
                stopRecording();
                stopRecording();
            }
            }
@@ -151,7 +151,7 @@ public class SoundRecorderService extends Service implements MediaProviderHelper
        return mStatus == RecorderStatus.RECORDING;
        return mStatus == RecorderStatus.RECORDING;
    }
    }


    public void startRecording() {
    public void startRecording(@Nullable String locationName) {
        Log.d(TAG, "Sound recorder service started recording\u2026");
        Log.d(TAG, "Sound recorder service started recording\u2026");
        mElapsedTime = 0;
        mElapsedTime = 0;


@@ -159,11 +159,7 @@ public class SoundRecorderService extends Service implements MediaProviderHelper
            return;
            return;
        }
        }


        File file = createNewAudioFile();
        File file = createNewAudioFile(locationName);
        if (file == null) {
            return;
        }

        mFilePath = file.getAbsolutePath();
        mFilePath = file.getAbsolutePath();
        String fileName = file.getName().replace(EXTENSION, "");
        String fileName = file.getName().replace(EXTENSION, "");


@@ -218,11 +214,14 @@ public class SoundRecorderService extends Service implements MediaProviderHelper
                getContentResolver(), new File(mOutFilePath), this);
                getContentResolver(), new File(mOutFilePath), this);
    }
    }


    private File createNewAudioFile() {
    private File createNewAudioFile(@Nullable String locationName) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss",
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss",
                Locale.getDefault());
                Locale.getDefault());
        final String baseName = "SoundRecords/%1$s (%2$s)%3$s";

        File file = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC),
        File file = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC),
                "SoundRecords/SoundRecord-" + dateFormat.format(new Date()) + EXTENSION);
                String.format(baseName, locationName == null ? "Sound record" : locationName,
                        dateFormat.format(new Date()), EXTENSION));
        File recordingDir = file.getParentFile();
        File recordingDir = file.getParentFile();
        if (recordingDir != null && !recordingDir.exists()) {
        if (recordingDir != null && !recordingDir.exists()) {
            //noinspection ResultOfMethodCallIgnored
            //noinspection ResultOfMethodCallIgnored
+105 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2020-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.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.IOException;
import java.util.List;

public final class LocationHelper {
    private static final String TAG = "LocationHelper";

    @NonNull
    private final Context context;

    @Nullable
    private final LocationManager locationManager;

    public LocationHelper(@NonNull Context context) {
        this.context = context;

        locationManager = context.getSystemService(LocationManager.class);
    }

    @Nullable
    public String getCurrentLocationName() {
        final Location lastGoodLocation = getLastGoodLocation();
        if (lastGoodLocation == null) {
            return null;
        }

        final Geocoder geocoder = new Geocoder(context);
        try {
            final List<Address> addressList = geocoder.getFromLocation(
                    lastGoodLocation.getLatitude(), lastGoodLocation.getLongitude(), 1);
            if (addressList.isEmpty()) {
                return null;
            }

            final Address address = addressList.get(0);
            final String featureName = address.getFeatureName();
            // Street numbers may be returned here, ignore them
            if (featureName != null && featureName.length() > 3) {
                return featureName;
            }
            final String locality = address.getLocality();
            if (locality != null) {
                return locality;
            }
            return address.getCountryName();
        } catch (IOException e) {
            Log.e(TAG, "Failed to obtain address from last known location", e);
        }
        return null;
    }

    @Nullable
    private Location getLastGoodLocation() {
        if (locationManager == null) {
            return null;
        }
        Location lastGoodLocation;
        try {
            lastGoodLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            if (lastGoodLocation == null) {
                // Try network provider
                lastGoodLocation = locationManager.getLastKnownLocation(
                        LocationManager.NETWORK_PROVIDER);
            }
            if (lastGoodLocation == null) {
                // Fallback from passive provider
                lastGoodLocation = locationManager.getLastKnownLocation(
                        LocationManager.PASSIVE_PROVIDER);
            }
        } catch (SecurityException e) {
            return null;
        }

        if (lastGoodLocation == null || lastGoodLocation.getAccuracy() == 0f) {
            return null;
        }
        return lastGoodLocation;
    }
}
Loading