FileOperationsHelper.java 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. /*
  2. * ownCloud Android client application
  3. *
  4. * @author masensio
  5. * @author David A. Velasco
  6. * @author Juan Carlos González Cabrero
  7. * Copyright (C) 2015 ownCloud Inc.
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2,
  11. * as published by the Free Software Foundation.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. package com.owncloud.android.ui.helpers;
  22. import android.accounts.Account;
  23. import android.content.ActivityNotFoundException;
  24. import android.content.Context;
  25. import android.content.Intent;
  26. import android.content.pm.PackageManager;
  27. import android.content.pm.ResolveInfo;
  28. import android.net.Uri;
  29. import android.os.Build;
  30. import android.support.annotation.Nullable;
  31. import android.support.v4.content.FileProvider;
  32. import android.webkit.MimeTypeMap;
  33. import android.widget.Toast;
  34. import com.owncloud.android.MainApp;
  35. import com.owncloud.android.R;
  36. import com.owncloud.android.authentication.AccountUtils;
  37. import com.owncloud.android.datamodel.FileDataStorageManager;
  38. import com.owncloud.android.datamodel.OCFile;
  39. import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
  40. import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
  41. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  42. import com.owncloud.android.lib.common.utils.Log_OC;
  43. import com.owncloud.android.lib.resources.shares.OCShare;
  44. import com.owncloud.android.lib.resources.shares.ShareType;
  45. import com.owncloud.android.lib.resources.status.OwnCloudVersion;
  46. import com.owncloud.android.operations.SynchronizeFileOperation;
  47. import com.owncloud.android.services.OperationsService;
  48. import com.owncloud.android.services.observer.FileObserverService;
  49. import com.owncloud.android.ui.activity.ConflictsResolveActivity;
  50. import com.owncloud.android.ui.activity.FileActivity;
  51. import com.owncloud.android.ui.activity.ShareActivity;
  52. import com.owncloud.android.ui.events.FavoriteEvent;
  53. import com.owncloud.android.ui.events.SyncEventFinished;
  54. import com.owncloud.android.utils.FileStorageUtils;
  55. import com.owncloud.android.utils.DisplayUtils;
  56. import org.greenrobot.eventbus.EventBus;
  57. import java.io.BufferedReader;
  58. import java.io.File;
  59. import java.io.FileInputStream;
  60. import java.io.IOException;
  61. import java.io.InputStreamReader;
  62. import java.util.ArrayList;
  63. import java.util.Collection;
  64. import java.util.List;
  65. import java.util.regex.Matcher;
  66. import java.util.regex.Pattern;
  67. /**
  68. *
  69. */
  70. public class FileOperationsHelper {
  71. private static final String TAG = FileOperationsHelper.class.getSimpleName();
  72. private static final Pattern mPatternUrl = Pattern.compile("^URL=(.+)$");
  73. private static final Pattern mPatternString = Pattern.compile("<string>(.+)</string>");
  74. private FileActivity mFileActivity = null;
  75. /// Identifier of operation in progress which result shouldn't be lost
  76. private long mWaitingForOpId = Long.MAX_VALUE;
  77. public FileOperationsHelper(FileActivity fileActivity) {
  78. mFileActivity = fileActivity;
  79. }
  80. @Nullable
  81. private String getUrlFromFile(String storagePath, Pattern pattern) {
  82. String url = null;
  83. InputStreamReader fr = null;
  84. BufferedReader br = null;
  85. try {
  86. fr = new InputStreamReader(new FileInputStream(storagePath), "UTF8");
  87. br = new BufferedReader(fr);
  88. String line;
  89. while ((line = br.readLine()) != null) {
  90. Matcher m = pattern.matcher(line);
  91. if (m.find()) {
  92. url = m.group(1);
  93. break;
  94. }
  95. }
  96. } catch (IOException e) {
  97. Log_OC.d(TAG, e.getMessage());
  98. } finally {
  99. if (br != null) {
  100. try {
  101. br.close();
  102. } catch (IOException e) {
  103. Log_OC.d(TAG, "Error closing buffered reader for URL file", e);
  104. }
  105. }
  106. if (fr != null) {
  107. try {
  108. fr.close();
  109. } catch (IOException e) {
  110. Log_OC.d(TAG, "Error closing file reader for URL file", e);
  111. }
  112. }
  113. }
  114. return url;
  115. }
  116. @Nullable
  117. private Intent createIntentFromFile(String storagePath) {
  118. String url = null;
  119. int lastIndexOfDot = storagePath.lastIndexOf('.');
  120. if (lastIndexOfDot >= 0) {
  121. String fileExt = storagePath.substring(lastIndexOfDot + 1);
  122. if (fileExt.equalsIgnoreCase("url") || fileExt.equalsIgnoreCase("desktop")) {
  123. // Windows internet shortcut file .url
  124. // Ubuntu internet shortcut file .desktop
  125. url = getUrlFromFile(storagePath, mPatternUrl);
  126. } else if (fileExt.equalsIgnoreCase("webloc")) {
  127. // mac internet shortcut file .webloc
  128. url = getUrlFromFile(storagePath, mPatternString);
  129. }
  130. }
  131. if (url == null) {
  132. return null;
  133. }
  134. return new Intent(Intent.ACTION_VIEW, Uri.parse(url));
  135. }
  136. public void startSyncForFileAndIntent(OCFile file, Intent intent) {
  137. mFileActivity.showLoadingDialog(mFileActivity.getResources().getString(R.string.sync_in_progress));
  138. new Thread(new Runnable() {
  139. @Override
  140. public void run() {
  141. Account account = AccountUtils.getCurrentOwnCloudAccount(mFileActivity);
  142. FileDataStorageManager storageManager =
  143. new FileDataStorageManager(account, mFileActivity.getContentResolver());
  144. SynchronizeFileOperation sfo =
  145. new SynchronizeFileOperation(file, null, account, true, mFileActivity);
  146. RemoteOperationResult result = sfo.execute(storageManager, mFileActivity);
  147. if (result.getCode() == RemoteOperationResult.ResultCode.SYNC_CONFLICT) {
  148. // ISSUE 5: if the user is not running the app (this is a service!),
  149. // this can be very intrusive; a notification should be preferred
  150. Intent i = new Intent(mFileActivity, ConflictsResolveActivity.class);
  151. i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
  152. i.putExtra(ConflictsResolveActivity.EXTRA_FILE, file);
  153. i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, account);
  154. mFileActivity.startActivity(i);
  155. } else {
  156. FileStorageUtils.checkIfFileFinishedSaving(file);
  157. EventBus.getDefault().post(new SyncEventFinished(intent));
  158. }
  159. mFileActivity.dismissLoadingDialog();
  160. }
  161. }).start();
  162. }
  163. public void openFile(OCFile file) {
  164. if (file != null) {
  165. String storagePath = file.getStoragePath();
  166. Intent openFileWithIntent = null;
  167. int lastIndexOfDot = storagePath.lastIndexOf('.');
  168. if (lastIndexOfDot >= 0) {
  169. String fileExt = storagePath.substring(lastIndexOfDot + 1);
  170. String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExt);
  171. if (guessedMimeType != null) {
  172. openFileWithIntent = new Intent(Intent.ACTION_VIEW);
  173. openFileWithIntent.setDataAndType(
  174. file.getExposedFileUri(mFileActivity),
  175. guessedMimeType
  176. );
  177. }
  178. }
  179. if (openFileWithIntent == null) {
  180. openFileWithIntent = createIntentFromFile(storagePath);
  181. }
  182. if (openFileWithIntent == null) {
  183. openFileWithIntent = new Intent(Intent.ACTION_VIEW);
  184. openFileWithIntent.setDataAndType(
  185. file.getExposedFileUri(mFileActivity),
  186. file.getMimetype()
  187. );
  188. }
  189. openFileWithIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
  190. List<ResolveInfo> launchables = mFileActivity.getPackageManager().
  191. queryIntentActivities(openFileWithIntent, PackageManager.GET_RESOLVED_FILTER);
  192. mFileActivity.showLoadingDialog(mFileActivity.getResources().getString(R.string.sync_in_progress));
  193. Intent finalOpenFileWithIntent = openFileWithIntent;
  194. new Thread(new Runnable() {
  195. @Override
  196. public void run() {
  197. Account account = AccountUtils.getCurrentOwnCloudAccount(mFileActivity);
  198. FileDataStorageManager storageManager =
  199. new FileDataStorageManager(account, mFileActivity.getContentResolver());
  200. // a fresh object is needed; many things could have occurred to the file
  201. // since it was registered to observe again, assuming that local files
  202. // are linked to a remote file AT MOST, SOMETHING TO BE DONE;
  203. SynchronizeFileOperation sfo =
  204. new SynchronizeFileOperation(file, null, account, true, mFileActivity);
  205. RemoteOperationResult result = sfo.execute(storageManager, mFileActivity);
  206. mFileActivity.dismissLoadingDialog();
  207. if (result.getCode() == RemoteOperationResult.ResultCode.SYNC_CONFLICT) {
  208. // ISSUE 5: if the user is not running the app (this is a service!),
  209. // this can be very intrusive; a notification should be preferred
  210. Intent i = new Intent(mFileActivity, ConflictsResolveActivity.class);
  211. i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
  212. i.putExtra(ConflictsResolveActivity.EXTRA_FILE, file);
  213. i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, account);
  214. mFileActivity.startActivity(i);
  215. } else {
  216. if (launchables != null && launchables.size() > 0) {
  217. try {
  218. mFileActivity.startActivity(
  219. Intent.createChooser(
  220. finalOpenFileWithIntent,
  221. mFileActivity.getString(R.string.actionbar_open_with)
  222. )
  223. );
  224. } catch (ActivityNotFoundException anfe) {
  225. DisplayUtils.showSnackMessage(mFileActivity, R.string.file_list_no_app_for_file_type);
  226. }
  227. } else {
  228. DisplayUtils.showSnackMessage(mFileActivity, R.string.file_list_no_app_for_file_type);
  229. }
  230. }
  231. }
  232. }).start();
  233. } else {
  234. Log_OC.e(TAG, "Trying to open a NULL OCFile");
  235. }
  236. }
  237. /**
  238. * Helper method to share a file via a public link. Starts a request to do it in {@link OperationsService}
  239. *
  240. * @param file The file to share.
  241. * @param password Optional password to protect the public share.
  242. */
  243. public void shareFileViaLink(OCFile file, String password) {
  244. if (isSharedSupported()) {
  245. if (file != null) {
  246. mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
  247. Intent service = new Intent(mFileActivity, OperationsService.class);
  248. service.setAction(OperationsService.ACTION_CREATE_SHARE_VIA_LINK);
  249. service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  250. if (password != null && password.length() > 0) {
  251. service.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, password);
  252. }
  253. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  254. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
  255. } else {
  256. Log_OC.e(TAG, "Trying to share a NULL OCFile");
  257. // TODO user-level error?
  258. }
  259. } else {
  260. // Show a Message
  261. DisplayUtils.showSnackMessage(mFileActivity, R.string.share_link_no_support_share_api);
  262. }
  263. }
  264. public void getFileWithLink(OCFile file) {
  265. if (isSharedSupported()) {
  266. if (file != null) {
  267. mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
  268. getString(R.string.wait_a_moment));
  269. Intent service = new Intent(mFileActivity, OperationsService.class);
  270. service.setAction(OperationsService.ACTION_CREATE_SHARE_VIA_LINK);
  271. service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  272. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  273. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
  274. } else {
  275. Log_OC.e(TAG, "Trying to share a NULL OCFile");
  276. }
  277. } else {
  278. // Show a Message
  279. DisplayUtils.showSnackMessage(mFileActivity, R.string.share_link_no_support_share_api);
  280. }
  281. }
  282. /**
  283. * Helper method to share a file with a known sharee. Starts a request to do it in {@link OperationsService}
  284. *
  285. * @param file The file to share.
  286. * @param shareeName Name (user name or group name) of the target sharee.
  287. * @param shareType The share type determines the sharee type.
  288. * @param permissions Permissions to grant to sharee on the shared file.
  289. */
  290. public void shareFileWithSharee(OCFile file, String shareeName, ShareType shareType, int permissions) {
  291. if (file != null) {
  292. // TODO check capability?
  293. mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
  294. getString(R.string.wait_a_moment));
  295. Intent service = new Intent(mFileActivity, OperationsService.class);
  296. service.setAction(OperationsService.ACTION_CREATE_SHARE_WITH_SHAREE);
  297. service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  298. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  299. service.putExtra(OperationsService.EXTRA_SHARE_WITH, shareeName);
  300. service.putExtra(OperationsService.EXTRA_SHARE_TYPE, shareType);
  301. service.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, permissions);
  302. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
  303. } else {
  304. Log_OC.e(TAG, "Trying to share a NULL OCFile");
  305. }
  306. }
  307. /**
  308. * @return 'True' if the server supports the Share API
  309. */
  310. public boolean isSharedSupported() {
  311. if (mFileActivity.getAccount() != null) {
  312. OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
  313. return (serverVersion != null && serverVersion.isSharedSupported());
  314. }
  315. return false;
  316. }
  317. /**
  318. * Helper method to unshare a file publicly shared via link.
  319. * Starts a request to do it in {@link OperationsService}
  320. *
  321. * @param file The file to unshare.
  322. */
  323. public void unshareFileViaLink(OCFile file) {
  324. // Unshare the file: Create the intent
  325. Intent unshareService = new Intent(mFileActivity, OperationsService.class);
  326. unshareService.setAction(OperationsService.ACTION_UNSHARE);
  327. unshareService.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  328. unshareService.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  329. unshareService.putExtra(OperationsService.EXTRA_SHARE_TYPE, ShareType.PUBLIC_LINK);
  330. unshareService.putExtra(OperationsService.EXTRA_SHARE_WITH, "");
  331. queueShareIntent(unshareService);
  332. }
  333. public void unshareFileWithUserOrGroup(OCFile file, ShareType shareType, String userOrGroup) {
  334. // Unshare the file: Create the intent
  335. Intent unshareService = new Intent(mFileActivity, OperationsService.class);
  336. unshareService.setAction(OperationsService.ACTION_UNSHARE);
  337. unshareService.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  338. unshareService.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  339. unshareService.putExtra(OperationsService.EXTRA_SHARE_TYPE, shareType);
  340. unshareService.putExtra(OperationsService.EXTRA_SHARE_WITH, userOrGroup);
  341. queueShareIntent(unshareService);
  342. }
  343. private void queueShareIntent(Intent shareIntent) {
  344. if (isSharedSupported()) {
  345. // Unshare the file
  346. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().
  347. queueNewOperation(shareIntent);
  348. mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
  349. getString(R.string.wait_a_moment));
  350. } else {
  351. // Show a Message
  352. DisplayUtils.showSnackMessage(mFileActivity, R.string.share_link_no_support_share_api);
  353. }
  354. }
  355. /**
  356. * Show an instance of {@link ShareType} for sharing or unsharing the {@link OCFile} received as parameter.
  357. *
  358. * @param file File to share or unshare.
  359. */
  360. public void showShareFile(OCFile file) {
  361. Intent intent = new Intent(mFileActivity, ShareActivity.class);
  362. intent.putExtra(FileActivity.EXTRA_FILE, file);
  363. intent.putExtra(FileActivity.EXTRA_ACCOUNT, mFileActivity.getAccount());
  364. mFileActivity.startActivity(intent);
  365. }
  366. /**
  367. * Updates a public share on a file to set its password.
  368. * Starts a request to do it in {@link OperationsService}
  369. *
  370. * @param file File which public share will be protected with a password.
  371. * @param password Password to set for the public link; null or empty string to clear
  372. * the current password
  373. */
  374. public void setPasswordToShareViaLink(OCFile file, String password) {
  375. // Set password updating share
  376. Intent updateShareIntent = new Intent(mFileActivity, OperationsService.class);
  377. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE);
  378. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  379. updateShareIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  380. updateShareIntent.putExtra(
  381. OperationsService.EXTRA_SHARE_PASSWORD,
  382. (password == null) ? "" : password
  383. );
  384. queueShareIntent(updateShareIntent);
  385. }
  386. /**
  387. * Updates a public share on a file to set its expiration date.
  388. * Starts a request to do it in {@link OperationsService}
  389. *
  390. * @param file File which public share will be constrained with an expiration date.
  391. * @param expirationTimeInMillis Expiration date to set. A negative value clears the current expiration
  392. * date, leaving the link unrestricted. Zero makes no change.
  393. */
  394. public void setExpirationDateToShareViaLink(OCFile file, long expirationTimeInMillis) {
  395. Intent updateShareIntent = new Intent(mFileActivity, OperationsService.class);
  396. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE);
  397. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  398. updateShareIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  399. updateShareIntent.putExtra(
  400. OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS,
  401. expirationTimeInMillis
  402. );
  403. queueShareIntent(updateShareIntent);
  404. }
  405. /**
  406. * Updates a share on a file to set its access permissions.
  407. * Starts a request to do it in {@link OperationsService}
  408. *
  409. * @param share {@link OCShare} instance which permissions will be updated.
  410. * @param permissions New permissions to set. A value <= 0 makes no update.
  411. */
  412. public void setPermissionsToShare(OCShare share, int permissions) {
  413. Intent updateShareIntent = new Intent(mFileActivity, OperationsService.class);
  414. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE);
  415. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  416. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  417. updateShareIntent.putExtra(
  418. OperationsService.EXTRA_SHARE_PERMISSIONS,
  419. permissions
  420. );
  421. queueShareIntent(updateShareIntent);
  422. }
  423. /**
  424. * Updates a public share on a folder to set its editing permission.
  425. * Starts a request to do it in {@link OperationsService}
  426. *
  427. * @param folder Folder which editing permission of his public share will be modified.
  428. * @param uploadPermission New state of the permission for editing the folder shared via link.
  429. */
  430. public void setUploadPermissionsToShare(OCFile folder, boolean uploadPermission) {
  431. Intent updateShareIntent = new Intent(mFileActivity, OperationsService.class);
  432. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE);
  433. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  434. updateShareIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, folder.getRemotePath());
  435. updateShareIntent.putExtra(
  436. OperationsService.EXTRA_SHARE_PUBLIC_UPLOAD,
  437. uploadPermission
  438. );
  439. queueShareIntent(updateShareIntent);
  440. }
  441. /**
  442. * Updates a public share on a folder to set its hide file listing permission.
  443. * Starts a request to do it in {@link OperationsService}
  444. *
  445. * @param share {@link OCShare} instance which permissions will be updated.
  446. * @param hideFileListing New state of the permission for editing the folder shared via link.
  447. */
  448. public void setHideFileListingPermissionsToShare(OCShare share, boolean hideFileListing) {
  449. Intent updateShareIntent = new Intent(mFileActivity, OperationsService.class);
  450. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE);
  451. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  452. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  453. if (hideFileListing) {
  454. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, OCShare.CREATE_PERMISSION_FLAG);
  455. } else {
  456. OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
  457. if (serverVersion != null && serverVersion.isNotReshareableFederatedSupported()) {
  458. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS,
  459. OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER_AFTER_OC9);
  460. } else {
  461. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS,
  462. OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER_UP_TO_OC9);
  463. }
  464. }
  465. queueShareIntent(updateShareIntent);
  466. }
  467. /**
  468. * @return 'True' if the server supports the Search Users API
  469. */
  470. public boolean isSearchUserSupportedSupported() {
  471. if (mFileActivity.getAccount() != null) {
  472. OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
  473. return (serverVersion != null && serverVersion.isSearchUsersSupported());
  474. }
  475. return false;
  476. }
  477. public void sendDownloadedFile(OCFile file) {
  478. if (file != null) {
  479. Intent sendIntent = new Intent(Intent.ACTION_SEND);
  480. // set MimeType
  481. sendIntent.setType(file.getMimetype());
  482. sendIntent.putExtra(
  483. Intent.EXTRA_STREAM,
  484. file.getExposedFileUri(mFileActivity)
  485. );
  486. sendIntent.putExtra(Intent.ACTION_SEND, true); // Send Action
  487. // Show dialog
  488. final String sendTitle = mFileActivity.getString(R.string.activity_chooser_send_file_title);
  489. mFileActivity.startActivity(Intent.createChooser(sendIntent, sendTitle));
  490. } else {
  491. Log_OC.e(TAG, "Trying to send a NULL OCFile");
  492. }
  493. }
  494. public void syncFiles(Collection<OCFile> files) {
  495. for (OCFile file : files) {
  496. syncFile(file);
  497. }
  498. }
  499. public void sendCachedImage(OCFile file) {
  500. if (file != null) {
  501. Context context = MainApp.getAppContext();
  502. Intent sendIntent = new Intent(Intent.ACTION_SEND);
  503. // set MimeType
  504. sendIntent.setType(file.getMimetype());
  505. sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" +
  506. context.getResources().getString(R.string.image_cache_provider_authority) +
  507. file.getRemotePath()));
  508. sendIntent.putExtra(Intent.ACTION_SEND, true); // Send Action
  509. mFileActivity.startActivity(Intent.createChooser(sendIntent,
  510. context.getString(R.string.actionbar_send_file)));
  511. } else {
  512. Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
  513. }
  514. }
  515. public void setPictureAs(OCFile file) {
  516. if (file != null) {
  517. if (file.isDown()) {
  518. Context context = MainApp.getAppContext();
  519. try {
  520. File externalFile = new File(file.getStoragePath());
  521. Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
  522. Uri sendUri;
  523. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  524. intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  525. sendUri = FileProvider.getUriForFile(context,
  526. context.getResources().getString(R.string.file_provider_authority), externalFile);
  527. } else {
  528. sendUri = Uri.fromFile(externalFile);
  529. }
  530. intent.setDataAndType(sendUri, file.getMimetype());
  531. intent.putExtra("mimeType", file.getMimetype());
  532. mFileActivity.startActivityForResult(Intent.createChooser(intent,
  533. mFileActivity.getString(R.string.set_as)), 200);
  534. } catch (ActivityNotFoundException exception) {
  535. Toast.makeText(context, R.string.picture_set_as_no_app, Toast.LENGTH_LONG).show();
  536. }
  537. }
  538. } else {
  539. Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
  540. }
  541. }
  542. /**
  543. * Request the synchronization of a file or folder with the OC server, including its contents.
  544. *
  545. * @param file The file or folder to synchronize
  546. */
  547. public void syncFile(OCFile file) {
  548. if (!file.isFolder()) {
  549. Intent intent = new Intent(mFileActivity, OperationsService.class);
  550. intent.setAction(OperationsService.ACTION_SYNC_FILE);
  551. intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  552. intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  553. intent.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
  554. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(intent);
  555. mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
  556. getString(R.string.wait_a_moment));
  557. } else {
  558. Intent intent = new Intent(mFileActivity, OperationsService.class);
  559. intent.setAction(OperationsService.ACTION_SYNC_FOLDER);
  560. intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  561. intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  562. mFileActivity.startService(intent);
  563. }
  564. }
  565. public void toggleFavoriteFiles(Collection<OCFile> files, boolean shouldBeFavorite) {
  566. List<OCFile> alreadyRightStateList = new ArrayList<>();
  567. for (OCFile file : files) {
  568. if (file.getIsFavorite() == shouldBeFavorite) {
  569. alreadyRightStateList.add(file);
  570. }
  571. }
  572. files.removeAll(alreadyRightStateList);
  573. for (OCFile file : files) {
  574. toggleFavoriteFile(file, shouldBeFavorite);
  575. }
  576. }
  577. private void toggleFavoriteFile(OCFile file, boolean shouldBeFavorite) {
  578. if (file.getIsFavorite() != shouldBeFavorite) {
  579. EventBus.getDefault().post(new FavoriteEvent(file.getRemotePath(), shouldBeFavorite, file.getRemoteId()));
  580. }
  581. }
  582. public void toggleOfflineFiles(Collection<OCFile> files, boolean isAvailableOffline) {
  583. List<OCFile> alreadyRightStateList = new ArrayList<>();
  584. for (OCFile file : files) {
  585. if (file.isAvailableOffline() == isAvailableOffline) {
  586. alreadyRightStateList.add(file);
  587. }
  588. }
  589. files.removeAll(alreadyRightStateList);
  590. for (OCFile file : files) {
  591. toggleOfflineFile(file, isAvailableOffline);
  592. }
  593. }
  594. public void toggleOfflineFile(OCFile file, boolean isAvailableOffline) {
  595. if (file.isAvailableOffline() != isAvailableOffline) {
  596. file.setAvailableOffline(isAvailableOffline);
  597. mFileActivity.getStorageManager().saveFile(file);
  598. /// register the OCFile instance in the observer service to monitor local updates
  599. Intent observedFileIntent = FileObserverService.makeObservedFileIntent(
  600. mFileActivity,
  601. file,
  602. mFileActivity.getAccount(),
  603. isAvailableOffline);
  604. mFileActivity.startService(observedFileIntent);
  605. /// immediate content synchronization
  606. if (file.isAvailableOffline()) {
  607. syncFile(file);
  608. }
  609. }
  610. }
  611. public void renameFile(OCFile file, String newFilename) {
  612. // RenameFile
  613. Intent service = new Intent(mFileActivity, OperationsService.class);
  614. service.setAction(OperationsService.ACTION_RENAME);
  615. service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  616. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  617. service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
  618. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
  619. mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
  620. }
  621. /**
  622. * Start operations to delete one or several files
  623. *
  624. * @param files Files to delete
  625. * @param onlyLocalCopy When 'true' only local copy of the files is removed; otherwise files are also deleted
  626. * in the server.
  627. */
  628. public void removeFiles(Collection<OCFile> files, boolean onlyLocalCopy) {
  629. for (OCFile file : files) {
  630. // RemoveFile
  631. Intent service = new Intent(mFileActivity, OperationsService.class);
  632. service.setAction(OperationsService.ACTION_REMOVE);
  633. service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  634. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  635. service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
  636. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
  637. }
  638. mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
  639. }
  640. public void createFolder(String remotePath, boolean createFullPath) {
  641. // Create Folder
  642. Intent service = new Intent(mFileActivity, OperationsService.class);
  643. service.setAction(OperationsService.ACTION_CREATE_FOLDER);
  644. service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  645. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
  646. service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
  647. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
  648. mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
  649. }
  650. /**
  651. * Cancel the transference in downloads (files/folders) and file uploads
  652. *
  653. * @param file OCFile
  654. */
  655. public void cancelTransference(OCFile file) {
  656. Account account = mFileActivity.getAccount();
  657. if (file.isFolder()) {
  658. OperationsService.OperationsServiceBinder opsBinder =
  659. mFileActivity.getOperationsServiceBinder();
  660. if (opsBinder != null) {
  661. opsBinder.cancel(account, file);
  662. }
  663. }
  664. // for both files and folders
  665. FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
  666. if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
  667. downloaderBinder.cancel(account, file);
  668. }
  669. FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
  670. if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
  671. uploaderBinder.cancel(account, file);
  672. }
  673. }
  674. /**
  675. * Start operations to move one or several files
  676. *
  677. * @param files Files to move
  678. * @param targetFolder Folder where the files while be moved into
  679. */
  680. public void moveFiles(Collection<OCFile> files, OCFile targetFolder) {
  681. for (OCFile file : files) {
  682. Intent service = new Intent(mFileActivity, OperationsService.class);
  683. service.setAction(OperationsService.ACTION_MOVE_FILE);
  684. service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, targetFolder.getRemotePath());
  685. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  686. service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  687. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
  688. }
  689. mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
  690. }
  691. /**
  692. * Start operations to copy one or several files
  693. *
  694. * @param files Files to copy
  695. * @param targetFolder Folder where the files while be copied into
  696. */
  697. public void copyFiles(Collection<OCFile> files, OCFile targetFolder) {
  698. for (OCFile file : files) {
  699. Intent service = new Intent(mFileActivity, OperationsService.class);
  700. service.setAction(OperationsService.ACTION_COPY_FILE);
  701. service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, targetFolder.getRemotePath());
  702. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  703. service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
  704. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
  705. }
  706. mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
  707. }
  708. public long getOpIdWaitingFor() {
  709. return mWaitingForOpId;
  710. }
  711. public void setOpIdWaitingFor(long waitingForOpId) {
  712. mWaitingForOpId = waitingForOpId;
  713. }
  714. /**
  715. * @return 'True' if the server doesn't need to check forbidden characters
  716. */
  717. public boolean isVersionWithForbiddenCharacters() {
  718. if (mFileActivity.getAccount() != null) {
  719. OwnCloudVersion serverVersion =
  720. AccountUtils.getServerVersion(mFileActivity.getAccount());
  721. return (serverVersion != null && serverVersion.isVersionWithForbiddenCharacters());
  722. }
  723. return false;
  724. }
  725. /**
  726. * Starts a check of the currently stored credentials for the given account.
  727. *
  728. * @param account OC account which credentials will be checked.
  729. */
  730. public void checkCurrentCredentials(Account account) {
  731. Intent service = new Intent(mFileActivity, OperationsService.class);
  732. service.setAction(OperationsService.ACTION_CHECK_CURRENT_CREDENTIALS);
  733. service.putExtra(OperationsService.EXTRA_ACCOUNT, account);
  734. mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
  735. mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_checking_credentials));
  736. }
  737. }