Przeglądaj źródła

Multiple upload available from the app

David A. Velasco 12 lat temu
rodzic
commit
1ecd2b61c5

+ 4 - 2
AndroidManifest.xml

@@ -17,8 +17,8 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  -->
 <manifest package="com.owncloud.android"
-    android:versionCode="103004"
-    android:versionName="1.3.4" xmlns:android="http://schemas.android.com/apk/res/android">
+    android:versionCode="103005"
+    android:versionName="1.3.5" xmlns:android="http://schemas.android.com/apk/res/android">
 
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
     <uses-permission android:name="android.permission.USE_CREDENTIALS" />
@@ -54,6 +54,8 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <activity android:name=".ui.activity.UploadFilesActivity">
+        </activity>
         <activity android:name=".Uploader" >
             <intent-filter>
                 <action android:name="android.intent.action.SEND" >

+ 1 - 1
res/layout-large-land/files.xml

@@ -32,7 +32,7 @@
             android:id="@+id/fileList"
             android:layout_width="fill_parent"
             android:layout_height="fill_parent"
-            class="com.owncloud.android.ui.fragment.FileListFragment" >
+            class="com.owncloud.android.ui.fragment.OCFileListFragment" >
 
             <!-- Preview: layout=@layout/list_layout -->
         </fragment>

+ 1 - 1
res/layout/files.xml

@@ -27,7 +27,7 @@
         android:id="@+id/fileList"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
-        class="com.owncloud.android.ui.fragment.FileListFragment" >
+        class="com.owncloud.android.ui.fragment.OCFileListFragment" >
 
         <!-- Preview: layout=@layout/list_layout -->
     </fragment>

+ 115 - 116
res/layout/list_layout.xml

@@ -1,116 +1,115 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-  ownCloud Android client application
-
-  Copyright (C) 2012  Bartek Przybylski
-  This program is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation, either version 3 of the License, or
-  (at your option) any later version.
-
-  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"
-    android:id="@+id/ListItemLayout"
-    android:layout_width="fill_parent"
-    android:background="@drawable/list_selector"
-    android:orientation="horizontal"
-    android:layout_height="56dp">
-
-    <FrameLayout
-        android:layout_width="wrap_content"
-        android:layout_height="56dp"
-        android:focusable="false"
-        android:focusableInTouchMode="false">
-        
-        <ImageView
-            android:id="@+id/imageView2"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/local_file_indicator"/>
-
-        <!-- ImageView
-            android:id="@+id/imageView4"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/downloading_file_indicator"/ >
-
-        <ImageView
-            android:id="@+id/imageView5"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/uploading_file_indicator"/ -->
-
-        <ImageView
-            android:id="@+id/imageView1"
-            android:layout_width="20dp"
-            android:layout_height="20dp"
-            android:layout_gravity="center_vertical|center"
-            android:layout_margin="4dp"
-            android:src="@drawable/ic_menu_archive" />
-
-        <ImageView
-            android:id="@+id/imageView3"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="bottom"
-            android:layout_weight=".1"
-            android:maxHeight="15dip"
-            android:src="@drawable/ic_favorite" />
-        
-    </FrameLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical" 
-        android:gravity="center_vertical">
-
-        <TextView
-            android:id="@+id/Filename"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:layout_marginLeft="4dp"
-            android:layout_marginRight="4dp"
-            android:ellipsize="middle"
-            android:singleLine="true"
-            android:text="TextView"
-            android:textColor="#303030"
-            android:textSize="16dip" />
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="4dp"
-            android:layout_marginRight="4dp"
-            android:weightSum="1">
-
-            <TextView
-                android:id="@+id/last_mod"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="TextView"
-                android:layout_weight=".5"
-                android:textSize="12dip"/>
-
-            <TextView
-                android:id="@+id/file_size"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:gravity="right"
-                android:text="TextView"
-                android:layout_weight=".5"
-                android:textSize="12dip"/>
-
-        </LinearLayout>
-
-    </LinearLayout>
-
-</LinearLayout>
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ownCloud Android client application
+
+  Copyright (C) 2012  Bartek Przybylski
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  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"
+    android:id="@+id/ListItemLayout"
+    android:layout_width="fill_parent"
+    android:background="@drawable/list_selector"
+    android:orientation="horizontal"
+    android:layout_height="56dp">
+
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="56dp"
+        android:focusable="false"
+        android:focusableInTouchMode="false">
+        
+        <ImageView
+            android:id="@+id/imageView2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/local_file_indicator"/>
+
+        <ImageView
+            android:id="@+id/imageView1"
+            android:layout_width="20dp"
+            android:layout_height="20dp"
+            android:layout_gravity="center_vertical|center"
+            android:layout_margin="4dp"
+            android:src="@drawable/ic_menu_archive" />
+
+        <ImageView
+            android:id="@+id/imageView3"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom"
+            android:layout_weight=".1"
+            android:maxHeight="15dip"
+            android:src="@drawable/ic_favorite" />
+        
+    </FrameLayout>
+



+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:gravity="center_vertical"
+        android:orientation="vertical" >
+

+        <TextView
+            android:id="@+id/Filename"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginLeft="4dp"
+            android:layout_marginRight="4dp"
+            android:ellipsize="middle"
+            android:singleLine="true"
+            android:text="TextView"
+            android:textColor="#303030"
+            android:textSize="16dip" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="4dp"
+            android:layout_marginRight="4dp"
+            android:weightSum="1">
+
+            <TextView
+                android:id="@+id/last_mod"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="TextView"
+                android:layout_weight=".5"
+                android:textSize="12dip"/>
+
+            <TextView
+                android:id="@+id/file_size"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="right"
+                android:text="TextView"
+                android:layout_weight=".5"
+                android:textSize="12dip"/>
+
+        </LinearLayout>
+
+    </LinearLayout>
+



+    <ImageView
+        android:id="@+id/custom_checkbox"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginLeft="4dp"
+        android:layout_marginRight="4dp"
+        android:gravity=""
+        android:src="@android:drawable/checkbox_off_background" />
+
+</LinearLayout>

+ 53 - 0
res/layout/upload_files_layout.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 
+  ownCloud Android client application
+
+  Copyright (C) 2012  Bartek Przybylski
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  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"
+    android:id="@+id/upload_files_layout"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:background="@color/owncloud_white"
+    android:orientation="vertical" >
+
+    <fragment
+        android:id="@+id/local_files_list"
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        class="com.owncloud.android.ui.fragment.LocalFileListFragment" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="horizontal" >
+
        <Button
+            android:id="@+id/upload_files_btn_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/common_cancel" />
+
		<Button
+		    android:id="@+id/upload_files_btn_upload"
+		    android:layout_width="wrap_content"
+		    android:layout_height="wrap_content"
+		    android:layout_weight="1"
+		    android:text="@string/uploader_btn_upload_text" />
+		
+	</LinearLayout>
+    
+</LinearLayout>

+ 2 - 1
res/values-de/strings.xml

@@ -15,7 +15,8 @@
   <string name="main_tit_accsetup">Konto einrichten</string>
   <string name="main_wrn_accsetup">Auf deinem Gerät sind keine Konten eingerichtet. Bitte erstelle ein Konto, um diese App nutzen zu können.</string>
   <string name="actionbar_sync">Neuladen</string>
-  <string name="actionbar_upload">Datei hochladen</string>
+  <string name="actionbar_upload">Hochladen</string>
+  <string name="actionbar_upload_files">Datei</string>
   <string name="actionbar_mkdir">Verzeichnis erstellen</string>
   <string name="actionbar_search">Suche</string>
   <string name="actionbar_settings">Einstellungen</string>

+ 3 - 1
res/values-es/strings.xml

@@ -15,7 +15,9 @@
   <string name="main_tit_accsetup">Configuración de cuenta</string>
   <string name="main_wrn_accsetup">No hay cuentas de ownCloud en tu dispositivo. Para usar esta aplicación, necesitas crear una.</string>
   <string name="actionbar_sync">Sincronización de cuenta</string>
-  <string name="actionbar_upload">Subir archivo</string>
+  <string name="actionbar_upload">Subir</string>
+  <string name="actionbar_upload_from_apps">Contenido de otras apps</string>
+  <string name="actionbar_upload_files">Ficheros</string>
   <string name="actionbar_mkdir">Crear directorio</string>
   <string name="actionbar_search">Buscar</string>
   <string name="actionbar_settings">Ajustes</string>

+ 5 - 2
res/values/strings.xml

@@ -16,7 +16,9 @@
     <string name="main_wrn_accsetup">There are no ownCloud accounts on your device. In order to use this App, you need to create one.</string>
     
     <string name="actionbar_sync">Refresh</string>
-    <string name="actionbar_upload">Upload file</string>
+    <string name="actionbar_upload">Upload</string>
+    <string name="actionbar_upload_from_apps">Content from other apps</string>
+    <string name="actionbar_upload_files">Files</string>
     <string name="actionbar_mkdir">Create directory</string>
     <string name="actionbar_search">Search</string>
     <string name="actionbar_settings">Settings</string>
@@ -81,7 +83,7 @@
     <string name="delete_account">Delete account</string>
     <string name="create_account">Create account</string>
     
-    <string name="upload_chooser_title">Upload file from &#8230;</string>
+    <string name="upload_chooser_title">Upload from &#8230;</string>
     <string name="uploader_info_dirname">Directory name</string>
 	<string name="uploader_upload_in_progress_ticker">Uploading &#8230;</string>    
 	<string name="uploader_upload_in_progress_content">%1$d%% Uploading %2$s</string>    
@@ -175,4 +177,5 @@
     <string name="wait_a_moment">Wait a moment</string>
 	
     <string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please, try other app to select the file"</string>
+    <string name="filedisplay_no_file_selected">No file was selected</string>
 </resources>

+ 1 - 1
src/com/owncloud/android/ui/FragmentListView.java

@@ -14,7 +14,7 @@ import android.widget.AdapterView.OnItemClickListener;
 
 public class FragmentListView extends SherlockFragment implements
         OnItemClickListener, OnItemLongClickListener {
-    ListView mList;
+    protected ListView mList;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {

+ 121 - 66
src/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -69,7 +69,7 @@ import com.owncloud.android.files.services.FileDownloader;
 import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.syncadapter.FileSyncService;
 import com.owncloud.android.ui.fragment.FileDetailFragment;
-import com.owncloud.android.ui.fragment.FileListFragment;
+import com.owncloud.android.ui.fragment.OCFileListFragment;
 
 import com.owncloud.android.R;
 import eu.alefzero.webdav.WebdavClient;
@@ -82,7 +82,7 @@ import eu.alefzero.webdav.WebdavClient;
  */
 
 public class FileDisplayActivity extends SherlockFragmentActivity implements
-    FileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener {
+    OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener {
     
     private ArrayAdapter<String> mDirectories;
     private OCFile mCurrentDir;
@@ -92,7 +92,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     private UploadFinishReceiver mUploadFinishReceiver;
     private DownloadFinishReceiver mDownloadFinishReceiver;
     
-    private FileListFragment mFileList;
+    private OCFileListFragment mFileList;
     
     private boolean mDualPane;
     
@@ -100,8 +100,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     private static final int DIALOG_CREATE_DIR = 1;
     private static final int DIALOG_ABOUT_APP = 2;
     public static final int DIALOG_SHORT_WAIT = 3;
+    private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 4;
     
-    private static final int ACTION_SELECT_FILE = 1;
+    private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
+    private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
     
     private static final String TAG = "FileDisplayActivity";
     
@@ -142,14 +144,14 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
         OCFile currFile = mCurrentDir;
         while(currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {
-            mDirectories.insert(currFile.getFileName(), 0);
+            mDirectories.add(currFile.getFileName());
             currFile = mStorageManager.getFileById(currFile.getParentId());
         }
-        mDirectories.insert(OCFile.PATH_SEPARATOR, 0);
+        mDirectories.add(OCFile.PATH_SEPARATOR);
 
         // Inflate and set the layout view
         setContentView(R.layout.files);    
-        mFileList = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+        mFileList = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
         mDualPane = (findViewById(R.id.file_details_container) != null);
         if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) {
             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
@@ -228,12 +230,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
                 break;
             }
             case R.id.action_upload: {
-                Intent action = new Intent(Intent.ACTION_GET_CONTENT);
-                action = action.setType("*/*")
-                        .addCategory(Intent.CATEGORY_OPENABLE);
-                startActivityForResult(
-                        Intent.createChooser(action, getString(R.string.upload_chooser_title)),
-                        ACTION_SELECT_FILE);
+                showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE);
                 break;
             }
             case R.id.action_settings: {
@@ -275,58 +272,90 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
      * Called, when the user selected something for uploading
      */
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == ACTION_SELECT_FILE) {
-            if (resultCode == RESULT_OK) {
-                String filepath = null;
-                try {
-                    Uri selectedImageUri = data.getData();
-    
-                    String filemanagerstring = selectedImageUri.getPath();
-                    String selectedImagePath = getPath(selectedImageUri);
-    
-                    if (selectedImagePath != null)
-                        filepath = selectedImagePath;
-                    else
-                        filepath = filemanagerstring;
-                    
-                } catch (Exception e) {
-                    Log.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);
-                    e.printStackTrace();
-                    
-                } finally {
-                    if (filepath == null) {
-                        Log.e("FileDisplay", "Couldnt resolve path to file");
-                        Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);
-                        t.show();
-                        return;
-                    }
-                }
-    
-                Intent i = new Intent(this, FileUploader.class);
-                i.putExtra(FileUploader.KEY_ACCOUNT,
-                        AccountUtils.getCurrentOwnCloudAccount(this));
-                String remotepath = new String();
-                for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
-                    remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
-                }
-                if (!remotepath.endsWith(OCFile.PATH_SEPARATOR))
-                    remotepath += OCFile.PATH_SEPARATOR;
-                remotepath += new File(filepath).getName();
-    
-                i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath);
-                i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath);
-                i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
-                startService(i);
+        
+        if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && resultCode == RESULT_OK) {
+            requestSimpleUpload(data);
+            
+        } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && resultCode == RESULT_OK) {
+            requestMultipleUpload(data);
+            
+        }
+    }
+
+    private void requestMultipleUpload(Intent data) {
+        String[] filePaths = data.getStringArrayExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES);
+        if (filePaths != null) {
+            String[] remotePaths = new String[filePaths.length];
+            String remotePathBase = "";
+            for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
+                remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
+            }
+            if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR))
+                remotePathBase += OCFile.PATH_SEPARATOR;
+            for (int j = 0; j< remotePaths.length; j++) {
+                remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName();
             }
+
+            Intent i = new Intent(this, FileUploader.class);
+            i.putExtra(FileUploader.KEY_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+            i.putExtra(FileUploader.KEY_LOCAL_FILE, filePaths);
+            i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePaths);
+            i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
+            startService(i);
+            
+        } else {
+            Log.d("FileDisplay", "User clicked on 'Update' with no selection");
+            Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG);
+            t.show();
+            return;
+        }
+    }
+
+
+    private void requestSimpleUpload(Intent data) {
+        String filepath = null;
+        try {
+            Uri selectedImageUri = data.getData();
+
+            String filemanagerstring = selectedImageUri.getPath();
+            String selectedImagePath = getPath(selectedImageUri);
+
+            if (selectedImagePath != null)
+                filepath = selectedImagePath;
+            else
+                filepath = filemanagerstring;
+            
+        } catch (Exception e) {
+            Log.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);
+            e.printStackTrace();
             
-        }/* dvelasco: WIP - not working as expected ... yet :)
-             else if (requestCode == ACTION_CREATE_FIRST_ACCOUNT) {
-            if (resultCode != RESULT_OK) {
-                finish();   // the user cancelled the AuthenticatorActivity
+        } finally {
+            if (filepath == null) {
+                Log.e("FileDisplay", "Couldnt resolve path to file");
+                Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);
+                t.show();
+                return;
             }
-        }*/
+        }
+
+        Intent i = new Intent(this, FileUploader.class);
+        i.putExtra(FileUploader.KEY_ACCOUNT,
+                AccountUtils.getCurrentOwnCloudAccount(this));
+        String remotepath = new String();
+        for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
+            remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
+        }
+        if (!remotepath.endsWith(OCFile.PATH_SEPARATOR))
+            remotepath += OCFile.PATH_SEPARATOR;
+        remotepath += new File(filepath).getName();
+
+        i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath);
+        i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath);
+        i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
+        startService(i);
     }
 
+
     @Override
     public void onBackPressed() {
         if (mDirectories.getCount() <= 1) {
@@ -471,7 +500,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         case DIALOG_CREATE_DIR: {
             builder = new Builder(this);
             final EditText dirNameInput = new EditText(getBaseContext());
-            final Account a = AccountUtils.getCurrentOwnCloudAccount(this);
             builder.setView(dirNameInput);
             builder.setTitle(R.string.uploader_info_dirname);
             int typed_color = getResources().getColor(R.color.setup_text_typed);
@@ -499,7 +527,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
                             
                             // Create directory
                             path += directoryName + OCFile.PATH_SEPARATOR;
-                            Thread thread = new Thread(new DirectoryCreator(path, a, new Handler()));
+                            Thread thread = new Thread(new DirectoryCreator(path,  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
                             thread.start();
                             
                             dialog.dismiss();
@@ -525,6 +553,33 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             dialog = working_dialog;
             break;
         }
+        case DIALOG_CHOOSE_UPLOAD_SOURCE: {
+            final String [] items = {   getString(R.string.actionbar_upload_files), 
+                                        getString(R.string.actionbar_upload_from_apps) }; 
+            builder = new AlertDialog.Builder(this);
+            builder.setTitle(R.string.actionbar_upload);
+            builder.setItems(items, new DialogInterface.OnClickListener() {
+                public void onClick(DialogInterface dialog, int item) {
+                    if (item == 0) {
+                        //if (!mDualPane) { 
+                            Intent action = new Intent(FileDisplayActivity.this, UploadFilesActivity.class);
+                            startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);
+                        //} else {
+                            // TODO create and handle new fragment LocalFileListFragment
+                        //}
+                    } else if (item == 1) {
+                        Intent action = new Intent(Intent.ACTION_GET_CONTENT);
+                        action = action.setType("*/*")
+                                .addCategory(Intent.CATEGORY_OPENABLE);
+                        startActivityForResult(
+                                Intent.createChooser(action, getString(R.string.upload_chooser_title)),
+                                ACTION_SELECT_CONTENT_FROM_APPS);
+                    }
+                }
+            });
+            dialog = builder.create();
+            break;
+        }
         default:
             dialog = null;
         }
@@ -688,7 +743,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
                         || fillBlankRoot ) {
                     if (!fillBlankRoot) 
                         mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath);
-                    FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager()
+                    OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
                             .findFragmentById(R.id.fileList);
                     if (fileListFragment != null) {
                         fileListFragment.listDirectory(mCurrentDir);  
@@ -720,7 +775,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
                             parentDir.equals(mCurrentDir)
                     )
                 ) {
-                FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+                OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
                 if (fileListFragment != null) { 
                     fileListFragment.listDirectory();
                 }
@@ -741,7 +796,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
 
             if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name) &&
                      mCurrentDir != null && mCurrentDir.getFileId() == mStorageManager.getFileByPath(downloadedRemotePath).getParentId()) {
-                FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+                OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
                 if (fileListFragment != null) { 
                     fileListFragment.listDirectory();
                 }
@@ -811,7 +866,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
      */
     @Override
     public void onFileStateChanged() {
-        FileListFragment fileListFragment = (FileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+        OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
         if (fileListFragment != null) { 
             fileListFragment.listDirectory();
         }

+ 266 - 0
src/com/owncloud/android/ui/activity/UploadFilesActivity.java

@@ -0,0 +1,266 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   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.io.File;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.actionbarsherlock.view.MenuItem;
+import com.owncloud.android.ui.fragment.LocalFileListFragment;
+
+import com.owncloud.android.R;
+
+/**
+ * Displays local files and let the user choose what of them wants to upload
+ * to the current ownCloud account
+ * 
+ * @author David A. Velasco
+ * 
+ */
+
+public class UploadFilesActivity extends SherlockFragmentActivity implements
+    LocalFileListFragment.ContainerActivity, OnNavigationListener, OnClickListener {
+    
+    private ArrayAdapter<String> mDirectories;
+    private File mCurrentDir = null;
+    private LocalFileListFragment mFileListFragment;
+    private Button mCancelBtn;
+    private Button mUploadBtn;
+    
+    public static final String EXTRA_DIRECTORY_PATH = "com.owncloud.android.Directory"; 
+    public static final String EXTRA_CHOSEN_FILES = "com.owncloud.android.ChosenFiles";
+    
+    private static final String TAG = "UploadFilesActivity";
+    
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Log.d(TAG, "onCreate() start");
+        super.onCreate(savedInstanceState);
+
+        if(savedInstanceState != null) {
+            mCurrentDir = new File(savedInstanceState.getString(UploadFilesActivity.EXTRA_DIRECTORY_PATH));
+        } else {
+            mCurrentDir = Environment.getExternalStorageDirectory();
+        }
+        
+        /// USER INTERFACE
+            
+        // Drop-down navigation 
+        mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
+        File currDir = mCurrentDir;
+        while(currDir != null && currDir.getParentFile() != null) {
+            mDirectories.add(currDir.getName());
+            currDir = currDir.getParentFile();
+        }
+        mDirectories.add(File.separator);
+
+        // Inflate and set the layout view
+        setContentView(R.layout.upload_files_layout);
+        mFileListFragment = (LocalFileListFragment) getSupportFragmentManager().findFragmentById(R.id.local_files_list);
+        
+        // Set input controllers
+        mCancelBtn = (Button) findViewById(R.id.upload_files_btn_cancel);
+        mCancelBtn.setOnClickListener(this);
+        mUploadBtn = (Button) findViewById(R.id.upload_files_btn_upload);
+        mUploadBtn.setOnClickListener(this);
+            
+        // Action bar setup
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setHomeButtonEnabled(true);   // mandatory since Android ICS, according to the official documentation
+        actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null && mCurrentDir.getName() != null);
+        actionBar.setDisplayShowTitleEnabled(false);
+        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+        actionBar.setListNavigationCallbacks(mDirectories, this);
+            
+        Log.d(TAG, "onCreate() end");
+    }
+
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        boolean retval = true;
+        switch (item.getItemId()) {
+            case android.R.id.home: {
+                if(mCurrentDir != null && mCurrentDir.getParentFile() != null){
+                    onBackPressed(); 
+                }
+                break;
+            }
+            default:
+                retval = false;
+        }
+        return retval;
+    }
+
+    
+    @Override
+    public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+        int i = itemPosition;
+        while (i-- != 0) {
+            onBackPressed();
+        }
+        // the next operation triggers a new call to this method, but it's necessary to 
+        // ensure that the name exposed in the action bar is the current directory when the 
+        // user selected it in the navigation list
+        if (itemPosition != 0)
+            getSupportActionBar().setSelectedNavigationItem(0);
+        return true;
+    }
+
+    
+    @Override
+    public void onBackPressed() {
+        if (mDirectories.getCount() <= 1) {
+            finish();
+            return;
+        }
+        popDirname();
+        mFileListFragment.onNavigateUp();
+        mCurrentDir = mFileListFragment.getCurrentDirectory();
+        
+        if(mCurrentDir.getParentFile() == null){
+            ActionBar actionBar = getSupportActionBar(); 
+            actionBar.setDisplayHomeAsUpEnabled(false);
+        } 
+    }
+
+    
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
+        Log.d(TAG, "onSaveInstanceState() start");
+        super.onSaveInstanceState(outState);
+        outState.putString(UploadFilesActivity.EXTRA_DIRECTORY_PATH, mCurrentDir.getAbsolutePath());
+        Log.d(TAG, "onSaveInstanceState() end");
+    }
+
+    @Override
+    protected void onResume() {
+        Log.d(TAG, "onResume() start");
+        super.onResume();
+
+        // List current directory
+        mFileListFragment.listDirectory(mCurrentDir);
+            
+        Log.d(TAG, "onResume() end");
+    }
+
+    
+    /**
+     * Pushes a directory to the drop down list
+     * @param directory to push
+     * @throws IllegalArgumentException If the {@link File#isDirectory()} returns false.
+     */
+    public void pushDirname(File directory) {
+        if(!directory.isDirectory()){
+            throw new IllegalArgumentException("Only directories may be pushed!");
+        }
+        mDirectories.insert(directory.getName(), 0);
+        mCurrentDir = directory;
+    }
+
+    /**
+     * Pops a directory name from the drop down list
+     * @return True, unless the stack is empty
+     */
+    public boolean popDirname() {
+        mDirectories.remove(mDirectories.getItem(0));
+        return !mDirectories.isEmpty();
+    }
+
+    
+    // Custom array adapter to override text colors
+    private class CustomArrayAdapter<T> extends ArrayAdapter<T> {
+    
+        public CustomArrayAdapter(UploadFilesActivity ctx, int view) {
+            super(ctx, view);
+        }
+    
+        public View getView(int position, View convertView, ViewGroup parent) {
+            View v = super.getView(position, convertView, parent);
+    
+            ((TextView) v).setTextColor(getResources().getColorStateList(
+                    android.R.color.white));
+            return v;
+        }
+    
+        public View getDropDownView(int position, View convertView,
+                ViewGroup parent) {
+            View v = super.getDropDownView(position, convertView, parent);
+    
+            ((TextView) v).setTextColor(getResources().getColorStateList(
+                    android.R.color.white));
+    
+            return v;
+        }
+    
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onDirectoryClick(File directory) {
+        pushDirname(directory);
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setDisplayHomeAsUpEnabled(true);
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onFileClick(File file) {
+        // nothing to do
+    }
+
+
+    /**
+     * Performs corresponding action when user presses 'Cancel' or 'Upload' button
+     */
+    @Override
+    public void onClick(View v) {
+        if (v.getId() == R.id.upload_files_btn_cancel) {
+            setResult(RESULT_CANCELED);
+            finish();
+            
+        } else if (v.getId() == R.id.upload_files_btn_upload) {
+            Intent data = new Intent();
+            data.putExtra(EXTRA_CHOSEN_FILES, mFileListFragment.getCheckedFilePaths());
+            setResult(RESULT_OK, data);
+            finish();
+        }
+    }
+    
+}

+ 28 - 28
src/com/owncloud/android/ui/adapter/FileListListAdapter.java

@@ -35,8 +35,10 @@ import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.CheckedTextView;
 import android.widget.ImageView;
 import android.widget.ListAdapter;
+import android.widget.ListView;
 import android.widget.TextView;
 
 /**
@@ -129,33 +131,17 @@ public class FileListListAdapter implements ListAdapter {
             } else {
                 localStateView.setVisibility(View.INVISIBLE);
             }
-                /*
-            ImageView down = (ImageView) view.findViewById(R.id.imageView2);
-            ImageView downloading = (ImageView) view.findViewById(R.id.imageView4);
-            ImageView uploading = (ImageView) view.findViewById(R.id.imageView5);
-            if (FileDownloader.isDownloading(mAccount, file.getRemotePath())) {
-                down.setVisibility(View.INVISIBLE);
-                downloading.setVisibility(View.VISIBLE);
-                uploading.setVisibility(View.INVISIBLE);
-            } else if (FileUploader.isUploading(mAccount, file.getRemotePath())) {
-                down.setVisibility(View.INVISIBLE);
-                downloading.setVisibility(View.INVISIBLE);
-                uploading.setVisibility(View.VISIBLE);
-            } else if (file.isDown()) {
-                 down.setVisibility(View.VISIBLE);
-                 downloading.setVisibility(View.INVISIBLE);
-                 uploading.setVisibility(View.INVISIBLE);
-            } else {
-                down.setVisibility(View.INVISIBLE);
-                downloading.setVisibility(View.INVISIBLE);
-                uploading.setVisibility(View.INVISIBLE);
-            }*/
-                
+
+            
+            TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);
+            TextView lastModV = (TextView) view.findViewById(R.id.last_mod);
+            ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);
+            
             if (!file.isDirectory()) {
-                view.findViewById(R.id.file_size).setVisibility(View.VISIBLE);
-                view.findViewById(R.id.last_mod).setVisibility(View.VISIBLE);
-                ((TextView)view.findViewById(R.id.file_size)).setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));
-                ((TextView)view.findViewById(R.id.last_mod)).setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()));
+                fileSizeV.setVisibility(View.VISIBLE);
+                fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));
+                lastModV.setVisibility(View.VISIBLE);
+                lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()));
                 // this if-else is needed even thoe fav icon is visible by default
                 // because android reuses views in listview
                 if (!file.keepInSync()) {
@@ -163,9 +149,23 @@ public class FileListListAdapter implements ListAdapter {
                 } else {
                     view.findViewById(R.id.imageView3).setVisibility(View.VISIBLE);
                 }
+                
+                ListView parentList = (ListView)parent;
+                if (parentList.getChoiceMode() == ListView.CHOICE_MODE_NONE) { 
+                    checkBoxV.setVisibility(View.GONE);
+                } else {
+                    checkBoxV.setVisibility(View.VISIBLE);
+                    if (parentList.isItemChecked(position)) {
+                        checkBoxV.setImageResource(android.R.drawable.checkbox_on_background);
+                    } else {
+                        checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);
+                    }
+                }
+                
             } else {
-               view.findViewById(R.id.file_size).setVisibility(View.GONE);
-               view.findViewById(R.id.last_mod).setVisibility(View.GONE);
+               fileSizeV.setVisibility(View.GONE);
+               lastModV.setVisibility(View.GONE);
+               checkBoxV.setVisibility(View.GONE);
                view.findViewById(R.id.imageView3).setVisibility(View.GONE);
             }
         }

+ 202 - 0
src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java

@@ -0,0 +1,202 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   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.adapter;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.owncloud.android.DisplayUtils;
+import com.owncloud.android.R;
+
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+/**
+ * This Adapter populates a ListView with all files and directories contained
+ * in a local directory
+ * 
+ * @author David A. Velasco
+ * 
+ */
+public class LocalFileListAdapter extends BaseAdapter implements ListAdapter {
+    
+    private Context mContext;
+    private File mDirectory;
+    private File[] mFiles = null;
+    private Set<DataSetObserver> mObservers = new HashSet<DataSetObserver>();
+
+    public LocalFileListAdapter(File directory, Context context) {
+        mContext = context;
+        swapDirectory(directory);
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() {
+        return true;
+    }
+
+    @Override
+    public boolean isEnabled(int position) {
+        return true;
+    }
+
+    @Override
+    public int getCount() {
+        return mFiles != null ? mFiles.length : 0;
+    }
+
+    @Override
+    public Object getItem(int position) {
+        if (mFiles == null || mFiles.length <= position)
+            return null;
+        return mFiles[position];
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return mFiles != null && mFiles.length <= position ? position : -1;
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return 0;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        View view = convertView;
+        if (view == null) {
+            LayoutInflater inflator = (LayoutInflater) mContext
+                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            view = inflator.inflate(R.layout.list_layout, null);
+        }
+        if (mFiles != null && mFiles.length > position) {
+            File file = mFiles[position];
+            
+            TextView fileName = (TextView) view.findViewById(R.id.Filename);
+            String name = file.getName();
+            fileName.setText(name);
+            
+            ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1);
+            if (!file.isDirectory()) {
+                fileIcon.setImageResource(R.drawable.file);
+            } else {
+                fileIcon.setImageResource(R.drawable.ic_menu_archive);
+            }
+
+            TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);
+            TextView lastModV = (TextView) view.findViewById(R.id.last_mod);
+            ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);
+            if (!file.isDirectory()) {
+                fileSizeV.setVisibility(View.VISIBLE);
+                fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.length()));
+                lastModV.setVisibility(View.VISIBLE);
+                lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.lastModified()));
+                ListView parentList = (ListView)parent;
+                if (parentList.getChoiceMode() == ListView.CHOICE_MODE_NONE) { 
+                    checkBoxV.setVisibility(View.GONE);
+                } else {
+                    checkBoxV.setVisibility(View.VISIBLE);
+                    if (parentList.isItemChecked(position)) {
+                        checkBoxV.setImageResource(android.R.drawable.checkbox_on_background);
+                    } else {
+                        checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);
+                    }
+                }
+
+            } else {
+                fileSizeV.setVisibility(View.GONE);
+                lastModV.setVisibility(View.GONE);
+                checkBoxV.setVisibility(View.GONE);
+            }
+            
+            view.findViewById(R.id.imageView2).setVisibility(View.INVISIBLE);   // not GONE; the alignment changes; ugly way to keep it
+            view.findViewById(R.id.imageView3).setVisibility(View.GONE);
+        }
+
+        return view;
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        return 1;
+    }
+
+    @Override
+    public boolean hasStableIds() {
+        return false;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return (mFiles == null || mFiles.length == 0);
+    }
+
+    @Override
+    public void registerDataSetObserver(DataSetObserver observer) {
+        mObservers.add(observer);
+    }
+
+    @Override
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        mObservers.remove(observer);
+    }
+
+    /**
+     * Change the adapted directory for a new one
+     * @param directory     New file to adapt. 
+     */
+    public void swapDirectory(File directory) {
+        mDirectory = directory;
+        mFiles = mDirectory.listFiles();
+        if (mFiles != null) {
+            Arrays.sort(mFiles, new Comparator<File>() {
+                @Override
+                public int compare(File lhs, File rhs) {
+                    if (lhs.isDirectory() && !rhs.isDirectory()) {
+                        return -1;
+                    } else if (!lhs.isDirectory() && rhs.isDirectory()) {
+                        return 1;
+                    }
+                    return compareNames(lhs, rhs);
+                }
+            
+                private int compareNames(File lhs, File rhs) {
+                    return lhs.getName().toLowerCase().compareTo(rhs.getName().toLowerCase());                
+                }
+            
+            });
+        }
+        Iterator<DataSetObserver> it = mObservers.iterator();
+        while (it.hasNext()) {
+            it.next().onChanged();
+        }
+    }
+}

+ 242 - 0
src/com/owncloud/android/ui/fragment/LocalFileListFragment.java

@@ -0,0 +1,242 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   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.fragment;
+
+import java.io.File;
+
+import com.owncloud.android.ui.FragmentListView;
+import com.owncloud.android.ui.adapter.LocalFileListAdapter;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Log;
+import android.util.SparseBooleanArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
+
+import com.owncloud.android.R;
+
+/**
+ * A Fragment that lists all files and folders in a given LOCAL path.
+ * 
+ * @author David A. Velasco
+ * 
+ */
+public class LocalFileListFragment extends FragmentListView {
+    private static final String TAG = "LocalFileListFragment";
+    
+    /** Reference to the Activity which this fragment is attached to. For callbacks */
+    private LocalFileListFragment.ContainerActivity mContainerActivity;
+    
+    /** Directory to show */
+    private File mDirectory = null;
+    
+    /** Adapter to connect the data from the directory with the View object */
+    private LocalFileListAdapter mAdapter = null;
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        try {
+            mContainerActivity = (ContainerActivity) activity;
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString() + " must implement " + LocalFileListFragment.ContainerActivity.class.getCanonicalName());
+        }
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        Log.i(getClass().toString(), "onCreateView() start");
+        super.onCreateView(inflater, container, savedInstanceState);
+        getListView().setDivider(getResources().getDrawable(R.drawable.uploader_list_separator));
+        getListView().setDividerHeight(1);
+        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+        
+        if (savedInstanceState != null) {
+            // TODO recover previous state; or maybe in onActivityCreated
+        }
+        
+        Log.i(getClass().toString(), "onCreateView() end");
+        return getListView();
+    }    
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        Log.i(getClass().toString(), "onActivityCreated() start");
+        
+        super.onCreate(savedInstanceState);
+        
+        Log.i(getClass().toString(), "onActivityCreated() stop");
+    }
+    
+    
+    /**
+     * Checks the file clicked over. Browses inside if it is a directory. Notifies the container activity in any case.
+     */
+    @Override
+    public void onItemClick(AdapterView<?> l, View v, int position, long id) {
+        File file = (File) mAdapter.getItem(position); 
+        if (file != null) {
+            /// Click on a directory
+            if (file.isDirectory()) {
+                // just local updates
+                listDirectory(file);
+                // notify the click to container Activity
+                mContainerActivity.onDirectoryClick(file);
+            
+            } else {    /// Click on a file
+                // notify the change to the container Activity
+                mContainerActivity.onFileClick(file);
+            }
+            
+        } else {
+            Log.w(TAG, "Null object in ListAdapter!!");
+        }
+    }
+
+    
+    /**
+     * Call this, when the user presses the up button
+     */
+    public void onNavigateUp() {
+        File parentDir = null;
+        if(mDirectory != null) {
+            parentDir = mDirectory.getParentFile();  // can be null
+        }
+        listDirectory(parentDir);
+    }
+
+    
+    /**
+     * Use this to query the {@link File} object for the directory
+     * that is currently being displayed by this fragment
+     * 
+     * @return File     The currently displayed directory
+     */
+    public File getCurrentDirectory(){
+        return mDirectory;
+    }
+    
+    
+    /**
+     * Calls {@link LocalFileListFragment#listDirectory(File)} with a null parameter
+     * to refresh the current directory.
+     */
+    public void listDirectory(){
+        listDirectory(null);
+    }
+    
+    
+    /**
+     * Lists the given directory on the view. When the input parameter is null,
+     * it will either refresh the last known directory, or list the root
+     * if there never was a directory.
+     * 
+     * @param directory     Directory to be listed
+     */
+    public void listDirectory(File directory) {
+        
+        // Check input parameters for null
+        if(directory == null) {
+            if(mDirectory != null){
+                directory = mDirectory;
+            } else {
+                directory = Environment.getExternalStorageDirectory();  // TODO be careful with the state of the storage; could not be available
+                if (directory == null) return; // no files, wait for sync
+            }
+        }
+        
+        
+        // if that's not a directory -> List its parent
+        if(!directory.isDirectory()){
+            Log.w(TAG, "You see, that is not a directory -> " + directory.toString());
+            directory = directory.getParentFile();
+        }
+
+        mDirectory = directory;
+        if (mAdapter == null) {
+            mAdapter = new LocalFileListAdapter(mDirectory, getActivity());
+            setListAdapter(mAdapter);
+        } else {
+            mList.clearChoices();   // by now, only files in the same directory will be kept as selected
+            mAdapter.swapDirectory(mDirectory);
+        }
+        
+    }
+    
+
+    /**
+     * Returns the fule paths to the files checked by the user
+     * 
+     * @return      File paths to the files checked by the user.
+     */
+    public String[] getCheckedFilePaths() {
+        String [] result = null;
+        SparseBooleanArray positions = mList.getCheckedItemPositions();
+        if (positions.size() > 0) {
+            Log.d(TAG, "Returning " + positions.size() + " selected files");
+            result = new String[positions.size()];
+            for (int i=0; i<positions.size(); i++) {
+                result[i] = ((File) mList.getItemAtPosition(positions.keyAt(i))).getAbsolutePath();
+            }
+        }
+        return result;
+    }
+
+    
+    /**
+     * Interface to implement by any Activity that includes some instance of LocalFileListFragment
+     * 
+     * @author David A. Velasco
+     */
+    public interface ContainerActivity {
+
+        /**
+         * Callback method invoked when a directory is clicked by the user on the files list
+         *  
+         * @param file
+         */
+        public void onDirectoryClick(File directory);
+        
+        /**
+         * Callback method invoked when a file (non directory) is clicked by the user on the files list
+         *  
+         * @param file
+         */
+        public void onFileClick(File file);
+
+    }
+
+
+}

+ 203 - 205
src/com/owncloud/android/ui/fragment/FileListFragment.java → src/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -1,205 +1,203 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   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.fragment;
-
-import java.util.Vector;
-
-import com.owncloud.android.datamodel.DataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.ui.FragmentListView;
-import com.owncloud.android.ui.adapter.FileListListAdapter;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import com.owncloud.android.R;
-
-/**
- * A Fragment that lists all files and folders in a given path.
- * 
- * @author Bartek Przybylski
- * 
- */
-public class FileListFragment extends FragmentListView {
-    private static final String TAG = "FileListFragment";
-    
-    private FileListFragment.ContainerActivity mContainerActivity;
-    
-    private OCFile mFile = null;
-    private FileListListAdapter mAdapter;
-
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        try {
-            mContainerActivity = (ContainerActivity) activity;
-        } catch (ClassCastException e) {
-            throw new ClassCastException(activity.toString() + " must implement FileListFragment.ContainerActivity");
-        }
-    }
-    
-    
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        Log.i(getClass().toString(), "onCreateView() start");
-        super.onCreateView(inflater, container, savedInstanceState);
-        getListView().setDivider(getResources().getDrawable(R.drawable.uploader_list_separator));
-        getListView().setDividerHeight(1);
-        
-        Log.i(getClass().toString(), "onCreateView() end");
-        return getListView();
-    }    
-
-
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        Log.i(getClass().toString(), "onActivityCreated() start");
-        
-        super.onCreate(savedInstanceState);
-        //mAdapter = new FileListListAdapter();
-        
-        Log.i(getClass().toString(), "onActivityCreated() stop");
-    }
-    
-    
-    @Override
-    public void onItemClick(AdapterView<?> l, View v, int position, long id) {
-        OCFile file = (OCFile) mAdapter.getItem(position);
-        if (file != null) {
-            /// Click on a directory
-            if (file.getMimetype().equals("DIR")) {
-                // just local updates
-                mFile = file;
-                listDirectory(file);
-                // any other updates are let to the container Activity
-                mContainerActivity.onDirectoryClick(file);
-            
-            } else {    /// Click on a file
-                mContainerActivity.onFileClick(file);
-            }
-            
-        } else {
-            Log.d(TAG, "Null object in ListAdapter!!");
-        }
-        
-    }
-
-    /**
-     * Call this, when the user presses the up button
-     */
-    public void onNavigateUp() {
-        OCFile parentDir = null;
-        
-        if(mFile != null){
-            DataStorageManager storageManager = mContainerActivity.getStorageManager();
-            parentDir = storageManager.getFileById(mFile.getParentId());
-            mFile = parentDir;
-        }
-        listDirectory(parentDir);
-    }
-
-    /**
-     * Use this to query the {@link OCFile} that is currently
-     * being displayed by this fragment
-     * @return The currently viewed OCFile
-     */
-    public OCFile getCurrentFile(){
-        return mFile;
-    }
-    
-    /**
-     * Calls {@link FileListFragment#listDirectory(OCFile)} with a null parameter
-     */
-    public void listDirectory(){
-        listDirectory(null);
-    }
-    
-    /**
-     * Lists the given directory on the view. When the input parameter is null,
-     * it will either refresh the last known directory, or list the root
-     * if there never was a directory.
-     * 
-     * @param directory File to be listed
-     */
-    public void listDirectory(OCFile directory) {
-        
-        DataStorageManager storageManager = mContainerActivity.getStorageManager();
-
-        // Check input parameters for null
-        if(directory == null){
-            if(mFile != null){
-                directory = mFile;
-            } else {
-                directory = storageManager.getFileByPath("/");
-                if (directory == null) return; // no files, wait for sync
-            }
-        }
-        
-        
-        // If that's not a directory -> List its parent
-        if(!directory.isDirectory()){
-            Log.w(TAG, "You see, that is not a directory -> " + directory.toString());
-            directory = storageManager.getFileById(directory.getParentId());
-        }
-
-        mFile = directory;
-        
-        mAdapter = new FileListListAdapter(directory, storageManager, getActivity());
-        setListAdapter(mAdapter);
-    }
-    
-    
-    
-    /**
-     * Interface to implement by any Activity that includes some instance of FileListFragment
-     * 
-     * @author David A. Velasco
-     */
-    public interface ContainerActivity {
-
-        /**
-         * Callback method invoked when a directory is clicked by the user on the files list
-         *  
-         * @param file
-         */
-        public void onDirectoryClick(OCFile file);
-        
-        /**
-         * Callback method invoked when a file (non directory) is clicked by the user on the files list
-         *  
-         * @param file
-         */
-        public void onFileClick(OCFile file);
-
-        /**
-         * Getter for the current DataStorageManager in the container activity
-         */
-        public DataStorageManager getStorageManager();
-        
-    }
-
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   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.fragment;
+
+import com.owncloud.android.datamodel.DataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.FragmentListView;
+import com.owncloud.android.ui.adapter.FileListListAdapter;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import com.owncloud.android.R;
+
+/**
+ * A Fragment that lists all files and folders in a given path.
+ * 
+ * @author Bartek Przybylski
+ * 
+ */
+public class OCFileListFragment extends FragmentListView {
+    private static final String TAG = "FileListFragment";
+    
+    private OCFileListFragment.ContainerActivity mContainerActivity;
+    
+    private OCFile mFile = null;
+    private FileListListAdapter mAdapter;
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        try {
+            mContainerActivity = (ContainerActivity) activity;
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString() + " must implement FileListFragment.ContainerActivity");
+        }
+    }
+    
+    
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        Log.i(getClass().toString(), "onCreateView() start");
+        super.onCreateView(inflater, container, savedInstanceState);
+        getListView().setDivider(getResources().getDrawable(R.drawable.uploader_list_separator));
+        getListView().setDividerHeight(1);
+        
+        Log.i(getClass().toString(), "onCreateView() end");
+        return getListView();
+    }    
+
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        Log.i(getClass().toString(), "onActivityCreated() start");
+        
+        super.onCreate(savedInstanceState);
+        //mAdapter = new FileListListAdapter();
+        
+        Log.i(getClass().toString(), "onActivityCreated() stop");
+    }
+    
+    
+    @Override
+    public void onItemClick(AdapterView<?> l, View v, int position, long id) {
+        OCFile file = (OCFile) mAdapter.getItem(position);
+        if (file != null) {
+            /// Click on a directory
+            if (file.getMimetype().equals("DIR")) {
+                // just local updates
+                mFile = file;
+                listDirectory(file);
+                // any other updates are let to the container Activity
+                mContainerActivity.onDirectoryClick(file);
+            
+            } else {    /// Click on a file
+                mContainerActivity.onFileClick(file);
+            }
+            
+        } else {
+            Log.d(TAG, "Null object in ListAdapter!!");
+        }
+        
+    }
+
+    /**
+     * Call this, when the user presses the up button
+     */
+    public void onNavigateUp() {
+        OCFile parentDir = null;
+        
+        if(mFile != null){
+            DataStorageManager storageManager = mContainerActivity.getStorageManager();
+            parentDir = storageManager.getFileById(mFile.getParentId());
+            mFile = parentDir;
+        }
+        listDirectory(parentDir);
+    }
+
+    /**
+     * Use this to query the {@link OCFile} that is currently
+     * being displayed by this fragment
+     * @return The currently viewed OCFile
+     */
+    public OCFile getCurrentFile(){
+        return mFile;
+    }
+    
+    /**
+     * Calls {@link OCFileListFragment#listDirectory(OCFile)} with a null parameter
+     */
+    public void listDirectory(){
+        listDirectory(null);
+    }
+    
+    /**
+     * Lists the given directory on the view. When the input parameter is null,
+     * it will either refresh the last known directory, or list the root
+     * if there never was a directory.
+     * 
+     * @param directory File to be listed
+     */
+    public void listDirectory(OCFile directory) {
+        
+        DataStorageManager storageManager = mContainerActivity.getStorageManager();
+
+        // Check input parameters for null
+        if(directory == null){
+            if(mFile != null){
+                directory = mFile;
+            } else {
+                directory = storageManager.getFileByPath("/");
+                if (directory == null) return; // no files, wait for sync
+            }
+        }
+        
+        
+        // If that's not a directory -> List its parent
+        if(!directory.isDirectory()){
+            Log.w(TAG, "You see, that is not a directory -> " + directory.toString());
+            directory = storageManager.getFileById(directory.getParentId());
+        }
+
+        mFile = directory;
+        
+        mAdapter = new FileListListAdapter(directory, storageManager, getActivity());
+        setListAdapter(mAdapter);
+    }
+    
+    
+    
+    /**
+     * Interface to implement by any Activity that includes some instance of FileListFragment
+     * 
+     * @author David A. Velasco
+     */
+    public interface ContainerActivity {
+
+        /**
+         * Callback method invoked when a directory is clicked by the user on the files list
+         *  
+         * @param file
+         */
+        public void onDirectoryClick(OCFile file);
+        
+        /**
+         * Callback method invoked when a file (non directory) is clicked by the user on the files list
+         *  
+         * @param file
+         */
+        public void onFileClick(OCFile file);
+
+        /**
+         * Getter for the current DataStorageManager in the container activity
+         */
+        public DataStorageManager getStorageManager();
+        
+    }
+
+}