1 /* ownCloud Android client application 
   2  *   Copyright (C) 2012 Bartek Przybylski 
   3  *   Copyright (C) 2012-2014 ownCloud Inc. 
   5  *   This program is free software: you can redistribute it and/or modify 
   6  *   it under the terms of the GNU General Public License version 2, 
   7  *   as published by the Free Software Foundation. 
   9  *   This program is distributed in the hope that it will be useful, 
  10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
  11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  12  *   GNU General Public License for more details. 
  14  *   You should have received a copy of the GNU General Public License 
  15  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  19 package com
.owncloud
.android
.files
; 
  23 import android
.accounts
.Account
; 
  24 import android
.content
.Context
; 
  25 import android
.content
.Intent
; 
  26 import android
.os
.FileObserver
; 
  27 import android
.os
.Handler
; 
  29 import com
.owncloud
.android
.datamodel
.FileDataStorageManager
; 
  30 import com
.owncloud
.android
.datamodel
.OCFile
; 
  31 import com
.owncloud
.android
.lib
.common
.operations
.RemoteOperationResult
; 
  32 import com
.owncloud
.android
.lib
.common
.operations
.RemoteOperationResult
.ResultCode
; 
  33 import com
.owncloud
.android
.operations
.SynchronizeFileOperation
; 
  34 import com
.owncloud
.android
.ui
.activity
.ConflictsResolveActivity
; 
  35 import com
.owncloud
.android
.utils
.Log_OC
; 
  37 public class OwnCloudFileObserver 
extends FileObserver 
{ 
  39     private static int MASK 
= (FileObserver
.MODIFY 
| FileObserver
.CLOSE_WRITE
); 
  40     private static int IN_IGNORE 
= 32768; 
  42     private static String TAG 
= OwnCloudFileObserver
.class.getSimpleName(); 
  46     private Account mOCAccount
; 
  47     private Context mContext
; 
  48     private boolean mModified
; 
  49     private long mFileLastModified
; 
  50     private boolean mRestartWatching
; 
  51     private Handler mHandler
; 
  53     public OwnCloudFileObserver(String path
, Account account
, Context context
, Handler handler
) { 
  54         super(path
, FileObserver
.ALL_EVENTS
); 
  56             throw new IllegalArgumentException("NULL path argument received"); 
  58             throw new IllegalArgumentException("NULL account argument received"); 
  60             throw new IllegalArgumentException("NULL context argument received"); 
  65         mFileLastModified 
= new File(path
).lastModified(); 
  67         Log_OC
.d(TAG
, "Create Observer - FileLastModified: " + mFileLastModified
); 
  71     public void onEvent(int event
, String path
) { 
  72         Log_OC
.d(TAG
, "Got file modified with event " + event 
+ " and path " + mPath
 
  73                 + ((path 
!= null
) ? File
.separator 
+ path 
: "")); 
  74         if ((event 
& MASK
) == 0) { 
  75             Log_OC
.wtf(TAG
, "Incorrect event " + event 
+ " sent for file " + mPath
 
  76                     + ((path 
!= null
) ? File
.separator 
+ path 
: "") + " with registered for " + mMask
 
  77                     + " and original path " + mPath
); 
  79             // in case need start watching again 
  80             if ((event 
& IN_IGNORE
) != 0 && mRestartWatching
) { 
  81                 mRestartWatching 
= false
; 
  83                 mHandler
.postDelayed(new Runnable() { 
  91             if ((event 
& FileObserver
.MODIFY
) != 0) { 
  95             // not sure if it's possible, but let's assume that both kind of 
  96             // events can be received at the same time 
  97             if ((event 
& FileObserver
.CLOSE_WRITE
) != 0) { 
 101                     mRestartWatching 
= false
; 
 102                     startSyncOperation(); 
 103                 } else if (isFileUpdated()) { 
 104                     // if file has been modified but Modify event type has not 
 106                     mRestartWatching 
= true
; 
 107                     mFileLastModified 
= new File(mPath
).lastModified(); 
 108                     Log_OC
.d(TAG
, "CLOSE_WRITE - New FileLastModified: " + mFileLastModified
); 
 109                     startSyncOperation(); 
 115     private void startSyncOperation() { 
 116         FileDataStorageManager storageManager 
= new FileDataStorageManager(mOCAccount
, mContext
.getContentResolver()); 
 117         // a fresh object is needed; many things could have occurred to the file 
 118         // since it was registered to observe again, assuming that local files 
 119         // are linked to a remote file AT MOST, SOMETHING TO BE DONE; 
 120         OCFile file 
= storageManager
.getFileByLocalPath(mPath
); 
 121         SynchronizeFileOperation sfo 
= new SynchronizeFileOperation(file
, null
, mOCAccount
, true
, mContext
); 
 122         RemoteOperationResult result 
= sfo
.execute(storageManager
, mContext
); 
 123         if (result
.getCode() == ResultCode
.SYNC_CONFLICT
) { 
 124             // ISSUE 5: if the user is not running the app (this is a service!), 
 125             // this can be very intrusive; a notification should be preferred 
 126             Intent i 
= new Intent(mContext
, ConflictsResolveActivity
.class); 
 127             i
.setFlags(i
.getFlags() | Intent
.FLAG_ACTIVITY_NEW_TASK
); 
 128             i
.putExtra(ConflictsResolveActivity
.EXTRA_FILE
, file
); 
 129             i
.putExtra(ConflictsResolveActivity
.EXTRA_ACCOUNT
, mOCAccount
); 
 130             mContext
.startActivity(i
); 
 132         // TODO save other errors in some point where the user can inspect them 
 134         // or maybe just toast them; 
 135         // or nothing, very strange fails 
 139      * Check if the timestamp of last file modification in local is more current 
 140      * that the timestamp when setting observer to the file 
 142      * @return boolean: True if file is updated, False if not 
 144     private boolean isFileUpdated() { 
 145         Log_OC
.d(TAG
, "FileLastModified: " + mFileLastModified
); 
 146         return (new File(mPath
).lastModified() > mFileLastModified
);