complete two way synchronization
[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
11 import android.accounts.Account;
12 import android.accounts.AccountManager;
13 import android.app.Service;
14 import android.content.BroadcastReceiver;
15 import android.content.Context;
16 import android.content.Intent;
17 import android.content.IntentFilter;
18 import android.database.Cursor;
19 import android.os.Binder;
20 import android.os.IBinder;
21 import android.util.Log;
22
23 public class FileObserverService extends Service {
24
25 public final static String KEY_FILE_CMD = "KEY_FILE_CMD";
26 public final static String KEY_CMD_ARG = "KEY_CMD_ARG";
27
28 public final static int CMD_INIT_OBSERVED_LIST = 1;
29 public final static int CMD_ADD_OBSERVED_FILE = 2;
30 public final static int CMD_DEL_OBSERVED_FILE = 3;
31
32 private static String TAG = "FileObserverService";
33 private static List<OwnCloudFileObserver> mObservers;
34 private static List<DownloadCompletedReceiver> mDownloadReceivers;
35 private static Object mReceiverListLock = new Object();
36 private IBinder mBinder = new LocalBinder();
37
38 public class LocalBinder extends Binder {
39 FileObserverService getService() {
40 return FileObserverService.this;
41 }
42 }
43
44 @Override
45 public IBinder onBind(Intent intent) {
46 return mBinder;
47 }
48
49 @Override
50 public int onStartCommand(Intent intent, int flags, int startId) {
51 if (!intent.hasExtra(KEY_FILE_CMD)) {
52 Log.e(TAG, "No KEY_FILE_CMD argument given");
53 return Service.START_STICKY;
54 }
55
56 switch (intent.getIntExtra(KEY_FILE_CMD, -1)) {
57 case CMD_INIT_OBSERVED_LIST:
58 initializeObservedList();
59 break;
60 case CMD_ADD_OBSERVED_FILE:
61 addObservedFile(intent.getStringExtra(KEY_CMD_ARG));
62 break;
63 case CMD_DEL_OBSERVED_FILE:
64 removeObservedFile(intent.getStringExtra(KEY_CMD_ARG));
65 break;
66 default:
67 Log.wtf(TAG, "Incorrect key given");
68 }
69
70 return Service.START_STICKY;
71 }
72
73 private void initializeObservedList() {
74 if (mObservers != null) return; // nothing to do here
75 mObservers = new ArrayList<OwnCloudFileObserver>();
76 mDownloadReceivers = new ArrayList<DownloadCompletedReceiver>();
77 Cursor c = getContentResolver().query(
78 ProviderTableMeta.CONTENT_URI,
79 null,
80 ProviderTableMeta.FILE_KEEP_IN_SYNC + " = ?",
81 new String[] {String.valueOf(1)},
82 null);
83 if (!c.moveToFirst()) return;
84 AccountManager acm = AccountManager.get(this);
85 Account[] accounts = acm.getAccounts();
86 do {
87 Account account = null;
88 for (Account a : accounts)
89 if (a.name.equals(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ACCOUNT_OWNER)))) {
90 account = a;
91 break;
92 }
93
94 if (account == null) continue;
95 FileDataStorageManager storage =
96 new FileDataStorageManager(account, getContentResolver());
97 if (!storage.fileExists(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH))))
98 continue;
99
100 String path = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));
101 OwnCloudFileObserver observer =
102 new OwnCloudFileObserver(path, OwnCloudFileObserver.CHANGES_ONLY);
103 observer.setContext(getBaseContext());
104 observer.setAccount(account);
105 observer.setStorageManager(storage);
106 observer.setOCFile(storage.getFileByPath(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH))));
107 observer.startWatching();
108 mObservers.add(observer);
109 Log.d(TAG, "Started watching file " + path);
110
111 } while (c.moveToNext());
112 c.close();
113 }
114
115 private void addObservedFile(String path) {
116 if (path == null) return;
117 if (mObservers == null) {
118 // this is very rare case when service was killed by system
119 // and observers list was deleted in that procedure
120 initializeObservedList();
121 }
122 boolean duplicate = false;
123 OwnCloudFileObserver observer = null;
124 for (int i = 0; i < mObservers.size(); ++i) {
125 observer = mObservers.get(i);
126 if (observer.getPath().equals(path))
127 duplicate = true;
128 observer.setContext(getBaseContext());
129 }
130 if (duplicate) return;
131 observer = new OwnCloudFileObserver(path, OwnCloudFileObserver.CHANGES_ONLY);
132 observer.setContext(getBaseContext());
133 Account account = AccountUtils.getCurrentOwnCloudAccount(getBaseContext());
134 observer.setAccount(account);
135 FileDataStorageManager storage =
136 new FileDataStorageManager(account, getContentResolver());
137 observer.setStorageManager(storage);
138 observer.setOCFile(storage.getFileByLocalPath(path));
139
140 DownloadCompletedReceiver receiver = new DownloadCompletedReceiver(path, observer);
141 registerReceiver(receiver, new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE));
142
143 mObservers.add(observer);
144 Log.d(TAG, "Observer added for path " + path);
145 }
146
147 private void removeObservedFile(String path) {
148 if (path == null) return;
149 if (mObservers == null) {
150 initializeObservedList();
151 return;
152 }
153 for (int i = 0; i < mObservers.size(); ++i) {
154 OwnCloudFileObserver observer = mObservers.get(i);
155 if (observer.getPath().equals(path)) {
156 observer.stopWatching();
157 mObservers.remove(i);
158 break;
159 }
160 }
161 Log.d(TAG, "Stopped watching " + path);
162 }
163
164 private static void addReceiverToList(DownloadCompletedReceiver r) {
165 synchronized(mReceiverListLock) {
166 mDownloadReceivers.add(r);
167 }
168 }
169
170 private static void removeReceiverFromList(DownloadCompletedReceiver r) {
171 synchronized(mReceiverListLock) {
172 mDownloadReceivers.remove(r);
173 }
174 }
175
176 private class DownloadCompletedReceiver extends BroadcastReceiver {
177 String mPath;
178 OwnCloudFileObserver mObserver;
179
180 public DownloadCompletedReceiver(String path, OwnCloudFileObserver observer) {
181 mPath = path;
182 mObserver = observer;
183 addReceiverToList(this);
184 }
185
186 @Override
187 public void onReceive(Context context, Intent intent) {
188 if (mPath.equals(intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH))) {
189 context.unregisterReceiver(this);
190 removeReceiverFromList(this);
191 mObserver.startWatching();
192 Log.d(TAG, "Started watching " + mPath);
193 return;
194 }
195 }
196
197 @Override
198 public boolean equals(Object o) {
199 if (o instanceof DownloadCompletedReceiver)
200 return mPath.equals(((DownloadCompletedReceiver)o).mPath);
201 return super.equals(o);
202 }
203 }
204 }