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