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

Commit 41d070e0 authored by vince-bourgmayer's avatar vince-bourgmayer
Browse files

Fix account Suppression behaviour. OperationManagerService is now a started + bound service

parent 1b28fa17
Loading
Loading
Loading
Loading
Loading
+29 −48
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ package io.eelo.drive.services;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.NotificationManager;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
@@ -23,7 +24,6 @@ import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.util.Log;

//import com.crashlytics.android.Crashlytics;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
import com.owncloud.android.lib.common.operations.RemoteOperation;
@@ -65,8 +65,9 @@ public class ObserverService extends Service implements OnRemoteOperationListene
    private boolean mBoundToOperationManager = false;
    private boolean isWorking = false;
    private OperationManagerService mOperationManagerService;

    private final int notificationID = 3310;
    private int initialFolderCounter;
    private Account mAccount;
    /**
     * ServiceConnection for binder to OperationManagerService
     */
@@ -76,8 +77,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene
        public void onServiceConnected(ComponentName className, IBinder service) {
            Log.i(TAG, "onServiceConnected");
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            OperationManagerService.OperationManagerBinder binder = (OperationManagerService.OperationManagerBinder) service;
            mOperationManagerService = binder.getService();
            mOperationManagerService = ((OperationManagerService.OperationManagerBinder) service).getService();
            mBoundToOperationManager = true;
            handleCachedFile();
            startScan(true);
@@ -86,6 +86,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene
        public void onServiceDisconnected(ComponentName arg0) {
            Log.i(TAG, "OnServiceDisconnected");
            mBoundToOperationManager = false;
            mOperationManagerService = null;
        }
    };

@@ -108,28 +109,25 @@ public class ObserverService extends Service implements OnRemoteOperationListene
        this.mClient = null;
        this.mHandler = null;
        this.mSyncedFolders = null;
        NotificationManager nM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        nM.cancel(notificationID);
    }

    @Override
    public void onCreate() {
        Log.i(TAG, "onCreate()");
        super.onCreate();
        //Fabric.with(this, new Crashlytics());
        this.mHandler = new Handler();

        /* Test */
        Intent opMgrSrvIntent = new Intent(this, OperationManagerService.class);
        getApplicationContext().startService(opMgrSrvIntent);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");

        //I know it's quite dumb, but stopService doesn't work
        /*if(intent.getExtras() != null && intent.getExtras().getString("action").equals("stop")){
            if(mBoundToOperationManager) {
                unbindService(mOperationManagerServiceConnection);
                mBoundToOperationManager = false;
            }
            this.stopSelf();
        }*/
        SharedPreferences prefs = this.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);

        if (prefs.getBoolean(INITIALIZERSERVICE_HAS_RUN, false)) {
@@ -137,33 +135,11 @@ public class ObserverService extends Service implements OnRemoteOperationListene
            String accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, "");
            String accountType = prefs.getString(AccountManager.KEY_ACCOUNT_TYPE, "");
            initialFolderCounter = prefs.getInt(AppConstants.INITIALFOLDERS_NUMBER, 0);
            Account mAccount = CommonUtils.getAccount(accountName, accountType, AccountManager.get(this));

            //There is no account set
            /*if(mAccount == null){
                final String CURRENTTAG = TAG+"_onStartCommand / no Account";
                Log.d(CURRENTTAG, "Account is null, so start to clear prefs.");
                //clear prefs
                prefs.edit().putString(AccountManager.KEY_ACCOUNT_NAME, "")
                        .putString(AccountManager.KEY_ACCOUNT_TYPE, "")
                        .putBoolean(INITIALIZERSERVICE_HAS_RUN, false)
                        .putInt(INITIALFOLDERS_NUMBER, 0)
                        .apply();

                //clear DB
                boolean result = this.deleteDatabase(DbHelper.DATABASE_NAME);
                Log.d(CURRENTTAG, "Remove Database: "+result);
                //Disable scheduledJob
                JobUtils.stopScheduledJob(this);
                //Stop operationManagerService
                if(mBoundToOperationManager) mOperationManagerService.stopSelf();
                boolean unregisteredReceiver = CommonUtils.unregisterScreenOff(getApplicationContext());
                Log.d(CURRENTTAG, "ScreenOffReceiver unregistered : "+unregisteredReceiver);

            }else */
            if (mAccount != null && CommonUtils.isMediaSyncEnabled(mAccount) && CommonUtils.isSettingsSyncEnabled(mAccount)) {
            this.mAccount = CommonUtils.getAccount(accountName, accountType, AccountManager.get(this));

            if (this.mAccount != null && ( CommonUtils.isMediaSyncEnabled(mAccount) || CommonUtils.isSettingsSyncEnabled(this.mAccount) ) ) {
                if (mClient == null) //background task
                    CommonUtils.getOwnCloudClient(mAccount, getApplicationContext(), this);
                    CommonUtils.getOwnCloudClient(this.mAccount, getApplicationContext(), this);
                else
                    begin();
            } else {
@@ -188,7 +164,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene
            if (CommonUtils.haveNetworkConnexion(this)) {
                if (!mBoundToOperationManager) {
                    Intent opMgrSrvIntent = new Intent(this, OperationManagerService.class);
                    bindService(opMgrSrvIntent, this.mOperationManagerServiceConnection, Context.BIND_AUTO_CREATE);
                    bindService(opMgrSrvIntent, this.mOperationManagerServiceConnection, Context.BIND_NOT_FOREGROUND);
                } else {
                    handleCachedFile();
                    Log.d(TAG+"_begin()", "going to call startScan(true)");
@@ -254,14 +230,20 @@ public class ObserverService extends Service implements OnRemoteOperationListene
     */
    private void startScan(boolean remote) {
        Log.i(TAG, "startScan("+remote+")");
        if(remote){
            Log.d(TAG+"_startScan(...)", "Going to scan remote files");
        boolean mediaSyncEnabled = CommonUtils.isMediaSyncEnabled(mAccount);
        this.mSyncedFolders = DbHelper.getSyncedFolders(this);
        if(remote && mediaSyncEnabled){
            Log.d(TAG+"_startScan(...)", "Going to scan remote files");

            ListRemoteFileOperation loadOperation = new ListRemoteFileOperation(this.mSyncedFolders, this, this.initialFolderCounter);
            loadOperation.execute(mClient, this, mHandler);
        }else{
            if((mediaSyncEnabled || CommonUtils.isSettingsSyncEnabled(mAccount) ) ){
                Log.d(TAG+"_startScan(...)", "Going to scan local files");
                scanLocalFiles();
            }else{
                this.stopSelf();
            }
        }
    }
    /**
@@ -279,7 +261,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene
                if(resultDatas != null ){
                    List<SyncedFileState> syncedFileStateList = DbHelper.getSyncedFileStatesByFolders( this,
                            getIdsFromFolderToScan());
                    if(!resultDatas.isEmpty() || ! syncedFileStateList.isEmpty() ) {
                    if(!resultDatas.isEmpty() || ! syncedFileStateList.isEmpty() && CommonUtils.isMediaSyncEnabled(mAccount)) {
                        handleRemoteFiles(resultDatas, syncedFileStateList);
                    }else{
                        Log.v(TAG, "No remote files nor syncedFileStates. Go next step");
@@ -438,7 +420,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene
                    Log.d(CURRENTTAG, file.getName()+" doesn't exists *2");
                    //It means that file has been correctly deleted from device. So update DB.
                    if (DbHelper.manageSyncedFileStateDB(syncedFileState, "DELETE", this) > 0)
                        CommonUtils.sendNotification(this,3310, syncedFileState.getName() + " has been removed", android.R.drawable.ic_delete, null, null);
                        CommonUtils.sendNotification(this,notificationID, syncedFileState.getName() + " has been removed", android.R.drawable.ic_delete, null, null);
                    else
                        Log.e(CURRENTTAG, "SyncedFileState row hasn't been deleted from DB");
                }else
@@ -483,7 +465,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene
        List<Long> folderIds= new ArrayList<>();

        //Regenere list of application's package
        generateAppListFile();
        if(CommonUtils.isSettingsSyncEnabled(mAccount)) generateAppListFile();

        boolean contentToSyncFound = false;
        ListIterator<SyncedFolder> iterator = mSyncedFolders.listIterator() ;
@@ -585,7 +567,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene
                                    folderIndex = size;
                                }
                            }

                            //add Upload operation to queue.
                            UploadFileOperation uploadFileOperation = new UploadFileOperation( localFile, this, syncedFileState, checkEtag );
                            this.mOperationManagerService.addOperation( uploadFileOperation );
+47 −52
Original line number Diff line number Diff line
@@ -6,13 +6,11 @@
 * http://www.gnu.org/licenses/gpl.html
 */


package io.eelo.drive.services;


import android.accounts.Account;
import android.accounts.AccountManager;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
@@ -51,19 +49,21 @@ import io.eelo.drive.utils.IGetOCClient;
 * @author Vincent Bourgmayer
 * Service to do upload, remove and download operation.
 */

public class OperationManagerService extends Service implements OnRemoteOperationListener, IGetOCClient{
    private final static String TAG = OperationManagerService.class.getSimpleName();

    private int workerAmount = 0;
    private Thread[] mThreadPool;
    private boolean[] mThreadWorkingState;
    private ArrayDeque<RemoteOperation> mOperationsQueue;
    private Hashtable<RemoteOperation, Integer> mStartedOperations;
    private List<String> lockedfilePath; //Used by ObserverService to know if files corresponding to those path is syncing or not
    private int workerAmount = 0; //Number of thread available to execute RemoteOperation
    private Thread[] mThreadPool; //The threads to use
    private boolean[] mThreadWorkingState; //State of the threads; true mean the thread is working
    private ArrayDeque<RemoteOperation> mOperationsQueue; // Queue of Operation
    private Hashtable<RemoteOperation, Integer> mStartedOperations; //Operations which are running
    private List<String> lockedfilePath; //Used by ObserverService to know if files corresponding to those path is syncing or not. List of device's path of syncing files
    private OperationManagerHandler mHandler;
    private int notificationID;
    private OwnCloudClient mClient;
    private Account mAccount;
    private int notificationID; //NotificationID
    private OwnCloudClient mClient; //ClientObect
    private Account mAccount; //Will be used soon


    // Binder given to clients
    private final IBinder mBinder = new OperationManagerBinder();
@@ -73,6 +73,20 @@ public class OperationManagerService extends Service implements OnRemoteOperatio
     */
    @Override
    public void onDestroy() {
        this.mClient.clearCredentials();
        this.mOperationsQueue.clear();
        this.workerAmount = 0;
        for(int i =-1, size = mThreadPool.length;++i < size;){
            try{
                if(mThreadPool[i] != null)
                    mThreadPool[i].interrupt();}
            catch(Exception e){
                Log.e(TAG, e.toString());
            }
        }
        NotificationManager nM= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        nM.cancel(notificationID);

        Log.i(TAG, "onDestroy()");
        super.onDestroy();
    }
@@ -101,12 +115,7 @@ public class OperationManagerService extends Service implements OnRemoteOperatio
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");
        //I know it's quite dumb, but stopService doesn't work
        if(intent.getExtras() != null && intent.getExtras().getString("action").equals("stop")){
            this.stopItself();
        }else {
            begin();
        }
        //begin();
        return super.onStartCommand(intent, flags, startId);
    }

@@ -122,11 +131,10 @@ public class OperationManagerService extends Service implements OnRemoteOperatio

    /**
     * Start to run all threads
     * This is only call at begining
     */
    private void startAllThreads(){
        Log.i(TAG, "startAllThreads");

        //if (CommonUtils.isMediaSyncEnabled(mAccount) && CommonUtils.isSettingsSyncEnabled(mAccount)){
        if(this.mClient == null){
            Log.e(TAG, "my OwnCloudClient is null: stop here.");
            return;
@@ -134,27 +142,33 @@ public class OperationManagerService extends Service implements OnRemoteOperatio
        for(int i =-1; ++i < workerAmount;){
            this.startWork(i);
        }
        //}
    }

    /**
     *
     * retrieve an operation from queue and execute it.
     * @param threadIndex index of thread which execute job.
     */
    private void startWork( int threadIndex ){
        Log.i(TAG, "startWork("+threadIndex+")" );
        if( !mThreadWorkingState[threadIndex] ) {
            RemoteOperation operation = this.mOperationsQueue.poll();
            RemoteOperation operation = this.mOperationsQueue.poll(); //return null if deque is empty
            if (operation != null) {
                Log.v(TAG, " an operation has been poll from queue");
                //check if a SyncedFileState is already syncing before to start an operation on the same SyncedFileState
                String localPath;
                if( operation instanceof UploadFileOperation) {
                    /*
                     * @TODO: need to add a check for CommonUtils.isMediaSyncEnabled(mAccount) and/or CommonUtils.isSettingsSyncEnabled(mAccount)
                     * depending of if the file is  media or settings
                     */
                    localPath = CommonUtils.getLocalPath(((UploadFileOperation) operation).getFile());
                } else if( operation instanceof DownloadFileOperation) {
                } else if( operation instanceof DownloadFileOperation && CommonUtils.isMediaSyncEnabled(this.mAccount) ) {
                    localPath = ( (DownloadFileOperation) operation ).getTargetPath();
                } else {
                } else if(operation instanceof RemoveFileOperation && CommonUtils.isMediaSyncEnabled(this.mAccount) ) {
                    localPath = ( (RemoveFileOperation) operation ).getSyncedFileState().getLocalPath();
                }else{
                    return;
                }

                //Try to add a "lock" on file localPath. it will fail if there is already a "lock" on this file.
@@ -173,8 +187,8 @@ public class OperationManagerService extends Service implements OnRemoteOperatio
    }

    /**
     * Tell if there is at least one thread that can get new job
     * @return boolean true is is there is a free thread place else return false
     * Tell if there is at least one thread which can get new task to do
     * @return boolean true if there is a free thread place else return false
     */
    private boolean isThereAFreeThreadPlace(){
        Log.i(TAG, "isThereAFreeThreadPlace()");
@@ -185,8 +199,6 @@ public class OperationManagerService extends Service implements OnRemoteOperatio
        return false;
    }



    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
@@ -286,7 +298,6 @@ public class OperationManagerService extends Service implements OnRemoteOperatio
        begin();
    }


    /**
     * Binder for the class
     */
@@ -320,7 +331,6 @@ public class OperationManagerService extends Service implements OnRemoteOperatio
        }
    }


    /**
     * Public method to allow other service to add a new operation to the queue
     * @param operation Remote operation to execute
@@ -349,19 +359,4 @@ public class OperationManagerService extends Service implements OnRemoteOperatio
    public boolean isSyncingFile(String filePath){
        return this.lockedfilePath.contains(filePath);
    }


    public void stopItself(){
        this.mOperationsQueue.clear();
        this.workerAmount = 0;
        Log.i(TAG, "stopItself()");
        for(int i =-1, size = mThreadPool.length;++i < size;){
            try{mThreadPool[i].interrupt();}
            catch(Exception e){
                Log.e(TAG, e.toString());
            }
        }


    }
}
+11 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ package io.eelo.drive.services;

import android.accounts.AccountManager;
import android.app.ActivityManager;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@@ -18,6 +19,9 @@ import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

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

import io.eelo.drive.database.DbHelper;
import io.eelo.drive.utils.AppConstants;
import io.eelo.drive.utils.CommonUtils;
@@ -77,6 +81,13 @@ public class ResetService extends Service {
                    //5. Unregister screenOffReceiver
                    result = CommonUtils.unregisterScreenOff(getApplicationContext());
                    Log.d(TAG, "Unregistered ScreenOffReceiver: "+result);

                    //6. Remove Cached File
                    File[] cachedFiles =  this.getApplicationContext().getExternalCacheDir().listFiles();
                    for(File f : cachedFiles){
                        f.delete();
                    }

                }
            }
        }