89de5e9a26756a45b70b980238ba643b328f2c3c
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / activity / MoveActivity.java
1 package com.owncloud.android.ui.activity;
2
3 import java.io.IOException;
4
5 import android.accounts.Account;
6 import android.accounts.AccountManager;
7 import android.accounts.AuthenticatorException;
8 import android.accounts.OperationCanceledException;
9 import android.content.BroadcastReceiver;
10 import android.content.Context;
11 import android.content.Intent;
12 import android.content.IntentFilter;
13 import android.os.Bundle;
14 import android.support.v4.app.Fragment;
15 import android.support.v4.app.FragmentTransaction;
16 import android.util.Log;
17 import android.view.View;
18 import android.view.View.OnClickListener;
19 import android.widget.Button;
20 import android.widget.Toast;
21
22 import com.actionbarsherlock.app.ActionBar;
23 import com.actionbarsherlock.view.Menu;
24 import com.actionbarsherlock.view.MenuInflater;
25 import com.actionbarsherlock.view.MenuItem;
26 import com.actionbarsherlock.view.Window;
27 import com.owncloud.android.R;
28 import com.owncloud.android.datamodel.OCFile;
29 import com.owncloud.android.lib.common.OwnCloudAccount;
30 import com.owncloud.android.lib.common.OwnCloudClient;
31 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
32 import com.owncloud.android.lib.common.OwnCloudCredentials;
33 import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
34 import com.owncloud.android.lib.common.operations.RemoteOperation;
35 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
36 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
37 import com.owncloud.android.operations.SynchronizeFolderOperation;
38 import com.owncloud.android.syncadapter.FileSyncAdapter;
39 import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
40 import com.owncloud.android.ui.fragment.FileFragment;
41 import com.owncloud.android.ui.fragment.MoveFileListFragment;
42 import com.owncloud.android.utils.DisplayUtils;
43 import com.owncloud.android.utils.Log_OC;
44
45 public class MoveActivity extends HookActivity implements FileFragment.ContainerActivity,
46 OnClickListener{
47
48 private SyncBroadcastReceiver mSyncBroadcastReceiver;
49
50 private static final String TAG = MoveActivity.class.getSimpleName();
51
52 private static final String TAG_LIST_OF_FOLDERS = "LIST_OF_FOLDERS";
53
54 private boolean mSyncInProgress = false;
55
56 private Button mCancelBtn;
57 private Button mChooseBtn;
58
59
60 @Override
61 protected void onCreate(Bundle savedInstanceState) {
62 Log_OC.d(TAG, "onCreate() start");
63 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
64
65 super.onCreate(savedInstanceState);
66
67 setContentView(R.layout.files_move);
68
69 if (savedInstanceState == null) {
70 createFragments();
71 }
72
73 // sets callback listeners for UI elements
74 initControls();
75
76 // Action bar setup
77 ActionBar actionBar = getSupportActionBar();
78 actionBar.setDisplayShowTitleEnabled(true);
79 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
80 setSupportProgressBarIndeterminateVisibility(mSyncInProgress);
81 // always AFTER setContentView(...) ; to work around bug in its implementation
82
83 // sets message for empty list of folders
84 setBackgroundText();
85
86 Log_OC.d(TAG, "onCreate() end");
87
88 }
89
90 @Override
91 protected void onStart() {
92 super.onStart();
93 getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
94 }
95
96 @Override
97 protected void onDestroy() {
98 super.onDestroy();
99 }
100
101 /**
102 * Called when the ownCloud {@link Account} associated to the Activity was just updated.
103 */
104 @Override
105 protected void onAccountSet(boolean stateWasRecovered) {
106 super.onAccountSet(stateWasRecovered);
107 if (getAccount() != null) {
108
109 updateFileFromDB();
110
111 OCFile folder = getFile();
112 if (folder == null || !folder.isFolder()) {
113 // fall back to root folder
114 setFile(getStorageManager().getFileByPath(OCFile.ROOT_PATH));
115 folder = getFile();
116 }
117
118 if (!stateWasRecovered) {
119 MoveFileListFragment listOfFolders = getListOfFilesFragment();
120 listOfFolders.listDirectory(folder);
121
122 startSyncFolderOperation(folder);
123 }
124
125 updateNavigationElementsInActionBar();
126 }
127 }
128
129 private void createFragments() {
130 MoveFileListFragment listOfFiles = new MoveFileListFragment();
131 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
132 transaction.add(R.id.fragment_container, listOfFiles, TAG_LIST_OF_FOLDERS);
133 transaction.commit();
134 }
135
136 /**
137 * Show a text message on screen view for notifying user if content is
138 * loading or folder is empty
139 */
140 private void setBackgroundText() {
141 MoveFileListFragment MoveFileListFragment = getListOfFilesFragment();
142 if (MoveFileListFragment != null) {
143 int message = R.string.file_list_loading;
144 if (!mSyncInProgress) {
145 // In case folder list is empty
146 message = R.string.file_list_empty_moving;
147 }
148 MoveFileListFragment.setMessageForEmptyList(getString(message));
149 } else {
150 Log.e(TAG, "MoveFileListFragment is null");
151 }
152 }
153
154 private MoveFileListFragment getListOfFilesFragment() {
155 Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag(MoveActivity.TAG_LIST_OF_FOLDERS);
156 if (listOfFiles != null) {
157 return (MoveFileListFragment)listOfFiles;
158 }
159 Log_OC.wtf(TAG, "Access to unexisting list of files fragment!!");
160 return null;
161 }
162
163
164 /**
165 * {@inheritDoc}
166 *
167 * Updates action bar and second fragment, if in dual pane mode.
168 */
169 @Override
170 public void onBrowsedDownTo(OCFile directory) {
171 setFile(directory);
172 updateNavigationElementsInActionBar();
173 // Sync Folder
174 startSyncFolderOperation(directory);
175
176 }
177
178
179 public void startSyncFolderOperation(OCFile folder) {
180 long currentSyncTime = System.currentTimeMillis();
181
182 mSyncInProgress = true;
183
184 // perform folder synchronization
185 RemoteOperation synchFolderOp = new SynchronizeFolderOperation( folder,
186 currentSyncTime,
187 false,
188 getFileOperationsHelper().isSharedSupported(),
189 getStorageManager(),
190 getAccount(),
191 getApplicationContext()
192 );
193 synchFolderOp.execute(getAccount(), this, null, null);
194
195 setSupportProgressBarIndeterminateVisibility(true);
196
197 setBackgroundText();
198 }
199
200 @Override
201 protected void onResume() {
202 super.onResume();
203 Log_OC.e(TAG, "onResume() start");
204
205 // refresh list of files
206 refreshListOfFilesFragment();
207
208 // Listen for sync messages
209 IntentFilter syncIntentFilter = new IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START);
210 syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_END);
211 syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED);
212 syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED);
213 syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
214 mSyncBroadcastReceiver = new SyncBroadcastReceiver();
215 registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
216
217 Log_OC.d(TAG, "onResume() end");
218 }
219
220 @Override
221 protected void onPause() {
222 Log_OC.e(TAG, "onPause() start");
223 if (mSyncBroadcastReceiver != null) {
224 unregisterReceiver(mSyncBroadcastReceiver);
225 //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
226 mSyncBroadcastReceiver = null;
227 }
228
229 Log_OC.d(TAG, "onPause() end");
230 super.onPause();
231 }
232
233 @Override
234 public boolean onCreateOptionsMenu(Menu menu) {
235 MenuInflater inflater = getSherlock().getMenuInflater();
236 inflater.inflate(R.menu.main_menu, menu);
237 menu.findItem(R.id.action_upload).setVisible(false);
238 menu.findItem(R.id.action_settings).setVisible(false);
239 menu.findItem(R.id.action_sync_account).setVisible(false);
240 return true;
241 }
242
243 @Override
244 public boolean onOptionsItemSelected(MenuItem item) {
245 boolean retval = true;
246 switch (item.getItemId()) {
247 case R.id.action_create_dir: {
248 CreateFolderDialogFragment dialog =
249 CreateFolderDialogFragment.newInstance(getCurrentFolder());
250 dialog.show(
251 getSupportFragmentManager(),
252 CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT
253 );
254 break;
255 }
256 case android.R.id.home: {
257 OCFile currentDir = getCurrentFolder();
258 if(currentDir != null && currentDir.getParentId() != 0) {
259 onBackPressed();
260 }
261 break;
262 }
263 default:
264 retval = super.onOptionsItemSelected(item);
265 }
266 return retval;
267 }
268
269 private OCFile getCurrentFolder() {
270 OCFile file = getFile();
271 if (file != null) {
272 if (file.isFolder()) {
273 return file;
274 } else if (getStorageManager() != null) {
275 String parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
276 return getStorageManager().getFileByPath(parentPath);
277 }
278 }
279 return null;
280 }
281
282 protected void refreshListOfFilesFragment() {
283 MoveFileListFragment fileListFragment = getListOfFilesFragment();
284 if (fileListFragment != null) {
285 fileListFragment.listDirectory();
286 }
287 }
288
289 public void browseToRoot() {
290 MoveFileListFragment listOfFiles = getListOfFilesFragment();
291 if (listOfFiles != null) { // should never be null, indeed
292 OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
293 listOfFiles.listDirectory(root);
294 setFile(listOfFiles.getCurrentFile());
295 updateNavigationElementsInActionBar();
296 startSyncFolderOperation(root);
297 }
298 }
299
300 @Override
301 public void onBackPressed() {
302 MoveFileListFragment listOfFiles = getListOfFilesFragment();
303 if (listOfFiles != null) { // should never be null, indeed
304 int levelsUp = listOfFiles.onBrowseUp();
305 if (levelsUp == 0) {
306 finish();
307 return;
308 }
309 setFile(listOfFiles.getCurrentFile());
310 updateNavigationElementsInActionBar();
311 }
312 }
313
314 private void updateNavigationElementsInActionBar() {
315 ActionBar actionBar = getSupportActionBar();
316 OCFile currentDir = getCurrentFolder();
317 boolean atRoot = (currentDir == null || currentDir.getParentId() == 0);
318 actionBar.setDisplayHomeAsUpEnabled(!atRoot);
319 actionBar.setHomeButtonEnabled(!atRoot);
320 actionBar.setTitle(
321 atRoot
322 ? getString(R.string.default_display_name_for_root_folder)
323 : currentDir.getFileName()
324 );
325 }
326
327 /**
328 * Set per-view controllers
329 */
330 private void initControls(){
331 mCancelBtn = (Button) findViewById(R.id.move_files_btn_cancel);
332 mCancelBtn.setOnClickListener(this);
333 mChooseBtn = (Button) findViewById(R.id.move_files_btn_choose);
334 mChooseBtn.setOnClickListener(this);
335 }
336
337 @Override
338 public void onClick(View v) {
339 if (v == mCancelBtn) {
340 finish();
341 } else if (v == mChooseBtn) {
342 // TODO request to move, OR save selected folder as a result and let request for caller
343 Toast.makeText( MoveActivity.this,
344 "TODO: MOVE IMPLEMENTATION",
345 Toast.LENGTH_LONG)
346 .show();
347 finish();
348 }
349 }
350
351
352 private class SyncBroadcastReceiver extends BroadcastReceiver {
353
354 /**
355 * {@link BroadcastReceiver} to enable syncing feedback in UI
356 */
357 @Override
358 public void onReceive(Context context, Intent intent) {
359 try {
360 String event = intent.getAction();
361 Log_OC.d(TAG, "Received broadcast " + event);
362 String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME);
363 String synchFolderRemotePath = intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH);
364 RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncAdapter.EXTRA_RESULT);
365 boolean sameAccount = (getAccount() != null && accountName.equals(getAccount().name) && getStorageManager() != null);
366
367 if (sameAccount) {
368
369 if (FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) {
370 mSyncInProgress = true;
371
372 } else {
373 OCFile currentFile = (getFile() == null) ? null : getStorageManager().getFileByPath(getFile().getRemotePath());
374 OCFile currentDir = (getCurrentFolder() == null) ? null : getStorageManager().getFileByPath(getCurrentFolder().getRemotePath());
375
376 if (currentDir == null) {
377 // current folder was removed from the server
378 Toast.makeText( MoveActivity.this,
379 String.format(getString(R.string.sync_current_folder_was_removed), "PLACEHOLDER"),
380 Toast.LENGTH_LONG)
381 .show();
382 browseToRoot();
383
384 } else {
385 if (currentFile == null && !getFile().isFolder()) {
386 // currently selected file was removed in the server, and now we know it
387 currentFile = currentDir;
388 }
389
390 if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) {
391 MoveFileListFragment fileListFragment = getListOfFilesFragment();
392 if (fileListFragment != null) {
393 fileListFragment.listDirectory(currentDir);
394 }
395 }
396 setFile(currentFile);
397 }
398
399 mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event));
400
401 if (SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
402 equals(event) &&
403 /// TODO refactor and make common
404 synchResult != null && !synchResult.isSuccess() &&
405 (synchResult.getCode() == ResultCode.UNAUTHORIZED ||
406 synchResult.isIdPRedirection() ||
407 (synchResult.isException() && synchResult.getException()
408 instanceof AuthenticatorException))) {
409
410 OwnCloudClient client = null;
411 try {
412 OwnCloudAccount ocAccount =
413 new OwnCloudAccount(getAccount(), context);
414 client = (OwnCloudClientManagerFactory.getDefaultSingleton().
415 removeClientFor(ocAccount));
416 // TODO get rid of these exceptions
417 } catch (AccountNotFoundException e) {
418 e.printStackTrace();
419 } catch (AuthenticatorException e) {
420 e.printStackTrace();
421 } catch (OperationCanceledException e) {
422 e.printStackTrace();
423 } catch (IOException e) {
424 e.printStackTrace();
425 }
426
427 if (client != null) {
428 OwnCloudCredentials cred = client.getCredentials();
429 if (cred != null) {
430 AccountManager am = AccountManager.get(context);
431 if (cred.authTokenExpires()) {
432 am.invalidateAuthToken(
433 getAccount().type,
434 cred.getAuthToken()
435 );
436 } else {
437 am.clearPassword(getAccount());
438 }
439 }
440 }
441
442 requestCredentialsUpdate();
443
444 }
445 }
446 removeStickyBroadcast(intent);
447 Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
448 setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/);
449
450 setBackgroundText();
451
452 }
453
454 } catch (RuntimeException e) {
455 // avoid app crashes after changing the serial id of RemoteOperationResult
456 // in owncloud library with broadcast notifications pending to process
457 removeStickyBroadcast(intent);
458 }
459 }
460 }
461
462
463
464 /**
465 * Shows the information of the {@link OCFile} received as a
466 * parameter in the second fragment.
467 *
468 * @param file {@link OCFile} whose details will be shown
469 */
470 @Override
471 public void showDetails(OCFile file) {
472
473 }
474
475 /**
476 * {@inheritDoc}
477 */
478 @Override
479 public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
480
481 }
482
483
484 }