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

Commit 99911fa7 authored by Michael W's avatar Michael W
Browse files

Dialer: Remove WRITE_EXTERNAL_STORAGE permission

* Callrecording has been moved away from using the external storage
  in lineage-17.1 in commit 05afe35d
* On R or higher, the permission has no effect, resulting in recordings
  to not work since the request for the permission always fails
* Auto-migration also fails due to that
* It's 2023 and 3 versions later (with the 4th being worked on), whoever
  hasn't got the recordings migrated yet won't do so anymore, anyway

Change-Id: I38182b7d22895cc8f7c6cfec1776b93e2a705e16
parent 6800bf53
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.VIBRATE" />
@@ -114,7 +113,6 @@
        android:hardwareAccelerated="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/applicationLabel"
        android:requestLegacyExternalStorage="true"
        android:supportsRtl="true"
        android:usesCleartextTraffic="false">

+0 −6
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ import android.os.Trace;

import androidx.annotation.NonNull;

import com.android.dialer.callrecord.CallRecordingAutoMigrator;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.inject.HasRootComponent;
import com.android.dialer.notification.NotificationChannelManager;
import com.android.dialer.persistentlog.PersistentLogger;
@@ -36,10 +34,6 @@ public abstract class DialerApplication extends Application implements HasRootCo
  public void onCreate() {
    Trace.beginSection("DialerApplication.onCreate");
    super.onCreate();
    new CallRecordingAutoMigrator(
            this.getApplicationContext(),
            DialerExecutorComponent.get(this).dialerExecutorFactory())
        .asyncAutoMigrate();
    PersistentLogger.initialize(this);
    NotificationChannelManager.initChannels(this);
    Trace.endSection();
+0 −152
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 * Copyright (C) 2020 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 com.android.dialer.callrecord;

import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.SparseArray;

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

import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor.Worker;
import com.android.dialer.common.concurrent.DialerExecutorFactory;
import com.android.voicemail.impl.mail.utils.LogUtils;

import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;

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

  @NonNull
  private final Context appContext;
  @NonNull private final DialerExecutorFactory dialerExecutorFactory;

  public CallRecordingAutoMigrator(
      @NonNull Context appContext,
      @NonNull DialerExecutorFactory dialerExecutorFactory) {
    this.appContext = Assert.isNotNull(appContext);
    this.dialerExecutorFactory = Assert.isNotNull(dialerExecutorFactory);
  }

  public void asyncAutoMigrate() {
    dialerExecutorFactory
        .createNonUiTaskBuilder(new ShouldAttemptAutoMigrate(appContext))
        .onSuccess(this::autoMigrate)
        .build()
        .executeParallel(null);
  }

  private void autoMigrate(boolean shouldAttemptAutoMigrate) {
    if (!shouldAttemptAutoMigrate) {
      return;
    }

    final CallRecordingDataStore store = new CallRecordingDataStore();
    store.open(appContext);

    final ContentResolver cr = appContext.getContentResolver();
    final SparseArray<CallRecording> oldRecordingData = store.getUnmigratedRecordingData();
    final File dir = Environment.getExternalStoragePublicDirectory("CallRecordings");
    for (File recording : dir.listFiles()) {
      OutputStream os = null;
      try {
        // determine data store ID and call creation time of recording
        int id = -1;
        long creationTime = System.currentTimeMillis();
        for (int i = 0; i < oldRecordingData.size(); i++) {
          if (TextUtils.equals(recording.getName(), oldRecordingData.valueAt(i).fileName)) {
            creationTime = oldRecordingData.valueAt(i).creationTime;
            id = oldRecordingData.keyAt(i);
            break;
          }
        }

        // create media store entry for recording
        Uri uri = cr.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
            CallRecording.generateMediaInsertValues(recording.getName(), creationTime));
        os = cr.openOutputStream(uri);

        // copy file contents to media store stream
        Files.copy(recording.toPath(), os);

        // insert media store id to store
        if (id >= 0) {
          store.updateMigratedRecording(id, Integer.parseInt(uri.getLastPathSegment()));
        }

        // mark recording as complete
        cr.update(uri, CallRecording.generateCompletedValues(), null, null);

        // delete file
        LogUtils.i(TAG, "Successfully migrated recording " + recording + " (ID " + id + ")");
        recording.delete();
      } catch (IOException e) {
        LogUtils.w(TAG, "Failed migrating call recording " + recording, e);
      } finally {
        if (os != null) {
          IOUtils.closeQuietly(os);
        }
      }
    }

    if (dir.listFiles().length == 0) {
      dir.delete();
    }

    store.close();
  }

  private static class ShouldAttemptAutoMigrate implements Worker<Void, Boolean> {
    private final Context appContext;

    ShouldAttemptAutoMigrate(Context appContext) {
      this.appContext = appContext;
    }

    @Nullable
    @Override
    public Boolean doInBackground(@Nullable Void input) {
      if (appContext.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
          != PackageManager.PERMISSION_GRANTED) {
        LogUtil.i(TAG, "not attempting auto-migrate: no storage permission");
        return false;
      }

      final File dir = Environment.getExternalStoragePublicDirectory("CallRecordings");
      if (!dir.exists()) {
        LogUtil.i(TAG, "not attempting auto-migrate: no recordings present");
        return false;
      }

      return true;
    }
  }
}
+1 −2
Original line number Diff line number Diff line
@@ -57,8 +57,7 @@ public class CallRecorder implements CallList.Listener {
  public static final String TAG = "CallRecorder";

  public static final String[] REQUIRED_PERMISSIONS = new String[] {
    android.Manifest.permission.RECORD_AUDIO,
    android.Manifest.permission.WRITE_EXTERNAL_STORAGE
    android.Manifest.permission.RECORD_AUDIO
  };
  private static final HashMap<String, Boolean> RECORD_ALLOWED_STATE_BY_COUNTRY = new HashMap<>();