FileActivity.java 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. /*
  2. * ownCloud Android client application
  3. *
  4. * @author David A. Velasco
  5. * @author Chris Narkiewicz
  6. * Copyright (C) 2011 Bartek Przybylski
  7. * Copyright (C) 2016 ownCloud Inc.
  8. * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2,
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. package com.owncloud.android.ui.activity;
  24. import android.accounts.Account;
  25. import android.accounts.AccountManager;
  26. import android.accounts.AuthenticatorException;
  27. import android.app.Activity;
  28. import android.content.ComponentName;
  29. import android.content.Context;
  30. import android.content.Intent;
  31. import android.content.ServiceConnection;
  32. import android.content.pm.PackageManager;
  33. import android.net.Uri;
  34. import android.os.Bundle;
  35. import android.os.Handler;
  36. import android.os.IBinder;
  37. import android.view.View;
  38. import com.google.android.material.snackbar.Snackbar;
  39. import com.nextcloud.client.account.UserAccountManager;
  40. import com.nextcloud.client.network.ConnectivityService;
  41. import com.owncloud.android.MainApp;
  42. import com.owncloud.android.R;
  43. import com.owncloud.android.authentication.AuthenticatorActivity;
  44. import com.owncloud.android.datamodel.ArbitraryDataProvider;
  45. import com.owncloud.android.datamodel.OCFile;
  46. import com.owncloud.android.files.services.FileDownloader;
  47. import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
  48. import com.owncloud.android.files.services.FileUploader;
  49. import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
  50. import com.owncloud.android.lib.common.OwnCloudAccount;
  51. import com.owncloud.android.lib.common.OwnCloudClient;
  52. import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
  53. import com.owncloud.android.lib.common.OwnCloudCredentials;
  54. import com.owncloud.android.lib.common.network.CertificateCombinedException;
  55. import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
  56. import com.owncloud.android.lib.common.operations.RemoteOperation;
  57. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  58. import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
  59. import com.owncloud.android.lib.common.utils.Log_OC;
  60. import com.owncloud.android.operations.CreateShareWithShareeOperation;
  61. import com.owncloud.android.operations.GetSharesForFileOperation;
  62. import com.owncloud.android.operations.SynchronizeFileOperation;
  63. import com.owncloud.android.operations.SynchronizeFolderOperation;
  64. import com.owncloud.android.operations.UnshareOperation;
  65. import com.owncloud.android.operations.UpdateSharePermissionsOperation;
  66. import com.owncloud.android.operations.UpdateShareViaLinkOperation;
  67. import com.owncloud.android.services.OperationsService;
  68. import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
  69. import com.owncloud.android.ui.asynctasks.CheckRemoteWipeTask;
  70. import com.owncloud.android.ui.asynctasks.LoadingVersionNumberTask;
  71. import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
  72. import com.owncloud.android.ui.dialog.LoadingDialog;
  73. import com.owncloud.android.ui.dialog.ShareLinkToDialog;
  74. import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
  75. import com.owncloud.android.ui.helpers.FileOperationsHelper;
  76. import com.owncloud.android.utils.ClipboardUtil;
  77. import com.owncloud.android.utils.DisplayUtils;
  78. import com.owncloud.android.utils.ErrorMessageAdapter;
  79. import com.owncloud.android.utils.FilesSyncHelper;
  80. import com.owncloud.android.utils.ThemeUtils;
  81. import java.lang.ref.WeakReference;
  82. import javax.inject.Inject;
  83. import androidx.annotation.NonNull;
  84. import androidx.fragment.app.DialogFragment;
  85. import androidx.fragment.app.Fragment;
  86. import androidx.fragment.app.FragmentManager;
  87. import androidx.fragment.app.FragmentTransaction;
  88. /**
  89. * Activity with common behaviour for activities handling {@link OCFile}s in ownCloud {@link Account}s .
  90. */
  91. public abstract class FileActivity extends DrawerActivity
  92. implements OnRemoteOperationListener, ComponentsGetter, SslUntrustedCertDialog.OnSslUntrustedCertListener,
  93. LoadingVersionNumberTask.VersionDevInterface {
  94. public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE";
  95. public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT";
  96. public static final String EXTRA_FROM_NOTIFICATION = "com.owncloud.android.ui.activity.FROM_NOTIFICATION";
  97. public static final String APP_OPENED_COUNT = "APP_OPENED_COUNT";
  98. public static final String EXTRA_SEARCH = "com.owncloud.android.ui.activity.SEARCH";
  99. public static final String EXTRA_SEARCH_QUERY = "com.owncloud.android.ui.activity.SEARCH_QUERY";
  100. public static final String TAG = FileActivity.class.getSimpleName();
  101. private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
  102. private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";
  103. private static final String KEY_ACTION_BAR_TITLE = "ACTION_BAR_TITLE";
  104. public static final int REQUEST_CODE__UPDATE_CREDENTIALS = 0;
  105. public static final int REQUEST_CODE__LAST_SHARED = REQUEST_CODE__UPDATE_CREDENTIALS;
  106. protected static final long DELAY_TO_REQUEST_OPERATIONS_LATER = 200;
  107. /* Dialog tags */
  108. private static final String DIALOG_UNTRUSTED_CERT = "DIALOG_UNTRUSTED_CERT";
  109. private static final String DIALOG_CERT_NOT_SAVED = "DIALOG_CERT_NOT_SAVED";
  110. /** Main {@link OCFile} handled by the activity.*/
  111. private OCFile mFile;
  112. /** Flag to signal if the activity is launched by a notification */
  113. private boolean mFromNotification;
  114. /** Messages handler associated to the main thread and the life cycle of the activity */
  115. private Handler mHandler;
  116. private FileOperationsHelper mFileOperationsHelper;
  117. private ServiceConnection mOperationsServiceConnection;
  118. private OperationsServiceBinder mOperationsServiceBinder;
  119. private boolean mResumed;
  120. protected FileDownloaderBinder mDownloaderBinder;
  121. protected FileUploaderBinder mUploaderBinder;
  122. private ServiceConnection mDownloadServiceConnection;
  123. private ServiceConnection mUploadServiceConnection;
  124. @Inject
  125. UserAccountManager accountManager;
  126. @Inject
  127. ConnectivityService connectivityService;
  128. @Override
  129. public void showFiles(boolean onDeviceOnly) {
  130. // must be specialized in subclasses
  131. MainApp.showOnlyFilesOnDevice(onDeviceOnly);
  132. }
  133. /**
  134. * Loads the ownCloud {@link Account} and main {@link OCFile} to be handled by the instance of
  135. * the {@link FileActivity}.
  136. *
  137. * Grants that a valid ownCloud {@link Account} is associated to the instance, or that the user
  138. * is requested to create a new one.
  139. */
  140. @Override
  141. protected void onCreate(Bundle savedInstanceState) {
  142. super.onCreate(savedInstanceState);
  143. mHandler = new Handler();
  144. mFileOperationsHelper = new FileOperationsHelper(this, getUserAccountManager(), connectivityService);
  145. Account account = null;
  146. if (savedInstanceState != null) {
  147. mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);
  148. mFromNotification = savedInstanceState.getBoolean(FileActivity.EXTRA_FROM_NOTIFICATION);
  149. mFileOperationsHelper.setOpIdWaitingFor(
  150. savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE)
  151. );
  152. ThemeUtils.setColoredTitle(getSupportActionBar(), savedInstanceState.getString(KEY_ACTION_BAR_TITLE), this);
  153. } else {
  154. account = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
  155. mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
  156. mFromNotification = getIntent().getBooleanExtra(FileActivity.EXTRA_FROM_NOTIFICATION,
  157. false);
  158. }
  159. setAccount(account, savedInstanceState != null);
  160. mOperationsServiceConnection = new OperationsServiceConnection();
  161. bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection,
  162. Context.BIND_AUTO_CREATE);
  163. mDownloadServiceConnection = newTransferenceServiceConnection();
  164. if (mDownloadServiceConnection != null) {
  165. bindService(new Intent(this, FileDownloader.class), mDownloadServiceConnection,
  166. Context.BIND_AUTO_CREATE);
  167. }
  168. mUploadServiceConnection = newTransferenceServiceConnection();
  169. if (mUploadServiceConnection != null) {
  170. bindService(new Intent(this, FileUploader.class), mUploadServiceConnection,
  171. Context.BIND_AUTO_CREATE);
  172. }
  173. }
  174. @Override
  175. protected void onStart() {
  176. super.onStart();
  177. fetchExternalLinks(false);
  178. }
  179. @Override
  180. protected void onResume() {
  181. super.onResume();
  182. mResumed = true;
  183. if (mOperationsServiceBinder != null) {
  184. doOnResumeAndBound();
  185. }
  186. }
  187. @Override
  188. protected void onPause() {
  189. if (mOperationsServiceBinder != null) {
  190. mOperationsServiceBinder.removeOperationListener(this);
  191. }
  192. mResumed = false;
  193. super.onPause();
  194. }
  195. @Override
  196. protected void onDestroy() {
  197. if (mOperationsServiceConnection != null) {
  198. unbindService(mOperationsServiceConnection);
  199. mOperationsServiceBinder = null;
  200. }
  201. if (mDownloadServiceConnection != null) {
  202. unbindService(mDownloadServiceConnection);
  203. mDownloadServiceConnection = null;
  204. }
  205. if (mUploadServiceConnection != null) {
  206. unbindService(mUploadServiceConnection);
  207. mUploadServiceConnection = null;
  208. }
  209. super.onDestroy();
  210. }
  211. /**
  212. * {@inheritDoc}
  213. */
  214. @Override
  215. protected void onSaveInstanceState(@NonNull Bundle outState) {
  216. super.onSaveInstanceState(outState);
  217. outState.putParcelable(FileActivity.EXTRA_FILE, mFile);
  218. outState.putBoolean(FileActivity.EXTRA_FROM_NOTIFICATION, mFromNotification);
  219. outState.putLong(KEY_WAITING_FOR_OP_ID, mFileOperationsHelper.getOpIdWaitingFor());
  220. if(getSupportActionBar() != null && getSupportActionBar().getTitle() != null) {
  221. // Null check in case the actionbar is used in ActionBar.NAVIGATION_MODE_LIST
  222. // since it doesn't have a title then
  223. outState.putString(KEY_ACTION_BAR_TITLE, getSupportActionBar().getTitle().toString());
  224. }
  225. }
  226. /**
  227. * Getter for the main {@link OCFile} handled by the activity.
  228. *
  229. * @return Main {@link OCFile} handled by the activity.
  230. */
  231. public OCFile getFile() {
  232. return mFile;
  233. }
  234. /**
  235. * Setter for the main {@link OCFile} handled by the activity.
  236. *
  237. * @param file Main {@link OCFile} to be handled by the activity.
  238. */
  239. public void setFile(OCFile file) {
  240. mFile = file;
  241. }
  242. /**
  243. * @return Value of mFromNotification: True if the Activity is launched by a notification
  244. */
  245. public boolean fromNotification() {
  246. return mFromNotification;
  247. }
  248. public OperationsServiceBinder getOperationsServiceBinder() {
  249. return mOperationsServiceBinder;
  250. }
  251. protected ServiceConnection newTransferenceServiceConnection() {
  252. return null;
  253. }
  254. public OnRemoteOperationListener getRemoteOperationListener() {
  255. return this;
  256. }
  257. public Handler getHandler() {
  258. return mHandler;
  259. }
  260. public FileOperationsHelper getFileOperationsHelper() {
  261. return mFileOperationsHelper;
  262. }
  263. /**
  264. *
  265. * @param operation Operation performed.
  266. * @param result Result of the removal.
  267. */
  268. @Override
  269. public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
  270. Log_OC.d(TAG, "Received result of operation in FileActivity - common behaviour for all the "
  271. + "FileActivities ");
  272. mFileOperationsHelper.setOpIdWaitingFor(Long.MAX_VALUE);
  273. dismissLoadingDialog();
  274. if (!result.isSuccess() && (
  275. result.getCode() == ResultCode.UNAUTHORIZED ||
  276. (result.isException() && result.getException() instanceof AuthenticatorException)
  277. )) {
  278. requestCredentialsUpdate(this);
  279. if (result.getCode() == ResultCode.UNAUTHORIZED) {
  280. DisplayUtils.showSnackMessage(
  281. this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
  282. );
  283. }
  284. } else if (!result.isSuccess() && ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED.equals(result.getCode())) {
  285. showUntrustedCertDialog(result);
  286. } else if (operation == null ||
  287. operation instanceof CreateShareWithShareeOperation ||
  288. operation instanceof UnshareOperation ||
  289. operation instanceof SynchronizeFolderOperation ||
  290. operation instanceof UpdateShareViaLinkOperation ||
  291. operation instanceof UpdateSharePermissionsOperation
  292. ) {
  293. if (result.isSuccess()) {
  294. updateFileFromDB();
  295. } else if (result.getCode() != ResultCode.CANCELLED) {
  296. DisplayUtils.showSnackMessage(
  297. this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
  298. );
  299. }
  300. } else if (operation instanceof SynchronizeFileOperation) {
  301. onSynchronizeFileOperationFinish((SynchronizeFileOperation) operation, result);
  302. } else if (operation instanceof GetSharesForFileOperation) {
  303. if (result.isSuccess() || result.getCode() == ResultCode.SHARE_NOT_FOUND) {
  304. updateFileFromDB();
  305. } else {
  306. DisplayUtils.showSnackMessage(
  307. this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
  308. );
  309. }
  310. }
  311. }
  312. /**
  313. * Invalidates the credentials stored for the current OC account and requests new credentials to the user,
  314. * navigating to {@link AuthenticatorActivity}
  315. *
  316. * Equivalent to call requestCredentialsUpdate(context, null);
  317. *
  318. * @param context Android Context needed to access the {@link AccountManager}. Received as a parameter
  319. * to make the method accessible to {@link android.content.BroadcastReceiver}s.
  320. */
  321. protected void requestCredentialsUpdate(Context context) {
  322. requestCredentialsUpdate(context, null);
  323. }
  324. /**
  325. * Invalidates the credentials stored for the given OC account and requests new credentials to the user,
  326. * navigating to {@link AuthenticatorActivity}
  327. *
  328. * @param context Android Context needed to access the {@link AccountManager}. Received as a parameter
  329. * to make the method accessible to {@link android.content.BroadcastReceiver}s.
  330. * @param account Stored OC account to request credentials update for. If null, current account will
  331. * be used.
  332. */
  333. protected void requestCredentialsUpdate(Context context, Account account) {
  334. if (account == null) {
  335. account = getAccount();
  336. }
  337. boolean remoteWipeSupported = accountManager.getServerVersion(account).isRemoteWipeSupported();
  338. if (remoteWipeSupported) {
  339. new CheckRemoteWipeTask(account, new WeakReference<>(this)).execute();
  340. } else {
  341. performCredentialsUpdate(account, context);
  342. }
  343. }
  344. public void performCredentialsUpdate(Account account, Context context) {
  345. try {
  346. /// step 1 - invalidate credentials of current account
  347. OwnCloudAccount ocAccount = new OwnCloudAccount(account, context);
  348. OwnCloudClient client = OwnCloudClientManagerFactory.getDefaultSingleton().removeClientFor(ocAccount);
  349. if (client != null) {
  350. OwnCloudCredentials credentials = client.getCredentials();
  351. if (credentials != null) {
  352. AccountManager accountManager = AccountManager.get(context);
  353. if (credentials.authTokenExpires()) {
  354. accountManager.invalidateAuthToken(account.type, credentials.getAuthToken());
  355. } else {
  356. accountManager.clearPassword(account);
  357. }
  358. }
  359. }
  360. /// step 2 - request credentials to user
  361. Intent updateAccountCredentials = new Intent(context, AuthenticatorActivity.class);
  362. updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, account);
  363. updateAccountCredentials.putExtra(
  364. AuthenticatorActivity.EXTRA_ACTION,
  365. AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
  366. updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
  367. startActivityForResult(updateAccountCredentials, REQUEST_CODE__UPDATE_CREDENTIALS);
  368. } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) {
  369. DisplayUtils.showSnackMessage(this, R.string.auth_account_does_not_exist);
  370. }
  371. }
  372. /**
  373. * Show untrusted cert dialog
  374. */
  375. public void showUntrustedCertDialog(RemoteOperationResult result) {
  376. // Show a dialog with the certificate info
  377. FragmentManager fm = getSupportFragmentManager();
  378. SslUntrustedCertDialog dialog = (SslUntrustedCertDialog) fm.findFragmentByTag(DIALOG_UNTRUSTED_CERT);
  379. if(dialog == null) {
  380. dialog = SslUntrustedCertDialog.newInstanceForFullSslError(
  381. (CertificateCombinedException) result.getException());
  382. FragmentTransaction ft = fm.beginTransaction();
  383. dialog.show(ft, DIALOG_UNTRUSTED_CERT);
  384. }
  385. }
  386. private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation,
  387. RemoteOperationResult result) {
  388. OCFile syncedFile = operation.getLocalFile();
  389. if (!result.isSuccess()) {
  390. if (result.getCode() == ResultCode.SYNC_CONFLICT) {
  391. Intent i = new Intent(this, ConflictsResolveActivity.class);
  392. i.putExtra(ConflictsResolveActivity.EXTRA_FILE, syncedFile);
  393. i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, getAccount());
  394. startActivity(i);
  395. }
  396. } else {
  397. if (!operation.transferWasRequested()) {
  398. DisplayUtils.showSnackMessage(this, ErrorMessageAdapter.getErrorCauseMessage(result,
  399. operation, getResources()));
  400. }
  401. supportInvalidateOptionsMenu();
  402. }
  403. }
  404. protected void updateFileFromDB(){
  405. OCFile file = getFile();
  406. if (file != null) {
  407. file = getStorageManager().getFileByPath(file.getRemotePath());
  408. setFile(file);
  409. }
  410. }
  411. /**
  412. * Show loading dialog
  413. */
  414. public void showLoadingDialog(String message) {
  415. // grant that only one waiting dialog is shown
  416. dismissLoadingDialog();
  417. // Construct dialog
  418. Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
  419. if (frag == null) {
  420. Log_OC.d(TAG, "show loading dialog");
  421. LoadingDialog loading = LoadingDialog.newInstance(message);
  422. FragmentManager fm = getSupportFragmentManager();
  423. FragmentTransaction ft = fm.beginTransaction();
  424. loading.show(ft, DIALOG_WAIT_TAG);
  425. fm.executePendingTransactions();
  426. }
  427. }
  428. /**
  429. * Dismiss loading dialog
  430. */
  431. public void dismissLoadingDialog() {
  432. Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
  433. if (frag != null) {
  434. Log_OC.d(TAG, "dismiss loading dialog");
  435. LoadingDialog loading = (LoadingDialog) frag;
  436. loading.dismissAllowingStateLoss();
  437. }
  438. }
  439. private void doOnResumeAndBound() {
  440. mOperationsServiceBinder.addOperationListener(this, mHandler);
  441. long waitingForOpId = mFileOperationsHelper.getOpIdWaitingFor();
  442. if (waitingForOpId <= Integer.MAX_VALUE) {
  443. boolean wait = mOperationsServiceBinder.dispatchResultIfFinished((int)waitingForOpId,
  444. this);
  445. if (!wait ) {
  446. dismissLoadingDialog();
  447. }
  448. }
  449. }
  450. /**
  451. * Implements callback methods for service binding. Passed as a parameter to {
  452. */
  453. private class OperationsServiceConnection implements ServiceConnection {
  454. @Override
  455. public void onServiceConnected(ComponentName component, IBinder service) {
  456. if (component.equals(new ComponentName(FileActivity.this, OperationsService.class))) {
  457. Log_OC.d(TAG, "Operations service connected");
  458. mOperationsServiceBinder = (OperationsServiceBinder) service;
  459. /*if (!mOperationsServiceBinder.isPerformingBlockingOperation()) {
  460. dismissLoadingDialog();
  461. }*/
  462. if (mResumed) {
  463. doOnResumeAndBound();
  464. }
  465. } else {
  466. return;
  467. }
  468. }
  469. @Override
  470. public void onServiceDisconnected(ComponentName component) {
  471. if (component.equals(new ComponentName(FileActivity.this, OperationsService.class))) {
  472. Log_OC.d(TAG, "Operations service disconnected");
  473. mOperationsServiceBinder = null;
  474. // TODO whatever could be waiting for the service is unbound
  475. }
  476. }
  477. }
  478. @Override
  479. public FileDownloaderBinder getFileDownloaderBinder() {
  480. return mDownloaderBinder;
  481. }
  482. @Override
  483. public FileUploaderBinder getFileUploaderBinder() {
  484. return mUploaderBinder;
  485. }
  486. @Override
  487. public void restart() {
  488. Intent i = new Intent(this, FileDisplayActivity.class);
  489. i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  490. i.setAction(FileDisplayActivity.RESTART);
  491. startActivity(i);
  492. fetchExternalLinks(false);
  493. }
  494. public OCFile getCurrentDir() {
  495. OCFile file = getFile();
  496. if (file != null) {
  497. if (file.isFolder()) {
  498. return file;
  499. } else if (getStorageManager() != null) {
  500. String parentPath = file.getParentRemotePath();
  501. return getStorageManager().getFileByPath(parentPath);
  502. }
  503. }
  504. return null;
  505. }
  506. /* OnSslUntrustedCertListener methods */
  507. @Override
  508. public void onSavedCertificate() {
  509. // Nothing to do in this context
  510. }
  511. @Override
  512. public void onFailedSavingCertificate() {
  513. ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(
  514. R.string.ssl_validator_not_saved, new String[]{}, 0, R.string.common_ok, -1, -1
  515. );
  516. dialog.show(getSupportFragmentManager(), DIALOG_CERT_NOT_SAVED);
  517. }
  518. public void checkForNewDevVersionNecessary(View view, Context context) {
  519. if (getResources().getBoolean(R.bool.dev_version_direct_download_enabled)) {
  520. ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
  521. int count = arbitraryDataProvider.getIntegerValue(FilesSyncHelper.GLOBAL, APP_OPENED_COUNT);
  522. if (count > 10 || count == -1) {
  523. checkForNewDevVersion(this, context);
  524. }
  525. }
  526. }
  527. @Override
  528. public void returnVersion(Integer latestVersion) {
  529. showDevSnackbar(this, latestVersion, false);
  530. }
  531. public static void checkForNewDevVersion(LoadingVersionNumberTask.VersionDevInterface callback, Context context) {
  532. String url = context.getString(R.string.dev_latest);
  533. LoadingVersionNumberTask loadTask = new LoadingVersionNumberTask(callback);
  534. loadTask.execute(url);
  535. }
  536. public static void showDevSnackbar(Activity activity, Integer latestVersion, boolean openDirectly) {
  537. Integer currentVersion = -1;
  538. try {
  539. currentVersion = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionCode;
  540. } catch (PackageManager.NameNotFoundException e) {
  541. Log_OC.e(TAG, "Package not found", e);
  542. }
  543. if (latestVersion == -1 || currentVersion == -1) {
  544. DisplayUtils.showSnackMessage(activity, R.string.dev_version_no_information_available, Snackbar.LENGTH_LONG);
  545. }
  546. if (latestVersion > currentVersion) {
  547. if (openDirectly) {
  548. String devApkLink = (String) activity.getText(R.string.dev_link) + latestVersion + ".apk";
  549. Uri uriUrl = Uri.parse(devApkLink);
  550. Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl);
  551. DisplayUtils.startIntentIfAppAvailable(intent, activity, R.string.no_browser_available);
  552. } else {
  553. Snackbar.make(activity.findViewById(android.R.id.content), R.string.dev_version_new_version_available,
  554. Snackbar.LENGTH_LONG)
  555. .setAction(activity.getString(R.string.version_dev_download), v -> {
  556. String devApkLink = (String) activity.getText(R.string.dev_link) + latestVersion + ".apk";
  557. Uri uriUrl = Uri.parse(devApkLink);
  558. Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl);
  559. DisplayUtils.startIntentIfAppAvailable(intent, activity, R.string.no_browser_available);
  560. }).show();
  561. }
  562. } else {
  563. DisplayUtils.showSnackMessage(activity, R.string.dev_version_no_new_version_available, Snackbar.LENGTH_LONG);
  564. }
  565. }
  566. public static void copyAndShareFileLink(FileActivity activity, OCFile file, String link) {
  567. ClipboardUtil.copyToClipboard(activity, link, false);
  568. Snackbar snackbar = Snackbar.make(activity.findViewById(android.R.id.content), R.string.clipboard_text_copied,
  569. Snackbar.LENGTH_LONG)
  570. .setAction(R.string.share, v -> showShareLinkDialog(activity, file, link));
  571. ThemeUtils.colorSnackbar(activity, snackbar);
  572. snackbar.show();
  573. }
  574. public static void showShareLinkDialog(FileActivity activity, OCFile file, String link) {
  575. // Create dialog to allow the user choose an app to send the link
  576. Intent intentToShareLink = new Intent(Intent.ACTION_SEND);
  577. intentToShareLink.putExtra(Intent.EXTRA_TEXT, link);
  578. intentToShareLink.setType("text/plain");
  579. String username;
  580. try {
  581. OwnCloudAccount oca = new OwnCloudAccount(activity.getAccount(), activity);
  582. if (oca.getDisplayName() != null && !oca.getDisplayName().isEmpty()) {
  583. username = oca.getDisplayName();
  584. } else {
  585. username = com.owncloud.android.lib.common.accounts.AccountUtils
  586. .getUsernameForAccount(activity.getAccount());
  587. }
  588. } catch (Exception e) {
  589. username = com.owncloud.android.lib.common.accounts.AccountUtils
  590. .getUsernameForAccount(activity.getAccount());
  591. }
  592. if (username != null) {
  593. intentToShareLink.putExtra(Intent.EXTRA_SUBJECT,
  594. activity.getString(R.string.subject_user_shared_with_you, username,
  595. file.getFileName()));
  596. } else {
  597. intentToShareLink.putExtra(Intent.EXTRA_SUBJECT,
  598. activity.getString(R.string.subject_shared_with_you,
  599. file.getFileName()));
  600. }
  601. String[] packagesToExclude = new String[]{activity.getPackageName()};
  602. DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intentToShareLink, packagesToExclude);
  603. chooserDialog.show(activity.getSupportFragmentManager(), FileDisplayActivity.FTAG_CHOOSER_DIALOG);
  604. }
  605. }