FileActivity.java 36 KB

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