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