FileOperationsHelper.java 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. /*
  2. * ownCloud Android client application
  3. *
  4. * @author masensio
  5. * @author David A. Velasco
  6. * @author Juan Carlos González Cabrero
  7. * @author Andy Scherzinger
  8. * @author Chris Narkiewicz
  9. * @author TSI-mc
  10. *
  11. * Copyright (C) 2015 ownCloud Inc.
  12. * Copyright (C) 2018 Andy Scherzinger
  13. * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  14. * Copyright (C) 2021 TSI-mc
  15. *
  16. * This program is free software: you can redistribute it and/or modify
  17. * it under the terms of the GNU General Public License version 2,
  18. * as published by the Free Software Foundation.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  27. */
  28. package com.owncloud.android.ui.helpers;
  29. import android.Manifest;
  30. import android.accounts.Account;
  31. import android.app.Activity;
  32. import android.content.ActivityNotFoundException;
  33. import android.content.ComponentName;
  34. import android.content.Context;
  35. import android.content.Intent;
  36. import android.content.pm.PackageManager;
  37. import android.content.pm.ResolveInfo;
  38. import android.net.Uri;
  39. import android.os.Build;
  40. import android.os.Environment;
  41. import android.os.StatFs;
  42. import android.provider.MediaStore;
  43. import android.text.TextUtils;
  44. import android.util.Log;
  45. import android.view.View;
  46. import android.webkit.MimeTypeMap;
  47. import com.nextcloud.client.account.CurrentAccountProvider;
  48. import com.nextcloud.client.account.User;
  49. import com.nextcloud.client.network.ConnectivityService;
  50. import com.nextcloud.java.util.Optional;
  51. import com.owncloud.android.MainApp;
  52. import com.owncloud.android.R;
  53. import com.owncloud.android.datamodel.FileDataStorageManager;
  54. import com.owncloud.android.datamodel.OCFile;
  55. import com.owncloud.android.files.FileMenuFilter;
  56. import com.owncloud.android.files.StreamMediaFileOperation;
  57. import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
  58. import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
  59. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  60. import com.owncloud.android.lib.common.utils.Log_OC;
  61. import com.owncloud.android.lib.resources.files.CheckEtagRemoteOperation;
  62. import com.owncloud.android.lib.resources.files.model.FileVersion;
  63. import com.owncloud.android.lib.resources.shares.OCShare;
  64. import com.owncloud.android.lib.resources.shares.ShareType;
  65. import com.owncloud.android.lib.resources.status.OCCapability;
  66. import com.owncloud.android.operations.SynchronizeFileOperation;
  67. import com.owncloud.android.services.OperationsService;
  68. import com.owncloud.android.ui.activity.ConflictsResolveActivity;
  69. import com.owncloud.android.ui.activity.ExternalSiteWebView;
  70. import com.owncloud.android.ui.activity.FileActivity;
  71. import com.owncloud.android.ui.activity.FileDisplayActivity;
  72. import com.owncloud.android.ui.activity.RichDocumentsEditorWebView;
  73. import com.owncloud.android.ui.activity.ShareActivity;
  74. import com.owncloud.android.ui.activity.TextEditorWebView;
  75. import com.owncloud.android.ui.dialog.SendFilesDialog;
  76. import com.owncloud.android.ui.dialog.SendShareDialog;
  77. import com.owncloud.android.ui.events.EncryptionEvent;
  78. import com.owncloud.android.ui.events.FavoriteEvent;
  79. import com.owncloud.android.ui.events.SyncEventFinished;
  80. import com.owncloud.android.utils.DisplayUtils;
  81. import com.owncloud.android.utils.FileStorageUtils;
  82. import com.owncloud.android.utils.PermissionUtil;
  83. import com.owncloud.android.utils.UriUtils;
  84. import org.greenrobot.eventbus.EventBus;
  85. import java.io.BufferedReader;
  86. import java.io.File;
  87. import java.io.FileInputStream;
  88. import java.io.IOException;
  89. import java.io.InputStreamReader;
  90. import java.nio.charset.Charset;
  91. import java.text.SimpleDateFormat;
  92. import java.util.ArrayList;
  93. import java.util.Arrays;
  94. import java.util.Collection;
  95. import java.util.Date;
  96. import java.util.List;
  97. import java.util.Locale;
  98. import java.util.Set;
  99. import java.util.regex.Matcher;
  100. import java.util.regex.Pattern;
  101. import androidx.annotation.NonNull;
  102. import androidx.annotation.Nullable;
  103. import androidx.core.content.FileProvider;
  104. import androidx.fragment.app.FragmentManager;
  105. import androidx.fragment.app.FragmentTransaction;
  106. /**
  107. * Helper implementation for file operations locally and remote.
  108. */
  109. public class FileOperationsHelper {
  110. private static final String TAG = FileOperationsHelper.class.getSimpleName();
  111. private static final Pattern mPatternUrl = Pattern.compile("^URL=(.+)$");
  112. private static final Pattern mPatternString = Pattern.compile("<string>(.+)</string>");
  113. private static final String FILE_EXTENSION_URL = "url";
  114. private static final String FILE_EXTENSION_DESKTOP = "desktop";
  115. private static final String FILE_EXTENSION_WEBLOC = "webloc";
  116. public static final int SINGLE_LINK_SIZE = 1;
  117. private FileActivity fileActivity;
  118. private CurrentAccountProvider currentAccount;
  119. private ConnectivityService connectivityService;
  120. /// Identifier of operation in progress which result shouldn't be lost
  121. private long mWaitingForOpId = Long.MAX_VALUE;
  122. public FileOperationsHelper(FileActivity fileActivity,
  123. CurrentAccountProvider currentAccount,
  124. ConnectivityService connectivityService) {
  125. this.fileActivity = fileActivity;
  126. this.currentAccount = currentAccount;
  127. this.connectivityService = connectivityService;
  128. }
  129. @Nullable
  130. private String getUrlFromFile(String storagePath, Pattern pattern) {
  131. String url = null;
  132. InputStreamReader fr = null;
  133. BufferedReader br = null;
  134. try {
  135. fr = new InputStreamReader(new FileInputStream(storagePath), Charset.forName("UTF-8"));
  136. br = new BufferedReader(fr);
  137. String line;
  138. while ((line = br.readLine()) != null) {
  139. Matcher m = pattern.matcher(line);
  140. if (m.find()) {
  141. url = m.group(1);
  142. break;
  143. }
  144. }
  145. } catch (IOException e) {
  146. Log_OC.d(TAG, e.getMessage());
  147. } finally {
  148. if (br != null) {
  149. try {
  150. br.close();
  151. } catch (IOException e) {
  152. Log_OC.d(TAG, "Error closing buffered reader for URL file", e);
  153. }
  154. }
  155. if (fr != null) {
  156. try {
  157. fr.close();
  158. } catch (IOException e) {
  159. Log_OC.d(TAG, "Error closing file reader for URL file", e);
  160. }
  161. }
  162. }
  163. return url;
  164. }
  165. @Nullable
  166. private Intent createIntentFromFile(String storagePath) {
  167. String url = null;
  168. int lastIndexOfDot = storagePath.lastIndexOf('.');
  169. if (lastIndexOfDot >= 0) {
  170. String fileExt = storagePath.substring(lastIndexOfDot + 1);
  171. if (FILE_EXTENSION_URL.equalsIgnoreCase(fileExt) || FILE_EXTENSION_DESKTOP.equalsIgnoreCase(fileExt)) {
  172. // Windows internet shortcut file .url
  173. // Ubuntu internet shortcut file .desktop
  174. url = getUrlFromFile(storagePath, mPatternUrl);
  175. } else if (FILE_EXTENSION_WEBLOC.equalsIgnoreCase(fileExt)) {
  176. // mac internet shortcut file .webloc
  177. url = getUrlFromFile(storagePath, mPatternString);
  178. }
  179. }
  180. if (url == null) {
  181. return null;
  182. }
  183. return new Intent(Intent.ACTION_VIEW, Uri.parse(url));
  184. }
  185. public void startSyncForFileAndIntent(OCFile file, Intent intent) {
  186. new Thread(() -> {
  187. User user = fileActivity.getUser().orElseThrow(RuntimeException::new);
  188. FileDataStorageManager storageManager = new FileDataStorageManager(user,
  189. fileActivity.getContentResolver());
  190. // check if file is in conflict (this is known due to latest folder refresh)
  191. if (file.isInConflict()) {
  192. syncFile(file, user, storageManager);
  193. EventBus.getDefault().post(new SyncEventFinished(intent));
  194. return;
  195. }
  196. // check if latest sync is >30s ago
  197. OCFile parent = storageManager.getFileById(file.getParentId());
  198. if (parent != null && parent.getLastSyncDateForData() + 30 * 1000 > System.currentTimeMillis()) {
  199. EventBus.getDefault().post(new SyncEventFinished(intent));
  200. return;
  201. }
  202. // if offline or walled garden, show old version with warning
  203. if (!connectivityService.getConnectivity().isConnected() || connectivityService.isInternetWalled()) {
  204. DisplayUtils.showSnackMessage(fileActivity, R.string.file_not_synced);
  205. EventBus.getDefault().post(new SyncEventFinished(intent));
  206. return;
  207. }
  208. // check for changed eTag
  209. CheckEtagRemoteOperation checkEtagOperation = new CheckEtagRemoteOperation(file.getRemotePath(),
  210. file.getEtag());
  211. RemoteOperationResult result = checkEtagOperation.execute(user.toPlatformAccount(), fileActivity);
  212. // eTag changed, sync file
  213. if (result.getCode() == RemoteOperationResult.ResultCode.ETAG_CHANGED) {
  214. syncFile(file, user, storageManager);
  215. }
  216. EventBus.getDefault().post(new SyncEventFinished(intent));
  217. }).start();
  218. }
  219. private void syncFile(OCFile file, User user, FileDataStorageManager storageManager) {
  220. fileActivity.runOnUiThread(() -> fileActivity.showLoadingDialog(fileActivity.getResources()
  221. .getString(R.string.sync_in_progress)));
  222. SynchronizeFileOperation sfo = new SynchronizeFileOperation(file,
  223. null,
  224. user,
  225. true,
  226. fileActivity,
  227. storageManager);
  228. RemoteOperationResult result = sfo.execute(fileActivity);
  229. if (result.getCode() == RemoteOperationResult.ResultCode.SYNC_CONFLICT) {
  230. // ISSUE 5: if the user is not running the app (this is a service!),
  231. // this can be very intrusive; a notification should be preferred
  232. Intent intent = ConflictsResolveActivity.createIntent(file,
  233. user.toPlatformAccount(),
  234. -1,
  235. Intent.FLAG_ACTIVITY_NEW_TASK,
  236. fileActivity);
  237. fileActivity.startActivity(intent);
  238. } else {
  239. if (file.isDown()) {
  240. FileStorageUtils.checkIfFileFinishedSaving(file);
  241. if (!result.isSuccess()) {
  242. DisplayUtils.showSnackMessage(fileActivity, R.string.file_not_synced);
  243. try {
  244. Thread.sleep(3000);
  245. } catch (InterruptedException e) {
  246. Log.e(TAG, "Failed to sleep for a bit");
  247. }
  248. }
  249. }
  250. }
  251. fileActivity.dismissLoadingDialog();
  252. }
  253. public void openFile(OCFile file) {
  254. if (file != null) {
  255. final Intent openFileWithIntent = createOpenFileIntent(file);
  256. List<ResolveInfo> launchables = fileActivity.getPackageManager().
  257. queryIntentActivities(openFileWithIntent, PackageManager.GET_RESOLVED_FILTER);
  258. if (launchables.isEmpty()) {
  259. Optional<User> optionalUser = fileActivity.getUser();
  260. if (optionalUser.isPresent() && FileMenuFilter.isEditorAvailable(fileActivity.getContentResolver(),
  261. optionalUser.get(),
  262. file.getMimeType())) {
  263. openFileWithTextEditor(file, fileActivity);
  264. } else {
  265. Account account = fileActivity.getAccount();
  266. OCCapability capability = fileActivity.getStorageManager().getCapability(account.name);
  267. if (capability.getRichDocumentsMimeTypeList().contains(file.getMimeType()) &&
  268. capability.getRichDocumentsDirectEditing().isTrue()) {
  269. openFileAsRichDocument(file, fileActivity);
  270. return;
  271. } else {
  272. DisplayUtils.showSnackMessage(fileActivity, R.string.file_list_no_app_for_file_type);
  273. return;
  274. }
  275. }
  276. }
  277. fileActivity.showLoadingDialog(fileActivity.getResources().getString(R.string.sync_in_progress));
  278. new Thread(new Runnable() {
  279. @Override
  280. public void run() {
  281. User user = currentAccount.getUser();
  282. FileDataStorageManager storageManager =
  283. new FileDataStorageManager(user, fileActivity.getContentResolver());
  284. // a fresh object is needed; many things could have occurred to the file
  285. // since it was registered to observe again, assuming that local files
  286. // are linked to a remote file AT MOST, SOMETHING TO BE DONE;
  287. SynchronizeFileOperation sfo = new SynchronizeFileOperation(file,
  288. null,
  289. user,
  290. true,
  291. fileActivity,
  292. storageManager);
  293. RemoteOperationResult result = sfo.execute(fileActivity);
  294. fileActivity.dismissLoadingDialog();
  295. if (result.getCode() == RemoteOperationResult.ResultCode.SYNC_CONFLICT) {
  296. // ISSUE 5: if the user is not running the app (this is a service!),
  297. // this can be very intrusive; a notification should be preferred
  298. Intent intent = ConflictsResolveActivity.createIntent(file,
  299. user.toPlatformAccount(),
  300. -1,
  301. Intent.FLAG_ACTIVITY_NEW_TASK,
  302. fileActivity);
  303. fileActivity.startActivity(intent);
  304. } else {
  305. if (!launchables.isEmpty()) {
  306. try {
  307. if (!result.isSuccess()) {
  308. DisplayUtils.showSnackMessage(fileActivity, R.string.file_not_synced);
  309. try {
  310. Thread.sleep(3000);
  311. } catch (InterruptedException e) {
  312. Log.e(TAG, "Failed to sleep");
  313. }
  314. }
  315. openFileWithIntent.setFlags(openFileWithIntent.getFlags() |
  316. Intent.FLAG_ACTIVITY_NEW_TASK);
  317. fileActivity.startActivity(openFileWithIntent);
  318. } catch (ActivityNotFoundException exception) {
  319. DisplayUtils.showSnackMessage(fileActivity, R.string.file_list_no_app_for_file_type);
  320. }
  321. } else {
  322. DisplayUtils.showSnackMessage(fileActivity, R.string.file_list_no_app_for_file_type);
  323. }
  324. }
  325. }
  326. }).start();
  327. } else {
  328. Log_OC.e(TAG, "Trying to open a NULL OCFile");
  329. }
  330. }
  331. public void openFileAsRichDocument(OCFile file, Context context) {
  332. Intent collaboraWebViewIntent = new Intent(context, RichDocumentsEditorWebView.class);
  333. collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, "Collabora");
  334. collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_FILE, file);
  335. collaboraWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
  336. context.startActivity(collaboraWebViewIntent);
  337. }
  338. public void openFileWithTextEditor(OCFile file, Context context) {
  339. Intent textEditorIntent = new Intent(context, TextEditorWebView.class);
  340. textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, "Text");
  341. textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_FILE, file);
  342. textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
  343. context.startActivity(textEditorIntent);
  344. }
  345. public void openRichWorkspaceWithTextEditor(OCFile file, String url, Context context) {
  346. Intent textEditorIntent = new Intent(context, TextEditorWebView.class);
  347. textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, "Text");
  348. textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_URL, url);
  349. textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_FILE, file);
  350. textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false);
  351. context.startActivity(textEditorIntent);
  352. }
  353. @NonNull
  354. private Intent createOpenFileIntent(OCFile file) {
  355. String storagePath = file.getStoragePath();
  356. Uri fileUri = getFileUri(file, MainApp.getAppContext().getResources().getStringArray(R.array
  357. .ms_office_extensions));
  358. Intent openFileWithIntent = null;
  359. int lastIndexOfDot = storagePath.lastIndexOf('.');
  360. if (lastIndexOfDot >= 0) {
  361. String fileExt = storagePath.substring(lastIndexOfDot + 1);
  362. String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExt);
  363. if (guessedMimeType != null) {
  364. openFileWithIntent = new Intent(Intent.ACTION_VIEW);
  365. openFileWithIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
  366. openFileWithIntent.setDataAndType(
  367. fileUri,
  368. guessedMimeType
  369. );
  370. }
  371. }
  372. if (openFileWithIntent == null) {
  373. openFileWithIntent = createIntentFromFile(storagePath);
  374. }
  375. if (openFileWithIntent == null) {
  376. openFileWithIntent = new Intent(Intent.ACTION_VIEW);
  377. openFileWithIntent.setDataAndType(
  378. fileUri,
  379. file.getMimeType()
  380. );
  381. }
  382. openFileWithIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
  383. return openFileWithIntent;
  384. }
  385. private Uri getFileUri(OCFile file, String... officeExtensions) {
  386. if (file.getFileName().contains(".") &&
  387. Arrays.asList(officeExtensions).contains(file.getFileName().substring(file.getFileName().
  388. lastIndexOf(".") + 1)) &&
  389. !file.getStoragePath().startsWith(MainApp.getAppContext().getFilesDir().getAbsolutePath())) {
  390. return file.getLegacyExposedFileUri();
  391. } else {
  392. return file.getExposedFileUri(fileActivity);
  393. }
  394. }
  395. public void streamMediaFile(OCFile file) {
  396. fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
  397. final User user = currentAccount.getUser();
  398. new Thread(() -> {
  399. StreamMediaFileOperation sfo = new StreamMediaFileOperation(file.getLocalId());
  400. RemoteOperationResult result = sfo.execute(user.toPlatformAccount(), fileActivity);
  401. fileActivity.dismissLoadingDialog();
  402. if (!result.isSuccess()) {
  403. DisplayUtils.showSnackMessage(fileActivity, R.string.stream_not_possible_headline);
  404. return;
  405. }
  406. Intent openFileWithIntent = new Intent(Intent.ACTION_VIEW);
  407. Uri uri = Uri.parse((String) result.getData().get(0));
  408. openFileWithIntent.setDataAndType(uri, file.getMimeType());
  409. fileActivity.startActivity(Intent.createChooser(openFileWithIntent,
  410. fileActivity.getString(R.string.stream)));
  411. }).start();
  412. }
  413. /**
  414. * Helper method to share a file via a public link. Starts a request to do it in {@link OperationsService}
  415. *
  416. * @param file The file to share.
  417. * @param password Optional password to protect the public share.
  418. */
  419. public void shareFileViaPublicShare(OCFile file, String password) {
  420. if (file != null) {
  421. fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
  422. Intent service = new Intent(fileActivity, OperationsService.class);
  423. service.setAction(OperationsService.ACTION_CREATE_SHARE_VIA_LINK);
  424. service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  425. if (!TextUtils.isEmpty(password)) {
  426. service.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, password);
  427. }
  428. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  429. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
  430. } else {
  431. Log_OC.e(TAG, "Trying to share a NULL OCFile");
  432. // TODO user-level error?
  433. }
  434. }
  435. public void getFileWithLink(@NonNull OCFile file) {
  436. List<OCShare> shares = fileActivity.getStorageManager().getSharesByPathAndType(file.getRemotePath(),
  437. ShareType.PUBLIC_LINK,
  438. "");
  439. if (shares.size() == SINGLE_LINK_SIZE) {
  440. FileActivity.copyAndShareFileLink(fileActivity, file, shares.get(0).getShareLink());
  441. } else {
  442. if (fileActivity instanceof FileDisplayActivity) {
  443. ((FileDisplayActivity) fileActivity).showDetails(file, 1);
  444. } else {
  445. showShareFile(file);
  446. }
  447. }
  448. }
  449. /**
  450. * Helper method to share a file with a known sharee. Starts a request to do it in {@link OperationsService}
  451. *
  452. * @param file The file to share.
  453. * @param shareeName Name (user name or group name) of the target sharee.
  454. * @param shareType The share type determines the sharee type.
  455. * @param permissions Permissions to grant to sharee on the shared file.
  456. */
  457. public void shareFileWithSharee(OCFile file, String shareeName, ShareType shareType, int permissions) {
  458. if (file != null) {
  459. // TODO check capability?
  460. fileActivity.showLoadingDialog(fileActivity.getApplicationContext().
  461. getString(R.string.wait_a_moment));
  462. Intent service = new Intent(fileActivity, OperationsService.class);
  463. service.setAction(OperationsService.ACTION_CREATE_SHARE_WITH_SHAREE);
  464. service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  465. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  466. service.putExtra(OperationsService.EXTRA_SHARE_WITH, shareeName);
  467. service.putExtra(OperationsService.EXTRA_SHARE_TYPE, shareType);
  468. service.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, permissions);
  469. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
  470. } else {
  471. Log_OC.e(TAG, "Trying to share a NULL OCFile");
  472. }
  473. }
  474. /**
  475. * Helper method to share a file with a known sharee. Starts a request to do it in {@link OperationsService}
  476. *
  477. * @param file The file to share.
  478. * @param shareeName Name (user name or group name) of the target sharee.
  479. * @param shareType The share type determines the sharee type.
  480. * @param permissions Permissions to grant to sharee on the shared file.
  481. * @param hideFileDownload true/false to hide file download
  482. * @param password Password to set for the public link; null or empty string to clear the current
  483. * password
  484. * @param expirationTimeInMillis Expiration date to set. A negative value clears the current expiration date,
  485. * leaving the link unrestricted. Zero makes no change.
  486. * @param note note message for the receiver. Null or empty for no message
  487. * @param label new label
  488. */
  489. public void shareFileWithSharee(OCFile file, String shareeName, ShareType shareType, int permissions,
  490. boolean hideFileDownload, String password, long expirationTimeInMillis,
  491. String note, String label) {
  492. if (file != null) {
  493. // TODO check capability?
  494. fileActivity.showLoadingDialog(fileActivity.getApplicationContext().
  495. getString(R.string.wait_a_moment));
  496. Intent service = new Intent(fileActivity, OperationsService.class);
  497. service.setAction(OperationsService.ACTION_CREATE_SHARE_WITH_SHAREE);
  498. service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  499. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  500. service.putExtra(OperationsService.EXTRA_SHARE_WITH, shareeName);
  501. service.putExtra(OperationsService.EXTRA_SHARE_TYPE, shareType);
  502. service.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, permissions);
  503. service.putExtra(OperationsService.EXTRA_SHARE_HIDE_FILE_DOWNLOAD, hideFileDownload);
  504. service.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, (password == null) ? "" : password);
  505. service.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis);
  506. service.putExtra(OperationsService.EXTRA_SHARE_NOTE, note);
  507. service.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_LABEL, (label == null) ? "" : label);
  508. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
  509. } else {
  510. Log_OC.e(TAG, "Trying to share a NULL OCFile");
  511. }
  512. }
  513. /**
  514. * Helper method to revert to a file version. Starts a request to do it in {@link OperationsService}
  515. *
  516. * @param fileVersion The file version to restore
  517. */
  518. public void restoreFileVersion(FileVersion fileVersion) {
  519. if (fileVersion != null) {
  520. fileActivity.showLoadingDialog(fileActivity.getApplicationContext().
  521. getString(R.string.wait_a_moment));
  522. Intent service = new Intent(fileActivity, OperationsService.class);
  523. service.setAction(OperationsService.ACTION_RESTORE_VERSION);
  524. service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  525. service.putExtra(OperationsService.EXTRA_FILE_VERSION, fileVersion);
  526. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
  527. } else {
  528. Log_OC.e(TAG, "Trying to restore a NULL FileVersion");
  529. }
  530. }
  531. /**
  532. * Helper method to unshare a file publicly shared via link. Starts a request to do it in {@link OperationsService}
  533. *
  534. * @param file The file to unshare.
  535. */
  536. public void unshareShare(OCFile file, OCShare share) {
  537. // Unshare the file: Create the intent
  538. Intent unshareService = new Intent(fileActivity, OperationsService.class);
  539. unshareService.setAction(OperationsService.ACTION_UNSHARE);
  540. unshareService.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  541. unshareService.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  542. unshareService.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  543. queueShareIntent(unshareService);
  544. }
  545. private void queueShareIntent(Intent shareIntent) {
  546. // Unshare the file
  547. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(shareIntent);
  548. fileActivity.showLoadingDialog(fileActivity.getApplicationContext().getString(R.string.wait_a_moment));
  549. }
  550. /**
  551. * Show an instance of {@link ShareType} for sharing or unsharing the {@link OCFile} received as parameter.
  552. *
  553. * @param file File to share or unshare.
  554. */
  555. public void showShareFile(OCFile file) {
  556. Intent intent = new Intent(fileActivity, ShareActivity.class);
  557. intent.putExtra(FileActivity.EXTRA_FILE, file);
  558. intent.putExtra(FileActivity.EXTRA_ACCOUNT, fileActivity.getAccount());
  559. fileActivity.startActivity(intent);
  560. }
  561. /**
  562. * Updates a public share on a file to set its label. Starts a request to do it in {@link OperationsService}
  563. *
  564. * @param label new label
  565. */
  566. public void setLabelToPublicShare(OCShare share, String label) {
  567. // Set password updating share
  568. Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
  569. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_PUBLIC_SHARE);
  570. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  571. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  572. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_LABEL, (label == null) ? "" : label);
  573. queueShareIntent(updateShareIntent);
  574. }
  575. /**
  576. * Updates a share on a file to set its password.
  577. * Starts a request to do it in {@link OperationsService}
  578. *
  579. * @param share File which share will be protected with a password.
  580. * @param password Password to set for the public link; null or empty string to clear
  581. * the current password
  582. */
  583. public void setPasswordToShare(OCShare share, String password) {
  584. Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
  585. if (TextUtils.isEmpty(share.getShareLink())) {
  586. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_USER_SHARE);
  587. } else {
  588. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_PUBLIC_SHARE);
  589. }
  590. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  591. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  592. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, (password == null) ? "" : password);
  593. queueShareIntent(updateShareIntent);
  594. }
  595. /**
  596. * Updates a public share on a file to set its expiration date.
  597. * Starts a request to do it in {@link OperationsService}
  598. *
  599. * @param share {@link OCShare} instance which permissions will be updated.
  600. * @param expirationTimeInMillis Expiration date to set. A negative value clears the current expiration
  601. * date, leaving the link unrestricted. Zero makes no change.
  602. */
  603. public void setExpirationDateToShare(OCShare share, long expirationTimeInMillis) {
  604. Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
  605. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_USER_SHARE);
  606. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  607. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  608. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis);
  609. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, 0);
  610. queueShareIntent(updateShareIntent);
  611. }
  612. /**
  613. * Updates a share on a file to set its access permissions.
  614. * Starts a request to do it in {@link OperationsService}
  615. *
  616. * @param share {@link OCShare} instance which permissions will be updated.
  617. * @param permissions New permissions to set. A value <= 0 makes no update.
  618. */
  619. public void setPermissionsToShare(OCShare share, int permissions) {
  620. Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
  621. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_USER_SHARE);
  622. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  623. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  624. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, permissions);
  625. queueShareIntent(updateShareIntent);
  626. }
  627. /**
  628. * Updates a public share on a folder to set its editing permission. Starts a request to do it in {@link
  629. * OperationsService}
  630. *
  631. * @param share {@link OCShare} instance which permissions will be updated.
  632. * @param uploadPermission New state of the permission for editing the folder shared via link.
  633. */
  634. public void setUploadPermissionsToPublicShare(OCShare share, boolean uploadPermission) {
  635. Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
  636. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_USER_SHARE);
  637. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  638. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  639. if (uploadPermission) {
  640. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, 3);
  641. } else {
  642. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, 1);
  643. }
  644. queueShareIntent(updateShareIntent);
  645. }
  646. public void setHideFileDownloadPermissionsToPublicShare(OCShare share, boolean hideFileDownload) {
  647. Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
  648. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_PUBLIC_SHARE);
  649. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  650. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  651. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_HIDE_FILE_DOWNLOAD, hideFileDownload);
  652. queueShareIntent(updateShareIntent);
  653. }
  654. public void updateNoteToShare(OCShare share, String note) {
  655. Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
  656. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE_NOTE);
  657. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  658. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  659. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_NOTE, note);
  660. queueShareIntent(updateShareIntent);
  661. }
  662. /**
  663. * Helper method to update the share information
  664. *
  665. * @param share {@link OCShare} instance which information will be updated.
  666. * @param permissions Permissions to grant to sharee on the shared file.
  667. * @param hideFileDownload true/false to hide file download
  668. * @param password Password to set for the public link; null or empty string to clear the current
  669. * password
  670. * @param expirationTimeInMillis Expiration date to set. A negative value clears the current expiration date,
  671. * leaving the link unrestricted. Zero makes no change.
  672. * @param label new label
  673. */
  674. public void updateShareInformation(OCShare share, int permissions,
  675. boolean hideFileDownload, String password, long expirationTimeInMillis,
  676. String label) {
  677. Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
  678. updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE_INFO);
  679. updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  680. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
  681. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, permissions);
  682. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_HIDE_FILE_DOWNLOAD, hideFileDownload);
  683. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, (password == null) ? "" : password);
  684. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis);
  685. updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_LABEL, (label == null) ? "" : label);
  686. queueShareIntent(updateShareIntent);
  687. }
  688. public void sendShareFile(OCFile file, boolean hideNcSharingOptions) {
  689. // Show dialog
  690. FragmentManager fm = fileActivity.getSupportFragmentManager();
  691. FragmentTransaction ft = fm.beginTransaction();
  692. ft.addToBackStack(null);
  693. OCCapability capability = fileActivity.getStorageManager().getCapability(fileActivity.getAccount().name);
  694. SendShareDialog mSendShareDialog = SendShareDialog.newInstance(file, hideNcSharingOptions, capability);
  695. mSendShareDialog.setFileOperationsHelper(this);
  696. mSendShareDialog.show(ft, "TAG_SEND_SHARE_DIALOG");
  697. }
  698. public void sendFiles(Set<OCFile> files) {
  699. // Show dialog
  700. FragmentManager fm = fileActivity.getSupportFragmentManager();
  701. FragmentTransaction ft = fm.beginTransaction();
  702. ft.addToBackStack(null);
  703. SendFilesDialog sendFilesDialog = SendFilesDialog.newInstance(files);
  704. sendFilesDialog.show(ft, "TAG_SEND_SHARE_DIALOG");
  705. }
  706. public void sendShareFile(OCFile file) {
  707. sendShareFile(file, !file.canReshare());
  708. }
  709. public void sendCachedImage(OCFile file, String packageName, String activityName) {
  710. if (file != null) {
  711. Context context = MainApp.getAppContext();
  712. Intent sendIntent = new Intent(Intent.ACTION_SEND);
  713. // set MimeType
  714. sendIntent.setType(file.getMimeType());
  715. sendIntent.setComponent(new ComponentName(packageName, activityName));
  716. sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" +
  717. context.getResources().getString(R.string.image_cache_provider_authority) +
  718. file.getRemotePath()));
  719. sendIntent.putExtra(Intent.ACTION_SEND, true); // Send Action
  720. sendIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  721. fileActivity.startActivity(Intent.createChooser(sendIntent,
  722. context.getString(R.string.actionbar_send_file)));
  723. } else {
  724. Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
  725. }
  726. }
  727. public void setPictureAs(OCFile file, View view) {
  728. if (file != null) {
  729. Context context = MainApp.getAppContext();
  730. Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
  731. Uri uri;
  732. try {
  733. if (file.isDown()) {
  734. File externalFile = new File(file.getStoragePath());
  735. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  736. intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  737. uri = FileProvider.getUriForFile(context,
  738. context.getResources().getString(R.string.file_provider_authority), externalFile);
  739. } else {
  740. uri = Uri.fromFile(externalFile);
  741. }
  742. } else {
  743. uri = Uri.parse(UriUtils.URI_CONTENT_SCHEME +
  744. context.getResources().getString(R.string.image_cache_provider_authority) +
  745. file.getRemotePath());
  746. }
  747. intent.setDataAndType(uri, file.getMimeType());
  748. intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  749. fileActivity.startActivityForResult(Intent.createChooser(intent,
  750. fileActivity.getString(R.string.set_as)),
  751. 200);
  752. intent.setDataAndType(uri, file.getMimeType());
  753. } catch (ActivityNotFoundException exception) {
  754. DisplayUtils.showSnackMessage(view, R.string.picture_set_as_no_app);
  755. }
  756. } else {
  757. Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
  758. }
  759. }
  760. /**
  761. * Request the synchronization of a file or folder with the OC server, including its contents.
  762. *
  763. * @param file The file or folder to synchronize
  764. */
  765. public void syncFile(OCFile file) {
  766. if (!file.isFolder()) {
  767. Intent intent = new Intent(fileActivity, OperationsService.class);
  768. intent.setAction(OperationsService.ACTION_SYNC_FILE);
  769. intent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  770. intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  771. intent.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
  772. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(intent);
  773. fileActivity.showLoadingDialog(fileActivity.getApplicationContext().
  774. getString(R.string.wait_a_moment));
  775. } else {
  776. Intent intent = new Intent(fileActivity, OperationsService.class);
  777. intent.setAction(OperationsService.ACTION_SYNC_FOLDER);
  778. intent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  779. intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  780. fileActivity.startService(intent);
  781. }
  782. }
  783. public void toggleFavoriteFiles(Collection<OCFile> files, boolean shouldBeFavorite) {
  784. List<OCFile> alreadyRightStateList = new ArrayList<>();
  785. for (OCFile file : files) {
  786. if (file.isFavorite() == shouldBeFavorite) {
  787. alreadyRightStateList.add(file);
  788. }
  789. }
  790. files.removeAll(alreadyRightStateList);
  791. for (OCFile file : files) {
  792. toggleFavoriteFile(file, shouldBeFavorite);
  793. }
  794. }
  795. public void toggleFavoriteFile(OCFile file, boolean shouldBeFavorite) {
  796. if (file.isFavorite() != shouldBeFavorite) {
  797. EventBus.getDefault().post(new FavoriteEvent(file.getRemotePath(), shouldBeFavorite, file.getRemoteId()));
  798. }
  799. }
  800. public void toggleEncryption(OCFile file, boolean shouldBeEncrypted) {
  801. if (file.isEncrypted() != shouldBeEncrypted) {
  802. EventBus.getDefault().post(new EncryptionEvent(file.getLocalId(),
  803. file.getRemoteId(),
  804. file.getRemotePath(),
  805. shouldBeEncrypted));
  806. }
  807. }
  808. public void renameFile(OCFile file, String newFilename) {
  809. // RenameFile
  810. Intent service = new Intent(fileActivity, OperationsService.class);
  811. service.setAction(OperationsService.ACTION_RENAME);
  812. service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  813. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  814. service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
  815. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
  816. fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
  817. }
  818. /**
  819. * Start operations to delete one or several files
  820. *
  821. * @param files Files to delete
  822. * @param onlyLocalCopy When 'true' only local copy of the files is removed; otherwise files are also deleted
  823. * in the server.
  824. * @param inBackground When 'true', do not show any loading dialog
  825. */
  826. public void removeFiles(Collection<OCFile> files, boolean onlyLocalCopy, boolean inBackground) {
  827. for (OCFile file : files) {
  828. // RemoveFile
  829. Intent service = new Intent(fileActivity, OperationsService.class);
  830. service.setAction(OperationsService.ACTION_REMOVE);
  831. service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  832. service.putExtra(OperationsService.EXTRA_FILE, file);
  833. service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
  834. service.putExtra(OperationsService.EXTRA_IN_BACKGROUND, inBackground);
  835. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
  836. }
  837. if (!inBackground) {
  838. fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
  839. }
  840. }
  841. public void createFolder(String remotePath) {
  842. // Create Folder
  843. Intent service = new Intent(fileActivity, OperationsService.class);
  844. service.setAction(OperationsService.ACTION_CREATE_FOLDER);
  845. service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  846. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
  847. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
  848. fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
  849. }
  850. /**
  851. * Cancel the transference in downloads (files/folders) and file uploads
  852. *
  853. * @param file OCFile
  854. */
  855. public void cancelTransference(OCFile file) {
  856. User currentUser = fileActivity.getUser().orElseThrow(IllegalStateException::new);
  857. if (file.isFolder()) {
  858. OperationsService.OperationsServiceBinder opsBinder =
  859. fileActivity.getOperationsServiceBinder();
  860. if (opsBinder != null) {
  861. opsBinder.cancel(currentUser.toPlatformAccount(), file);
  862. }
  863. }
  864. // for both files and folders
  865. FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder();
  866. if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) {
  867. downloaderBinder.cancel(currentUser.toPlatformAccount(), file);
  868. }
  869. FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder();
  870. if (uploaderBinder != null && uploaderBinder.isUploading(currentUser, file)) {
  871. uploaderBinder.cancel(currentUser.toPlatformAccount(), file);
  872. }
  873. }
  874. /**
  875. * Start operations to move one or several files
  876. *
  877. * @param files Files to move
  878. * @param targetFolder Folder where the files while be moved into
  879. */
  880. public void moveFiles(Collection<OCFile> files, OCFile targetFolder) {
  881. for (OCFile file : files) {
  882. Intent service = new Intent(fileActivity, OperationsService.class);
  883. service.setAction(OperationsService.ACTION_MOVE_FILE);
  884. service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, targetFolder.getRemotePath());
  885. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  886. service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  887. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
  888. }
  889. fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
  890. }
  891. /**
  892. * Start operations to copy one or several files
  893. *
  894. * @param files Files to copy
  895. * @param targetFolder Folder where the files while be copied into
  896. */
  897. public void copyFiles(Collection<OCFile> files, OCFile targetFolder) {
  898. for (OCFile file : files) {
  899. Intent service = new Intent(fileActivity, OperationsService.class);
  900. service.setAction(OperationsService.ACTION_COPY_FILE);
  901. service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, targetFolder.getRemotePath());
  902. service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
  903. service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
  904. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
  905. }
  906. fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
  907. }
  908. public long getOpIdWaitingFor() {
  909. return mWaitingForOpId;
  910. }
  911. public void setOpIdWaitingFor(long waitingForOpId) {
  912. mWaitingForOpId = waitingForOpId;
  913. }
  914. /**
  915. * Starts a check of the currently stored credentials for the given account.
  916. *
  917. * @param account OC account which credentials will be checked.
  918. */
  919. public void checkCurrentCredentials(Account account) {
  920. Intent service = new Intent(fileActivity, OperationsService.class);
  921. service.setAction(OperationsService.ACTION_CHECK_CURRENT_CREDENTIALS);
  922. service.putExtra(OperationsService.EXTRA_ACCOUNT, account);
  923. mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
  924. fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_checking_credentials));
  925. }
  926. public void uploadFromCamera(Activity activity, int requestCode) {
  927. Intent pictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  928. File photoFile = createImageFile(activity);
  929. Uri photoUri = FileProvider.getUriForFile(activity.getApplicationContext(),
  930. activity.getResources().getString(R.string.file_provider_authority), photoFile);
  931. pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
  932. if (pictureIntent.resolveActivity(activity.getPackageManager()) != null) {
  933. if (PermissionUtil.checkSelfPermission(activity, Manifest.permission.CAMERA)) {
  934. activity.startActivityForResult(pictureIntent, requestCode);
  935. } else {
  936. PermissionUtil.requestCameraPermission(activity);
  937. }
  938. } else {
  939. DisplayUtils.showSnackMessage(activity, "No Camera found");
  940. }
  941. }
  942. public static File createImageFile(Activity activity) {
  943. File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
  944. return new File(storageDir + "/directCameraUpload.jpg");
  945. }
  946. public static String getCapturedImageName() {
  947. return new SimpleDateFormat("yyyy-MM-dd_HHmmss", Locale.US).format(new Date()) + ".jpg";
  948. }
  949. /**
  950. * @return -1 if no space could computed, otherwise available space in bytes
  951. */
  952. public static Long getAvailableSpaceOnDevice() {
  953. StatFs stat;
  954. try {
  955. stat = new StatFs(MainApp.getStoragePath());
  956. } catch (NullPointerException | IllegalArgumentException e) {
  957. return -1L;
  958. }
  959. return stat.getBlockSizeLong() * stat.getAvailableBlocksLong();
  960. }
  961. }