8af69f228b2ccd9c9e77c3aecfb783a7215384fa
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / activity / FileDetailActivity.java
1 /* ownCloud Android client application
2 * Copyright (C) 2011 Bartek Przybylski
3 * Copyright (C) 2012-2013 ownCloud Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18 package com.owncloud.android.ui.activity;
19
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;
35
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;
52
53 /**
54 * This activity displays the details of a file like its name, its size and so
55 * on.
56 *
57 * @author Bartek Przybylski
58 * @author David A. Velasco
59 */
60 public class FileDetailActivity extends SherlockFragmentActivity implements FileFragment.ContainerActivity {
61
62 public static final int DIALOG_SHORT_WAIT = 0;
63
64 public static final String TAG = FileDetailActivity.class.getSimpleName();
65
66 public static final String EXTRA_MODE = "MODE";
67 public static final int MODE_DETAILS = 0;
68 public static final int MODE_PREVIEW = 1;
69
70 public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
71
72 private FileDownloaderBinder mDownloaderBinder = null;
73 private ServiceConnection mDownloadConnection, mUploadConnection = null;
74 private FileUploaderBinder mUploaderBinder = null;
75 private boolean mWaitingToPreview;
76
77 private OCFile mFile;
78 private Account mAccount;
79
80 private FileDataStorageManager mStorageManager;
81 private DownloadFinishReceiver mDownloadFinishReceiver;
82
83
84 @Override
85 protected void onCreate(Bundle savedInstanceState) {
86 super.onCreate(savedInstanceState);
87
88 mFile = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
89 mAccount = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
90 mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
91
92 setContentView(R.layout.file_activity_details);
93
94 ActionBar actionBar = getSupportActionBar();
95 actionBar.setDisplayHomeAsUpEnabled(true);
96
97 if (savedInstanceState == null) {
98 mWaitingToPreview = false;
99 createChildFragment();
100 } else {
101 mWaitingToPreview = savedInstanceState.getBoolean(KEY_WAITING_TO_PREVIEW);
102 }
103
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);
108 }
109
110 /**
111 * Creates the proper fragment depending upon the state of the handled {@link OCFile} and
112 * the requested {@link Intent}.
113 */
114 private void createChildFragment() {
115 int mode = getIntent().getIntExtra(EXTRA_MODE, MODE_PREVIEW);
116
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);
123
124 } else {
125 newFragment = new FileDetailFragment(mFile, mAccount);
126 mWaitingToPreview = true;
127 }
128
129 } else {
130 newFragment = new FileDetailFragment(mFile, mAccount);
131 }
132 FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
133 ft.replace(R.id.fragment, newFragment, FileDetailFragment.FTAG);
134 ft.commit();
135 }
136
137
138 @Override
139 public void onConfigurationChanged (Configuration newConfig) {
140 super.onConfigurationChanged(newConfig);
141 finish();
142 Intent intent = null;
143 if ((newConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE
144 && newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
145
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());
156 }
157
158 } else {
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());
168 }
169 // and maybe 'waiting to preview' flag
170 }
171 startActivity(intent);
172 }
173
174
175 @Override
176 protected void onSaveInstanceState(Bundle outState) {
177 super.onSaveInstanceState(outState);
178 outState.putBoolean(KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
179 }
180
181
182 @Override
183 public void onPause() {
184 super.onPause();
185 if (mDownloadFinishReceiver != null) {
186 unregisterReceiver(mDownloadFinishReceiver);
187 mDownloadFinishReceiver = null;
188 }
189 }
190
191
192 @Override
193 public void onResume() {
194 super.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);
199 }
200
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);
206 }
207
208
209 /** Defines callbacks for service binding, passed to bindService() */
210 private class DetailsServiceConnection implements ServiceConnection {
211
212 @Override
213 public void onServiceConnected(ComponentName component, IBinder service) {
214
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();
220 }
221
222 } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {
223 Log_OC.d(TAG, "Upload service connected");
224 mUploaderBinder = (FileUploaderBinder) service;
225 } else {
226 return;
227 }
228
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())
234 }
235 }
236
237 @Override
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;
245 }
246 }
247 };
248
249
250 @Override
251 public void onDestroy() {
252 super.onDestroy();
253 if (mDownloadConnection != null) {
254 unbindService(mDownloadConnection);
255 mDownloadConnection = null;
256 }
257 if (mUploadConnection != null) {
258 unbindService(mUploadConnection);
259 mUploadConnection = null;
260 }
261 }
262
263
264 @Override
265 public boolean onOptionsItemSelected(MenuItem item) {
266 boolean returnValue = false;
267
268 switch(item.getItemId()){
269 case android.R.id.home:
270 //backToDisplayActivity();
271 onBackPressed();
272 returnValue = true;
273 break;
274 default:
275 returnValue = super.onOptionsItemSelected(item);
276 }
277
278 return returnValue;
279 }
280
281 //private void backToDisplayActivity() {
282 @Override
283 public void onBackPressed() {
284 Intent intent = new Intent(this, FileDisplayActivity.class);
285 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
286 OCFile targetFile = null;
287 if (mFile != null) {
288 targetFile = mStorageManager.getFileById(mFile.getParentId());
289 }
290 intent.putExtra(FileDetailFragment.EXTRA_FILE, targetFile);
291 intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
292 startActivity(intent);
293 finish();
294 }
295
296 @Override
297 protected Dialog onCreateDialog(int id) {
298 Dialog dialog = null;
299 switch (id) {
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;
307 break;
308 }
309 default:
310 dialog = null;
311 }
312 return dialog;
313 }
314
315
316 /**
317 * {@inheritDoc}
318 */
319 @Override
320 public void onFileStateChanged() {
321 // nothing to do here!
322 }
323
324
325 /**
326 * {@inheritDoc}
327 */
328 @Override
329 public FileDownloaderBinder getFileDownloaderBinder() {
330 return mDownloaderBinder;
331 }
332
333
334 @Override
335 public FileUploaderBinder getFileUploaderBinder() {
336 return mUploaderBinder;
337 }
338
339
340 @Override
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();
345 }
346
347
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);
353 startService(i);
354 }
355 }
356
357
358 /**
359 * Class waiting for broadcast events from the {@link FielDownloader} service.
360 *
361 * Updates the UI when a download is started or finished, provided that it is relevant for the
362 * current file.
363 */
364 private class DownloadFinishReceiver extends BroadcastReceiver {
365 @Override
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));
370
371 if (sameAccount && samePath) {
372 updateChildFragment(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
373 }
374
375 removeStickyBroadcast(intent);
376 }
377
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));
381 }
382 }
383
384
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;
393
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);
398
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;
407
408 } else {
409 detailsFragment.updateFileDetails(false, (success));
410 // TODO error message if !success ¿?
411 }
412 }
413 } // TODO else if (fragment != null && fragment )
414
415 }
416
417 }