package co.smartreceipts.android.sync.drive.managers; import android.content.Context; import android.support.annotation.NonNull; import com.google.common.base.Preconditions; import java.io.File; import java.util.concurrent.atomic.AtomicBoolean; import co.smartreceipts.android.analytics.Analytics; import co.smartreceipts.android.analytics.events.ErrorEvent; import co.smartreceipts.android.persistence.DatabaseHelper; import co.smartreceipts.android.sync.drive.device.GoogleDriveSyncMetadata; import co.smartreceipts.android.sync.drive.rx.DriveStreamsManager; import co.smartreceipts.android.sync.model.impl.Identifier; import co.smartreceipts.android.sync.network.NetworkManager; import co.smartreceipts.android.utils.log.Logger; import io.reactivex.Scheduler; import io.reactivex.Single; import io.reactivex.schedulers.Schedulers; public class DriveDatabaseManager { private final Context mContext; private final DriveStreamsManager mDriveTaskManager; private final GoogleDriveSyncMetadata mGoogleDriveSyncMetadata; private final NetworkManager mNetworkManager; private final Analytics mAnalytics; private final Scheduler mObserveOnScheduler; private final Scheduler mSubscribeOnScheduler; private final AtomicBoolean mIsSyncInProgress = new AtomicBoolean(false); public DriveDatabaseManager(@NonNull Context context, @NonNull DriveStreamsManager driveTaskManager, @NonNull GoogleDriveSyncMetadata googleDriveSyncMetadata, @NonNull NetworkManager networkManager, @NonNull Analytics analytics) { this(context, driveTaskManager, googleDriveSyncMetadata, networkManager, analytics, Schedulers.io(), Schedulers.io()); } public DriveDatabaseManager(@NonNull Context context, @NonNull DriveStreamsManager driveTaskManager, @NonNull GoogleDriveSyncMetadata googleDriveSyncMetadata, @NonNull NetworkManager networkManager, @NonNull Analytics analytics, @NonNull Scheduler observeOnScheduler, @NonNull Scheduler subscribeOnScheduler) { mContext = Preconditions.checkNotNull(context.getApplicationContext()); mDriveTaskManager = Preconditions.checkNotNull(driveTaskManager); mGoogleDriveSyncMetadata = Preconditions.checkNotNull(googleDriveSyncMetadata); mNetworkManager = Preconditions.checkNotNull(networkManager); mAnalytics = Preconditions.checkNotNull(analytics); mObserveOnScheduler = Preconditions.checkNotNull(observeOnScheduler); mSubscribeOnScheduler = Preconditions.checkNotNull(subscribeOnScheduler); } public void syncDatabase() { if (mNetworkManager.isNetworkAvailable()) { // TODO: Make sure the database is closed or inactive before performing this // TODO: We can trigger this off of our #close() method in DB helper final File filesDir = mContext.getExternalFilesDir(null); if (filesDir != null) { final File dbFile = new File(filesDir, DatabaseHelper.DATABASE_NAME); if (dbFile.exists()) { if (!mIsSyncInProgress.getAndSet(true)) { getSyncDatabaseObservable(dbFile) .observeOn(mObserveOnScheduler) .subscribeOn(mSubscribeOnScheduler) .subscribe(identifier -> { Logger.info(DriveDatabaseManager.this, "Successfully synced our database"); mGoogleDriveSyncMetadata.setDatabaseSyncIdentifier(identifier); mIsSyncInProgress.set(false); }, throwable -> { mIsSyncInProgress.set(false); mAnalytics.record(new ErrorEvent(DriveDatabaseManager.this, throwable)); Logger.error(DriveDatabaseManager.this, "Failed to synced our database", throwable); }); } else { Logger.debug(DriveDatabaseManager.this, "A sync is already in progress. Ignoring subsequent one for now"); } } else { Logger.error(DriveDatabaseManager.this, "Failed to find our main database"); } } else { Logger.error(DriveDatabaseManager.this, "Failed to find our main database storage directory"); } } else { Logger.error(DriveDatabaseManager.this, "Network not available to sync our database"); } } @NonNull private Single<Identifier> getSyncDatabaseObservable(@NonNull final File dbFile) { final Identifier driveDatabaseId = mGoogleDriveSyncMetadata.getDatabaseSyncIdentifier(); if (driveDatabaseId != null) { return mDriveTaskManager.updateDriveFile(driveDatabaseId, dbFile); } else { return mDriveTaskManager.uploadFileToDrive(dbFile); } } }