Disable On Device option in Navigation Drawer
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / activity / FileDisplayActivity.java
1 /**
2 * ownCloud Android client application
3 *
4 * @author Bartek Przybylski
5 * @author David A. Velasco
6 * Copyright (C) 2011 Bartek Przybylski
7 * Copyright (C) 2015 ownCloud Inc.
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2,
11 * as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 package com.owncloud.android.ui.activity;
24
25 import java.io.File;
26
27 import android.accounts.Account;
28 import android.accounts.AccountManager;
29 import android.accounts.AuthenticatorException;
30 import android.accounts.OperationCanceledException;
31 import android.annotation.TargetApi;
32 import android.app.AlertDialog;
33 import android.content.BroadcastReceiver;
34 import android.content.ComponentName;
35 import android.content.ContentResolver;
36 import android.content.Context;
37 import android.content.DialogInterface;
38 import android.content.Intent;
39 import android.content.IntentFilter;
40 import android.content.ServiceConnection;
41 import android.content.SharedPreferences;
42 import android.content.SyncRequest;
43 import android.content.res.Configuration;
44 import android.content.res.Resources.NotFoundException;
45 import android.database.Cursor;
46 import android.net.Uri;
47 import android.os.Build;
48 import android.os.Bundle;
49 import android.os.IBinder;
50 import android.preference.PreferenceManager;
51 import android.provider.OpenableColumns;
52 import android.support.v4.app.ActionBarDrawerToggle;
53 import android.support.v4.app.Fragment;
54 import android.support.v4.app.FragmentManager;
55 import android.support.v4.app.FragmentTransaction;
56 import android.support.v4.view.GravityCompat;
57 import android.support.v4.widget.DrawerLayout;
58 import android.util.Log;
59 import android.view.View;
60 import android.view.ViewGroup;
61 import android.widget.AdapterView;
62 import android.widget.AdapterView.OnItemClickListener;
63 import android.widget.ArrayAdapter;
64 import android.widget.ImageView;
65 import android.widget.LinearLayout;
66 import android.widget.ListView;
67 import android.widget.TextView;
68 import android.widget.Toast;
69
70 import com.actionbarsherlock.app.ActionBar;
71 import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
72 import com.actionbarsherlock.view.Menu;
73 import com.actionbarsherlock.view.MenuInflater;
74 import com.actionbarsherlock.view.MenuItem;
75 import com.actionbarsherlock.view.Window;
76 import com.owncloud.android.MainApp;
77 import com.owncloud.android.R;
78 import com.owncloud.android.authentication.AccountUtils;
79 import com.owncloud.android.datamodel.OCFile;
80 import com.owncloud.android.files.services.FileDownloader;
81 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
82 import com.owncloud.android.files.services.FileUploader;
83 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
84 import com.owncloud.android.lib.common.OwnCloudAccount;
85 import com.owncloud.android.lib.common.OwnCloudClient;
86 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
87 import com.owncloud.android.lib.common.OwnCloudCredentials;
88 import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
89 import com.owncloud.android.lib.common.network.CertificateCombinedException;
90 import com.owncloud.android.lib.common.operations.RemoteOperation;
91 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
92 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
93 import com.owncloud.android.lib.common.utils.Log_OC;
94 import com.owncloud.android.operations.CreateFolderOperation;
95 import com.owncloud.android.operations.CreateShareOperation;
96 import com.owncloud.android.operations.MoveFileOperation;
97 import com.owncloud.android.operations.RemoveFileOperation;
98 import com.owncloud.android.operations.RenameFileOperation;
99 import com.owncloud.android.operations.SynchronizeFileOperation;
100 import com.owncloud.android.operations.RefreshFolderOperation;
101 import com.owncloud.android.operations.UnshareLinkOperation;
102 import com.owncloud.android.services.observer.FileObserverService;
103 import com.owncloud.android.syncadapter.FileSyncAdapter;
104 import com.owncloud.android.ui.adapter.FileListListAdapter;
105 import com.owncloud.android.ui.adapter.NavigationDrawerListAdapter;
106 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
107 import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
108 import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
109 import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
110 import com.owncloud.android.ui.dialog.UploadSourceDialogFragment;
111 import com.owncloud.android.ui.fragment.FileDetailFragment;
112 import com.owncloud.android.ui.fragment.FileFragment;
113 import com.owncloud.android.ui.fragment.OCFileListFragment;
114 import com.owncloud.android.ui.preview.PreviewImageActivity;
115 import com.owncloud.android.ui.preview.PreviewImageFragment;
116 import com.owncloud.android.ui.preview.PreviewMediaFragment;
117 import com.owncloud.android.ui.preview.PreviewVideoActivity;
118 import com.owncloud.android.utils.DisplayUtils;
119 import com.owncloud.android.utils.ErrorMessageAdapter;
120 import com.owncloud.android.utils.FileStorageUtils;
121 import com.owncloud.android.utils.UriUtils;
122
123
124 /**
125 * Displays, what files the user has available in his ownCloud.
126 */
127
128 public class FileDisplayActivity extends HookActivity implements
129 FileFragment.ContainerActivity, OnNavigationListener,
130 OnSslUntrustedCertListener, OnEnforceableRefreshListener {
131
132 private ArrayAdapter<String> mDirectories;
133
134 private SyncBroadcastReceiver mSyncBroadcastReceiver;
135 private UploadFinishReceiver mUploadFinishReceiver;
136 private DownloadFinishReceiver mDownloadFinishReceiver;
137 private RemoteOperationResult mLastSslUntrustedServerResult = null;
138
139 private boolean mDualPane;
140 private View mLeftFragmentContainer;
141 private View mRightFragmentContainer;
142
143 private static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
144 private static final String KEY_SYNC_IN_PROGRESS = "SYNC_IN_PROGRESS";
145 private static final String KEY_WAITING_TO_SEND = "WAITING_TO_SEND";
146
147 public static final String ACTION_DETAILS = "com.owncloud.android.ui.activity.action.DETAILS";
148
149 public static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
150 public static final int ACTION_SELECT_MULTIPLE_FILES = 2;
151 public static final int ACTION_MOVE_FILES = 3;
152
153 private static final String TAG = FileDisplayActivity.class.getSimpleName();
154
155 private static final String TAG_LIST_OF_FILES = "LIST_OF_FILES";
156 private static final String TAG_SECOND_FRAGMENT = "SECOND_FRAGMENT";
157
158 private OCFile mWaitingToPreview;
159
160 private boolean mSyncInProgress = false;
161
162 private static String DIALOG_UNTRUSTED_CERT = "DIALOG_UNTRUSTED_CERT";
163 private static String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER";
164 private static String DIALOG_UPLOAD_SOURCE = "DIALOG_UPLOAD_SOURCE";
165 private static String DIALOG_CERT_NOT_SAVED = "DIALOG_CERT_NOT_SAVED";
166
167 private NavigationDrawerListAdapter adapter = null;
168
169 private OCFile mWaitingToSend;
170
171 private DrawerLayout mDrawerLayout;
172 private ActionBarDrawerToggle mDrawerToggle;
173 private boolean showAccounts = false;
174
175 @Override
176 protected void onCreate(Bundle savedInstanceState) {
177 Log_OC.v(TAG, "onCreate() start");
178 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
179
180 super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account is valid
181
182 /// grant that FileObserverService is watching favorite files
183 if (savedInstanceState == null) {
184 Intent initObserversIntent = FileObserverService.makeInitIntent(this);
185 startService(initObserversIntent);
186 }
187
188 /// Load of saved instance state
189 if(savedInstanceState != null) {
190 mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW);
191 mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS);
192 mWaitingToSend = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND);
193
194 } else {
195 mWaitingToPreview = null;
196 mSyncInProgress = false;
197 mWaitingToSend = null;
198 }
199
200 /// USER INTERFACE
201
202 // Inflate and set the layout view
203 setContentView(R.layout.files);
204
205 // TODO move to another place that all activity can use it
206 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
207
208 mDrawerToggle = new ActionBarDrawerToggle(
209 this,
210 mDrawerLayout,
211 R.drawable.ic_drawer,
212 R.string.drawer_open,
213 R.string.empty
214 ) {
215
216 /** Called when a drawer has settled in a completely closed state. */
217 public void onDrawerClosed(View view) {
218 super.onDrawerClosed(view);
219 getSupportActionBar().setDisplayShowTitleEnabled(true);
220 getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
221 initFragmentsWithFile();
222 invalidateOptionsMenu();
223 }
224
225 /** Called when a drawer has settled in a completely open state. */
226 public void onDrawerOpened(View drawerView) {
227 super.onDrawerOpened(drawerView);
228 getSupportActionBar().setTitle(R.string.drawer_open);
229 getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
230 invalidateOptionsMenu();
231 }
232 };
233
234 mDrawerToggle.setDrawerIndicatorEnabled(true);
235
236 // Notification Drawer
237 LinearLayout notificatonDrawer = (LinearLayout) findViewById(R.id.left_drawer);
238
239 // ListView
240 ListView listView = (ListView) notificatonDrawer.findViewById(R.id.drawer_list);
241 adapter = new NavigationDrawerListAdapter(getApplicationContext(), this);
242
243 listView.setAdapter(adapter);
244
245 listView.setOnItemClickListener(new OnItemClickListener() {
246 @Override
247 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
248 if (showAccounts && position > 0){
249 position = position - 1;
250 }
251 switch (position){
252 case 0:
253 showAccounts = !showAccounts;
254 adapter.setShowAccounts(showAccounts);
255 adapter.notifyDataSetChanged();
256 break;
257 case 1:
258 // TODO Enable when "On Device" is recovered ?
259 //MainApp.showOnlyFilesOnDevice(false);
260 mDrawerLayout.closeDrawers();
261 break;
262 // TODO Enable when "On Device" is recovered ?
263 // case 2:
264 // MainApp.showOnlyFilesOnDevice(true);
265 // mDrawerLayout.closeDrawers();
266 // break;
267 case 2:
268 Intent settingsIntent = new Intent(getApplicationContext(), Preferences.class);
269 startActivity(settingsIntent);
270 break;
271 }
272 }
273 });
274
275 // User-Icon
276 ImageView userIcon = (ImageView) notificatonDrawer.findViewById(R.id.drawer_userIcon);
277 userIcon.setImageResource(DisplayUtils.getSeasonalIconId());
278
279 // Username
280 TextView username = (TextView) notificatonDrawer.findViewById(R.id.drawer_username);
281 Account account = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
282
283 if (account != null) {
284 int lastAtPos = account.name.lastIndexOf("@");
285 username.setText(account.name.substring(0, lastAtPos));
286 }
287
288 // Set the drawer toggle as the DrawerListener
289 mDrawerLayout.setDrawerListener(mDrawerToggle);
290
291 mDualPane = getResources().getBoolean(R.bool.large_land_layout);
292 mLeftFragmentContainer = findViewById(R.id.left_fragment_container);
293 mRightFragmentContainer = findViewById(R.id.right_fragment_container);
294 if (savedInstanceState == null) {
295 createMinFragments();
296 }
297
298 // Action bar setup
299 mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
300 getSupportActionBar().setDisplayHomeAsUpEnabled(true);
301 getSupportActionBar().setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation
302 getSupportActionBar().setDisplayShowCustomEnabled(true); // CRUCIAL - for displaying your custom actionbar
303 getSupportActionBar().setDisplayShowTitleEnabled(true);
304 setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/); // always AFTER setContentView(...) ; to work around bug in its implementation
305
306 mDrawerToggle.syncState();
307
308 setBackgroundText();
309
310 Log_OC.v(TAG, "onCreate() end");
311 }
312
313 @Override
314 protected void onStart() {
315 Log_OC.v(TAG, "onStart() start");
316 super.onStart();
317 getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
318 Log_OC.v(TAG, "onStart() end");
319 }
320
321 @Override
322 protected void onPostCreate(Bundle savedInstanceState) {
323 super.onPostCreate(savedInstanceState);
324 // Sync the toggle state after onRestoreInstanceState has occurred.
325 mDrawerToggle.syncState();
326 }
327
328 @Override
329 public void onConfigurationChanged(Configuration newConfig) {
330 super.onConfigurationChanged(newConfig);
331 mDrawerToggle.onConfigurationChanged(newConfig);
332 }
333
334 @Override
335 protected void onDestroy() {
336 Log_OC.v(TAG, "onDestroy() start");
337 super.onDestroy();
338 Log_OC.v(TAG, "onDestroy() end");
339 }
340
341 /**
342 * Called when the ownCloud {@link Account} associated to the Activity was just updated.
343 */
344 @Override
345 protected void onAccountSet(boolean stateWasRecovered) {
346 super.onAccountSet(stateWasRecovered);
347 if (getAccount() != null) {
348 /// Check whether the 'main' OCFile handled by the Activity is contained in the current Account
349 OCFile file = getFile();
350 // get parent from path
351 String parentPath = "";
352 if (file != null) {
353 if (file.isDown() && file.getLastSyncDateForProperties() == 0) {
354 // upload in progress - right now, files are not inserted in the local cache until the upload is successful
355 // get parent from path
356 parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
357 if (getStorageManager().getFileByPath(parentPath) == null)
358 file = null; // not able to know the directory where the file is uploading
359 } else {
360 file = getStorageManager().getFileByPath(file.getRemotePath()); // currentDir = null if not in the current Account
361 }
362 }
363 if (file == null) {
364 // fall back to root folder
365 file = getStorageManager().getFileByPath(OCFile.ROOT_PATH); // never returns null
366 }
367 setFile(file);
368 setNavigationListWithFolder(file);
369
370 if (!stateWasRecovered) {
371 Log_OC.d(TAG, "Initializing Fragments in onAccountChanged..");
372 initFragmentsWithFile();
373 if (file.isFolder()) {
374 startSyncFolderOperation(file, false);
375 }
376
377 } else {
378 updateFragmentsVisibility(!file.isFolder());
379 updateNavigationElementsInActionBar(file.isFolder() ? null : file);
380 }
381 }
382 }
383
384
385 private void setNavigationListWithFolder(OCFile file) {
386 mDirectories.clear();
387 OCFile fileIt = file;
388 String parentPath;
389 while(fileIt != null && fileIt.getFileName() != OCFile.ROOT_PATH) {
390 if (fileIt.isFolder()) {
391 mDirectories.add(fileIt.getFileName());
392 }
393 // get parent from path
394 parentPath = fileIt.getRemotePath().substring(0, fileIt.getRemotePath().lastIndexOf(fileIt.getFileName()));
395 fileIt = getStorageManager().getFileByPath(parentPath);
396 }
397 mDirectories.add(OCFile.PATH_SEPARATOR);
398 }
399
400
401 private void createMinFragments() {
402 OCFileListFragment listOfFiles = new OCFileListFragment();
403 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
404 transaction.add(R.id.left_fragment_container, listOfFiles, TAG_LIST_OF_FILES);
405 transaction.commit();
406 }
407
408 private void initFragmentsWithFile() {
409 if (getAccount() != null && getFile() != null) {
410 /// First fragment
411 OCFileListFragment listOfFiles = getListOfFilesFragment();
412 if (listOfFiles != null) {
413 listOfFiles.listDirectory(getCurrentDir());
414 // TODO Enable when "On Device" is recovered
415 // listOfFiles.listDirectory(getCurrentDir(), MainApp.getOnlyOnDevice());
416 } else {
417 Log_OC.e(TAG, "Still have a chance to lose the initializacion of list fragment >(");
418 }
419
420 /// Second fragment
421 OCFile file = getFile();
422 Fragment secondFragment = chooseInitialSecondFragment(file);
423 if (secondFragment != null) {
424 setSecondFragment(secondFragment);
425 updateFragmentsVisibility(true);
426 updateNavigationElementsInActionBar(file);
427
428 } else {
429 cleanSecondFragment();
430 }
431
432 } else {
433 Log_OC.wtf(TAG, "initFragments() called with invalid NULLs!");
434 if (getAccount() == null) {
435 Log_OC.wtf(TAG, "\t account is NULL");
436 }
437 if (getFile() == null) {
438 Log_OC.wtf(TAG, "\t file is NULL");
439 }
440 }
441 }
442
443 private Fragment chooseInitialSecondFragment(OCFile file) {
444 Fragment secondFragment = null;
445 if (file != null && !file.isFolder()) {
446 if (file.isDown() && PreviewMediaFragment.canBePreviewed(file)
447 && file.getLastSyncDateForProperties() > 0 // temporal fix
448 ) {
449 int startPlaybackPosition = getIntent().getIntExtra(PreviewVideoActivity.EXTRA_START_POSITION, 0);
450 boolean autoplay = getIntent().getBooleanExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, true);
451 secondFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition, autoplay);
452
453 } else {
454 secondFragment = new FileDetailFragment(file, getAccount());
455 }
456 }
457 return secondFragment;
458 }
459
460
461 /**
462 * Replaces the second fragment managed by the activity with the received as
463 * a parameter.
464 *
465 * Assumes never will be more than two fragments managed at the same time.
466 *
467 * @param fragment New second Fragment to set.
468 */
469 private void setSecondFragment(Fragment fragment) {
470 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
471 transaction.replace(R.id.right_fragment_container, fragment, TAG_SECOND_FRAGMENT);
472 transaction.commit();
473 }
474
475
476 private void updateFragmentsVisibility(boolean existsSecondFragment) {
477 if (mDualPane) {
478 if (mLeftFragmentContainer.getVisibility() != View.VISIBLE) {
479 mLeftFragmentContainer.setVisibility(View.VISIBLE);
480 }
481 if (mRightFragmentContainer.getVisibility() != View.VISIBLE) {
482 mRightFragmentContainer.setVisibility(View.VISIBLE);
483 }
484
485 } else if (existsSecondFragment) {
486 if (mLeftFragmentContainer.getVisibility() != View.GONE) {
487 mLeftFragmentContainer.setVisibility(View.GONE);
488 }
489 if (mRightFragmentContainer.getVisibility() != View.VISIBLE) {
490 mRightFragmentContainer.setVisibility(View.VISIBLE);
491 }
492
493 } else {
494 if (mLeftFragmentContainer.getVisibility() != View.VISIBLE) {
495 mLeftFragmentContainer.setVisibility(View.VISIBLE);
496 }
497 if (mRightFragmentContainer.getVisibility() != View.GONE) {
498 mRightFragmentContainer.setVisibility(View.GONE);
499 }
500 }
501 }
502
503
504 private OCFileListFragment getListOfFilesFragment() {
505 Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_LIST_OF_FILES);
506 if (listOfFiles != null) {
507 return (OCFileListFragment)listOfFiles;
508 }
509 Log_OC.wtf(TAG, "Access to unexisting list of files fragment!!");
510 return null;
511 }
512
513 public FileFragment getSecondFragment() {
514 Fragment second = getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_SECOND_FRAGMENT);
515 if (second != null) {
516 return (FileFragment)second;
517 }
518 return null;
519 }
520
521 protected void cleanSecondFragment() {
522 Fragment second = getSecondFragment();
523 if (second != null) {
524 FragmentTransaction tr = getSupportFragmentManager().beginTransaction();
525 tr.remove(second);
526 tr.commit();
527 }
528 updateFragmentsVisibility(false);
529 updateNavigationElementsInActionBar(null);
530 }
531
532 protected void refreshListOfFilesFragment() {
533 OCFileListFragment fileListFragment = getListOfFilesFragment();
534 if (fileListFragment != null) {
535 fileListFragment.listDirectory();
536 // TODO Enable when "On Device" is recovered ?
537 // fileListFragment.listDirectory(MainApp.getOnlyOnDevice());
538 }
539 }
540
541 protected void refreshSecondFragment(String downloadEvent, String downloadedRemotePath, boolean success) {
542 FileFragment secondFragment = getSecondFragment();
543 boolean waitedPreview = (mWaitingToPreview != null && mWaitingToPreview.getRemotePath().equals(downloadedRemotePath));
544 if (secondFragment != null && secondFragment instanceof FileDetailFragment) {
545 FileDetailFragment detailsFragment = (FileDetailFragment) secondFragment;
546 OCFile fileInFragment = detailsFragment.getFile();
547 if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
548 // the user browsed to other file ; forget the automatic preview
549 mWaitingToPreview = null;
550
551 } else if (downloadEvent.equals(FileDownloader.getDownloadAddedMessage())) {
552 // grant that the right panel updates the progress bar
553 detailsFragment.listenForTransferProgress();
554 detailsFragment.updateFileDetails(true, false);
555
556 } else if (downloadEvent.equals(FileDownloader.getDownloadFinishMessage())) {
557 // update the right panel
558 boolean detailsFragmentChanged = false;
559 if (waitedPreview) {
560 if (success) {
561 mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); // update the file from database, for the local storage path
562 if (PreviewMediaFragment.canBePreviewed(mWaitingToPreview)) {
563 startMediaPreview(mWaitingToPreview, 0, true);
564 detailsFragmentChanged = true;
565 } else {
566 getFileOperationsHelper().openFile(mWaitingToPreview);
567 }
568 }
569 mWaitingToPreview = null;
570 }
571 if (!detailsFragmentChanged) {
572 detailsFragment.updateFileDetails(false, (success));
573 }
574 }
575 }
576 }
577
578 @Override
579 public boolean onPrepareOptionsMenu(Menu menu) {
580 boolean drawerOpen = mDrawerLayout.isDrawerOpen(GravityCompat.START);
581 menu.findItem(R.id.action_upload).setVisible(!drawerOpen);
582 menu.findItem(R.id.action_create_dir).setVisible(!drawerOpen);
583 menu.findItem(R.id.action_sort).setVisible(!drawerOpen);
584
585 return super.onPrepareOptionsMenu(menu);
586 }
587
588 @Override
589 public boolean onCreateOptionsMenu(Menu menu) {
590 MenuInflater inflater = getSherlock().getMenuInflater();
591 inflater.inflate(R.menu.main_menu, menu);
592 return true;
593 }
594
595
596 @Override
597 public boolean onOptionsItemSelected(MenuItem item) {
598 boolean retval = true;
599 switch (item.getItemId()) {
600 case R.id.action_create_dir: {
601 CreateFolderDialogFragment dialog = CreateFolderDialogFragment.newInstance(getCurrentDir());
602 dialog.show(getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
603 break;
604 }
605 case R.id.action_upload: {
606 UploadSourceDialogFragment dialog = UploadSourceDialogFragment.newInstance(getAccount());
607 dialog.show(getSupportFragmentManager(), DIALOG_UPLOAD_SOURCE);
608
609 break;
610 }
611 case android.R.id.home: {
612 if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
613 mDrawerLayout.closeDrawer(GravityCompat.START);
614 } else {
615 mDrawerLayout.openDrawer(GravityCompat.START);
616 }
617 // TODO add hamburger to left of android.R.id.home
618 break;
619 }
620 case R.id.action_sort: {
621 SharedPreferences appPreferences = PreferenceManager
622 .getDefaultSharedPreferences(this);
623
624 // Read sorting order, default to sort by name ascending
625 Integer sortOrder = appPreferences
626 .getInt("sortOrder", FileStorageUtils.SORT_NAME);
627
628 AlertDialog.Builder builder = new AlertDialog.Builder(this);
629 builder.setTitle(R.string.actionbar_sort_title)
630 .setSingleChoiceItems(R.array.actionbar_sortby, sortOrder , new DialogInterface.OnClickListener() {
631 public void onClick(DialogInterface dialog, int which) {
632
633 switch (which){
634 case 0:
635 sortByName(true);
636 break;
637 case 1:
638 sortByDate(false);
639 break;
640
641 }
642
643 dialog.dismiss();
644
645 }
646 });
647 builder.create().show();
648 break;
649 }
650 default:
651 retval = super.onOptionsItemSelected(item);
652 }
653 return retval;
654 }
655
656 private void startSynchronization() {
657 Log_OC.d(TAG, "Got to start sync");
658 if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
659 Log_OC.d(TAG, "Canceling all syncs for " + MainApp.getAuthority());
660 ContentResolver.cancelSync(null, MainApp.getAuthority()); // cancel the current synchronizations of any ownCloud account
661 Bundle bundle = new Bundle();
662 bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
663 bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
664 Log_OC.d(TAG, "Requesting sync for " + getAccount().name + " at " + MainApp.getAuthority());
665 ContentResolver.requestSync(
666 getAccount(),
667 MainApp.getAuthority(), bundle);
668 } else {
669 Log_OC.d(TAG, "Requesting sync for " + getAccount().name + " at " + MainApp.getAuthority() + " with new API");
670 SyncRequest.Builder builder = new SyncRequest.Builder();
671 builder.setSyncAdapter(getAccount(), MainApp.getAuthority());
672 builder.setExpedited(true);
673 builder.setManual(true);
674 builder.syncOnce();
675
676 // Fix bug in Android Lollipop when you click on refresh the whole account
677 Bundle extras = new Bundle();
678 builder.setExtras(extras);
679
680 SyncRequest request = builder.build();
681 ContentResolver.requestSync(request);
682 }
683 }
684
685
686 @Override
687 public boolean onNavigationItemSelected(int itemPosition, long itemId) {
688 if (itemPosition != 0) {
689 String targetPath = "";
690 for (int i=itemPosition; i < mDirectories.getCount() - 1; i++) {
691 targetPath = mDirectories.getItem(i) + OCFile.PATH_SEPARATOR + targetPath;
692 }
693 targetPath = OCFile.PATH_SEPARATOR + targetPath;
694 OCFile targetFolder = getStorageManager().getFileByPath(targetPath);
695 if (targetFolder != null) {
696 browseTo(targetFolder);
697 }
698
699 // the next operation triggers a new call to this method, but it's necessary to
700 // ensure that the name exposed in the action bar is the current directory when the
701 // user selected it in the navigation list
702 if (getSupportActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST && itemPosition != 0)
703 getSupportActionBar().setSelectedNavigationItem(0);
704 }
705 return true;
706 }
707
708 /**
709 * Called, when the user selected something for uploading
710 *
711 */
712 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
713 @Override
714 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
715
716 if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
717 //getClipData is only supported on api level 16+, Jelly Bean
718 if (data.getData() == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN){
719 for( int i = 0; i < data.getClipData().getItemCount(); i++){
720 Intent intent = new Intent();
721 intent.setData(data.getClipData().getItemAt(i).getUri());
722 requestSimpleUpload(intent, resultCode);
723 }
724 }else {
725 requestSimpleUpload(data, resultCode);
726 }
727 } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
728 requestMultipleUpload(data, resultCode);
729
730 } else if (requestCode == ACTION_MOVE_FILES && resultCode == RESULT_OK){
731
732 final Intent fData = data;
733 final int fResultCode = resultCode;
734 getHandler().postDelayed(
735 new Runnable() {
736 @Override
737 public void run() {
738 requestMoveOperation(fData, fResultCode);
739 }
740 },
741 DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
742 );
743
744 } else {
745 super.onActivityResult(requestCode, resultCode, data);
746 }
747
748 }
749
750 private void requestMultipleUpload(Intent data, int resultCode) {
751 String[] filePaths = data.getStringArrayExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES);
752 if (filePaths != null) {
753 String[] remotePaths = new String[filePaths.length];
754 String remotePathBase = "";
755
756 for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
757 remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
758 }
759 if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR))
760 remotePathBase += OCFile.PATH_SEPARATOR;
761 for (int j = 0; j< remotePaths.length; j++) {
762 remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName();
763 }
764
765 Intent i = new Intent(this, FileUploader.class);
766 i.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
767 i.putExtra(FileUploader.KEY_LOCAL_FILE, filePaths);
768 i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePaths);
769 i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
770 if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)
771 i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
772 startService(i);
773
774 } else {
775 Log_OC.d(TAG, "User clicked on 'Update' with no selection");
776 Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG);
777 t.show();
778 return;
779 }
780 }
781
782
783 private void requestSimpleUpload(Intent data, int resultCode) {
784 String filePath = null;
785 String mimeType = null;
786
787 Uri selectedImageUri = data.getData();
788
789 try {
790 mimeType = getContentResolver().getType(selectedImageUri);
791
792 String fileManagerString = selectedImageUri.getPath();
793 String selectedImagePath = UriUtils.getLocalPath(selectedImageUri, this);
794
795 if (selectedImagePath != null)
796 filePath = selectedImagePath;
797 else
798 filePath = fileManagerString;
799
800 } catch (Exception e) {
801 Log_OC.e(TAG, "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);
802
803 } finally {
804 if (filePath == null) {
805 Log_OC.e(TAG, "Couldn't resolve path to file");
806 Toast t = Toast.makeText(
807 this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG
808 );
809 t.show();
810 return;
811 }
812 }
813
814 Intent i = new Intent(this, FileUploader.class);
815 i.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
816 OCFile currentDir = getCurrentDir();
817 String remotePath = (currentDir != null) ? currentDir.getRemotePath() : OCFile.ROOT_PATH;
818
819 if (filePath.startsWith(UriUtils.URI_CONTENT_SCHEME)) {
820 Cursor cursor = getContentResolver().query(Uri.parse(filePath), null, null, null, null);
821 try {
822 if (cursor != null && cursor.moveToFirst()) {
823 String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
824 Log_OC.v(TAG, "Display Name: " + displayName );
825
826 displayName.replace(File.separatorChar, '_');
827 displayName.replace(File.pathSeparatorChar, '_');
828 remotePath += displayName + DisplayUtils.getComposedFileExtension(filePath);
829
830 }
831 // and what happens in case of error?; wrong target name for the upload
832 } finally {
833 cursor.close();
834 }
835
836 } else {
837 remotePath += new File(filePath).getName();
838 }
839
840 i.putExtra(FileUploader.KEY_LOCAL_FILE, filePath);
841 i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePath);
842 i.putExtra(FileUploader.KEY_MIME_TYPE, mimeType);
843 i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
844 if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)
845 i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
846 startService(i);
847 }
848
849 /**
850 * Request the operation for moving the file/folder from one path to another
851 *
852 * @param data Intent received
853 * @param resultCode Result code received
854 */
855 private void requestMoveOperation(Intent data, int resultCode) {
856 OCFile folderToMoveAt = (OCFile) data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER);
857 OCFile targetFile = (OCFile) data.getParcelableExtra(FolderPickerActivity.EXTRA_FILE);
858 getFileOperationsHelper().moveFile(folderToMoveAt, targetFile);
859 }
860
861 @Override
862 public void onBackPressed() {
863 OCFileListFragment listOfFiles = getListOfFilesFragment();
864 if (mDualPane || getSecondFragment() == null) {
865 if (listOfFiles != null) { // should never be null, indeed
866 if (mDirectories.getCount() <= 1) {
867 finish();
868 return;
869 }
870 int levelsUp = listOfFiles.onBrowseUp();
871 for (int i=0; i < levelsUp && mDirectories.getCount() > 1 ; i++) {
872 popDirname();
873 }
874 }
875 }
876 if (listOfFiles != null) { // should never be null, indeed
877 setFile(listOfFiles.getCurrentFile());
878 }
879 cleanSecondFragment();
880
881 }
882
883 @Override
884 protected void onSaveInstanceState(Bundle outState) {
885 // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
886 Log_OC.v(TAG, "onSaveInstanceState() start");
887 super.onSaveInstanceState(outState);
888 outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
889 outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress);
890 //outState.putBoolean(FileDisplayActivity.KEY_REFRESH_SHARES_IN_PROGRESS, mRefreshSharesInProgress);
891 outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND, mWaitingToSend);
892
893 Log_OC.v(TAG, "onSaveInstanceState() end");
894 }
895
896
897
898 @Override
899 protected void onResume() {
900 Log_OC.v(TAG, "onResume() start");
901 super.onResume();
902
903 // refresh Navigation Drawer account list
904 adapter.updateAccountList();
905
906 // refresh list of files
907 refreshListOfFilesFragment();
908
909 // Listen for sync messages
910 IntentFilter syncIntentFilter = new IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START);
911 syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_END);
912 syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED);
913 syncIntentFilter.addAction(RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED);
914 syncIntentFilter.addAction(RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
915 mSyncBroadcastReceiver = new SyncBroadcastReceiver();
916 registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
917 //LocalBroadcastManager.getInstance(this).registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
918
919 // Listen for upload messages
920 IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.getUploadFinishMessage());
921 mUploadFinishReceiver = new UploadFinishReceiver();
922 registerReceiver(mUploadFinishReceiver, uploadIntentFilter);
923
924 // Listen for download messages
925 IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.getDownloadAddedMessage());
926 downloadIntentFilter.addAction(FileDownloader.getDownloadFinishMessage());
927 mDownloadFinishReceiver = new DownloadFinishReceiver();
928 registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
929
930 Log_OC.v(TAG, "onResume() end");
931 }
932
933
934 @Override
935 protected void onPause() {
936 Log_OC.v(TAG, "onPause() start");
937 if (mSyncBroadcastReceiver != null) {
938 unregisterReceiver(mSyncBroadcastReceiver);
939 //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
940 mSyncBroadcastReceiver = null;
941 }
942 if (mUploadFinishReceiver != null) {
943 unregisterReceiver(mUploadFinishReceiver);
944 mUploadFinishReceiver = null;
945 }
946 if (mDownloadFinishReceiver != null) {
947 unregisterReceiver(mDownloadFinishReceiver);
948 mDownloadFinishReceiver = null;
949 }
950
951 super.onPause();
952 Log_OC.v(TAG, "onPause() end");
953 }
954
955 /**
956 * Pushes a directory to the drop down list
957 * @param directory to push
958 * @throws IllegalArgumentException If the {@link OCFile#isFolder()} returns false.
959 */
960 public void pushDirname(OCFile directory) {
961 if(!directory.isFolder()){
962 throw new IllegalArgumentException("Only directories may be pushed!");
963 }
964 mDirectories.insert(directory.getFileName(), 0);
965 setFile(directory);
966 }
967
968 /**
969 * Pops a directory name from the drop down list
970 * @return True, unless the stack is empty
971 */
972 public boolean popDirname() {
973 mDirectories.remove(mDirectories.getItem(0));
974 return !mDirectories.isEmpty();
975 }
976
977 // Custom array adapter to override text colors
978 private class CustomArrayAdapter<T> extends ArrayAdapter<T> {
979
980 public CustomArrayAdapter(FileDisplayActivity ctx, int view) {
981 super(ctx, view);
982 }
983
984 public View getView(int position, View convertView, ViewGroup parent) {
985 View v = super.getView(position, convertView, parent);
986
987 ((TextView) v).setTextColor(getResources().getColorStateList(
988 android.R.color.white));
989
990 fixRoot((TextView) v );
991 return v;
992 }
993
994 public View getDropDownView(int position, View convertView,
995 ViewGroup parent) {
996 View v = super.getDropDownView(position, convertView, parent);
997
998 ((TextView) v).setTextColor(getResources().getColorStateList(
999 android.R.color.white));
1000
1001 fixRoot((TextView) v );
1002 return v;
1003 }
1004
1005 private void fixRoot(TextView v) {
1006 if (v.getText().equals(OCFile.PATH_SEPARATOR)) {
1007 v.setText(R.string.default_display_name_for_root_folder);
1008 }
1009 }
1010
1011 }
1012
1013 private class SyncBroadcastReceiver extends BroadcastReceiver {
1014
1015 /**
1016 * {@link BroadcastReceiver} to enable syncing feedback in UI
1017 */
1018 @Override
1019 public void onReceive(Context context, Intent intent) {
1020 try {
1021 String event = intent.getAction();
1022 Log_OC.d(TAG, "Received broadcast " + event);
1023 String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME);
1024 String synchFolderRemotePath = intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH);
1025 RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncAdapter.EXTRA_RESULT);
1026 boolean sameAccount = (getAccount() != null && accountName.equals(getAccount().name) && getStorageManager() != null);
1027
1028 if (sameAccount) {
1029
1030 if (FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) {
1031 mSyncInProgress = true;
1032
1033 } else {
1034 OCFile currentFile = (getFile() == null) ? null : getStorageManager().getFileByPath(getFile().getRemotePath());
1035 OCFile currentDir = (getCurrentDir() == null) ? null : getStorageManager().getFileByPath(getCurrentDir().getRemotePath());
1036
1037 if (currentDir == null) {
1038 // current folder was removed from the server
1039 Toast.makeText( FileDisplayActivity.this,
1040 String.format(getString(R.string.sync_current_folder_was_removed), mDirectories.getItem(0)),
1041 Toast.LENGTH_LONG)
1042 .show();
1043 browseToRoot();
1044
1045 } else {
1046 if (currentFile == null && !getFile().isFolder()) {
1047 // currently selected file was removed in the server, and now we know it
1048 cleanSecondFragment();
1049 currentFile = currentDir;
1050 }
1051
1052 if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) {
1053 OCFileListFragment fileListFragment = getListOfFilesFragment();
1054 if (fileListFragment != null) {
1055 fileListFragment.listDirectory();
1056 // TODO Enable when "On Device" is recovered ?
1057 // fileListFragment.listDirectory(currentDir, MainApp.getOnlyOnDevice());
1058 }
1059 }
1060 setFile(currentFile);
1061 }
1062
1063 mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event));
1064
1065 if (RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
1066 equals(event) &&
1067 /// TODO refactor and make common
1068 synchResult != null && !synchResult.isSuccess() &&
1069 (synchResult.getCode() == ResultCode.UNAUTHORIZED ||
1070 synchResult.isIdPRedirection() ||
1071 (synchResult.isException() && synchResult.getException()
1072 instanceof AuthenticatorException))) {
1073
1074
1075 try {
1076 OwnCloudClient client;
1077 OwnCloudAccount ocAccount =
1078 new OwnCloudAccount(getAccount(), context);
1079 client = (OwnCloudClientManagerFactory.getDefaultSingleton().
1080 removeClientFor(ocAccount));
1081
1082 if (client != null) {
1083 OwnCloudCredentials cred = client.getCredentials();
1084 if (cred != null) {
1085 AccountManager am = AccountManager.get(context);
1086 if (cred.authTokenExpires()) {
1087 am.invalidateAuthToken(
1088 getAccount().type,
1089 cred.getAuthToken()
1090 );
1091 } else {
1092 am.clearPassword(getAccount());
1093 }
1094 }
1095 }
1096 requestCredentialsUpdate();
1097
1098 } catch (AccountNotFoundException e) {
1099 Log_OC.e(TAG, "Account " + getAccount() + " was removed!", e);
1100 }
1101
1102 }
1103 }
1104 removeStickyBroadcast(intent);
1105 Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
1106 setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/);
1107
1108 setBackgroundText();
1109
1110 }
1111
1112 if (synchResult != null) {
1113 if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
1114 mLastSslUntrustedServerResult = synchResult;
1115 }
1116 }
1117 } catch (RuntimeException e) {
1118 // avoid app crashes after changing the serial id of RemoteOperationResult
1119 // in owncloud library with broadcast notifications pending to process
1120 removeStickyBroadcast(intent);
1121 }
1122 }
1123 }
1124
1125 /**
1126 * Show a text message on screen view for notifying user if content is
1127 * loading or folder is empty
1128 */
1129 private void setBackgroundText() {
1130 OCFileListFragment ocFileListFragment = getListOfFilesFragment();
1131 if (ocFileListFragment != null) {
1132 int message = R.string.file_list_loading;
1133 if (!mSyncInProgress) {
1134 // In case file list is empty
1135 message = R.string.file_list_empty;
1136 }
1137 ocFileListFragment.setMessageForEmptyList(getString(message));
1138 } else {
1139 Log_OC.e(TAG, "OCFileListFragment is null");
1140 }
1141 }
1142
1143 /**
1144 * Once the file upload has finished -> update view
1145 */
1146 private class UploadFinishReceiver extends BroadcastReceiver {
1147 /**
1148 * Once the file upload has finished -> update view
1149 * @author David A. Velasco
1150 * {@link BroadcastReceiver} to enable upload feedback in UI
1151 */
1152 @Override
1153 public void onReceive(Context context, Intent intent) {
1154 try {
1155 String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
1156 String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
1157 boolean sameAccount = getAccount() != null && accountName.equals(getAccount().name);
1158 OCFile currentDir = getCurrentDir();
1159 boolean isDescendant = (currentDir != null) && (uploadedRemotePath != null) &&
1160 (uploadedRemotePath.startsWith(currentDir.getRemotePath()));
1161
1162 if (sameAccount && isDescendant) {
1163 refreshListOfFilesFragment();
1164 }
1165
1166 boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);
1167 boolean renamedInUpload = getFile().getRemotePath().
1168 equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));
1169 boolean sameFile = getFile().getRemotePath().equals(uploadedRemotePath) ||
1170 renamedInUpload;
1171 FileFragment details = getSecondFragment();
1172 boolean detailFragmentIsShown = (details != null &&
1173 details instanceof FileDetailFragment);
1174
1175 if (sameAccount && sameFile && detailFragmentIsShown) {
1176 if (uploadWasFine) {
1177 setFile(getStorageManager().getFileByPath(uploadedRemotePath));
1178 }
1179 if (renamedInUpload) {
1180 String newName = (new File(uploadedRemotePath)).getName();
1181 Toast msg = Toast.makeText(
1182 context,
1183 String.format(
1184 getString(R.string.filedetails_renamed_in_upload_msg),
1185 newName),
1186 Toast.LENGTH_LONG);
1187 msg.show();
1188 }
1189 if (uploadWasFine || getFile().fileExists()) {
1190 ((FileDetailFragment)details).updateFileDetails(false, true);
1191 } else {
1192 cleanSecondFragment();
1193 }
1194
1195 // Force the preview if the file is an image
1196 if (uploadWasFine && PreviewImageFragment.canBePreviewed(getFile())) {
1197 startImagePreview(getFile());
1198 } // TODO what about other kind of previews?
1199 }
1200
1201 } finally {
1202 if (intent != null) {
1203 removeStickyBroadcast(intent);
1204 }
1205 }
1206
1207 }
1208
1209 }
1210
1211
1212 /**
1213 * Class waiting for broadcast events from the {@link FileDownloader} service.
1214 *
1215 * Updates the UI when a download is started or finished, provided that it is relevant for the
1216 * current folder.
1217 */
1218 private class DownloadFinishReceiver extends BroadcastReceiver {
1219
1220 //int refreshCounter = 0;
1221 @Override
1222 public void onReceive(Context context, Intent intent) {
1223 try {
1224 boolean sameAccount = isSameAccount(context, intent);
1225 String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
1226 boolean isDescendant = isDescendant(downloadedRemotePath);
1227
1228 if (sameAccount && isDescendant) {
1229 String linkedToRemotePath = intent.getStringExtra(FileDownloader.EXTRA_LINKED_TO_PATH);
1230 if (linkedToRemotePath == null || isAscendant(linkedToRemotePath)) {
1231 //Log_OC.v(TAG, "refresh #" + ++refreshCounter);
1232 refreshListOfFilesFragment();
1233 }
1234 refreshSecondFragment(
1235 intent.getAction(),
1236 downloadedRemotePath,
1237 intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false)
1238 );
1239 }
1240
1241 if (mWaitingToSend != null) {
1242 mWaitingToSend = getStorageManager().getFileByPath(mWaitingToSend.getRemotePath());
1243 if (mWaitingToSend.isDown()) {
1244 sendDownloadedFile();
1245 }
1246 }
1247
1248 } finally {
1249 if (intent != null) {
1250 removeStickyBroadcast(intent);
1251 }
1252 }
1253 }
1254
1255 private boolean isDescendant(String downloadedRemotePath) {
1256 OCFile currentDir = getCurrentDir();
1257 return (
1258 currentDir != null &&
1259 downloadedRemotePath != null &&
1260 downloadedRemotePath.startsWith(currentDir.getRemotePath())
1261 );
1262 }
1263
1264 private boolean isAscendant(String linkedToRemotePath) {
1265 OCFile currentDir = getCurrentDir();
1266 return (
1267 currentDir != null &&
1268 currentDir.getRemotePath().startsWith(linkedToRemotePath)
1269 );
1270 }
1271
1272 private boolean isSameAccount(Context context, Intent intent) {
1273 String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
1274 return (accountName != null && getAccount() != null && accountName.equals(getAccount().name));
1275 }
1276 }
1277
1278
1279 public void browseToRoot() {
1280 OCFileListFragment listOfFiles = getListOfFilesFragment();
1281 if (listOfFiles != null) { // should never be null, indeed
1282 while (mDirectories.getCount() > 1) {
1283 popDirname();
1284 }
1285 OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
1286 listOfFiles.listDirectory(root);
1287 // TODO Enable when "On Device" is recovered ?
1288 // listOfFiles.listDirectory(root, MainApp.getOnlyOnDevice());
1289 setFile(listOfFiles.getCurrentFile());
1290 startSyncFolderOperation(root, false);
1291 }
1292 cleanSecondFragment();
1293 }
1294
1295
1296 public void browseTo(OCFile folder) {
1297 if (folder == null || !folder.isFolder()) {
1298 throw new IllegalArgumentException("Trying to browse to invalid folder " + folder);
1299 }
1300 OCFileListFragment listOfFiles = getListOfFilesFragment();
1301 if (listOfFiles != null) {
1302 setNavigationListWithFolder(folder);
1303 listOfFiles.listDirectory(folder);
1304 // TODO Enable when "On Device" is recovered ?
1305 // listOfFiles.listDirectory(folder, MainApp.getOnlyOnDevice());
1306 setFile(listOfFiles.getCurrentFile());
1307 startSyncFolderOperation(folder, false);
1308 } else {
1309 Log_OC.e(TAG, "Unexpected null when accessing list fragment");
1310 }
1311 cleanSecondFragment();
1312 }
1313
1314
1315 /**
1316 * {@inheritDoc}
1317 *
1318 * Updates action bar and second fragment, if in dual pane mode.
1319 */
1320 @Override
1321 public void onBrowsedDownTo(OCFile directory) {
1322 pushDirname(directory);
1323 cleanSecondFragment();
1324
1325 // Sync Folder
1326 startSyncFolderOperation(directory, false);
1327
1328 }
1329
1330 /**
1331 * Shows the information of the {@link OCFile} received as a
1332 * parameter in the second fragment.
1333 *
1334 * @param file {@link OCFile} whose details will be shown
1335 */
1336 @Override
1337 public void showDetails(OCFile file) {
1338 Fragment detailFragment = new FileDetailFragment(file, getAccount());
1339 setSecondFragment(detailFragment);
1340 updateFragmentsVisibility(true);
1341 updateNavigationElementsInActionBar(file);
1342 setFile(file);
1343 }
1344
1345
1346 /**
1347 * TODO
1348 */
1349 private void updateNavigationElementsInActionBar(OCFile chosenFile) {
1350 ActionBar actionBar = getSupportActionBar();
1351
1352 // For adding content description tag to a title field in the action bar
1353 int actionBarTitleId = getResources().getIdentifier("action_bar_title", "id", "android");
1354
1355 if (chosenFile == null || mDualPane) {
1356 // only list of files - set for browsing through folders
1357 OCFile currentDir = getCurrentDir();
1358 boolean noRoot = (currentDir != null && currentDir.getParentId() != 0);
1359 // actionBar.setDisplayHomeAsUpEnabled(noRoot);
1360 // actionBar.setDisplayShowTitleEnabled(!noRoot);
1361 actionBar.setDisplayHomeAsUpEnabled(true);
1362 actionBar.setDisplayShowTitleEnabled(true);
1363 if (!noRoot) {
1364 actionBar.setTitle(getString(R.string.default_display_name_for_root_folder));
1365 View actionBarTitleView = getWindow().getDecorView().findViewById(actionBarTitleId);
1366 if (actionBarTitleView != null) { // it's null in Android 2.x
1367 actionBarTitleView.setContentDescription(getString(R.string.default_display_name_for_root_folder));
1368 }
1369 }
1370 actionBar.setNavigationMode(!noRoot ? ActionBar.NAVIGATION_MODE_STANDARD : ActionBar.NAVIGATION_MODE_LIST);
1371 actionBar.setListNavigationCallbacks(mDirectories, this); // assuming mDirectories is updated
1372
1373 } else {
1374 actionBar.setDisplayHomeAsUpEnabled(true);
1375 actionBar.setDisplayShowTitleEnabled(true);
1376 actionBar.setTitle(chosenFile.getFileName());
1377 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
1378 View actionBarTitleView = getWindow().getDecorView().findViewById(actionBarTitleId);
1379 if (actionBarTitleView != null) { // it's null in Android 2.x
1380 getWindow().getDecorView().findViewById(actionBarTitleId).
1381 setContentDescription(chosenFile.getFileName());
1382 }
1383 }
1384 }
1385
1386
1387 @Override
1388 protected ServiceConnection newTransferenceServiceConnection() {
1389 return new ListServiceConnection();
1390 }
1391
1392 /** Defines callbacks for service binding, passed to bindService() */
1393 private class ListServiceConnection implements ServiceConnection {
1394
1395 @Override
1396 public void onServiceConnected(ComponentName component, IBinder service) {
1397 if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
1398 Log_OC.d(TAG, "Download service connected");
1399 mDownloaderBinder = (FileDownloaderBinder) service;
1400 if (mWaitingToPreview != null)
1401 if (getStorageManager() != null) {
1402 mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); // update the file
1403 if (!mWaitingToPreview.isDown()) {
1404 requestForDownload();
1405 }
1406 }
1407
1408 } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
1409 Log_OC.d(TAG, "Upload service connected");
1410 mUploaderBinder = (FileUploaderBinder) service;
1411 } else {
1412 return;
1413 }
1414 // a new chance to get the mDownloadBinder through getFileDownloadBinder() - THIS IS A MESS
1415 OCFileListFragment listOfFiles = getListOfFilesFragment();
1416 if (listOfFiles != null) {
1417 listOfFiles.listDirectory();
1418 // TODO Enable when "On Device" is recovered ?
1419 // listOfFiles.listDirectory(MainApp.getOnlyOnDevice());
1420 }
1421 FileFragment secondFragment = getSecondFragment();
1422 if (secondFragment != null && secondFragment instanceof FileDetailFragment) {
1423 FileDetailFragment detailFragment = (FileDetailFragment)secondFragment;
1424 detailFragment.listenForTransferProgress();
1425 detailFragment.updateFileDetails(false, false);
1426 }
1427 }
1428
1429 @Override
1430 public void onServiceDisconnected(ComponentName component) {
1431 if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
1432 Log_OC.d(TAG, "Download service disconnected");
1433 mDownloaderBinder = null;
1434 } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
1435 Log_OC.d(TAG, "Upload service disconnected");
1436 mUploaderBinder = null;
1437 }
1438 }
1439 };
1440
1441 @Override
1442 public void onSavedCertificate() {
1443 startSyncFolderOperation(getCurrentDir(), false);
1444 }
1445
1446
1447 @Override
1448 public void onFailedSavingCertificate() {
1449 ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(
1450 R.string.ssl_validator_not_saved, new String[]{}, R.string.common_ok, -1, -1
1451 );
1452 dialog.show(getSupportFragmentManager(), DIALOG_CERT_NOT_SAVED);
1453 }
1454
1455 @Override
1456 public void onCancelCertificate() {
1457 // nothing to do
1458 }
1459
1460 /**
1461 * Updates the view associated to the activity after the finish of some operation over files
1462 * in the current account.
1463 *
1464 * @param operation Removal operation performed.
1465 * @param result Result of the removal.
1466 */
1467 @Override
1468 public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
1469 super.onRemoteOperationFinish(operation, result);
1470
1471 if (operation instanceof RemoveFileOperation) {
1472 onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
1473
1474 } else if (operation instanceof RenameFileOperation) {
1475 onRenameFileOperationFinish((RenameFileOperation)operation, result);
1476
1477 } else if (operation instanceof SynchronizeFileOperation) {
1478 onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
1479
1480 } else if (operation instanceof CreateFolderOperation) {
1481 onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
1482
1483 } else if (operation instanceof CreateShareOperation) {
1484 onCreateShareOperationFinish((CreateShareOperation) operation, result);
1485
1486 } else if (operation instanceof UnshareLinkOperation) {
1487 onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result);
1488
1489 } else if (operation instanceof MoveFileOperation) {
1490 onMoveFileOperationFinish((MoveFileOperation)operation, result);
1491 }
1492
1493 }
1494
1495
1496 private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
1497 if (result.isSuccess()) {
1498 refreshShowDetails();
1499 refreshListOfFilesFragment();
1500 }
1501 }
1502
1503
1504 private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
1505 if (result.isSuccess()) {
1506 refreshShowDetails();
1507 refreshListOfFilesFragment();
1508
1509 } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
1510 cleanSecondFragment();
1511 refreshListOfFilesFragment();
1512 }
1513 }
1514
1515 private void refreshShowDetails() {
1516 FileFragment details = getSecondFragment();
1517 if (details != null) {
1518 OCFile file = details.getFile();
1519 if (file != null) {
1520 file = getStorageManager().getFileByPath(file.getRemotePath());
1521 if (details instanceof PreviewMediaFragment) {
1522 // Refresh OCFile of the fragment
1523 ((PreviewMediaFragment) details).updateFile(file);
1524 } else {
1525 showDetails(file);
1526 }
1527 }
1528 invalidateOptionsMenu();
1529 }
1530 }
1531
1532 /**
1533 * Updates the view associated to the activity after the finish of an operation trying to remove a
1534 * file.
1535 *
1536 * @param operation Removal operation performed.
1537 * @param result Result of the removal.
1538 */
1539 private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
1540 dismissLoadingDialog();
1541
1542 Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
1543 Toast.LENGTH_LONG);
1544 msg.show();
1545
1546 if (result.isSuccess()) {
1547 OCFile removedFile = operation.getFile();
1548 FileFragment second = getSecondFragment();
1549 if (second != null && removedFile.equals(second.getFile())) {
1550 if (second instanceof PreviewMediaFragment) {
1551 ((PreviewMediaFragment)second).stopPreview(true);
1552 }
1553 setFile(getStorageManager().getFileById(removedFile.getParentId()));
1554 cleanSecondFragment();
1555 }
1556 if (getStorageManager().getFileById(removedFile.getParentId()).equals(getCurrentDir())) {
1557 refreshListOfFilesFragment();
1558 }
1559 invalidateOptionsMenu();
1560 } else {
1561 if (result.isSslRecoverableException()) {
1562 mLastSslUntrustedServerResult = result;
1563 showUntrustedCertDialog(mLastSslUntrustedServerResult);
1564 }
1565 }
1566 }
1567
1568
1569 /**
1570 * Updates the view associated to the activity after the finish of an operation trying to move a
1571 * file.
1572 *
1573 * @param operation Move operation performed.
1574 * @param result Result of the move operation.
1575 */
1576 private void onMoveFileOperationFinish(MoveFileOperation operation, RemoteOperationResult result) {
1577 if (result.isSuccess()) {
1578 dismissLoadingDialog();
1579 refreshListOfFilesFragment();
1580 } else {
1581 dismissLoadingDialog();
1582 try {
1583 Toast msg = Toast.makeText(FileDisplayActivity.this,
1584 ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
1585 Toast.LENGTH_LONG);
1586 msg.show();
1587
1588 } catch (NotFoundException e) {
1589 Log_OC.e(TAG, "Error while trying to show fail message " , e);
1590 }
1591 }
1592 }
1593
1594
1595 /**
1596 * Updates the view associated to the activity after the finish of an operation trying to rename a
1597 * file.
1598 *
1599 * @param operation Renaming operation performed.
1600 * @param result Result of the renaming.
1601 */
1602 private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {
1603 dismissLoadingDialog();
1604 OCFile renamedFile = operation.getFile();
1605 if (result.isSuccess()) {
1606 FileFragment details = getSecondFragment();
1607 if (details != null) {
1608 if (details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) {
1609 ((FileDetailFragment) details).updateFileDetails(renamedFile, getAccount());
1610 showDetails(renamedFile);
1611
1612 } else if (details instanceof PreviewMediaFragment && renamedFile.equals(details.getFile())) {
1613 ((PreviewMediaFragment) details).updateFile(renamedFile);
1614 if (PreviewMediaFragment.canBePreviewed(renamedFile)) {
1615 int position = ((PreviewMediaFragment)details).getPosition();
1616 startMediaPreview(renamedFile, position, true);
1617 } else {
1618 getFileOperationsHelper().openFile(renamedFile);
1619 }
1620 }
1621 }
1622
1623 if (getStorageManager().getFileById(renamedFile.getParentId()).equals(getCurrentDir())) {
1624 refreshListOfFilesFragment();
1625 }
1626
1627 } else {
1628 Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
1629 Toast.LENGTH_LONG);
1630 msg.show();
1631
1632 if (result.isSslRecoverableException()) {
1633 mLastSslUntrustedServerResult = result;
1634 showUntrustedCertDialog(mLastSslUntrustedServerResult);
1635 }
1636 }
1637 }
1638
1639 private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
1640 dismissLoadingDialog();
1641 OCFile syncedFile = operation.getLocalFile();
1642 if (!result.isSuccess()) {
1643 if (result.getCode() == ResultCode.SYNC_CONFLICT) {
1644 Intent i = new Intent(this, ConflictsResolveActivity.class);
1645 i.putExtra(ConflictsResolveActivity.EXTRA_FILE, syncedFile);
1646 i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, getAccount());
1647 startActivity(i);
1648
1649 }
1650
1651 } else {
1652 if (operation.transferWasRequested()) {
1653 onTransferStateChanged(syncedFile, true, true);
1654
1655 } else {
1656 Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
1657 Toast.LENGTH_LONG);
1658 msg.show();
1659 }
1660 }
1661 }
1662
1663 /**
1664 * Updates the view associated to the activity after the finish of an operation trying create a new folder
1665 *
1666 * @param operation Creation operation performed.
1667 * @param result Result of the creation.
1668 */
1669 private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {
1670 if (result.isSuccess()) {
1671 dismissLoadingDialog();
1672 refreshListOfFilesFragment();
1673 } else {
1674 dismissLoadingDialog();
1675 try {
1676 Toast msg = Toast.makeText(FileDisplayActivity.this,
1677 ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
1678 Toast.LENGTH_LONG);
1679 msg.show();
1680
1681 } catch (NotFoundException e) {
1682 Log_OC.e(TAG, "Error while trying to show fail message " , e);
1683 }
1684 }
1685 }
1686
1687
1688 /**
1689 * {@inheritDoc}
1690 */
1691 @Override
1692 public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
1693 refreshListOfFilesFragment();
1694 FileFragment details = getSecondFragment();
1695 if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) {
1696 if (downloading || uploading) {
1697 ((FileDetailFragment)details).updateFileDetails(file, getAccount());
1698 } else {
1699 if (!file.fileExists()) {
1700 cleanSecondFragment();
1701 } else {
1702 ((FileDetailFragment)details).updateFileDetails(false, true);
1703 }
1704 }
1705 }
1706
1707 }
1708
1709
1710 private void requestForDownload() {
1711 Account account = getAccount();
1712 //if (!mWaitingToPreview.isDownloading()) {
1713 if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) {
1714 Intent i = new Intent(this, FileDownloader.class);
1715 i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
1716 i.putExtra(FileDownloader.EXTRA_FILE, mWaitingToPreview);
1717 startService(i);
1718 }
1719 }
1720
1721
1722 private OCFile getCurrentDir() {
1723 OCFile file = getFile();
1724 if (file != null) {
1725 if (file.isFolder()) {
1726 return file;
1727 } else if (getStorageManager() != null) {
1728 String parentPath = file.getRemotePath().substring(0,
1729 file.getRemotePath().lastIndexOf(file.getFileName()));
1730 return getStorageManager().getFileByPath(parentPath);
1731 }
1732 }
1733 return null;
1734 }
1735
1736 public void startSyncFolderOperation(OCFile folder, boolean ignoreETag) {
1737 long currentSyncTime = System.currentTimeMillis();
1738
1739 mSyncInProgress = true;
1740
1741 // perform folder synchronization
1742 RemoteOperation synchFolderOp = new RefreshFolderOperation( folder,
1743 currentSyncTime,
1744 false,
1745 getFileOperationsHelper().isSharedSupported(),
1746 ignoreETag,
1747 getStorageManager(),
1748 getAccount(),
1749 getApplicationContext()
1750 );
1751 synchFolderOp.execute(getAccount(), MainApp.getAppContext(), this, null, null);
1752
1753 setSupportProgressBarIndeterminateVisibility(true);
1754
1755 setBackgroundText();
1756 }
1757
1758 /**
1759 * Show untrusted cert dialog
1760 */
1761 public void showUntrustedCertDialog(RemoteOperationResult result) {
1762 // Show a dialog with the certificate info
1763 SslUntrustedCertDialog dialog = SslUntrustedCertDialog.newInstanceForFullSslError(
1764 (CertificateCombinedException) result.getException());
1765 FragmentManager fm = getSupportFragmentManager();
1766 FragmentTransaction ft = fm.beginTransaction();
1767 dialog.show(ft, DIALOG_UNTRUSTED_CERT);
1768 }
1769
1770 private void requestForDownload(OCFile file) {
1771 Account account = getAccount();
1772 if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) {
1773 Intent i = new Intent(this, FileDownloader.class);
1774 i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
1775 i.putExtra(FileDownloader.EXTRA_FILE, file);
1776 startService(i);
1777 }
1778 }
1779
1780 private void sendDownloadedFile(){
1781 getFileOperationsHelper().sendDownloadedFile(mWaitingToSend);
1782 mWaitingToSend = null;
1783 }
1784
1785
1786 /**
1787 * Requests the download of the received {@link OCFile} , updates the UI
1788 * to monitor the download progress and prepares the activity to send the file
1789 * when the download finishes.
1790 *
1791 * @param file {@link OCFile} to download and preview.
1792 */
1793 public void startDownloadForSending(OCFile file) {
1794 mWaitingToSend = file;
1795 requestForDownload(mWaitingToSend);
1796 boolean hasSecondFragment = (getSecondFragment()!= null);
1797 updateFragmentsVisibility(hasSecondFragment);
1798 }
1799
1800 /**
1801 * Opens the image gallery showing the image {@link OCFile} received as parameter.
1802 *
1803 * @param file Image {@link OCFile} to show.
1804 */
1805 public void startImagePreview(OCFile file) {
1806 Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
1807 showDetailsIntent.putExtra(EXTRA_FILE, file);
1808 showDetailsIntent.putExtra(EXTRA_ACCOUNT, getAccount());
1809 startActivity(showDetailsIntent);
1810
1811 }
1812
1813 /**
1814 * Stars the preview of an already down media {@link OCFile}.
1815 *
1816 * @param file Media {@link OCFile} to preview.
1817 * @param startPlaybackPosition Media position where the playback will be started, in milliseconds.
1818 * @param autoplay When 'true', the playback will start without user interactions.
1819 */
1820 public void startMediaPreview(OCFile file, int startPlaybackPosition, boolean autoplay) {
1821 Fragment mediaFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition, autoplay);
1822 setSecondFragment(mediaFragment);
1823 updateFragmentsVisibility(true);
1824 updateNavigationElementsInActionBar(file);
1825 setFile(file);
1826 }
1827
1828 /**
1829 * Requests the download of the received {@link OCFile} , updates the UI
1830 * to monitor the download progress and prepares the activity to preview
1831 * or open the file when the download finishes.
1832 *
1833 * @param file {@link OCFile} to download and preview.
1834 */
1835 public void startDownloadForPreview(OCFile file) {
1836 Fragment detailFragment = new FileDetailFragment(file, getAccount());
1837 setSecondFragment(detailFragment);
1838 mWaitingToPreview = file;
1839 requestForDownload();
1840 updateFragmentsVisibility(true);
1841 updateNavigationElementsInActionBar(file);
1842 setFile(file);
1843 }
1844
1845
1846 public void cancelTransference(OCFile file) {
1847 getFileOperationsHelper().cancelTransference(file);
1848 if (mWaitingToPreview != null &&
1849 mWaitingToPreview.getRemotePath().equals(file.getRemotePath())) {
1850 mWaitingToPreview = null;
1851 }
1852 if (mWaitingToSend != null &&
1853 mWaitingToSend.getRemotePath().equals(file.getRemotePath())) {
1854 mWaitingToSend = null;
1855 }
1856 onTransferStateChanged(file, false, false);
1857 }
1858
1859 @Override
1860 public void onRefresh(boolean ignoreETag) {
1861 refreshList(ignoreETag);
1862 }
1863
1864 @Override
1865 public void onRefresh() {
1866 refreshList(true);
1867 }
1868
1869 private void refreshList(boolean ignoreETag) {
1870 OCFileListFragment listOfFiles = getListOfFilesFragment();
1871 if (listOfFiles != null) {
1872 OCFile folder = listOfFiles.getCurrentFile();
1873 if (folder != null) {
1874 /*mFile = mContainerActivity.getStorageManager().getFileById(mFile.getFileId());
1875 listDirectory(mFile);*/
1876 startSyncFolderOperation(folder, ignoreETag);
1877 }
1878 }
1879 }
1880
1881 private void sortByDate(boolean ascending){
1882 getListOfFilesFragment().sortByDate(ascending);
1883 }
1884
1885 private void sortBySize(boolean ascending){
1886 getListOfFilesFragment().sortBySize(ascending);
1887 }
1888
1889 private void sortByName(boolean ascending){
1890 getListOfFilesFragment().sortByName(ascending);
1891 }
1892
1893 public void restart(){
1894 Intent i = new Intent(this, FileDisplayActivity.class);
1895 i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1896 startActivity(i);
1897 }
1898
1899 public void closeDrawer() {
1900 mDrawerLayout.closeDrawers();
1901 }
1902
1903 }