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