FileActivity.java 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * @author David A. Velasco
  5. * Copyright (C) 2011 Bartek Przybylski
  6. * Copyright (C) 2015 ownCloud Inc.
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2,
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. package com.owncloud.android.ui.activity;
  22. import android.accounts.Account;
  23. import android.accounts.AccountManager;
  24. import android.accounts.AccountManagerCallback;
  25. import android.accounts.AccountManagerFuture;
  26. import android.accounts.AuthenticatorException;
  27. import android.accounts.OperationCanceledException;
  28. import android.content.ComponentName;
  29. import android.content.Context;
  30. import android.content.Intent;
  31. import android.content.ServiceConnection;
  32. import android.content.res.Configuration;
  33. import android.os.Bundle;
  34. import android.os.Handler;
  35. import android.os.IBinder;
  36. import android.support.v4.app.ActionBarDrawerToggle;
  37. import android.support.v4.app.Fragment;
  38. import android.support.v4.app.FragmentManager;
  39. import android.support.v4.app.FragmentTransaction;
  40. import android.support.v4.view.GravityCompat;
  41. import android.support.v4.widget.DrawerLayout;
  42. import android.support.v7.app.ActionBar;
  43. import android.support.v7.app.ActionBarActivity;
  44. import android.view.View;
  45. import android.widget.AdapterView;
  46. import android.widget.LinearLayout;
  47. import android.widget.ListView;
  48. import android.widget.Toast;
  49. import com.owncloud.android.BuildConfig;
  50. import com.owncloud.android.MainApp;
  51. import com.owncloud.android.R;
  52. import com.owncloud.android.authentication.AccountUtils;
  53. import com.owncloud.android.authentication.AuthenticatorActivity;
  54. import com.owncloud.android.datamodel.FileDataStorageManager;
  55. import com.owncloud.android.datamodel.OCFile;
  56. import com.owncloud.android.files.FileOperationsHelper;
  57. import com.owncloud.android.files.services.FileDownloader;
  58. import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
  59. import com.owncloud.android.files.services.FileUploader;
  60. import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
  61. import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
  62. import com.owncloud.android.lib.common.operations.RemoteOperation;
  63. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  64. import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
  65. import com.owncloud.android.lib.common.utils.Log_OC;
  66. import com.owncloud.android.operations.CreateShareOperation;
  67. import com.owncloud.android.operations.SynchronizeFileOperation;
  68. import com.owncloud.android.operations.SynchronizeFolderOperation;
  69. import com.owncloud.android.operations.UnshareLinkOperation;
  70. import com.owncloud.android.services.OperationsService;
  71. import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
  72. import com.owncloud.android.ui.NavigationDrawerItem;
  73. import com.owncloud.android.ui.adapter.NavigationDrawerListAdapter;
  74. import com.owncloud.android.ui.dialog.LoadingDialog;
  75. import com.owncloud.android.ui.dialog.SharePasswordDialogFragment;
  76. import com.owncloud.android.ui.fragment.FileDetailFragment;
  77. import com.owncloud.android.ui.fragment.FileFragment;
  78. import com.owncloud.android.utils.ErrorMessageAdapter;
  79. import java.util.ArrayList;
  80. /**
  81. * Activity with common behaviour for activities handling {@link OCFile}s in ownCloud
  82. * {@link Account}s .
  83. */
  84. public class FileActivity extends ActionBarActivity
  85. implements OnRemoteOperationListener, ComponentsGetter {
  86. public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE";
  87. public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT";
  88. public static final String EXTRA_WAITING_TO_PREVIEW =
  89. "com.owncloud.android.ui.activity.WAITING_TO_PREVIEW";
  90. public static final String EXTRA_FROM_NOTIFICATION =
  91. "com.owncloud.android.ui.activity.FROM_NOTIFICATION";
  92. public static final String TAG = FileActivity.class.getSimpleName();
  93. private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
  94. private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";
  95. private static final String DIALOG_SHARE_PASSWORD = "DIALOG_SHARE_PASSWORD";
  96. private static final String KEY_TRY_SHARE_AGAIN = "TRY_SHARE_AGAIN";
  97. private static final String KEY_ACTION_BAR_TITLE = "ACTION_BAR_TITLE";
  98. protected static final long DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS = 200;
  99. /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located.*/
  100. private Account mAccount;
  101. /** Main {@link OCFile} handled by the activity.*/
  102. private OCFile mFile;
  103. /** Flag to signal that the activity will is finishing to enforce the creation of an ownCloud
  104. * {@link Account} */
  105. private boolean mRedirectingToSetupAccount = false;
  106. /** Flag to signal when the value of mAccount was set */
  107. protected boolean mAccountWasSet;
  108. /** Flag to signal when the value of mAccount was restored from a saved state */
  109. protected boolean mAccountWasRestored;
  110. /** Flag to signal if the activity is launched by a notification */
  111. private boolean mFromNotification;
  112. /** Messages handler associated to the main thread and the life cycle of the activity */
  113. private Handler mHandler;
  114. /** Access point to the cached database for the current ownCloud {@link Account} */
  115. private FileDataStorageManager mStorageManager = null;
  116. private FileOperationsHelper mFileOperationsHelper;
  117. private ServiceConnection mOperationsServiceConnection = null;
  118. private OperationsServiceBinder mOperationsServiceBinder = null;
  119. protected FileDownloaderBinder mDownloaderBinder = null;
  120. protected FileUploaderBinder mUploaderBinder = null;
  121. private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null;
  122. private boolean mTryShareAgain = false;
  123. // Navigation Drawer
  124. protected DrawerLayout mDrawerLayout;
  125. protected ActionBarDrawerToggle mDrawerToggle;
  126. protected ListView mDrawerList;
  127. // Slide menu items
  128. protected String[] mDrawerTitles;
  129. protected String[] mDrawerContentDescriptions;
  130. protected ArrayList<NavigationDrawerItem> mDrawerItems;
  131. protected NavigationDrawerListAdapter mNavigationDrawerAdapter = null;
  132. // TODO re-enable when "Accounts" is available in Navigation Drawer
  133. // protected boolean mShowAccounts = false;
  134. /**
  135. * Loads the ownCloud {@link Account} and main {@link OCFile} to be handled by the instance of
  136. * the {@link FileActivity}.
  137. *
  138. * Grants that a valid ownCloud {@link Account} is associated to the instance, or that the user
  139. * is requested to create a new one.
  140. */
  141. @Override
  142. protected void onCreate(Bundle savedInstanceState) {
  143. super.onCreate(savedInstanceState);
  144. mHandler = new Handler();
  145. mFileOperationsHelper = new FileOperationsHelper(this);
  146. Account account = null;
  147. if(savedInstanceState != null) {
  148. mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);
  149. mFromNotification = savedInstanceState.getBoolean(FileActivity.EXTRA_FROM_NOTIFICATION);
  150. mFileOperationsHelper.setOpIdWaitingFor(
  151. savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE)
  152. );
  153. mTryShareAgain = savedInstanceState.getBoolean(KEY_TRY_SHARE_AGAIN);
  154. getSupportActionBar().setTitle(savedInstanceState.getString(KEY_ACTION_BAR_TITLE));
  155. } else {
  156. account = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
  157. mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
  158. mFromNotification = getIntent().getBooleanExtra(FileActivity.EXTRA_FROM_NOTIFICATION,
  159. false);
  160. }
  161. AccountUtils.updateAccountVersion(this); // best place, before any access to AccountManager
  162. // or database
  163. setAccount(account, savedInstanceState != null);
  164. mOperationsServiceConnection = new OperationsServiceConnection();
  165. bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection,
  166. Context.BIND_AUTO_CREATE);
  167. mDownloadServiceConnection = newTransferenceServiceConnection();
  168. if (mDownloadServiceConnection != null) {
  169. bindService(new Intent(this, FileDownloader.class), mDownloadServiceConnection,
  170. Context.BIND_AUTO_CREATE);
  171. }
  172. mUploadServiceConnection = newTransferenceServiceConnection();
  173. if (mUploadServiceConnection != null) {
  174. bindService(new Intent(this, FileUploader.class), mUploadServiceConnection,
  175. Context.BIND_AUTO_CREATE);
  176. }
  177. }
  178. @Override
  179. protected void onNewIntent (Intent intent) {
  180. Log_OC.v(TAG, "onNewIntent() start");
  181. Account current = AccountUtils.getCurrentOwnCloudAccount(this);
  182. if (current != null && mAccount != null && !mAccount.name.equals(current.name)) {
  183. mAccount = current;
  184. }
  185. Log_OC.v(TAG, "onNewIntent() stop");
  186. }
  187. /**
  188. * Since ownCloud {@link Account}s can be managed from the system setting menu,
  189. * the existence of the {@link Account} associated to the instance must be checked
  190. * every time it is restarted.
  191. */
  192. @Override
  193. protected void onRestart() {
  194. Log_OC.v(TAG, "onRestart() start");
  195. super.onRestart();
  196. boolean validAccount = (mAccount != null && AccountUtils.exists(mAccount, this));
  197. if (!validAccount) {
  198. swapToDefaultAccount();
  199. }
  200. Log_OC.v(TAG, "onRestart() end");
  201. }
  202. @Override
  203. protected void onStart() {
  204. super.onStart();
  205. if (mAccountWasSet) {
  206. onAccountSet(mAccountWasRestored);
  207. }
  208. }
  209. @Override
  210. protected void onResume() {
  211. super.onResume();
  212. if (mOperationsServiceBinder != null) {
  213. doOnResumeAndBound();
  214. }
  215. }
  216. @Override
  217. protected void onPause() {
  218. if (mOperationsServiceBinder != null) {
  219. mOperationsServiceBinder.removeOperationListener(this);
  220. }
  221. super.onPause();
  222. }
  223. @Override
  224. protected void onDestroy() {
  225. if (mOperationsServiceConnection != null) {
  226. unbindService(mOperationsServiceConnection);
  227. mOperationsServiceBinder = null;
  228. }
  229. if (mDownloadServiceConnection != null) {
  230. unbindService(mDownloadServiceConnection);
  231. mDownloadServiceConnection = null;
  232. }
  233. if (mUploadServiceConnection != null) {
  234. unbindService(mUploadServiceConnection);
  235. mUploadServiceConnection = null;
  236. }
  237. super.onDestroy();
  238. }
  239. @Override
  240. protected void onPostCreate(Bundle savedInstanceState) {
  241. super.onPostCreate(savedInstanceState);
  242. // Sync the toggle state after onRestoreInstanceState has occurred.
  243. if (mDrawerToggle != null) {
  244. mDrawerToggle.syncState();
  245. if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
  246. getSupportActionBar().setTitle(R.string.app_name);
  247. mDrawerToggle.setDrawerIndicatorEnabled(true);
  248. }
  249. }
  250. }
  251. @Override
  252. public void onConfigurationChanged(Configuration newConfig) {
  253. super.onConfigurationChanged(newConfig);
  254. if (mDrawerToggle != null) {
  255. mDrawerToggle.onConfigurationChanged(newConfig);
  256. }
  257. }
  258. protected void initDrawer(){
  259. // constant settings for action bar when navigation drawer is inited
  260. getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
  261. mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
  262. // Notification Drawer
  263. LinearLayout navigationDrawerLayout = (LinearLayout) findViewById(R.id.left_drawer);
  264. mDrawerList = (ListView) navigationDrawerLayout.findViewById(R.id.drawer_list);
  265. // TODO re-enable when "Accounts" is available in Navigation Drawer
  266. // // load Account in the Drawer Title
  267. // // User-Icon
  268. // ImageView userIcon = (ImageView) navigationDrawerLayout.findViewById(R.id.drawer_userIcon);
  269. // userIcon.setImageResource(DisplayUtils.getSeasonalIconId());
  270. //
  271. // // Username
  272. // TextView username = (TextView) navigationDrawerLayout.findViewById(R.id.drawer_username);
  273. // Account account = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
  274. //
  275. // if (account != null) {
  276. // int lastAtPos = account.name.lastIndexOf("@");
  277. // username.setText(account.name.substring(0, lastAtPos));
  278. // }
  279. // load slide menu items
  280. mDrawerTitles = getResources().getStringArray(R.array.drawer_items);
  281. // nav drawer content description from resources
  282. mDrawerContentDescriptions = getResources().
  283. getStringArray(R.array.drawer_content_descriptions);
  284. // nav drawer items
  285. mDrawerItems = new ArrayList<NavigationDrawerItem>();
  286. // adding nav drawer items to array
  287. // TODO re-enable when "Accounts" is available in Navigation Drawer
  288. // Accounts
  289. // mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[0],
  290. // mDrawerContentDescriptions[0]));
  291. // All Files
  292. mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[0], mDrawerContentDescriptions[0]));
  293. // TODO Enable when "On Device" is recovered
  294. // On Device
  295. //mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[2],
  296. // mDrawerContentDescriptions[2]));
  297. // Settings
  298. mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[1], mDrawerContentDescriptions[1]));
  299. // Logs
  300. if (BuildConfig.DEBUG) {
  301. mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[2],
  302. mDrawerContentDescriptions[2]));
  303. }
  304. // setting the nav drawer list adapter
  305. mNavigationDrawerAdapter = new NavigationDrawerListAdapter(getApplicationContext(), this,
  306. mDrawerItems);
  307. mDrawerList.setAdapter(mNavigationDrawerAdapter);
  308. mDrawerToggle = new ActionBarDrawerToggle(
  309. this,
  310. mDrawerLayout,
  311. R.drawable.ic_drawer,
  312. R.string.app_name,
  313. R.string.drawer_close) {
  314. /** Called when a drawer has settled in a completely closed state. */
  315. public void onDrawerClosed(View view) {
  316. super.onDrawerClosed(view);
  317. updateActionBarTitleAndHomeButton(null);
  318. invalidateOptionsMenu();
  319. }
  320. /** Called when a drawer has settled in a completely open state. */
  321. public void onDrawerOpened(View drawerView) {
  322. super.onDrawerOpened(drawerView);
  323. getSupportActionBar().setTitle(R.string.app_name);
  324. mDrawerToggle.setDrawerIndicatorEnabled(true);
  325. invalidateOptionsMenu();
  326. }
  327. };
  328. //mDrawerToggle.setDrawerIndicatorEnabled(true);
  329. // Set the list's click listener
  330. mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
  331. // Set the drawer toggle as the DrawerListener
  332. mDrawerLayout.setDrawerListener(mDrawerToggle);
  333. }
  334. /**
  335. * Updates title bar and home buttons (state and icon).
  336. *
  337. * Assumes that navigation drawer is NOT visible.
  338. */
  339. protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) {
  340. String title = getString(R.string.default_display_name_for_root_folder); // default
  341. boolean inRoot;
  342. /// choose the appropiate title
  343. if (chosenFile == null) {
  344. chosenFile = mFile; // if no file is passed, current file decides
  345. }
  346. inRoot = (
  347. chosenFile == null ||
  348. (chosenFile.isFolder() && chosenFile.getParentId() == FileDataStorageManager.ROOT_PARENT_ID)
  349. );
  350. if (!inRoot) {
  351. title = chosenFile.getFileName();
  352. }
  353. /// set the chosen title
  354. ActionBar actionBar = getSupportActionBar();
  355. actionBar.setTitle(title);
  356. /// also as content description
  357. View actionBarTitleView = getWindow().getDecorView().findViewById(
  358. getResources().getIdentifier("action_bar_title", "id", "android")
  359. );
  360. if (actionBarTitleView != null) { // it's null in Android 2.x
  361. actionBarTitleView.setContentDescription(title);
  362. }
  363. /// set home button properties
  364. mDrawerToggle.setDrawerIndicatorEnabled(inRoot);
  365. actionBar.setDisplayHomeAsUpEnabled(true);
  366. actionBar.setDisplayShowTitleEnabled(true);
  367. }
  368. /**
  369. * Sets and validates the ownCloud {@link Account} associated to the Activity.
  370. *
  371. * If not valid, tries to swap it for other valid and existing ownCloud {@link Account}.
  372. *
  373. * POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.
  374. *
  375. * @param account New {@link Account} to set.
  376. * @param savedAccount When 'true', account was retrieved from a saved instance state.
  377. */
  378. protected void setAccount(Account account, boolean savedAccount) {
  379. Account oldAccount = mAccount;
  380. boolean validAccount =
  381. (account != null && AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(),
  382. account.name));
  383. if (validAccount) {
  384. mAccount = account;
  385. mAccountWasSet = true;
  386. mAccountWasRestored = (savedAccount || mAccount.equals(oldAccount));
  387. } else {
  388. swapToDefaultAccount();
  389. }
  390. }
  391. /**
  392. * Tries to swap the current ownCloud {@link Account} for other valid and existing.
  393. *
  394. * If no valid ownCloud {@link Account} exists, the the user is requested
  395. * to create a new ownCloud {@link Account}.
  396. *
  397. * POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.
  398. */
  399. private void swapToDefaultAccount() {
  400. // default to the most recently used account
  401. Account newAccount = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
  402. if (newAccount == null) {
  403. /// no account available: force account creation
  404. createFirstAccount();
  405. mRedirectingToSetupAccount = true;
  406. mAccountWasSet = false;
  407. mAccountWasRestored = false;
  408. } else {
  409. mAccountWasSet = true;
  410. mAccountWasRestored = (newAccount.equals(mAccount));
  411. mAccount = newAccount;
  412. }
  413. }
  414. /**
  415. * Launches the account creation activity. To use when no ownCloud account is available
  416. */
  417. private void createFirstAccount() {
  418. AccountManager am = AccountManager.get(getApplicationContext());
  419. am.addAccount(MainApp.getAccountType(),
  420. null,
  421. null,
  422. null,
  423. this,
  424. new AccountCreationCallback(),
  425. null);
  426. }
  427. /**
  428. * {@inheritDoc}
  429. */
  430. @Override
  431. protected void onSaveInstanceState(Bundle outState) {
  432. super.onSaveInstanceState(outState);
  433. outState.putParcelable(FileActivity.EXTRA_FILE, mFile);
  434. outState.putBoolean(FileActivity.EXTRA_FROM_NOTIFICATION, mFromNotification);
  435. outState.putLong(KEY_WAITING_FOR_OP_ID, mFileOperationsHelper.getOpIdWaitingFor());
  436. outState.putBoolean(KEY_TRY_SHARE_AGAIN, mTryShareAgain);
  437. outState.putString(KEY_ACTION_BAR_TITLE, getSupportActionBar().getTitle().toString());
  438. }
  439. /**
  440. * Getter for the main {@link OCFile} handled by the activity.
  441. *
  442. * @return Main {@link OCFile} handled by the activity.
  443. */
  444. public OCFile getFile() {
  445. return mFile;
  446. }
  447. /**
  448. * Setter for the main {@link OCFile} handled by the activity.
  449. *
  450. * @param file Main {@link OCFile} to be handled by the activity.
  451. */
  452. public void setFile(OCFile file) {
  453. mFile = file;
  454. }
  455. /**
  456. * Getter for the ownCloud {@link Account} where the main {@link OCFile} handled by the activity
  457. * is located.
  458. *
  459. * @return OwnCloud {@link Account} where the main {@link OCFile} handled by the activity
  460. * is located.
  461. */
  462. public Account getAccount() {
  463. return mAccount;
  464. }
  465. protected void setAccount(Account account) {
  466. mAccount = account;
  467. }
  468. /**
  469. * @return Value of mFromNotification: True if the Activity is launched by a notification
  470. */
  471. public boolean fromNotification() {
  472. return mFromNotification;
  473. }
  474. /**
  475. * @return 'True' when the Activity is finishing to enforce the setup of a new account.
  476. */
  477. protected boolean isRedirectingToSetupAccount() {
  478. return mRedirectingToSetupAccount;
  479. }
  480. public boolean isTryShareAgain(){
  481. return mTryShareAgain;
  482. }
  483. public void setTryShareAgain(boolean tryShareAgain) {
  484. mTryShareAgain = tryShareAgain;
  485. }
  486. public OperationsServiceBinder getOperationsServiceBinder() {
  487. return mOperationsServiceBinder;
  488. }
  489. protected ServiceConnection newTransferenceServiceConnection() {
  490. return null;
  491. }
  492. /**
  493. * Helper class handling a callback from the {@link AccountManager} after the creation of
  494. * a new ownCloud {@link Account} finished, successfully or not.
  495. *
  496. * At this moment, only called after the creation of the first account.
  497. */
  498. public class AccountCreationCallback implements AccountManagerCallback<Bundle> {
  499. @Override
  500. public void run(AccountManagerFuture<Bundle> future) {
  501. FileActivity.this.mRedirectingToSetupAccount = false;
  502. boolean accountWasSet = false;
  503. if (future != null) {
  504. try {
  505. Bundle result;
  506. result = future.getResult();
  507. String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
  508. String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
  509. if (AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), name)) {
  510. setAccount(new Account(name, type), false);
  511. accountWasSet = true;
  512. }
  513. } catch (OperationCanceledException e) {
  514. Log_OC.d(TAG, "Account creation canceled");
  515. } catch (Exception e) {
  516. Log_OC.e(TAG, "Account creation finished in exception: ", e);
  517. }
  518. } else {
  519. Log_OC.e(TAG, "Account creation callback with null bundle");
  520. }
  521. if (!accountWasSet) {
  522. moveTaskToBack(true);
  523. }
  524. }
  525. }
  526. /**
  527. * Called when the ownCloud {@link Account} associated to the Activity was just updated.
  528. *
  529. * Child classes must grant that state depending on the {@link Account} is updated.
  530. */
  531. protected void onAccountSet(boolean stateWasRecovered) {
  532. if (getAccount() != null) {
  533. mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver());
  534. } else {
  535. Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!");
  536. }
  537. }
  538. public FileDataStorageManager getStorageManager() {
  539. return mStorageManager;
  540. }
  541. public OnRemoteOperationListener getRemoteOperationListener() {
  542. return this;
  543. }
  544. public Handler getHandler() {
  545. return mHandler;
  546. }
  547. public FileOperationsHelper getFileOperationsHelper() {
  548. return mFileOperationsHelper;
  549. }
  550. /**
  551. *
  552. * @param operation Removal operation performed.
  553. * @param result Result of the removal.
  554. */
  555. @Override
  556. public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
  557. Log_OC.d(TAG, "Received result of operation in FileActivity - common behaviour for all the "
  558. + "FileActivities ");
  559. mFileOperationsHelper.setOpIdWaitingFor(Long.MAX_VALUE);
  560. if (!result.isSuccess() && (
  561. result.getCode() == ResultCode.UNAUTHORIZED ||
  562. result.isIdPRedirection() ||
  563. (result.isException() && result.getException() instanceof AuthenticatorException)
  564. )) {
  565. requestCredentialsUpdate();
  566. if (result.getCode() == ResultCode.UNAUTHORIZED) {
  567. dismissLoadingDialog();
  568. Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
  569. operation, getResources()),
  570. Toast.LENGTH_LONG);
  571. t.show();
  572. }
  573. mTryShareAgain = false;
  574. } else if (operation instanceof CreateShareOperation) {
  575. onCreateShareOperationFinish((CreateShareOperation) operation, result);
  576. } else if (operation instanceof UnshareLinkOperation) {
  577. onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result);
  578. } else if (operation instanceof SynchronizeFolderOperation) {
  579. onSynchronizeFolderOperationFinish((SynchronizeFolderOperation)operation, result);
  580. }else if (operation instanceof SynchronizeFileOperation) {
  581. onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
  582. }
  583. }
  584. protected void requestCredentialsUpdate() {
  585. Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
  586. updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());
  587. updateAccountCredentials.putExtra(
  588. AuthenticatorActivity.EXTRA_ACTION,
  589. AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
  590. updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
  591. startActivity(updateAccountCredentials);
  592. }
  593. private void onCreateShareOperationFinish(CreateShareOperation operation,
  594. RemoteOperationResult result) {
  595. dismissLoadingDialog();
  596. if (result.isSuccess()) {
  597. mTryShareAgain = false;
  598. updateFileFromDB();
  599. Intent sendIntent = operation.getSendIntent();
  600. startActivity(sendIntent);
  601. } else {
  602. // Detect Failure (403) --> needs Password
  603. if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
  604. if (!isTryShareAgain()) {
  605. SharePasswordDialogFragment dialog =
  606. SharePasswordDialogFragment.newInstance(new OCFile(operation.getPath()),
  607. operation.getSendIntent());
  608. dialog.show(getSupportFragmentManager(), DIALOG_SHARE_PASSWORD);
  609. } else {
  610. Toast t = Toast.makeText(this,
  611. ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
  612. Toast.LENGTH_LONG);
  613. t.show();
  614. mTryShareAgain = false;
  615. }
  616. } else {
  617. Toast t = Toast.makeText(this,
  618. ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
  619. Toast.LENGTH_LONG);
  620. t.show();
  621. }
  622. }
  623. }
  624. private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
  625. RemoteOperationResult result) {
  626. dismissLoadingDialog();
  627. if (result.isSuccess()){
  628. updateFileFromDB();
  629. } else {
  630. Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
  631. operation, getResources()), Toast.LENGTH_LONG);
  632. t.show();
  633. }
  634. }
  635. private void onSynchronizeFolderOperationFinish(
  636. SynchronizeFolderOperation operation, RemoteOperationResult result
  637. ) {
  638. if (!result.isSuccess() && result.getCode() != ResultCode.CANCELLED){
  639. Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
  640. operation, getResources()), Toast.LENGTH_LONG);
  641. t.show();
  642. }
  643. }
  644. private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation,
  645. RemoteOperationResult result) {
  646. dismissLoadingDialog();
  647. OCFile syncedFile = operation.getLocalFile();
  648. if (!result.isSuccess()) {
  649. if (result.getCode() == ResultCode.SYNC_CONFLICT) {
  650. Intent i = new Intent(this, ConflictsResolveActivity.class);
  651. i.putExtra(ConflictsResolveActivity.EXTRA_FILE, syncedFile);
  652. i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, getAccount());
  653. startActivity(i);
  654. }
  655. } else {
  656. if (!operation.transferWasRequested()) {
  657. Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
  658. operation, getResources()), Toast.LENGTH_LONG);
  659. msg.show();
  660. }
  661. invalidateOptionsMenu();
  662. }
  663. }
  664. protected void updateFileFromDB(){
  665. OCFile file = getFile();
  666. if (file != null) {
  667. file = getStorageManager().getFileByPath(file.getRemotePath());
  668. setFile(file);
  669. }
  670. }
  671. /**
  672. * Show loading dialog
  673. */
  674. public void showLoadingDialog() {
  675. // Construct dialog
  676. LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment));
  677. FragmentManager fm = getSupportFragmentManager();
  678. FragmentTransaction ft = fm.beginTransaction();
  679. loading.show(ft, DIALOG_WAIT_TAG);
  680. }
  681. /**
  682. * Dismiss loading dialog
  683. */
  684. public void dismissLoadingDialog(){
  685. Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
  686. if (frag != null) {
  687. LoadingDialog loading = (LoadingDialog) frag;
  688. loading.dismiss();
  689. }
  690. }
  691. private void doOnResumeAndBound() {
  692. mOperationsServiceBinder.addOperationListener(FileActivity.this, mHandler);
  693. long waitingForOpId = mFileOperationsHelper.getOpIdWaitingFor();
  694. if (waitingForOpId <= Integer.MAX_VALUE) {
  695. boolean wait = mOperationsServiceBinder.dispatchResultIfFinished((int)waitingForOpId,
  696. this);
  697. if (!wait ) {
  698. dismissLoadingDialog();
  699. }
  700. }
  701. }
  702. /**
  703. * Implements callback methods for service binding. Passed as a parameter to {
  704. */
  705. private class OperationsServiceConnection implements ServiceConnection {
  706. @Override
  707. public void onServiceConnected(ComponentName component, IBinder service) {
  708. if (component.equals(new ComponentName(FileActivity.this, OperationsService.class))) {
  709. Log_OC.d(TAG, "Operations service connected");
  710. mOperationsServiceBinder = (OperationsServiceBinder) service;
  711. /*if (!mOperationsServiceBinder.isPerformingBlockingOperation()) {
  712. dismissLoadingDialog();
  713. }*/
  714. doOnResumeAndBound();
  715. } else {
  716. return;
  717. }
  718. }
  719. @Override
  720. public void onServiceDisconnected(ComponentName component) {
  721. if (component.equals(new ComponentName(FileActivity.this, OperationsService.class))) {
  722. Log_OC.d(TAG, "Operations service disconnected");
  723. mOperationsServiceBinder = null;
  724. // TODO whatever could be waiting for the service is unbound
  725. }
  726. }
  727. }
  728. @Override
  729. public FileDownloaderBinder getFileDownloaderBinder() {
  730. return mDownloaderBinder;
  731. }
  732. @Override
  733. public FileUploaderBinder getFileUploaderBinder() {
  734. return mUploaderBinder;
  735. }
  736. public void restart(){
  737. Intent i = new Intent(this, FileDisplayActivity.class);
  738. i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  739. startActivity(i);
  740. }
  741. // TODO re-enable when "Accounts" is available in Navigation Drawer
  742. // public void closeDrawer() {
  743. // mDrawerLayout.closeDrawers();
  744. // }
  745. public void allFilesOption(){
  746. restart();
  747. }
  748. private class DrawerItemClickListener implements ListView.OnItemClickListener {
  749. @Override
  750. public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
  751. // TODO re-enable when "Accounts" is available in Navigation Drawer
  752. // if (mShowAccounts && position > 0){
  753. // position = position - 1;
  754. // }
  755. switch (position){
  756. // TODO re-enable when "Accounts" is available in Navigation Drawer
  757. // case 0: // Accounts
  758. // mShowAccounts = !mShowAccounts;
  759. // mNavigationDrawerAdapter.setShowAccounts(mShowAccounts);
  760. // mNavigationDrawerAdapter.notifyDataSetChanged();
  761. // break;
  762. case 0: // All Files
  763. allFilesOption();
  764. mDrawerLayout.closeDrawers();
  765. break;
  766. // TODO Enable when "On Device" is recovered ?
  767. // case 2:
  768. // MainApp.showOnlyFilesOnDevice(true);
  769. // mDrawerLayout.closeDrawers();
  770. // break;
  771. case 1: // Settings
  772. Intent settingsIntent = new Intent(getApplicationContext(),
  773. Preferences.class);
  774. startActivity(settingsIntent);
  775. mDrawerLayout.closeDrawers();
  776. break;
  777. case 2: // Logs
  778. Intent loggerIntent = new Intent(getApplicationContext(),
  779. LogHistoryActivity.class);
  780. startActivity(loggerIntent);
  781. mDrawerLayout.closeDrawers();
  782. break;
  783. }
  784. }
  785. }
  786. }