1 package com
.owncloud
.android
.ui
.activity
;
3 import java
.io
.IOException
;
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
;
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
;
45 public class MoveActivity
extends HookActivity
implements FileFragment
.ContainerActivity
,
48 private SyncBroadcastReceiver mSyncBroadcastReceiver
;
50 private static final String TAG
= MoveActivity
.class.getSimpleName();
52 private static final String TAG_LIST_OF_FOLDERS
= "LIST_OF_FOLDERS";
54 private boolean mSyncInProgress
= false
;
56 private Button mCancelBtn
;
57 private Button mChooseBtn
;
61 protected void onCreate(Bundle savedInstanceState
) {
62 Log_OC
.d(TAG
, "onCreate() start");
63 requestWindowFeature(Window
.FEATURE_INDETERMINATE_PROGRESS
);
65 super.onCreate(savedInstanceState
);
67 setContentView(R
.layout
.files_move
);
69 if (savedInstanceState
== null
) {
73 // sets callback listeners for UI elements
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
83 // sets message for empty list of folders
86 Log_OC
.d(TAG
, "onCreate() end");
91 protected void onStart() {
93 getSupportActionBar().setIcon(DisplayUtils
.getSeasonalIconId());
97 protected void onDestroy() {
102 * Called when the ownCloud {@link Account} associated to the Activity was just updated.
105 protected void onAccountSet(boolean stateWasRecovered
) {
106 super.onAccountSet(stateWasRecovered
);
107 if (getAccount() != null
) {
111 OCFile folder
= getFile();
112 if (folder
== null
|| !folder
.isFolder()) {
113 // fall back to root folder
114 setFile(getStorageManager().getFileByPath(OCFile
.ROOT_PATH
));
118 if (!stateWasRecovered
) {
119 MoveFileListFragment listOfFolders
= getListOfFilesFragment();
120 listOfFolders
.listDirectory(folder
);
122 startSyncFolderOperation(folder
);
125 updateNavigationElementsInActionBar();
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();
137 * Show a text message on screen view for notifying user if content is
138 * loading or folder is empty
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
;
148 MoveFileListFragment
.setMessageForEmptyList(getString(message
));
150 Log
.e(TAG
, "MoveFileListFragment is null");
154 private MoveFileListFragment
getListOfFilesFragment() {
155 Fragment listOfFiles
= getSupportFragmentManager().findFragmentByTag(MoveActivity
.TAG_LIST_OF_FOLDERS
);
156 if (listOfFiles
!= null
) {
157 return (MoveFileListFragment
)listOfFiles
;
159 Log_OC
.wtf(TAG
, "Access to unexisting list of files fragment!!");
167 * Updates action bar and second fragment, if in dual pane mode.
170 public void onBrowsedDownTo(OCFile directory
) {
172 updateNavigationElementsInActionBar();
174 startSyncFolderOperation(directory
);
179 public void startSyncFolderOperation(OCFile folder
) {
180 long currentSyncTime
= System
.currentTimeMillis();
182 mSyncInProgress
= true
;
184 // perform folder synchronization
185 RemoteOperation synchFolderOp
= new SynchronizeFolderOperation( folder
,
188 getFileOperationsHelper().isSharedSupported(),
191 getApplicationContext()
193 synchFolderOp
.execute(getAccount(), this, null
, null
);
195 setSupportProgressBarIndeterminateVisibility(true
);
201 protected void onResume() {
203 Log_OC
.e(TAG
, "onResume() start");
205 // refresh list of files
206 refreshListOfFilesFragment();
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
);
217 Log_OC
.d(TAG
, "onResume() end");
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
;
229 Log_OC
.d(TAG
, "onPause() end");
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
);
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());
251 getSupportFragmentManager(),
252 CreateFolderDialogFragment
.CREATE_FOLDER_FRAGMENT
256 case android
.R
.id
.home
: {
257 OCFile currentDir
= getCurrentFolder();
258 if(currentDir
!= null
&& currentDir
.getParentId() != 0) {
264 retval
= super.onOptionsItemSelected(item
);
269 private OCFile
getCurrentFolder() {
270 OCFile file
= getFile();
272 if (file
.isFolder()) {
274 } else if (getStorageManager() != null
) {
275 String parentPath
= file
.getRemotePath().substring(0, file
.getRemotePath().lastIndexOf(file
.getFileName()));
276 return getStorageManager().getFileByPath(parentPath
);
282 protected void refreshListOfFilesFragment() {
283 MoveFileListFragment fileListFragment
= getListOfFilesFragment();
284 if (fileListFragment
!= null
) {
285 fileListFragment
.listDirectory();
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
);
301 public void onBackPressed() {
302 MoveFileListFragment listOfFiles
= getListOfFilesFragment();
303 if (listOfFiles
!= null
) { // should never be null, indeed
304 int levelsUp
= listOfFiles
.onBrowseUp();
309 setFile(listOfFiles
.getCurrentFile());
310 updateNavigationElementsInActionBar();
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
);
322 ?
getString(R
.string
.default_display_name_for_root_folder
)
323 : currentDir
.getFileName()
328 * Set per-view controllers
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);
338 public void onClick(View v
) {
339 if (v
== mCancelBtn
) {
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",
352 private class SyncBroadcastReceiver
extends BroadcastReceiver
{
355 * {@link BroadcastReceiver} to enable syncing feedback in UI
358 public void onReceive(Context context
, Intent intent
) {
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
);
369 if (FileSyncAdapter
.EVENT_FULL_SYNC_START
.equals(event
)) {
370 mSyncInProgress
= true
;
373 OCFile currentFile
= (getFile() == null
) ? null
: getStorageManager().getFileByPath(getFile().getRemotePath());
374 OCFile currentDir
= (getCurrentFolder() == null
) ? null
: getStorageManager().getFileByPath(getCurrentFolder().getRemotePath());
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"),
385 if (currentFile
== null
&& !getFile().isFolder()) {
386 // currently selected file was removed in the server, and now we know it
387 currentFile
= currentDir
;
390 if (synchFolderRemotePath
!= null
&& currentDir
.getRemotePath().equals(synchFolderRemotePath
)) {
391 MoveFileListFragment fileListFragment
= getListOfFilesFragment();
392 if (fileListFragment
!= null
) {
393 fileListFragment
.listDirectory(currentDir
);
396 setFile(currentFile
);
399 mSyncInProgress
= (!FileSyncAdapter
.EVENT_FULL_SYNC_END
.equals(event
) && !SynchronizeFolderOperation
.EVENT_SINGLE_FOLDER_SHARES_SYNCED
.equals(event
));
401 if (SynchronizeFolderOperation
.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED
.
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
))) {
410 OwnCloudClient client
= null
;
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
) {
419 } catch (AuthenticatorException e
) {
421 } catch (OperationCanceledException e
) {
423 } catch (IOException e
) {
427 if (client
!= null
) {
428 OwnCloudCredentials cred
= client
.getCredentials();
430 AccountManager am
= AccountManager
.get(context
);
431 if (cred
.authTokenExpires()) {
432 am
.invalidateAuthToken(
437 am
.clearPassword(getAccount());
442 requestCredentialsUpdate();
446 removeStickyBroadcast(intent
);
447 Log_OC
.d(TAG
, "Setting progress visibility to " + mSyncInProgress
);
448 setSupportProgressBarIndeterminateVisibility(mSyncInProgress
/*|| mRefreshSharesInProgress*/);
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
);
465 * Shows the information of the {@link OCFile} received as a
466 * parameter in the second fragment.
468 * @param file {@link OCFile} whose details will be shown
471 public void showDetails(OCFile file
) {
479 public void onTransferStateChanged(OCFile file
, boolean downloading
, boolean uploading
) {