mobile/android/base/FilePickerResultHandler.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 package org.mozilla.gecko;
     7 import org.mozilla.gecko.mozglue.GeckoLoader;
     8 import org.mozilla.gecko.util.ActivityResultHandler;
     9 import org.mozilla.gecko.util.ThreadUtils;
    11 import android.app.Activity;
    12 import android.content.ContentResolver;
    13 import android.content.Context;
    14 import android.content.Intent;
    15 import android.database.Cursor;
    16 import android.net.Uri;
    17 import android.os.Bundle;
    18 import android.os.Environment;
    19 import android.provider.MediaStore;
    20 import android.provider.OpenableColumns;
    21 import android.support.v4.app.FragmentActivity;
    22 import android.support.v4.app.LoaderManager;
    23 import android.support.v4.app.LoaderManager.LoaderCallbacks;
    24 import android.support.v4.content.CursorLoader;
    25 import android.support.v4.content.Loader;
    26 import android.text.TextUtils;
    27 import android.text.format.Time;
    28 import android.util.Log;
    29 import android.os.Process;
    31 import java.io.File;
    32 import java.io.FileOutputStream;
    33 import java.io.InputStream;
    34 import java.io.IOException;
    36 class FilePickerResultHandler implements ActivityResultHandler {
    37     private static final String LOGTAG = "GeckoFilePickerResultHandler";
    38     private static final String UPLOADS_DIR = "uploads";
    40     protected final FilePicker.ResultHandler handler;
    41     private final int tabId;
    42     private final File cacheDir;
    44     // this code is really hacky and doesn't belong anywhere so I'm putting it here for now
    45     // until I can come up with a better solution.
    46     private String mImageName = "";
    48     /* Use this constructor to asynchronously listen for results */
    49     public FilePickerResultHandler(final FilePicker.ResultHandler handler, final Context context, final int tabId) {
    50         this.tabId = tabId;
    51         cacheDir = new File(context.getCacheDir(), UPLOADS_DIR);
    52         this.handler = handler;
    53     }
    55     private void sendResult(String res) {
    56         if (handler != null) {
    57             handler.gotFile(res);
    58         }
    59     }
    61     @Override
    62     public void onActivityResult(int resultCode, Intent intent) {
    63         if (resultCode != Activity.RESULT_OK) {
    64             sendResult("");
    65             return;
    66         }
    68         // Camera results won't return an Intent. Use the file name we passed to the original intent.
    69         if (intent == null) {
    70             if (mImageName != null) {
    71                 File file = new File(Environment.getExternalStorageDirectory(), mImageName);
    72                 sendResult(file.getAbsolutePath());
    73             } else {
    74                 sendResult("");
    75             }
    76             return;
    77         }
    79         Uri uri = intent.getData();
    80         if (uri == null) {
    81             sendResult("");
    82             return;
    83         }
    85         // Some file pickers may return a file uri
    86         if ("file".equals(uri.getScheme())) {
    87             String path = uri.getPath();
    88             sendResult(path == null ? "" : path);
    89             return;
    90         }
    92         final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
    93         final LoaderManager lm = fa.getSupportLoaderManager();
    94         // Finally, Video pickers and some file pickers may return a content provider.
    95         Cursor cursor = null;
    96         try {
    97             // Try a query to make sure the expected columns exist
    98             final ContentResolver cr = fa.getContentResolver();
    99             cursor = cr.query(uri, new String[] { MediaStore.Video.Media.DATA }, null, null, null);
   101             int index = cursor.getColumnIndex(MediaStore.Video.Media.DATA);
   102             if (index >= 0) {
   103                 lm.initLoader(intent.hashCode(), null, new VideoLoaderCallbacks(uri));
   104                 return;
   105             }
   106         } catch(Exception ex) {
   107             // We'll try a different loader below
   108         } finally {
   109             if (cursor != null) {
   110                 cursor.close();
   111             }
   112         }
   114         lm.initLoader(uri.hashCode(), null, new FileLoaderCallbacks(uri));
   115         return;
   116     }
   118     public String generateImageName() {
   119         Time now = new Time();
   120         now.setToNow();
   121         mImageName = now.format("%Y-%m-%d %H.%M.%S") + ".jpg";
   122         return mImageName;
   123     }
   125     private class VideoLoaderCallbacks implements LoaderCallbacks<Cursor> {
   126         final private Uri uri;
   127         public VideoLoaderCallbacks(Uri uri) {
   128             this.uri = uri;
   129         }
   131         @Override
   132         public Loader<Cursor> onCreateLoader(int id, Bundle args) {
   133             final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
   134             return new CursorLoader(fa,
   135                                     uri,
   136                                     new String[] { MediaStore.Video.Media.DATA },
   137                                     null,  // selection
   138                                     null,  // selectionArgs
   139                                     null); // sortOrder
   140         }
   142         @Override
   143         public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
   144             if (cursor.moveToFirst()) {
   145                 String res = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
   147                 // Some pickers (the KitKat Documents one for instance) won't return a temporary file here.
   148                 // Fall back to the normal FileLoader if we didn't find anything.
   149                 if (TextUtils.isEmpty(res)) {
   150                     tryFileLoaderCallback();
   151                     return;
   152                 }
   154                 sendResult(res);
   155             } else {
   156                 tryFileLoaderCallback();
   157             }
   158         }
   160         private void tryFileLoaderCallback() {
   161             final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
   162             final LoaderManager lm = fa.getSupportLoaderManager();
   163             lm.initLoader(uri.hashCode(), null, new FileLoaderCallbacks(uri));
   164         }
   166         @Override
   167         public void onLoaderReset(Loader<Cursor> loader) { }
   168     }
   170     private class FileLoaderCallbacks implements LoaderCallbacks<Cursor>,
   171                                                  Tabs.OnTabsChangedListener {
   172         final private Uri uri;
   173         private String tempFile;
   175         public FileLoaderCallbacks(Uri uri) {
   176             this.uri = uri;
   177         }
   179         @Override
   180         public Loader<Cursor> onCreateLoader(int id, Bundle args) {
   181             final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
   182             return new CursorLoader(fa,
   183                                     uri,
   184                                     new String[] { OpenableColumns.DISPLAY_NAME },
   185                                     null,  // selection
   186                                     null,  // selectionArgs
   187                                     null); // sortOrder
   188         }
   190         @Override
   191         public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
   192             if (cursor.moveToFirst()) {
   193                 String name = cursor.getString(0);
   194                 // tmp filenames must be at least 3 characters long. Add a prefix to make sure that happens
   195                 String fileName = "tmp_" + Process.myPid() + "-";
   196                 String fileExt = null;
   197                 int period;
   199                 final FragmentActivity fa = (FragmentActivity) GeckoAppShell.getGeckoInterface().getActivity();
   200                 final ContentResolver cr = fa.getContentResolver();
   202                 // Generate an extension if we don't already have one
   203                 if (name == null || (period = name.lastIndexOf('.')) == -1) {
   204                     String mimeType = cr.getType(uri);
   205                     fileExt = "." + GeckoAppShell.getExtensionFromMimeType(mimeType);
   206                 } else {
   207                     fileExt = name.substring(period);
   208                     fileName += name.substring(0, period);
   209                 }
   211                 // Now write the data to the temp file
   212                 try {
   213                     cacheDir.mkdir();
   215                     File file = File.createTempFile(fileName, fileExt, cacheDir);
   216                     FileOutputStream fos = new FileOutputStream(file);
   217                     InputStream is = cr.openInputStream(uri);
   218                     byte[] buf = new byte[4096];
   219                     int len = is.read(buf);
   220                     while (len != -1) {
   221                         fos.write(buf, 0, len);
   222                         len = is.read(buf);
   223                     }
   224                     fos.close();
   226                     tempFile = file.getAbsolutePath();
   227                     sendResult((tempFile == null) ? "" : tempFile);
   229                     if (tabId > -1 && !TextUtils.isEmpty(tempFile)) {
   230                         Tabs.registerOnTabsChangedListener(this);
   231                     }
   232                 } catch(IOException ex) {
   233                     Log.i(LOGTAG, "Error writing file", ex);
   234                 }
   235             } else {
   236                 sendResult("");
   237             }
   238         }
   240         @Override
   241         public void onLoaderReset(Loader<Cursor> loader) { }
   243         /*Tabs.OnTabsChangedListener*/
   244         // This cleans up our temp file. If it doesn't run, we just hope that Android
   245         // will eventually does the cleanup for us.
   246         @Override
   247         public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
   248             if (tab.getId() != tabId) {
   249                 return;
   250             }
   252             if (msg == Tabs.TabEvents.LOCATION_CHANGE ||
   253                 msg == Tabs.TabEvents.CLOSED) {
   254                 ThreadUtils.postToBackgroundThread(new Runnable() {
   255                     @Override
   256                     public void run() {
   257                         File f = new File(tempFile);
   258                         f.delete();
   259                     }
   260                 });
   262                 // Tabs' listener array is safe to modify during use: its
   263                 // iteration pattern is based on snapshots.
   264                 Tabs.unregisterOnTabsChangedListener(this);
   265             }
   266         }
   267     }
   269 }

mercurial