FileDownloader.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * Copyright (C) 2012 Bartek Przybylski
  5. * Copyright (C) 2012-2016 ownCloud Inc.
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2,
  9. * as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. package com.owncloud.android.files.services;
  21. import android.accounts.Account;
  22. import android.accounts.AccountManager;
  23. import android.accounts.OnAccountsUpdateListener;
  24. import android.app.Notification;
  25. import android.app.NotificationManager;
  26. import android.app.PendingIntent;
  27. import android.app.Service;
  28. import android.content.Intent;
  29. import android.os.Binder;
  30. import android.os.Handler;
  31. import android.os.HandlerThread;
  32. import android.os.IBinder;
  33. import android.os.Looper;
  34. import android.os.Message;
  35. import android.os.Process;
  36. import android.support.v4.app.NotificationCompat;
  37. import android.util.Pair;
  38. import com.owncloud.android.R;
  39. import com.owncloud.android.authentication.AccountUtils;
  40. import com.owncloud.android.authentication.AuthenticatorActivity;
  41. import com.owncloud.android.datamodel.FileDataStorageManager;
  42. import com.owncloud.android.datamodel.OCFile;
  43. import com.owncloud.android.lib.common.OwnCloudAccount;
  44. import com.owncloud.android.lib.common.OwnCloudClient;
  45. import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
  46. import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
  47. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  48. import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
  49. import com.owncloud.android.lib.common.utils.Log_OC;
  50. import com.owncloud.android.lib.resources.files.FileUtils;
  51. import com.owncloud.android.operations.DownloadFileOperation;
  52. import com.owncloud.android.ui.activity.FileActivity;
  53. import com.owncloud.android.ui.activity.FileDisplayActivity;
  54. import com.owncloud.android.ui.fragment.OCFileListFragment;
  55. import com.owncloud.android.ui.notifications.NotificationUtils;
  56. import com.owncloud.android.ui.preview.PreviewImageActivity;
  57. import com.owncloud.android.ui.preview.PreviewImageFragment;
  58. import com.owncloud.android.utils.ErrorMessageAdapter;
  59. import java.io.File;
  60. import java.util.AbstractList;
  61. import java.util.HashMap;
  62. import java.util.Iterator;
  63. import java.util.Map;
  64. import java.util.Vector;
  65. public class FileDownloader extends Service
  66. implements OnDatatransferProgressListener, OnAccountsUpdateListener {
  67. public static final String EXTRA_ACCOUNT = "ACCOUNT";
  68. public static final String EXTRA_FILE = "FILE";
  69. private static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED";
  70. private static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";
  71. public static final String EXTRA_DOWNLOAD_RESULT = "RESULT";
  72. public static final String EXTRA_FILE_PATH = "FILE_PATH";
  73. public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
  74. public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO";
  75. public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
  76. private static final int FOREGROUND_SERVICE_ID = 412;
  77. private static final String TAG = FileDownloader.class.getSimpleName();
  78. private Looper mServiceLooper;
  79. private ServiceHandler mServiceHandler;
  80. private IBinder mBinder;
  81. private OwnCloudClient mDownloadClient = null;
  82. private Account mCurrentAccount = null;
  83. private FileDataStorageManager mStorageManager;
  84. private IndexedForest<DownloadFileOperation> mPendingDownloads = new IndexedForest<DownloadFileOperation>();
  85. private DownloadFileOperation mCurrentDownload = null;
  86. private NotificationManager mNotificationManager;
  87. private NotificationCompat.Builder mNotificationBuilder;
  88. private int mLastPercent;
  89. private Notification mNotification;
  90. public static String getDownloadAddedMessage() {
  91. return FileDownloader.class.getName() + DOWNLOAD_ADDED_MESSAGE;
  92. }
  93. public static String getDownloadFinishMessage() {
  94. return FileDownloader.class.getName() + DOWNLOAD_FINISH_MESSAGE;
  95. }
  96. /**
  97. * Service initialization
  98. */
  99. @Override
  100. public void onCreate() {
  101. super.onCreate();
  102. Log_OC.d(TAG, "Creating service");
  103. mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
  104. HandlerThread thread = new HandlerThread("FileDownloaderThread",
  105. Process.THREAD_PRIORITY_BACKGROUND);
  106. thread.start();
  107. mServiceLooper = thread.getLooper();
  108. mServiceHandler = new ServiceHandler(mServiceLooper, this);
  109. mBinder = new FileDownloaderBinder();
  110. mNotification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext().
  111. getResources().getString(R.string.app_name))
  112. .build();
  113. // add AccountsUpdatedListener
  114. AccountManager am = AccountManager.get(getApplicationContext());
  115. am.addOnAccountsUpdatedListener(this, null, false);
  116. }
  117. /**
  118. * Service clean up
  119. */
  120. @Override
  121. public void onDestroy() {
  122. Log_OC.v(TAG, "Destroying service");
  123. mBinder = null;
  124. mServiceHandler = null;
  125. mServiceLooper.quit();
  126. mServiceLooper = null;
  127. mNotificationManager = null;
  128. // remove AccountsUpdatedListener
  129. AccountManager am = AccountManager.get(getApplicationContext());
  130. am.removeOnAccountsUpdatedListener(this);
  131. super.onDestroy();
  132. }
  133. /**
  134. * Entry point to add one or several files to the queue of downloads.
  135. *
  136. * New downloads are added calling to startService(), resulting in a call to this method.
  137. * This ensures the service will keep on working although the caller activity goes away.
  138. */
  139. @Override
  140. public int onStartCommand(Intent intent, int flags, int startId) {
  141. Log_OC.d(TAG, "Starting command with id " + startId);
  142. startForeground(FOREGROUND_SERVICE_ID, mNotification);
  143. if (!intent.hasExtra(EXTRA_ACCOUNT) ||
  144. !intent.hasExtra(EXTRA_FILE)
  145. ) {
  146. Log_OC.e(TAG, "Not enough information provided in intent");
  147. return START_NOT_STICKY;
  148. } else {
  149. final Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
  150. final OCFile file = intent.getParcelableExtra(EXTRA_FILE);
  151. final String behaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR);
  152. AbstractList<String> requestedDownloads = new Vector<String>();
  153. try {
  154. DownloadFileOperation newDownload = new DownloadFileOperation(account, file, behaviour);
  155. newDownload.addDatatransferProgressListener(this);
  156. newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder);
  157. Pair<String, String> putResult = mPendingDownloads.putIfAbsent(
  158. account.name, file.getRemotePath(), newDownload);
  159. if (putResult != null) {
  160. String downloadKey = putResult.first;
  161. requestedDownloads.add(downloadKey);
  162. sendBroadcastNewDownload(newDownload, putResult.second);
  163. } // else, file already in the queue of downloads; don't repeat the request
  164. } catch (IllegalArgumentException e) {
  165. Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage());
  166. return START_NOT_STICKY;
  167. }
  168. if (requestedDownloads.size() > 0) {
  169. Message msg = mServiceHandler.obtainMessage();
  170. msg.arg1 = startId;
  171. msg.obj = requestedDownloads;
  172. mServiceHandler.sendMessage(msg);
  173. }
  174. }
  175. return START_NOT_STICKY;
  176. }
  177. /**
  178. * Provides a binder object that clients can use to perform operations on the queue of downloads,
  179. * excepting the addition of new files.
  180. * <p/>
  181. * Implemented to perform cancellation, pause and resume of existing downloads.
  182. */
  183. @Override
  184. public IBinder onBind(Intent arg0) {
  185. return mBinder;
  186. }
  187. /**
  188. * Called when ALL the bound clients were onbound.
  189. */
  190. @Override
  191. public boolean onUnbind(Intent intent) {
  192. ((FileDownloaderBinder) mBinder).clearListeners();
  193. return false; // not accepting rebinding (default behaviour)
  194. }
  195. @Override
  196. public void onAccountsUpdated(Account[] accounts) {
  197. //review the current download and cancel it if its account doesn't exist
  198. if (mCurrentDownload != null &&
  199. !AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) {
  200. mCurrentDownload.cancel();
  201. }
  202. // The rest of downloads are cancelled when they try to start
  203. }
  204. /**
  205. * Binder to let client components to perform operations on the queue of downloads.
  206. * <p/>
  207. * It provides by itself the available operations.
  208. */
  209. public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener {
  210. /**
  211. * Map of listeners that will be reported about progress of downloads from a
  212. * {@link FileDownloaderBinder}
  213. * instance.
  214. */
  215. private Map<Long, OnDatatransferProgressListener> mBoundListeners =
  216. new HashMap<Long, OnDatatransferProgressListener>();
  217. /**
  218. * Cancels a pending or current download of a remote file.
  219. *
  220. * @param account ownCloud account where the remote file is stored.
  221. * @param file A file in the queue of pending downloads
  222. */
  223. public void cancel(Account account, OCFile file) {
  224. Pair<DownloadFileOperation, String> removeResult =
  225. mPendingDownloads.remove(account.name, file.getRemotePath());
  226. DownloadFileOperation download = removeResult.first;
  227. if (download != null) {
  228. download.cancel();
  229. } else {
  230. if (mCurrentDownload != null && mCurrentAccount != null &&
  231. mCurrentDownload.getRemotePath().startsWith(file.getRemotePath()) &&
  232. account.name.equals(mCurrentAccount.name)) {
  233. mCurrentDownload.cancel();
  234. }
  235. }
  236. }
  237. /**
  238. * Cancels all the downloads for an account
  239. *
  240. * @param account ownCloud account.
  241. */
  242. public void cancel(Account account) {
  243. Log_OC.d(TAG, "Account= " + account.name);
  244. if (mCurrentDownload != null) {
  245. Log_OC.d(TAG, "Current Download Account= " + mCurrentDownload.getAccount().name);
  246. if (mCurrentDownload.getAccount().name.equals(account.name)) {
  247. mCurrentDownload.cancel();
  248. }
  249. }
  250. // Cancel pending downloads
  251. cancelDownloadsForAccount(account);
  252. }
  253. public void clearListeners() {
  254. mBoundListeners.clear();
  255. }
  256. /**
  257. * Returns True when the file described by 'file' in the ownCloud account 'account'
  258. * is downloading or waiting to download.
  259. *
  260. * If 'file' is a directory, returns 'true' if any of its descendant files is downloading or
  261. * waiting to download.
  262. *
  263. * @param account ownCloud account where the remote file is stored.
  264. * @param file A file that could be in the queue of downloads.
  265. */
  266. public boolean isDownloading(Account account, OCFile file) {
  267. if (account == null || file == null) {
  268. return false;
  269. }
  270. return (mPendingDownloads.contains(account.name, file.getRemotePath()));
  271. }
  272. /**
  273. * Adds a listener interested in the progress of the download for a concrete file.
  274. *
  275. * @param listener Object to notify about progress of transfer.
  276. * @param account ownCloud account holding the file of interest.
  277. * @param file {@link OCFile} of interest for listener.
  278. */
  279. public void addDatatransferProgressListener(
  280. OnDatatransferProgressListener listener, Account account, OCFile file
  281. ) {
  282. if (account == null || file == null || listener == null) {
  283. return;
  284. }
  285. mBoundListeners.put(file.getFileId(), listener);
  286. }
  287. /**
  288. * Removes a listener interested in the progress of the download for a concrete file.
  289. *
  290. * @param listener Object to notify about progress of transfer.
  291. * @param account ownCloud account holding the file of interest.
  292. * @param file {@link OCFile} of interest for listener.
  293. */
  294. public void removeDatatransferProgressListener(
  295. OnDatatransferProgressListener listener, Account account, OCFile file
  296. ) {
  297. if (account == null || file == null || listener == null) {
  298. return;
  299. }
  300. Long fileId = file.getFileId();
  301. if (mBoundListeners.get(fileId) == listener) {
  302. mBoundListeners.remove(fileId);
  303. }
  304. }
  305. @Override
  306. public void onTransferProgress(long progressRate, long totalTransferredSoFar,
  307. long totalToTransfer, String fileName) {
  308. OnDatatransferProgressListener boundListener =
  309. mBoundListeners.get(mCurrentDownload.getFile().getFileId());
  310. if (boundListener != null) {
  311. boundListener.onTransferProgress(progressRate, totalTransferredSoFar,
  312. totalToTransfer, fileName);
  313. }
  314. }
  315. }
  316. /**
  317. * Download worker. Performs the pending downloads in the order they were requested.
  318. * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}.
  319. */
  320. private static class ServiceHandler extends Handler {
  321. // don't make it a final class, and don't remove the static ; lint will warn about a
  322. // possible memory leak
  323. FileDownloader mService;
  324. public ServiceHandler(Looper looper, FileDownloader service) {
  325. super(looper);
  326. if (service == null) {
  327. throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
  328. }
  329. mService = service;
  330. }
  331. @Override
  332. public void handleMessage(Message msg) {
  333. @SuppressWarnings("unchecked")
  334. AbstractList<String> requestedDownloads = (AbstractList<String>) msg.obj;
  335. if (msg.obj != null) {
  336. Iterator<String> it = requestedDownloads.iterator();
  337. while (it.hasNext()) {
  338. String next = it.next();
  339. mService.downloadFile(next);
  340. }
  341. }
  342. Log_OC.d(TAG, "Stopping after command with id " + msg.arg1);
  343. mService.stopForeground(true);
  344. mService.stopSelf(msg.arg1);
  345. }
  346. }
  347. /**
  348. * Core download method: requests a file to download and stores it.
  349. *
  350. * @param downloadKey Key to access the download to perform, contained in mPendingDownloads
  351. */
  352. private void downloadFile(String downloadKey) {
  353. mCurrentDownload = mPendingDownloads.get(downloadKey);
  354. if (mCurrentDownload != null) {
  355. // Detect if the account exists
  356. if (AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) {
  357. Log_OC.d(TAG, "Account " + mCurrentDownload.getAccount().name + " exists");
  358. notifyDownloadStart(mCurrentDownload);
  359. RemoteOperationResult downloadResult = null;
  360. try {
  361. /// prepare client object to send the request to the ownCloud server
  362. if (mCurrentAccount == null ||
  363. !mCurrentAccount.equals(mCurrentDownload.getAccount())) {
  364. mCurrentAccount = mCurrentDownload.getAccount();
  365. mStorageManager = new FileDataStorageManager(
  366. mCurrentAccount,
  367. getContentResolver()
  368. );
  369. } // else, reuse storage manager from previous operation
  370. // always get client from client manager, to get fresh credentials in case
  371. // of update
  372. OwnCloudAccount ocAccount = new OwnCloudAccount(
  373. mCurrentAccount,
  374. this
  375. );
  376. mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
  377. getClientFor(ocAccount, this);
  378. /// perform the download
  379. downloadResult = mCurrentDownload.execute(mDownloadClient);
  380. if (downloadResult.isSuccess()) {
  381. saveDownloadedFile();
  382. }
  383. } catch (Exception e) {
  384. Log_OC.e(TAG, "Error downloading", e);
  385. downloadResult = new RemoteOperationResult(e);
  386. } finally {
  387. Pair<DownloadFileOperation, String> removeResult =
  388. mPendingDownloads.removePayload(
  389. mCurrentAccount.name,
  390. mCurrentDownload.getRemotePath()
  391. );
  392. /// notify result
  393. notifyDownloadResult(mCurrentDownload, downloadResult);
  394. sendBroadcastDownloadFinished(mCurrentDownload, downloadResult, removeResult.second);
  395. }
  396. } else {
  397. // Cancel the transfer
  398. Log_OC.d(TAG, "Account " + mCurrentDownload.getAccount().toString() +
  399. " doesn't exist");
  400. cancelDownloadsForAccount(mCurrentDownload.getAccount());
  401. }
  402. }
  403. }
  404. /**
  405. * Updates the OC File after a successful download.
  406. *
  407. * TODO move to DownloadFileOperation
  408. */
  409. private void saveDownloadedFile() {
  410. OCFile file = mStorageManager.getFileById(mCurrentDownload.getFile().getFileId());
  411. long syncDate = System.currentTimeMillis();
  412. file.setLastSyncDateForProperties(syncDate);
  413. file.setLastSyncDateForData(syncDate);
  414. file.setNeedsUpdateThumbnail(true);
  415. file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp());
  416. file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp());
  417. file.setEtag(mCurrentDownload.getEtag());
  418. file.setMimetype(mCurrentDownload.getMimeType());
  419. file.setStoragePath(mCurrentDownload.getSavePath());
  420. file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));
  421. file.setRemoteId(mCurrentDownload.getFile().getRemoteId());
  422. mStorageManager.saveFile(file);
  423. FileDataStorageManager.triggerMediaScan(file.getStoragePath());
  424. mStorageManager.saveConflict(file, null);
  425. }
  426. /**
  427. * Creates a status notification to show the download progress
  428. *
  429. * @param download Download operation starting.
  430. */
  431. private void notifyDownloadStart(DownloadFileOperation download) {
  432. /// create status notification with a progress bar
  433. mLastPercent = 0;
  434. mNotificationBuilder =
  435. NotificationUtils.newNotificationBuilder(this);
  436. mNotificationBuilder
  437. .setSmallIcon(R.drawable.notification_icon)
  438. .setTicker(getString(R.string.downloader_download_in_progress_ticker))
  439. .setContentTitle(getString(R.string.downloader_download_in_progress_ticker))
  440. .setOngoing(true)
  441. .setProgress(100, 0, download.getSize() < 0)
  442. .setContentText(
  443. String.format(getString(R.string.downloader_download_in_progress_content), 0,
  444. new File(download.getSavePath()).getName())
  445. );
  446. /// includes a pending intent in the notification showing the details view of the file
  447. Intent showDetailsIntent = null;
  448. if (PreviewImageFragment.canBePreviewed(download.getFile())) {
  449. showDetailsIntent = new Intent(this, PreviewImageActivity.class);
  450. } else {
  451. showDetailsIntent = new Intent(this, FileDisplayActivity.class);
  452. }
  453. showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile());
  454. showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, download.getAccount());
  455. showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  456. mNotificationBuilder.setContentIntent(PendingIntent.getActivity(
  457. this, (int) System.currentTimeMillis(), showDetailsIntent, 0
  458. ));
  459. mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build());
  460. }
  461. /**
  462. * Callback method to update the progress bar in the status notification.
  463. */
  464. @Override
  465. public void onTransferProgress(long progressRate, long totalTransferredSoFar,
  466. long totalToTransfer, String filePath) {
  467. int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer));
  468. if (percent != mLastPercent) {
  469. mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0);
  470. String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1);
  471. String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName);
  472. mNotificationBuilder.setContentText(text);
  473. mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build());
  474. }
  475. mLastPercent = percent;
  476. }
  477. /**
  478. * Updates the status notification with the result of a download operation.
  479. *
  480. * @param downloadResult Result of the download operation.
  481. * @param download Finished download operation
  482. */
  483. private void notifyDownloadResult(DownloadFileOperation download,
  484. RemoteOperationResult downloadResult) {
  485. mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker);
  486. if (!downloadResult.isCancelled()) {
  487. int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker :
  488. R.string.downloader_download_failed_ticker;
  489. boolean needsToUpdateCredentials = (ResultCode.UNAUTHORIZED.equals(downloadResult.getCode()));
  490. tickerId = (needsToUpdateCredentials) ?
  491. R.string.downloader_download_failed_credentials_error : tickerId;
  492. mNotificationBuilder
  493. .setTicker(getString(tickerId))
  494. .setContentTitle(getString(tickerId))
  495. .setAutoCancel(true)
  496. .setOngoing(false)
  497. .setProgress(0, 0, false);
  498. if (needsToUpdateCredentials) {
  499. // let the user update credentials with one click
  500. Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
  501. updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT,
  502. download.getAccount());
  503. updateAccountCredentials.putExtra(
  504. AuthenticatorActivity.EXTRA_ACTION,
  505. AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN
  506. );
  507. updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  508. updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
  509. updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
  510. mNotificationBuilder
  511. .setContentIntent(PendingIntent.getActivity(
  512. this, (int) System.currentTimeMillis(), updateAccountCredentials,
  513. PendingIntent.FLAG_ONE_SHOT));
  514. } else {
  515. // TODO put something smart in showDetailsIntent
  516. Intent showDetailsIntent = new Intent();
  517. mNotificationBuilder
  518. .setContentIntent(PendingIntent.getActivity(
  519. this, (int) System.currentTimeMillis(), showDetailsIntent, 0));
  520. }
  521. mNotificationBuilder.setContentText(
  522. ErrorMessageAdapter.getErrorCauseMessage(downloadResult, download,
  523. getResources())
  524. );
  525. mNotificationManager.notify(tickerId, mNotificationBuilder.build());
  526. // Remove success notification
  527. if (downloadResult.isSuccess()) {
  528. // Sleep 2 seconds, so show the notification before remove it
  529. NotificationUtils.cancelWithDelay(
  530. mNotificationManager,
  531. R.string.downloader_download_succeeded_ticker,
  532. 2000);
  533. }
  534. }
  535. }
  536. /**
  537. * Sends a broadcast when a download finishes in order to the interested activities can
  538. * update their view
  539. *
  540. * @param download Finished download operation
  541. * @param downloadResult Result of the download operation
  542. * @param unlinkedFromRemotePath Path in the downloads tree where the download was unlinked from
  543. */
  544. private void sendBroadcastDownloadFinished(
  545. DownloadFileOperation download,
  546. RemoteOperationResult downloadResult,
  547. String unlinkedFromRemotePath) {
  548. Intent end = new Intent(getDownloadFinishMessage());
  549. end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess());
  550. end.putExtra(ACCOUNT_NAME, download.getAccount().name);
  551. end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());
  552. end.putExtra(EXTRA_FILE_PATH, download.getSavePath());
  553. end.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.getBehaviour());
  554. if (unlinkedFromRemotePath != null) {
  555. end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath);
  556. }
  557. end.setPackage(getPackageName());
  558. sendStickyBroadcast(end);
  559. }
  560. /**
  561. * Sends a broadcast when a new download is added to the queue.
  562. *
  563. * @param download Added download operation
  564. * @param linkedToRemotePath Path in the downloads tree where the download was linked to
  565. */
  566. private void sendBroadcastNewDownload(DownloadFileOperation download,
  567. String linkedToRemotePath) {
  568. Intent added = new Intent(getDownloadAddedMessage());
  569. added.putExtra(ACCOUNT_NAME, download.getAccount().name);
  570. added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());
  571. added.putExtra(EXTRA_FILE_PATH, download.getSavePath());
  572. added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath);
  573. added.setPackage(getPackageName());
  574. sendStickyBroadcast(added);
  575. }
  576. /**
  577. * Remove downloads of an account
  578. *
  579. * @param account Downloads account to remove
  580. */
  581. private void cancelDownloadsForAccount(Account account) {
  582. // Cancel pending downloads
  583. mPendingDownloads.remove(account.name);
  584. }
  585. }