浏览代码

Merge branch 'develop' into automationTest

purigarcia 10 年之前
父节点
当前提交
6a9dfdb330

+ 1 - 1
AndroidManifest.xml

@@ -151,7 +151,7 @@
         <service android:name=".files.services.FileUploader" />
         <service android:name=".files.services.FileUploader" />
         <service android:name=".media.MediaService" />
         <service android:name=".media.MediaService" />
         
         
-        <activity android:name=".ui.activity.PinCodeActivity" />
+        <activity android:name=".ui.activity.PassCodeActivity" />
         <activity android:name=".ui.activity.ConflictsResolveActivity"/>
         <activity android:name=".ui.activity.ConflictsResolveActivity"/>
         <activity android:name=".ui.activity.GenericExplanationActivity"/>
         <activity android:name=".ui.activity.GenericExplanationActivity"/>
         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>

+ 88 - 78
res/layout/pincodelock.xml → res/layout/passcodelock.xml

@@ -1,78 +1,88 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ownCloud Android client application
-
-  Copyright (C) 2012  Bartek Przybylski
-  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/>.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:gravity="center_horizontal"
-    android:orientation="vertical"
-    android:padding="20dp" >
-
-
-    <TextView
-        android:id="@+id/pinHdr"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/pincode_enter_pin_code"
-        android:textColor="@android:color/black"
-        android:gravity="center_horizontal"
-         />
-
-    <TextView
-        android:id="@+id/pinHdrExpl"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/pincode_configure_your_pin_explanation"
-        android:textAppearance="@android:style/TextAppearance.Small"
-        android:gravity="center_horizontal"
-         />
-    
-    <LinearLayout
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_horizontal" >
-
-        <EditText
-            android:id="@+id/txt1"
-            android:focusable="true"
-            style="@style/PassCodeStyle"
-            android:cursorVisible="true"
-            ><requestFocus/></EditText>
-
-        <EditText
-            android:id="@+id/txt2"
-            style="@style/PassCodeStyle" />
-
-        <EditText
-            android:id="@+id/txt3"
-            style="@style/PassCodeStyle" />
-
-        <EditText
-            android:id="@+id/txt4"
-            style="@style/PassCodeStyle" />
-    </LinearLayout>
-
-    <Button
-        android:id="@+id/cancel"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/common_cancel" />
-
-</LinearLayout>
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+
+  Copyright (C) 2012  Bartek Przybylski
+  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/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:gravity="center_horizontal"
+    android:orientation="vertical"
+    android:padding="20dp" >
+
+
+    <TextView
+        android:id="@+id/header"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/pass_code_enter_pass_code"
+        android:textColor="@android:color/black"
+        android:gravity="center_horizontal"
+         />
+
+    <TextView
+        android:id="@+id/explanation"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/pass_code_configure_your_pass_code_explanation"
+        android:textAppearance="@android:style/TextAppearance.Small"
+        android:gravity="center_horizontal"
+         />
+    
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_horizontal" >
+
+        <EditText
+            android:id="@+id/txt0"
+            android:focusable="true"
+            style="@style/PassCodeStyle"
+            android:cursorVisible="true"
+            android:imeOptions="flagNoExtractUi"
+            ><requestFocus/></EditText>
+
+        <EditText
+            android:id="@+id/txt1"
+            style="@style/PassCodeStyle"
+            android:cursorVisible="true"
+            android:imeOptions="flagNoExtractUi"
+            />
+
+        <EditText
+            android:id="@+id/txt2"
+            style="@style/PassCodeStyle"
+            android:cursorVisible="true"
+            android:imeOptions="flagNoExtractUi"
+            />
+
+        <EditText
+            android:id="@+id/txt3"
+            style="@style/PassCodeStyle"
+            android:cursorVisible="true"
+            android:imeOptions="flagNoExtractUi"
+            />
+    </LinearLayout>
+
+    <Button
+        android:id="@+id/cancel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/common_cancel" />
+
+</LinearLayout>

+ 11 - 11
res/values/strings.xml

@@ -24,8 +24,7 @@
     <string name="prefs_category_more">More</string>
     <string name="prefs_category_more">More</string>
     <string name="prefs_accounts">Accounts</string>
     <string name="prefs_accounts">Accounts</string>
     <string name="prefs_manage_accounts">Manage Accounts</string>
     <string name="prefs_manage_accounts">Manage Accounts</string>
-    <string name="prefs_pincode">App PIN</string>
-    <string name="prefs_pincode_summary">Protect your client</string>
+    <string name="prefs_passcode">Pass code lock</string>
     <string name="prefs_instant_upload">Instant picture uploads</string>
     <string name="prefs_instant_upload">Instant picture uploads</string>
     <string name="prefs_instant_upload_summary">Instantly upload pictures taken by camera</string>
     <string name="prefs_instant_upload_summary">Instantly upload pictures taken by camera</string>
     <string name="prefs_instant_video_upload">Instant video uploads</string>
     <string name="prefs_instant_video_upload">Instant video uploads</string>
@@ -132,16 +131,16 @@
     <string name="foreign_files_local_text">"Local: %1$s"</string>
     <string name="foreign_files_local_text">"Local: %1$s"</string>
     <string name="foreign_files_remote_text">"Remote: %1$s"</string>
     <string name="foreign_files_remote_text">"Remote: %1$s"</string>
     <string name="upload_query_move_foreign_files">There is not space enough to copy the selected files into the %1$s folder. Would you like to move them instead? </string>
     <string name="upload_query_move_foreign_files">There is not space enough to copy the selected files into the %1$s folder. Would you like to move them instead? </string>
-    <string name="pincode_enter_pin_code">Please, insert your App PIN</string>
+    <string name="pass_code_enter_pass_code">Please, insert your pass code</string>
     
     
-    <string name="pincode_configure_your_pin">Enter your App PIN</string>
-    <string name="pincode_configure_your_pin_explanation">The PIN will be requested every time the app is started</string>
-    <string name="pincode_reenter_your_pincode">Please, reenter your App PIN</string>
-    <string name="pincode_remove_your_pincode">Remove your App PIN</string>
-    <string name="pincode_mismatch">The App PINs are not the same</string>
-    <string name="pincode_wrong">Incorrect App PIN</string>
-    <string name="pincode_removed">App PIN removed</string>
-    <string name="pincode_stored">App PIN stored</string>
+    <string name="pass_code_configure_your_pass_code">Enter your pass code</string>
+    <string name="pass_code_configure_your_pass_code_explanation">The pass code will be requested every time the app is started</string>
+    <string name="pass_code_reenter_your_pass_code">Please, reenter your pass code</string>
+    <string name="pass_code_remove_your_pass_code">Remove your pass code</string>
+    <string name="pass_code_mismatch">The pass codes are not the same</string>
+    <string name="pass_code_wrong">Incorrect pass code</string>
+    <string name="pass_code_removed">Pass code removed</string>
+    <string name="pass_code_stored">Pass code stored</string>
     
     
     <string name="media_notif_ticker">"%1$s music player"</string>
     <string name="media_notif_ticker">"%1$s music player"</string>
     <string name="media_state_playing">"%1$s (playing)"</string>
     <string name="media_state_playing">"%1$s (playing)"</string>
@@ -220,6 +219,7 @@
     <string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string>
     <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="filedisplay_no_file_selected">No file was selected</string>
     <string name="activity_chooser_title">Send link to &#8230;</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_check_onoff">Login with oAuth2</string> 
     <string name="oauth_login_connection">Connecting to oAuth2 server…</string>    
     <string name="oauth_login_connection">Connecting to oAuth2 server…</string>    

+ 1 - 7
res/xml/preferences.xml

@@ -22,13 +22,7 @@
     </PreferenceCategory>
     </PreferenceCategory>
     
     
 	<PreferenceCategory android:title="@string/prefs_category_security">
 	<PreferenceCategory android:title="@string/prefs_category_security">
-	    <!-- ListPreference
-	        android:key="select_oc_account"
-	        android:title="@string/prefs_select_oc_account"
-	        android:summary="@string/prefs_summary_select_oc_account"
-	        / -->
-	    <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:title="@string/prefs_pincode" android:key="set_pincode" 
-                        android:summary="@string/prefs_pincode_summary"/>
+	    <android.preference.CheckBoxPreference android:title="@string/prefs_passcode" android:key="set_pincode" />
 	</PreferenceCategory>
 	</PreferenceCategory>
 
 
     <PreferenceCategory android:title="@string/prefs_category_instant_uploading" android:key="instant_uploading_category">
     <PreferenceCategory android:title="@string/prefs_category_instant_uploading" android:key="instant_uploading_category">

+ 50 - 1
src/com/owncloud/android/MainApp.java

@@ -20,16 +20,21 @@
  */
  */
 package com.owncloud.android;
 package com.owncloud.android;
 
 
+import android.app.Activity;
 import android.app.Application;
 import android.app.Application;
 import android.content.Context;
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
 
 
+import com.owncloud.android.authentication.PassCodeManager;
 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy;
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.common.utils.Log_OC;
 
 
+
 /**
 /**
  * Main Application of the project
  * Main Application of the project
  * 
  * 
@@ -41,7 +46,7 @@ public class MainApp extends Application {
     private static final String TAG = MainApp.class.getSimpleName();
     private static final String TAG = MainApp.class.getSimpleName();
 
 
     private static final String AUTH_ON = "on";
     private static final String AUTH_ON = "on";
-    
+
     @SuppressWarnings("unused")
     @SuppressWarnings("unused")
     private static final String POLICY_SINGLE_SESSION_PER_ACCOUNT = "single session per account";
     private static final String POLICY_SINGLE_SESSION_PER_ACCOUNT = "single session per account";
     @SuppressWarnings("unused")
     @SuppressWarnings("unused")
@@ -75,6 +80,50 @@ public class MainApp extends Application {
             Log_OC.startLogging();
             Log_OC.startLogging();
             Log_OC.d("Debug", "start logging");
             Log_OC.d("Debug", "start logging");
         }
         }
+
+        // register global protection with pass code
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            this.registerActivityLifecycleCallbacks( new ActivityLifecycleCallbacks() {
+
+                @Override
+                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+                    Log_OC.d(activity.getClass().getSimpleName(),  "onCreate(Bundle) starting" );
+                    PassCodeManager.getPassCodeManager().onActivityCreated(activity);
+                }
+
+                @Override
+                public void onActivityStarted(Activity activity) {
+                    Log_OC.d(activity.getClass().getSimpleName(),  "onStart() starting" );
+                    PassCodeManager.getPassCodeManager().onActivityStarted(activity);
+                }
+
+                @Override
+                public void onActivityResumed(Activity activity) {
+                    Log_OC.d(activity.getClass().getSimpleName(), "onResume() starting" );
+                }
+
+                @Override
+                public void onActivityPaused(Activity activity) {
+                    Log_OC.d(activity.getClass().getSimpleName(), "onPause() ending");
+                }
+
+                @Override
+                public void onActivityStopped(Activity activity) {
+                    Log_OC.d(activity.getClass().getSimpleName(), "onStop() ending" );
+                    PassCodeManager.getPassCodeManager().onActivityStopped(activity);
+                }
+
+                @Override
+                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+                    Log_OC.d(activity.getClass().getSimpleName(), "onSaveInstanceState(Bundle) starting" );
+                }
+
+                @Override
+                public void onActivityDestroyed(Activity activity) {
+                    Log_OC.d(activity.getClass().getSimpleName(), "onDestroy() ending" );
+                }
+            });
+        }
     }
     }
 
 
     public static Context getAppContext() {
     public static Context getAppContext() {

+ 115 - 0
src/com/owncloud/android/authentication/PassCodeManager.java

@@ -0,0 +1,115 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   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.authentication;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.PowerManager;
+import android.preference.PreferenceManager;
+import android.view.WindowManager;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.ui.activity.PassCodeActivity;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class PassCodeManager {
+
+    private static final Set<Class> sExemptOfPasscodeActivites;
+
+    static {
+        sExemptOfPasscodeActivites = new HashSet<Class>();
+        sExemptOfPasscodeActivites.add(PassCodeActivity.class);
+        // other activities may be exempted, if needed
+    }
+
+    private static int PASS_CODE_TIMEOUT = 1000;
+        // keeping a "low" positive value is the easiest way to prevent the pass code is requested on rotations
+
+    public static PassCodeManager mPassCodeManagerInstance = null;
+
+    public static PassCodeManager getPassCodeManager() {
+        if (mPassCodeManagerInstance == null) {
+            mPassCodeManagerInstance = new PassCodeManager();
+        }
+        return mPassCodeManagerInstance;
+    }
+
+    private Long mTimestamp = 0l;
+    private int mVisibleActivitiesCounter = 0;
+
+    protected PassCodeManager() {};
+
+    public void onActivityCreated(Activity activity) {
+        if (passCodeIsEnabled()) {
+            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
+        } else {
+            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
+        }
+    }
+
+    public void onActivityStarted(Activity activity) {
+        if (!sExemptOfPasscodeActivites.contains(activity.getClass()) &&
+                passCodeShouldBeRequested()
+                ){
+
+            Intent i = new Intent(MainApp.getAppContext(), PassCodeActivity.class);
+            i.setAction(PassCodeActivity.ACTION_REQUEST);
+            i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+            activity.startActivity(i);
+
+        }
+
+        mVisibleActivitiesCounter++;    // keep it AFTER passCodeShouldBeRequested was checked
+    }
+
+    public void onActivityStopped(Activity activity) {
+        if (mVisibleActivitiesCounter > 0) {
+            mVisibleActivitiesCounter--;
+        }
+        setUnlockTimestamp();
+        PowerManager powerMgr = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
+        if (passCodeIsEnabled() && powerMgr != null && !powerMgr.isScreenOn()) {
+            activity.moveTaskToBack(true);
+        }
+    }
+
+    private void setUnlockTimestamp() {
+        mTimestamp = System.currentTimeMillis();
+    }
+
+    private boolean passCodeShouldBeRequested(){
+        if ((System.currentTimeMillis() - mTimestamp) > PASS_CODE_TIMEOUT &&
+                mVisibleActivitiesCounter <= 0
+                ){
+            return passCodeIsEnabled();
+        }
+        return false;
+    }
+
+    private boolean passCodeIsEnabled() {
+        SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(MainApp.getAppContext());
+        return (appPrefs.getBoolean("set_pincode", false));
+    }
+
+}

+ 0 - 9
src/com/owncloud/android/ui/activity/FileActivity.java

@@ -197,42 +197,34 @@ public class FileActivity extends SherlockFragmentActivity
     
     
     @Override 
     @Override 
     protected void onStart() {
     protected void onStart() {
-        Log_OC.v(TAG, "onStart() start");
         super.onStart();
         super.onStart();
 
 
         if (mAccountWasSet) {
         if (mAccountWasSet) {
             onAccountSet(mAccountWasRestored);
             onAccountSet(mAccountWasRestored);
         }
         }
-        Log_OC.v(TAG, "onStart() end");
     }
     }
     
     
     @Override
     @Override
     protected void onResume() {
     protected void onResume() {
-        Log_OC.v(TAG, "onResume() start");
         super.onResume();
         super.onResume();
         
         
         if (mOperationsServiceBinder != null) {
         if (mOperationsServiceBinder != null) {
             doOnResumeAndBound();
             doOnResumeAndBound();
         }
         }
-        Log_OC.v(TAG, "onResume() end");
     }
     }
     
     
     @Override
     @Override
     protected void onPause()  {
     protected void onPause()  {
-        Log_OC.v(TAG, "onPause() start");
-
         if (mOperationsServiceBinder != null) {
         if (mOperationsServiceBinder != null) {
             mOperationsServiceBinder.removeOperationListener(this);
             mOperationsServiceBinder.removeOperationListener(this);
         }
         }
         
         
         super.onPause();
         super.onPause();
-        Log_OC.v(TAG, "onPause() end");
     }
     }
     
     
     
     
     @Override
     @Override
     protected void onDestroy() {
     protected void onDestroy() {
-        Log_OC.v(TAG, "onDestroy() start");
         if (mOperationsServiceConnection != null) {
         if (mOperationsServiceConnection != null) {
             unbindService(mOperationsServiceConnection);
             unbindService(mOperationsServiceConnection);
             mOperationsServiceBinder = null;
             mOperationsServiceBinder = null;
@@ -247,7 +239,6 @@ public class FileActivity extends SherlockFragmentActivity
         }
         }
 
 
         super.onDestroy();
         super.onDestroy();
-        Log_OC.v(TAG, "onDestroy() end");
     }
     }
     
     
     
     

+ 14 - 43
src/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -153,22 +153,15 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
 
 
 
 
     private OCFile mWaitingToSend;
     private OCFile mWaitingToSend;
-
+    
     @Override
     @Override
     protected void onCreate(Bundle savedInstanceState) {
     protected void onCreate(Bundle savedInstanceState) {
-        Log_OC.d(TAG, "onCreate() start");
+        Log_OC.v(TAG, "onCreate() start");
         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
 
 
         super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account is valid
         super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account is valid
 
 
-        // PIN CODE request ;  best location is to decide, let's try this first
-        if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {
-            requestPinCode();
-        } else if (getIntent().getAction() == null && savedInstanceState == null) {
-            requestPinCode();
-        }
-
-        /// grant that FileObserverService is watching favourite files
+        /// grant that FileObserverService is watching favorite files
         if (savedInstanceState == null) {
         if (savedInstanceState == null) {
             Intent initObserversIntent = FileObserverService.makeInitIntent(this);
             Intent initObserversIntent = FileObserverService.makeInitIntent(this);
             startService(initObserversIntent);
             startService(initObserversIntent);
@@ -204,22 +197,22 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
         
         
         setBackgroundText();
         setBackgroundText();
 
 
-        Log_OC.d(TAG, "onCreate() end");
+        Log_OC.v(TAG, "onCreate() end");
     }
     }
     
     
     @Override
     @Override
     protected void onStart() {
     protected void onStart() {
-        Log_OC.d(TAG, "onStart() start");
+        Log_OC.v(TAG, "onStart() start");
         super.onStart();
         super.onStart();
         getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
         getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
-        Log_OC.d(TAG, "onStart() end");
+        Log_OC.v(TAG, "onStart() end");
     }
     }
 
 
     @Override
     @Override
     protected void onDestroy() {
     protected void onDestroy() {
-        Log_OC.d(TAG, "onDestroy() start");
+        Log_OC.v(TAG, "onDestroy() start");
         super.onDestroy();
         super.onDestroy();
-        Log_OC.d(TAG, "onDestroy() end");
+        Log_OC.v(TAG, "onDestroy() end");
     }
     }
 
 
     /**
     /**
@@ -532,10 +525,6 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
                         sortByDate(false);
                         sortByDate(false);
                         break;
                         break;
                         
                         
-// TODO re-enable when server-side folder size calculation is available                       
-//                    case 2:
-//                        sortBySize(false);
-//                        break;
                     }
                     }
                     
                     
                     dialog.dismiss();
                     dialog.dismiss();
@@ -781,21 +770,21 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
     @Override
     @Override
     protected void onSaveInstanceState(Bundle outState) {
     protected void onSaveInstanceState(Bundle outState) {
         // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
         // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
-        Log_OC.d(TAG, "onSaveInstanceState() start");
+        Log_OC.v(TAG, "onSaveInstanceState() start");
         super.onSaveInstanceState(outState);
         super.onSaveInstanceState(outState);
         outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
         outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
         outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress);
         outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress);
         //outState.putBoolean(FileDisplayActivity.KEY_REFRESH_SHARES_IN_PROGRESS, mRefreshSharesInProgress);
         //outState.putBoolean(FileDisplayActivity.KEY_REFRESH_SHARES_IN_PROGRESS, mRefreshSharesInProgress);
         outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND, mWaitingToSend);
         outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND, mWaitingToSend);
 
 
-        Log_OC.d(TAG, "onSaveInstanceState() end");
+        Log_OC.v(TAG, "onSaveInstanceState() end");
     }
     }
     
     
 
 
 
 
     @Override
     @Override
     protected void onResume() {
     protected void onResume() {
-        Log_OC.d(TAG, "onResume() start");
+        Log_OC.v(TAG, "onResume() start");
         super.onResume();
         super.onResume();
 
 
         // refresh list of files
         // refresh list of files
@@ -822,13 +811,13 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
         mDownloadFinishReceiver = new DownloadFinishReceiver();
         mDownloadFinishReceiver = new DownloadFinishReceiver();
         registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
         registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
         
         
-        Log_OC.d(TAG, "onResume() end");
+        Log_OC.v(TAG, "onResume() end");
     }
     }
 
 
 
 
     @Override
     @Override
     protected void onPause() {
     protected void onPause() {
-        Log_OC.d(TAG, "onPause() start");
+        Log_OC.v(TAG, "onPause() start");
         if (mSyncBroadcastReceiver != null) {
         if (mSyncBroadcastReceiver != null) {
             unregisterReceiver(mSyncBroadcastReceiver);
             unregisterReceiver(mSyncBroadcastReceiver);
             //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
             //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
@@ -843,9 +832,8 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
             mDownloadFinishReceiver = null;
             mDownloadFinishReceiver = null;
         }
         }
         
         
-        
         super.onPause();
         super.onPause();
-        Log_OC.d(TAG, "onPause() end");
+        Log_OC.v(TAG, "onPause() end");
     }
     }
 
 
     /**
     /**
@@ -1324,23 +1312,6 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
         }
         }
     };    
     };    
 
 
-
-
-    /**
-     * Launch an intent to request the PIN code to the user before letting him use the app
-     */
-    private void requestPinCode() {
-        boolean pinStart = false;
-        SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
-        pinStart = appPrefs.getBoolean("set_pincode", false);
-        if (pinStart) {
-            Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
-            i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity");
-            startActivity(i);
-        }
-    }
-
-
     @Override
     @Override
     public void onSavedCertificate() {
     public void onSavedCertificate() {
         startSyncFolderOperation(getCurrentDir(), false);
         startSyncFolderOperation(getCurrentDir(), false);

+ 499 - 0
src/com/owncloud/android/ui/activity/PassCodeActivity.java

@@ -0,0 +1,499 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2011 Bartek Przybylski
+ *   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.ui.activity;
+
+import java.util.Arrays;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.owncloud.android.R;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.utils.DisplayUtils;
+
+public class PassCodeActivity extends SherlockFragmentActivity {
+
+
+    private static final String TAG = PassCodeActivity.class.getSimpleName();
+
+    public final static String ACTION_ENABLE = PassCodeActivity.class.getCanonicalName() + ".ENABLE";
+    public final static String ACTION_DISABLE = PassCodeActivity.class.getCanonicalName() + ".DISABLE";
+    public final static String ACTION_REQUEST = PassCodeActivity.class.getCanonicalName()  + ".REQUEST";
+
+    private Button mBCancel;
+    private TextView mPassCodeHdr;
+    private TextView mPassCodeHdrExplanation;
+    private EditText[] mPassCodeEditTexts = new EditText[4];
+    
+    private String [] mPassCodeDigits = {"","","",""};
+    private boolean mConfirmingPassCode = false;
+
+    private boolean mBChange = true; // to control that only one blocks jump
+
+
+    /**
+     * Initializes the activity.
+     *
+     * An intent with a valid ACTION is expected; if none is found, an {@link IllegalArgumentException} will be thrown.
+     *
+     * @param savedInstanceState    Previously saved state - irrelevant in this case
+     */
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.passcodelock);
+        
+        mBCancel = (Button) findViewById(R.id.cancel);
+        mPassCodeHdr = (TextView) findViewById(R.id.header);
+        mPassCodeHdrExplanation = (TextView) findViewById(R.id.explanation);
+        mPassCodeEditTexts[0] = (EditText) findViewById(R.id.txt0);
+        mPassCodeEditTexts[0].requestFocus();
+        getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        mPassCodeEditTexts[1] = (EditText) findViewById(R.id.txt1);
+        mPassCodeEditTexts[2] = (EditText) findViewById(R.id.txt2);
+        mPassCodeEditTexts[3] = (EditText) findViewById(R.id.txt3);
+
+        if (ACTION_REQUEST.equals(getIntent().getAction())) {
+            /// this is a pass code request; the user has to input the right value
+            mPassCodeHdr.setText(R.string.pass_code_enter_pass_code);
+            mPassCodeHdrExplanation.setVisibility(View.INVISIBLE);
+            setCancelButtonEnabled(false);      // no option to cancel
+
+        } else if (ACTION_ENABLE.equals(getIntent().getAction())) {
+            /// pass code preference has just been activated in Preferences; will receive and confirm pass code value
+            mPassCodeHdr.setText(R.string.pass_code_configure_your_pass_code);
+            //mPassCodeHdr.setText(R.string.pass_code_enter_pass_code); // TODO choose a header, check iOS
+            mPassCodeHdrExplanation.setVisibility(View.VISIBLE);
+            setCancelButtonEnabled(true);
+
+        } else if (ACTION_DISABLE.equals(getIntent().getAction())) {
+            /// pass code preference has just been disabled in Preferences;
+            // will confirm user knows pass code, then remove it
+            mPassCodeHdr.setText(R.string.pass_code_remove_your_pass_code);
+            mPassCodeHdrExplanation.setVisibility(View.INVISIBLE);
+            setCancelButtonEnabled(true);
+
+        } else {
+            throw new IllegalArgumentException("A valid ACTION is needed in the Intent passed to " + TAG);
+        }
+
+        setTextListeners();
+        
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setIcon(DisplayUtils.getSeasonalIconId());
+    }
+
+
+    /**
+     * Enables or disables the cancel button to allow the user interrupt the ACTION requested to the activity.
+     *
+     * @param enabled       'True' makes the cancel button available, 'false' hides it.
+     */
+    protected void setCancelButtonEnabled(boolean enabled){
+        if(enabled){
+            mBCancel.setVisibility(View.VISIBLE);
+            mBCancel.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    revertActionAndExit();
+                }
+            });
+        } else {
+            mBCancel.setVisibility(View.GONE);
+            mBCancel.setVisibility(View.INVISIBLE);
+            mBCancel.setOnClickListener(null);
+        }
+    }
+
+
+    /**
+     * Binds the appropiate listeners to the input boxes receiving each digit of the pass code.
+     */
+    protected void setTextListeners() {
+    
+         ///  First input field
+        mPassCodeEditTexts[0].addTextChangedListener(new PassCodeDigitTextWatcher(0, false));
+
+
+        /*------------------------------------------------
+         *  SECOND BOX 
+         -------------------------------------------------*/
+        mPassCodeEditTexts[1].addTextChangedListener(new PassCodeDigitTextWatcher(1, false));
+
+        mPassCodeEditTexts[1].setOnKeyListener(new View.OnKeyListener() {
+
+            @Override
+            public boolean onKey(View v, int keyCode, KeyEvent event) {
+                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {  // TODO WIP: event should be used to control what's exactly happening with DEL, not any custom field...
+                    mPassCodeEditTexts[0].setText("");
+                    mPassCodeEditTexts[0].requestFocus();
+                    if (!mConfirmingPassCode)
+                        mPassCodeDigits[0] = "";
+                    mBChange = false;
+
+                } else if (!mBChange) {
+                    mBChange = true;
+                }
+                return false;
+            }
+        });
+
+        mPassCodeEditTexts[1].setOnFocusChangeListener(new View.OnFocusChangeListener() {
+
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                /// TODO WIP: should take advantage of hasFocus to reduce processing
+                if (mPassCodeEditTexts[0].getText().toString().equals("")) {    // TODO WIP validation could be done in a global way, with a single OnFocusChangeListener for all the input fields
+                    mPassCodeEditTexts[0].requestFocus();
+                }
+            }
+        });
+        
+        
+        /*------------------------------------------------
+         *  THIRD BOX
+         -------------------------------------------------*/
+        mPassCodeEditTexts[2].addTextChangedListener(new PassCodeDigitTextWatcher(2, false));
+
+        mPassCodeEditTexts[2].setOnKeyListener(new View.OnKeyListener() {
+
+            @Override
+            public boolean onKey(View v, int keyCode, KeyEvent event) {
+                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
+                    mPassCodeEditTexts[1].requestFocus();
+                    if (!mConfirmingPassCode)
+                        mPassCodeDigits[1] = "";
+                    mPassCodeEditTexts[1].setText("");
+                    mBChange = false;
+
+                } else if (!mBChange) {
+                    mBChange = true;
+
+                }
+                return false;
+            }
+        });
+
+        mPassCodeEditTexts[2].setOnFocusChangeListener(new View.OnFocusChangeListener() {
+
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (mPassCodeEditTexts[0].getText().toString().equals("")) {
+                    mPassCodeEditTexts[0].requestFocus();
+                } else if (mPassCodeEditTexts[1].getText().toString().equals("")) {
+                    mPassCodeEditTexts[1].requestFocus();
+                }
+            }
+        });
+
+
+        /*------------------------------------------------
+         *  FOURTH BOX
+         -------------------------------------------------*/
+        mPassCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true));
+
+        mPassCodeEditTexts[3].setOnKeyListener(new View.OnKeyListener() {
+
+            @Override
+            public boolean onKey(View v, int keyCode, KeyEvent event) {
+                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
+                    mPassCodeEditTexts[2].requestFocus();
+                    if (!mConfirmingPassCode)
+                        mPassCodeDigits[2] = "";
+                    mPassCodeEditTexts[2].setText("");
+                    mBChange = false;
+
+                } else if (!mBChange) {
+                    mBChange = true;
+                }
+                return false;
+            }
+        });
+
+        mPassCodeEditTexts[3].setOnFocusChangeListener(new View.OnFocusChangeListener() {
+
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+
+                if (mPassCodeEditTexts[0].getText().toString().equals("")) {
+                    mPassCodeEditTexts[0].requestFocus();
+                } else if (mPassCodeEditTexts[1].getText().toString().equals("")) {
+                    mPassCodeEditTexts[1].requestFocus();
+                } else if (mPassCodeEditTexts[2].getText().toString().equals("")) {
+                    mPassCodeEditTexts[2].requestFocus();
+                }
+
+            }
+        });
+
+    } // end setTextListener
+
+
+    /**
+     * Processes the pass code entered by the user just after the last digit was in.
+     *
+     * Takes into account the action requested to the activity, the currently saved pass code and the previously
+     * typed pass code, if any.
+     */
+    private void processFullPassCode() {
+        if (ACTION_REQUEST.equals(getIntent().getAction())) {
+            if (checkPassCode()) {
+                /// pass code accepted in request, user is allowed to access the app
+                finish();
+
+            }  else {
+                showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE);
+            }
+
+        } else if (ACTION_DISABLE.equals(getIntent().getAction())) {
+            if (checkPassCode()) {
+                /// pass code accepted when disabling, pass code is removed
+                SharedPreferences.Editor appPrefs = PreferenceManager
+                        .getDefaultSharedPreferences(getApplicationContext()).edit();
+                appPrefs.putBoolean("set_pincode", false);  // TODO remove; this should be unnecessary, was done before entering in the activity
+                appPrefs.commit();
+
+                Toast.makeText(PassCodeActivity.this, R.string.pass_code_removed, Toast.LENGTH_LONG).show();
+                finish();
+
+            } else {
+                showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE);
+            }
+
+        } else if (ACTION_ENABLE.equals(getIntent().getAction())) {
+            /// enabling pass code
+            if (!mConfirmingPassCode) {
+                requestPassCodeConfirmation();
+
+            } else if (confirmPassCode()) {
+                /// confirmed: user typed the same pass code twice
+                savePassCodeAndExit();
+
+            } else {
+                showErrorAndRestart(
+                        R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE
+                );
+            }
+        }
+    }
+
+
+    private void showErrorAndRestart(int errorMessage, int headerMessage, int explanationVisibility) {
+        Arrays.fill(mPassCodeDigits, null);
+        CharSequence errorSeq = getString(errorMessage);
+        Toast.makeText(this, errorSeq, Toast.LENGTH_LONG).show();
+        mPassCodeHdr.setText(headerMessage);                // TODO check if really needed
+        mPassCodeHdrExplanation.setVisibility(explanationVisibility);  // TODO check if really needed
+        clearBoxes();
+    }
+
+
+    /**
+     * Ask to the user for retyping the pass code just entered before saving it as the current pass code.
+     */
+    protected void requestPassCodeConfirmation(){
+        clearBoxes();
+        mPassCodeHdr.setText(R.string.pass_code_reenter_your_pass_code);
+        mPassCodeHdrExplanation.setVisibility(View.INVISIBLE);
+        mConfirmingPassCode = true;
+    }
+
+    /**
+     * Compares pass code entered by the user with the value currently saved in the app.
+     *
+     * @return     'True' if entered pass code equals to the saved one.
+     */
+    protected boolean checkPassCode(){
+        SharedPreferences appPrefs = PreferenceManager
+            .getDefaultSharedPreferences(getApplicationContext());
+
+        String savedPassCodeDigits[] = new String[4];
+        savedPassCodeDigits[0] = appPrefs.getString("PrefPinCode1", null);
+        savedPassCodeDigits[1] = appPrefs.getString("PrefPinCode2", null);
+        savedPassCodeDigits[2] = appPrefs.getString("PrefPinCode3", null);
+        savedPassCodeDigits[3] = appPrefs.getString("PrefPinCode4", null);
+
+        boolean result = true;
+        for (int i = 0; i < mPassCodeDigits.length && result; i++) {
+            result = result && (mPassCodeDigits[i] != null) && mPassCodeDigits[i].equals(savedPassCodeDigits[i]);
+        }
+        return result;
+    }
+
+    /**
+     * Compares pass code retyped by the user in the input fields with the value entered just before.
+     *
+     * @return     'True' if retyped pass code equals to the entered before.
+     */
+    protected boolean confirmPassCode(){
+        mConfirmingPassCode = false;
+
+        boolean result = true;
+        for (int i = 0; i < mPassCodeEditTexts.length && result; i++) {
+            result = result && ((mPassCodeEditTexts[i].getText().toString()).equals(mPassCodeDigits[i]));
+        }
+        return result;
+    }
+
+    /**
+     * Sets the input fields to empty strings and puts the focus on the first one.
+     */
+    protected void clearBoxes(){
+        for (int i=0; i < mPassCodeEditTexts.length; i++) {
+            mPassCodeEditTexts[i].setText("");
+        }
+        mPassCodeEditTexts[0].requestFocus();
+    }
+
+    /**
+     * Overrides click on the BACK arrow to correctly cancel ACTION_ENABLE or ACTION_DISABLE, while preventing
+     * than ACTION_REQUEST may be worked around.
+     *
+     * @param keyCode       Key code of the key that triggered the down event.
+     * @param event         Event triggered.
+     * @return              'True' when the key event was processed by this method.
+     */
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event){
+        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount()== 0){
+            if (ACTION_ENABLE.equals(getIntent().getAction()) || ACTION_DISABLE.equals(getIntent().getAction())) {
+                revertActionAndExit();
+            }
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    /**
+     * Saves the pass code input by the user as the current pass code.
+     */
+    protected void savePassCodeAndExit() {
+        SharedPreferences.Editor appPrefs = PreferenceManager
+                .getDefaultSharedPreferences(getApplicationContext()).edit();
+        
+        appPrefs.putString("PrefPinCode1", mPassCodeDigits[0]);
+        appPrefs.putString("PrefPinCode2", mPassCodeDigits[1]);
+        appPrefs.putString("PrefPinCode3", mPassCodeDigits[2]);
+        appPrefs.putString("PrefPinCode4", mPassCodeDigits[3]);
+        appPrefs.putBoolean("set_pincode", true);    /// TODO remove; unnecessary, Preferences did it before entering here
+        appPrefs.commit();
+
+        Toast.makeText(this, R.string.pass_code_stored, Toast.LENGTH_LONG).show();
+        finish();
+    }
+
+    /**
+     * Cancellation of ACTION_ENABLE or ACTION_DISABLE; reverts the enable or disable action done by
+     * {@link Preferences}, then finishes.
+     */
+    protected void revertActionAndExit() {
+        SharedPreferences.Editor appPrefsE = PreferenceManager
+                .getDefaultSharedPreferences(getApplicationContext()).edit();
+
+        SharedPreferences appPrefs = PreferenceManager
+                .getDefaultSharedPreferences(getApplicationContext());
+
+        boolean state = appPrefs.getBoolean("set_pincode", false);
+        appPrefsE.putBoolean("set_pincode", !state);
+        // TODO WIP: this is reverting the value of the preference because it was changed BEFORE entering
+        // TODO         in this activity; was the PreferenceCheckBox in the caller who did it
+        appPrefsE.commit();
+        finish();
+    }
+
+
+    private class PassCodeDigitTextWatcher implements TextWatcher {
+
+        private int mIndex = -1;
+        private boolean mLastOne = false;
+
+        /**
+         * Constructor
+         *
+         * @param index         Position in the pass code of the input field that will be bound to this watcher.
+         * @param lastOne       'True' means that watcher corresponds to the last position of the pass code.
+         */
+        public PassCodeDigitTextWatcher(int index, boolean lastOne) {
+            mIndex = index;
+            mLastOne  = lastOne;
+            if (mIndex < 0) {
+                throw new IllegalArgumentException(
+                        "Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() + " constructor"
+                );
+            }
+        }
+
+        private int next() {
+            return mLastOne ? 0 : mIndex + 1;
+        }
+
+        /**
+         * Performs several actions when the user types a digit in an input field:
+         *  - saves the input digit to the state of the activity; this will allow retyping the pass code to confirm it.
+         *  - moves the focus automatically to the next field
+         *  - for the last field, triggers the processing of the full pass code
+         *
+         * @param s
+         */
+        @Override
+        public void afterTextChanged(Editable s) {
+            if (s.length() > 0) {
+                if (!mConfirmingPassCode) {
+                    mPassCodeDigits[mIndex] = mPassCodeEditTexts[mIndex].getText().toString();
+                }
+                mPassCodeEditTexts[next()].requestFocus();
+
+                if (mLastOne) {
+                    processFullPassCode();
+                }
+
+            } else {
+                Log_OC.d(TAG, "Text box " + mIndex + " was cleaned");
+            }
+        }
+
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            // nothing to do
+        }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+            // nothing to do
+        }
+
+    }
+
+
+}

+ 0 - 644
src/com/owncloud/android/ui/activity/PinCodeActivity.java

@@ -1,644 +0,0 @@
-/**
- *   ownCloud Android client application
- *
- *   Copyright (C) 2011 Bartek Przybylski
- *   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.ui.activity;
-
-import java.util.Arrays;
-
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.SherlockFragmentActivity;
-import com.owncloud.android.R;
-import com.owncloud.android.utils.DisplayUtils;
-
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnKeyListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
-
-public class PinCodeActivity extends SherlockFragmentActivity {
-
-  
-    public final static String EXTRA_ACTIVITY = "com.owncloud.android.ui.activity.PinCodeActivity.ACTIVITY";
-    public final static String EXTRA_NEW_STATE = "com.owncloud.android.ui.activity.PinCodeActivity.NEW_STATE";
-    
-    private Button mBCancel;
-    private TextView mPinHdr;
-    private TextView mPinHdrExplanation;
-    private EditText mText1;
-    private EditText mText2;
-    private EditText mText3;
-    private EditText mText4;
-    
-    private String [] mTempText ={"","","",""};
-    
-    private String mActivity;
-    
-    private boolean mConfirmingPinCode = false;
-    private boolean mPinCodeChecked = false;
-    private boolean mNewPasswordEntered = false;
-    private boolean mBChange = true; // to control that only one blocks jump
-    //private int mTCounter ; // Count the number of attempts an user could introduce the PIN code
-
-    
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.pincodelock); 
-        
-        Intent intent = getIntent();
-        mActivity = intent.getStringExtra(EXTRA_ACTIVITY);
-     
-        mBCancel = (Button) findViewById(R.id.cancel);
-        mPinHdr = (TextView) findViewById(R.id.pinHdr);
-        mPinHdrExplanation = (TextView) findViewById(R.id.pinHdrExpl);
-        mText1 = (EditText) findViewById(R.id.txt1);
-        mText1.requestFocus();
-        getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
-        mText2 = (EditText) findViewById(R.id.txt2);
-        mText3 = (EditText) findViewById(R.id.txt3);
-        mText4 = (EditText) findViewById(R.id.txt4);
-        
-        SharedPreferences appPrefs = PreferenceManager
-                .getDefaultSharedPreferences(getApplicationContext());
-        
- 
-        // Not PIN Code defined yet.
-        // In a previous version settings is allow from start
-        if ( (appPrefs.getString("PrefPinCode1", null) == null ) ){
-            setChangePincodeView(true);
-            mPinCodeChecked = true; 
-            mNewPasswordEntered = true;
-            
-        }else{ 
-            
-            if (appPrefs.getBoolean("set_pincode", false)){
-               // pincode activated
-               if (mActivity.equals("preferences")){
-                // PIN has been activated yet
-                 mPinHdr.setText(R.string.pincode_configure_your_pin);
-                 mPinHdrExplanation.setVisibility(View.VISIBLE);
-                 mPinCodeChecked = true ; // No need to check it 
-                 setChangePincodeView(true);
-               }else{
-                // PIN active
-                 mBCancel.setVisibility(View.INVISIBLE);
-                 mBCancel.setVisibility(View.GONE);
-                 mPinHdr.setText(R.string.pincode_enter_pin_code);
-                 mPinHdrExplanation.setVisibility(View.INVISIBLE);
-                 setChangePincodeView(false);
-              }
-            
-           }else {
-            // pincode removal
-              mPinHdr.setText(R.string.pincode_remove_your_pincode);
-              mPinHdrExplanation.setVisibility(View.INVISIBLE);
-              mPinCodeChecked = false;
-              setChangePincodeView(true); 
-           }
-           
-        }
-        setTextListeners();
-        
-        ActionBar actionBar = getSupportActionBar();
-        actionBar.setIcon(DisplayUtils.getSeasonalIconId());
-    }
-    
-
-     
-    protected void setInitVars(){
-        mConfirmingPinCode = false;
-        mPinCodeChecked = false;
-        mNewPasswordEntered = false;
-
-    }
-    
-    protected void setInitView(){
-        mBCancel.setVisibility(View.INVISIBLE);
-        mBCancel.setVisibility(View.GONE);
-        mPinHdr.setText(R.string.pincode_enter_pin_code);
-        mPinHdrExplanation.setVisibility(View.INVISIBLE);
-    }
-    
-   
-    protected void setChangePincodeView(boolean state){
-       
-        if(state){
-        mBCancel.setVisibility(View.VISIBLE);
-        mBCancel.setOnClickListener(new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            
-            SharedPreferences.Editor appPrefsE = PreferenceManager
-                    .getDefaultSharedPreferences(getApplicationContext()).edit();
-            
-            SharedPreferences appPrefs = PreferenceManager
-                    .getDefaultSharedPreferences(getApplicationContext());
-            
-            boolean state = appPrefs.getBoolean("set_pincode", false);
-            appPrefsE.putBoolean("set_pincode",!state); 
-            appPrefsE.commit();
-            setInitVars();
-            finish();
-            }
-        });
-        }  
-    
-    }
-    
-    
-    
-    /*
-     *  
-     */
-    protected void setTextListeners(){
-    
-        /*------------------------------------------------
-         *  FIRST BOX
-         -------------------------------------------------*/
-        
-        mText1.addTextChangedListener(new TextWatcher() {
-
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before,
-                    int count) {
-            }
-
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count,
-                    int after) {
-            }
-
-            @Override
-            public void afterTextChanged(Editable s) {
-                if (s.length() > 0) {
-                    if (!mConfirmingPinCode){
-                       mTempText[0] = mText1.getText().toString();
-                       
-                    }
-                    mText2.requestFocus();
-                 }
-            }
-        });
-        
-        
-
-        /*------------------------------------------------
-         *  SECOND BOX 
-         -------------------------------------------------*/
-        mText2.addTextChangedListener(new TextWatcher() {
-
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before,
-                    int count) {
-            }
-
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count,
-                    int after) {
-            }
-
-            @Override
-            public void afterTextChanged(Editable s) {
-                if (s.length() > 0) {
-                    if (!mConfirmingPinCode){
-                        mTempText[1] = mText2.getText().toString();
-                    }
-                    
-                    mText3.requestFocus();
-                }
-            }
-        });
- 
-        mText2.setOnKeyListener(new OnKeyListener() {
-
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
-
-                    mText1.setText("");
-                    mText1.requestFocus();
-                    if (!mConfirmingPinCode)
-                       mTempText[0] = "";
-                    mBChange= false;
-                
-                }else if(!mBChange){
-                    mBChange=true;
-                    
-                }
-                return false;
-            }
-        });        
- 
-        mText2.setOnFocusChangeListener(new OnFocusChangeListener() {
-               
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                mText2.setCursorVisible(true);
-                if (mText1.getText().toString().equals("")){
-                    mText2.setSelected(false);
-                    mText2.setCursorVisible(false);
-                    mText1.requestFocus(); 
-                    mText1.setSelected(true);
-                    mText1.setSelection(0);
-                }
-                
-            }
-        });
-        
-        
-        /*------------------------------------------------
-         *  THIRD BOX
-         -------------------------------------------------*/
-        mText3.addTextChangedListener(new TextWatcher() {
-
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before,
-                    int count) {
-            }
-
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count,
-                    int after) {
-            }
-
-            @Override
-            public void afterTextChanged(Editable s) {
-                if (s.length() > 0) {
-                    if (!mConfirmingPinCode){
-                        mTempText[2] = mText3.getText().toString();
-                    }
-                    mText4.requestFocus();
-                }
-            }
-        });
-        
-        mText3.setOnKeyListener(new OnKeyListener() {
-
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
-                    mText2.requestFocus();
-                    if (!mConfirmingPinCode)
-                        mTempText[1] = "";
-                    mText2.setText("");
-                    mBChange= false;
-                    
-                }else if(!mBChange){
-                    mBChange=true;                        
-                    
-                }
-                return false;
-            }
-        });
-        
-        mText3.setOnFocusChangeListener(new OnFocusChangeListener() {
-            
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                mText3.setCursorVisible(true);
-                if (mText1.getText().toString().equals("")){
-                    mText3.setSelected(false);
-                    mText3.setCursorVisible(false);
-                    mText1.requestFocus();
-                    mText1.setSelected(true);
-                    mText1.setSelection(0);
-                }else if (mText2.getText().toString().equals("")){
-                    mText3.setSelected(false);
-                    mText3.setCursorVisible(false);
-                    mText2.requestFocus();
-                    mText2.setSelected(true);
-                    mText2.setSelection(0);
-                }
-                
-            }
-        });
-        
-        /*------------------------------------------------
-         *  FOURTH BOX
-         -------------------------------------------------*/
-        mText4.addTextChangedListener(new TextWatcher() {
-
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before,
-                    int count) {
-            }
-
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count,
-                    int after) {
-            }
-
-            @Override
-            public void afterTextChanged(Editable s) {
-                if (s.length() > 0) {
-                    
-                    if (!mConfirmingPinCode){
-                       mTempText[3] = mText4.getText().toString();
-                    }
-                    mText1.requestFocus();
-
-                    if (!mPinCodeChecked){
-                        mPinCodeChecked = checkPincode();
-                    }
-                    
-                    if (mPinCodeChecked && 
-                            ( mActivity.equals("FileDisplayActivity") || mActivity.equals("PreviewImageActivity") ) ){
-                        finish();
-                    } else if (mPinCodeChecked){
-                        
-                        Intent intent = getIntent();
-                        String newState = intent.getStringExtra(EXTRA_NEW_STATE);
-                        
-                        if (newState.equals("false")){
-                            SharedPreferences.Editor appPrefs = PreferenceManager
-                                    .getDefaultSharedPreferences(getApplicationContext()).edit();
-                            appPrefs.putBoolean("set_pincode",false);
-                            appPrefs.commit();
-                            
-                            setInitVars();
-                            pinCodeEnd(false);
-                            
-                        }else{
-                        
-                            if (!mConfirmingPinCode){
-                                pinCodeChangeRequest();
-                             
-                            } else {
-                                confirmPincode();
-                            }
-                        }
-                   
-                        
-                    }    
-                }
-            }
-        });
-
-        
-        
-        mText4.setOnKeyListener(new OnKeyListener() {
-
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
-                    mText3.requestFocus();
-                    if (!mConfirmingPinCode)
-                        mTempText[2]="";
-                    mText3.setText("");
-                    mBChange= false;
-                    
-                }else if(!mBChange){
-                    mBChange=true;    
-                }
-                return false;
-            }
-        });
-        
-       mText4.setOnFocusChangeListener(new OnFocusChangeListener() {
-            
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                mText4.setCursorVisible(true);
-                
-                if (mText1.getText().toString().equals("")){
-                    mText4.setSelected(false);
-                    mText4.setCursorVisible(false);
-                    mText1.requestFocus();
-                    mText1.setSelected(true);
-                    mText1.setSelection(0);
-                }else if (mText2.getText().toString().equals("")){
-                    mText4.setSelected(false);
-                    mText4.setCursorVisible(false);
-                    mText2.requestFocus();
-                    mText2.setSelected(true);
-                    mText2.setSelection(0);
-                }else if (mText3.getText().toString().equals("")){
-                    mText4.setSelected(false);
-                    mText4.setCursorVisible(false);
-                    mText3.requestFocus();
-                    mText3.setSelected(true);
-                    mText3.setSelection(0);
-                }
-                
-            }
-        });
-        
-        
-        
-    } // end setTextListener
-    
-    
-    protected void pinCodeChangeRequest(){
-    
-        clearBoxes(); 
-        mPinHdr.setText(R.string.pincode_reenter_your_pincode); 
-        mPinHdrExplanation.setVisibility(View.INVISIBLE);        
-        mConfirmingPinCode =true;
-        
-    }
-    
-    
-    protected boolean checkPincode(){
-        
-        
-        SharedPreferences appPrefs = PreferenceManager
-                .getDefaultSharedPreferences(getApplicationContext());
-        
-       String pText1 = appPrefs.getString("PrefPinCode1", null);
-        String pText2 = appPrefs.getString("PrefPinCode2", null);
-        String pText3 = appPrefs.getString("PrefPinCode3", null);
-        String pText4 = appPrefs.getString("PrefPinCode4", null);
-
-        if ( mTempText[0].equals(pText1) && 
-             mTempText[1].equals(pText2) &&
-             mTempText[2].equals(pText3) &&
-             mTempText[3].equals(pText4) ) {
-            
-            return true;
-        
-        
-        }else {
-            Arrays.fill(mTempText, null);
-            AlertDialog aDialog = new AlertDialog.Builder(this).create();
-            CharSequence errorSeq = getString(R.string.common_error);
-            aDialog.setTitle(errorSeq);
-            CharSequence cseq = getString(R.string.pincode_wrong);
-            aDialog.setMessage(cseq);
-            CharSequence okSeq = getString(R.string.common_ok);
-            aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){
-
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                   return; 
-                }
-                
-            });
-            aDialog.show();
-            clearBoxes(); 
-            mPinHdr.setText(R.string.pincode_enter_pin_code);
-            mPinHdrExplanation.setVisibility(View.INVISIBLE);
-            mNewPasswordEntered = true;
-            mConfirmingPinCode = false;
-            
-        }
-     
-        
-        return false;
-    }
-    
-    protected void confirmPincode(){
-        
-        mConfirmingPinCode = false;
-        
-        String rText1 = mText1.getText().toString();
-        String rText2 = mText2.getText().toString();
-        String rText3 = mText3.getText().toString();
-        String rText4 = mText4.getText().toString();
-        
-        if ( mTempText[0].equals(rText1) && 
-             mTempText[1].equals(rText2) &&
-             mTempText[2].equals(rText3) &&
-             mTempText[3].equals(rText4) ) {
-                        
-            savePincodeAndExit();
-            
-        } else {
-            
-            Arrays.fill(mTempText, null);
-            AlertDialog aDialog = new AlertDialog.Builder(this).create();
-            CharSequence errorSeq = getString(R.string.common_error);
-            aDialog.setTitle(errorSeq);
-            CharSequence cseq = getString(R.string.pincode_mismatch);
-            aDialog.setMessage(cseq);
-            CharSequence okSeq = getString(R.string.common_ok);
-            aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){
-
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                   return; 
-                }
-                
-            });
-            aDialog.show();
-            mPinHdr.setText(R.string.pincode_configure_your_pin);
-            mPinHdrExplanation.setVisibility(View.VISIBLE);
-            clearBoxes();
-        }
-    
-    }
-   
-    
-    protected void pinCodeEnd(boolean state){
-        AlertDialog aDialog = new AlertDialog.Builder(this).create();
-        
-        if (state){
-            CharSequence saveSeq = getString(R.string.common_save_exit);
-            aDialog.setTitle(saveSeq);
-            CharSequence cseq = getString(R.string.pincode_stored);
-            aDialog.setMessage(cseq);
-            
-        }else{
-            CharSequence saveSeq = getString(R.string.common_save_exit);
-            aDialog.setTitle(saveSeq);
-            CharSequence cseq = getString(R.string.pincode_removed);
-            aDialog.setMessage(cseq);
-            
-        }
-        CharSequence okSeq = getString(R.string.common_ok);
-        aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){
-
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                finish();
-                return; 
-            }
-            
-        });
-        aDialog.show(); 
-    }
-    
-    protected void savePincodeAndExit(){
-        SharedPreferences.Editor appPrefs = PreferenceManager
-                .getDefaultSharedPreferences(getApplicationContext()).edit();
-        
-        appPrefs.putString("PrefPinCode1", mTempText[0]);
-        appPrefs.putString("PrefPinCode2",mTempText[1]);
-        appPrefs.putString("PrefPinCode3", mTempText[2]);
-        appPrefs.putString("PrefPinCode4", mTempText[3]);
-        appPrefs.putBoolean("set_pincode",true);
-        appPrefs.commit();
-        
-        pinCodeEnd(true);
-        
-        
-        
-    }
-    
-    
-    protected void clearBoxes(){
-        
-        mText1.setText("");
-        mText2.setText("");
-        mText3.setText("");
-        mText4.setText("");
-        mText1.requestFocus(); 
-    }
-    
-    
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event){
-        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount()== 0){
-            
-            if (mActivity.equals("preferences")){
-                SharedPreferences.Editor appPrefsE = PreferenceManager
-            
-                    .getDefaultSharedPreferences(getApplicationContext()).edit();
-            
-                SharedPreferences appPrefs = PreferenceManager
-                    .getDefaultSharedPreferences(getApplicationContext());
-            
-                boolean state = appPrefs.getBoolean("set_pincode", false);
-                appPrefsE.putBoolean("set_pincode",!state); 
-                appPrefsE.commit();
-                setInitVars();
-                finish();
-            }
-            return true; 
-            
-        }
-        
-        return super.onKeyDown(keyCode, event);
-    }
-    
-   
-
-    
-            
-}

+ 5 - 10
src/com/owncloud/android/ui/activity/Preferences.java

@@ -69,8 +69,6 @@ import com.owncloud.android.services.OperationsService;
 import com.owncloud.android.ui.RadioButtonPreference;
 import com.owncloud.android.ui.RadioButtonPreference;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.DisplayUtils;
 
 
-import java.io.File;
-
 
 
 /**
 /**
  * An Activity that allows the user to change the application's settings.
  * An Activity that allows the user to change the application's settings.
@@ -168,9 +166,11 @@ public class Preferences extends SherlockPreferenceActivity
             pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
             pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
                 @Override
                 @Override
                 public boolean onPreferenceChange(Preference preference, Object newValue) {
                 public boolean onPreferenceChange(Preference preference, Object newValue) {
-                    Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
-                    i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences");
-                    i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString());
+                    Intent i = new Intent(getApplicationContext(), PassCodeActivity.class);
+                    Boolean enable = (Boolean) newValue;
+                    i.setAction(
+                            enable.booleanValue() ? PassCodeActivity.ACTION_ENABLE : PassCodeActivity.ACTION_DISABLE
+                    );
                     startActivity(i);
                     startActivity(i);
                     
                     
                     return true;
                     return true;
@@ -395,11 +395,6 @@ public class Preferences extends SherlockPreferenceActivity
         }
         }
     }
     }
 
 
-    @Override
-    protected void onPause() {
-        super.onPause();
-    }
-
     @Override
     @Override
     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
 
 

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

@@ -2,6 +2,7 @@
  *   ownCloud Android client application
  *   ownCloud Android client application
  *
  *
  *   @author Bartek Przybylski
  *   @author Bartek Przybylski
+ *   @author masensio
  *   Copyright (C) 2012  Bartek Przybylski
  *   Copyright (C) 2012  Bartek Przybylski
  *   Copyright (C) 2015 ownCloud Inc.
  *   Copyright (C) 2015 ownCloud Inc.
  *
  *
@@ -29,6 +30,7 @@ import java.util.List;
 import java.util.Stack;
 import java.util.Stack;
 import java.util.Vector;
 import java.util.Vector;
 
 
+
 import android.accounts.Account;
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountManager;
 import android.app.AlertDialog;
 import android.app.AlertDialog;
@@ -47,9 +49,13 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.Parcelable;
 import android.preference.PreferenceManager;
 import android.preference.PreferenceManager;
+import android.provider.MediaStore;
 import android.provider.MediaStore.Audio;
 import android.provider.MediaStore.Audio;
 import android.provider.MediaStore.Images;
 import android.provider.MediaStore.Images;
 import android.provider.MediaStore.Video;
 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.view.View;
 import android.widget.AdapterView;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 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.lib.common.utils.Log_OC;
 import com.owncloud.android.operations.CreateFolderOperation;
 import com.owncloud.android.operations.CreateFolderOperation;
 import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
 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.DisplayUtils;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 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.
  * This can be used to upload things to an ownCloud instance.
  */
  */
 public class Uploader extends FileActivity
 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();
     private static final String TAG = Uploader.class.getSimpleName();
 
 
@@ -90,6 +99,10 @@ public class Uploader extends FileActivity
     private String mUploadPath;
     private String mUploadPath;
     private OCFile mFile;
     private OCFile mFile;
     private boolean mAccountSelected;
     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_NO_ACCOUNT = 0;
     private final static int DIALOG_WAITING = 1;
     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_PARENTS = "PARENTS";
     private final static String KEY_FILE = "FILE";
     private final static String KEY_FILE = "FILE";
     private final static String KEY_ACCOUNT_SELECTED = "ACCOUNT_SELECTED";
     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
     @Override
     protected void onCreate(Bundle savedInstanceState) {
     protected void onCreate(Bundle savedInstanceState) {
@@ -109,13 +127,27 @@ public class Uploader extends FileActivity
         if (savedInstanceState == null) {
         if (savedInstanceState == null) {
             mParents = new Stack<String>();
             mParents = new Stack<String>();
             mAccountSelected = false;
             mAccountSelected = false;
+            mAccountSelectionShowing = false;
+            mNumCacheFile = 0;
+
+            // ArrayList for files with path in private storage
+            mRemoteCacheData = new ArrayList<String>();
         } else {
         } else {
             mParents = (Stack<String>) savedInstanceState.getSerializable(KEY_PARENTS);
             mParents = (Stack<String>) savedInstanceState.getSerializable(KEY_PARENTS);
             mFile = savedInstanceState.getParcelable(KEY_FILE);
             mFile = savedInstanceState.getParcelable(KEY_FILE);
             mAccountSelected = savedInstanceState.getBoolean(KEY_ACCOUNT_SELECTED);
             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);
         super.onCreate(savedInstanceState);
 
 
+        if (mAccountSelected) {
+            setAccount((Account) savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT));
+        }
+
+
         ActionBar actionBar = getSupportActionBar();
         ActionBar actionBar = getSupportActionBar();
         actionBar.setIcon(DisplayUtils.getSeasonalIconId());
         actionBar.setIcon(DisplayUtils.getSeasonalIconId());
 
 
@@ -129,9 +161,10 @@ public class Uploader extends FileActivity
             if (accounts.length == 0) {
             if (accounts.length == 0) {
                 Log_OC.i(TAG, "No ownCloud account is available");
                 Log_OC.i(TAG, "No ownCloud account is available");
                 showDialog(DIALOG_NO_ACCOUNT);
                 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");
                 Log_OC.i(TAG, "More than one ownCloud is available");
                 showDialog(DIALOG_MULTIPLE_ACCOUNT);
                 showDialog(DIALOG_MULTIPLE_ACCOUNT);
+                mAccountSelectionShowing = true;
             } else {
             } else {
                 if (!savedAccount) {
                 if (!savedAccount) {
                     setAccount(accounts[0]);
                     setAccount(accounts[0]);
@@ -160,6 +193,10 @@ public class Uploader extends FileActivity
         //outState.putParcelable(KEY_ACCOUNT, mAccount);
         //outState.putParcelable(KEY_ACCOUNT, mAccount);
         outState.putParcelable(KEY_FILE, mFile);
         outState.putParcelable(KEY_FILE, mFile);
         outState.putBoolean(KEY_ACCOUNT_SELECTED, mAccountSelected);
         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");
         Log_OC.d(TAG, "onSaveInstanceState() end");
     }
     }
@@ -225,12 +262,14 @@ public class Uploader extends FileActivity
                     onAccountSet(mAccountWasRestored);
                     onAccountSet(mAccountWasRestored);
                     dialog.dismiss();
                     dialog.dismiss();
                     mAccountSelected = true;
                     mAccountSelected = true;
+                    mAccountSelectionShowing = false;
                 }
                 }
             });
             });
             builder.setCancelable(true);
             builder.setCancelable(true);
             builder.setOnCancelListener(new OnCancelListener() {
             builder.setOnCancelListener(new OnCancelListener() {
                 @Override
                 @Override
                 public void onCancel(DialogInterface dialog) {
                 public void onCancel(DialogInterface dialog) {
+                    mAccountSelectionShowing = false;
                     dialog.cancel();
                     dialog.cancel();
                     finish();
                     finish();
                 }
                 }
@@ -366,7 +405,7 @@ public class Uploader extends FileActivity
         actionBar.setHomeButtonEnabled(notRoot);
         actionBar.setHomeButtonEnabled(notRoot);
 
 
         String full_path = generatePath(mParents);
         String full_path = generatePath(mParents);
-        
+
         Log_OC.d(TAG, "Populating view with content of : " + full_path);
         Log_OC.d(TAG, "Populating view with content of : " + full_path);
 
 
         mFile = getStorageManager().getFileByPath(full_path);
         mFile = getStorageManager().getFileByPath(full_path);
@@ -421,6 +460,7 @@ public class Uploader extends FileActivity
     public void uploadFiles() {
     public void uploadFiles() {
         try {
         try {
 
 
+            // ArrayList for files with path in external storage
             ArrayList<String> local = new ArrayList<String>();
             ArrayList<String> local = new ArrayList<String>();
             ArrayList<String> remote = new ArrayList<String>();
             ArrayList<String> remote = new ArrayList<String>();
             
             
@@ -428,101 +468,106 @@ public class Uploader extends FileActivity
             for (Parcelable mStream : mStreamsToUpload) {
             for (Parcelable mStream : mStreamsToUpload) {
                 
                 
                 Uri uri = (Uri) mStream;
                 Uri uri = (Uri) mStream;
-                if (uri !=null) {
+                String data = null;
+                String filePath = "";
+
+                if (uri != null) {
                     if (uri.getScheme().equals("content")) {
                     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.DISPLAY_NAME, Video.Media.MIME_TYPE,
                                    Video.Media.SIZE, Video.Media.DATE_MODIFIED };
                                    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);
                                    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.DISPLAY_NAME, Audio.Media.MIME_TYPE,
                                    Audio.Media.SIZE };
                                    Audio.Media.SIZE };
-                           Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
+                            Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
                                    null, 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")) {
                     } 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")) {
                         if (filePath.contains("mnt")) {
                            String splitedFilePath[] = filePath.split("/mnt");
                            String splitedFilePath[] = filePath.split("/mnt");
                            filePath = splitedFilePath[1];
                            filePath = splitedFilePath[1];
                         }
                         }
                         final File file = new File(filePath);
                         final File file = new File(filePath);
-                        local.add(file.getAbsolutePath());
-                        remote.add(mUploadPath + file.getName());
+                        data = file.getAbsolutePath();
+                        filePath = mUploadPath + file.getName();
                     }
                     }
                     else {
                     else {
                         throw new SecurityException();
                         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 {
                 else {
                     throw new SecurityException();
                     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) {
         } catch (SecurityException e) {
@@ -588,16 +633,15 @@ public class Uploader extends FileActivity
         // "/" equals root-directory
         // "/" equals root-directory
         if(last_path.equals("/")) {
         if(last_path.equals("/")) {
             mParents.add("");
             mParents.add("");
-        }
-        else{
+        } else{
             String[] dir_names = last_path.split("/");
             String[] dir_names = last_path.split("/");
             for (String dir : dir_names)
             for (String dir : dir_names)
                 mParents.add(dir);
                 mParents.add(dir);
         }
         }
         //Make sure that path still exists, if it doesn't pop the stack and try the previous path
         //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) {
     public boolean onOptionsItemSelected(MenuItem item) {
         boolean retval = true;
         boolean retval = true;
         switch (item.getItemId()) {
         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;
         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();
+        }
+    }
 }
 }

+ 7 - 29
src/com/owncloud/android/ui/preview/PreviewImageActivity.java

@@ -26,13 +26,11 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.ServiceConnection;
-import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Message;
-import android.preference.PreferenceManager;
 import android.support.v4.view.ViewPager;
 import android.support.v4.view.ViewPager;
 import android.view.View;
 import android.view.View;
 
 
@@ -58,7 +56,6 @@ import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.UnshareLinkOperation;
 import com.owncloud.android.operations.UnshareLinkOperation;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.activity.PinCodeActivity;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.DisplayUtils;
 
 
@@ -90,7 +87,7 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
     
     
     private View mFullScreenAnchorView;
     private View mFullScreenAnchorView;
     
     
-    
+
     @Override
     @Override
     protected void onCreate(Bundle savedInstanceState) {
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         super.onCreate(savedInstanceState);
@@ -102,11 +99,6 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
         actionBar.setIcon(DisplayUtils.getSeasonalIconId());
         actionBar.setIcon(DisplayUtils.getSeasonalIconId());
         actionBar.setDisplayHomeAsUpEnabled(true);
         actionBar.setDisplayHomeAsUpEnabled(true);
         actionBar.hide();
         actionBar.hide();
-        
-        // PIN CODE request
-        if (getIntent().getExtras() != null && savedInstanceState == null && fromNotification()) {
-            requestPinCode();
-        }
 
 
         // Make sure we're running on Honeycomb or higher to use FullScreen and
         // Make sure we're running on Honeycomb or higher to use FullScreen and
         // Immersive Mode
         // Immersive Mode
@@ -323,7 +315,7 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
     @Override
     @Override
     protected void onResume() {
     protected void onResume() {
         super.onResume();
         super.onResume();
-        //Log_OC.e(TAG, "ACTIVITY, ONRESUME");
+
         mDownloadFinishReceiver = new DownloadFinishReceiver();
         mDownloadFinishReceiver = new DownloadFinishReceiver();
         
         
         IntentFilter filter = new IntentFilter(FileDownloader.getDownloadFinishMessage());
         IntentFilter filter = new IntentFilter(FileDownloader.getDownloadFinishMessage());
@@ -333,14 +325,16 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
 
 
     @Override
     @Override
     protected void onPostResume() {
     protected void onPostResume() {
-        //Log_OC.e(TAG, "ACTIVITY, ONPOSTRESUME");
         super.onPostResume();
         super.onPostResume();
     }
     }
     
     
     @Override
     @Override
     public void onPause() {
     public void onPause() {
-        unregisterReceiver(mDownloadFinishReceiver);
-        mDownloadFinishReceiver = null;
+        if (mDownloadFinishReceiver != null){
+            unregisterReceiver(mDownloadFinishReceiver);
+            mDownloadFinishReceiver = null;
+        }
+        
         super.onPause();
         super.onPause();
     }
     }
     
     
@@ -527,21 +521,6 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
             }
             }
         }
         }
     }
     }
-    
-    
-    /**
-     * Launch an intent to request the PIN code to the user before letting him use the app
-     */
-    private void requestPinCode() {
-        boolean pinStart = false;
-        SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
-        pinStart = appPrefs.getBoolean("set_pincode", false);
-        if (pinStart) {
-            Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
-            i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "PreviewImageActivity");
-            startActivity(i);
-        }
-    }
 
 
     @Override
     @Override
     public void onBrowsedDownTo(OCFile folder) {
     public void onBrowsedDownTo(OCFile folder) {
@@ -588,5 +567,4 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
         }
         }
         return false;
         return false;
     }
     }
-
 }
 }

+ 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);
+    }
+}