content: package allen.town.podcast.core.storage;
  
  import android.content.Context;
  import android.database.sqlite.SQLiteDatabase;
  import android.database.sqlite.SQLiteException;
  import android.net.Uri;
  import android.os.ParcelFileDescriptor;
  import android.text.format.Formatter;
  import android.util.Log;
  import allen.town.podcast.core.R;
  import allen.town.podcast.storage.db.Db;
  import org.apache.commons.io.FileUtils;
  import org.apache.commons.io.IOUtils;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.nio.channels.FileChannel;
  
  public class DatabaseExporter {
      private static final String TAG = "DatabaseExporter";
      private static final String TEMP_DB_NAME = Db.DATABASE_NAME + "_tmp";
  
      public static void exportToDocument(Uri uri, Context context) throws IOException {
          ParcelFileDescriptor pfd = null;
          FileOutputStream fileOutputStream = null;
          try {
              pfd = context.getContentResolver().openFileDescriptor(uri, "wt");
              fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
              exportToStream(fileOutputStream, context);
          } catch (IOException e) {
              Log.e(TAG, Log.getStackTraceString(e));
              throw e;
          } finally {
              IOUtils.closeQuietly(fileOutputStream);
  
              if (pfd != null) {
                  try {
                      pfd.close();
                  } catch (IOException e) {
                      Log.d(TAG, "Unable to close ParcelFileDescriptor");
                  }
              }
          }
      }
  
      public static void exportToStream(FileOutputStream outFileStream, Context context) throws IOException {
          FileChannel src = null;
          FileChannel dst = null;
          try {
              File currentDB = context.getDatabasePath(Db.DATABASE_NAME);
  
              if (currentDB.exists()) {
                  src = new FileInputStream(currentDB).getChannel();
                  dst = outFileStream.getChannel();
                  long srcSize = src.size();
                  dst.transferFrom(src, 0, srcSize);
  
                  long newDstSize = dst.size();
                  if (newDstSize != srcSize) {
                      throw new IOException(String.format(
                              "Unable to write entire database. Expected to write %s, but wrote %s.",
                              Formatter.formatShortFileSize(context, srcSize),
                              Formatter.formatShortFileSize(context, newDstSize)));
                  }
              } else {
                  throw new IOException("Can not access current database");
              }
          } catch (IOException e) {
              Log.e(TAG, Log.getStackTraceString(e));
              throw e;
          } finally {
              IOUtils.closeQuietly(src);
              IOUtils.closeQuietly(dst);
          }
      }
  
      public static void importBackup(Uri inputUri, Context context) throws IOException {
          InputStream inputStream = null;
          try {
              File tempDB = context.getDatabasePath(TEMP_DB_NAME);
              inputStream = context.getContentResolver().openInputStream(inputUri);
              FileUtils.copyInputStreamToFile(inputStream, tempDB);
  
              SQLiteDatabase db = SQLiteDatabase.openDatabase(tempDB.getAbsolutePath(),
                      null, SQLiteDatabase.OPEN_READONLY);
              if (db.getVersion() > Db.VERSION) {
                  throw new IOException(context.getString(R.string.import_no_downgrade));
              }
              db.close();
  
              File currentDB = context.getDatabasePath(Db.DATABASE_NAME);
              boolean success = currentDB.delete();
              if (!success) {
                  throw new IOException("Unable to delete old database");
              }
              FileUtils.moveFile(tempDB, currentDB);
          } catch (IOException | SQLiteException e) {
              Log.e(TAG, Log.getStackTraceString(e));
              throw e;
          } finally {
              IOUtils.closeQuietly(inputStream);
          }
      }
  }
  