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