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