FileDisplayActivity.java 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889
  1. /* ownCloud Android client application
  2. * Copyright (C) 2011 Bartek Przybylski
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. */
  18. package com.owncloud.android.ui.activity;
  19. import java.io.File;
  20. import android.accounts.Account;
  21. import android.accounts.AccountManager;
  22. import android.app.AlertDialog;
  23. import android.app.ProgressDialog;
  24. import android.app.AlertDialog.Builder;
  25. import android.app.Dialog;
  26. import android.content.BroadcastReceiver;
  27. import android.content.ContentResolver;
  28. import android.content.Context;
  29. import android.content.DialogInterface;
  30. import android.content.DialogInterface.OnClickListener;
  31. import android.content.Intent;
  32. import android.content.IntentFilter;
  33. import android.content.SharedPreferences;
  34. import android.content.pm.PackageInfo;
  35. import android.content.pm.PackageManager.NameNotFoundException;
  36. import android.content.res.Resources.NotFoundException;
  37. import android.database.Cursor;
  38. import android.net.Uri;
  39. import android.os.Bundle;
  40. import android.os.Environment;
  41. import android.os.Handler;
  42. import android.preference.PreferenceManager;
  43. import android.provider.MediaStore;
  44. import android.support.v4.app.FragmentTransaction;
  45. import android.util.Log;
  46. import android.view.View;
  47. import android.view.ViewGroup;
  48. import android.widget.ArrayAdapter;
  49. import android.widget.EditText;
  50. import android.widget.TextView;
  51. import android.widget.Toast;
  52. import com.actionbarsherlock.app.ActionBar;
  53. import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
  54. import com.actionbarsherlock.app.SherlockFragmentActivity;
  55. import com.actionbarsherlock.view.Menu;
  56. import com.actionbarsherlock.view.MenuInflater;
  57. import com.actionbarsherlock.view.MenuItem;
  58. import com.actionbarsherlock.view.Window;
  59. import com.owncloud.android.AccountUtils;
  60. import com.owncloud.android.authenticator.AccountAuthenticator;
  61. import com.owncloud.android.datamodel.DataStorageManager;
  62. import com.owncloud.android.datamodel.FileDataStorageManager;
  63. import com.owncloud.android.datamodel.OCFile;
  64. import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
  65. import com.owncloud.android.files.OwnCloudFileObserver;
  66. import com.owncloud.android.files.services.FileDownloader;
  67. import com.owncloud.android.files.services.FileObserverService;
  68. import com.owncloud.android.files.services.FileUploader;
  69. import com.owncloud.android.network.OwnCloudClientUtils;
  70. import com.owncloud.android.syncadapter.FileSyncService;
  71. import com.owncloud.android.ui.fragment.FileDetailFragment;
  72. import com.owncloud.android.ui.fragment.OCFileListFragment;
  73. import com.owncloud.android.R;
  74. import eu.alefzero.webdav.WebdavClient;
  75. /**
  76. * Displays, what files the user has available in his ownCloud.
  77. *
  78. * @author Bartek Przybylski
  79. *
  80. */
  81. public class FileDisplayActivity extends SherlockFragmentActivity implements
  82. OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener {
  83. private ArrayAdapter<String> mDirectories;
  84. private OCFile mCurrentDir;
  85. private DataStorageManager mStorageManager;
  86. private SyncBroadcastReceiver mSyncBroadcastReceiver;
  87. private UploadFinishReceiver mUploadFinishReceiver;
  88. private DownloadFinishReceiver mDownloadFinishReceiver;
  89. private OCFileListFragment mFileList;
  90. private boolean mDualPane;
  91. private static final int DIALOG_SETUP_ACCOUNT = 0;
  92. private static final int DIALOG_CREATE_DIR = 1;
  93. private static final int DIALOG_ABOUT_APP = 2;
  94. public static final int DIALOG_SHORT_WAIT = 3;
  95. private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 4;
  96. private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
  97. private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
  98. private static final String TAG = "FileDisplayActivity";
  99. @Override
  100. public void onCreate(Bundle savedInstanceState) {
  101. Log.d(getClass().toString(), "onCreate() start");
  102. super.onCreate(savedInstanceState);
  103. /// saved instance state: keep this always before initDataFromCurrentAccount()
  104. if(savedInstanceState != null) {
  105. mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);
  106. }
  107. if (!AccountUtils.accountsAreSetup(this)) {
  108. /// no account available: FORCE ACCOUNT CREATION
  109. mStorageManager = null;
  110. createFirstAccount();
  111. } else { /// at least an account is available
  112. initDataFromCurrentAccount();
  113. }
  114. // PIN CODE request ; best location is to decide, let's try this first
  115. if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {
  116. requestPinCode();
  117. }
  118. // file observer
  119. /*Intent observer_intent = new Intent(this, FileObserverService.class);
  120. observer_intent.putExtra(FileObserverService.KEY_FILE_CMD, FileObserverService.CMD_INIT_OBSERVED_LIST);
  121. startService(observer_intent);
  122. */
  123. /// USER INTERFACE
  124. requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
  125. // Drop-down navigation
  126. mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
  127. OCFile currFile = mCurrentDir;
  128. while(currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {
  129. mDirectories.add(currFile.getFileName());
  130. currFile = mStorageManager.getFileById(currFile.getParentId());
  131. }
  132. mDirectories.add(OCFile.PATH_SEPARATOR);
  133. // Inflate and set the layout view
  134. setContentView(R.layout.files);
  135. mFileList = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
  136. mDualPane = (findViewById(R.id.file_details_container) != null);
  137. if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) {
  138. FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
  139. transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment
  140. transaction.commit();
  141. }
  142. // Action bar setup
  143. ActionBar actionBar = getSupportActionBar();
  144. actionBar.setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation
  145. actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null && mCurrentDir.getParentId() != 0);
  146. actionBar.setDisplayShowTitleEnabled(false);
  147. actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
  148. actionBar.setListNavigationCallbacks(mDirectories, this);
  149. setSupportProgressBarIndeterminateVisibility(false); // always AFTER setContentView(...) ; to workaround bug in its implementation
  150. Log.d(getClass().toString(), "onCreate() end");
  151. }
  152. /**
  153. * Launches the account creation activity. To use when no ownCloud account is available
  154. */
  155. private void createFirstAccount() {
  156. Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);
  157. intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });
  158. startActivity(intent); // the new activity won't be created until this.onStart() and this.onResume() are finished;
  159. }
  160. /**
  161. * Load of state dependent of the existence of an ownCloud account
  162. */
  163. private void initDataFromCurrentAccount() {
  164. /// Storage manager initialization - access to local database
  165. mStorageManager = new FileDataStorageManager(
  166. AccountUtils.getCurrentOwnCloudAccount(this),
  167. getContentResolver());
  168. /// State recovery - CURRENT DIRECTORY ; priority: 1/ getIntent(), 2/ savedInstanceState (in onCreate()), 3/ root dir
  169. if(getIntent().hasExtra(FileDetailFragment.EXTRA_FILE)) {
  170. mCurrentDir = (OCFile) getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
  171. if(mCurrentDir != null && !mCurrentDir.isDirectory()){
  172. mCurrentDir = mStorageManager.getFileById(mCurrentDir.getParentId());
  173. }
  174. // clear intent extra, so rotating the screen will not return us to this directory
  175. getIntent().removeExtra(FileDetailFragment.EXTRA_FILE);
  176. }
  177. if (mCurrentDir == null)
  178. mCurrentDir = mStorageManager.getFileByPath("/"); // this will return NULL if the database has not ever synchronized
  179. }
  180. @Override
  181. public boolean onCreateOptionsMenu(Menu menu) {
  182. MenuInflater inflater = getSherlock().getMenuInflater();
  183. inflater.inflate(R.menu.menu, menu);
  184. return true;
  185. }
  186. @Override
  187. public boolean onOptionsItemSelected(MenuItem item) {
  188. boolean retval = true;
  189. switch (item.getItemId()) {
  190. case R.id.createDirectoryItem: {
  191. showDialog(DIALOG_CREATE_DIR);
  192. break;
  193. }
  194. case R.id.startSync: {
  195. ContentResolver.cancelSync(null, AccountAuthenticator.AUTH_TOKEN_TYPE); // cancel the current synchronizations of any ownCloud account
  196. Bundle bundle = new Bundle();
  197. bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
  198. ContentResolver.requestSync(
  199. AccountUtils.getCurrentOwnCloudAccount(this),
  200. AccountAuthenticator.AUTH_TOKEN_TYPE, bundle);
  201. break;
  202. }
  203. case R.id.action_upload: {
  204. showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE);
  205. break;
  206. }
  207. case R.id.action_settings: {
  208. Intent settingsIntent = new Intent(this, Preferences.class);
  209. startActivity(settingsIntent);
  210. break;
  211. }
  212. case R.id.about_app : {
  213. showDialog(DIALOG_ABOUT_APP);
  214. break;
  215. }
  216. case android.R.id.home: {
  217. if(mCurrentDir != null && mCurrentDir.getParentId() != 0){
  218. onBackPressed();
  219. }
  220. break;
  221. }
  222. default:
  223. retval = false;
  224. }
  225. return retval;
  226. }
  227. @Override
  228. public boolean onNavigationItemSelected(int itemPosition, long itemId) {
  229. int i = itemPosition;
  230. while (i-- != 0) {
  231. onBackPressed();
  232. }
  233. // the next operation triggers a new call to this method, but it's necessary to
  234. // ensure that the name exposed in the action bar is the current directory when the
  235. // user selected it in the navigation list
  236. if (itemPosition != 0)
  237. getSupportActionBar().setSelectedNavigationItem(0);
  238. return true;
  239. }
  240. /**
  241. * Called, when the user selected something for uploading
  242. */
  243. public void onActivityResult(int requestCode, int resultCode, Intent data) {
  244. if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && resultCode == RESULT_OK) {
  245. requestSimpleUpload(data);
  246. } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && resultCode == RESULT_OK) {
  247. requestMultipleUpload(data);
  248. }
  249. }
  250. private void requestMultipleUpload(Intent data) {
  251. String[] filePaths = data.getStringArrayExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES);
  252. if (filePaths != null) {
  253. String[] remotePaths = new String[filePaths.length];
  254. String remotePathBase = "";
  255. for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
  256. remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
  257. }
  258. if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR))
  259. remotePathBase += OCFile.PATH_SEPARATOR;
  260. for (int j = 0; j< remotePaths.length; j++) {
  261. remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName();
  262. }
  263. Intent i = new Intent(this, FileUploader.class);
  264. i.putExtra(FileUploader.KEY_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
  265. i.putExtra(FileUploader.KEY_LOCAL_FILE, filePaths);
  266. i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePaths);
  267. i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
  268. startService(i);
  269. } else {
  270. Log.d("FileDisplay", "User clicked on 'Update' with no selection");
  271. Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG);
  272. t.show();
  273. return;
  274. }
  275. }
  276. private void requestSimpleUpload(Intent data) {
  277. String filepath = null;
  278. try {
  279. Uri selectedImageUri = data.getData();
  280. String filemanagerstring = selectedImageUri.getPath();
  281. String selectedImagePath = getPath(selectedImageUri);
  282. if (selectedImagePath != null)
  283. filepath = selectedImagePath;
  284. else
  285. filepath = filemanagerstring;
  286. } catch (Exception e) {
  287. Log.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);
  288. e.printStackTrace();
  289. } finally {
  290. if (filepath == null) {
  291. Log.e("FileDisplay", "Couldnt resolve path to file");
  292. Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);
  293. t.show();
  294. return;
  295. }
  296. }
  297. Intent i = new Intent(this, FileUploader.class);
  298. i.putExtra(FileUploader.KEY_ACCOUNT,
  299. AccountUtils.getCurrentOwnCloudAccount(this));
  300. String remotepath = new String();
  301. for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
  302. remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
  303. }
  304. if (!remotepath.endsWith(OCFile.PATH_SEPARATOR))
  305. remotepath += OCFile.PATH_SEPARATOR;
  306. remotepath += new File(filepath).getName();
  307. i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath);
  308. i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath);
  309. i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
  310. startService(i);
  311. }
  312. @Override
  313. public void onBackPressed() {
  314. if (mDirectories.getCount() <= 1) {
  315. finish();
  316. return;
  317. }
  318. popDirname();
  319. mFileList.onNavigateUp();
  320. mCurrentDir = mFileList.getCurrentFile();
  321. if (mDualPane) {
  322. // Resets the FileDetailsFragment on Tablets so that it always displays
  323. FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
  324. if (fileDetails != null && !fileDetails.isEmpty()) {
  325. FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
  326. transaction.remove(fileDetails);
  327. transaction.add(R.id.file_details_container, new FileDetailFragment(null, null));
  328. transaction.commit();
  329. }
  330. }
  331. if(mCurrentDir.getParentId() == 0){
  332. ActionBar actionBar = getSupportActionBar();
  333. actionBar.setDisplayHomeAsUpEnabled(false);
  334. }
  335. }
  336. @Override
  337. protected void onSaveInstanceState(Bundle outState) {
  338. // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
  339. Log.d(getClass().toString(), "onSaveInstanceState() start");
  340. super.onSaveInstanceState(outState);
  341. outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir);
  342. Log.d(getClass().toString(), "onSaveInstanceState() end");
  343. }
  344. @Override
  345. protected void onResume() {
  346. Log.d(getClass().toString(), "onResume() start");
  347. super.onResume();
  348. if (AccountUtils.accountsAreSetup(this)) {
  349. if (mStorageManager == null) {
  350. // this is necessary for handling the come back to FileDisplayActivity when the first ownCloud account is created
  351. initDataFromCurrentAccount();
  352. }
  353. // Listen for sync messages
  354. IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE);
  355. mSyncBroadcastReceiver = new SyncBroadcastReceiver();
  356. registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
  357. // Listen for upload messages
  358. IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
  359. mUploadFinishReceiver = new UploadFinishReceiver();
  360. registerReceiver(mUploadFinishReceiver, uploadIntentFilter);
  361. // Listen for download messages
  362. IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
  363. mDownloadFinishReceiver = new DownloadFinishReceiver();
  364. registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
  365. // List current directory
  366. mFileList.listDirectory(mCurrentDir);
  367. } else {
  368. mStorageManager = null; // an invalid object will be there if all the ownCloud accounts are removed
  369. showDialog(DIALOG_SETUP_ACCOUNT);
  370. }
  371. Log.d(getClass().toString(), "onResume() end");
  372. }
  373. @Override
  374. protected void onPause() {
  375. Log.d(getClass().toString(), "onPause() start");
  376. super.onPause();
  377. if (mSyncBroadcastReceiver != null) {
  378. unregisterReceiver(mSyncBroadcastReceiver);
  379. mSyncBroadcastReceiver = null;
  380. }
  381. if (mUploadFinishReceiver != null) {
  382. unregisterReceiver(mUploadFinishReceiver);
  383. mUploadFinishReceiver = null;
  384. }
  385. if (mDownloadFinishReceiver != null) {
  386. unregisterReceiver(mDownloadFinishReceiver);
  387. mDownloadFinishReceiver = null;
  388. }
  389. if (!AccountUtils.accountsAreSetup(this)) {
  390. dismissDialog(DIALOG_SETUP_ACCOUNT);
  391. }
  392. getIntent().putExtra(FileDetailFragment.EXTRA_FILE, mCurrentDir);
  393. Log.d(getClass().toString(), "onPause() end");
  394. }
  395. @Override
  396. protected Dialog onCreateDialog(int id) {
  397. Dialog dialog = null;
  398. AlertDialog.Builder builder;
  399. switch (id) {
  400. case DIALOG_SETUP_ACCOUNT: {
  401. builder = new AlertDialog.Builder(this);
  402. builder.setTitle(R.string.main_tit_accsetup);
  403. builder.setMessage(R.string.main_wrn_accsetup);
  404. builder.setCancelable(false);
  405. builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
  406. public void onClick(DialogInterface dialog, int which) {
  407. createFirstAccount();
  408. dialog.dismiss();
  409. }
  410. });
  411. builder.setNegativeButton(R.string.common_exit, new OnClickListener() {
  412. public void onClick(DialogInterface dialog, int which) {
  413. dialog.dismiss();
  414. finish();
  415. }
  416. });
  417. //builder.setNegativeButton(android.R.string.cancel, this);
  418. dialog = builder.create();
  419. break;
  420. }
  421. case DIALOG_ABOUT_APP: {
  422. builder = new AlertDialog.Builder(this);
  423. builder.setTitle(getString(R.string.about_title));
  424. PackageInfo pkg;
  425. try {
  426. pkg = getPackageManager().getPackageInfo(getPackageName(), 0);
  427. builder.setMessage("ownCloud android client\n\nversion: " + pkg.versionName );
  428. builder.setIcon(android.R.drawable.ic_menu_info_details);
  429. dialog = builder.create();
  430. } catch (NameNotFoundException e) {
  431. builder = null;
  432. dialog = null;
  433. Log.e(TAG, "Error while showing about dialog", e);
  434. }
  435. break;
  436. }
  437. case DIALOG_CREATE_DIR: {
  438. builder = new Builder(this);
  439. final EditText dirNameInput = new EditText(getBaseContext());
  440. builder.setView(dirNameInput);
  441. builder.setTitle(R.string.uploader_info_dirname);
  442. int typed_color = getResources().getColor(R.color.setup_text_typed);
  443. dirNameInput.setTextColor(typed_color);
  444. builder.setPositiveButton(android.R.string.ok,
  445. new OnClickListener() {
  446. public void onClick(DialogInterface dialog, int which) {
  447. String directoryName = dirNameInput.getText().toString();
  448. if (directoryName.trim().length() == 0) {
  449. dialog.cancel();
  450. return;
  451. }
  452. // Figure out the path where the dir needs to be created
  453. String path;
  454. if (mCurrentDir == null) {
  455. // this is just a patch; we should ensure that mCurrentDir never is null
  456. if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {
  457. OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
  458. mStorageManager.saveFile(file);
  459. }
  460. mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
  461. }
  462. path = FileDisplayActivity.this.mCurrentDir.getRemotePath();
  463. // Create directory
  464. path += directoryName + OCFile.PATH_SEPARATOR;
  465. Thread thread = new Thread(new DirectoryCreator(path, AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
  466. thread.start();
  467. dialog.dismiss();
  468. showDialog(DIALOG_SHORT_WAIT);
  469. }
  470. });
  471. builder.setNegativeButton(R.string.common_cancel,
  472. new OnClickListener() {
  473. public void onClick(DialogInterface dialog, int which) {
  474. dialog.cancel();
  475. }
  476. });
  477. dialog = builder.create();
  478. break;
  479. }
  480. case DIALOG_SHORT_WAIT: {
  481. ProgressDialog working_dialog = new ProgressDialog(this);
  482. working_dialog.setMessage(getResources().getString(
  483. R.string.wait_a_moment));
  484. working_dialog.setIndeterminate(true);
  485. working_dialog.setCancelable(false);
  486. dialog = working_dialog;
  487. break;
  488. }
  489. case DIALOG_CHOOSE_UPLOAD_SOURCE: {
  490. final String [] items = { getString(R.string.actionbar_upload_files),
  491. getString(R.string.actionbar_upload_from_apps) };
  492. builder = new AlertDialog.Builder(this);
  493. builder.setTitle(R.string.actionbar_upload);
  494. builder.setItems(items, new DialogInterface.OnClickListener() {
  495. public void onClick(DialogInterface dialog, int item) {
  496. if (item == 0) {
  497. //if (!mDualPane) {
  498. Intent action = new Intent(FileDisplayActivity.this, UploadFilesActivity.class);
  499. startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);
  500. //} else {
  501. // TODO create and handle new fragment LocalFileListFragment
  502. //}
  503. } else if (item == 1) {
  504. Intent action = new Intent(Intent.ACTION_GET_CONTENT);
  505. action = action.setType("*/*")
  506. .addCategory(Intent.CATEGORY_OPENABLE);
  507. startActivityForResult(
  508. Intent.createChooser(action, getString(R.string.upload_chooser_title)),
  509. ACTION_SELECT_CONTENT_FROM_APPS);
  510. }
  511. }
  512. });
  513. dialog = builder.create();
  514. break;
  515. }
  516. default:
  517. dialog = null;
  518. }
  519. return dialog;
  520. }
  521. /**
  522. * Translates a content URI of an image to a physical path
  523. * on the disk
  524. * @param uri The URI to resolve
  525. * @return The path to the image or null if it could not be found
  526. */
  527. public String getPath(Uri uri) {
  528. String[] projection = { MediaStore.Images.Media.DATA };
  529. Cursor cursor = managedQuery(uri, projection, null, null, null);
  530. if (cursor != null) {
  531. int column_index = cursor
  532. .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
  533. cursor.moveToFirst();
  534. return cursor.getString(column_index);
  535. }
  536. return null;
  537. }
  538. /**
  539. * Pushes a directory to the drop down list
  540. * @param directory to push
  541. * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false.
  542. */
  543. public void pushDirname(OCFile directory) {
  544. if(!directory.isDirectory()){
  545. throw new IllegalArgumentException("Only directories may be pushed!");
  546. }
  547. mDirectories.insert(directory.getFileName(), 0);
  548. mCurrentDir = directory;
  549. }
  550. /**
  551. * Pops a directory name from the drop down list
  552. * @return True, unless the stack is empty
  553. */
  554. public boolean popDirname() {
  555. mDirectories.remove(mDirectories.getItem(0));
  556. return !mDirectories.isEmpty();
  557. }
  558. private class DirectoryCreator implements Runnable {
  559. private String mTargetPath;
  560. private Account mAccount;
  561. private AccountManager mAm;
  562. private Handler mHandler;
  563. public DirectoryCreator(String targetPath, Account account, Handler handler) {
  564. mTargetPath = targetPath;
  565. mAccount = account;
  566. mAm = (AccountManager) getSystemService(ACCOUNT_SERVICE);
  567. mHandler = handler;
  568. }
  569. @Override
  570. public void run() {
  571. WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());
  572. boolean created = wdc.createDirectory(mTargetPath);
  573. if (created) {
  574. mHandler.post(new Runnable() {
  575. @Override
  576. public void run() {
  577. dismissDialog(DIALOG_SHORT_WAIT);
  578. // Save new directory in local database
  579. OCFile newDir = new OCFile(mTargetPath);
  580. newDir.setMimetype("DIR");
  581. newDir.setParentId(mCurrentDir.getFileId());
  582. mStorageManager.saveFile(newDir);
  583. // Display the new folder right away
  584. mFileList.listDirectory(mCurrentDir);
  585. }
  586. });
  587. } else {
  588. mHandler.post(new Runnable() {
  589. @Override
  590. public void run() {
  591. dismissDialog(DIALOG_SHORT_WAIT);
  592. try {
  593. Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG);
  594. msg.show();
  595. } catch (NotFoundException e) {
  596. Log.e(TAG, "Error while trying to show fail message " , e);
  597. }
  598. }
  599. });
  600. }
  601. }
  602. }
  603. // Custom array adapter to override text colors
  604. private class CustomArrayAdapter<T> extends ArrayAdapter<T> {
  605. public CustomArrayAdapter(FileDisplayActivity ctx, int view) {
  606. super(ctx, view);
  607. }
  608. public View getView(int position, View convertView, ViewGroup parent) {
  609. View v = super.getView(position, convertView, parent);
  610. ((TextView) v).setTextColor(getResources().getColorStateList(
  611. android.R.color.white));
  612. return v;
  613. }
  614. public View getDropDownView(int position, View convertView,
  615. ViewGroup parent) {
  616. View v = super.getDropDownView(position, convertView, parent);
  617. ((TextView) v).setTextColor(getResources().getColorStateList(
  618. android.R.color.white));
  619. return v;
  620. }
  621. }
  622. private class SyncBroadcastReceiver extends BroadcastReceiver {
  623. /**
  624. * {@link BroadcastReceiver} to enable syncing feedback in UI
  625. */
  626. @Override
  627. public void onReceive(Context context, Intent intent) {
  628. boolean inProgress = intent.getBooleanExtra(
  629. FileSyncService.IN_PROGRESS, false);
  630. String accountName = intent
  631. .getStringExtra(FileSyncService.ACCOUNT_NAME);
  632. Log.d("FileDisplay", "sync of account " + accountName
  633. + " is in_progress: " + inProgress);
  634. if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) {
  635. String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH);
  636. boolean fillBlankRoot = false;
  637. if (mCurrentDir == null) {
  638. mCurrentDir = mStorageManager.getFileByPath("/");
  639. fillBlankRoot = (mCurrentDir != null);
  640. }
  641. if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath)))
  642. || fillBlankRoot ) {
  643. if (!fillBlankRoot)
  644. mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath);
  645. OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
  646. .findFragmentById(R.id.fileList);
  647. if (fileListFragment != null) {
  648. fileListFragment.listDirectory(mCurrentDir);
  649. }
  650. }
  651. setSupportProgressBarIndeterminateVisibility(inProgress);
  652. }
  653. }
  654. }
  655. private class UploadFinishReceiver extends BroadcastReceiver {
  656. /**
  657. * Once the file upload has finished -> update view
  658. * @author David A. Velasco
  659. * {@link BroadcastReceiver} to enable upload feedback in UI
  660. */
  661. @Override
  662. public void onReceive(Context context, Intent intent) {
  663. long parentDirId = intent.getLongExtra(FileUploader.EXTRA_PARENT_DIR_ID, -1);
  664. OCFile parentDir = mStorageManager.getFileById(parentDirId);
  665. String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
  666. if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) &&
  667. parentDir != null &&
  668. ( (mCurrentDir == null && parentDir.getFileName().equals("/")) ||
  669. parentDir.equals(mCurrentDir)
  670. )
  671. ) {
  672. OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
  673. if (fileListFragment != null) {
  674. fileListFragment.listDirectory();
  675. }
  676. }
  677. }
  678. }
  679. /**
  680. * Once the file download has finished -> update view
  681. */
  682. private class DownloadFinishReceiver extends BroadcastReceiver {
  683. @Override
  684. public void onReceive(Context context, Intent intent) {
  685. String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
  686. String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
  687. if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) &&
  688. mCurrentDir != null && mCurrentDir.getFileId() == mStorageManager.getFileByPath(downloadedRemotePath).getParentId()) {
  689. OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
  690. if (fileListFragment != null) {
  691. fileListFragment.listDirectory();
  692. }
  693. }
  694. }
  695. }
  696. /**
  697. * {@inheritDoc}
  698. */
  699. @Override
  700. public DataStorageManager getStorageManager() {
  701. return mStorageManager;
  702. }
  703. /**
  704. * {@inheritDoc}
  705. */
  706. @Override
  707. public void onDirectoryClick(OCFile directory) {
  708. pushDirname(directory);
  709. ActionBar actionBar = getSupportActionBar();
  710. actionBar.setDisplayHomeAsUpEnabled(true);
  711. if (mDualPane) {
  712. // Resets the FileDetailsFragment on Tablets so that it always displays
  713. FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
  714. if (fileDetails != null && !fileDetails.isEmpty()) {
  715. FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
  716. transaction.remove(fileDetails);
  717. transaction.add(R.id.file_details_container, new FileDetailFragment(null, null));
  718. transaction.commit();
  719. }
  720. }
  721. }
  722. /**
  723. * {@inheritDoc}
  724. */
  725. @Override
  726. public void onFileClick(OCFile file) {
  727. // If we are on a large device -> update fragment
  728. if (mDualPane) {
  729. // buttons in the details view are problematic when trying to reuse an existing fragment; create always a new one solves some of them, BUT no all; downloads are 'dangerous'
  730. FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
  731. transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
  732. transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
  733. transaction.commit();
  734. } else { // small or medium screen device -> new Activity
  735. Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
  736. showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
  737. showDetailsIntent.putExtra(FileDownloader.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
  738. startActivity(showDetailsIntent);
  739. }
  740. }
  741. /**
  742. * {@inheritDoc}
  743. */
  744. @Override
  745. public void onFileStateChanged() {
  746. OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
  747. if (fileListFragment != null) {
  748. fileListFragment.listDirectory();
  749. }
  750. }
  751. /**
  752. * Launch an intent to request the PIN code to the user before letting him use the app
  753. */
  754. private void requestPinCode() {
  755. boolean pinStart = false;
  756. SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
  757. pinStart = appPrefs.getBoolean("set_pincode", false);
  758. if (pinStart) {
  759. Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
  760. i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity");
  761. startActivity(i);
  762. }
  763. }
  764. }