Solving modified date and length conflicts
[pub/Android/ownCloud.git] / src / com / owncloud / android / files / services / FileObserverService.java
1 package com.owncloud.android.files.services;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import com.owncloud.android.AccountUtils;
7 import com.owncloud.android.datamodel.FileDataStorageManager;
8 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
9 import com.owncloud.android.files.OwnCloudFileObserver;
10 import com.owncloud.android.files.OwnCloudFileObserver.FileObserverStatusListener;
11 import com.owncloud.android.ui.activity.ConflictsResolveActivity;
12
13 import android.accounts.Account;
14 import android.accounts.AccountManager;
15 import android.app.Service;
16 import android.content.BroadcastReceiver;
17 import android.content.Context;
18 import android.content.Intent;
19 import android.content.IntentFilter;
20 import android.database.Cursor;
21 import android.os.Binder;
22 import android.os.IBinder;
23 import android.util.Log;
24
25 public class FileObserverService extends Service implements FileObserverStatusListener {
26
27 public final static String KEY_FILE_CMD = "KEY_FILE_CMD";
28 public final static String KEY_CMD_ARG = "KEY_CMD_ARG";
29
30 public final static int CMD_INIT_OBSERVED_LIST = 1;
31 public final static int CMD_ADD_OBSERVED_FILE = 2;
32 public final static int CMD_DEL_OBSERVED_FILE = 3;
33 public final static int CMD_ADD_DOWNLOADING_FILE = 4;
34
35 private static String TAG = "FileObserverService";
36 private static List<OwnCloudFileObserver> mObservers;
37 private static List<DownloadCompletedReceiver> mDownloadReceivers;
38 private static Object mReceiverListLock = new Object();
39 private IBinder mBinder = new LocalBinder();
40
41 public class LocalBinder extends Binder {
42 FileObserverService getService() {
43 return FileObserverService.this;
44 }
45 }
46
47 @Override
48 public IBinder onBind(Intent intent) {
49 return mBinder;
50 }
51
52 @Override
53 public int onStartCommand(Intent intent, int flags, int startId) {
54 // this occurs when system tries to restart
55 // service, so we need to reinitialize observers
56 if (intent == null) {
57 initializeObservedList();
58 return Service.START_STICKY;
59 }
60
61 if (!intent.hasExtra(KEY_FILE_CMD)) {
62 Log.e(TAG, "No KEY_FILE_CMD argument given");
63 return Service.START_STICKY;
64 }
65
66 switch (intent.getIntExtra(KEY_FILE_CMD, -1)) {
67 case CMD_INIT_OBSERVED_LIST:
68 initializeObservedList();
69 break;
70 case CMD_ADD_OBSERVED_FILE:
71 addObservedFile(intent.getStringExtra(KEY_CMD_ARG));
72 break;
73 case CMD_DEL_OBSERVED_FILE:
74 removeObservedFile(intent.getStringExtra(KEY_CMD_ARG));
75 break;
76 case CMD_ADD_DOWNLOADING_FILE:
77 addDownloadingFile(intent.getStringExtra(KEY_CMD_ARG));
78 break;
79 default:
80 Log.wtf(TAG, "Incorrect key given");
81 }
82
83 return Service.START_STICKY;
84 }
85
86 private void initializeObservedList() {
87 if (mObservers != null) return; // nothing to do here
88 mObservers = new ArrayList<OwnCloudFileObserver>();
89 mDownloadReceivers = new ArrayList<DownloadCompletedReceiver>();
90 Cursor c = getContentResolver().query(
91 ProviderTableMeta.CONTENT_URI,
92 null,
93 ProviderTableMeta.FILE_KEEP_IN_SYNC + " = ?",
94 new String[] {String.valueOf(1)},
95 null);
96 if (!c.moveToFirst()) return;
97 AccountManager acm = AccountManager.get(this);
98 Account[] accounts = acm.getAccounts();
99 do {
100 Account account = null;
101 for (Account a : accounts)
102 if (a.name.equals(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ACCOUNT_OWNER)))) {
103 account = a;
104 break;
105 }
106
107 if (account == null) continue;
108 FileDataStorageManager storage =
109 new FileDataStorageManager(account, getContentResolver());
110 if (!storage.fileExists(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH))))
111 continue;
112
113 String path = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));
114 OwnCloudFileObserver observer =
115 new OwnCloudFileObserver(path, OwnCloudFileObserver.CHANGES_ONLY);
116 observer.setContext(getApplicationContext());
117 observer.setAccount(account);
118 observer.setStorageManager(storage);
119 observer.setOCFile(storage.getFileByPath(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH))));
120 observer.addObserverStatusListener(this);
121 observer.startWatching();
122 mObservers.add(observer);
123 Log.d(TAG, "Started watching file " + path);
124
125 } while (c.moveToNext());
126 c.close();
127 }
128
129 private void addObservedFile(String path) {
130 if (path == null) return;
131 if (mObservers == null) {
132 // this is very rare case when service was killed by system
133 // and observers list was deleted in that procedure
134 initializeObservedList();
135 }
136 boolean duplicate = false;
137 OwnCloudFileObserver observer = null;
138 for (int i = 0; i < mObservers.size(); ++i) {
139 observer = mObservers.get(i);
140 if (observer.getPath().equals(path))
141 duplicate = true;
142 observer.setContext(getBaseContext());
143 }
144 if (duplicate) return;
145 observer = new OwnCloudFileObserver(path, OwnCloudFileObserver.CHANGES_ONLY);
146 observer.setContext(getBaseContext());
147 Account account = AccountUtils.getCurrentOwnCloudAccount(getBaseContext());
148 observer.setAccount(account);
149 FileDataStorageManager storage =
150 new FileDataStorageManager(account, getContentResolver());
151 observer.setStorageManager(storage);
152 observer.setOCFile(storage.getFileByLocalPath(path));
153 observer.addObserverStatusListener(this);
154
155 DownloadCompletedReceiver receiver = new DownloadCompletedReceiver(path, observer);
156 registerReceiver(receiver, new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE));
157
158 mObservers.add(observer);
159 Log.d(TAG, "Observer added for path " + path);
160 }
161
162 private void removeObservedFile(String path) {
163 if (path == null) return;
164 if (mObservers == null) {
165 initializeObservedList();
166 return;
167 }
168 for (int i = 0; i < mObservers.size(); ++i) {
169 OwnCloudFileObserver observer = mObservers.get(i);
170 if (observer.getPath().equals(path)) {
171 observer.stopWatching();
172 mObservers.remove(i);
173 break;
174 }
175 }
176 Log.d(TAG, "Stopped watching " + path);
177 }
178
179 private void addDownloadingFile(String remotePath) {
180 OwnCloudFileObserver observer = null;
181 for (OwnCloudFileObserver o : mObservers) {
182 if (o.getRemotePath().equals(remotePath)) {
183 observer = o;
184 break;
185 }
186 }
187 if (observer == null) {
188 Log.e(TAG, "Couldn't find observer for remote file " + remotePath);
189 return;
190 }
191 observer.stopWatching();
192 DownloadCompletedReceiver dcr = new DownloadCompletedReceiver(observer.getPath(), observer);
193 registerReceiver(dcr, new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE));
194 }
195
196
197 private static void addReceiverToList(DownloadCompletedReceiver r) {
198 synchronized(mReceiverListLock) {
199 mDownloadReceivers.add(r);
200 }
201 }
202
203 private static void removeReceiverFromList(DownloadCompletedReceiver r) {
204 synchronized(mReceiverListLock) {
205 mDownloadReceivers.remove(r);
206 }
207 }
208
209 @Override
210 public void OnObservedFileStatusUpdate(String localPath, String remotePath, Account account, Status status) {
211 switch (status) {
212 case CONFLICT:
213 {
214 Intent i = new Intent(getApplicationContext(), ConflictsResolveActivity.class);
215 i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
216 i.putExtra("remotepath", remotePath);
217 i.putExtra("localpath", localPath);
218 i.putExtra("account", account);
219 startActivity(i);
220 break;
221 }
222 case SENDING_TO_UPLOADER:
223 case INCORRECT_MASK:
224 break;
225 default:
226 Log.wtf(TAG, "Unhandled status " + status);
227 }
228 }
229
230 private class DownloadCompletedReceiver extends BroadcastReceiver {
231 String mPath;
232 OwnCloudFileObserver mObserver;
233
234 public DownloadCompletedReceiver(String path, OwnCloudFileObserver observer) {
235 mPath = path;
236 mObserver = observer;
237 addReceiverToList(this);
238 }
239
240 @Override
241 public void onReceive(Context context, Intent intent) {
242 if (mPath.equals(intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH))) {
243 context.unregisterReceiver(this);
244 removeReceiverFromList(this);
245 mObserver.startWatching();
246 Log.d(TAG, "Started watching " + mPath);
247 return;
248 }
249 }
250
251 @Override
252 public boolean equals(Object o) {
253 if (o instanceof DownloadCompletedReceiver)
254 return mPath.equals(((DownloadCompletedReceiver)o).mPath);
255 return super.equals(o);
256 }
257 }
258 }