0397e5b5f3189add31723cff0ffea0533ca1c821
[pub/Android/ownCloud.git] / src / eu / alefzero / owncloud / ui / fragment / FileDetailFragment.java
1 /* ownCloud Android client application
2 * Copyright (C) 2011 Bartek Przybylski
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
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 eu.alefzero.owncloud.ui.fragment;
19
20 import java.util.List;
21
22 import android.accounts.Account;
23 import android.accounts.AccountManager;
24 import android.app.ActionBar.LayoutParams;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.pm.PackageManager;
30 import android.graphics.Bitmap;
31 import android.graphics.BitmapFactory;
32 import android.graphics.BitmapFactory.Options;
33 import android.graphics.Path.FillType;
34 import android.net.Uri;
35 import android.os.Bundle;
36 import android.util.Log;
37 import android.view.LayoutInflater;
38 import android.view.View;
39 import android.view.View.OnClickListener;
40 import android.view.ViewGroup;
41 import android.widget.Button;
42 import android.widget.ImageView;
43 import android.widget.TextView;
44 import android.widget.Toast;
45
46 import com.actionbarsherlock.app.SherlockFragment;
47
48 import eu.alefzero.owncloud.DisplayUtils;
49 import eu.alefzero.owncloud.R;
50 import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
51 import eu.alefzero.owncloud.datamodel.OCFile;
52 import eu.alefzero.owncloud.files.services.FileDownloader;
53 import eu.alefzero.owncloud.utils.OwnCloudVersion;
54
55 /**
56 * This Fragment is used to display the details about a file.
57 *
58 * @author Bartek Przybylski
59 *
60 */
61 public class FileDetailFragment extends SherlockFragment implements
62 OnClickListener {
63
64 public static final String EXTRA_FILE = "FILE";
65
66 private DownloadFinishReceiver mDownloadFinishReceiver;
67 private Intent mIntent;
68 private int mLayout;
69 private View mView;
70 private OCFile mFile;
71 private static final String TAG = "FileDetailFragment";
72
73 /**
74 * Default constructor - contains real layout
75 */
76 public FileDetailFragment(){
77 mLayout = R.layout.file_details_fragment;
78 }
79
80 /**
81 * Creates a dummy layout. For use if the user never has
82 * tapped on a file before
83 *
84 * @param useEmptyView If true, use empty layout
85 */
86 public FileDetailFragment(boolean useEmptyView){
87 if(useEmptyView){
88 mLayout = R.layout.file_details_empty;
89 } else {
90 mLayout = R.layout.file_details_fragment;
91 }
92 }
93
94 /**
95 * Use this when creating the fragment and display
96 * a file at the same time
97 *
98 * @param showDetailsIntent The Intent with the required parameters
99 * @see FileDetailFragment#updateFileDetails(Intent)
100 */
101 public FileDetailFragment(Intent showDetailsIntent) {
102 mIntent = showDetailsIntent;
103 mLayout = R.layout.file_details_fragment;
104 }
105
106 @Override
107 public void onResume() {
108 super.onResume();
109 mDownloadFinishReceiver = new DownloadFinishReceiver();
110 IntentFilter filter = new IntentFilter(
111 FileDownloader.DOWNLOAD_FINISH_MESSAGE);
112 getActivity().registerReceiver(mDownloadFinishReceiver, filter);
113 }
114
115 @Override
116 public void onPause() {
117 super.onPause();
118 getActivity().unregisterReceiver(mDownloadFinishReceiver);
119 mDownloadFinishReceiver = null;
120 }
121
122 @Override
123 public View onCreateView(LayoutInflater inflater, ViewGroup container,
124 Bundle savedInstanceState) {
125 View view = null;
126 view = inflater.inflate(mLayout, container, false);
127 mView = view;
128 if(mLayout == R.layout.file_details_fragment){
129 // Phones will launch an activity with this intent
130 if(mIntent == null){
131 mIntent = getActivity().getIntent();
132 }
133 updateFileDetails();
134 }
135
136 return view;
137 }
138
139 @Override
140 public View getView() {
141 return super.getView() == null ? mView : super.getView();
142 }
143
144 @Override
145 public void onClick(View v) {
146 Toast.makeText(getActivity(), "Downloading", Toast.LENGTH_LONG).show();
147 Intent i = new Intent(getActivity(), FileDownloader.class);
148 i.putExtra(FileDownloader.EXTRA_ACCOUNT,
149 mIntent.getParcelableExtra(FileDownloader.EXTRA_ACCOUNT));
150 i.putExtra(FileDownloader.EXTRA_REMOTE_PATH, mFile.getRemotePath());
151 i.putExtra(FileDownloader.EXTRA_FILE_PATH, mFile.getURLDecodedRemotePath());
152 i.putExtra(FileDownloader.EXTRA_FILE_SIZE, mFile.getFileLength());
153 getActivity().startService(i);
154 }
155
156 /**
157 * Can be used to get the file that is currently being displayed.
158 * @return The file on the screen.
159 */
160 public OCFile getDisplayedFile(){
161 return mFile;
162 }
163
164 /**
165 * Use this method to signal this Activity that it shall update its view.
166 *
167 * @param intent The {@link Intent} that contains extra information about
168 * this file The intent needs to have these extras:
169 * <p>
170 *
171 * {@link FileDetailFragment#EXTRA_FILE}: An {@link OCFile}
172 * {@link FileDownloader#EXTRA_ACCOUNT}: The Account that file
173 * belongs to (required for downloading)
174 */
175 public void updateFileDetails(Intent intent) {
176 mIntent = intent;
177 updateFileDetails();
178 }
179
180 /**
181 * Updates the view with all relevant details about that file.
182 */
183 private void updateFileDetails() {
184 mFile = mIntent.getParcelableExtra(EXTRA_FILE);
185 Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);
186
187 if (mFile != null) {
188 // set file details
189 setFilename(mFile.getFileName());
190 setFiletype(DisplayUtils.convertMIMEtoPrettyPrint(mFile
191 .getMimetype()));
192 setFilesize(mFile.getFileLength());
193 if(ocVersionSupportsTimeCreated()){
194 setTimeCreated(mFile.getCreationTimestamp());
195 }
196
197 setTimeModified(mFile.getModificationTimestamp());
198
199 // Update preview
200 if (mFile.getStoragePath() != null) {
201 ImageView preview = (ImageView) getView().findViewById(R.id.fdPreview);
202 try {
203 if (mFile.getMimetype().startsWith("image/")) {
204 BitmapFactory.Options options = new Options();
205 options.inScaled = true;
206 options.inPurgeable = true;
207 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
208 options.inPreferQualityOverSpeed = false;
209 }
210 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
211 options.inMutable = false;
212 }
213
214 Bitmap bmp = BitmapFactory.decodeFile(mFile.getStoragePath(), options);
215
216 int width = options.outWidth;
217 int height = options.outHeight;
218 int scale = 1;
219 if (width >= 2048 || height >= 2048) {
220 scale = (int) (Math.ceil(Math.max(height, width)/2048.));
221 options.inSampleSize = scale;
222 bmp.recycle();
223
224 bmp = BitmapFactory.decodeFile(mFile.getStoragePath(), options);
225 }
226 preview.setImageBitmap(bmp);
227 }
228 } catch (OutOfMemoryError e) {
229 preview.setVisibility(View.INVISIBLE);
230 Log.e(TAG, "Out of memory occured for file with size " + mFile.getFileLength());
231
232 } catch (NoSuchFieldError e) {
233 preview.setVisibility(View.INVISIBLE);
234 Log.e(TAG, "Error from access to unexisting field despite protection " + mFile.getFileLength());
235
236 } catch (Throwable t) {
237 preview.setVisibility(View.INVISIBLE);
238 Log.e(TAG, "Unexpected error while creating image preview " + mFile.getFileLength());
239 }
240 downloadButton.setText(R.string.filedetails_open);
241 downloadButton.setOnClickListener(new OnClickListener() {
242 @Override
243 public void onClick(View v) {
244 Intent i = new Intent(Intent.ACTION_VIEW);
245 i.setDataAndType(Uri.parse("file://"+mFile.getStoragePath()), mFile.getMimetype());
246 List list = getActivity().getPackageManager().queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY);
247 if (list.size() > 0) {
248 startActivity(i);
249 } else {
250 Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();
251 }
252 }
253 });
254 } else {
255 // Make download button effective
256 downloadButton.setOnClickListener(this);
257 }
258 }
259 }
260
261 /**
262 * Updates the filename in view
263 * @param filename to set
264 */
265 private void setFilename(String filename) {
266 TextView tv = (TextView) getView().findViewById(R.id.fdFilename);
267 if (tv != null)
268 tv.setText(filename);
269 }
270
271 /**
272 * Updates the MIME type in view
273 * @param mimetype to set
274 */
275 private void setFiletype(String mimetype) {
276 TextView tv = (TextView) getView().findViewById(R.id.fdType);
277 if (tv != null)
278 tv.setText(mimetype);
279 }
280
281 /**
282 * Updates the file size in view
283 * @param filesize in bytes to set
284 */
285 private void setFilesize(long filesize) {
286 TextView tv = (TextView) getView().findViewById(R.id.fdSize);
287 if (tv != null)
288 tv.setText(DisplayUtils.bytesToHumanReadable(filesize));
289 }
290
291 /**
292 * Updates the time that the file was created in view
293 * @param milliseconds Unix time to set
294 */
295 private void setTimeCreated(long milliseconds){
296 TextView tv = (TextView) getView().findViewById(R.id.fdCreated);
297 TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel);
298 if(tv != null){
299 tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));
300 tv.setVisibility(View.VISIBLE);
301 tvLabel.setVisibility(View.VISIBLE);
302 }
303 }
304
305 /**
306 * Updates the time that the file was last modified
307 * @param milliseconds Unix time to set
308 */
309 private void setTimeModified(long milliseconds){
310 TextView tv = (TextView) getView().findViewById(R.id.fdModified);
311 if(tv != null){
312 tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));
313 }
314 }
315
316 /**
317 * In ownCloud 3.0.3 and 4.0.0 there is a bug that SabreDAV does not return
318 * the time that the file was created. There is a chance that this will
319 * be fixed in future versions. Use this method to check if this version of
320 * ownCloud has this fix.
321 * @return True, if ownCloud the ownCloud version is > 3.0.4 and 4.0.1
322 */
323 private boolean ocVersionSupportsTimeCreated(){
324 if(mIntent != null){
325 Account ocAccount = mIntent.getParcelableExtra(FileDownloader.EXTRA_ACCOUNT);
326 if(ocAccount != null){
327 AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE);
328 OwnCloudVersion ocVersion = new OwnCloudVersion(accManager
329 .getUserData(ocAccount, AccountAuthenticator.KEY_OC_VERSION));
330 if(ocVersion.compareTo(new OwnCloudVersion(0x030004)) >= 0 || ocVersion.compareTo(new OwnCloudVersion(0x040001)) >= 0){
331 return true;
332 }
333 }
334 }
335 return false;
336 }
337
338 /**
339 * Once the file download has finished -> update view
340 * @author Bartek Przybylski
341 */
342 private class DownloadFinishReceiver extends BroadcastReceiver {
343 @Override
344 public void onReceive(Context context, Intent intent) {
345 ((OCFile)mIntent.getParcelableExtra(EXTRA_FILE)).setStoragePath(intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH));
346 updateFileDetails(mIntent);
347 }
348
349 }
350
351 }