View Javadoc
1   /*
2    * Copyright (C) 2003-2014 eXo Platform SAS.
3    *
4    * This is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU Lesser General Public License as
6    * published by the Free Software Foundation; either version 3 of
7    * the License, or (at your option) any later version.
8    *
9    * This software 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 GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this software; if not, write to the Free
16   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18   */
19  package org.exoplatform.utils;
20  
21  import java.io.File;
22  import java.io.FileOutputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.OutputStream;
26  
27  import org.apache.http.HttpEntity;
28  import org.apache.http.HttpResponse;
29  import org.apache.http.client.methods.HttpGet;
30  import org.apache.http.impl.client.DefaultHttpClient;
31  import org.apache.http.params.BasicHttpParams;
32  import org.apache.http.params.HttpConnectionParams;
33  import org.apache.http.params.HttpParams;
34  
35  import org.exoplatform.R;
36  import org.exoplatform.ui.WebViewActivity;
37  import org.exoplatform.utils.image.FileCache;
38  import org.exoplatform.widget.ConnectionErrorDialog;
39  import org.exoplatform.widget.UnreadableFileDialog;
40  
41  import android.app.Dialog;
42  import android.app.ProgressDialog;
43  import android.content.ActivityNotFoundException;
44  import android.content.Context;
45  import android.content.Intent;
46  import android.content.res.Resources;
47  import android.net.Uri;
48  import android.os.AsyncTask;
49  
50  
51  /**
52   * Created by The eXo Platform SAS Author : eXoPlatform exo@exoplatform.com Jul
53   * 6, 2012
54   */
55  public class CompatibleFileOpen {
56    private static final int       RESULT_OK                = 0;
57  
58    private static final int       RESULT_ERROR             = 1;
59  
60    private static final int       RESULT_CANCEL            = 2;
61  
62    private Context                mContext;
63  
64    private String                 fileType;
65  
66    private String                 filePath;
67  
68    private String                 fileName;
69  
70    private DownloadProgressDialog mProgressDialog;
71  
72    public static final int        DIALOG_DOWNLOAD_PROGRESS = 0;
73  
74    private FileDownloadTask       mLoadTask;
75  
76    private String                 downLoadingFile;
77  
78    private String                 noAppFound;
79  
80    private String                 fileNotSupport;
81  
82    private String                 cannotOpenFile;
83  
84    private String                 fileNotFound;
85  
86    private String                 memoryWarning;
87  
88    private Resources              resource;
89  
90    private FileCache              fileCache;
91  
92    public CompatibleFileOpen(Context context, String fType, String fPath, String fName) {
93      mContext = context;
94      changeLanguage();
95      fileCache = new FileCache(context, ExoConstants.DOCUMENT_FILE_CACHE);
96      fileType = fType;
97      filePath = fPath;
98      fileName = fName;
99  
100     if (ExoDocumentUtils.isForbidden(fileType)) {
101       new UnreadableFileDialog(mContext, fileNotSupport).show();
102     } else if (!ExoDocumentUtils.isCallable(mContext, fileType, filePath)) {
103       new UnreadableFileDialog(mContext, noAppFound).show();
104     } else {
105       CrashUtils.setOpenFileType(fileType);
106       onLoad(filePath);
107     }
108 
109   }
110 
111   private void onLoad(String path) {
112     if (ExoConnectionUtils.isNetworkAvailableExt(mContext)) {
113       if (mLoadTask == null || mLoadTask.getStatus() == FileDownloadTask.Status.FINISHED) {
114         mLoadTask = (FileDownloadTask) new FileDownloadTask().execute(path);
115       }
116     } else {
117       new ConnectionErrorDialog(mContext).show();
118     }
119   }
120 
121   public void onCancelLoad() {
122     if (mLoadTask != null && mLoadTask.getStatus() == FileDownloadTask.Status.RUNNING) {
123       Log.i(getClass().getSimpleName(), "Canceling File Download Task");
124       mLoadTask.cancel(true);
125       mLoadTask = null;
126     }
127   }
128 
129   private void changeLanguage() {
130     resource = mContext.getResources();
131     downLoadingFile = resource.getString(R.string.DownloadingFile);
132     noAppFound = resource.getString(R.string.NoAppFound);
133     cannotOpenFile = resource.getString(R.string.CannotOpenFile);
134     fileNotFound = resource.getString(R.string.FileNotFound);
135     fileNotSupport = resource.getString(R.string.FileNotSupported);
136     memoryWarning = resource.getString(R.string.FileNotSupported);
137   }
138   
139   public static enum FileOpenRequestResult {
140     /**
141      * The file type is unknown
142      */
143     ERROR,
144     
145     /**
146      * The file is opened internally in {@link WebViewActivity}
147      */
148     WEBVIEW,
149     
150     /**
151      * The file is opened by another app installed on the device
152      */
153     EXTERNAL
154   }
155   
156   /**
157    * Represents a request to open a file. Possible {@code mResult} values are:
158    * <ul>
159    * <li>{@link FileOpenRequestResult#ERROR} if the file format is unknown</li>
160    * <li>{@link FileOpenRequestResult#WEBVIEW} if the file can be opened in a webview</li>
161    * <li>{@link FileOpenRequestResult#EXTERNAL} if the file can be opened by an external app</li>
162    * </ul>
163    * If result is {@link FileOpenRequestResult#EXTERNAL} then the property {@code mFileOpenController} 
164    * contains the {@link CompatibleFileOpen} object controlling the download and opening of the file.
165    * 
166    * @author paristote
167    *
168    */
169   public static class FileOpenRequest {
170     public FileOpenRequestResult mResult;
171     public CompatibleFileOpen    mFileOpenController;
172   }
173 
174   private class FileDownloadTask extends AsyncTask<String, String, Integer> {
175 
176     private File file;
177 
178     @Override
179     protected void onPreExecute() {
180       mProgressDialog = (DownloadProgressDialog) onCreateDialog(DIALOG_DOWNLOAD_PROGRESS);
181       mProgressDialog.show();
182     }
183 
184     @Override
185     protected Integer doInBackground(String... params) {
186 
187       /*
188        * If file exists return file else download from url
189        */
190       file = fileCache.getFileFromName(fileName);
191       if (file.exists()) {
192         return RESULT_OK;
193       }
194 
195       String url = params[0].replaceAll(" ", "%20");
196       HttpParams httpParameters = new BasicHttpParams();
197       HttpConnectionParams.setConnectionTimeout(httpParameters, 10000);
198       HttpConnectionParams.setSoTimeout(httpParameters, 10000);
199       HttpConnectionParams.setTcpNoDelay(httpParameters, true);
200       DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
201       httpClient.setCookieStore(ExoConnectionUtils.cookiesStore);
202 
203       try {
204 
205         HttpGet getRequest = new HttpGet(url);
206         HttpResponse response = httpClient.execute(getRequest);
207         HttpEntity entity = response.getEntity();
208         if (entity != null) {
209 
210           // lenghtOfFile is used for calculating download progress
211           long lenghtOfFile = entity.getContentLength();
212           /*
213            * Compare the file size and free sdcard memory
214            */
215           if (!ExoDocumentUtils.isEnoughMemory((int) lenghtOfFile)) {
216             return RESULT_CANCEL;
217           }
218           mProgressDialog.setMax((int) lenghtOfFile);
219           InputStream is = entity.getContent();
220           OutputStream os = new FileOutputStream(file);
221 
222           // here's the downloading progress
223           byte[] buffer = new byte[1024];
224           int len = 0;
225           long total = 0;
226 
227           while ((len = is.read(buffer)) > 0) {
228             total += len; // total = total + len
229             publishProgress("" + total);
230             os.write(buffer, 0, len);
231           }
232 
233           os.close();
234         }
235         return RESULT_OK;
236       } catch (IOException e) {
237         if (Log.LOGD)
238           Log.d(getClass().getSimpleName(), e.getMessage(), Log.getStackTraceString(e));
239         if (file != null) {
240           file.delete();
241         }
242         return RESULT_ERROR;
243       } finally {
244         httpClient.getConnectionManager().shutdown();
245       }
246     }
247 
248     /*
249      * If cancelled, delete the downloading file
250      */
251     @Override
252     protected void onCancelled() {
253       if (file.exists()) {
254         file.delete();
255       }
256       if (mProgressDialog.isAttachedToWindow())
257         mProgressDialog.dismiss();
258       super.onCancelled();
259     }
260 
261     @Override
262     protected void onProgressUpdate(String... values) {
263       mProgressDialog.setProgress(Integer.parseInt(values[0]));
264     }
265 
266     @Override
267     protected void onPostExecute(Integer result) {
268       if (result == RESULT_OK) {
269         /*
270          * get exactly document type from content type and open it with
271          * compatible intent
272          */
273         String docFileType = ExoDocumentUtils.getFullFileType(fileType);
274 
275         if (docFileType != null) {
276           Uri path = Uri.fromFile(file);
277           Intent intent = new Intent(Intent.ACTION_VIEW);
278           intent.setDataAndType(path, docFileType);
279           intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
280           try {
281             mContext.startActivity(intent);
282           } catch (ActivityNotFoundException e) {
283             new UnreadableFileDialog(mContext, noAppFound).show();
284           }
285 
286         } else {
287           new UnreadableFileDialog(mContext, cannotOpenFile).show();
288         }
289 
290       } else if (result == RESULT_ERROR) {
291         new UnreadableFileDialog(mContext, fileNotFound).show();
292       } else if (result == RESULT_CANCEL) {
293         new UnreadableFileDialog(mContext, memoryWarning).show();
294       }
295       if (mProgressDialog.isAttachedToWindow())
296         mProgressDialog.dismiss();
297     }
298 
299   }
300   
301   private Dialog onCreateDialog(int id) {
302     switch (id) {
303     case DIALOG_DOWNLOAD_PROGRESS: // we set this to 0
304       mProgressDialog = new DownloadProgressDialog(mContext);
305       mProgressDialog.setMessage(downLoadingFile);
306       mProgressDialog.setIndeterminate(false);
307       mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
308       mProgressDialog.setCancelable(true);
309       mProgressDialog.show();
310       return mProgressDialog;
311     default:
312       return null;
313     }
314   }
315 
316   private class DownloadProgressDialog extends ProgressDialog {
317 
318     private boolean mIsAttached;
319     
320     public DownloadProgressDialog(Context context) {
321       super(context);
322     }
323 
324     /**
325      * Override onBackPressed() method to call onCancelLoad() to cancel
326      * downloading file task and delete the downloading file
327      */
328     @Override
329     public void onBackPressed() {
330       onCancelLoad();
331       super.onBackPressed();
332     }
333     
334     @Override
335     public void onAttachedToWindow() {
336       mIsAttached = true;
337       super.onAttachedToWindow();
338     }
339     
340     @Override
341     public void onDetachedFromWindow() {
342       mIsAttached = false;
343       super.onDetachedFromWindow();
344     }
345     
346     public boolean isAttachedToWindow() {
347       return mIsAttached;
348     }
349   }
350 
351 }