Merge branch 'develop' into file_browsing_refactoring
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / activity / FileDisplayActivity.java
1 /* ownCloud Android client application
2 * Copyright (C) 2011 Bartek Przybylski
3 * Copyright (C) 2012-2013 ownCloud Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2,
7 * as published by the Free Software Foundation.
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
19 package com.owncloud.android.ui.activity;
20
21 import java.io.File;
22
23 import android.accounts.Account;
24 import android.app.AlertDialog;
25 import android.app.ProgressDialog;
26 import android.app.Dialog;
27 import android.content.BroadcastReceiver;
28 import android.content.ComponentName;
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.DialogInterface;
32 import android.content.DialogInterface.OnClickListener;
33 import android.content.Intent;
34 import android.content.IntentFilter;
35 import android.content.ServiceConnection;
36 import android.content.SharedPreferences;
37 import android.content.res.Configuration;
38 import android.content.res.Resources.NotFoundException;
39 import android.database.Cursor;
40 import android.net.Uri;
41 import android.os.Bundle;
42 import android.os.Handler;
43 import android.os.IBinder;
44 import android.preference.PreferenceManager;
45 import android.provider.MediaStore;
46 import android.support.v4.app.Fragment;
47 import android.support.v4.app.FragmentTransaction;
48 import android.view.View;
49 import android.view.ViewGroup;
50 import android.widget.ArrayAdapter;
51 import android.widget.TextView;
52 import android.widget.Toast;
53
54 import com.actionbarsherlock.app.ActionBar;
55 import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
56 import com.actionbarsherlock.app.SherlockFragmentActivity;
57 import com.actionbarsherlock.view.Menu;
58 import com.actionbarsherlock.view.MenuInflater;
59 import com.actionbarsherlock.view.MenuItem;
60 import com.actionbarsherlock.view.Window;
61 import com.owncloud.android.AccountUtils;
62 import com.owncloud.android.Log_OC;
63 import com.owncloud.android.R;
64 import com.owncloud.android.authentication.AccountAuthenticator;
65 import com.owncloud.android.datamodel.DataStorageManager;
66 import com.owncloud.android.datamodel.FileDataStorageManager;
67 import com.owncloud.android.datamodel.OCFile;
68 import com.owncloud.android.files.services.FileDownloader;
69 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
70 import com.owncloud.android.files.services.FileObserverService;
71 import com.owncloud.android.files.services.FileUploader;
72 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
73 import com.owncloud.android.operations.CreateFolderOperation;
74 import com.owncloud.android.operations.OnRemoteOperationListener;
75 import com.owncloud.android.operations.RemoteOperation;
76 import com.owncloud.android.operations.RemoteOperationResult;
77 import com.owncloud.android.operations.RemoveFileOperation;
78 import com.owncloud.android.operations.RenameFileOperation;
79 import com.owncloud.android.operations.SynchronizeFileOperation;
80 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
81 import com.owncloud.android.syncadapter.FileSyncService;
82 import com.owncloud.android.ui.dialog.EditNameDialog;
83 import com.owncloud.android.ui.dialog.SslValidatorDialog;
84 import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
85 import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
86 import com.owncloud.android.ui.fragment.FileDetailFragment;
87 import com.owncloud.android.ui.fragment.FileFragment;
88 import com.owncloud.android.ui.fragment.OCFileListFragment;
89 import com.owncloud.android.ui.preview.PreviewImageActivity;
90 import com.owncloud.android.ui.preview.PreviewImageFragment;
91 import com.owncloud.android.ui.preview.PreviewMediaFragment;
92 import com.owncloud.android.ui.preview.PreviewVideoActivity;
93
94 /**
95 * Displays, what files the user has available in his ownCloud.
96 *
97 * @author Bartek Przybylski
98 * @author David A. Velasco
99 */
100
101 public class FileDisplayActivity extends SherlockFragmentActivity implements
102 OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener, EditNameDialogListener {
103
104 private ArrayAdapter<String> mDirectories;
105 private OCFile mCurrentDir = null;
106 private OCFile mCurrentFile = null;
107
108 private DataStorageManager mStorageManager;
109 private SyncBroadcastReceiver mSyncBroadcastReceiver;
110 private UploadFinishReceiver mUploadFinishReceiver;
111 private DownloadFinishReceiver mDownloadFinishReceiver;
112 private FileDownloaderBinder mDownloaderBinder = null;
113 private FileUploaderBinder mUploaderBinder = null;
114 private ServiceConnection mDownloadConnection = null, mUploadConnection = null;
115 private RemoteOperationResult mLastSslUntrustedServerResult = null;
116
117 private OCFileListFragment mFileList;
118
119 private boolean mDualPane;
120 private boolean mBackFromCreatingFirstAccount;
121
122 private static final int DIALOG_SETUP_ACCOUNT = 0;
123 public static final int DIALOG_SHORT_WAIT = 1;
124 private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 2;
125 private static final int DIALOG_SSL_VALIDATOR = 3;
126 private static final int DIALOG_CERT_NOT_SAVED = 4;
127
128 private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
129 private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
130
131 private static final String TAG = "FileDisplayActivity";
132
133 private OCFile mWaitingToPreview;
134 private Handler mHandler;
135
136 private Configuration mNewConfigurationChangeToApplyOnStart;
137 private boolean mStarted;
138
139 @Override
140 public void onCreate(Bundle savedInstanceState) {
141 Log_OC.d(getClass().toString(), "onCreate() start");
142 super.onCreate(savedInstanceState);
143 mStarted = false;
144
145 mHandler = new Handler();
146
147 /// Load of parameters from received intent
148 Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
149 if (account != null && AccountUtils.setCurrentOwnCloudAccount(this, account.name)) {
150 mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
151 }
152
153 /// Load of saved instance state: keep this always before initDataFromCurrentAccount()
154 if(savedInstanceState != null) {
155 // TODO - test if savedInstanceState should take precedence over file in the intent ALWAYS (now), NEVER. SOME TIMES
156 mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);
157 mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW);
158
159 } else {
160 mWaitingToPreview = null;
161 }
162
163 if (!AccountUtils.accountsAreSetup(this)) {
164 /// no account available: FORCE ACCOUNT CREATION
165 mStorageManager = null;
166 createFirstAccount();
167
168 } else { /// at least an account is available
169
170 initDataFromCurrentAccount(); // it checks mCurrentDir and mCurrentFile with the current account
171
172 }
173
174 mUploadConnection = new ListServiceConnection();
175 mDownloadConnection = new ListServiceConnection();
176 bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
177 bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
178
179 // PIN CODE request ; best location is to decide, let's try this first
180 if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {
181 requestPinCode();
182 }
183
184 // file observer
185 Intent observer_intent = new Intent(this, FileObserverService.class);
186 observer_intent.putExtra(FileObserverService.KEY_FILE_CMD, FileObserverService.CMD_INIT_OBSERVED_LIST);
187 startService(observer_intent);
188
189
190 /// USER INTERFACE
191 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
192
193 // Drop-down navigation
194 mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
195 OCFile currFile = mCurrentDir;
196 while(mStorageManager != null && currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {
197 mDirectories.add(currFile.getFileName());
198 currFile = mStorageManager.getFileById(currFile.getParentId());
199 }
200 mDirectories.add(OCFile.PATH_SEPARATOR);
201
202 // Inflate and set the layout view
203 setContentView(R.layout.files);
204 mFileList = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
205 mDualPane = (findViewById(R.id.file_details_container) != null);
206 if (mDualPane && savedInstanceState == null) {
207 initFileDetailsInDualPane();
208 }
209
210 // Action bar setup
211 ActionBar actionBar = getSupportActionBar();
212 actionBar.setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation
213 actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null && mCurrentDir.getParentId() != 0);
214 actionBar.setDisplayShowTitleEnabled(false);
215 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
216 actionBar.setListNavigationCallbacks(mDirectories, this);
217 setSupportProgressBarIndeterminateVisibility(false); // always AFTER setContentView(...) ; to workaround bug in its implementation
218
219
220 mBackFromCreatingFirstAccount = false;
221
222 Log_OC.d(getClass().toString(), "onCreate() end");
223 }
224
225
226 @Override
227 public void onConfigurationChanged (Configuration newConfig) {
228 super.onConfigurationChanged(newConfig);
229 if (mStarted) {
230 checkConfigurationChange(newConfig);
231 } else {
232 mNewConfigurationChangeToApplyOnStart = newConfig;
233 }
234 }
235
236
237 /**
238 * Launches the account creation activity. To use when no ownCloud account is available
239 */
240 private void createFirstAccount() {
241 Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);
242 intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTHORITY });
243 startActivity(intent); // the new activity won't be created until this.onStart() and this.onResume() are finished;
244 }
245
246
247 /**
248 * Load of state dependent of the existence of an ownCloud account
249 */
250 private void initDataFromCurrentAccount() {
251 /// Storage manager initialization - access to local database
252 mStorageManager = new FileDataStorageManager(
253 AccountUtils.getCurrentOwnCloudAccount(this),
254 getContentResolver());
255
256 /// Check if mCurrentDir is a directory
257 if(mCurrentDir != null && !mCurrentDir.isDirectory()) {
258 mCurrentFile = mCurrentDir;
259 mCurrentDir = mStorageManager.getFileById(mCurrentDir.getParentId());
260 }
261
262 /// Check if mCurrentDir and mCurrentFile are in the current account, and update them
263 if (mCurrentDir != null) {
264 mCurrentDir = mStorageManager.getFileByPath(mCurrentDir.getRemotePath()); // mCurrentDir == null if it is not in the current account
265 }
266 if (mCurrentFile != null) {
267 if (mCurrentFile.fileExists()) {
268 mCurrentFile = mStorageManager.getFileByPath(mCurrentFile.getRemotePath()); // mCurrentFile == null if it is not in the current account
269 } // else : keep mCurrentFile with the received value; this is currently the case of an upload in progress, when the user presses the status notification in a landscape tablet
270 }
271
272 /// Default to root if mCurrentDir was not found
273 if (mCurrentDir == null) {
274 mCurrentDir = mStorageManager.getFileByPath("/"); // will be NULL if the database was never synchronized
275 }
276 }
277
278
279 private void initFileDetailsInDualPane() {
280 if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) {
281 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
282 if (mCurrentFile != null) {
283 if (PreviewMediaFragment.canBePreviewed(mCurrentFile)) {
284 if (mCurrentFile.isDown()) {
285 int startPlaybackPosition = getIntent().getIntExtra(PreviewVideoActivity.EXTRA_START_POSITION, 0);
286 boolean autoplay = getIntent().getBooleanExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, true);
287 transaction.replace(R.id.file_details_container, new PreviewMediaFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this), startPlaybackPosition, autoplay), FileDetailFragment.FTAG);
288 } else {
289 transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
290 mWaitingToPreview = mCurrentFile;
291 }
292 } else {
293 transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
294 }
295 mCurrentFile = null;
296
297 } else {
298 transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment
299 }
300 transaction.commit();
301 }
302 }
303
304
305 @Override
306 public void onStart() {
307 super.onStart();
308 if (mNewConfigurationChangeToApplyOnStart != null) {
309 checkConfigurationChange(mNewConfigurationChangeToApplyOnStart);
310 mNewConfigurationChangeToApplyOnStart = null;
311 }
312 mStarted = true;
313 }
314
315 @Override
316 public void onStop() {
317 super.onStop();
318 mStarted = false;
319 }
320
321
322 private void checkConfigurationChange(Configuration newConfig) {
323 FileFragment fragment = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
324 if (fragment != null
325 && fragment.getFile() != null
326 && (newConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE
327 && newConfig.orientation != Configuration.ORIENTATION_LANDSCAPE) {
328
329 onFileClick(fragment.getFile(), true);
330 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
331 transaction.remove((Fragment)fragment);
332 transaction.commit();
333
334 } else {
335 finish();
336 Intent intent = new Intent(this, FileDisplayActivity.class);
337 intent.putExtra(FileDetailFragment.EXTRA_FILE, mCurrentDir);
338 intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
339 startActivity(intent);
340 }
341 }
342
343
344 @Override
345 public void onDestroy() {
346 super.onDestroy();
347 if (mDownloadConnection != null)
348 unbindService(mDownloadConnection);
349 if (mUploadConnection != null)
350 unbindService(mUploadConnection);
351 }
352
353
354 @Override
355 public boolean onCreateOptionsMenu(Menu menu) {
356 MenuInflater inflater = getSherlock().getMenuInflater();
357 inflater.inflate(R.menu.main_menu, menu);
358
359 return true;
360 }
361
362 @Override
363 public boolean onOptionsItemSelected(MenuItem item) {
364 boolean retval = true;
365 switch (item.getItemId()) {
366 case R.id.action_create_dir: {
367 EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.uploader_info_dirname), "", -1, -1, this);
368 dialog.show(getSupportFragmentManager(), "createdirdialog");
369 break;
370 }
371 case R.id.action_sync_account: {
372 startSynchronization();
373 break;
374 }
375 case R.id.action_upload: {
376 showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE);
377 break;
378 }
379 case R.id.action_settings: {
380 Intent settingsIntent = new Intent(this, Preferences.class);
381 startActivity(settingsIntent);
382 break;
383 }
384 case android.R.id.home: {
385 if(mCurrentDir != null && mCurrentDir.getParentId() != 0){
386 onBackPressed();
387 }
388 break;
389 }
390 default:
391 retval = super.onOptionsItemSelected(item);
392 }
393 return retval;
394 }
395
396 private void startSynchronization() {
397 ContentResolver.cancelSync(null, AccountAuthenticator.AUTHORITY); // cancel the current synchronizations of any ownCloud account
398 Bundle bundle = new Bundle();
399 bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
400 ContentResolver.requestSync(
401 AccountUtils.getCurrentOwnCloudAccount(this),
402 AccountAuthenticator.AUTHORITY, bundle);
403 }
404
405
406 @Override
407 public boolean onNavigationItemSelected(int itemPosition, long itemId) {
408 int i = itemPosition;
409 while (i-- != 0) {
410 onBackPressed();
411 }
412 // the next operation triggers a new call to this method, but it's necessary to
413 // ensure that the name exposed in the action bar is the current directory when the
414 // user selected it in the navigation list
415 if (itemPosition != 0)
416 getSupportActionBar().setSelectedNavigationItem(0);
417 return true;
418 }
419
420 /**
421 * Called, when the user selected something for uploading
422 */
423 public void onActivityResult(int requestCode, int resultCode, Intent data) {
424 super.onActivityResult(requestCode, resultCode, data);
425
426 if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
427 requestSimpleUpload(data, resultCode);
428
429 } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
430 requestMultipleUpload(data, resultCode);
431
432 }
433 }
434
435 private void requestMultipleUpload(Intent data, int resultCode) {
436 String[] filePaths = data.getStringArrayExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES);
437 if (filePaths != null) {
438 String[] remotePaths = new String[filePaths.length];
439 String remotePathBase = "";
440 for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
441 remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
442 }
443 if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR))
444 remotePathBase += OCFile.PATH_SEPARATOR;
445 for (int j = 0; j< remotePaths.length; j++) {
446 remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName();
447 }
448
449 Intent i = new Intent(this, FileUploader.class);
450 i.putExtra(FileUploader.KEY_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
451 i.putExtra(FileUploader.KEY_LOCAL_FILE, filePaths);
452 i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePaths);
453 i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
454 if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)
455 i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
456 startService(i);
457
458 } else {
459 Log_OC.d("FileDisplay", "User clicked on 'Update' with no selection");
460 Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG);
461 t.show();
462 return;
463 }
464 }
465
466
467 private void requestSimpleUpload(Intent data, int resultCode) {
468 String filepath = null;
469 try {
470 Uri selectedImageUri = data.getData();
471
472 String filemanagerstring = selectedImageUri.getPath();
473 String selectedImagePath = getPath(selectedImageUri);
474
475 if (selectedImagePath != null)
476 filepath = selectedImagePath;
477 else
478 filepath = filemanagerstring;
479
480 } catch (Exception e) {
481 Log_OC.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);
482 e.printStackTrace();
483
484 } finally {
485 if (filepath == null) {
486 Log_OC.e("FileDisplay", "Couldnt resolve path to file");
487 Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);
488 t.show();
489 return;
490 }
491 }
492
493 Intent i = new Intent(this, FileUploader.class);
494 i.putExtra(FileUploader.KEY_ACCOUNT,
495 AccountUtils.getCurrentOwnCloudAccount(this));
496 String remotepath = new String();
497 for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
498 remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
499 }
500 if (!remotepath.endsWith(OCFile.PATH_SEPARATOR))
501 remotepath += OCFile.PATH_SEPARATOR;
502 remotepath += new File(filepath).getName();
503
504 i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath);
505 i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath);
506 i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
507 if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)
508 i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
509 startService(i);
510 }
511
512
513 @Override
514 public void onBackPressed() {
515 if (mDirectories.getCount() <= 1) {
516 finish();
517 return;
518 }
519 popDirname();
520 mFileList.onNavigateUp();
521 mCurrentDir = mFileList.getCurrentFile();
522
523 if (mDualPane) {
524 // Resets the FileDetailsFragment on Tablets so that it always displays
525 Fragment fileFragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
526 if (fileFragment != null && (fileFragment instanceof PreviewMediaFragment || !((FileDetailFragment) fileFragment).isEmpty())) {
527 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
528 transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment
529 transaction.commit();
530 }
531 }
532
533 if(mCurrentDir.getParentId() == 0){
534 ActionBar actionBar = getSupportActionBar();
535 actionBar.setDisplayHomeAsUpEnabled(false);
536 }
537 }
538
539 @Override
540 protected void onSaveInstanceState(Bundle outState) {
541 // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
542 Log_OC.d(getClass().toString(), "onSaveInstanceState() start");
543 super.onSaveInstanceState(outState);
544 outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir);
545 if (mDualPane) {
546 FileFragment fragment = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
547 if (fragment != null) {
548 OCFile file = fragment.getFile();
549 if (file != null) {
550 outState.putParcelable(FileDetailFragment.EXTRA_FILE, file);
551 }
552 }
553 }
554 outState.putParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
555 Log_OC.d(getClass().toString(), "onSaveInstanceState() end");
556 }
557
558 @Override
559 protected void onResume() {
560 Log_OC.d(getClass().toString(), "onResume() start");
561 super.onResume();
562
563 if (AccountUtils.accountsAreSetup(this)) {
564
565 if (mStorageManager == null) {
566 // this is necessary for handling the come back to FileDisplayActivity when the first ownCloud account is created
567 initDataFromCurrentAccount();
568 if (mDualPane) {
569 initFileDetailsInDualPane();
570 }
571 mBackFromCreatingFirstAccount = true;
572 }
573
574 // Listen for sync messages
575 IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE);
576 mSyncBroadcastReceiver = new SyncBroadcastReceiver();
577 registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
578
579 // Listen for upload messages
580 IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
581 mUploadFinishReceiver = new UploadFinishReceiver();
582 registerReceiver(mUploadFinishReceiver, uploadIntentFilter);
583
584 // Listen for download messages
585 IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE);
586 downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
587 mDownloadFinishReceiver = new DownloadFinishReceiver();
588 registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
589
590 // List current directory
591 mFileList.listDirectory(mCurrentDir); // TODO we should find the way to avoid the need of this (maybe it's not necessary yet; to check)
592
593 } else {
594
595 mStorageManager = null; // an invalid object will be there if all the ownCloud accounts are removed
596 showDialog(DIALOG_SETUP_ACCOUNT);
597
598 }
599 Log_OC.d(getClass().toString(), "onResume() end");
600 }
601
602
603 @Override
604 protected void onPause() {
605 Log_OC.d(getClass().toString(), "onPause() start");
606 super.onPause();
607 if (mSyncBroadcastReceiver != null) {
608 unregisterReceiver(mSyncBroadcastReceiver);
609 mSyncBroadcastReceiver = null;
610 }
611 if (mUploadFinishReceiver != null) {
612 unregisterReceiver(mUploadFinishReceiver);
613 mUploadFinishReceiver = null;
614 }
615 if (mDownloadFinishReceiver != null) {
616 unregisterReceiver(mDownloadFinishReceiver);
617 mDownloadFinishReceiver = null;
618 }
619 if (!AccountUtils.accountsAreSetup(this)) {
620 dismissDialog(DIALOG_SETUP_ACCOUNT);
621 }
622
623 Log_OC.d(getClass().toString(), "onPause() end");
624 }
625
626
627 @Override
628 protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
629 if (id == DIALOG_SSL_VALIDATOR && mLastSslUntrustedServerResult != null) {
630 ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);
631 }
632 }
633
634
635 @Override
636 protected Dialog onCreateDialog(int id) {
637 Dialog dialog = null;
638 AlertDialog.Builder builder;
639 switch (id) {
640 case DIALOG_SETUP_ACCOUNT: {
641 builder = new AlertDialog.Builder(this);
642 builder.setTitle(R.string.main_tit_accsetup);
643 builder.setMessage(R.string.main_wrn_accsetup);
644 builder.setCancelable(false);
645 builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
646 public void onClick(DialogInterface dialog, int which) {
647 createFirstAccount();
648 dialog.dismiss();
649 }
650 });
651 String message = String.format(getString(R.string.common_exit), getString(R.string.app_name));
652 builder.setNegativeButton(message, new OnClickListener() {
653 public void onClick(DialogInterface dialog, int which) {
654 dialog.dismiss();
655 finish();
656 }
657 });
658 //builder.setNegativeButton(android.R.string.cancel, this);
659 dialog = builder.create();
660 break;
661 }
662 case DIALOG_SHORT_WAIT: {
663 ProgressDialog working_dialog = new ProgressDialog(this);
664 working_dialog.setMessage(getResources().getString(
665 R.string.wait_a_moment));
666 working_dialog.setIndeterminate(true);
667 working_dialog.setCancelable(false);
668 dialog = working_dialog;
669 break;
670 }
671 case DIALOG_CHOOSE_UPLOAD_SOURCE: {
672
673 String[] items = null;
674
675 String[] allTheItems = { getString(R.string.actionbar_upload_files),
676 getString(R.string.actionbar_upload_from_apps),
677 getString(R.string.actionbar_failed_instant_upload) };
678
679 String[] commonItems = { getString(R.string.actionbar_upload_files),
680 getString(R.string.actionbar_upload_from_apps) };
681
682 if (InstantUploadActivity.IS_ENABLED)
683 items = allTheItems;
684 else
685 items = commonItems;
686
687 builder = new AlertDialog.Builder(this);
688 builder.setTitle(R.string.actionbar_upload);
689 builder.setItems(items, new DialogInterface.OnClickListener() {
690 public void onClick(DialogInterface dialog, int item) {
691 if (item == 0) {
692 // if (!mDualPane) {
693 Intent action = new Intent(FileDisplayActivity.this, UploadFilesActivity.class);
694 action.putExtra(UploadFilesActivity.EXTRA_ACCOUNT,
695 AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this));
696 startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);
697 // } else {
698 // TODO create and handle new fragment
699 // LocalFileListFragment
700 // }
701 } else if (item == 1) {
702 Intent action = new Intent(Intent.ACTION_GET_CONTENT);
703 action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
704 startActivityForResult(Intent.createChooser(action, getString(R.string.upload_chooser_title)),
705 ACTION_SELECT_CONTENT_FROM_APPS);
706 } else if (item == 2 && InstantUploadActivity.IS_ENABLED) {
707 Account account = AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this);
708 Intent action = new Intent(FileDisplayActivity.this, InstantUploadActivity.class);
709 action.putExtra(FileUploader.KEY_ACCOUNT, account);
710 startActivity(action);
711 }
712 }
713 });
714 dialog = builder.create();
715 break;
716 }
717 case DIALOG_SSL_VALIDATOR: {
718 dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);
719 break;
720 }
721 case DIALOG_CERT_NOT_SAVED: {
722 builder = new AlertDialog.Builder(this);
723 builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));
724 builder.setCancelable(false);
725 builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
726 @Override
727 public void onClick(DialogInterface dialog, int which) {
728 dialog.dismiss();
729 };
730 });
731 dialog = builder.create();
732 break;
733 }
734 default:
735 dialog = null;
736 }
737
738 return dialog;
739 }
740
741
742 /**
743 * Translates a content URI of an image to a physical path
744 * on the disk
745 * @param uri The URI to resolve
746 * @return The path to the image or null if it could not be found
747 */
748 public String getPath(Uri uri) {
749 String[] projection = { MediaStore.Images.Media.DATA };
750 Cursor cursor = managedQuery(uri, projection, null, null, null);
751 if (cursor != null) {
752 int column_index = cursor
753 .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
754 cursor.moveToFirst();
755 return cursor.getString(column_index);
756 }
757 return null;
758 }
759
760 /**
761 * Pushes a directory to the drop down list
762 * @param directory to push
763 * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false.
764 */
765 public void pushDirname(OCFile directory) {
766 if(!directory.isDirectory()){
767 throw new IllegalArgumentException("Only directories may be pushed!");
768 }
769 mDirectories.insert(directory.getFileName(), 0);
770 mCurrentDir = directory;
771 }
772
773 /**
774 * Pops a directory name from the drop down list
775 * @return True, unless the stack is empty
776 */
777 public boolean popDirname() {
778 mDirectories.remove(mDirectories.getItem(0));
779 return !mDirectories.isEmpty();
780 }
781
782 // Custom array adapter to override text colors
783 private class CustomArrayAdapter<T> extends ArrayAdapter<T> {
784
785 public CustomArrayAdapter(FileDisplayActivity ctx, int view) {
786 super(ctx, view);
787 }
788
789 public View getView(int position, View convertView, ViewGroup parent) {
790 View v = super.getView(position, convertView, parent);
791
792 ((TextView) v).setTextColor(getResources().getColorStateList(
793 android.R.color.white));
794 return v;
795 }
796
797 public View getDropDownView(int position, View convertView,
798 ViewGroup parent) {
799 View v = super.getDropDownView(position, convertView, parent);
800
801 ((TextView) v).setTextColor(getResources().getColorStateList(
802 android.R.color.white));
803
804 return v;
805 }
806
807 }
808
809 private class SyncBroadcastReceiver extends BroadcastReceiver {
810
811 /**
812 * {@link BroadcastReceiver} to enable syncing feedback in UI
813 */
814 @Override
815 public void onReceive(Context context, Intent intent) {
816 boolean inProgress = intent.getBooleanExtra(FileSyncService.IN_PROGRESS, false);
817 String accountName = intent.getStringExtra(FileSyncService.ACCOUNT_NAME);
818
819 Log_OC.d("FileDisplay", "sync of account " + accountName + " is in_progress: " + inProgress);
820
821 if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) {
822
823 String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH);
824
825 boolean fillBlankRoot = false;
826 if (mCurrentDir == null) {
827 mCurrentDir = mStorageManager.getFileByPath("/");
828 fillBlankRoot = (mCurrentDir != null);
829 }
830
831 if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath)))
832 || fillBlankRoot ) {
833 if (!fillBlankRoot)
834 mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath);
835 OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
836 .findFragmentById(R.id.fileList);
837 if (fileListFragment != null) {
838 fileListFragment.listDirectory(mCurrentDir);
839 }
840 }
841
842 setSupportProgressBarIndeterminateVisibility(inProgress);
843 if (mBackFromCreatingFirstAccount) {
844 // awful patch to fix problem with visibility of progress circle with the first refresh of the first account
845 // TODO - kill this Activity when the first account has to be created instead of stack the account creation on it
846 getSupportActionBar().hide();
847 getSupportActionBar().show();
848 mBackFromCreatingFirstAccount = false;
849 }
850 removeStickyBroadcast(intent);
851
852 }
853
854 RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT);
855 if (synchResult != null) {
856 if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
857 mLastSslUntrustedServerResult = synchResult;
858 showDialog(DIALOG_SSL_VALIDATOR);
859 }
860 }
861 }
862 }
863
864
865 private class UploadFinishReceiver extends BroadcastReceiver {
866 /**
867 * Once the file upload has finished -> update view
868 * @author David A. Velasco
869 * {@link BroadcastReceiver} to enable upload feedback in UI
870 */
871 @Override
872 public void onReceive(Context context, Intent intent) {
873 String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
874 String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
875 boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);
876 boolean isDescendant = (mCurrentDir != null) && (uploadedRemotePath != null) && (uploadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
877 if (sameAccount && isDescendant) {
878 OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
879 if (fileListFragment != null) {
880 fileListFragment.listDirectory();
881 }
882 }
883 }
884
885 }
886
887
888 /**
889 * Class waiting for broadcast events from the {@link FielDownloader} service.
890 *
891 * Updates the UI when a download is started or finished, provided that it is relevant for the
892 * current folder.
893 */
894 private class DownloadFinishReceiver extends BroadcastReceiver {
895 @Override
896 public void onReceive(Context context, Intent intent) {
897 boolean sameAccount = isSameAccount(context, intent);
898 String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
899 boolean isDescendant = isDescendant(downloadedRemotePath);
900
901 if (sameAccount && isDescendant) {
902 updateLeftPanel();
903 if (mDualPane) {
904 updateRightPanel(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
905 }
906 }
907
908 removeStickyBroadcast(intent);
909 }
910
911 private boolean isDescendant(String downloadedRemotePath) {
912 return (mCurrentDir != null && downloadedRemotePath != null && downloadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
913 }
914
915 private boolean isSameAccount(Context context, Intent intent) {
916 String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
917 return (accountName != null && accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name));
918 }
919 }
920
921
922 protected void updateLeftPanel() {
923 OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
924 if (fileListFragment != null) {
925 fileListFragment.listDirectory();
926 }
927 }
928
929 protected void updateRightPanel(String downloadEvent, String downloadedRemotePath, boolean success) {
930 Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
931 boolean waitedPreview = (mWaitingToPreview != null && mWaitingToPreview.getRemotePath().equals(downloadedRemotePath));
932 if (fragment != null && fragment instanceof FileDetailFragment) {
933 FileDetailFragment detailsFragment = (FileDetailFragment) fragment;
934 OCFile fileInFragment = detailsFragment.getFile();
935 if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
936 // the user browsed to other file ; forget the automatic preview
937 mWaitingToPreview = null;
938
939 } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) {
940 // grant that the right panel updates the progress bar
941 detailsFragment.listenForTransferProgress();
942 detailsFragment.updateFileDetails(true, false);
943
944 } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {
945 // update the right panel
946 if (success && waitedPreview) {
947 mWaitingToPreview = mStorageManager.getFileById(mWaitingToPreview.getFileId()); // update the file from database, for the local storage path
948 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
949 transaction.replace(R.id.file_details_container, new PreviewMediaFragment(mWaitingToPreview, AccountUtils.getCurrentOwnCloudAccount(this), 0, true), FileDetailFragment.FTAG);
950 transaction.commit();
951 mWaitingToPreview = null;
952
953 } else {
954 detailsFragment.updateFileDetails(false, (success));
955 }
956 }
957 }
958 }
959
960
961 /**
962 * {@inheritDoc}
963 */
964 @Override
965 public DataStorageManager getStorageManager() {
966 return mStorageManager;
967 }
968
969
970 /**
971 * {@inheritDoc}
972 */
973 @Override
974 public void onDirectoryClick(OCFile directory) {
975 pushDirname(directory);
976 ActionBar actionBar = getSupportActionBar();
977 actionBar.setDisplayHomeAsUpEnabled(true);
978
979 if (mDualPane) {
980 // Resets the FileDetailsFragment on Tablets so that it always displays
981 Fragment fileFragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
982 if (fileFragment != null && (fileFragment instanceof PreviewMediaFragment || !((FileDetailFragment) fileFragment).isEmpty())) {
983 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
984 transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment
985 transaction.commit();
986 }
987 }
988 }
989
990
991 /**
992 * {@inheritDoc}
993 */
994 @Override
995 public void onFileClick(OCFile file, boolean onOrientationChange) {
996 if (file != null && PreviewImageFragment.canBePreviewed(file)) {
997 // preview image - it handles the download, if needed
998 startPreviewImage(file);
999
1000 } else if (file != null && PreviewMediaFragment.canBePreviewed(file)) {
1001 if (file.isDown()) {
1002 // general preview
1003 if (!onOrientationChange) {
1004 startMediaPreview(file, 0, true, onOrientationChange);
1005 } else {
1006 int startPlaybackPosition = 0;
1007 boolean autoplay = true;
1008 Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
1009 if (fragment != null && file.isVideo()) {
1010 PreviewMediaFragment videoFragment = (PreviewMediaFragment)fragment;
1011 startPlaybackPosition = videoFragment.getPosition();
1012 autoplay = videoFragment.isPlaying();
1013 }
1014 startMediaPreview(file, startPlaybackPosition, autoplay, onOrientationChange);
1015 }
1016
1017 } else {
1018 // automatic download, preview on finish
1019 startDownloadForPreview(file, onOrientationChange);
1020
1021 }
1022 } else {
1023 // details view
1024 startDetails(file, onOrientationChange);
1025 }
1026 }
1027
1028 private void startPreviewImage(OCFile file) {
1029 Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
1030 showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
1031 showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
1032 startActivity(showDetailsIntent);
1033 }
1034
1035 private void startMediaPreview(OCFile file, int startPlaybackPosition, boolean autoplay, boolean onOrientationChange) {
1036 if (mDualPane && !onOrientationChange) {
1037 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1038 transaction.replace(R.id.file_details_container, new PreviewMediaFragment(file, AccountUtils.getCurrentOwnCloudAccount(this), startPlaybackPosition, autoplay), FileDetailFragment.FTAG);
1039 transaction.commit();
1040
1041 } else {
1042 Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
1043 showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
1044 showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
1045 showDetailsIntent.putExtra(PreviewVideoActivity.EXTRA_START_POSITION, startPlaybackPosition);
1046 showDetailsIntent.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, autoplay);
1047 startActivity(showDetailsIntent);
1048 }
1049 }
1050
1051 private void startDownloadForPreview(OCFile file, boolean onOrientationChange) {
1052 if (mDualPane && !onOrientationChange) {
1053 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1054 transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
1055 transaction.commit();
1056 mWaitingToPreview = file;
1057 requestForDownload();
1058
1059 } else {
1060 Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
1061 showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
1062 showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
1063 startActivity(showDetailsIntent);
1064 }
1065 }
1066
1067
1068 private void startDetails(OCFile file, boolean onOrientationChange) {
1069 if (mDualPane && !file.isImage() && !onOrientationChange) {
1070 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1071 transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
1072 transaction.commit();
1073 } else {
1074 Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
1075 showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
1076 showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
1077 startActivity(showDetailsIntent);
1078 }
1079 }
1080
1081
1082 /**
1083 * {@inheritDoc}
1084 */
1085 @Override
1086 public OCFile getInitialDirectory() {
1087 return mCurrentDir;
1088 }
1089
1090
1091 /**
1092 * {@inheritDoc}
1093 */
1094 @Override
1095 public void onFileStateChanged() {
1096 OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
1097 if (fileListFragment != null) {
1098 fileListFragment.listDirectory();
1099 }
1100 }
1101
1102
1103 /**
1104 * {@inheritDoc}
1105 */
1106 @Override
1107 public FileDownloaderBinder getFileDownloaderBinder() {
1108 return mDownloaderBinder;
1109 }
1110
1111
1112 /**
1113 * {@inheritDoc}
1114 */
1115 @Override
1116 public FileUploaderBinder getFileUploaderBinder() {
1117 return mUploaderBinder;
1118 }
1119
1120
1121 /** Defines callbacks for service binding, passed to bindService() */
1122 private class ListServiceConnection implements ServiceConnection {
1123
1124 @Override
1125 public void onServiceConnected(ComponentName component, IBinder service) {
1126 if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
1127 Log_OC.d(TAG, "Download service connected");
1128 mDownloaderBinder = (FileDownloaderBinder) service;
1129 if (mWaitingToPreview != null) {
1130 requestForDownload();
1131 }
1132
1133 } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
1134 Log_OC.d(TAG, "Upload service connected");
1135 mUploaderBinder = (FileUploaderBinder) service;
1136 } else {
1137 return;
1138 }
1139 // a new chance to get the mDownloadBinder through getFileDownloadBinder() - THIS IS A MESS
1140 if (mFileList != null)
1141 mFileList.listDirectory();
1142 if (mDualPane) {
1143 Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
1144 if (fragment != null && fragment instanceof FileDetailFragment) {
1145 FileDetailFragment detailFragment = (FileDetailFragment)fragment;
1146 detailFragment.listenForTransferProgress();
1147 detailFragment.updateFileDetails(false, false);
1148 }
1149 }
1150 }
1151
1152 @Override
1153 public void onServiceDisconnected(ComponentName component) {
1154 if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
1155 Log_OC.d(TAG, "Download service disconnected");
1156 mDownloaderBinder = null;
1157 } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
1158 Log_OC.d(TAG, "Upload service disconnected");
1159 mUploaderBinder = null;
1160 }
1161 }
1162 };
1163
1164
1165
1166 /**
1167 * Launch an intent to request the PIN code to the user before letting him use the app
1168 */
1169 private void requestPinCode() {
1170 boolean pinStart = false;
1171 SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
1172 pinStart = appPrefs.getBoolean("set_pincode", false);
1173 if (pinStart) {
1174 Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
1175 i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity");
1176 startActivity(i);
1177 }
1178 }
1179
1180
1181 @Override
1182 public void onSavedCertificate() {
1183 startSynchronization();
1184 }
1185
1186
1187 @Override
1188 public void onFailedSavingCertificate() {
1189 showDialog(DIALOG_CERT_NOT_SAVED);
1190 }
1191
1192
1193 /**
1194 * Updates the view associated to the activity after the finish of some operation over files
1195 * in the current account.
1196 *
1197 * @param operation Removal operation performed.
1198 * @param result Result of the removal.
1199 */
1200 @Override
1201 public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
1202 if (operation instanceof RemoveFileOperation) {
1203 onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
1204
1205 } else if (operation instanceof RenameFileOperation) {
1206 onRenameFileOperationFinish((RenameFileOperation)operation, result);
1207
1208 } else if (operation instanceof SynchronizeFileOperation) {
1209 onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
1210
1211 } else if (operation instanceof CreateFolderOperation) {
1212 onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
1213 }
1214 }
1215
1216
1217 /**
1218 * Updates the view associated to the activity after the finish of an operation trying to remove a
1219 * file.
1220 *
1221 * @param operation Removal operation performed.
1222 * @param result Result of the removal.
1223 */
1224 private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
1225 dismissDialog(DIALOG_SHORT_WAIT);
1226 if (result.isSuccess()) {
1227 Toast msg = Toast.makeText(this, R.string.remove_success_msg, Toast.LENGTH_LONG);
1228 msg.show();
1229 OCFile removedFile = operation.getFile();
1230 if (mDualPane) {
1231 FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
1232 if (details != null && removedFile.equals(details.getFile())) {
1233 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1234 transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment
1235 transaction.commit();
1236 }
1237 }
1238 if (mStorageManager.getFileById(removedFile.getParentId()).equals(mCurrentDir)) {
1239 mFileList.listDirectory();
1240 }
1241
1242 } else {
1243 Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG);
1244 msg.show();
1245 if (result.isSslRecoverableException()) {
1246 mLastSslUntrustedServerResult = result;
1247 showDialog(DIALOG_SSL_VALIDATOR);
1248 }
1249 }
1250 }
1251
1252 /**
1253 * Updates the view associated to the activity after the finish of an operation trying create a new folder
1254 *
1255 * @param operation Creation operation performed.
1256 * @param result Result of the creation.
1257 */
1258 private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {
1259 if (result.isSuccess()) {
1260 dismissDialog(DIALOG_SHORT_WAIT);
1261 mFileList.listDirectory();
1262
1263 } else {
1264 dismissDialog(DIALOG_SHORT_WAIT);
1265 try {
1266 Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG);
1267 msg.show();
1268
1269 } catch (NotFoundException e) {
1270 Log_OC.e(TAG, "Error while trying to show fail message " , e);
1271 }
1272 }
1273 }
1274
1275
1276 /**
1277 * Updates the view associated to the activity after the finish of an operation trying to rename a
1278 * file.
1279 *
1280 * @param operation Renaming operation performed.
1281 * @param result Result of the renaming.
1282 */
1283 private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {
1284 dismissDialog(DIALOG_SHORT_WAIT);
1285 OCFile renamedFile = operation.getFile();
1286 if (result.isSuccess()) {
1287 if (mDualPane) {
1288 FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
1289 if (details != null && details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) {
1290 ((FileDetailFragment) details).updateFileDetails(renamedFile, AccountUtils.getCurrentOwnCloudAccount(this));
1291 }
1292 }
1293 if (mStorageManager.getFileById(renamedFile.getParentId()).equals(mCurrentDir)) {
1294 mFileList.listDirectory();
1295 }
1296
1297 } else {
1298 if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
1299 Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG);
1300 msg.show();
1301 // TODO throw again the new rename dialog
1302 } else {
1303 Toast msg = Toast.makeText(this, R.string.rename_server_fail_msg, Toast.LENGTH_LONG);
1304 msg.show();
1305 if (result.isSslRecoverableException()) {
1306 mLastSslUntrustedServerResult = result;
1307 showDialog(DIALOG_SSL_VALIDATOR);
1308 }
1309 }
1310 }
1311 }
1312
1313
1314 private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
1315 dismissDialog(DIALOG_SHORT_WAIT);
1316 OCFile syncedFile = operation.getLocalFile();
1317 if (!result.isSuccess()) {
1318 if (result.getCode() == ResultCode.SYNC_CONFLICT) {
1319 Intent i = new Intent(this, ConflictsResolveActivity.class);
1320 i.putExtra(ConflictsResolveActivity.EXTRA_FILE, syncedFile);
1321 i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
1322 startActivity(i);
1323
1324 } else {
1325 Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG);
1326 msg.show();
1327 }
1328
1329 } else {
1330 if (operation.transferWasRequested()) {
1331 mFileList.listDirectory();
1332 onTransferStateChanged(syncedFile, true, true);
1333
1334 } else {
1335 Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG);
1336 msg.show();
1337 }
1338 }
1339 }
1340
1341
1342 /**
1343 * {@inheritDoc}
1344 */
1345 @Override
1346 public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
1347 /*OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
1348 if (fileListFragment != null) {
1349 fileListFragment.listDirectory();
1350 }*/
1351 if (mDualPane) {
1352 FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
1353 if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) {
1354 if (downloading || uploading) {
1355 ((FileDetailFragment)details).updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this));
1356 } else {
1357 ((FileDetailFragment)details).updateFileDetails(false, true);
1358 }
1359 }
1360 }
1361 }
1362
1363
1364 @Override
1365 public void showFragmentWithDetails(OCFile file) {
1366 if (mDualPane) {
1367 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1368 transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
1369 transaction.commit();
1370
1371 } else {
1372 Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
1373 showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
1374 showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
1375 showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
1376 startActivity(showDetailsIntent);
1377 }
1378 }
1379
1380 public void onDismiss(EditNameDialog dialog) {
1381 //dialog.dismiss();
1382 if (dialog.getResult()) {
1383 String newDirectoryName = dialog.getNewFilename().trim();
1384 Log_OC.d(TAG, "'create directory' dialog dismissed with new name " + newDirectoryName);
1385 if (newDirectoryName.length() > 0) {
1386 String path;
1387 if (mCurrentDir == null) {
1388 // this is just a patch; we should ensure that mCurrentDir never is null
1389 if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {
1390 OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
1391 mStorageManager.saveFile(file);
1392 }
1393 mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
1394 }
1395 path = FileDisplayActivity.this.mCurrentDir.getRemotePath();
1396
1397 // Create directory
1398 path += newDirectoryName + OCFile.PATH_SEPARATOR;
1399 RemoteOperation operation = new CreateFolderOperation(path, mCurrentDir.getFileId(), mStorageManager);
1400 operation.execute( AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this),
1401 FileDisplayActivity.this,
1402 FileDisplayActivity.this,
1403 mHandler,
1404 FileDisplayActivity.this);
1405
1406 showDialog(DIALOG_SHORT_WAIT);
1407 }
1408 }
1409 }
1410
1411
1412 private void requestForDownload() {
1413 Account account = AccountUtils.getCurrentOwnCloudAccount(this);
1414 if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) {
1415 Intent i = new Intent(this, FileDownloader.class);
1416 i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
1417 i.putExtra(FileDownloader.EXTRA_FILE, mWaitingToPreview);
1418 startService(i);
1419 }
1420 }
1421
1422
1423 }