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

Commit eba29294 authored by vince-bourgmayer's avatar vince-bourgmayer
Browse files

make background service for initial folder creation to perform all folders...

make background service for initial folder creation to perform all folders creation and DB registering
parent 4517a0f0
Loading
Loading
Loading
Loading
+147 −33
Original line number Diff line number Diff line
package foundation.e.drive.backgroundServices;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.IntentService;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

@@ -13,12 +14,16 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import foundation.e.drive.database.DbHelper;
import foundation.e.drive.models.SyncedFolder;
import foundation.e.drive.utils.AppConstants;
import foundation.e.drive.utils.CommonUtils;

import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR;
import static foundation.e.drive.utils.AppConstants.ACCOUNT_KEY_CODE;
import static foundation.e.drive.utils.AppConstants.resultCodeKey;
import static foundation.e.drive.utils.AppConstants.resultIntentActionKey;
@@ -28,62 +33,171 @@ import static foundation.e.drive.utils.AppConstants.resultIntentActionKey;
//https://developer.android.com/guide/components/services.html#ExtendingIntentService
public class CreateInitialRemoteFoldersIntentService extends IntentService {
    private static final String TAG = CreateInitialRemoteFoldersIntentService.class.getSimpleName();
    public static final String createFullPathKey = "create_full_path";
    public static final String syncedFolderKey = "synced_folder";


    /**
     * Creates an IntentService.
     *
     * default constructor
     */
    public CreateInitialRemoteFoldersIntentService() {
        super(TAG);
    }
    public CreateInitialRemoteFoldersIntentService() { super(TAG); }


    @Override
    protected void onHandleIntent(Intent workIntent) {
        if(workIntent == null || workIntent.getExtras() == null) return;

        Bundle extras = workIntent.getExtras();
        boolean mCreateFullPath = extras.getBoolean(createFullPathKey);
        SyncedFolder mSyncedFolder = (SyncedFolder) extras.getParcelable(syncedFolderKey);
        Account mAccount = extras.getParcelable(ACCOUNT_KEY_CODE);
        //@TODO: if(mAccount == null)
        OwnCloudClient client = CommonUtils.getOwnCloudClient(mAccount, this);

        if(mSyncedFolder == null) return; //@TODO: Move this check in performTask
        performTask(mSyncedFolder, mCreateFullPath, client);
        LocalBroadcastManager.getInstance(this).sendBroadcast(doMission(client));
    }


    private void performTask(SyncedFolder mSyncedFolder, boolean mCreateFullPath, OwnCloudClient client){
    /**
     * @TODO: rename it
     * @return Intent the result intent to send to launcher service
     */
    private Intent doMission(OwnCloudClient client){

        Intent resultIntent = new Intent(resultIntentActionKey);
        List<String> syncCategories = Arrays.asList("Rom settings", "Images", "Movies", "Music", "Ringtones", "Documents", "Podcasts");

        Log.d(TAG, "syncCategories. size : "+syncCategories.size());

        //Get SyncedFolders
        List<SyncedFolder> mSyncedFolders = getInitialSyncedFolders(syncCategories);

        Log.d(TAG, "mSyncedFolders. size : "+mSyncedFolders.size());

        resultIntent.putExtra(resultCodeKey, true);
        for(SyncedFolder folder : mSyncedFolders){
            Log.d(TAG, "Folder: "+folder.getLibelle());
            if(!createFolder(folder, client)){
                //@TODO: What to do if not succeed ?
                resultIntent.putExtra(resultCodeKey, false);
                break; //Leave the loop. Try again later.
            }
        }
        Log.d(TAG, "Result: "+resultIntent.getExtras().getBoolean(resultCodeKey));
        return resultIntent;
    }

    /**
     * Return a list of SyncedFolder
     * @param categories categories indicating which syncedFolder to create
     */
    private List<SyncedFolder> getInitialSyncedFolders( List<String> categories){
        Log.i(TAG, "getInitialSyncedFolders");

        List<SyncedFolder> mSyncedFolders = new ArrayList<>();

        for(int i=-1, size = categories.size(); ++i < size;){
            final String DEVICE_SPECIFIC_PATH = PATH_SEPARATOR+"Devices"+PATH_SEPARATOR+ Build.BRAND+"_"+ Build.MODEL+"_"
                    + Build.SERIAL;
            switch ( categories.get(i) ){
                case "Medias":
                    break;
                case "Images":
                    mSyncedFolders.add( new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_DCIM),
                            "/Photos/", true) );
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_PICTURES),
                            "/Pictures/", true ) );
                    break;
                case "Movies":
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_MOVIES),
                            "/Movies/", true));
                    break;
                case "Music":
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_MUSIC),
                            "/Music/", true));
                    break;
                case "Ringtones":
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_RINGTONES),
                            "/Ringtones/", true));
                    break;
                case "Documents":
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_DOCUMENTS),
                            "/Documents/", true));
                    break;
                case "Podcasts":
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_PODCASTS),
                            "/Podcasts/", true));
                    break;
                case "Rom settings":
                    String remoteFolderPath = DEVICE_SPECIFIC_PATH+"/rom_settings/";
                    mSyncedFolders.add( new SyncedFolder(categories.get(i), "/data/system/users/0/", remoteFolderPath, true, false, true, false) );
                    try{
                        mSyncedFolders.add( new SyncedFolder(
                                categories.get(i),
                                getFilesDir().getCanonicalPath()+PATH_SEPARATOR,
                                remoteFolderPath+"app_list/",
                                true,
                                false,
                                true,
                                false) );
                    }catch (Exception e){ Log.e(TAG, e.toString()); }
                break;
            }
        }
        return mSyncedFolders;
    }

        File folder = new File(mSyncedFolder.getLocalFolder() );
    private String getExternalFolder(String directory){
        return CommonUtils.getLocalPath(Environment.getExternalStoragePublicDirectory(directory))+ PATH_SEPARATOR;
    }

    /**
     * Create a single folder
     * @param syncedFolder folder to create
     * @param client Client to use to perform the operation
     * @return true if success, false either
     */
    private boolean createFolder(SyncedFolder syncedFolder, OwnCloudClient client){
        int trialCounter = 0;
        //Check that local Folder exist
        File folder = new File(syncedFolder.getLocalFolder() );
        if( !folder.exists() ){
            Log.e(TAG, "Local folder doesn't exist, so create it");
            folder.mkdirs();
        }
        CreateFolderRemoteOperation createFolderOperation = new CreateFolderRemoteOperation(mSyncedFolder.getRemoteFolder(), mCreateFullPath);

        RemoteOperationResult createOperationResult;
        createOperationResult = createFolderOperation.execute(client, true);
        if(createOperationResult.isSuccess() || createOperationResult.getCode() == RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS ){
            if(DbHelper.insertSyncedFolder(mSyncedFolder, this) >= 0 ) {
                resultIntent.putExtra(resultCodeKey, RemoteOperationResult.ResultCode.OK);
                resultIntent.putExtra(AppConstants.resultIntentHttpCodeKey, createOperationResult.getHttpCode());
        //Create the operation to create file
        CreateFolderRemoteOperation createFolderOperation = new CreateFolderRemoteOperation(syncedFolder.getRemoteFolder(), true);

        while(trialCounter < 3){
            //Execute the operation
            RemoteOperationResult createOperationResult = createFolderOperation.execute(client, true);

            //Handle the result
            int result = handleResult(createOperationResult);
            if( result== 0) {
                if(DbHelper.insertSyncedFolder(syncedFolder, this) >= 0 ) {
                    return true;
                }else {
                    Log.d(TAG, "insertion of folder in DB failed");
                resultIntent.putExtra(resultCodeKey, RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS);
                resultIntent.putExtra(AppConstants.resultIntentHttpCodeKey, createOperationResult.getHttpCode());
                    //@TODO: check in DB if folder is already present
                    //if(DbHelper.syncedFolderExist()){ return true;}
                    return false;
                }
            }else {
            resultIntent.putExtra(resultCodeKey, createOperationResult.getCode());
            resultIntent.putExtra(AppConstants.resultIntentHttpCodeKey, createOperationResult.getHttpCode());
                trialCounter += result;
            }
        }
        return false;
    }

        Log.d(TAG, createOperationResult.getLogMessage()+" \n"+createOperationResult.getCode()+
                " \n"+createOperationResult.getHttpCode()+" \n"+createOperationResult.getAuthenticateHeaders().toString());
        LocalBroadcastManager.getInstance(this).sendBroadcast(resultIntent);
    /**
     * Handle the result
     * @param result the operation result to analyze
     * @return int value 0 if success, 1 if operation should be retry, 3 if failure with no retry
     */
    private int handleResult(RemoteOperationResult result){
        if(result.isSuccess() || result.getCode() == RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS ){
            return 0;
        }else if(result.getHttpCode() == 423 || result.getHttpCode() == 409){
                Log.w( TAG, " retry the operation" );
                return 1; //It will make operation to be retried
        }else{
            Log.e(TAG, result.getCode()+" "+result.getHttpCode() );
            return 3; //total failure
        }
    }
}
+24 −198
Original line number Diff line number Diff line
@@ -16,55 +16,35 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import foundation.e.drive.backgroundServices.CreateInitialRemoteFoldersIntentService;
import foundation.e.drive.models.SyncedFolder;
import foundation.e.drive.operations.CreateInitialFolderRemoteOperation;
import foundation.e.drive.receivers.ScreenOffReceiver;
import foundation.e.drive.utils.AppConstants;
import foundation.e.drive.utils.CommonUtils;
import foundation.e.drive.utils.JobUtils;

import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR;
import static foundation.e.drive.backgroundServices.CreateInitialRemoteFoldersIntentService.createFullPathKey;
import static foundation.e.drive.backgroundServices.CreateInitialRemoteFoldersIntentService.syncedFolderKey;
import static foundation.e.drive.utils.AppConstants.INITIALFOLDERS_NUMBER;
import static foundation.e.drive.utils.AppConstants.MEDIA_SYNCABLE_CATEGORIES;
import static foundation.e.drive.utils.AppConstants.SETTINGS_SYNCABLE_CATEGORIES;

/**
 * @author Vincent Bourgmayer
 */
public class InitializerService extends Service {
    final private String TAG = InitializerService.class.getSimpleName();
    //Complex properties
    private int existingRemoteFolderCounter; //@dev-only; Temporarily used to know if all remotePath exist
    private List<SyncedFolder> mSyncedFolders; //syncedFolders
    private OwnCloudClient mCloudClient;
    private Handler mHandler;
    private Account mAccount;
    private int restartFolderCreationCounter =0;


    @Override
    public void onCreate() {
        Log.i(TAG, "onCreate()");
        super.onCreate();
        this.existingRemoteFolderCounter = 0;
        //JobUtils.scheduleInitializerJob(getApplicationContext());
        IntentFilter intentFilter = new IntentFilter(AppConstants.resultIntentActionKey);
        LocalBroadcastManager.getInstance(this).registerReceiver(
@@ -101,178 +81,36 @@ public class InitializerService extends Service {
                Log.w(TAG, "Account's name not found. Neither in shared prefs nor in intent's extras");
                stopSelf();
            }else{
                this.mAccount = CommonUtils.getAccount( accountName, accountType, AccountManager.get(this) );
                Account mAccount = CommonUtils.getAccount( accountName, accountType, AccountManager.get(this) );
                //Get OwnCloudlient
                if (this.mAccount != null) {
                    this.mCloudClient = CommonUtils.getOwnCloudClient( this.mAccount, getApplicationContext());
                    start();
                }else {
                if (mAccount == null) {
                    Log.w(TAG, "Got account is invalid.");
                    stopSelf();
                }
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }


    /**
     * start to do its job
     */
    public void start() {
        Log.i(TAG, "start");
        if (mCloudClient == null){
            stopSelf();
            return;
        }


        //Get categories of element to sync
        List<String> syncCategories = new ArrayList<>();

        if (CommonUtils.isMediaSyncEnabled(mAccount)) {
            syncCategories.addAll(Arrays.asList(MEDIA_SYNCABLE_CATEGORIES));
        }

        if (CommonUtils.isSettingsSyncEnabled(mAccount)) {
            syncCategories.addAll(Arrays.asList(SETTINGS_SYNCABLE_CATEGORIES));
        }

        //Get SyncedFolders
        getInitialSyncedFolders(syncCategories);

        this.existingRemoteFolderCounter = 0;

        CreateNextRemoteFolder();
        }

    /**
     * Return a list of SyncedFolder
     * @param categories categories indicating which syncedFolder to create
     */
    private void getInitialSyncedFolders( List<String> categories){
        Log.i(TAG, "getInitialSyncedFolders");

        this.mSyncedFolders = new ArrayList<>();

        for(int i=-1, size = categories.size(); ++i < size;){
            final String DEVICE_SPECIFIC_PATH = PATH_SEPARATOR+"Devices"+PATH_SEPARATOR+ Build.BRAND+"_"+ Build.MODEL+"_"
                    + Build.SERIAL;
            switch ( categories.get(i) ){
                case "Medias":
                    break;
                case "Images":
                    mSyncedFolders.add( new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_DCIM),
                            "/Photos/", true) );
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_PICTURES),
                            "/Pictures/", true ) );
                    break;
                case "Movies":
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_MOVIES),
                            "/Movies/", true));
                    break;
                case "Music":
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_MUSIC),
                            "/Music/", true));
                    break;
                case "Ringtones":
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_RINGTONES),
                            "/Ringtones/", true));
                    break;
                case "Documents":
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_DOCUMENTS),
                            "/Documents/", true));
                    break;
                case "Podcasts":
                    mSyncedFolders.add(new SyncedFolder(categories.get(i), getExternalFolder(Environment.DIRECTORY_PODCASTS),
                            "/Podcasts/", true));
                    break;
                case "Rom settings":
                    String remoteFolderPath = DEVICE_SPECIFIC_PATH+"/rom_settings/";
                    mSyncedFolders.add( new SyncedFolder(categories.get(i), "/data/system/users/0/", remoteFolderPath, true, false, true, false) );
                    try{
                        mSyncedFolders.add( new SyncedFolder(
                                categories.get(i),
                        getFilesDir().getCanonicalPath()+PATH_SEPARATOR,
                        remoteFolderPath+"app_list/",
                                true,
                                false,
                                true,
                                false) );
                    }catch (Exception e){ Log.e(TAG, e.toString()); }
                    break;
            }
        }
    }

    private String getExternalFolder(String directory){
        return CommonUtils.getLocalPath(Environment.getExternalStoragePublicDirectory(directory))+ PATH_SEPARATOR;
    }

    /**
     * Start to createSyncedFolder in the cloud
     */
    private void CreateNextRemoteFolder(){
        this.restartFolderCreationCounter = 0;

        if( this.mSyncedFolders == null || this.mSyncedFolders.isEmpty() ){
            //JobUtils.stopScheduledJob(getApplicationContext(), JobUtils.InitializerJobId);
            this.stopSelf();
        }

        //It means that there are still folders to create
        if( this.existingRemoteFolderCounter < this.mSyncedFolders.size() ){

            if( this.mHandler == null ) this.mHandler = new Handler();

                Intent createFolderIntent = new Intent(this, CreateInitialRemoteFoldersIntentService.class);

            createFolderIntent.putExtra(syncedFolderKey, mSyncedFolders.get(this.existingRemoteFolderCounter));
            createFolderIntent.putExtra(createFullPathKey, true);
                createFolderIntent.putExtra(AppConstants.ACCOUNT_KEY_CODE, mAccount);
                startService(createFolderIntent);

        }else if(this.existingRemoteFolderCounter ==  this.mSyncedFolders.size() ){
            doLastStep();
        }else{
            Log.e(TAG, "this.existingRemoteFolderCounter : "+this.existingRemoteFolderCounter+" > this.mSyncedFolders.size() : "+this.mSyncedFolders.size() );
            this.stopSelf();
        }
    }


    public void onFolderCreationResult(RemoteOperationResult.ResultCode resultCode, int httpResultCode){
        if(resultCode != null && (resultCode.equals(RemoteOperationResult.ResultCode.OK) || resultCode.equals(RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS))){
            this.existingRemoteFolderCounter+=1;
            CreateNextRemoteFolder();
        }else if(httpResultCode == 423 || httpResultCode == 409){
            if( this.restartFolderCreationCounter < 3) {
                Log.w( TAG, " restart operation" );
                //operation.execute( this.mCloudClient, this, this.mHandler );
                this.restartFolderCreationCounter+=1;
            }else{
                Log.e(TAG, "Remote folder's creation failed due to conflict with server");
                stopSelf();
            }
        }else{
            Log.e(TAG, resultCode+" "+httpResultCode );
            stopSelf();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * Function to check if all remote folder have been created
     **/
    private void doLastStep(){
        Log.i(TAG, "doLastStep()");
    private void doLastStep(boolean initDone, int initializedFoldersNumber){
        Log.i(TAG, "doLastStep("+initDone+", "+initializedFoldersNumber+")");

        getApplicationContext().getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME,
                Context.MODE_PRIVATE )
                .edit()
                .putBoolean(AppConstants.INITIALIZATION_HAS_BEEN_DONE, true)
                .putInt( INITIALFOLDERS_NUMBER, mSyncedFolders.size() )
                .putBoolean(AppConstants.INITIALIZATION_HAS_BEEN_DONE, initDone)
                .putInt( INITIALFOLDERS_NUMBER, initializedFoldersNumber )
                .apply();

        if(initDone) {
            //all folder have been created
            JobUtils.scheduleScannerJob(this);

@@ -284,20 +122,11 @@ public class InitializerService extends Service {
            //Immediatly start ObserverService to not have to wait 30 minutes.
            Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class);
            startService(observersServiceIntent);
        }
        //JobUtils.stopScheduledJob(appContext, JobUtils.InitializerJobId);
        stopSelf();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        this.mHandler = null;
        this.mAccount = null;
        this.mCloudClient = null;
        if(this.mSyncedFolders != null) this.mSyncedFolders.clear();
        this.mSyncedFolders = null;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
@@ -311,12 +140,9 @@ public class InitializerService extends Service {
            if(intent == null || (extras = intent.getExtras()) == null) {
                return;
            }
            RemoteOperationResult.ResultCode resultCode = extras.getParcelable(AppConstants.resultCodeKey);
            //Note: Problem with parsing parcelable to ResultCode. Probably because it's null...

            int httpResultCode = extras.getInt(AppConstants.resultIntentHttpCodeKey);

            onFolderCreationResult(resultCode, httpResultCode);
            doLastStep( extras.getBoolean(AppConstants.resultCodeKey, false),
                        extras.getInt(AppConstants.createdFolderCounterKey));
        }
    };
}
 No newline at end of file
+1 −6
Original line number Diff line number Diff line
@@ -25,15 +25,10 @@ public abstract class AppConstants {
    public static final String KEY_LAST_SYNC_TIME = "lastSyncTimestamp";  //key for read/write last sync time (in ms) in prefs.
    public static final String KEY_OMS_IS_WORKING = "OMS_is_working";

    public static final String[] MEDIA_SYNCABLE_CATEGORIES = new String[]{"Images", "Movies", "Music", "Ringtones", "Documents", "Podcasts"};
    public static final String[] SETTINGS_SYNCABLE_CATEGORIES = new String[]{"Rom settings"};

    //Initializer
    public static final String resultCodeKey = "result_code";
    public static final String resultIntentActionKey = "CreateInitialFolderResult";
    public static final String resultIntentHttpCodeKey = "result_http_code";
    public static final String ACCOUNT_KEY_CODE = "account";



    public static String createdFolderCounterKey = "createdFolderCounterKey";
}