content: package de.danoeh.antennapod.storage.importexport;
  
  import android.Manifest;
  import android.app.Notification;
  import android.app.NotificationManager;
  import android.app.PendingIntent;
  import android.content.Context;
  import android.content.Intent;
  import android.content.pm.PackageManager;
  import android.net.Uri;
  import android.os.Build;
  import android.widget.Toast;
  import androidx.annotation.NonNull;
  import androidx.core.app.NotificationCompat;
  import androidx.core.content.ContextCompat;
  import androidx.documentfile.provider.DocumentFile;
  import androidx.work.ExistingPeriodicWorkPolicy;
  import androidx.work.PeriodicWorkRequest;
  import androidx.work.WorkManager;
  import androidx.work.Worker;
  import androidx.work.WorkerParameters;
  import de.danoeh.antennapod.event.MessageEvent;
  import de.danoeh.antennapod.storage.preferences.UserPreferences;
  import de.danoeh.antennapod.ui.notifications.NotificationUtils;
  import java.io.IOException;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.Date;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Locale;
  import java.util.concurrent.TimeUnit;
  import org.greenrobot.eventbus.EventBus;
  
  public class AutomaticDatabaseExportWorker extends Worker {
      private static final String WORK_ID_AUTOMATIC_DATABASE_EXPORT = "de.danoeh.antennapod.AutomaticDbExport";
  
      public static void enqueueIfNeeded(Context context, boolean replace) {
          if (UserPreferences.getAutomaticExportFolder() == null) {
              WorkManager.getInstance(context).cancelUniqueWork(WORK_ID_AUTOMATIC_DATABASE_EXPORT);
          } else {
              PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
                          AutomaticDatabaseExportWorker.class, 3, TimeUnit.DAYS)
                      .build();
              WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_ID_AUTOMATIC_DATABASE_EXPORT,
                      replace ? ExistingPeriodicWorkPolicy.REPLACE : ExistingPeriodicWorkPolicy.KEEP, workRequest);
          }
      }
  
      public AutomaticDatabaseExportWorker(@NonNull Context context, @NonNull WorkerParameters params) {
          super(context, params);
      }
  
      @Override
      @NonNull
      public Result doWork() {
          String folderUri = UserPreferences.getAutomaticExportFolder();
          if (folderUri == null) {
              return Result.success();
          }
          try {
              export(folderUri);
              return Result.success();
          } catch (IOException e) {
              showErrorNotification(e);
              return Result.failure();
          }
      }
  
      private void export(String folderUri) throws IOException {
          DocumentFile documentFolder = DocumentFile.fromTreeUri(getApplicationContext(), Uri.parse(folderUri));
          if (documentFolder == null || !documentFolder.exists() || !documentFolder.canWrite()) {
              throw new IOException("Unable to open export folder");
          }
          String filename = String.format("AntennaPodBackup-%s.db",
                  new SimpleDateFormat("yyyy-MM-dd", Locale.US).format(new Date()));
          DocumentFile exportFile = documentFolder.createFile("application/x-sqlite3", filename);
          if (exportFile == null || !exportFile.canWrite()) {
              throw new IOException("Unable to create export file");
          }
          DatabaseExporter.exportToDocument(exportFile.getUri(), getApplicationContext());
          List<DocumentFile> files = new ArrayList<>(Arrays.asList(documentFolder.listFiles()));
          Iterator<DocumentFile> itr = files.iterator();
          while (itr.hasNext()) {
              DocumentFile file = itr.next();
              if (!file.getName().matches("AntennaPodBackup-\\d\\d\\d\\d-\\d\\d-\\d\\d\\.db")) {
                  itr.remove();
              }
          }
          Collections.sort(files, (o1, o2) -> Long.compare(o2.lastModified(), o1.lastModified()));
          boolean hasDeletionFailed = false;
          for (int i = 5; i < files.size(); i++) {
              boolean isDeleted = files.get(i).delete();
              if (!hasDeletionFailed && !isDeleted) {
                  hasDeletionFailed = true;
              }
          }
          if (hasDeletionFailed) {
              throw new IOException("Unable to delete some database backup files");
          }
      }
  
      private void showErrorNotification(Exception exception) {
          final String description = getApplicationContext().getString(R.string.automatic_database_export_error)
                  + " " + exception.getMessage();
          if (EventBus.getDefault().hasSubscriberForEvent(MessageEvent.class)) {
              EventBus.getDefault().post(new MessageEvent(description));
              return;
          }
  
          Intent intent = getApplicationContext().getPackageManager().getLaunchIntentForPackage(
                  getApplicationContext().getPackageName());
          PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
                  R.id.pending_intent_backup_error, intent, PendingIntent.FLAG_UPDATE_CURRENT
                          | (Build.VERSION.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0));
          Notification notification = new NotificationCompat.Builder(getApplicationContext(),
                          NotificationUtils.CHANNEL_ID_SYNC_ERROR)
                  .setContentTitle(getApplicationContext().getString(R.string.automatic_database_export_error))
                  .setContentText(exception.getMessage())
                  .setStyle(new NotificationCompat.BigTextStyle().bigText(description))
                  .setContentIntent(pendingIntent)
                  .setSmallIcon(R.drawable.ic_notification_sync_error)
                  .setAutoCancel(true)
                  .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                  .build();
          NotificationManager nm = (NotificationManager) getApplicationContext()
                  .getSystemService(Context.NOTIFICATION_SERVICE);
          if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.POST_NOTIFICATIONS)
                  == PackageManager.PERMISSION_GRANTED) {
              nm.notify(R.id.notification_id_backup_error, notification);
          } else {
              Toast.makeText(getApplicationContext(), description, Toast.LENGTH_LONG).show();
          }
      }
  }
  