1 /* ownCloud Android client application
2 * Copyright (C) 2011 Bartek Przybylski
3 * Copyright (C) 2012-2013 ownCloud Inc.
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.
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.
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/>.
18 package com
.owncloud
.android
.ui
.activity
;
20 import android
.accounts
.Account
;
21 import android
.app
.Activity
;
22 import android
.app
.Dialog
;
23 import android
.app
.ProgressDialog
;
24 import android
.content
.BroadcastReceiver
;
25 import android
.content
.ComponentName
;
26 import android
.content
.Context
;
27 import android
.content
.Intent
;
28 import android
.content
.IntentFilter
;
29 import android
.content
.ServiceConnection
;
30 import android
.content
.res
.Configuration
;
31 import android
.os
.Bundle
;
32 import android
.os
.IBinder
;
33 import android
.support
.v4
.app
.Fragment
;
34 import android
.support
.v4
.app
.FragmentTransaction
;
36 import com
.actionbarsherlock
.app
.ActionBar
;
37 import com
.actionbarsherlock
.app
.SherlockFragmentActivity
;
38 import com
.actionbarsherlock
.view
.MenuItem
;
39 import com
.owncloud
.android
.AccountUtils
;
40 import com
.owncloud
.android
.Log_OC
;
41 import com
.owncloud
.android
.R
;
42 import com
.owncloud
.android
.datamodel
.FileDataStorageManager
;
43 import com
.owncloud
.android
.datamodel
.OCFile
;
44 import com
.owncloud
.android
.files
.services
.FileDownloader
;
45 import com
.owncloud
.android
.files
.services
.FileDownloader
.FileDownloaderBinder
;
46 import com
.owncloud
.android
.files
.services
.FileUploader
;
47 import com
.owncloud
.android
.files
.services
.FileUploader
.FileUploaderBinder
;
48 import com
.owncloud
.android
.ui
.fragment
.FileDetailFragment
;
49 import com
.owncloud
.android
.ui
.fragment
.FileFragment
;
50 import com
.owncloud
.android
.ui
.preview
.PreviewMediaFragment
;
51 import com
.owncloud
.android
.ui
.preview
.PreviewVideoActivity
;
54 * This activity displays the details of a file like its name, its size and so
57 * @author Bartek Przybylski
58 * @author David A. Velasco
60 public class FileDetailActivity
extends SherlockFragmentActivity
implements FileFragment
.ContainerActivity
{
62 public static final int DIALOG_SHORT_WAIT
= 0;
64 public static final String TAG
= FileDetailActivity
.class.getSimpleName();
66 public static final String EXTRA_MODE
= "MODE";
67 public static final int MODE_DETAILS
= 0;
68 public static final int MODE_PREVIEW
= 1;
70 public static final String KEY_WAITING_TO_PREVIEW
= "WAITING_TO_PREVIEW";
72 private FileDownloaderBinder mDownloaderBinder
= null
;
73 private ServiceConnection mDownloadConnection
, mUploadConnection
= null
;
74 private FileUploaderBinder mUploaderBinder
= null
;
75 private boolean mWaitingToPreview
;
78 private Account mAccount
;
80 private FileDataStorageManager mStorageManager
;
81 private DownloadFinishReceiver mDownloadFinishReceiver
;
85 protected void onCreate(Bundle savedInstanceState
) {
86 super.onCreate(savedInstanceState
);
88 mFile
= getIntent().getParcelableExtra(FileDetailFragment
.EXTRA_FILE
);
89 mAccount
= getIntent().getParcelableExtra(FileDetailFragment
.EXTRA_ACCOUNT
);
90 mStorageManager
= new FileDataStorageManager(mAccount
, getContentResolver());
92 setContentView(R
.layout
.file_activity_details
);
94 ActionBar actionBar
= getSupportActionBar();
95 actionBar
.setDisplayHomeAsUpEnabled(true
);
97 if (savedInstanceState
== null
) {
98 mWaitingToPreview
= false
;
99 createChildFragment();
101 mWaitingToPreview
= savedInstanceState
.getBoolean(KEY_WAITING_TO_PREVIEW
);
104 mDownloadConnection
= new DetailsServiceConnection();
105 bindService(new Intent(this, FileDownloader
.class), mDownloadConnection
, Context
.BIND_AUTO_CREATE
);
106 mUploadConnection
= new DetailsServiceConnection();
107 bindService(new Intent(this, FileUploader
.class), mUploadConnection
, Context
.BIND_AUTO_CREATE
);
111 * Creates the proper fragment depending upon the state of the handled {@link OCFile} and
112 * the requested {@link Intent}.
114 private void createChildFragment() {
115 int mode
= getIntent().getIntExtra(EXTRA_MODE
, MODE_PREVIEW
);
117 Fragment newFragment
= null
;
118 if (PreviewMediaFragment
.canBePreviewed(mFile
) && mode
== MODE_PREVIEW
) {
119 if (mFile
.isDown()) {
120 int startPlaybackPosition
= getIntent().getIntExtra(PreviewVideoActivity
.EXTRA_START_POSITION
, 0);
121 boolean autoplay
= getIntent().getBooleanExtra(PreviewVideoActivity
.EXTRA_AUTOPLAY
, true
);
122 newFragment
= new PreviewMediaFragment(mFile
, mAccount
, startPlaybackPosition
, autoplay
);
125 newFragment
= new FileDetailFragment(mFile
, mAccount
);
126 mWaitingToPreview
= true
;
130 newFragment
= new FileDetailFragment(mFile
, mAccount
);
132 FragmentTransaction ft
= getSupportFragmentManager().beginTransaction();
133 ft
.replace(R
.id
.fragment
, newFragment
, FileDetailFragment
.FTAG
);
139 public void onConfigurationChanged (Configuration newConfig
) {
140 super.onConfigurationChanged(newConfig
);
142 Intent intent
= null
;
143 if ((newConfig
.screenLayout
& Configuration
.SCREENLAYOUT_SIZE_MASK
) >= Configuration
.SCREENLAYOUT_SIZE_LARGE
144 && newConfig
.orientation
== Configuration
.ORIENTATION_LANDSCAPE
) {
146 intent
= new Intent(this, FileDisplayActivity
.class);
147 intent
.putExtra(FileDetailFragment
.EXTRA_FILE
, mFile
);
148 intent
.putExtra(FileDetailFragment
.EXTRA_ACCOUNT
, mAccount
);
149 intent
.putExtra(EXTRA_MODE
, getIntent().getIntExtra(EXTRA_MODE
, MODE_PREVIEW
));
150 intent
.addFlags(Intent
.FLAG_ACTIVITY_CLEAR_TOP
);
151 Fragment fragment
= getSupportFragmentManager().findFragmentByTag(FileDetailFragment
.FTAG
);
152 if (fragment
!= null
&& mFile
!= null
&& fragment
instanceof PreviewMediaFragment
&& mFile
.isVideo()) {
153 PreviewMediaFragment videoFragment
= (PreviewMediaFragment
)fragment
;
154 intent
.putExtra(PreviewVideoActivity
.EXTRA_START_POSITION
, videoFragment
.getPosition());
155 intent
.putExtra(PreviewVideoActivity
.EXTRA_AUTOPLAY
, videoFragment
.isPlaying());
159 intent
= new Intent(this, FileDetailActivity
.class);
160 intent
.putExtra(FileDetailFragment
.EXTRA_FILE
, mFile
);
161 intent
.putExtra(FileDetailFragment
.EXTRA_ACCOUNT
, mAccount
);
162 intent
.putExtra(EXTRA_MODE
, getIntent().getIntExtra(EXTRA_MODE
, MODE_PREVIEW
));
163 Fragment fragment
= getSupportFragmentManager().findFragmentByTag(FileDetailFragment
.FTAG
);
164 if (fragment
!= null
&& mFile
!= null
&& fragment
instanceof PreviewMediaFragment
&& mFile
.isVideo()) {
165 PreviewMediaFragment videoFragment
= (PreviewMediaFragment
)fragment
;
166 intent
.putExtra(PreviewVideoActivity
.EXTRA_START_POSITION
, videoFragment
.getPosition());
167 intent
.putExtra(PreviewVideoActivity
.EXTRA_AUTOPLAY
, videoFragment
.isPlaying());
169 // and maybe 'waiting to preview' flag
171 startActivity(intent
);
176 protected void onSaveInstanceState(Bundle outState
) {
177 super.onSaveInstanceState(outState
);
178 outState
.putBoolean(KEY_WAITING_TO_PREVIEW
, mWaitingToPreview
);
183 public void onPause() {
185 if (mDownloadFinishReceiver
!= null
) {
186 unregisterReceiver(mDownloadFinishReceiver
);
187 mDownloadFinishReceiver
= null
;
193 public void onResume() {
195 // TODO this is probably unnecessary
196 Fragment fragment
= getSupportFragmentManager().findFragmentByTag(FileDetailFragment
.FTAG
);
197 if (fragment
!= null
&& fragment
instanceof FileDetailFragment
) {
198 ((FileDetailFragment
) fragment
).updateFileDetails(false
, false
);
201 // Listen for download messages
202 IntentFilter downloadIntentFilter
= new IntentFilter(FileDownloader
.DOWNLOAD_ADDED_MESSAGE
);
203 downloadIntentFilter
.addAction(FileDownloader
.DOWNLOAD_FINISH_MESSAGE
);
204 mDownloadFinishReceiver
= new DownloadFinishReceiver();
205 registerReceiver(mDownloadFinishReceiver
, downloadIntentFilter
);
209 /** Defines callbacks for service binding, passed to bindService() */
210 private class DetailsServiceConnection
implements ServiceConnection
{
213 public void onServiceConnected(ComponentName component
, IBinder service
) {
215 if (component
.equals(new ComponentName(FileDetailActivity
.this, FileDownloader
.class))) {
216 Log_OC
.d(TAG
, "Download service connected");
217 mDownloaderBinder
= (FileDownloaderBinder
) service
;
218 if (mWaitingToPreview
) {
219 requestForDownload();
222 } else if (component
.equals(new ComponentName(FileDetailActivity
.this, FileUploader
.class))) {
223 Log_OC
.d(TAG
, "Upload service connected");
224 mUploaderBinder
= (FileUploaderBinder
) service
;
229 Fragment fragment
= getSupportFragmentManager().findFragmentByTag(FileDetailFragment
.FTAG
);
230 FileDetailFragment detailsFragment
= (fragment
instanceof FileDetailFragment
) ?
(FileDetailFragment
) fragment
: null
;
231 if (detailsFragment
!= null
) {
232 detailsFragment
.listenForTransferProgress();
233 detailsFragment
.updateFileDetails(mWaitingToPreview
, false
); // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())
238 public void onServiceDisconnected(ComponentName component
) {
239 if (component
.equals(new ComponentName(FileDetailActivity
.this, FileDownloader
.class))) {
240 Log_OC
.d(TAG
, "Download service disconnected");
241 mDownloaderBinder
= null
;
242 } else if (component
.equals(new ComponentName(FileDetailActivity
.this, FileUploader
.class))) {
243 Log_OC
.d(TAG
, "Upload service disconnected");
244 mUploaderBinder
= null
;
251 public void onDestroy() {
253 if (mDownloadConnection
!= null
) {
254 unbindService(mDownloadConnection
);
255 mDownloadConnection
= null
;
257 if (mUploadConnection
!= null
) {
258 unbindService(mUploadConnection
);
259 mUploadConnection
= null
;
265 public boolean onOptionsItemSelected(MenuItem item
) {
266 boolean returnValue
= false
;
268 switch(item
.getItemId()){
269 case android
.R
.id
.home
:
270 //backToDisplayActivity();
275 returnValue
= super.onOptionsItemSelected(item
);
281 //private void backToDisplayActivity() {
283 public void onBackPressed() {
284 Intent intent
= new Intent(this, FileDisplayActivity
.class);
285 intent
.addFlags(Intent
.FLAG_ACTIVITY_CLEAR_TOP
);
286 OCFile targetFile
= null
;
288 targetFile
= mStorageManager
.getFileById(mFile
.getParentId());
290 intent
.putExtra(FileDetailFragment
.EXTRA_FILE
, targetFile
);
291 intent
.putExtra(FileDetailFragment
.EXTRA_ACCOUNT
, mAccount
);
292 startActivity(intent
);
297 protected Dialog
onCreateDialog(int id
) {
298 Dialog dialog
= null
;
300 case DIALOG_SHORT_WAIT
: {
301 ProgressDialog working_dialog
= new ProgressDialog(this);
302 working_dialog
.setMessage(getResources().getString(
303 R
.string
.wait_a_moment
));
304 working_dialog
.setIndeterminate(true
);
305 working_dialog
.setCancelable(false
);
306 dialog
= working_dialog
;
320 public void onFileStateChanged() {
321 // nothing to do here!
329 public FileDownloaderBinder
getFileDownloaderBinder() {
330 return mDownloaderBinder
;
335 public FileUploaderBinder
getFileUploaderBinder() {
336 return mUploaderBinder
;
341 public void showFragmentWithDetails(OCFile file
) {
342 FragmentTransaction transaction
= getSupportFragmentManager().beginTransaction();
343 transaction
.replace(R
.id
.fragment
, new FileDetailFragment(file
, mAccount
), FileDetailFragment
.FTAG
);
344 transaction
.commit();
348 private void requestForDownload() {
349 if (!mDownloaderBinder
.isDownloading(mAccount
, mFile
)) {
350 Intent i
= new Intent(this, FileDownloader
.class);
351 i
.putExtra(FileDownloader
.EXTRA_ACCOUNT
, mAccount
);
352 i
.putExtra(FileDownloader
.EXTRA_FILE
, mFile
);
359 * Class waiting for broadcast events from the {@link FielDownloader} service.
361 * Updates the UI when a download is started or finished, provided that it is relevant for the
364 private class DownloadFinishReceiver
extends BroadcastReceiver
{
366 public void onReceive(Context context
, Intent intent
) {
367 boolean sameAccount
= isSameAccount(context
, intent
);
368 String downloadedRemotePath
= intent
.getStringExtra(FileDownloader
.EXTRA_REMOTE_PATH
);
369 boolean samePath
= (mFile
!= null
&& mFile
.getRemotePath().equals(downloadedRemotePath
));
371 if (sameAccount
&& samePath
) {
372 updateChildFragment(intent
.getAction(), downloadedRemotePath
, intent
.getBooleanExtra(FileDownloader
.EXTRA_DOWNLOAD_RESULT
, false
));
375 removeStickyBroadcast(intent
);
378 private boolean isSameAccount(Context context
, Intent intent
) {
379 String accountName
= intent
.getStringExtra(FileDownloader
.ACCOUNT_NAME
);
380 return (accountName
!= null
&& accountName
.equals(AccountUtils
.getCurrentOwnCloudAccount(context
).name
));
385 public void updateChildFragment(String downloadEvent
, String downloadedRemotePath
, boolean success
) {
386 Fragment fragment
= getSupportFragmentManager().findFragmentByTag(FileDetailFragment
.FTAG
);
387 if (fragment
!= null
&& fragment
instanceof FileDetailFragment
) {
388 FileDetailFragment detailsFragment
= (FileDetailFragment
) fragment
;
389 OCFile fileInFragment
= detailsFragment
.getFile();
390 if (fileInFragment
!= null
&& !downloadedRemotePath
.equals(fileInFragment
.getRemotePath())) {
391 // this never should happen; fileInFragment should be always equals to mFile, that was compared to downloadedRemotePath in DownloadReceiver
392 mWaitingToPreview
= false
;
394 } else if (downloadEvent
.equals(FileDownloader
.DOWNLOAD_ADDED_MESSAGE
)) {
395 // grants that the progress bar is updated
396 detailsFragment
.listenForTransferProgress();
397 detailsFragment
.updateFileDetails(true
, false
);
399 } else if (downloadEvent
.equals(FileDownloader
.DOWNLOAD_FINISH_MESSAGE
)) {
400 // refresh the details fragment
401 if (success
&& mWaitingToPreview
) {
402 mFile
= mStorageManager
.getFileById(mFile
.getFileId()); // update the file from database, for the local storage path
403 FragmentTransaction transaction
= getSupportFragmentManager().beginTransaction();
404 transaction
.replace(R
.id
.fragment
, new PreviewMediaFragment(mFile
, mAccount
, 0, true
), FileDetailFragment
.FTAG
);
405 transaction
.commit();
406 mWaitingToPreview
= false
;
409 detailsFragment
.updateFileDetails(false
, (success
));
410 // TODO error message if !success ¿?
413 } // TODO else if (fragment != null && fragment )