PreviewTextFragment.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * Copyright (C) 2016 ownCloud Inc.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2,
  8. * as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package com.owncloud.android.ui.preview;
  20. import android.accounts.Account;
  21. import android.os.AsyncTask;
  22. import android.os.Bundle;
  23. import android.support.v4.app.Fragment;
  24. import android.support.v4.app.FragmentManager;
  25. import android.support.v4.app.FragmentTransaction;
  26. import android.view.LayoutInflater;
  27. import android.view.Menu;
  28. import android.view.MenuInflater;
  29. import android.view.MenuItem;
  30. import android.view.View;
  31. import android.view.ViewGroup;
  32. import android.widget.TextView;
  33. import com.owncloud.android.R;
  34. import com.owncloud.android.datamodel.OCFile;
  35. import com.owncloud.android.files.FileMenuFilter;
  36. import com.owncloud.android.lib.common.utils.Log_OC;
  37. import com.owncloud.android.ui.activity.FileDisplayActivity;
  38. import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
  39. import com.owncloud.android.ui.dialog.LoadingDialog;
  40. import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
  41. import com.owncloud.android.ui.fragment.FileFragment;
  42. import java.io.BufferedWriter;
  43. import java.io.FileInputStream;
  44. import java.io.IOException;
  45. import java.io.StringWriter;
  46. import java.lang.ref.WeakReference;
  47. import java.util.LinkedList;
  48. import java.util.List;
  49. import java.util.Scanner;
  50. public class PreviewTextFragment extends FileFragment {
  51. private static final String EXTRA_FILE = "FILE";
  52. private static final String EXTRA_ACCOUNT = "ACCOUNT";
  53. private static final String TAG = PreviewTextFragment.class.getSimpleName();
  54. private Account mAccount;
  55. private TextView mTextPreview;
  56. private TextLoadAsyncTask mTextLoadTask;
  57. /**
  58. * Creates an empty fragment for previews.
  59. * <p/>
  60. * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically
  61. * (for instance, when the device is turned a aside).
  62. * <p/>
  63. * DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful
  64. * construction
  65. */
  66. public PreviewTextFragment() {
  67. super();
  68. mAccount = null;
  69. }
  70. /**
  71. * {@inheritDoc}
  72. */
  73. @Override
  74. public View onCreateView(LayoutInflater inflater, ViewGroup container,
  75. Bundle savedInstanceState) {
  76. super.onCreateView(inflater, container, savedInstanceState);
  77. Log_OC.e(TAG, "onCreateView");
  78. View ret = inflater.inflate(R.layout.text_file_preview, container, false);
  79. mTextPreview = (TextView) ret.findViewById(R.id.text_preview);
  80. return ret;
  81. }
  82. /**
  83. * {@inheritDoc}
  84. */
  85. @Override
  86. public void onCreate(Bundle savedInstanceState) {
  87. super.onCreate(savedInstanceState);
  88. OCFile file = getFile();
  89. Bundle args = getArguments();
  90. if (file == null) {
  91. file = args.getParcelable(FileDisplayActivity.EXTRA_FILE);
  92. }
  93. if (mAccount == null) {
  94. mAccount = args.getParcelable(FileDisplayActivity.EXTRA_ACCOUNT);
  95. }
  96. if (savedInstanceState == null) {
  97. if (file == null) {
  98. throw new IllegalStateException("Instanced with a NULL OCFile");
  99. }
  100. if (mAccount == null) {
  101. throw new IllegalStateException("Instanced with a NULL ownCloud Account");
  102. }
  103. } else {
  104. file = savedInstanceState.getParcelable(EXTRA_FILE);
  105. mAccount = savedInstanceState.getParcelable(EXTRA_ACCOUNT);
  106. }
  107. setFile(file);
  108. setHasOptionsMenu(true);
  109. }
  110. /**
  111. * {@inheritDoc}
  112. */
  113. @Override
  114. public void onSaveInstanceState(Bundle outState) {
  115. super.onSaveInstanceState(outState);
  116. outState.putParcelable(PreviewTextFragment.EXTRA_FILE, getFile());
  117. outState.putParcelable(PreviewTextFragment.EXTRA_ACCOUNT, mAccount);
  118. }
  119. @Override
  120. public void onStart() {
  121. super.onStart();
  122. Log_OC.e(TAG, "onStart");
  123. loadAndShowTextPreview();
  124. }
  125. private void loadAndShowTextPreview() {
  126. mTextLoadTask = new TextLoadAsyncTask(new WeakReference<TextView>(mTextPreview));
  127. mTextLoadTask.execute(getFile().getStoragePath());
  128. }
  129. /**
  130. * Reads the file to preview and shows its contents. Too critical to be anonymous.
  131. */
  132. private class TextLoadAsyncTask extends AsyncTask<Object, Void, StringWriter> {
  133. private final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
  134. private final WeakReference<TextView> mTextViewReference;
  135. private TextLoadAsyncTask(WeakReference<TextView> textView) {
  136. mTextViewReference = textView;
  137. }
  138. @Override
  139. protected void onPreExecute() {
  140. showLoadingDialog();
  141. }
  142. @Override
  143. protected StringWriter doInBackground(java.lang.Object... params) {
  144. if (params.length != 1) {
  145. throw new IllegalArgumentException("The parameter to " + TextLoadAsyncTask.class.getName() + " must be (1) the file location");
  146. }
  147. final String location = (String) params[0];
  148. FileInputStream inputStream = null;
  149. Scanner sc = null;
  150. StringWriter source = new StringWriter();
  151. BufferedWriter bufferedWriter = new BufferedWriter(source);
  152. try {
  153. inputStream = new FileInputStream(location);
  154. sc = new Scanner(inputStream);
  155. while (sc.hasNextLine()) {
  156. bufferedWriter.append(sc.nextLine());
  157. if (sc.hasNextLine()) bufferedWriter.append("\n");
  158. }
  159. bufferedWriter.close();
  160. IOException exc = sc.ioException();
  161. if (exc != null) throw exc;
  162. } catch (IOException e) {
  163. Log_OC.e(TAG, e.getMessage(), e);
  164. finish();
  165. } finally {
  166. if (inputStream != null) {
  167. try {
  168. inputStream.close();
  169. } catch (IOException e) {
  170. Log_OC.e(TAG, e.getMessage(), e);
  171. finish();
  172. }
  173. }
  174. if (sc != null) {
  175. sc.close();
  176. }
  177. }
  178. return source;
  179. }
  180. @Override
  181. protected void onPostExecute(final StringWriter stringWriter) {
  182. final TextView textView = mTextViewReference.get();
  183. if (textView != null) {
  184. textView.setText(new String(stringWriter.getBuffer()));
  185. textView.setVisibility(View.VISIBLE);
  186. }
  187. dismissLoadingDialog();
  188. }
  189. /**
  190. * Show loading dialog
  191. */
  192. public void showLoadingDialog() {
  193. // only once
  194. Fragment frag = getActivity().getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
  195. LoadingDialog loading = null;
  196. if (frag == null) {
  197. // Construct dialog
  198. loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment));
  199. FragmentManager fm = getActivity().getSupportFragmentManager();
  200. FragmentTransaction ft = fm.beginTransaction();
  201. loading.show(ft, DIALOG_WAIT_TAG);
  202. } else {
  203. loading = (LoadingDialog) frag;
  204. loading.setShowsDialog(true);
  205. }
  206. }
  207. /**
  208. * Dismiss loading dialog
  209. */
  210. public void dismissLoadingDialog() {
  211. final Fragment frag = getActivity().getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
  212. if (frag != null) {
  213. LoadingDialog loading = (LoadingDialog) frag;
  214. loading.dismiss();
  215. }
  216. }
  217. }
  218. /**
  219. * {@inheritDoc}
  220. */
  221. @Override
  222. public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
  223. super.onCreateOptionsMenu(menu, inflater);
  224. inflater.inflate(R.menu.file_actions_menu, menu);
  225. }
  226. /**
  227. * {@inheritDoc}
  228. */
  229. @Override
  230. public void onPrepareOptionsMenu(Menu menu) {
  231. super.onPrepareOptionsMenu(menu);
  232. if (mContainerActivity.getStorageManager() != null) {
  233. FileMenuFilter mf = new FileMenuFilter(
  234. getFile(),
  235. mContainerActivity.getStorageManager().getAccount(),
  236. mContainerActivity,
  237. getActivity()
  238. );
  239. mf.filter(menu);
  240. }
  241. // additional restriction for this fragment
  242. MenuItem item = menu.findItem(R.id.action_rename_file);
  243. if (item != null) {
  244. item.setVisible(false);
  245. item.setEnabled(false);
  246. }
  247. // additional restriction for this fragment
  248. item = menu.findItem(R.id.action_move);
  249. if (item != null) {
  250. item.setVisible(false);
  251. item.setEnabled(false);
  252. }
  253. // this one doesn't make sense since the file has to be down in order to be previewed
  254. item = menu.findItem(R.id.action_download_file);
  255. if (item != null) {
  256. item.setVisible(false);
  257. item.setEnabled(false);
  258. }
  259. item = menu.findItem(R.id.action_sync_file);
  260. if (item != null) {
  261. item.setVisible(false);
  262. item.setEnabled(false);
  263. }
  264. item = menu.findItem(R.id.action_sync_account);
  265. if (item != null) {
  266. item.setVisible(false);
  267. item.setEnabled(false);
  268. }
  269. Boolean dualPane = getResources().getBoolean(R.bool.large_land_layout);
  270. item = menu.findItem(R.id.action_switch_view);
  271. if (item != null && !dualPane){
  272. item.setVisible(false);
  273. item.setEnabled(false);
  274. }
  275. item = menu.findItem(R.id.action_sort);
  276. if (item != null && !dualPane) {
  277. item.setVisible(false);
  278. item.setEnabled(false);
  279. }
  280. }
  281. /**
  282. * {@inheritDoc}
  283. */
  284. @Override
  285. public boolean onOptionsItemSelected(MenuItem item) {
  286. switch (item.getItemId()) {
  287. case R.id.action_share_file: {
  288. mContainerActivity.getFileOperationsHelper().showShareFile(getFile());
  289. return true;
  290. }
  291. case R.id.action_open_file_with: {
  292. openFile();
  293. return true;
  294. }
  295. case R.id.action_remove_file: {
  296. RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
  297. dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
  298. return true;
  299. }
  300. case R.id.action_see_details: {
  301. seeDetails();
  302. return true;
  303. }
  304. case R.id.action_send_file: {
  305. sendFile();
  306. return true;
  307. }
  308. case R.id.action_sync_file: {
  309. mContainerActivity.getFileOperationsHelper().syncFile(getFile());
  310. return true;
  311. }
  312. default:
  313. return false;
  314. }
  315. }
  316. /**
  317. * Update the file of the fragment with file value
  318. *
  319. * @param file The new file to set
  320. */
  321. public void updateFile(OCFile file) {
  322. setFile(file);
  323. }
  324. private void sendFile() {
  325. mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
  326. }
  327. private void seeDetails() {
  328. mContainerActivity.showDetails(getFile());
  329. }
  330. @Override
  331. public void onPause() {
  332. Log_OC.e(TAG, "onPause");
  333. super.onPause();
  334. }
  335. @Override
  336. public void onResume() {
  337. super.onResume();
  338. Log_OC.e(TAG, "onResume");
  339. }
  340. @Override
  341. public void onDestroy() {
  342. Log_OC.e(TAG, "onDestroy");
  343. super.onDestroy();
  344. }
  345. @Override
  346. public void onStop() {
  347. super.onStop();
  348. Log_OC.e(TAG, "onStop");
  349. if (mTextLoadTask != null) {
  350. mTextLoadTask.cancel(Boolean.TRUE);
  351. mTextLoadTask.dismissLoadingDialog();
  352. }
  353. }
  354. /**
  355. * Opens the previewed file with an external application.
  356. */
  357. private void openFile() {
  358. mContainerActivity.getFileOperationsHelper().openFile(getFile());
  359. finish();
  360. }
  361. /**
  362. * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewTextFragment} to be previewed.
  363. *
  364. * @param file File to test if can be previewed.
  365. * @return 'True' if the file can be handled by the fragment.
  366. */
  367. public static boolean canBePreviewed(OCFile file) {
  368. final List<String> unsupportedTypes = new LinkedList<String>();
  369. unsupportedTypes.add("text/richtext");
  370. unsupportedTypes.add("text/rtf");
  371. unsupportedTypes.add("text/vnd.abc");
  372. unsupportedTypes.add("text/vnd.fmi.flexstor");
  373. unsupportedTypes.add("text/vnd.rn-realtext");
  374. unsupportedTypes.add("text/vnd.wap.wml");
  375. unsupportedTypes.add("text/vnd.wap.wmlscript");
  376. return (file != null && file.isDown() && file.isText() &&
  377. !unsupportedTypes.contains(file.getMimetype()) &&
  378. !unsupportedTypes.contains(file.getMimeTypeFromName())
  379. );
  380. }
  381. /**
  382. * Finishes the preview
  383. */
  384. private void finish() {
  385. getActivity().runOnUiThread(new Runnable() {
  386. @Override
  387. public void run() {
  388. getActivity().onBackPressed();
  389. }
  390. });
  391. }
  392. }