711b07ade279a3c54ccd76df3eb3c0e6cf050535
[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.Dialog;
22 import android.app.ProgressDialog;
23 import android.content.BroadcastReceiver;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.ServiceConnection;
29 import android.content.res.Configuration;
30 import android.os.Bundle;
31 import android.os.IBinder;
32 import android.support.v4.app.Fragment;
33 import android.support.v4.app.FragmentTransaction;
34 import android.util.Log;
35
36 import com.actionbarsherlock.app.ActionBar;
37 import com.actionbarsherlock.app.SherlockFragmentActivity;
38 import com.actionbarsherlock.view.MenuItem;
39 import com.owncloud.android.datamodel.FileDataStorageManager;
40 import com.owncloud.android.datamodel.OCFile;
41 import com.owncloud.android.files.services.FileDownloader;
42 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
43 import com.owncloud.android.files.services.FileUploader;
44 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
45 import com.owncloud.android.ui.fragment.FileDetailFragment;
46 import com.owncloud.android.ui.fragment.FileFragment;
47 import com.owncloud.android.ui.preview.PreviewMediaFragment;
48 import com.owncloud.android.AccountUtils;
49 import com.owncloud.android.Log_OC;
50
51 import com.owncloud.android.R;
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 boolean mConfigurationChangedToLandscape = false;
73 private FileDownloaderBinder mDownloaderBinder = null;
74 private ServiceConnection mDownloadConnection, mUploadConnection = null;
75 private FileUploaderBinder mUploaderBinder = null;
76 private boolean mWaitingToPreview;
77
78 private OCFile mFile;
79 private Account mAccount;
80
81 private FileDataStorageManager mStorageManager;
82 private DownloadFinishReceiver mDownloadFinishReceiver;
83
84
85 @Override
86 protected void onCreate(Bundle savedInstanceState) {
87 super.onCreate(savedInstanceState);
88
89 mFile = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
90 mAccount = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
91 mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
92
93 // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity
94 Configuration conf = getResources().getConfiguration();
95 mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE &&
96 (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE
97 );
98
99 if (!mConfigurationChangedToLandscape) {
100 setContentView(R.layout.file_activity_details);
101
102 ActionBar actionBar = getSupportActionBar();
103 actionBar.setDisplayHomeAsUpEnabled(true);
104
105 if (savedInstanceState == null) {
106 mWaitingToPreview = false;
107 createChildFragment();
108 } else {
109 mWaitingToPreview = savedInstanceState.getBoolean(KEY_WAITING_TO_PREVIEW);
110 }
111
112 mDownloadConnection = new DetailsServiceConnection();
113 bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
114 mUploadConnection = new DetailsServiceConnection();
115 bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
116
117
118 } else {
119 backToDisplayActivity(false); // the 'back' won't be effective until this.onStart() and this.onResume() are completed;
120 }
121
122 }
123
124 /**
125 * Creates the proper fragment depending upon the state of the handled {@link OCFile} and
126 * the requested {@link Intent}.
127 */
128 private void createChildFragment() {
129 int mode = getIntent().getIntExtra(EXTRA_MODE, MODE_PREVIEW);
130
131 Fragment newFragment = null;
132 if (PreviewMediaFragment.canBePreviewed(mFile) && mode == MODE_PREVIEW) {
133 if (mFile.isDown()) {
134 newFragment = new PreviewMediaFragment(mFile, mAccount);
135
136 } else {
137 newFragment = new FileDetailFragment(mFile, mAccount);
138 mWaitingToPreview = true;
139 }
140
141 } else {
142 newFragment = new FileDetailFragment(mFile, mAccount);
143 }
144 FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
145 ft.replace(R.id.fragment, newFragment, FileDetailFragment.FTAG);
146 ft.commit();
147 }
148
149
150 @Override
151 protected void onSaveInstanceState(Bundle outState) {
152 super.onSaveInstanceState(outState);
153 outState.putBoolean(KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
154 }
155
156
157 @Override
158 public void onPause() {
159 super.onPause();
160 if (mDownloadFinishReceiver != null) {
161 unregisterReceiver(mDownloadFinishReceiver);
162 mDownloadFinishReceiver = null;
163 }
164 }
165
166
167 @Override
168 public void onResume() {
169 super.onResume();
170 if (!mConfigurationChangedToLandscape) {
171 // TODO this is probably unnecessary
172 Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
173 if (fragment != null && fragment instanceof FileDetailFragment) {
174 ((FileDetailFragment) fragment).updateFileDetails(false, false);
175 }
176 }
177 // Listen for download messages
178 IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE);
179 downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
180 mDownloadFinishReceiver = new DownloadFinishReceiver();
181 registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
182 }
183
184
185 /** Defines callbacks for service binding, passed to bindService() */
186 private class DetailsServiceConnection implements ServiceConnection {
187
188 @Override
189 public void onServiceConnected(ComponentName component, IBinder service) {
190
191 if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {
192 Log_OC.d(TAG, "Download service connected");
193 mDownloaderBinder = (FileDownloaderBinder) service;
194 if (mWaitingToPreview) {
195 requestForDownload();
196 }
197
198 } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {
199 Log_OC.d(TAG, "Upload service connected");
200 mUploaderBinder = (FileUploaderBinder) service;
201 } else {
202 return;
203 }
204
205 Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
206 FileDetailFragment detailsFragment = (fragment instanceof FileDetailFragment) ? (FileDetailFragment) fragment : null;
207 if (detailsFragment != null) {
208 detailsFragment.listenForTransferProgress();
209 detailsFragment.updateFileDetails(mWaitingToPreview, false); // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())
210 }
211 }
212
213 @Override
214 public void onServiceDisconnected(ComponentName component) {
215 if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {
216 Log_OC.d(TAG, "Download service disconnected");
217 mDownloaderBinder = null;
218 } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {
219 Log_OC.d(TAG, "Upload service disconnected");
220 mUploaderBinder = null;
221 }
222 }
223 };
224
225
226 @Override
227 public void onDestroy() {
228 super.onDestroy();
229 if (mDownloadConnection != null) {
230 unbindService(mDownloadConnection);
231 mDownloadConnection = null;
232 }
233 if (mUploadConnection != null) {
234 unbindService(mUploadConnection);
235 mUploadConnection = null;
236 }
237 }
238
239
240 @Override
241 public boolean onOptionsItemSelected(MenuItem item) {
242 boolean returnValue = false;
243
244 switch(item.getItemId()){
245 case android.R.id.home:
246 backToDisplayActivity(true);
247 returnValue = true;
248 break;
249 default:
250 returnValue = super.onOptionsItemSelected(item);
251 }
252
253 return returnValue;
254 }
255
256 private void backToDisplayActivity(boolean moveToParent) {
257 Intent intent = new Intent(this, FileDisplayActivity.class);
258 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
259 OCFile targetFile = null;
260 if (mFile != null) {
261 targetFile = moveToParent ? mStorageManager.getFileById(mFile.getParentId()) : mFile;
262 }
263 intent.putExtra(FileDetailFragment.EXTRA_FILE, targetFile);
264 intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
265 startActivity(intent);
266 finish();
267 }
268
269
270 @Override
271 protected Dialog onCreateDialog(int id) {
272 Dialog dialog = null;
273 switch (id) {
274 case DIALOG_SHORT_WAIT: {
275 ProgressDialog working_dialog = new ProgressDialog(this);
276 working_dialog.setMessage(getResources().getString(
277 R.string.wait_a_moment));
278 working_dialog.setIndeterminate(true);
279 working_dialog.setCancelable(false);
280 dialog = working_dialog;
281 break;
282 }
283 default:
284 dialog = null;
285 }
286 return dialog;
287 }
288
289
290 /**
291 * {@inheritDoc}
292 */
293 @Override
294 public void onFileStateChanged() {
295 // nothing to do here!
296 }
297
298
299 /**
300 * {@inheritDoc}
301 */
302 @Override
303 public FileDownloaderBinder getFileDownloaderBinder() {
304 return mDownloaderBinder;
305 }
306
307
308 @Override
309 public FileUploaderBinder getFileUploaderBinder() {
310 return mUploaderBinder;
311 }
312
313
314 @Override
315 public void showFragmentWithDetails(OCFile file) {
316 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
317 transaction.replace(R.id.fragment, new FileDetailFragment(file, mAccount), FileDetailFragment.FTAG);
318 transaction.commit();
319 }
320
321
322 private void requestForDownload() {
323 if (!mDownloaderBinder.isDownloading(mAccount, mFile)) {
324 Intent i = new Intent(this, FileDownloader.class);
325 i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
326 i.putExtra(FileDownloader.EXTRA_FILE, mFile);
327 startService(i);
328 }
329 }
330
331
332 /**
333 * Class waiting for broadcast events from the {@link FielDownloader} service.
334 *
335 * Updates the UI when a download is started or finished, provided that it is relevant for the
336 * current file.
337 */
338 private class DownloadFinishReceiver extends BroadcastReceiver {
339 @Override
340 public void onReceive(Context context, Intent intent) {
341 boolean sameAccount = isSameAccount(context, intent);
342 String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
343 boolean samePath = (mFile != null && mFile.getRemotePath().equals(downloadedRemotePath));
344
345 if (sameAccount && samePath) {
346 updateChildFragment(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
347 }
348
349 removeStickyBroadcast(intent);
350 }
351
352 private boolean isSameAccount(Context context, Intent intent) {
353 String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
354 return (accountName != null && accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name));
355 }
356 }
357
358
359 public void updateChildFragment(String downloadEvent, String downloadedRemotePath, boolean success) {
360 Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
361 if (fragment != null && fragment instanceof FileDetailFragment) {
362 FileDetailFragment detailsFragment = (FileDetailFragment) fragment;
363 OCFile fileInFragment = detailsFragment.getFile();
364 if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
365 // this never should happen; fileInFragment should be always equals to mFile, that was compared to downloadedRemotePath in DownloadReceiver
366 mWaitingToPreview = false;
367
368 } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) {
369 // grants that the progress bar is updated
370 detailsFragment.listenForTransferProgress();
371 detailsFragment.updateFileDetails(true, false);
372
373 } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {
374 // refresh the details fragment
375 if (success && mWaitingToPreview) {
376 mFile = mStorageManager.getFileById(mFile.getFileId()); // update the file from database, for the local storage path
377 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
378 transaction.replace(R.id.fragment, new PreviewMediaFragment(mFile, mAccount), FileDetailFragment.FTAG);
379 transaction.commit();
380 mWaitingToPreview = false;
381
382 } else {
383 detailsFragment.updateFileDetails(false, (success));
384 // TODO error message if !success ¿?
385 }
386 }
387 } // TODO else if (fragment != null && fragment )
388
389 }
390
391 }