Ver código fonte

Merge pull request #967 from owncloud/fix_upload_fails_sending_another_app

Fixed fail in upload sent from the private storage of other app
David A. Velasco 10 anos atrás
pai
commit
8882fb2dbd

+ 1 - 0
res/values/strings.xml

@@ -219,6 +219,7 @@
     <string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string>
     <string name="filedisplay_no_file_selected">No file was selected</string>
     <string name="activity_chooser_title">Send link to &#8230;</string>
+    <string name="wait_for_tmp_copy_from_private_storage">Copying file from private storage</string>
     
     <string name="oauth_check_onoff">Login with oAuth2</string> 
     <string name="oauth_login_connection">Connecting to oAuth2 server…</string>    

+ 181 - 87
src/com/owncloud/android/ui/activity/Uploader.java

@@ -2,6 +2,7 @@
  *   ownCloud Android client application
  *
  *   @author Bartek Przybylski
+ *   @author masensio
  *   Copyright (C) 2012  Bartek Przybylski
  *   Copyright (C) 2015 ownCloud Inc.
  *
@@ -29,6 +30,7 @@ import java.util.List;
 import java.util.Stack;
 import java.util.Vector;
 
+
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.app.AlertDialog;
@@ -47,9 +49,13 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.preference.PreferenceManager;
+import android.provider.MediaStore;
 import android.provider.MediaStore.Audio;
 import android.provider.MediaStore.Images;
 import android.provider.MediaStore.Video;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
 import android.view.View;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
@@ -71,6 +77,8 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.operations.CreateFolderOperation;
 import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
+import com.owncloud.android.ui.dialog.LoadingDialog;
+import com.owncloud.android.utils.CopyTmpFileAsyncTask;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 
@@ -79,7 +87,8 @@ import com.owncloud.android.utils.ErrorMessageAdapter;
  * This can be used to upload things to an ownCloud instance.
  */
 public class Uploader extends FileActivity
-        implements OnItemClickListener, android.view.View.OnClickListener {
+        implements OnItemClickListener, android.view.View.OnClickListener,
+        CopyTmpFileAsyncTask.OnCopyTmpFileTaskListener {
 
     private static final String TAG = Uploader.class.getSimpleName();
 
@@ -90,6 +99,10 @@ public class Uploader extends FileActivity
     private String mUploadPath;
     private OCFile mFile;
     private boolean mAccountSelected;
+    private boolean mAccountSelectionShowing;
+
+    private ArrayList<String> mRemoteCacheData;
+    private int mNumCacheFile;
     
     private final static int DIALOG_NO_ACCOUNT = 0;
     private final static int DIALOG_WAITING = 1;
@@ -101,6 +114,11 @@ public class Uploader extends FileActivity
     private final static String KEY_PARENTS = "PARENTS";
     private final static String KEY_FILE = "FILE";
     private final static String KEY_ACCOUNT_SELECTED = "ACCOUNT_SELECTED";
+    private final static String KEY_ACCOUNT_SELECTION_SHOWING = "ACCOUNT_SELECTION_SHOWING";
+    private final static String KEY_NUM_CACHE_FILE = "NUM_CACHE_FILE";
+    private final static String KEY_REMOTE_CACHE_DATA = "REMOTE_CACHE_DATA";
+
+    private static final String DIALOG_WAIT_COPY_FILE = "DIALOG_WAIT_COPY_FILE";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -109,13 +127,27 @@ public class Uploader extends FileActivity
         if (savedInstanceState == null) {
             mParents = new Stack<String>();
             mAccountSelected = false;
+            mAccountSelectionShowing = false;
+            mNumCacheFile = 0;
+
+            // ArrayList for files with path in private storage
+            mRemoteCacheData = new ArrayList<String>();
         } else {
             mParents = (Stack<String>) savedInstanceState.getSerializable(KEY_PARENTS);
             mFile = savedInstanceState.getParcelable(KEY_FILE);
             mAccountSelected = savedInstanceState.getBoolean(KEY_ACCOUNT_SELECTED);
+            mAccountSelectionShowing = savedInstanceState.getBoolean(KEY_ACCOUNT_SELECTION_SHOWING);
+            mNumCacheFile = savedInstanceState.getInt(KEY_NUM_CACHE_FILE);
+            mRemoteCacheData = savedInstanceState.getStringArrayList(KEY_REMOTE_CACHE_DATA);
         }
+
         super.onCreate(savedInstanceState);
 
+        if (mAccountSelected) {
+            setAccount((Account) savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT));
+        }
+
+
         ActionBar actionBar = getSupportActionBar();
         actionBar.setIcon(DisplayUtils.getSeasonalIconId());
 
@@ -129,9 +161,10 @@ public class Uploader extends FileActivity
             if (accounts.length == 0) {
                 Log_OC.i(TAG, "No ownCloud account is available");
                 showDialog(DIALOG_NO_ACCOUNT);
-            } else if (accounts.length > 1 && !mAccountSelected) {
+            } else if (accounts.length > 1 && !mAccountSelected && !mAccountSelectionShowing) {
                 Log_OC.i(TAG, "More than one ownCloud is available");
                 showDialog(DIALOG_MULTIPLE_ACCOUNT);
+                mAccountSelectionShowing = true;
             } else {
                 if (!savedAccount) {
                     setAccount(accounts[0]);
@@ -160,6 +193,10 @@ public class Uploader extends FileActivity
         //outState.putParcelable(KEY_ACCOUNT, mAccount);
         outState.putParcelable(KEY_FILE, mFile);
         outState.putBoolean(KEY_ACCOUNT_SELECTED, mAccountSelected);
+        outState.putBoolean(KEY_ACCOUNT_SELECTION_SHOWING, mAccountSelectionShowing);
+        outState.putInt(KEY_NUM_CACHE_FILE, mNumCacheFile);
+        outState.putStringArrayList(KEY_REMOTE_CACHE_DATA, mRemoteCacheData);
+        outState.putParcelable(FileActivity.EXTRA_ACCOUNT, getAccount());
 
         Log_OC.d(TAG, "onSaveInstanceState() end");
     }
@@ -225,12 +262,14 @@ public class Uploader extends FileActivity
                     onAccountSet(mAccountWasRestored);
                     dialog.dismiss();
                     mAccountSelected = true;
+                    mAccountSelectionShowing = false;
                 }
             });
             builder.setCancelable(true);
             builder.setOnCancelListener(new OnCancelListener() {
                 @Override
                 public void onCancel(DialogInterface dialog) {
+                    mAccountSelectionShowing = false;
                     dialog.cancel();
                     finish();
                 }
@@ -366,7 +405,7 @@ public class Uploader extends FileActivity
         actionBar.setHomeButtonEnabled(notRoot);
 
         String full_path = generatePath(mParents);
-        
+
         Log_OC.d(TAG, "Populating view with content of : " + full_path);
 
         mFile = getStorageManager().getFileByPath(full_path);
@@ -421,6 +460,7 @@ public class Uploader extends FileActivity
     public void uploadFiles() {
         try {
 
+            // ArrayList for files with path in external storage
             ArrayList<String> local = new ArrayList<String>();
             ArrayList<String> remote = new ArrayList<String>();
             
@@ -428,101 +468,106 @@ public class Uploader extends FileActivity
             for (Parcelable mStream : mStreamsToUpload) {
                 
                 Uri uri = (Uri) mStream;
-                if (uri !=null) {
+                String data = null;
+                String filePath = "";
+
+                if (uri != null) {
                     if (uri.getScheme().equals("content")) {
-                        
-                       String mimeType = getContentResolver().getType(uri);
-                       
-                       if (mimeType.contains("image")) {
-                           String[] CONTENT_PROJECTION = { Images.Media.DATA,
-                                   Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE,
-                                   Images.Media.SIZE};
-                           Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
-                                   null, null);
-                           c.moveToFirst();
-                           int index = c.getColumnIndex(Images.Media.DATA);
-                           String data = c.getString(index);
-                           local.add(data);
-                           remote.add(mUploadPath +
-                                   c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME)));
-                       
-                       }
-                       else if (mimeType.contains("video")) {
-                           String[] CONTENT_PROJECTION = { Video.Media.DATA,
+                        String mimeType = getContentResolver().getType(uri);
+
+                        if (mimeType.contains("image")) {
+                            String[] CONTENT_PROJECTION = { Images.Media.DATA,
+                                    Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE,
+                                    Images.Media.SIZE };
+                            Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
+                                    null, null);
+                            c.moveToFirst();
+                            int index = c.getColumnIndex(Images.Media.DATA);
+                            data = c.getString(index);
+                            filePath = mUploadPath +
+                                    c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME));
+
+                        } else if (mimeType.contains("video")) {
+                            String[] CONTENT_PROJECTION = { Video.Media.DATA,
                                    Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE,
                                    Video.Media.SIZE, Video.Media.DATE_MODIFIED };
-                           Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
+                            Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
                                    null, null);
-                           c.moveToFirst();
-                           int index = c.getColumnIndex(Video.Media.DATA);
-                           String data = c.getString(index);
-                           local.add(data);
-                           remote.add(mUploadPath +
-                                   c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME)));
+                            c.moveToFirst();
+                            int index = c.getColumnIndex(Video.Media.DATA);
+                            data = c.getString(index);
+                            filePath = mUploadPath +
+                                   c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME));
                           
-                       }
-                       else if (mimeType.contains("audio")) {
-                           String[] CONTENT_PROJECTION = { Audio.Media.DATA,
+                        } else if (mimeType.contains("audio")) {
+                            String[] CONTENT_PROJECTION = { Audio.Media.DATA,
                                    Audio.Media.DISPLAY_NAME, Audio.Media.MIME_TYPE,
                                    Audio.Media.SIZE };
-                           Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
+                            Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
                                    null, null);
-                           c.moveToFirst();
-                           int index = c.getColumnIndex(Audio.Media.DATA);
-                           String data = c.getString(index);
-                           local.add(data);
-                           remote.add(mUploadPath +
-                                   c.getString(c.getColumnIndex(Audio.Media.DISPLAY_NAME)));
-                        
-                       }
-                       else {
-                           String filePath = Uri.decode(uri.toString()).replace(uri.getScheme() +
-                                   "://", "");
-                           // cut everything whats before mnt. It occurred to me that sometimes
-                           // apps send their name into the URI
-                           if (filePath.contains("mnt")) {
-                              String splitedFilePath[] = filePath.split("/mnt");
-                              filePath = splitedFilePath[1];
-                           }
-                           final File file = new File(filePath);
-                           local.add(file.getAbsolutePath());
-                           remote.add(mUploadPath + file.getName());
-                       }
-                        
+                            c.moveToFirst();
+                            int index = c.getColumnIndex(Audio.Media.DATA);
+                            data = c.getString(index);
+                            filePath = mUploadPath +
+                                   c.getString(c.getColumnIndex(Audio.Media.DISPLAY_NAME));
+
+                        } else  {
+                            Cursor cursor = getContentResolver().query(uri,
+                                   new String[]{MediaStore.MediaColumns.DISPLAY_NAME},
+                                   null, null, null);
+                            cursor.moveToFirst();
+                            int nameIndex = cursor.getColumnIndex(cursor.getColumnNames()[0]);
+                            if (nameIndex >= 0) {
+                               filePath = mUploadPath + cursor.getString(nameIndex);
+                            }
+                        }
+
                     } else if (uri.getScheme().equals("file")) {
-                        String filePath = Uri.decode(uri.toString()).replace(uri.getScheme() +
+                        filePath = Uri.decode(uri.toString()).replace(uri.getScheme() +
                                 "://", "");
                         if (filePath.contains("mnt")) {
                            String splitedFilePath[] = filePath.split("/mnt");
                            filePath = splitedFilePath[1];
                         }
                         final File file = new File(filePath);
-                        local.add(file.getAbsolutePath());
-                        remote.add(mUploadPath + file.getName());
+                        data = file.getAbsolutePath();
+                        filePath = mUploadPath + file.getName();
                     }
                     else {
                         throw new SecurityException();
                     }
+                    if (data == null) {
+                        mRemoteCacheData.add(filePath);
+                        CopyTmpFileAsyncTask copyTask = new CopyTmpFileAsyncTask(this);
+                        Object[] params = { uri, filePath, mRemoteCacheData.size()-1,
+                                getAccount().name, getContentResolver()};
+                        mNumCacheFile++;
+                        showWaitingCopyDialog();
+                        copyTask.execute(params);
+                    } else {
+                        remote.add(filePath);
+                        local.add(data);
+                    }
                 }
                 else {
                     throw new SecurityException();
                 }
-           
-            Intent intent = new Intent(getApplicationContext(), FileUploader.class);
-            intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
-            intent.putExtra(FileUploader.KEY_LOCAL_FILE, local.toArray(new String[local.size()]));
-            intent.putExtra(FileUploader.KEY_REMOTE_FILE,
-                    remote.toArray(new String[remote.size()]));
-            intent.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
-            startService(intent);
 
-            //Save the path to shared preferences
-            SharedPreferences.Editor appPrefs = PreferenceManager
-                    .getDefaultSharedPreferences(getApplicationContext()).edit();
-            appPrefs.putString("last_upload_path", mUploadPath);
-            appPrefs.apply();
+                Intent intent = new Intent(getApplicationContext(), FileUploader.class);
+                intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
+                intent.putExtra(FileUploader.KEY_LOCAL_FILE, local.toArray(new String[local.size()]));
+                intent.putExtra(FileUploader.KEY_REMOTE_FILE,
+                        remote.toArray(new String[remote.size()]));
+                intent.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
+                startService(intent);
 
-            finish();
+                //Save the path to shared preferences
+                SharedPreferences.Editor appPrefs = PreferenceManager
+                        .getDefaultSharedPreferences(getApplicationContext()).edit();
+                appPrefs.putString("last_upload_path", mUploadPath);
+                appPrefs.apply();
+
+                finish();
             }
             
         } catch (SecurityException e) {
@@ -588,16 +633,15 @@ public class Uploader extends FileActivity
         // "/" equals root-directory
         if(last_path.equals("/")) {
             mParents.add("");
-        }
-        else{
+        } else{
             String[] dir_names = last_path.split("/");
             for (String dir : dir_names)
                 mParents.add(dir);
         }
         //Make sure that path still exists, if it doesn't pop the stack and try the previous path
-            while(!getStorageManager().fileExists(generatePath(mParents)) && mParents.size() > 1){
-                mParents.pop();
-            }
+        while(!getStorageManager().fileExists(generatePath(mParents)) && mParents.size() > 1){
+            mParents.pop();
+        }
     }
 
     
@@ -605,17 +649,67 @@ public class Uploader extends FileActivity
     public boolean onOptionsItemSelected(MenuItem item) {
         boolean retval = true;
         switch (item.getItemId()) {
-        case android.R.id.home: {
-            if((mParents.size() > 1)) {                
-                onBackPressed(); 
-            }
-            break;
-        }
-        default:
-            retval = super.onOptionsItemSelected(item);
+            case android.R.id.home:
+                if((mParents.size() > 1)) {
+                    onBackPressed();
+                }
+                break;
+
+            default:
+                retval = super.onOptionsItemSelected(item);
         }
         return retval;
     }
 
-    
+
+    /**
+     * Process the result of CopyTmpFileAsyncTask
+     * @param result
+     * @param index
+     */
+    @Override
+    public void onTmpFileCopied(String result, int index) {
+        if (mNumCacheFile -- == 0) {
+            dismissWaitingCopyDialog();
+        }
+        if (result != null) {
+            Intent intent = new Intent(getApplicationContext(), FileUploader.class);
+            intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
+            intent.putExtra(FileUploader.KEY_LOCAL_FILE, result);
+            intent.putExtra(FileUploader.KEY_REMOTE_FILE, mRemoteCacheData.get(index));
+            intent.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
+            startService(intent);
+
+        } else {
+            String message = String.format(getString(R.string.uploader_error_forbidden_content),
+                    getString(R.string.app_name));
+            Toast.makeText(this, message, Toast.LENGTH_LONG).show();
+            Log_OC.d(TAG, message);
+        }
+
+    }
+/**
+     * Show waiting for copy dialog
+     */
+    public void showWaitingCopyDialog() {
+        // Construct dialog
+        LoadingDialog loading = new LoadingDialog(
+                getResources().getString(R.string.wait_for_tmp_copy_from_private_storage));
+        FragmentManager fm = getSupportFragmentManager();
+        FragmentTransaction ft = fm.beginTransaction();
+        loading.show(ft, DIALOG_WAIT_COPY_FILE);
+
+    }
+
+
+    /**
+     * Dismiss waiting for copy dialog
+     */
+    public void dismissWaitingCopyDialog(){
+        Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_COPY_FILE);
+        if (frag != null) {
+            LoadingDialog loading = (LoadingDialog) frag;
+            loading.dismiss();
+        }
+    }
 }

+ 142 - 0
src/com/owncloud/android/utils/CopyTmpFileAsyncTask.java

@@ -0,0 +1,142 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   Copyright (C) 2015 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.utils;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+
+/**
+ * AsyncTask to copy a file from a uri in a temporal file
+ */
+public class CopyTmpFileAsyncTask  extends AsyncTask<Object, Void, String> {
+
+    private final String TAG = CopyTmpFileAsyncTask.class.getSimpleName();
+    private final WeakReference<OnCopyTmpFileTaskListener> mListener;
+    private int mIndex;
+
+    public int getIndex(){
+        return mIndex;
+    }
+
+    public CopyTmpFileAsyncTask(OnCopyTmpFileTaskListener listener) {
+        mListener = new WeakReference<OnCopyTmpFileTaskListener>(listener);
+    }
+
+    /**
+     * Params for execute:
+     * - Uri: uri of file
+     * - String: path for saving the file into the app
+     * - int: index of upload
+     * - String: accountName
+     * - ContentResolver: content resolver
+     */
+    @Override
+    protected String doInBackground(Object[] params) {
+        String result = null;
+
+        if (params != null && params.length == 5) {
+            Uri uri = (Uri) params[0];
+            String filePath = (String) params[1];
+            mIndex = ((Integer) params[2]).intValue();
+            String accountName = (String) params[3];
+            ContentResolver contentResolver = (ContentResolver) params[4];
+
+            String fullTempPath = FileStorageUtils.getTemporalPath(accountName) + filePath;
+            InputStream inputStream = null;
+            FileOutputStream outputStream = null;
+
+            try {
+                inputStream = contentResolver.openInputStream(uri);
+                File cacheFile = new File(fullTempPath);
+                File tempDir = cacheFile.getParentFile();
+                if (!tempDir.exists()) {
+                    tempDir.mkdirs();
+                }
+                cacheFile.createNewFile();
+                outputStream = new FileOutputStream(fullTempPath);
+                byte[] buffer = new byte[4096];
+
+                int count = 0;
+
+                while ((count = inputStream.read(buffer)) > 0) {
+                    outputStream.write(buffer, 0, count);
+                }
+
+                outputStream.close();
+                inputStream.close();
+
+                result = fullTempPath;
+            } catch (Exception e) {
+                 Log_OC.e(TAG, "Exception ", e);
+                if (inputStream != null) {
+                    try {
+                        inputStream.close();
+                    } catch (Exception e1) {
+                        Log_OC.e(TAG, "Input Stream Exception ", e1);
+                    }
+                }
+
+                if (outputStream != null) {
+                    try {
+                        outputStream.close();
+                    } catch (Exception e1) {
+                        Log_OC.e(TAG, "Output Stream Exception ", e1);
+                    }
+                }
+
+                if (fullTempPath != null) {
+                    File f = new File(fullTempPath);
+                    f.delete();
+                }
+                result =  null;
+            }
+        } else {
+             throw new IllegalArgumentException("Error in parameters number");
+        }
+
+        return result;
+    }
+
+    @Override
+    protected void onPostExecute(String result) {
+
+        OnCopyTmpFileTaskListener listener = mListener.get();
+        if (listener!= null)
+        {
+            listener.onTmpFileCopied(result, mIndex);
+        }
+    }
+
+    /*
+     * Interface to retrieve data from recognition task
+     */
+    public interface OnCopyTmpFileTaskListener{
+
+        void onTmpFileCopied(String result, int index);
+    }
+}