Merge branch 'develop' into introduce-travis-ci
3
.gitmodules
vendored
|
@ -1,3 +1,6 @@
|
||||||
[submodule "actionbarsherlock"]
|
[submodule "actionbarsherlock"]
|
||||||
path = actionbarsherlock
|
path = actionbarsherlock
|
||||||
url = git://github.com/JakeWharton/ActionBarSherlock.git
|
url = git://github.com/JakeWharton/ActionBarSherlock.git
|
||||||
|
[submodule "owncloud-android-library"]
|
||||||
|
path = owncloud-android-library
|
||||||
|
url = git://github.com/owncloud/android-library.git
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
<manifest package="com.owncloud.android"
|
<manifest package="com.owncloud.android"
|
||||||
android:versionCode="105002"
|
android:versionCode="105004"
|
||||||
android:versionName="1.5.2" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:versionName="1.5.4" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||||
|
@ -54,7 +54,6 @@
|
||||||
>
|
>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
@ -83,7 +82,8 @@
|
||||||
|
|
||||||
<data android:mimeType="*/*" >
|
<data android:mimeType="*/*" >
|
||||||
</data>
|
</data>
|
||||||
</intent-filter>
|
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.activity.Preferences"
|
android:name=".ui.activity.Preferences"
|
||||||
|
@ -92,11 +92,15 @@
|
||||||
<activity android:name=".ui.activity.PreferencesNewSessionewSession" >
|
<activity android:name=".ui.activity.PreferencesNewSessionewSession" >
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".ui.preview.PreviewImageActivity" />
|
<activity
|
||||||
|
android:name=".ui.preview.PreviewImageActivity"
|
||||||
|
/>
|
||||||
|
|
||||||
<activity android:name=".ui.preview.PreviewVideoActivity"
|
<activity
|
||||||
android:label="@string/app_name"
|
android:name=".ui.preview.PreviewVideoActivity"
|
||||||
android:theme="@style/Theme.ownCloud.Fullscreen" >
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/Theme.ownCloud.Fullscreen"
|
||||||
|
>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
|
@ -149,6 +153,7 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<service android:name=".services.OperationsService" />
|
||||||
<service android:name=".files.services.FileDownloader" />
|
<service android:name=".files.services.FileDownloader" />
|
||||||
<service android:name=".files.services.FileUploader" />
|
<service android:name=".files.services.FileUploader" />
|
||||||
<service android:name=".media.MediaService" />
|
<service android:name=".media.MediaService" />
|
||||||
|
@ -180,6 +185,11 @@
|
||||||
</receiver>
|
</receiver>
|
||||||
<service android:name=".files.services.FileObserverService"/>
|
<service android:name=".files.services.FileObserverService"/>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ui.activity.CopyToClipboardActivity"
|
||||||
|
android:label="@string/copy_link"
|
||||||
|
android:icon="@drawable/copy_link" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
40
SETUP.md
|
@ -12,6 +12,7 @@ NOTE: You must have git in your environment path variable to perform the next op
|
||||||
* Pull changes from your develop branch: "git pull origin develop"
|
* Pull changes from your develop branch: "git pull origin develop"
|
||||||
* Make official ownCloud repo known as upstream: "git remote add upstream git@github.com:owncloud/android.git"
|
* Make official ownCloud repo known as upstream: "git remote add upstream git@github.com:owncloud/android.git"
|
||||||
* Make sure to get the latest changes from official android/develop branch: "git pull upstream develop"
|
* Make sure to get the latest changes from official android/develop branch: "git pull upstream develop"
|
||||||
|
* Complete the setup of project properties and resolve pending dependencies running "setup_env.bat" or "./setup_env.sh" .
|
||||||
|
|
||||||
At this point you can continue using different tools to build the project. Section 2, 3 and 4 describe some of the existing alternatives.
|
At this point you can continue using different tools to build the project. Section 2, 3 and 4 describe some of the existing alternatives.
|
||||||
|
|
||||||
|
@ -19,23 +20,24 @@ At this point you can continue using different tools to build the project. Secti
|
||||||
|
|
||||||
NOTE: You must have the Android SDK 'tools/', and 'platforms-tools/' folders in your environment path variable.
|
NOTE: You must have the Android SDK 'tools/', and 'platforms-tools/' folders in your environment path variable.
|
||||||
|
|
||||||
* Complete the setup of project properties and resolve pending dependencies running "setup_env.bat" or "./setup_env.sh" .
|
|
||||||
* Run "ant clean" .
|
* Run "ant clean" .
|
||||||
* Run "ant debug" to generate a debuggable version of the ownCkoud app.
|
* Run "ant debug" to generate a debuggable version of the ownCloud app.
|
||||||
|
|
||||||
### 3. Building with console/maven:
|
### 3. Building with console/maven:
|
||||||
|
|
||||||
NOTE: You must have mvn (version >= 3.1.1) in your environment path. Current Android 'platforms-tools' need to be installed.
|
NOTE: You must have mvn (version >= 3.1.1) in your environment path. Current Android 'platforms-tools' need to be installed.
|
||||||
|
|
||||||
* Download/install Android plugin for Maven, then build ownCloud with mvn:
|
Download/install Android plugin for Maven, install owncloud-android-library, then build ownCloud with mvn:
|
||||||
* "cd .."
|
|
||||||
* "git clone https://github.com/mosabua/maven-android-sdk-deployer.git"
|
* cd ..
|
||||||
* "cd maven-android-sdk-deployer"
|
* git clone https://github.com/mosabua/maven-android-sdk-deployer.git
|
||||||
* "mvn -pl com.simpligility.android.sdk-deployer:android-19 -am install"
|
* cd maven-android-sdk-deployer
|
||||||
* "cd ../android/oc_framework"
|
* mvn -pl com.simpligility.android.sdk-deployer:android-19 -am install
|
||||||
* "mvn install"
|
* cd ../android/owncloud-android-library
|
||||||
* "cd .."
|
* mvn install
|
||||||
* Now you can create ownCloud APK using "mvn package"
|
* cd ..
|
||||||
|
|
||||||
|
Now you can create ownCloud APK using "mvn package"
|
||||||
|
|
||||||
### 4. Building with Eclipse:
|
### 4. Building with Eclipse:
|
||||||
|
|
||||||
|
@ -46,15 +48,15 @@ NOTE: You must have the Android SDK 'tools/', and 'platforms-tools/' folders in
|
||||||
* Clean project and compile.
|
* Clean project and compile.
|
||||||
* If any error appear, check the project properties; in the 'Android' section, API Level should be greater or equal than 14.
|
* If any error appear, check the project properties; in the 'Android' section, API Level should be greater or equal than 14.
|
||||||
* Make sure android/actionbarsherlock/library/bin/library.jar was created.
|
* Make sure android/actionbarsherlock/library/bin/library.jar was created.
|
||||||
* Create a new "Android Project from Existing Code". Choose android/oc_framework as root.
|
* Create a new "Android Project from Existing Code". Choose android/owncloud-android-library as root.
|
||||||
* Clean project and compile.
|
* Clean project and compile.
|
||||||
* If any error appear, check the project properties; in the 'Android' section, API Level should be 19 or greater.
|
* If any error appear, check the project properties; in the 'Android' section, API Level should be 19 or greater.
|
||||||
* Make sure android/oc_framework/bin/classes.jar was created.
|
* Make sure android/owncloud-android-library/bin/classes.jar was created.
|
||||||
* Import ownCloud Android project.
|
* Import ownCloud Android project.
|
||||||
* Clean project and compile.
|
* Clean project and compile.
|
||||||
* If any error appears, check the project properties of owncloud-android project; in the 'Android' section:
|
* If any error appears, check the project properties of owncloud-android project; in the 'Android' section:
|
||||||
- API Level should be 19 or greater.
|
- API Level should be 19 or greater.
|
||||||
- Two library projects should appear referred in the bottom square: actionbarsherlock/library and oc_framework. Add them if needed.
|
- Two library projects should appear referred in the bottom square: actionbarsherlock/library and owncloud-android-library. Add them if needed.
|
||||||
* After those actions you should be good to go. HAVE FUN!
|
* After those actions you should be good to go. HAVE FUN!
|
||||||
|
|
||||||
NOTE: Even though API level is set to 19, APK also runs on older devices because in AndroidManifest.xml minSdkVersion is set to 8.
|
NOTE: Even though API level is set to 19, APK also runs on older devices because in AndroidManifest.xml minSdkVersion is set to 8.
|
||||||
|
@ -70,6 +72,16 @@ NOTE: You must sign the [Contributor Agreement][1] before your changes can be ac
|
||||||
* Again, click "Edit" and set "compare:develop"
|
* Again, click "Edit" and set "compare:develop"
|
||||||
* Enter description and send pull request.
|
* Enter description and send pull request.
|
||||||
|
|
||||||
|
### 6. Create another pull request:
|
||||||
|
|
||||||
|
To make sure your new pull request does not contain commits which are already contained in previous PRs, create a new branch which is a clone of upstream/develop.
|
||||||
|
|
||||||
|
* git fetch upstream
|
||||||
|
* git checkout -b my_new_develop_branch upstream/develop
|
||||||
|
* If you want to rename that branch later: "git checkout -b my_new_develop_branch_with_new_name"
|
||||||
|
* Push branch to server: "git push -u origin name_of_local_develop_branch"
|
||||||
|
* Use Github to issue PR
|
||||||
|
|
||||||
|
|
||||||
[0]: https://github.com/owncloud/android/blob/master/CONTRIBUTING.md
|
[0]: https://github.com/owncloud/android/blob/master/CONTRIBUTING.md
|
||||||
[1]: http://owncloud.org/about/contributor-agreement/
|
[1]: http://owncloud.org/about/contributor-agreement/
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<classpath>
|
|
||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
|
||||||
<classpathentry exported="true" kind="lib" path="/oc_framework/bin/oc_framework.jar" sourcepath="/oc_framework"/>
|
|
||||||
<classpathentry kind="src" path="src"/>
|
|
||||||
<classpathentry kind="src" path="gen"/>
|
|
||||||
<classpathentry kind="output" path="bin/classes"/>
|
|
||||||
</classpath>
|
|
|
@ -1,33 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<projectDescription>
|
|
||||||
<name>oc_framework-test-project</name>
|
|
||||||
<comment></comment>
|
|
||||||
<projects>
|
|
||||||
</projects>
|
|
||||||
<buildSpec>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
</buildSpec>
|
|
||||||
<natures>
|
|
||||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
|
||||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
|
||||||
</natures>
|
|
||||||
</projectDescription>
|
|
|
@ -1,4 +0,0 @@
|
||||||
eclipse.preferences.version=1
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
|
||||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
|
||||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
|
@ -1,36 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.owncloud.android.oc_framework_test_project"
|
|
||||||
android:versionCode="1"
|
|
||||||
android:versionName="1.0" >
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
|
||||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
|
||||||
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
|
||||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
|
||||||
|
|
||||||
<uses-sdk
|
|
||||||
android:minSdkVersion="8"
|
|
||||||
android:targetSdkVersion="19" />
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:allowBackup="true"
|
|
||||||
android:icon="@drawable/ic_launcher"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:theme="@style/AppTheme" >
|
|
||||||
<activity
|
|
||||||
android:name="com.owncloud.android.oc_framework_test_project.TestActivity"
|
|
||||||
android:label="@string/app_name" >
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
|
|
||||||
</manifest>
|
|
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 50 KiB |
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<classpath>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
|
||||||
<classpathentry combineaccessrules="false" kind="src" path="/oc_framework-test-project"/>
|
|
||||||
<classpathentry kind="src" path="src"/>
|
|
||||||
<classpathentry kind="src" path="gen"/>
|
|
||||||
<classpathentry kind="output" path="bin/classes"/>
|
|
||||||
</classpath>
|
|
|
@ -1,34 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<projectDescription>
|
|
||||||
<name>oc_framework-test</name>
|
|
||||||
<comment></comment>
|
|
||||||
<projects>
|
|
||||||
<project>oc_framework-test-project</project>
|
|
||||||
</projects>
|
|
||||||
<buildSpec>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
</buildSpec>
|
|
||||||
<natures>
|
|
||||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
|
||||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
|
||||||
</natures>
|
|
||||||
</projectDescription>
|
|
|
@ -1,4 +0,0 @@
|
||||||
eclipse.preferences.version=1
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
|
||||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
|
||||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
|
@ -1,17 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.owncloud.android.oc_framework_test_project.test"
|
|
||||||
android:versionCode="1"
|
|
||||||
android:versionName="1.0" >
|
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="8" />
|
|
||||||
<application>
|
|
||||||
<uses-library android:name="android.test.runner" />
|
|
||||||
</application>
|
|
||||||
|
|
||||||
<instrumentation
|
|
||||||
android:name="android.test.InstrumentationTestRunner"
|
|
||||||
android:label="Tests for com.owncloud.android.oc_framework_test_project"
|
|
||||||
android:targetPackage="com.owncloud.android.oc_framework_test_project" />
|
|
||||||
|
|
||||||
</manifest>
|
|
|
@ -1,14 +0,0 @@
|
||||||
# This file is automatically generated by Android Tools.
|
|
||||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
|
||||||
#
|
|
||||||
# This file must be checked in Version Control Systems.
|
|
||||||
#
|
|
||||||
# To customize properties used by the Ant build system edit
|
|
||||||
# "ant.properties", and override values to adapt the script to your
|
|
||||||
# project structure.
|
|
||||||
#
|
|
||||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
|
||||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
|
||||||
|
|
||||||
# Project target.
|
|
||||||
target=android-19
|
|
Before Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 14 KiB |
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<string name="app_name">Oc_framework-testTest</string>
|
|
||||||
|
|
||||||
</resources>
|
|
|
@ -1,113 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework_test_project.test;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult.ResultCode;
|
|
||||||
import com.owncloud.android.oc_framework_test_project.TestActivity;
|
|
||||||
|
|
||||||
import android.test.ActivityInstrumentationTestCase2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to test Create Folder Operation
|
|
||||||
* @author masensio
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class CreateFolderTest extends ActivityInstrumentationTestCase2<TestActivity> {
|
|
||||||
|
|
||||||
private TestActivity mActivity;
|
|
||||||
private String mCurrentDate;
|
|
||||||
|
|
||||||
public CreateFolderTest() {
|
|
||||||
super(TestActivity.class);
|
|
||||||
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
|
||||||
mCurrentDate = sdf.format(new Date());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
setActivityInitialTouchMode(false);
|
|
||||||
mActivity = getActivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Create Folder
|
|
||||||
*/
|
|
||||||
public void testCreateFolder() {
|
|
||||||
|
|
||||||
String remotePath = "/testCreateFolder" + mCurrentDate;
|
|
||||||
boolean createFullPath = true;
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.createFolder(remotePath, createFullPath);
|
|
||||||
assertTrue(result.isSuccess() || result.getCode() == ResultCode.TIMEOUT);
|
|
||||||
|
|
||||||
// Create Subfolder
|
|
||||||
remotePath = "/testCreateFolder" + mCurrentDate + "/" + "testCreateFolder" + mCurrentDate;
|
|
||||||
createFullPath = true;
|
|
||||||
|
|
||||||
result = mActivity.createFolder(remotePath, createFullPath);
|
|
||||||
assertTrue(result.isSuccess() || result.getCode() == ResultCode.TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test to Create Folder with special characters: / \ < > : " | ? *
|
|
||||||
*/
|
|
||||||
public void testCreateFolderSpecialCharacters() {
|
|
||||||
boolean createFullPath = true;
|
|
||||||
|
|
||||||
String remotePath = "/testSpecialCharacters_\\" + mCurrentDate;
|
|
||||||
RemoteOperationResult result = mActivity.createFolder(remotePath, createFullPath);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
remotePath = "/testSpecialCharacters_<" + mCurrentDate;
|
|
||||||
result = mActivity.createFolder(remotePath, createFullPath);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
remotePath = "/testSpecialCharacters_>" + mCurrentDate;
|
|
||||||
result = mActivity.createFolder(remotePath, createFullPath);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
remotePath = "/testSpecialCharacters_:" + mCurrentDate;
|
|
||||||
result = mActivity.createFolder(remotePath, createFullPath);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
remotePath = "/testSpecialCharacters_\"" + mCurrentDate;
|
|
||||||
result = mActivity.createFolder(remotePath, createFullPath);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
remotePath = "/testSpecialCharacters_|" + mCurrentDate;
|
|
||||||
result = mActivity.createFolder(remotePath, createFullPath);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
remotePath = "/testSpecialCharacters_?" + mCurrentDate;
|
|
||||||
result = mActivity.createFolder(remotePath, createFullPath);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
remotePath = "/testSpecialCharacters_*" + mCurrentDate;
|
|
||||||
result = mActivity.createFolder(remotePath, createFullPath);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework_test_project.test;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult.ResultCode;
|
|
||||||
import com.owncloud.android.oc_framework_test_project.TestActivity;
|
|
||||||
|
|
||||||
import android.test.ActivityInstrumentationTestCase2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to test Delete a File Operation
|
|
||||||
* @author masensio
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DeleteFileTest extends ActivityInstrumentationTestCase2<TestActivity> {
|
|
||||||
|
|
||||||
/* Folder data to delete. */
|
|
||||||
private final String mFolderPath = "/folderToDelete";
|
|
||||||
|
|
||||||
/* File to delete. */
|
|
||||||
private final String mFilePath = "fileToDelete.png";
|
|
||||||
|
|
||||||
private TestActivity mActivity;
|
|
||||||
|
|
||||||
public DeleteFileTest() {
|
|
||||||
super(TestActivity.class);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
setActivityInitialTouchMode(false);
|
|
||||||
mActivity = getActivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Remove Folder
|
|
||||||
*/
|
|
||||||
public void testRemoveFolder() {
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.removeFile(mFolderPath);
|
|
||||||
assertTrue(result.isSuccess() || result.getCode() == ResultCode.FILE_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Remove File
|
|
||||||
*/
|
|
||||||
public void testRemoveFile() {
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.removeFile(mFilePath);
|
|
||||||
assertTrue(result.isSuccess() || result.getCode() == ResultCode.FILE_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore initial conditions
|
|
||||||
*/
|
|
||||||
public void testRestoreInitialConditions() {
|
|
||||||
RemoteOperationResult result = mActivity.createFolder(mFolderPath, true);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework_test_project.test;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteFile;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework_test_project.TestActivity;
|
|
||||||
|
|
||||||
import android.test.ActivityInstrumentationTestCase2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to test Download File Operation
|
|
||||||
* @author masensio
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DownloadFileTest extends ActivityInstrumentationTestCase2<TestActivity> {
|
|
||||||
|
|
||||||
|
|
||||||
/* Files to download. These files must exist on the account */
|
|
||||||
private final String mRemoteFilePng = "/fileToDownload.png";
|
|
||||||
private final String mRemoteFileChunks = "/fileToDownload.mp4";
|
|
||||||
private final String mRemoteFileSpecialChars = "/@file@download.png";
|
|
||||||
private final String mRemoteFileSpecialCharsChunks = "/@file@download.mp4";
|
|
||||||
private final String mRemoteFileNotFound = "/fileNotFound.png"; /* This file mustn't exist on the account */
|
|
||||||
|
|
||||||
private String mCurrentDate;
|
|
||||||
|
|
||||||
|
|
||||||
private TestActivity mActivity;
|
|
||||||
|
|
||||||
public DownloadFileTest() {
|
|
||||||
super(TestActivity.class);
|
|
||||||
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
|
||||||
mCurrentDate = sdf.format(new Date());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
setActivityInitialTouchMode(false);
|
|
||||||
mActivity = getActivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Download a File
|
|
||||||
*/
|
|
||||||
public void testDownloadFile() {
|
|
||||||
String temporalFolder = "/download" + mCurrentDate;
|
|
||||||
|
|
||||||
RemoteFile remoteFile= new RemoteFile(mRemoteFilePng);
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.downloadFile(remoteFile, temporalFolder);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Download a File with chunks
|
|
||||||
*/
|
|
||||||
public void testDownloadFileChunks() {
|
|
||||||
String temporalFolder = "/download" + mCurrentDate;
|
|
||||||
|
|
||||||
RemoteFile remoteFile= new RemoteFile(mRemoteFileChunks);
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.downloadFile(remoteFile, temporalFolder);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Download a File with special chars
|
|
||||||
*/
|
|
||||||
public void testDownloadFileSpecialChars() {
|
|
||||||
String temporalFolder = "/download" + mCurrentDate;
|
|
||||||
|
|
||||||
RemoteFile remoteFile= new RemoteFile(mRemoteFileSpecialChars);
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.downloadFile(remoteFile, temporalFolder);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Download a File with special chars and chunks
|
|
||||||
*/
|
|
||||||
public void testDownloadFileSpecialCharsChunks() {
|
|
||||||
String temporalFolder = "/download" + mCurrentDate;
|
|
||||||
|
|
||||||
RemoteFile remoteFile= new RemoteFile(mRemoteFileSpecialCharsChunks);
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.downloadFile(remoteFile, temporalFolder);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Download a Not Found File
|
|
||||||
*/
|
|
||||||
public void testDownloadFileNotFound() {
|
|
||||||
String temporalFolder = "/download" + mCurrentDate;
|
|
||||||
|
|
||||||
RemoteFile remoteFile = new RemoteFile(mRemoteFileNotFound);
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.downloadFile(remoteFile, temporalFolder);
|
|
||||||
assertFalse(result.isSuccess());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework_test_project.test;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework_test_project.TestActivity;
|
|
||||||
|
|
||||||
import android.test.ActivityInstrumentationTestCase2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to test Read File Operation
|
|
||||||
* @author masensio
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ReadFileTest extends ActivityInstrumentationTestCase2<TestActivity> {
|
|
||||||
|
|
||||||
/* File data to read. This file must exist on the account */
|
|
||||||
private final String mRemoteFolderPath = "/fileToRead.txt";
|
|
||||||
|
|
||||||
|
|
||||||
private TestActivity mActivity;
|
|
||||||
|
|
||||||
public ReadFileTest() {
|
|
||||||
super(TestActivity.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
setActivityInitialTouchMode(false);
|
|
||||||
mActivity = getActivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Read File
|
|
||||||
*/
|
|
||||||
public void testReadFile() {
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.readFile(mRemoteFolderPath);
|
|
||||||
assertTrue(result.getData().size() == 1);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework_test_project.test;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework_test_project.TestActivity;
|
|
||||||
|
|
||||||
import android.test.ActivityInstrumentationTestCase2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to test Read Folder Operation
|
|
||||||
* @author masensio
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ReadFolderTest extends ActivityInstrumentationTestCase2<TestActivity> {
|
|
||||||
|
|
||||||
|
|
||||||
/* Folder data to read. This folder must exist on the account */
|
|
||||||
private final String mRemoteFolderPath = "/folderToRead";
|
|
||||||
|
|
||||||
|
|
||||||
private TestActivity mActivity;
|
|
||||||
|
|
||||||
public ReadFolderTest() {
|
|
||||||
super(TestActivity.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
setActivityInitialTouchMode(false);
|
|
||||||
mActivity = getActivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Read Folder
|
|
||||||
*/
|
|
||||||
public void testReadFolder() {
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.readFile(mRemoteFolderPath);
|
|
||||||
assertTrue(result.getData().size() > 1);
|
|
||||||
assertTrue(result.getData().size() == 4);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,170 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework_test_project.test;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult.ResultCode;
|
|
||||||
import com.owncloud.android.oc_framework_test_project.TestActivity;
|
|
||||||
|
|
||||||
import android.test.ActivityInstrumentationTestCase2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to test Rename File Operation
|
|
||||||
* @author masensio
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class RenameFileTest extends ActivityInstrumentationTestCase2<TestActivity> {
|
|
||||||
|
|
||||||
/* Folder data to rename. This folder must exist on the account */
|
|
||||||
private final String mOldFolderName = "folderToRename";
|
|
||||||
private final String mOldFolderPath = "/folderToRename";
|
|
||||||
private final String mNewFolderName = "renamedFolder";
|
|
||||||
private final String mNewFolderPath = "/renamedFolder";
|
|
||||||
|
|
||||||
/* File data to rename. This file must exist on the account */
|
|
||||||
private final String mOldFileName = "fileToRename.png";
|
|
||||||
private final String mOldFilePath = "/fileToRename.png";
|
|
||||||
private final String mNewFileName = "renamedFile";
|
|
||||||
private final String mFileExtension = ".png";
|
|
||||||
private final String mNewFilePath ="/renamedFile.png";
|
|
||||||
|
|
||||||
|
|
||||||
private TestActivity mActivity;
|
|
||||||
|
|
||||||
public RenameFileTest() {
|
|
||||||
super(TestActivity.class);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
setActivityInitialTouchMode(false);
|
|
||||||
mActivity = getActivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Rename Folder
|
|
||||||
*/
|
|
||||||
public void testRenameFolder() {
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.renameFile(mOldFolderName, mOldFolderPath,
|
|
||||||
mNewFolderName, true);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Rename Folder with forbidden characters : \ < > : " | ? *
|
|
||||||
*/
|
|
||||||
public void testRenameFolderForbiddenChars() {
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.renameFile(mOldFolderName, mOldFolderPath,
|
|
||||||
mNewFolderName + "\\", true);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFolderName, mOldFolderPath,
|
|
||||||
mNewFolderName + "<", true);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFolderName, mOldFolderPath,
|
|
||||||
mNewFolderName + ">", true);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFolderName, mOldFolderPath,
|
|
||||||
mNewFolderName + ":", true);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFolderName, mOldFolderPath,
|
|
||||||
mNewFolderName + "\"", true);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFolderName, mOldFolderPath,
|
|
||||||
mNewFolderName + "|", true);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFolderName, mOldFolderPath,
|
|
||||||
mNewFolderName + "?", true);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFolderName, mOldFolderPath,
|
|
||||||
mNewFolderName + "*", true);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Rename File
|
|
||||||
*/
|
|
||||||
public void testRenameFile() {
|
|
||||||
RemoteOperationResult result = mActivity.renameFile(mOldFileName, mOldFilePath,
|
|
||||||
mNewFileName + mFileExtension, false);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Rename Folder with forbidden characters: \ < > : " | ? *
|
|
||||||
*/
|
|
||||||
public void testRenameFileForbiddenChars() {
|
|
||||||
RemoteOperationResult result = mActivity.renameFile(mOldFileName, mOldFilePath,
|
|
||||||
mNewFileName + "\\" + mFileExtension, false);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFileName, mOldFilePath,
|
|
||||||
mNewFileName + "<" + mFileExtension, false);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFileName, mOldFilePath,
|
|
||||||
mNewFileName + ">" + mFileExtension, false);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFileName, mOldFilePath,
|
|
||||||
mNewFileName + ":" + mFileExtension, false);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFileName, mOldFilePath,
|
|
||||||
mNewFileName + "\"" + mFileExtension, false);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFileName, mOldFilePath,
|
|
||||||
mNewFileName + "|" + mFileExtension, false);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFileName, mOldFilePath,
|
|
||||||
mNewFileName + "?" + mFileExtension, false);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mOldFileName, mOldFilePath,
|
|
||||||
mNewFileName + "*" + mFileExtension, false);
|
|
||||||
assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore initial conditions
|
|
||||||
*/
|
|
||||||
public void testRestoreInitialConditions() {
|
|
||||||
RemoteOperationResult result = mActivity.renameFile(mNewFolderName, mNewFolderPath, mOldFolderName, true);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
|
|
||||||
result = mActivity.renameFile(mNewFileName + mFileExtension, mNewFilePath, mOldFileName, false);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,161 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework_test_project.test;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import android.content.res.AssetManager;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.test.ActivityInstrumentationTestCase2;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework_test_project.TestActivity;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to test Update File Operation
|
|
||||||
* @author masensio
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class UploadFileTest extends ActivityInstrumentationTestCase2<TestActivity> {
|
|
||||||
|
|
||||||
/* Files to upload. These files must exists on the device */
|
|
||||||
private final String mFileToUpload = "fileToUpload.png";
|
|
||||||
private final String mMimeType = "image/png";
|
|
||||||
|
|
||||||
private final String mFileToUploadWithChunks = "fileToUploadChunks.MP4";
|
|
||||||
private final String mMimeTypeWithChunks = "video/mp4";
|
|
||||||
|
|
||||||
private final String mFileNotFound = "fileNotFound.png";
|
|
||||||
|
|
||||||
private final String mStoragePath = "/owncloud/tmp/uploadTest";
|
|
||||||
private String mPath;
|
|
||||||
|
|
||||||
private String mCurrentDate;
|
|
||||||
|
|
||||||
private TestActivity mActivity;
|
|
||||||
|
|
||||||
public UploadFileTest() {
|
|
||||||
super(TestActivity.class);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
setActivityInitialTouchMode(false);
|
|
||||||
mActivity = getActivity();
|
|
||||||
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
|
||||||
mCurrentDate = sdf.format(new Date());
|
|
||||||
|
|
||||||
File sdCard = Environment.getExternalStorageDirectory();
|
|
||||||
mPath = sdCard.getAbsolutePath() + "/" + mStoragePath + mCurrentDate;
|
|
||||||
|
|
||||||
//mActivity.createFolder(mPath, true);
|
|
||||||
|
|
||||||
copyAssets();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy Files to ulpload to SdCard
|
|
||||||
*/
|
|
||||||
private void copyAssets() {
|
|
||||||
AssetManager assetManager = getActivity().getAssets();
|
|
||||||
String[] files = { mFileToUpload, mFileToUploadWithChunks };
|
|
||||||
|
|
||||||
// Folder with contents
|
|
||||||
File folder = new File(mPath);
|
|
||||||
folder.mkdirs();
|
|
||||||
|
|
||||||
|
|
||||||
for(String filename : files) {
|
|
||||||
InputStream in = null;
|
|
||||||
OutputStream out = null;
|
|
||||||
try {
|
|
||||||
in = assetManager.open(filename);
|
|
||||||
File outFile = new File(folder, filename);
|
|
||||||
out = new FileOutputStream(outFile);
|
|
||||||
copyFile(in, out);
|
|
||||||
in.close();
|
|
||||||
in = null;
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
out = null;
|
|
||||||
} catch(IOException e) {
|
|
||||||
Log.e("tag", "Failed to copy asset file: " + filename, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void copyFile(InputStream in, OutputStream out) throws IOException {
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int read;
|
|
||||||
while((read = in.read(buffer)) != -1){
|
|
||||||
out.write(buffer, 0, read);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Upload File without chunks
|
|
||||||
*/
|
|
||||||
public void testUploadFile() {
|
|
||||||
|
|
||||||
String storagePath = mPath + "/" + mFileToUpload;
|
|
||||||
//String remotePath = "/uploadTest" + mCurrentDate + "/" + mFileToUpload;
|
|
||||||
String remotePath = "/" + mFileToUpload;
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.uploadFile(storagePath, remotePath, mMimeType);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Upload File with chunks
|
|
||||||
*/
|
|
||||||
public void testUploadFileWithChunks() {
|
|
||||||
|
|
||||||
String storagePath = mPath + "/" + mFileToUploadWithChunks;
|
|
||||||
//String remotePath = "/uploadTest" + mCurrentDate + "/" +mFileToUploadWithChunks;
|
|
||||||
String remotePath = "/" + mFileToUploadWithChunks;
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.uploadFile(storagePath, remotePath, mMimeTypeWithChunks);
|
|
||||||
assertTrue(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Upload Not Found File
|
|
||||||
*/
|
|
||||||
public void testUploadFileNotFound() {
|
|
||||||
|
|
||||||
String storagePath = mPath + "/" + mFileNotFound;
|
|
||||||
//String remotePath = "/uploadTest" + mCurrentDate + "/" + mFileToUpload;
|
|
||||||
String remotePath = "/" + mFileNotFound;
|
|
||||||
|
|
||||||
RemoteOperationResult result = mActivity.uploadFile(storagePath, remotePath, mMimeType);
|
|
||||||
assertFalse(result.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
# This file is automatically generated by Android Tools.
|
|
||||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
|
||||||
#
|
|
||||||
# This file must be checked in Version Control Systems.
|
|
||||||
#
|
|
||||||
# To customize properties used by the Ant build system edit
|
|
||||||
# "ant.properties", and override values to adapt the script to your
|
|
||||||
# project structure.
|
|
||||||
#
|
|
||||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
|
||||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
|
||||||
|
|
||||||
# Project target.
|
|
||||||
target=android-19
|
|
||||||
android.library.reference.1=../oc_framework
|
|
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 24 KiB |
|
@ -1,16 +0,0 @@
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
|
||||||
tools:context=".TestActivity" >
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/hello_world" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_settings"
|
|
||||||
android:orderInCategory="100"
|
|
||||||
android:showAsAction="never"
|
|
||||||
android:title="@string/action_settings"/>
|
|
||||||
|
|
||||||
</menu>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Customize dimensions originally defined in res/values/dimens.xml (such as
|
|
||||||
screen margins) for sw600dp devices (e.g. 7" tablets) here.
|
|
||||||
-->
|
|
||||||
|
|
||||||
</resources>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Customize dimensions originally defined in res/values/dimens.xml (such as
|
|
||||||
screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
|
|
||||||
-->
|
|
||||||
<dimen name="activity_horizontal_margin">128dp</dimen>
|
|
||||||
|
|
||||||
</resources>
|
|
|
@ -1,11 +0,0 @@
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Base application theme for API 11+. This theme completely replaces
|
|
||||||
AppBaseTheme from res/values/styles.xml on API 11+ devices.
|
|
||||||
-->
|
|
||||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
|
|
||||||
<!-- API 11 theme customizations can go here. -->
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
|
@ -1,12 +0,0 @@
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Base application theme for API 14+. This theme completely replaces
|
|
||||||
AppBaseTheme from BOTH res/values/styles.xml and
|
|
||||||
res/values-v11/styles.xml on API 14+ devices.
|
|
||||||
-->
|
|
||||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
|
||||||
<!-- API 14 theme customizations can go here. -->
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
|
||||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
|
||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
|
||||||
|
|
||||||
</resources>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<string name="app_name">oc_framework-test-project</string>
|
|
||||||
<string name="action_settings">Settings</string>
|
|
||||||
<string name="hello_world">Hello world!</string>
|
|
||||||
<string name="test_account_not_found">The test account %1$s could not be found in the device</string>
|
|
||||||
|
|
||||||
</resources>
|
|
|
@ -1,20 +0,0 @@
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Base application theme, dependent on API level. This theme is replaced
|
|
||||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
|
||||||
-->
|
|
||||||
<style name="AppBaseTheme" parent="android:Theme.Light">
|
|
||||||
<!--
|
|
||||||
Theme customizations available in newer API levels can go in
|
|
||||||
res/values-vXX/styles.xml, while customizations related to
|
|
||||||
backward-compatibility can go here.
|
|
||||||
-->
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!-- Application theme. -->
|
|
||||||
<style name="AppTheme" parent="AppBaseTheme">
|
|
||||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
|
@ -1,173 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework_test_project;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.OwnCloudClientFactory;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteFile;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework.operations.remote.ChunkedUploadRemoteFileOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.remote.CreateRemoteFolderOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.remote.DownloadRemoteFileOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.remote.ReadRemoteFolderOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.remote.RemoveRemoteFileOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.remote.RenameRemoteFileOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.remote.UploadRemoteFileOperation;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.view.Menu;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Activity to test OC framework
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class TestActivity extends Activity {
|
|
||||||
|
|
||||||
// This account must exists on the simulator / device
|
|
||||||
private static final String mServerUri = "https://beta.owncloud.com/owncloud/remote.php/webdav";
|
|
||||||
private static final String mUser = "testandroid";
|
|
||||||
private static final String mPass = "testandroid";
|
|
||||||
private static final boolean mChunked = true;
|
|
||||||
|
|
||||||
//private Account mAccount = null;
|
|
||||||
private WebdavClient mClient;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_test);
|
|
||||||
Uri uri = Uri.parse(mServerUri);
|
|
||||||
mClient = OwnCloudClientFactory.createOwnCloudClient(uri ,getApplicationContext(), true);
|
|
||||||
mClient.setBasicCredentials(mUser, mPass);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
// Inflate the menu; this adds items to the action bar if it is present.
|
|
||||||
getMenuInflater().inflate(R.menu.test, menu);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Access to the library method to Create a Folder
|
|
||||||
* @param remotePath Full path to the new directory to create in the remote server.
|
|
||||||
* @param createFullPath 'True' means that all the ancestor folders should be created if don't exist yet.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public RemoteOperationResult createFolder(String remotePath, boolean createFullPath) {
|
|
||||||
|
|
||||||
CreateRemoteFolderOperation createOperation = new CreateRemoteFolderOperation(remotePath, createFullPath);
|
|
||||||
RemoteOperationResult result = createOperation.execute(mClient);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Access to the library method to Rename a File or Folder
|
|
||||||
* @param oldName Old name of the file.
|
|
||||||
* @param oldRemotePath Old remote path of the file. For folders it starts and ends by "/"
|
|
||||||
* @param newName New name to set as the name of file.
|
|
||||||
* @param isFolder 'true' for folder and 'false' for files
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
|
|
||||||
public RemoteOperationResult renameFile(String oldName, String oldRemotePath, String newName, boolean isFolder) {
|
|
||||||
|
|
||||||
RenameRemoteFileOperation renameOperation = new RenameRemoteFileOperation(oldName, oldRemotePath, newName, isFolder);
|
|
||||||
RemoteOperationResult result = renameOperation.execute(mClient);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Access to the library method to Remove a File or Folder
|
|
||||||
*
|
|
||||||
* @param remotePath Remote path of the file or folder in the server.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public RemoteOperationResult removeFile(String remotePath) {
|
|
||||||
|
|
||||||
RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath);
|
|
||||||
RemoteOperationResult result = removeOperation.execute(mClient);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Access to the library method to Read a Folder (PROPFIND DEPTH 1)
|
|
||||||
* @param remotePath
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public RemoteOperationResult readFile(String remotePath) {
|
|
||||||
|
|
||||||
ReadRemoteFolderOperation readOperation= new ReadRemoteFolderOperation(remotePath);
|
|
||||||
RemoteOperationResult result = readOperation.execute(mClient);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Access to the library method to Download a File
|
|
||||||
* @param remotePath
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public RemoteOperationResult downloadFile(RemoteFile remoteFile, String temporalFolder) {
|
|
||||||
// Create folder
|
|
||||||
String path = "/owncloud/tmp/" + temporalFolder;
|
|
||||||
File sdCard = Environment.getExternalStorageDirectory();
|
|
||||||
File folder = new File(sdCard.getAbsolutePath() + "/" + path);
|
|
||||||
folder.mkdirs();
|
|
||||||
|
|
||||||
DownloadRemoteFileOperation downloadOperation = new DownloadRemoteFileOperation(remoteFile, folder.getAbsolutePath());
|
|
||||||
RemoteOperationResult result = downloadOperation.execute(mClient);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Access to the library method to Upload a File
|
|
||||||
* @param storagePath
|
|
||||||
* @param remotePath
|
|
||||||
* @param mimeType
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public RemoteOperationResult uploadFile(String storagePath, String remotePath, String mimeType) {
|
|
||||||
|
|
||||||
UploadRemoteFileOperation uploadOperation;
|
|
||||||
if ( mChunked && (new File(storagePath)).length() > ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) {
|
|
||||||
uploadOperation = new ChunkedUploadRemoteFileOperation(storagePath, remotePath, mimeType);
|
|
||||||
} else {
|
|
||||||
uploadOperation = new UploadRemoteFileOperation(storagePath, remotePath, mimeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoteOperationResult result = uploadOperation.execute(mClient);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<classpath>
|
|
||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
|
||||||
<classpathentry kind="src" path="src"/>
|
|
||||||
<classpathentry kind="src" path="gen"/>
|
|
||||||
<classpathentry kind="output" path="bin/classes"/>
|
|
||||||
</classpath>
|
|
|
@ -1,33 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<projectDescription>
|
|
||||||
<name>oc_framework</name>
|
|
||||||
<comment></comment>
|
|
||||||
<projects>
|
|
||||||
</projects>
|
|
||||||
<buildSpec>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
</buildSpec>
|
|
||||||
<natures>
|
|
||||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
|
||||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
|
||||||
</natures>
|
|
||||||
</projectDescription>
|
|
|
@ -1,4 +0,0 @@
|
||||||
eclipse.preferences.version=1
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
|
||||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
|
||||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.owncloud.android.oc_framework"
|
|
||||||
android:versionCode="1"
|
|
||||||
android:versionName="1.0" >
|
|
||||||
|
|
||||||
<uses-sdk
|
|
||||||
android:minSdkVersion="8"
|
|
||||||
android:targetSdkVersion="19" />
|
|
||||||
|
|
||||||
</manifest>
|
|
|
@ -1,92 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project name="ownCloudFramework" default="help">
|
|
||||||
|
|
||||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
|
||||||
It contains the path to the SDK. It should *NOT* be checked into
|
|
||||||
Version Control Systems. -->
|
|
||||||
<property file="local.properties" />
|
|
||||||
|
|
||||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
|
||||||
'android' tool to add properties to it.
|
|
||||||
This is the place to change some Ant specific build properties.
|
|
||||||
Here are some properties you may want to change/update:
|
|
||||||
|
|
||||||
source.dir
|
|
||||||
The name of the source directory. Default is 'src'.
|
|
||||||
out.dir
|
|
||||||
The name of the output directory. Default is 'bin'.
|
|
||||||
|
|
||||||
For other overridable properties, look at the beginning of the rules
|
|
||||||
files in the SDK, at tools/ant/build.xml
|
|
||||||
|
|
||||||
Properties related to the SDK location or the project target should
|
|
||||||
be updated using the 'android' tool with the 'update' action.
|
|
||||||
|
|
||||||
This file is an integral part of the build system for your
|
|
||||||
application and should be checked into Version Control Systems.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<property file="ant.properties" />
|
|
||||||
|
|
||||||
<!-- if sdk.dir was not set from one of the property file, then
|
|
||||||
get it from the ANDROID_HOME env var.
|
|
||||||
This must be done before we load project.properties since
|
|
||||||
the proguard config can use sdk.dir -->
|
|
||||||
<property environment="env" />
|
|
||||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
|
||||||
<isset property="env.ANDROID_HOME" />
|
|
||||||
</condition>
|
|
||||||
|
|
||||||
<!-- The project.properties file is created and updated by the 'android'
|
|
||||||
tool, as well as ADT.
|
|
||||||
|
|
||||||
This contains project specific properties such as project target, and library
|
|
||||||
dependencies. Lower level build properties are stored in ant.properties
|
|
||||||
(or in .classpath for Eclipse projects).
|
|
||||||
|
|
||||||
This file is an integral part of the build system for your
|
|
||||||
application and should be checked into Version Control Systems. -->
|
|
||||||
<loadproperties srcFile="project.properties" />
|
|
||||||
|
|
||||||
<!-- quick check on sdk.dir -->
|
|
||||||
<fail
|
|
||||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
|
||||||
unless="sdk.dir"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Import per project custom build rules if present at the root of the project.
|
|
||||||
This is the place to put custom intermediary targets such as:
|
|
||||||
-pre-build
|
|
||||||
-pre-compile
|
|
||||||
-post-compile (This is typically used for code obfuscation.
|
|
||||||
Compiled code location: ${out.classes.absolute.dir}
|
|
||||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
|
||||||
-post-package
|
|
||||||
-post-build
|
|
||||||
-pre-clean
|
|
||||||
-->
|
|
||||||
<import file="custom_rules.xml" optional="true" />
|
|
||||||
|
|
||||||
<!-- Import the actual build file.
|
|
||||||
|
|
||||||
To customize existing targets, there are two options:
|
|
||||||
- Customize only one target:
|
|
||||||
- copy/paste the target into this file, *before* the
|
|
||||||
<import> task.
|
|
||||||
- customize it to your needs.
|
|
||||||
- Customize the whole content of build.xml
|
|
||||||
- copy/paste the content of the rules files (minus the top node)
|
|
||||||
into this file, replacing the <import> task.
|
|
||||||
- customize to your needs.
|
|
||||||
|
|
||||||
***********************
|
|
||||||
****** IMPORTANT ******
|
|
||||||
***********************
|
|
||||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
|
||||||
in order to avoid having your file be overridden by tools such as "android update project"
|
|
||||||
-->
|
|
||||||
<!-- version-tag: 1 -->
|
|
||||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
|
||||||
|
|
||||||
</project>
|
|
|
@ -1,75 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>com.owncloud.android</groupId>
|
|
||||||
<artifactId>oc_framework</artifactId>
|
|
||||||
<version>${owncloud.version}</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<name>oc_framework for Owncloud Android</name>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<owncloud.version>1.5.1-SNAPSHOT</owncloud.version>
|
|
||||||
<java-version>1.6</java-version>
|
|
||||||
<!-- Given by maven-android-sdk-deployer -->
|
|
||||||
<google.android-version>4.4_r1</google.android-version>
|
|
||||||
<!-- Usually the latest Android API -->
|
|
||||||
<google.android-api>19</google.android-api>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<description>oc_framwork for Owncloud for Android</description>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>android</groupId>
|
|
||||||
<artifactId>android</artifactId>
|
|
||||||
<version>${google.android-version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.jackrabbit</groupId>
|
|
||||||
<artifactId>jackrabbit-webdav</artifactId>
|
|
||||||
<version>2.7.2</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<finalName>${project.artifactId}</finalName>
|
|
||||||
|
|
||||||
<sourceDirectory>src</sourceDirectory>
|
|
||||||
|
|
||||||
<plugins>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.0</version>
|
|
||||||
<configuration>
|
|
||||||
<source>${java-version}</source>
|
|
||||||
<target>${java-version}</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
|
|
||||||
<artifactId>android-maven-plugin</artifactId>
|
|
||||||
<version>3.8.0</version>
|
|
||||||
<configuration>
|
|
||||||
<sdk>
|
|
||||||
<path>${env.ANDROID_HOME}</path>
|
|
||||||
<platform>${google.android-api}</platform>
|
|
||||||
</sdk>
|
|
||||||
</configuration>
|
|
||||||
<extensions>true</extensions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
# This file is automatically generated by Android Tools.
|
|
||||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
|
||||||
#
|
|
||||||
# This file must be checked in Version Control Systems.
|
|
||||||
#
|
|
||||||
# To customize properties used by the Ant build system edit
|
|
||||||
# "ant.properties", and override values to adapt the script to your
|
|
||||||
# project structure.
|
|
||||||
#
|
|
||||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
|
||||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
|
||||||
|
|
||||||
# Project target.
|
|
||||||
target=android-19
|
|
||||||
android.library=true
|
|
|
@ -1,2 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources/>
|
|
|
@ -1,43 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.accounts;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author masensio
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
public class AccountTypeUtils {
|
|
||||||
|
|
||||||
public static String getAuthTokenTypePass(String accountType) {
|
|
||||||
return accountType + ".password";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getAuthTokenTypeAccessToken(String accountType) {
|
|
||||||
return accountType + ".oauth2.access_token";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getAuthTokenTypeRefreshToken(String accountType) {
|
|
||||||
return accountType + ".oauth2.refresh_token";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getAuthTokenTypeSamlSessionCookie(String accountType) {
|
|
||||||
return accountType + ".saml.web_sso.session_cookie";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.accounts;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.utils.OwnCloudVersion;
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.accounts.AccountManager;
|
|
||||||
import android.accounts.AccountsException;
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
public class AccountUtils {
|
|
||||||
public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";
|
|
||||||
public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";
|
|
||||||
public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav";
|
|
||||||
private static final String ODAV_PATH = "/remote.php/odav";
|
|
||||||
private static final String SAML_SSO_PATH = "/remote.php/webdav";
|
|
||||||
public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";
|
|
||||||
public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php";
|
|
||||||
public static final String STATUS_PATH = "/status.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param version version of owncloud
|
|
||||||
* @return webdav path for given OC version, null if OC version unknown
|
|
||||||
*/
|
|
||||||
public static String getWebdavPath(OwnCloudVersion version, boolean supportsOAuth, boolean supportsSamlSso) {
|
|
||||||
if (version != null) {
|
|
||||||
if (supportsOAuth) {
|
|
||||||
return ODAV_PATH;
|
|
||||||
}
|
|
||||||
if (supportsSamlSso) {
|
|
||||||
return SAML_SSO_PATH;
|
|
||||||
}
|
|
||||||
if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0)
|
|
||||||
return WEBDAV_PATH_4_0;
|
|
||||||
if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0
|
|
||||||
|| version.compareTo(OwnCloudVersion.owncloud_v2) >= 0)
|
|
||||||
return WEBDAV_PATH_2_0;
|
|
||||||
if (version.compareTo(OwnCloudVersion.owncloud_v1) >= 0)
|
|
||||||
return WEBDAV_PATH_1_2;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Returns the proper URL path to access the WebDAV interface of an ownCloud server,
|
|
||||||
// * according to its version and the authorization method used.
|
|
||||||
// *
|
|
||||||
// * @param version Version of ownCloud server.
|
|
||||||
// * @param authTokenType Authorization token type, matching some of the AUTH_TOKEN_TYPE_* constants in {@link AccountAuthenticator}.
|
|
||||||
// * @return WebDAV path for given OC version and authorization method, null if OC version is unknown.
|
|
||||||
// */
|
|
||||||
// public static String getWebdavPath(OwnCloudVersion version, String authTokenType) {
|
|
||||||
// if (version != null) {
|
|
||||||
// if (MainApp.getAuthTokenTypeAccessToken().equals(authTokenType)) {
|
|
||||||
// return ODAV_PATH;
|
|
||||||
// }
|
|
||||||
// if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(authTokenType)) {
|
|
||||||
// return SAML_SSO_PATH;
|
|
||||||
// }
|
|
||||||
// if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0)
|
|
||||||
// return WEBDAV_PATH_4_0;
|
|
||||||
// if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0
|
|
||||||
// || version.compareTo(OwnCloudVersion.owncloud_v2) >= 0)
|
|
||||||
// return WEBDAV_PATH_2_0;
|
|
||||||
// if (version.compareTo(OwnCloudVersion.owncloud_v1) >= 0)
|
|
||||||
// return WEBDAV_PATH_1_2;
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs full url to host and webdav resource basing on host version
|
|
||||||
* @param context
|
|
||||||
* @param account
|
|
||||||
* @return url or null on failure
|
|
||||||
* @throws AccountNotFoundException When 'account' is unknown for the AccountManager
|
|
||||||
*/
|
|
||||||
public static String constructFullURLForAccount(Context context, Account account) throws AccountNotFoundException {
|
|
||||||
AccountManager ama = AccountManager.get(context);
|
|
||||||
String baseurl = ama.getUserData(account, OwnCloudAccount.Constants.KEY_OC_BASE_URL);
|
|
||||||
String strver = ama.getUserData(account, OwnCloudAccount.Constants.KEY_OC_VERSION);
|
|
||||||
boolean supportsOAuth = (ama.getUserData(account, OwnCloudAccount.Constants.KEY_SUPPORTS_OAUTH2) != null);
|
|
||||||
boolean supportsSamlSso = (ama.getUserData(account, OwnCloudAccount.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null);
|
|
||||||
OwnCloudVersion ver = new OwnCloudVersion(strver);
|
|
||||||
String webdavpath = getWebdavPath(ver, supportsOAuth, supportsSamlSso);
|
|
||||||
|
|
||||||
if (baseurl == null || webdavpath == null)
|
|
||||||
throw new AccountNotFoundException(account, "Account not found", null);
|
|
||||||
|
|
||||||
return baseurl + webdavpath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class AccountNotFoundException extends AccountsException {
|
|
||||||
|
|
||||||
/** Generated - should be refreshed every time the class changes!! */
|
|
||||||
private static final long serialVersionUID = -1684392454798508693L;
|
|
||||||
|
|
||||||
private Account mFailedAccount;
|
|
||||||
|
|
||||||
public AccountNotFoundException(Account failedAccount, String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
mFailedAccount = failedAccount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Account getFailedAccount() {
|
|
||||||
return mFailedAccount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,289 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.network;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
//import java.security.Provider;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
//import java.util.Enumeration;
|
|
||||||
|
|
||||||
import javax.net.SocketFactory;
|
|
||||||
import javax.net.ssl.SSLContext;
|
|
||||||
import javax.net.ssl.SSLException;
|
|
||||||
import javax.net.ssl.SSLHandshakeException;
|
|
||||||
//import javax.net.ssl.SSLParameters;
|
|
||||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
|
||||||
import javax.net.ssl.SSLSession;
|
|
||||||
import javax.net.ssl.SSLSocket;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.ConnectTimeoutException;
|
|
||||||
import org.apache.commons.httpclient.params.HttpConnectionParams;
|
|
||||||
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
|
|
||||||
import org.apache.http.conn.ssl.X509HostnameVerifier;
|
|
||||||
|
|
||||||
//import android.os.Build;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AdvancedSSLProtocolSocketFactory allows to create SSL {@link Socket}s with
|
|
||||||
* a custom SSLContext and an optional Hostname Verifier.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class AdvancedSslSocketFactory implements ProtocolSocketFactory {
|
|
||||||
|
|
||||||
private static final String TAG = AdvancedSslSocketFactory.class.getSimpleName();
|
|
||||||
|
|
||||||
private SSLContext mSslContext = null;
|
|
||||||
private AdvancedX509TrustManager mTrustManager = null;
|
|
||||||
private X509HostnameVerifier mHostnameVerifier = null;
|
|
||||||
|
|
||||||
public SSLContext getSslContext() {
|
|
||||||
return mSslContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for AdvancedSSLProtocolSocketFactory.
|
|
||||||
*/
|
|
||||||
public AdvancedSslSocketFactory(SSLContext sslContext, AdvancedX509TrustManager trustManager, X509HostnameVerifier hostnameVerifier) {
|
|
||||||
if (sslContext == null)
|
|
||||||
throw new IllegalArgumentException("AdvancedSslSocketFactory can not be created with a null SSLContext");
|
|
||||||
if (trustManager == null)
|
|
||||||
throw new IllegalArgumentException("AdvancedSslSocketFactory can not be created with a null Trust Manager");
|
|
||||||
mSslContext = sslContext;
|
|
||||||
mTrustManager = trustManager;
|
|
||||||
mHostnameVerifier = hostnameVerifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int)
|
|
||||||
*/
|
|
||||||
public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException {
|
|
||||||
Socket socket = mSslContext.getSocketFactory().createSocket(host, port, clientHost, clientPort);
|
|
||||||
verifyPeerIdentity(host, port, socket);
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
private void logSslInfo() {
|
|
||||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) {
|
|
||||||
Log.v(TAG, "SUPPORTED SSL PARAMETERS");
|
|
||||||
logSslParameters(mSslContext.getSupportedSSLParameters());
|
|
||||||
Log.v(TAG, "DEFAULT SSL PARAMETERS");
|
|
||||||
logSslParameters(mSslContext.getDefaultSSLParameters());
|
|
||||||
Log.i(TAG, "CURRENT PARAMETERS");
|
|
||||||
Log.i(TAG, "Protocol: " + mSslContext.getProtocol());
|
|
||||||
}
|
|
||||||
Log.i(TAG, "PROVIDER");
|
|
||||||
logSecurityProvider(mSslContext.getProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void logSecurityProvider(Provider provider) {
|
|
||||||
Log.i(TAG, "name: " + provider.getName());
|
|
||||||
Log.i(TAG, "version: " + provider.getVersion());
|
|
||||||
Log.i(TAG, "info: " + provider.getInfo());
|
|
||||||
Enumeration<?> keys = provider.propertyNames();
|
|
||||||
String key;
|
|
||||||
while (keys.hasMoreElements()) {
|
|
||||||
key = (String) keys.nextElement();
|
|
||||||
Log.i(TAG, " property " + key + " : " + provider.getProperty(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void logSslParameters(SSLParameters params) {
|
|
||||||
Log.v(TAG, "Cipher suites: ");
|
|
||||||
String [] elements = params.getCipherSuites();
|
|
||||||
for (int i=0; i<elements.length ; i++) {
|
|
||||||
Log.v(TAG, " " + elements[i]);
|
|
||||||
}
|
|
||||||
Log.v(TAG, "Protocols: ");
|
|
||||||
elements = params.getProtocols();
|
|
||||||
for (int i=0; i<elements.length ; i++) {
|
|
||||||
Log.v(TAG, " " + elements[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to get a new socket connection to the given host within the
|
|
||||||
* given time limit.
|
|
||||||
*
|
|
||||||
* @param host the host name/IP
|
|
||||||
* @param port the port on the host
|
|
||||||
* @param clientHost the local host name/IP to bind the socket to
|
|
||||||
* @param clientPort the port on the local machine
|
|
||||||
* @param params {@link HttpConnectionParams Http connection parameters}
|
|
||||||
*
|
|
||||||
* @return Socket a new socket
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs while creating the socket
|
|
||||||
* @throws UnknownHostException if the IP address of the host cannot be
|
|
||||||
* determined
|
|
||||||
*/
|
|
||||||
public Socket createSocket(final String host, final int port,
|
|
||||||
final InetAddress localAddress, final int localPort,
|
|
||||||
final HttpConnectionParams params) throws IOException,
|
|
||||||
UnknownHostException, ConnectTimeoutException {
|
|
||||||
Log.d(TAG, "Creating SSL Socket with remote " + host + ":" + port + ", local " + localAddress + ":" + localPort + ", params: " + params);
|
|
||||||
if (params == null) {
|
|
||||||
throw new IllegalArgumentException("Parameters may not be null");
|
|
||||||
}
|
|
||||||
int timeout = params.getConnectionTimeout();
|
|
||||||
|
|
||||||
//logSslInfo();
|
|
||||||
|
|
||||||
SocketFactory socketfactory = mSslContext.getSocketFactory();
|
|
||||||
Log.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout());
|
|
||||||
Socket socket = socketfactory.createSocket();
|
|
||||||
SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
|
|
||||||
SocketAddress remoteaddr = new InetSocketAddress(host, port);
|
|
||||||
socket.setSoTimeout(params.getSoTimeout());
|
|
||||||
socket.bind(localaddr);
|
|
||||||
ServerNameIndicator.setServerNameIndication(host, (SSLSocket)socket);
|
|
||||||
socket.connect(remoteaddr, timeout);
|
|
||||||
verifyPeerIdentity(host, port, socket);
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ProtocolSocketFactory#createSocket(java.lang.String,int)
|
|
||||||
*/
|
|
||||||
public Socket createSocket(String host, int port) throws IOException,
|
|
||||||
UnknownHostException {
|
|
||||||
Log.d(TAG, "Creating SSL Socket with remote " + host + ":" + port);
|
|
||||||
Socket socket = mSslContext.getSocketFactory().createSocket(host, port);
|
|
||||||
verifyPeerIdentity(host, port, socket);
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return ((obj != null) && obj.getClass().equals(
|
|
||||||
AdvancedSslSocketFactory.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return AdvancedSslSocketFactory.class.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public X509HostnameVerifier getHostNameVerifier() {
|
|
||||||
return mHostnameVerifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setHostNameVerifier(X509HostnameVerifier hostnameVerifier) {
|
|
||||||
mHostnameVerifier = hostnameVerifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifies the identity of the server.
|
|
||||||
*
|
|
||||||
* The server certificate is verified first.
|
|
||||||
*
|
|
||||||
* Then, the host name is compared with the content of the server certificate using the current host name verifier, if any.
|
|
||||||
* @param socket
|
|
||||||
*/
|
|
||||||
private void verifyPeerIdentity(String host, int port, Socket socket) throws IOException {
|
|
||||||
try {
|
|
||||||
CertificateCombinedException failInHandshake = null;
|
|
||||||
/// 1. VERIFY THE SERVER CERTIFICATE through the registered TrustManager (that should be an instance of AdvancedX509TrustManager)
|
|
||||||
try {
|
|
||||||
SSLSocket sock = (SSLSocket) socket; // a new SSLSession instance is created as a "side effect"
|
|
||||||
sock.startHandshake();
|
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
|
|
||||||
if (e instanceof CertificateCombinedException) {
|
|
||||||
failInHandshake = (CertificateCombinedException) e;
|
|
||||||
} else {
|
|
||||||
Throwable cause = e.getCause();
|
|
||||||
Throwable previousCause = null;
|
|
||||||
while (cause != null && cause != previousCause && !(cause instanceof CertificateCombinedException)) {
|
|
||||||
previousCause = cause;
|
|
||||||
cause = cause.getCause();
|
|
||||||
}
|
|
||||||
if (cause != null && cause instanceof CertificateCombinedException) {
|
|
||||||
failInHandshake = (CertificateCombinedException)cause;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (failInHandshake == null) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
failInHandshake.setHostInUrl(host);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 2. VERIFY HOSTNAME
|
|
||||||
SSLSession newSession = null;
|
|
||||||
boolean verifiedHostname = true;
|
|
||||||
if (mHostnameVerifier != null) {
|
|
||||||
if (failInHandshake != null) {
|
|
||||||
/// 2.1 : a new SSLSession instance was NOT created in the handshake
|
|
||||||
X509Certificate serverCert = failInHandshake.getServerCertificate();
|
|
||||||
try {
|
|
||||||
mHostnameVerifier.verify(host, serverCert);
|
|
||||||
} catch (SSLException e) {
|
|
||||||
verifiedHostname = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/// 2.2 : a new SSLSession instance was created in the handshake
|
|
||||||
newSession = ((SSLSocket)socket).getSession();
|
|
||||||
if (!mTrustManager.isKnownServer((X509Certificate)(newSession.getPeerCertificates()[0]))) {
|
|
||||||
verifiedHostname = mHostnameVerifier.verify(host, newSession);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 3. Combine the exceptions to throw, if any
|
|
||||||
if (!verifiedHostname) {
|
|
||||||
SSLPeerUnverifiedException pue = new SSLPeerUnverifiedException("Names in the server certificate do not match to " + host + " in the URL");
|
|
||||||
if (failInHandshake == null) {
|
|
||||||
failInHandshake = new CertificateCombinedException((X509Certificate) newSession.getPeerCertificates()[0]);
|
|
||||||
failInHandshake.setHostInUrl(host);
|
|
||||||
}
|
|
||||||
failInHandshake.setSslPeerUnverifiedException(pue);
|
|
||||||
pue.initCause(failInHandshake);
|
|
||||||
throw pue;
|
|
||||||
|
|
||||||
} else if (failInHandshake != null) {
|
|
||||||
SSLHandshakeException hse = new SSLHandshakeException("Server certificate could not be verified");
|
|
||||||
hse.initCause(failInHandshake);
|
|
||||||
throw hse;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException io) {
|
|
||||||
try {
|
|
||||||
socket.close();
|
|
||||||
} catch (Exception x) {
|
|
||||||
// NOTHING - irrelevant exception for the caller
|
|
||||||
}
|
|
||||||
throw io;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.network;
|
|
||||||
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.cert.CertPathValidatorException;
|
|
||||||
import java.security.cert.CertStoreException;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.CertificateExpiredException;
|
|
||||||
import java.security.cert.CertificateNotYetValidException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
public class AdvancedX509TrustManager implements X509TrustManager {
|
|
||||||
|
|
||||||
private static final String TAG = AdvancedX509TrustManager.class.getSimpleName();
|
|
||||||
|
|
||||||
private X509TrustManager mStandardTrustManager = null;
|
|
||||||
private KeyStore mKnownServersKeyStore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for AdvancedX509TrustManager
|
|
||||||
*
|
|
||||||
* @param knownServersCertStore Local certificates store with server certificates explicitly trusted by the user.
|
|
||||||
* @throws CertStoreException When no default X509TrustManager instance was found in the system.
|
|
||||||
*/
|
|
||||||
public AdvancedX509TrustManager(KeyStore knownServersKeyStore)
|
|
||||||
throws NoSuchAlgorithmException, KeyStoreException, CertStoreException {
|
|
||||||
super();
|
|
||||||
TrustManagerFactory factory = TrustManagerFactory
|
|
||||||
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
|
||||||
factory.init((KeyStore)null);
|
|
||||||
mStandardTrustManager = findX509TrustManager(factory);
|
|
||||||
|
|
||||||
mKnownServersKeyStore = knownServersKeyStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locates the first X509TrustManager provided by a given TrustManagerFactory
|
|
||||||
* @param factory TrustManagerFactory to inspect in the search for a X509TrustManager
|
|
||||||
* @return The first X509TrustManager found in factory.
|
|
||||||
* @throws CertStoreException When no X509TrustManager instance was found in factory
|
|
||||||
*/
|
|
||||||
private X509TrustManager findX509TrustManager(TrustManagerFactory factory) throws CertStoreException {
|
|
||||||
TrustManager tms[] = factory.getTrustManagers();
|
|
||||||
for (int i = 0; i < tms.length; i++) {
|
|
||||||
if (tms[i] instanceof X509TrustManager) {
|
|
||||||
return (X509TrustManager) tms[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],
|
|
||||||
* String authType)
|
|
||||||
*/
|
|
||||||
public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
|
|
||||||
mStandardTrustManager.checkClientTrusted(certificates, authType);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],
|
|
||||||
* String authType)
|
|
||||||
*/
|
|
||||||
public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
|
|
||||||
if (!isKnownServer(certificates[0])) {
|
|
||||||
CertificateCombinedException result = new CertificateCombinedException(certificates[0]);
|
|
||||||
try {
|
|
||||||
certificates[0].checkValidity();
|
|
||||||
} catch (CertificateExpiredException c) {
|
|
||||||
result.setCertificateExpiredException(c);
|
|
||||||
|
|
||||||
} catch (CertificateNotYetValidException c) {
|
|
||||||
result.setCertificateNotYetException(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
mStandardTrustManager.checkServerTrusted(certificates, authType);
|
|
||||||
} catch (CertificateException c) {
|
|
||||||
Throwable cause = c.getCause();
|
|
||||||
Throwable previousCause = null;
|
|
||||||
while (cause != null && cause != previousCause && !(cause instanceof CertPathValidatorException)) { // getCause() is not funny
|
|
||||||
previousCause = cause;
|
|
||||||
cause = cause.getCause();
|
|
||||||
}
|
|
||||||
if (cause != null && cause instanceof CertPathValidatorException) {
|
|
||||||
result.setCertPathValidatorException((CertPathValidatorException)cause);
|
|
||||||
} else {
|
|
||||||
result.setOtherCertificateException(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.isException())
|
|
||||||
throw result;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
|
|
||||||
*/
|
|
||||||
public X509Certificate[] getAcceptedIssuers() {
|
|
||||||
return mStandardTrustManager.getAcceptedIssuers();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isKnownServer(X509Certificate cert) {
|
|
||||||
try {
|
|
||||||
return (mKnownServersKeyStore.getCertificateAlias(cert) != null);
|
|
||||||
} catch (KeyStoreException e) {
|
|
||||||
Log.d(TAG, "Fail while checking certificate in the known-servers store");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,272 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 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.oc_framework.network;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.Credentials;
|
|
||||||
import org.apache.commons.httpclient.HttpMethod;
|
|
||||||
import org.apache.commons.httpclient.auth.AuthChallengeParser;
|
|
||||||
import org.apache.commons.httpclient.auth.AuthScheme;
|
|
||||||
import org.apache.commons.httpclient.auth.AuthenticationException;
|
|
||||||
import org.apache.commons.httpclient.auth.InvalidCredentialsException;
|
|
||||||
import org.apache.commons.httpclient.auth.MalformedChallengeException;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bearer authentication scheme as defined in RFC 6750.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class BearerAuthScheme implements AuthScheme /*extends RFC2617Scheme*/ {
|
|
||||||
|
|
||||||
private static final String TAG = BearerAuthScheme.class.getSimpleName();
|
|
||||||
|
|
||||||
public static final String AUTH_POLICY = "Bearer";
|
|
||||||
|
|
||||||
/** Whether the bearer authentication process is complete */
|
|
||||||
private boolean mComplete;
|
|
||||||
|
|
||||||
/** Authentication parameter map */
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
private Map mParams = null;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor for the bearer authentication scheme.
|
|
||||||
*/
|
|
||||||
public BearerAuthScheme() {
|
|
||||||
mComplete = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for the basic authentication scheme.
|
|
||||||
*
|
|
||||||
* @param challenge Authentication challenge
|
|
||||||
*
|
|
||||||
* @throws MalformedChallengeException Thrown if the authentication challenge is malformed
|
|
||||||
*
|
|
||||||
* @deprecated Use parameterless constructor and {@link AuthScheme#processChallenge(String)} method
|
|
||||||
*/
|
|
||||||
public BearerAuthScheme(final String challenge) throws MalformedChallengeException {
|
|
||||||
processChallenge(challenge);
|
|
||||||
mComplete = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns textual designation of the bearer authentication scheme.
|
|
||||||
*
|
|
||||||
* @return "Bearer"
|
|
||||||
*/
|
|
||||||
public String getSchemeName() {
|
|
||||||
return "bearer";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes the Bearer challenge.
|
|
||||||
*
|
|
||||||
* @param challenge The challenge string
|
|
||||||
*
|
|
||||||
* @throws MalformedChallengeException Thrown if the authentication challenge is malformed
|
|
||||||
*/
|
|
||||||
public void processChallenge(String challenge) throws MalformedChallengeException {
|
|
||||||
String s = AuthChallengeParser.extractScheme(challenge);
|
|
||||||
if (!s.equalsIgnoreCase(getSchemeName())) {
|
|
||||||
throw new MalformedChallengeException(
|
|
||||||
"Invalid " + getSchemeName() + " challenge: " + challenge);
|
|
||||||
}
|
|
||||||
mParams = AuthChallengeParser.extractParams(challenge);
|
|
||||||
mComplete = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests if the Bearer authentication process has been completed.
|
|
||||||
*
|
|
||||||
* @return 'true' if Bearer authorization has been processed, 'false' otherwise.
|
|
||||||
*/
|
|
||||||
public boolean isComplete() {
|
|
||||||
return this.mComplete;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Produces bearer authorization string for the given set of
|
|
||||||
* {@link Credentials}.
|
|
||||||
*
|
|
||||||
* @param credentials The set of credentials to be used for authentication
|
|
||||||
* @param method Method name is ignored by the bearer authentication scheme
|
|
||||||
* @param uri URI is ignored by the bearer authentication scheme
|
|
||||||
* @throws InvalidCredentialsException If authentication credentials are not valid or not applicable
|
|
||||||
* for this authentication scheme
|
|
||||||
* @throws AuthenticationException If authorization string cannot be generated due to an authentication failure
|
|
||||||
* @return A bearer authorization string
|
|
||||||
*
|
|
||||||
* @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
|
|
||||||
*/
|
|
||||||
public String authenticate(Credentials credentials, String method, String uri) throws AuthenticationException {
|
|
||||||
Log.d(TAG, "enter BearerScheme.authenticate(Credentials, String, String)");
|
|
||||||
|
|
||||||
BearerCredentials bearer = null;
|
|
||||||
try {
|
|
||||||
bearer = (BearerCredentials) credentials;
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
throw new InvalidCredentialsException(
|
|
||||||
"Credentials cannot be used for bearer authentication: "
|
|
||||||
+ credentials.getClass().getName());
|
|
||||||
}
|
|
||||||
return BearerAuthScheme.authenticate(bearer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns 'false'. Bearer authentication scheme is request based.
|
|
||||||
*
|
|
||||||
* @return 'false'.
|
|
||||||
*/
|
|
||||||
public boolean isConnectionBased() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Produces bearer authorization string for the given set of {@link Credentials}.
|
|
||||||
*
|
|
||||||
* @param credentials The set of credentials to be used for authentication
|
|
||||||
* @param method The method being authenticated
|
|
||||||
* @throws InvalidCredentialsException If authentication credentials are not valid or not applicable for this authentication
|
|
||||||
* scheme.
|
|
||||||
* @throws AuthenticationException If authorization string cannot be generated due to an authentication failure.
|
|
||||||
*
|
|
||||||
* @return a basic authorization string
|
|
||||||
*/
|
|
||||||
public String authenticate(Credentials credentials, HttpMethod method) throws AuthenticationException {
|
|
||||||
Log.d(TAG, "enter BearerScheme.authenticate(Credentials, HttpMethod)");
|
|
||||||
|
|
||||||
if (method == null) {
|
|
||||||
throw new IllegalArgumentException("Method may not be null");
|
|
||||||
}
|
|
||||||
BearerCredentials bearer = null;
|
|
||||||
try {
|
|
||||||
bearer = (BearerCredentials) credentials;
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
throw new InvalidCredentialsException(
|
|
||||||
"Credentials cannot be used for bearer authentication: "
|
|
||||||
+ credentials.getClass().getName());
|
|
||||||
}
|
|
||||||
return BearerAuthScheme.authenticate(
|
|
||||||
bearer,
|
|
||||||
method.getParams().getCredentialCharset());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use {@link #authenticate(BearerCredentials, String)}
|
|
||||||
*
|
|
||||||
* Returns a bearer Authorization header value for the given
|
|
||||||
* {@link BearerCredentials}.
|
|
||||||
*
|
|
||||||
* @param credentials The credentials to encode.
|
|
||||||
*
|
|
||||||
* @return A bearer authorization string
|
|
||||||
*/
|
|
||||||
public static String authenticate(BearerCredentials credentials) {
|
|
||||||
return authenticate(credentials, "ISO-8859-1");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a bearer Authorization header value for the given
|
|
||||||
* {@link BearerCredentials} and charset.
|
|
||||||
*
|
|
||||||
* @param credentials The credentials to encode.
|
|
||||||
* @param charset The charset to use for encoding the credentials
|
|
||||||
*
|
|
||||||
* @return A bearer authorization string
|
|
||||||
*
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
public static String authenticate(BearerCredentials credentials, String charset) {
|
|
||||||
Log.d(TAG, "enter BearerAuthScheme.authenticate(BearerCredentials, String)");
|
|
||||||
|
|
||||||
if (credentials == null) {
|
|
||||||
throw new IllegalArgumentException("Credentials may not be null");
|
|
||||||
}
|
|
||||||
if (charset == null || charset.length() == 0) {
|
|
||||||
throw new IllegalArgumentException("charset may not be null or empty");
|
|
||||||
}
|
|
||||||
StringBuffer buffer = new StringBuffer();
|
|
||||||
buffer.append(credentials.getAccessToken());
|
|
||||||
|
|
||||||
//return "Bearer " + EncodingUtil.getAsciiString(EncodingUtil.getBytes(buffer.toString(), charset));
|
|
||||||
return "Bearer " + buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a String identifying the authentication challenge. This is
|
|
||||||
* used, in combination with the host and port to determine if
|
|
||||||
* authorization has already been attempted or not. Schemes which
|
|
||||||
* require multiple requests to complete the authentication should
|
|
||||||
* return a different value for each stage in the request.
|
|
||||||
*
|
|
||||||
* Additionally, the ID should take into account any changes to the
|
|
||||||
* authentication challenge and return a different value when appropriate.
|
|
||||||
* For example when the realm changes in basic authentication it should be
|
|
||||||
* considered a different authentication attempt and a different value should
|
|
||||||
* be returned.
|
|
||||||
*
|
|
||||||
* This method simply returns the realm for the challenge.
|
|
||||||
*
|
|
||||||
* @return String a String identifying the authentication challenge.
|
|
||||||
*
|
|
||||||
* @deprecated no longer used
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getID() {
|
|
||||||
return getRealm();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns authentication parameter with the given name, if available.
|
|
||||||
*
|
|
||||||
* @param name The name of the parameter to be returned
|
|
||||||
*
|
|
||||||
* @return The parameter with the given name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getParameter(String name) {
|
|
||||||
if (name == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter name may not be null");
|
|
||||||
}
|
|
||||||
if (mParams == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (String) mParams.get(name.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns authentication realm. The realm may not be null.
|
|
||||||
*
|
|
||||||
* @return The authentication realm
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getRealm() {
|
|
||||||
return getParameter("realm");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
package com.owncloud.android.oc_framework.network;
|
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.Credentials;
|
|
||||||
import org.apache.commons.httpclient.util.LangUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bearer token {@link Credentials}
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
public class BearerCredentials implements Credentials {
|
|
||||||
|
|
||||||
|
|
||||||
private String mAccessToken;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The constructor with the bearer token
|
|
||||||
*
|
|
||||||
* @param token The bearer token
|
|
||||||
*/
|
|
||||||
public BearerCredentials(String token) {
|
|
||||||
/*if (token == null) {
|
|
||||||
throw new IllegalArgumentException("Bearer token may not be null");
|
|
||||||
}*/
|
|
||||||
mAccessToken = (token == null) ? "" : token;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the access token
|
|
||||||
*
|
|
||||||
* @return The access token
|
|
||||||
*/
|
|
||||||
public String getAccessToken() {
|
|
||||||
return mAccessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get this object string.
|
|
||||||
*
|
|
||||||
* @return The access token
|
|
||||||
*/
|
|
||||||
public String toString() {
|
|
||||||
return mAccessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does a hash of the access token.
|
|
||||||
*
|
|
||||||
* @return The hash code of the access token
|
|
||||||
*/
|
|
||||||
public int hashCode() {
|
|
||||||
int hash = LangUtils.HASH_SEED;
|
|
||||||
hash = LangUtils.hashCode(hash, mAccessToken);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These credentials are assumed equal if accessToken is the same.
|
|
||||||
*
|
|
||||||
* @param o The other object to compare with.
|
|
||||||
*
|
|
||||||
* @return 'True' if the object is equivalent.
|
|
||||||
*/
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (o == null) return false;
|
|
||||||
if (this == o) return true;
|
|
||||||
if (this.getClass().equals(o.getClass())) {
|
|
||||||
BearerCredentials that = (BearerCredentials) o;
|
|
||||||
if (LangUtils.equals(mAccessToken, that.mAccessToken)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
package com.owncloud.android.oc_framework.network;
|
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import java.security.cert.CertPathValidatorException;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.CertificateExpiredException;
|
|
||||||
import java.security.cert.CertificateNotYetValidException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception joining all the problems that {@link AdvancedX509TrustManager} can find in
|
|
||||||
* a certificate chain for a server.
|
|
||||||
*
|
|
||||||
* This was initially created as an extension of CertificateException, but some
|
|
||||||
* implementations of the SSL socket layer in existing devices are REPLACING the CertificateException
|
|
||||||
* instances thrown by {@link javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[], String)}
|
|
||||||
* with SSLPeerUnverifiedException FORGETTING THE CAUSING EXCEPTION instead of wrapping it.
|
|
||||||
*
|
|
||||||
* Due to this, extending RuntimeException is necessary to get that the CertificateCombinedException
|
|
||||||
* instance reaches {@link AdvancedSslSocketFactory#verifyPeerIdentity}.
|
|
||||||
*
|
|
||||||
* BE CAREFUL. As a RuntimeException extensions, Java compilers do not require to handle it
|
|
||||||
* in client methods. Be sure to use it only when you know exactly where it will go.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
public class CertificateCombinedException extends RuntimeException {
|
|
||||||
|
|
||||||
/** Generated - to refresh every time the class changes */
|
|
||||||
private static final long serialVersionUID = -8875782030758554999L;
|
|
||||||
|
|
||||||
private X509Certificate mServerCert = null;
|
|
||||||
private String mHostInUrl;
|
|
||||||
|
|
||||||
private CertificateExpiredException mCertificateExpiredException = null;
|
|
||||||
private CertificateNotYetValidException mCertificateNotYetValidException = null;
|
|
||||||
private CertPathValidatorException mCertPathValidatorException = null;
|
|
||||||
private CertificateException mOtherCertificateException = null;
|
|
||||||
private SSLPeerUnverifiedException mSslPeerUnverifiedException = null;
|
|
||||||
|
|
||||||
public CertificateCombinedException(X509Certificate x509Certificate) {
|
|
||||||
mServerCert = x509Certificate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public X509Certificate getServerCertificate() {
|
|
||||||
return mServerCert;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getHostInUrl() {
|
|
||||||
return mHostInUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHostInUrl(String host) {
|
|
||||||
mHostInUrl = host;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CertificateExpiredException getCertificateExpiredException() {
|
|
||||||
return mCertificateExpiredException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCertificateExpiredException(CertificateExpiredException c) {
|
|
||||||
mCertificateExpiredException = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CertificateNotYetValidException getCertificateNotYetValidException() {
|
|
||||||
return mCertificateNotYetValidException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCertificateNotYetException(CertificateNotYetValidException c) {
|
|
||||||
mCertificateNotYetValidException = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CertPathValidatorException getCertPathValidatorException() {
|
|
||||||
return mCertPathValidatorException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCertPathValidatorException(CertPathValidatorException c) {
|
|
||||||
mCertPathValidatorException = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CertificateException getOtherCertificateException() {
|
|
||||||
return mOtherCertificateException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOtherCertificateException(CertificateException c) {
|
|
||||||
mOtherCertificateException = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SSLPeerUnverifiedException getSslPeerUnverifiedException() {
|
|
||||||
return mSslPeerUnverifiedException ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSslPeerUnverifiedException(SSLPeerUnverifiedException s) {
|
|
||||||
mSslPeerUnverifiedException = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isException() {
|
|
||||||
return (mCertificateExpiredException != null ||
|
|
||||||
mCertificateNotYetValidException != null ||
|
|
||||||
mCertPathValidatorException != null ||
|
|
||||||
mOtherCertificateException != null ||
|
|
||||||
mSslPeerUnverifiedException != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRecoverable() {
|
|
||||||
return (mCertificateExpiredException != null ||
|
|
||||||
mCertificateNotYetValidException != null ||
|
|
||||||
mCertPathValidatorException != null ||
|
|
||||||
mSslPeerUnverifiedException != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,168 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.network;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
|
|
||||||
import org.apache.commons.httpclient.protocol.Protocol;
|
|
||||||
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
|
|
||||||
import org.apache.http.conn.ssl.X509HostnameVerifier;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
public class NetworkUtils {
|
|
||||||
|
|
||||||
final private static String TAG = NetworkUtils.class.getSimpleName();
|
|
||||||
|
|
||||||
/** Default timeout for waiting data from the server */
|
|
||||||
public static final int DEFAULT_DATA_TIMEOUT = 60000;
|
|
||||||
|
|
||||||
/** Default timeout for establishing a connection */
|
|
||||||
public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
|
|
||||||
|
|
||||||
/** Connection manager for all the WebdavClients */
|
|
||||||
private static MultiThreadedHttpConnectionManager mConnManager = null;
|
|
||||||
|
|
||||||
private static Protocol mDefaultHttpsProtocol = null;
|
|
||||||
|
|
||||||
private static AdvancedSslSocketFactory mAdvancedSslSocketFactory = null;
|
|
||||||
|
|
||||||
private static X509HostnameVerifier mHostnameVerifier = null;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers or unregisters the proper components for advanced SSL handling.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static void registerAdvancedSslContext(boolean register, Context context) throws GeneralSecurityException, IOException {
|
|
||||||
Protocol pr = null;
|
|
||||||
try {
|
|
||||||
pr = Protocol.getProtocol("https");
|
|
||||||
if (pr != null && mDefaultHttpsProtocol == null) {
|
|
||||||
mDefaultHttpsProtocol = pr;
|
|
||||||
}
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
// nothing to do here; really
|
|
||||||
}
|
|
||||||
boolean isRegistered = (pr != null && pr.getSocketFactory() instanceof AdvancedSslSocketFactory);
|
|
||||||
if (register && !isRegistered) {
|
|
||||||
Protocol.registerProtocol("https", new Protocol("https", getAdvancedSslSocketFactory(context), 443));
|
|
||||||
|
|
||||||
} else if (!register && isRegistered) {
|
|
||||||
if (mDefaultHttpsProtocol != null) {
|
|
||||||
Protocol.registerProtocol("https", mDefaultHttpsProtocol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AdvancedSslSocketFactory getAdvancedSslSocketFactory(Context context) throws GeneralSecurityException, IOException {
|
|
||||||
if (mAdvancedSslSocketFactory == null) {
|
|
||||||
KeyStore trustStore = getKnownServersStore(context);
|
|
||||||
AdvancedX509TrustManager trustMgr = new AdvancedX509TrustManager(trustStore);
|
|
||||||
TrustManager[] tms = new TrustManager[] { trustMgr };
|
|
||||||
|
|
||||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
|
||||||
sslContext.init(null, tms, null);
|
|
||||||
|
|
||||||
mHostnameVerifier = new BrowserCompatHostnameVerifier();
|
|
||||||
mAdvancedSslSocketFactory = new AdvancedSslSocketFactory(sslContext, trustMgr, mHostnameVerifier);
|
|
||||||
}
|
|
||||||
return mAdvancedSslSocketFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static String LOCAL_TRUSTSTORE_FILENAME = "knownServers.bks";
|
|
||||||
|
|
||||||
private static String LOCAL_TRUSTSTORE_PASSWORD = "password";
|
|
||||||
|
|
||||||
private static KeyStore mKnownServersStore = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the local store of reliable server certificates, explicitly accepted by the user.
|
|
||||||
*
|
|
||||||
* Returns a KeyStore instance with empty content if the local store was never created.
|
|
||||||
*
|
|
||||||
* Loads the store from the storage environment if needed.
|
|
||||||
*
|
|
||||||
* @param context Android context where the operation is being performed.
|
|
||||||
* @return KeyStore instance with explicitly-accepted server certificates.
|
|
||||||
* @throws KeyStoreException When the KeyStore instance could not be created.
|
|
||||||
* @throws IOException When an existing local trust store could not be loaded.
|
|
||||||
* @throws NoSuchAlgorithmException When the existing local trust store was saved with an unsupported algorithm.
|
|
||||||
* @throws CertificateException When an exception occurred while loading the certificates from the local trust store.
|
|
||||||
*/
|
|
||||||
private static KeyStore getKnownServersStore(Context context) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
|
|
||||||
if (mKnownServersStore == null) {
|
|
||||||
//mKnownServersStore = KeyStore.getInstance("BKS");
|
|
||||||
mKnownServersStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
|
||||||
File localTrustStoreFile = new File(context.getFilesDir(), LOCAL_TRUSTSTORE_FILENAME);
|
|
||||||
Log.d(TAG, "Searching known-servers store at " + localTrustStoreFile.getAbsolutePath());
|
|
||||||
if (localTrustStoreFile.exists()) {
|
|
||||||
InputStream in = new FileInputStream(localTrustStoreFile);
|
|
||||||
try {
|
|
||||||
mKnownServersStore.load(in, LOCAL_TRUSTSTORE_PASSWORD.toCharArray());
|
|
||||||
} finally {
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mKnownServersStore.load(null, LOCAL_TRUSTSTORE_PASSWORD.toCharArray()); // necessary to initialize an empty KeyStore instance
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mKnownServersStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void addCertToKnownServersStore(Certificate cert, Context context) throws KeyStoreException, NoSuchAlgorithmException,
|
|
||||||
CertificateException, IOException {
|
|
||||||
KeyStore knownServers = getKnownServersStore(context);
|
|
||||||
knownServers.setCertificateEntry(Integer.toString(cert.hashCode()), cert);
|
|
||||||
FileOutputStream fos = null;
|
|
||||||
try {
|
|
||||||
fos = context.openFileOutput(LOCAL_TRUSTSTORE_FILENAME, Context.MODE_PRIVATE);
|
|
||||||
knownServers.store(fos, LOCAL_TRUSTSTORE_PASSWORD.toCharArray());
|
|
||||||
} finally {
|
|
||||||
fos.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static public MultiThreadedHttpConnectionManager getMultiThreadedConnManager() {
|
|
||||||
if (mConnManager == null) {
|
|
||||||
mConnManager = new MultiThreadedHttpConnectionManager();
|
|
||||||
mConnManager.getParams().setDefaultMaxConnectionsPerHost(5);
|
|
||||||
mConnManager.getParams().setMaxTotalConnections(5);
|
|
||||||
}
|
|
||||||
return mConnManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package com.owncloud.android.oc_framework.network;
|
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.OnDatatransferProgressListener;
|
|
||||||
|
|
||||||
|
|
||||||
public interface ProgressiveDataTransferer {
|
|
||||||
|
|
||||||
public void addDatatransferProgressListener (OnDatatransferProgressListener listener);
|
|
||||||
|
|
||||||
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners);
|
|
||||||
|
|
||||||
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,144 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.network;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLSocket;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables the support of Server Name Indication if existing
|
|
||||||
* in the underlying network implementation.
|
|
||||||
*
|
|
||||||
* Build as a singleton.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
public class ServerNameIndicator {
|
|
||||||
|
|
||||||
private static final String TAG = ServerNameIndicator.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final AtomicReference<ServerNameIndicator> mSingleInstance = new AtomicReference<ServerNameIndicator>();
|
|
||||||
|
|
||||||
private static final String METHOD_NAME = "setHostname";
|
|
||||||
|
|
||||||
private final WeakReference<Class<?>> mSSLSocketClassRef;
|
|
||||||
private final WeakReference<Method> mSetHostnameMethodRef;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private constructor, class is a singleton.
|
|
||||||
*
|
|
||||||
* @param sslSocketClass Underlying implementation class of {@link SSLSocket} used to connect with the server.
|
|
||||||
* @param setHostnameMethod Name of the method to call to enable the SNI support.
|
|
||||||
*/
|
|
||||||
private ServerNameIndicator(Class<?> sslSocketClass, Method setHostnameMethod) {
|
|
||||||
mSSLSocketClassRef = new WeakReference<Class<?>>(sslSocketClass);
|
|
||||||
mSetHostnameMethodRef = (setHostnameMethod == null) ? null : new WeakReference<Method>(setHostnameMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the {@code #setHostname(String)} method of the underlying implementation
|
|
||||||
* of {@link SSLSocket} if exists.
|
|
||||||
*
|
|
||||||
* Creates and initializes the single instance of the class when needed
|
|
||||||
*
|
|
||||||
* @param hostname The name of the server host of interest.
|
|
||||||
* @param sslSocket Client socket to connect with the server.
|
|
||||||
*/
|
|
||||||
public static void setServerNameIndication(String hostname, SSLSocket sslSocket) {
|
|
||||||
final Method setHostnameMethod = getMethod(sslSocket);
|
|
||||||
if (setHostnameMethod != null) {
|
|
||||||
try {
|
|
||||||
setHostnameMethod.invoke(sslSocket, hostname);
|
|
||||||
Log.i(TAG, "SNI done, hostname: " + hostname);
|
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
Log.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
|
|
||||||
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
Log.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
|
|
||||||
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
Log.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "SNI not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the method to invoke trying to minimize the effective
|
|
||||||
* application of reflection.
|
|
||||||
*
|
|
||||||
* @param sslSocket Instance of the SSL socket to use in connection with server.
|
|
||||||
* @return Method to call to indicate the server name of interest to the server.
|
|
||||||
*/
|
|
||||||
private static Method getMethod(SSLSocket sslSocket) {
|
|
||||||
final Class<?> sslSocketClass = sslSocket.getClass();
|
|
||||||
final ServerNameIndicator instance = mSingleInstance.get();
|
|
||||||
if (instance == null) {
|
|
||||||
return initFrom(sslSocketClass);
|
|
||||||
|
|
||||||
} else if (instance.mSSLSocketClassRef.get() != sslSocketClass) {
|
|
||||||
// the underlying class changed
|
|
||||||
return initFrom(sslSocketClass);
|
|
||||||
|
|
||||||
} else if (instance.mSetHostnameMethodRef == null) {
|
|
||||||
// SNI not supported
|
|
||||||
return null;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
final Method cachedSetHostnameMethod = instance.mSetHostnameMethodRef.get();
|
|
||||||
return (cachedSetHostnameMethod == null) ? initFrom(sslSocketClass) : cachedSetHostnameMethod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Singleton initializer.
|
|
||||||
*
|
|
||||||
* Uses reflection to extract and 'cache' the method to invoke to indicate the desited host name to the server side.
|
|
||||||
*
|
|
||||||
* @param sslSocketClass Underlying class providing the implementation of {@link SSLSocket}.
|
|
||||||
* @return Method to call to indicate the server name of interest to the server.
|
|
||||||
*/
|
|
||||||
private static Method initFrom(Class<?> sslSocketClass) {
|
|
||||||
Log.i(TAG, "SSLSocket implementation: " + sslSocketClass.getCanonicalName());
|
|
||||||
Method setHostnameMethod = null;
|
|
||||||
try {
|
|
||||||
setHostnameMethod = sslSocketClass.getMethod(METHOD_NAME, String.class);
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
Log.e(TAG, "Could not access to SSLSocket#setHostname(String) method ", e);
|
|
||||||
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
Log.i(TAG, "Could not find SSLSocket#setHostname(String) method - SNI not supported");
|
|
||||||
}
|
|
||||||
mSingleInstance.set(new ServerNameIndicator(sslSocketClass, setHostnameMethod));
|
|
||||||
return setHostnameMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.network.webdav;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.methods.RequestEntity;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.ProgressiveDataTransferer;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A RequestEntity that represents a PIECE of a file.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
public class ChunkFromFileChannelRequestEntity implements RequestEntity, ProgressiveDataTransferer {
|
|
||||||
|
|
||||||
private static final String TAG = ChunkFromFileChannelRequestEntity.class.getSimpleName();
|
|
||||||
|
|
||||||
//private final File mFile;
|
|
||||||
private final FileChannel mChannel;
|
|
||||||
private final String mContentType;
|
|
||||||
private final long mChunkSize;
|
|
||||||
private final File mFile;
|
|
||||||
private long mOffset;
|
|
||||||
private long mTransferred;
|
|
||||||
Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
|
|
||||||
private ByteBuffer mBuffer = ByteBuffer.allocate(4096);
|
|
||||||
|
|
||||||
public ChunkFromFileChannelRequestEntity(final FileChannel channel, final String contentType, long chunkSize, final File file) {
|
|
||||||
super();
|
|
||||||
if (channel == null) {
|
|
||||||
throw new IllegalArgumentException("File may not be null");
|
|
||||||
}
|
|
||||||
if (chunkSize <= 0) {
|
|
||||||
throw new IllegalArgumentException("Chunk size must be greater than zero");
|
|
||||||
}
|
|
||||||
mChannel = channel;
|
|
||||||
mContentType = contentType;
|
|
||||||
mChunkSize = chunkSize;
|
|
||||||
mFile = file;
|
|
||||||
mOffset = 0;
|
|
||||||
mTransferred = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOffset(long offset) {
|
|
||||||
mOffset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getContentLength() {
|
|
||||||
try {
|
|
||||||
return Math.min(mChunkSize, mChannel.size() - mChannel.position());
|
|
||||||
} catch (IOException e) {
|
|
||||||
return mChunkSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getContentType() {
|
|
||||||
return mContentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRepeatable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
mDataTransferListeners.add(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
mDataTransferListeners.addAll(listeners);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
mDataTransferListeners.remove(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void writeRequest(final OutputStream out) throws IOException {
|
|
||||||
int readCount = 0;
|
|
||||||
Iterator<OnDatatransferProgressListener> it = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
mChannel.position(mOffset);
|
|
||||||
long size = mFile.length();
|
|
||||||
if (size == 0) size = -1;
|
|
||||||
long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
|
|
||||||
while (mChannel.position() < maxCount) {
|
|
||||||
readCount = mChannel.read(mBuffer);
|
|
||||||
out.write(mBuffer.array(), 0, readCount);
|
|
||||||
mBuffer.clear();
|
|
||||||
if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
|
|
||||||
mTransferred += readCount;
|
|
||||||
}
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
it = mDataTransferListeners.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next().onTransferProgress(readCount, mTransferred, size, mFile.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException io) {
|
|
||||||
Log.e(TAG, io.getMessage());
|
|
||||||
throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.network.webdav;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.methods.RequestEntity;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.ProgressiveDataTransferer;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A RequestEntity that represents a File.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class FileRequestEntity implements RequestEntity, ProgressiveDataTransferer {
|
|
||||||
|
|
||||||
final File mFile;
|
|
||||||
final String mContentType;
|
|
||||||
Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
|
|
||||||
|
|
||||||
public FileRequestEntity(final File file, final String contentType) {
|
|
||||||
super();
|
|
||||||
this.mFile = file;
|
|
||||||
this.mContentType = contentType;
|
|
||||||
if (file == null) {
|
|
||||||
throw new IllegalArgumentException("File may not be null");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getContentLength() {
|
|
||||||
return mFile.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getContentType() {
|
|
||||||
return mContentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRepeatable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
mDataTransferListeners.add(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
mDataTransferListeners.addAll(listeners);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
mDataTransferListeners.remove(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeRequest(final OutputStream out) throws IOException {
|
|
||||||
//byte[] tmp = new byte[4096];
|
|
||||||
ByteBuffer tmp = ByteBuffer.allocate(4096);
|
|
||||||
int readResult = 0;
|
|
||||||
|
|
||||||
// TODO(bprzybylski): each mem allocation can throw OutOfMemoryError we need to handle it
|
|
||||||
// globally in some fashionable manner
|
|
||||||
RandomAccessFile raf = new RandomAccessFile(mFile, "r");
|
|
||||||
FileChannel channel = raf.getChannel();
|
|
||||||
Iterator<OnDatatransferProgressListener> it = null;
|
|
||||||
long transferred = 0;
|
|
||||||
long size = mFile.length();
|
|
||||||
if (size == 0) size = -1;
|
|
||||||
try {
|
|
||||||
while ((readResult = channel.read(tmp)) >= 0) {
|
|
||||||
out.write(tmp.array(), 0, readResult);
|
|
||||||
tmp.clear();
|
|
||||||
transferred += readResult;
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
it = mDataTransferListeners.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next().onTransferProgress(readResult, transferred, size, mFile.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException io) {
|
|
||||||
Log.e("FileRequestException", io.getMessage());
|
|
||||||
throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
channel.close();
|
|
||||||
raf.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.network.webdav;
|
|
||||||
|
|
||||||
public interface OnDatatransferProgressListener {
|
|
||||||
public void onTransferProgress(long progressRate);
|
|
||||||
public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName);
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.network.webdav;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.accounts.AccountTypeUtils;
|
|
||||||
import com.owncloud.android.oc_framework.accounts.AccountUtils;
|
|
||||||
import com.owncloud.android.oc_framework.accounts.OwnCloudAccount;
|
|
||||||
import com.owncloud.android.oc_framework.accounts.AccountUtils.AccountNotFoundException;
|
|
||||||
import com.owncloud.android.oc_framework.network.NetworkUtils;
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.accounts.AccountManager;
|
|
||||||
import android.accounts.AccountManagerFuture;
|
|
||||||
import android.accounts.AuthenticatorException;
|
|
||||||
import android.accounts.OperationCanceledException;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
public class OwnCloudClientFactory {
|
|
||||||
|
|
||||||
final private static String TAG = OwnCloudClientFactory.class.getSimpleName();
|
|
||||||
|
|
||||||
/** Default timeout for waiting data from the server */
|
|
||||||
public static final int DEFAULT_DATA_TIMEOUT = 60000;
|
|
||||||
|
|
||||||
/** Default timeout for establishing a connection */
|
|
||||||
public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a WebdavClient setup for an ownCloud account
|
|
||||||
*
|
|
||||||
* Do not call this method from the main thread.
|
|
||||||
*
|
|
||||||
* @param account The ownCloud account
|
|
||||||
* @param appContext Android application context
|
|
||||||
* @return A WebdavClient object ready to be used
|
|
||||||
* @throws AuthenticatorException If the authenticator failed to get the authorization token for the account.
|
|
||||||
* @throws OperationCanceledException If the authenticator operation was cancelled while getting the authorization token for the account.
|
|
||||||
* @throws IOException If there was some I/O error while getting the authorization token for the account.
|
|
||||||
* @throws AccountNotFoundException If 'account' is unknown for the AccountManager
|
|
||||||
*/
|
|
||||||
public static WebdavClient createOwnCloudClient (Account account, Context appContext) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException {
|
|
||||||
//Log_OC.d(TAG, "Creating WebdavClient associated to " + account.name);
|
|
||||||
|
|
||||||
Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
|
|
||||||
AccountManager am = AccountManager.get(appContext);
|
|
||||||
boolean isOauth2 = am.getUserData(account, OwnCloudAccount.Constants.KEY_SUPPORTS_OAUTH2) != null; // TODO avoid calling to getUserData here
|
|
||||||
boolean isSamlSso = am.getUserData(account, OwnCloudAccount.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
|
|
||||||
WebdavClient client = createOwnCloudClient(uri, appContext, !isSamlSso);
|
|
||||||
if (isOauth2) {
|
|
||||||
String accessToken = am.blockingGetAuthToken(account, AccountTypeUtils.getAuthTokenTypeAccessToken(account.type), false);
|
|
||||||
client.setBearerCredentials(accessToken); // TODO not assume that the access token is a bearer token
|
|
||||||
|
|
||||||
} else if (isSamlSso) { // TODO avoid a call to getUserData here
|
|
||||||
String accessToken = am.blockingGetAuthToken(account, AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type), false);
|
|
||||||
client.setSsoSessionCookie(accessToken);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
String username = account.name.substring(0, account.name.lastIndexOf('@'));
|
|
||||||
//String password = am.getPassword(account);
|
|
||||||
String password = am.blockingGetAuthToken(account, AccountTypeUtils.getAuthTokenTypePass(account.type), false);
|
|
||||||
client.setBasicCredentials(username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static WebdavClient createOwnCloudClient (Account account, Context appContext, Activity currentActivity) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException {
|
|
||||||
Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
|
|
||||||
AccountManager am = AccountManager.get(appContext);
|
|
||||||
boolean isOauth2 = am.getUserData(account, OwnCloudAccount.Constants.KEY_SUPPORTS_OAUTH2) != null; // TODO avoid calling to getUserData here
|
|
||||||
boolean isSamlSso = am.getUserData(account, OwnCloudAccount.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
|
|
||||||
WebdavClient client = createOwnCloudClient(uri, appContext, !isSamlSso);
|
|
||||||
|
|
||||||
if (isOauth2) { // TODO avoid a call to getUserData here
|
|
||||||
AccountManagerFuture<Bundle> future = am.getAuthToken(account, AccountTypeUtils.getAuthTokenTypeAccessToken(account.type), null, currentActivity, null, null);
|
|
||||||
Bundle result = future.getResult();
|
|
||||||
String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
|
|
||||||
if (accessToken == null) throw new AuthenticatorException("WTF!");
|
|
||||||
client.setBearerCredentials(accessToken); // TODO not assume that the access token is a bearer token
|
|
||||||
|
|
||||||
} else if (isSamlSso) { // TODO avoid a call to getUserData here
|
|
||||||
AccountManagerFuture<Bundle> future = am.getAuthToken(account, AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type), null, currentActivity, null, null);
|
|
||||||
Bundle result = future.getResult();
|
|
||||||
String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
|
|
||||||
if (accessToken == null) throw new AuthenticatorException("WTF!");
|
|
||||||
client.setSsoSessionCookie(accessToken);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
String username = account.name.substring(0, account.name.lastIndexOf('@'));
|
|
||||||
//String password = am.getPassword(account);
|
|
||||||
//String password = am.blockingGetAuthToken(account, MainApp.getAuthTokenTypePass(), false);
|
|
||||||
AccountManagerFuture<Bundle> future = am.getAuthToken(account, AccountTypeUtils.getAuthTokenTypePass(account.type), null, currentActivity, null, null);
|
|
||||||
Bundle result = future.getResult();
|
|
||||||
String password = result.getString(AccountManager.KEY_AUTHTOKEN);
|
|
||||||
client.setBasicCredentials(username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a WebdavClient to access a URL and sets the desired parameters for ownCloud client connections.
|
|
||||||
*
|
|
||||||
* @param uri URL to the ownCloud server
|
|
||||||
* @param context Android context where the WebdavClient is being created.
|
|
||||||
* @return A WebdavClient object ready to be used
|
|
||||||
*/
|
|
||||||
public static WebdavClient createOwnCloudClient(Uri uri, Context context, boolean followRedirects) {
|
|
||||||
try {
|
|
||||||
NetworkUtils.registerAdvancedSslContext(true, context);
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
Log.e(TAG, "Advanced SSL Context could not be loaded. Default SSL management in the system will be used for HTTPS connections", e);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "The local server truststore could not be read. Default SSL management in the system will be used for HTTPS connections", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
WebdavClient client = new WebdavClient(NetworkUtils.getMultiThreadedConnManager());
|
|
||||||
|
|
||||||
client.setDefaultTimeouts(DEFAULT_DATA_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
|
|
||||||
client.setBaseUri(uri);
|
|
||||||
client.setFollowRedirects(followRedirects);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,245 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2011 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.network.webdav;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.Credentials;
|
|
||||||
import org.apache.commons.httpclient.Header;
|
|
||||||
import org.apache.commons.httpclient.HttpClient;
|
|
||||||
import org.apache.commons.httpclient.HttpConnectionManager;
|
|
||||||
import org.apache.commons.httpclient.HttpException;
|
|
||||||
import org.apache.commons.httpclient.HttpMethod;
|
|
||||||
import org.apache.commons.httpclient.HttpMethodBase;
|
|
||||||
import org.apache.commons.httpclient.HttpVersion;
|
|
||||||
import org.apache.commons.httpclient.URI;
|
|
||||||
import org.apache.commons.httpclient.UsernamePasswordCredentials;
|
|
||||||
import org.apache.commons.httpclient.auth.AuthPolicy;
|
|
||||||
import org.apache.commons.httpclient.auth.AuthScope;
|
|
||||||
import org.apache.commons.httpclient.cookie.CookiePolicy;
|
|
||||||
import org.apache.commons.httpclient.methods.HeadMethod;
|
|
||||||
import org.apache.commons.httpclient.params.HttpMethodParams;
|
|
||||||
import org.apache.http.HttpStatus;
|
|
||||||
import org.apache.http.params.CoreProtocolPNames;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.BearerAuthScheme;
|
|
||||||
import com.owncloud.android.oc_framework.network.BearerCredentials;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
public class WebdavClient extends HttpClient {
|
|
||||||
private static final int MAX_REDIRECTIONS_COUNT = 3;
|
|
||||||
|
|
||||||
private Uri mUri;
|
|
||||||
private Credentials mCredentials;
|
|
||||||
private boolean mFollowRedirects;
|
|
||||||
private String mSsoSessionCookie;
|
|
||||||
final private static String TAG = WebdavClient.class.getSimpleName();
|
|
||||||
public static final String USER_AGENT = "Android-ownCloud";
|
|
||||||
|
|
||||||
static private byte[] sExhaustBuffer = new byte[1024];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
public WebdavClient(HttpConnectionManager connectionMgr) {
|
|
||||||
super(connectionMgr);
|
|
||||||
Log.d(TAG, "Creating WebdavClient");
|
|
||||||
getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
|
|
||||||
getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
|
|
||||||
mFollowRedirects = true;
|
|
||||||
mSsoSessionCookie = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBearerCredentials(String accessToken) {
|
|
||||||
AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class);
|
|
||||||
|
|
||||||
List<String> authPrefs = new ArrayList<String>(1);
|
|
||||||
authPrefs.add(BearerAuthScheme.AUTH_POLICY);
|
|
||||||
getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
|
|
||||||
|
|
||||||
mCredentials = new BearerCredentials(accessToken);
|
|
||||||
getState().setCredentials(AuthScope.ANY, mCredentials);
|
|
||||||
mSsoSessionCookie = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBasicCredentials(String username, String password) {
|
|
||||||
List<String> authPrefs = new ArrayList<String>(1);
|
|
||||||
authPrefs.add(AuthPolicy.BASIC);
|
|
||||||
getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
|
|
||||||
|
|
||||||
getParams().setAuthenticationPreemptive(true);
|
|
||||||
mCredentials = new UsernamePasswordCredentials(username, password);
|
|
||||||
getState().setCredentials(AuthScope.ANY, mCredentials);
|
|
||||||
mSsoSessionCookie = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSsoSessionCookie(String accessToken) {
|
|
||||||
getParams().setAuthenticationPreemptive(false);
|
|
||||||
getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
|
|
||||||
mSsoSessionCookie = accessToken;
|
|
||||||
mCredentials = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a file exists in the OC server
|
|
||||||
*
|
|
||||||
* TODO replace with ExistenceOperation
|
|
||||||
*
|
|
||||||
* @return 'true' if the file exists; 'false' it doesn't exist
|
|
||||||
* @throws Exception When the existence could not be determined
|
|
||||||
*/
|
|
||||||
public boolean existsFile(String path) throws IOException, HttpException {
|
|
||||||
HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path));
|
|
||||||
try {
|
|
||||||
int status = executeMethod(head);
|
|
||||||
Log.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":""));
|
|
||||||
exhaustResponse(head.getResponseBodyAsStream());
|
|
||||||
return (status == HttpStatus.SC_OK);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
head.releaseConnection(); // let the connection available for other methods
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests the received method with the received timeout (milliseconds).
|
|
||||||
*
|
|
||||||
* Executes the method through the inherited HttpClient.executedMethod(method).
|
|
||||||
*
|
|
||||||
* Sets the socket and connection timeouts only for the method received.
|
|
||||||
*
|
|
||||||
* The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default'
|
|
||||||
*
|
|
||||||
* @param method HTTP method request.
|
|
||||||
* @param readTimeout Timeout to set for data reception
|
|
||||||
* @param conntionTimout Timeout to set for connection establishment
|
|
||||||
*/
|
|
||||||
public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException {
|
|
||||||
int oldSoTimeout = getParams().getSoTimeout();
|
|
||||||
int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
|
|
||||||
try {
|
|
||||||
if (readTimeout >= 0) {
|
|
||||||
method.getParams().setSoTimeout(readTimeout); // this should be enough...
|
|
||||||
getParams().setSoTimeout(readTimeout); // ... but this looks like necessary for HTTPS
|
|
||||||
}
|
|
||||||
if (connectionTimeout >= 0) {
|
|
||||||
getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
|
|
||||||
}
|
|
||||||
return executeMethod(method);
|
|
||||||
} finally {
|
|
||||||
getParams().setSoTimeout(oldSoTimeout);
|
|
||||||
getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int executeMethod(HttpMethod method) throws IOException, HttpException {
|
|
||||||
boolean customRedirectionNeeded = false;
|
|
||||||
try {
|
|
||||||
method.setFollowRedirects(mFollowRedirects);
|
|
||||||
} catch (Exception e) {
|
|
||||||
//if (mFollowRedirects) Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName() + " method, custom redirection will be used if needed");
|
|
||||||
customRedirectionNeeded = mFollowRedirects;
|
|
||||||
}
|
|
||||||
if (mSsoSessionCookie != null && mSsoSessionCookie.length() > 0) {
|
|
||||||
method.setRequestHeader("Cookie", mSsoSessionCookie);
|
|
||||||
}
|
|
||||||
int status = super.executeMethod(method);
|
|
||||||
int redirectionsCount = 0;
|
|
||||||
while (customRedirectionNeeded &&
|
|
||||||
redirectionsCount < MAX_REDIRECTIONS_COUNT &&
|
|
||||||
( status == HttpStatus.SC_MOVED_PERMANENTLY ||
|
|
||||||
status == HttpStatus.SC_MOVED_TEMPORARILY ||
|
|
||||||
status == HttpStatus.SC_TEMPORARY_REDIRECT)
|
|
||||||
) {
|
|
||||||
|
|
||||||
Header location = method.getResponseHeader("Location");
|
|
||||||
if (location != null) {
|
|
||||||
Log.d(TAG, "Location to redirect: " + location.getValue());
|
|
||||||
method.setURI(new URI(location.getValue(), true));
|
|
||||||
status = super.executeMethod(method);
|
|
||||||
redirectionsCount++;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "No location to redirect!");
|
|
||||||
status = HttpStatus.SC_NOT_FOUND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.
|
|
||||||
*
|
|
||||||
* @param responseBodyAsStream InputStream with the HTTP response to exhaust.
|
|
||||||
*/
|
|
||||||
public void exhaustResponse(InputStream responseBodyAsStream) {
|
|
||||||
if (responseBodyAsStream != null) {
|
|
||||||
try {
|
|
||||||
while (responseBodyAsStream.read(sExhaustBuffer) >= 0);
|
|
||||||
responseBodyAsStream.close();
|
|
||||||
|
|
||||||
} catch (IOException io) {
|
|
||||||
Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.
|
|
||||||
*/
|
|
||||||
public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {
|
|
||||||
getParams().setSoTimeout(defaultDataTimeout);
|
|
||||||
getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs
|
|
||||||
* @param uri
|
|
||||||
*/
|
|
||||||
public void setBaseUri(Uri uri) {
|
|
||||||
mUri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Uri getBaseUri() {
|
|
||||||
return mUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Credentials getCredentials() {
|
|
||||||
return mCredentials;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String getSsoSessionCookie() {
|
|
||||||
return mSsoSessionCookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFollowRedirects(boolean followRedirects) {
|
|
||||||
mFollowRedirects = followRedirects;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 ownCloud
|
|
||||||
*
|
|
||||||
* 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.oc_framework.network.webdav;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import org.apache.jackrabbit.webdav.MultiStatusResponse;
|
|
||||||
import org.apache.jackrabbit.webdav.property.DavProperty;
|
|
||||||
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
|
||||||
import org.apache.jackrabbit.webdav.property.DavPropertySet;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
public class WebdavEntry {
|
|
||||||
private String mName, mPath, mUri, mContentType, mEtag;
|
|
||||||
private long mContentLength, mCreateTimestamp, mModifiedTimestamp;
|
|
||||||
|
|
||||||
public WebdavEntry(MultiStatusResponse ms, String splitElement) {
|
|
||||||
resetData();
|
|
||||||
if (ms.getStatus().length != 0) {
|
|
||||||
mUri = ms.getHref();
|
|
||||||
|
|
||||||
mPath = mUri.split(splitElement, 2)[1];
|
|
||||||
|
|
||||||
int status = ms.getStatus()[0].getStatusCode();
|
|
||||||
DavPropertySet propSet = ms.getProperties(status);
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
DavProperty prop = propSet.get(DavPropertyName.DISPLAYNAME);
|
|
||||||
if (prop != null) {
|
|
||||||
mName = (String) prop.getName().toString();
|
|
||||||
mName = mName.substring(1, mName.length()-1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
String[] tmp = mPath.split("/");
|
|
||||||
if (tmp.length > 0)
|
|
||||||
mName = tmp[tmp.length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// use unknown mimetype as default behavior
|
|
||||||
mContentType = "application/octet-stream";
|
|
||||||
prop = propSet.get(DavPropertyName.GETCONTENTTYPE);
|
|
||||||
if (prop != null) {
|
|
||||||
mContentType = (String) prop.getValue();
|
|
||||||
// dvelasco: some builds of ownCloud server 4.0.x added a trailing ';' to the MIME type ; if looks fixed, but let's be cautious
|
|
||||||
if (mContentType.indexOf(";") >= 0) {
|
|
||||||
mContentType = mContentType.substring(0, mContentType.indexOf(";"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if it's a folder in the standard way: see RFC2518 12.2 . RFC4918 14.3
|
|
||||||
prop = propSet.get(DavPropertyName.RESOURCETYPE);
|
|
||||||
if (prop!= null) {
|
|
||||||
Object value = prop.getValue();
|
|
||||||
if (value != null) {
|
|
||||||
mContentType = "DIR"; // a specific attribute would be better, but this is enough; unless while we have no reason to distinguish MIME types for folders
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prop = propSet.get(DavPropertyName.GETCONTENTLENGTH);
|
|
||||||
if (prop != null)
|
|
||||||
mContentLength = Long.parseLong((String) prop.getValue());
|
|
||||||
|
|
||||||
prop = propSet.get(DavPropertyName.GETLASTMODIFIED);
|
|
||||||
if (prop != null) {
|
|
||||||
Date d = WebdavUtils
|
|
||||||
.parseResponseDate((String) prop.getValue());
|
|
||||||
mModifiedTimestamp = (d != null) ? d.getTime() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
prop = propSet.get(DavPropertyName.CREATIONDATE);
|
|
||||||
if (prop != null) {
|
|
||||||
Date d = WebdavUtils
|
|
||||||
.parseResponseDate((String) prop.getValue());
|
|
||||||
mCreateTimestamp = (d != null) ? d.getTime() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
prop = propSet.get(DavPropertyName.GETETAG);
|
|
||||||
if (prop != null) {
|
|
||||||
mEtag = (String) prop.getValue();
|
|
||||||
mEtag = mEtag.substring(1, mEtag.length()-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log.e("WebdavEntry",
|
|
||||||
"General fuckup, no status for webdav response");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String path() {
|
|
||||||
return mPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String decodedPath() {
|
|
||||||
return Uri.decode(mPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String name() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDirectory() {
|
|
||||||
return mContentType.equals("DIR");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String contentType() {
|
|
||||||
return mContentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String uri() {
|
|
||||||
return mUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long contentLength() {
|
|
||||||
return mContentLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long createTimestamp() {
|
|
||||||
return mCreateTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long modifiedTimestamp() {
|
|
||||||
return mModifiedTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String etag() {
|
|
||||||
return mEtag;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resetData() {
|
|
||||||
mName = mUri = mContentType = null;
|
|
||||||
mContentLength = mCreateTimestamp = mModifiedTimestamp = 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.network.webdav;
|
|
||||||
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
public class WebdavUtils {
|
|
||||||
public static final SimpleDateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat(
|
|
||||||
"dd.MM.yyyy hh:mm");
|
|
||||||
private static final SimpleDateFormat DATETIME_FORMATS[] = {
|
|
||||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US),
|
|
||||||
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
|
|
||||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US),
|
|
||||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US),
|
|
||||||
new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US),
|
|
||||||
new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
|
|
||||||
new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
|
|
||||||
|
|
||||||
public static String prepareXmlForPropFind() {
|
|
||||||
String ret = "<?xml version=\"1.0\" ?><D:propfind xmlns:D=\"DAV:\"><D:allprop/></D:propfind>";
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String prepareXmlForPatch() {
|
|
||||||
return "<?xml version=\"1.0\" ?><D:propertyupdate xmlns:D=\"DAV:\"></D:propertyupdate>";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Date parseResponseDate(String date) {
|
|
||||||
Date returnDate = null;
|
|
||||||
for (int i = 0; i < DATETIME_FORMATS.length; ++i) {
|
|
||||||
try {
|
|
||||||
returnDate = DATETIME_FORMATS[i].parse(date);
|
|
||||||
return returnDate;
|
|
||||||
} catch (ParseException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes a path according to URI RFC 2396.
|
|
||||||
*
|
|
||||||
* If the received path doesn't start with "/", the method adds it.
|
|
||||||
*
|
|
||||||
* @param remoteFilePath Path
|
|
||||||
* @return Encoded path according to RFC 2396, always starting with "/"
|
|
||||||
*/
|
|
||||||
public static String encodePath(String remoteFilePath) {
|
|
||||||
String encodedPath = Uri.encode(remoteFilePath, "/");
|
|
||||||
if (!encodedPath.startsWith("/"))
|
|
||||||
encodedPath = "/" + encodedPath;
|
|
||||||
return encodedPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations;
|
|
||||||
|
|
||||||
public interface OnRemoteOperationListener {
|
|
||||||
|
|
||||||
void onRemoteOperationFinish(RemoteOperation caller, RemoteOperationResult result);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations;
|
|
||||||
|
|
||||||
public class OperationCancelledException extends Exception {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generated serial version - to avoid Java warning
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = -6350981497740424983L;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,180 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import android.os.Parcel;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavEntry;
|
|
||||||
import com.owncloud.android.oc_framework.utils.FileUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains the data of a Remote File from a WebDavEntry
|
|
||||||
*
|
|
||||||
* @author masensio
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class RemoteFile implements Parcelable, Serializable {
|
|
||||||
|
|
||||||
/** Generated - should be refreshed every time the class changes!! */
|
|
||||||
private static final long serialVersionUID = 532139091191390616L;
|
|
||||||
|
|
||||||
private String mRemotePath;
|
|
||||||
private String mMimeType;
|
|
||||||
private long mLength;
|
|
||||||
private long mCreationTimestamp;
|
|
||||||
private long mModifiedTimestamp;
|
|
||||||
private String mEtag;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getters and Setters
|
|
||||||
*/
|
|
||||||
|
|
||||||
public String getRemotePath() {
|
|
||||||
return mRemotePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRemotePath(String remotePath) {
|
|
||||||
this.mRemotePath = remotePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMimeType() {
|
|
||||||
return mMimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMimeType(String mimeType) {
|
|
||||||
this.mMimeType = mimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLength() {
|
|
||||||
return mLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLength(long length) {
|
|
||||||
this.mLength = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCreationTimestamp() {
|
|
||||||
return mCreationTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreationTimestamp(long creationTimestamp) {
|
|
||||||
this.mCreationTimestamp = creationTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getModifiedTimestamp() {
|
|
||||||
return mModifiedTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setModifiedTimestamp(long modifiedTimestamp) {
|
|
||||||
this.mModifiedTimestamp = modifiedTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEtag() {
|
|
||||||
return mEtag;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEtag(String etag) {
|
|
||||||
this.mEtag = etag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new {@link RemoteFile} with given path.
|
|
||||||
*
|
|
||||||
* The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'.
|
|
||||||
*
|
|
||||||
* @param path The remote path of the file.
|
|
||||||
*/
|
|
||||||
public RemoteFile(String path) {
|
|
||||||
resetData();
|
|
||||||
if (path == null || path.length() <= 0 || !path.startsWith(FileUtils.PATH_SEPARATOR)) {
|
|
||||||
throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path);
|
|
||||||
}
|
|
||||||
mRemotePath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemoteFile(WebdavEntry we) {
|
|
||||||
this(we.decodedPath());
|
|
||||||
this.setCreationTimestamp(we.createTimestamp());
|
|
||||||
this.setLength(we.contentLength());
|
|
||||||
this.setMimeType(we.contentType());
|
|
||||||
this.setModifiedTimestamp(we.modifiedTimestamp());
|
|
||||||
this.setEtag(we.etag());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used internally. Reset all file properties
|
|
||||||
*/
|
|
||||||
private void resetData() {
|
|
||||||
mRemotePath = null;
|
|
||||||
mMimeType = null;
|
|
||||||
mLength = 0;
|
|
||||||
mCreationTimestamp = 0;
|
|
||||||
mModifiedTimestamp = 0;
|
|
||||||
mEtag = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parcelable Methods
|
|
||||||
*/
|
|
||||||
public static final Parcelable.Creator<RemoteFile> CREATOR = new Parcelable.Creator<RemoteFile>() {
|
|
||||||
@Override
|
|
||||||
public RemoteFile createFromParcel(Parcel source) {
|
|
||||||
return new RemoteFile(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RemoteFile[] newArray(int size) {
|
|
||||||
return new RemoteFile[size];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reconstruct from parcel
|
|
||||||
*
|
|
||||||
* @param source The source parcel
|
|
||||||
*/
|
|
||||||
private RemoteFile(Parcel source) {
|
|
||||||
mRemotePath = source.readString();
|
|
||||||
mMimeType = source.readString();
|
|
||||||
mLength = source.readLong();
|
|
||||||
mCreationTimestamp = source.readLong();
|
|
||||||
mModifiedTimestamp = source.readLong();
|
|
||||||
mEtag = source.readString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int describeContents() {
|
|
||||||
return this.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
|
||||||
dest.writeString(mRemotePath);
|
|
||||||
dest.writeString(mMimeType);
|
|
||||||
dest.writeLong(mLength);
|
|
||||||
dest.writeLong(mCreationTimestamp);
|
|
||||||
dest.writeLong(mModifiedTimestamp);
|
|
||||||
dest.writeString(mEtag);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,287 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.Credentials;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.BearerCredentials;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.OwnCloudClientFactory;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult.ResultCode;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.accounts.AccountManager;
|
|
||||||
import android.accounts.AccountsException;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Operation which execution involves one or several interactions with an ownCloud server.
|
|
||||||
*
|
|
||||||
* Provides methods to execute the operation both synchronously or asynchronously.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
public abstract class RemoteOperation implements Runnable {
|
|
||||||
|
|
||||||
private static final String TAG = RemoteOperation.class.getSimpleName();
|
|
||||||
|
|
||||||
/** ownCloud account in the remote ownCloud server to operate */
|
|
||||||
private Account mAccount = null;
|
|
||||||
|
|
||||||
/** Android Application context */
|
|
||||||
private Context mContext = null;
|
|
||||||
|
|
||||||
/** Object to interact with the remote server */
|
|
||||||
private WebdavClient mClient = null;
|
|
||||||
|
|
||||||
/** Callback object to notify about the execution of the remote operation */
|
|
||||||
private OnRemoteOperationListener mListener = null;
|
|
||||||
|
|
||||||
/** Handler to the thread where mListener methods will be called */
|
|
||||||
private Handler mListenerHandler = null;
|
|
||||||
|
|
||||||
/** Activity */
|
|
||||||
private Activity mCallerActivity;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract method to implement the operation in derived classes.
|
|
||||||
*/
|
|
||||||
protected abstract RemoteOperationResult run(WebdavClient client);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronously executes the remote operation on the received ownCloud account.
|
|
||||||
*
|
|
||||||
* Do not call this method from the main thread.
|
|
||||||
*
|
|
||||||
* This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}.
|
|
||||||
*
|
|
||||||
* @param account ownCloud account in remote ownCloud server to reach during the execution of the operation.
|
|
||||||
* @param context Android context for the component calling the method.
|
|
||||||
* @return Result of the operation.
|
|
||||||
*/
|
|
||||||
public final RemoteOperationResult execute(Account account, Context context) {
|
|
||||||
if (account == null)
|
|
||||||
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
|
|
||||||
if (context == null)
|
|
||||||
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
|
|
||||||
mAccount = account;
|
|
||||||
mContext = context.getApplicationContext();
|
|
||||||
try {
|
|
||||||
mClient = OwnCloudClientFactory.createOwnCloudClient(mAccount, mContext);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Error while trying to access to " + mAccount.name, e);
|
|
||||||
return new RemoteOperationResult(e);
|
|
||||||
}
|
|
||||||
return run(mClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronously executes the remote operation
|
|
||||||
*
|
|
||||||
* Do not call this method from the main thread.
|
|
||||||
*
|
|
||||||
* @param client Client object to reach an ownCloud server during the execution of the operation.
|
|
||||||
* @return Result of the operation.
|
|
||||||
*/
|
|
||||||
public final RemoteOperationResult execute(WebdavClient client) {
|
|
||||||
if (client == null)
|
|
||||||
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL WebdavClient");
|
|
||||||
mClient = client;
|
|
||||||
return run(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronously executes the remote operation
|
|
||||||
*
|
|
||||||
* This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}.
|
|
||||||
*
|
|
||||||
* @param account ownCloud account in remote ownCloud server to reach during the execution of the operation.
|
|
||||||
* @param context Android context for the component calling the method.
|
|
||||||
* @param listener Listener to be notified about the execution of the operation.
|
|
||||||
* @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called.
|
|
||||||
* @return Thread were the remote operation is executed.
|
|
||||||
*/
|
|
||||||
public final Thread execute(Account account, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) {
|
|
||||||
if (account == null)
|
|
||||||
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
|
|
||||||
if (context == null)
|
|
||||||
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
|
|
||||||
mAccount = account;
|
|
||||||
mContext = context.getApplicationContext();
|
|
||||||
mCallerActivity = callerActivity;
|
|
||||||
mClient = null; // the client instance will be created from mAccount and mContext in the runnerThread to create below
|
|
||||||
|
|
||||||
mListener = listener;
|
|
||||||
|
|
||||||
mListenerHandler = listenerHandler;
|
|
||||||
|
|
||||||
Thread runnerThread = new Thread(this);
|
|
||||||
runnerThread.start();
|
|
||||||
return runnerThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronously executes the remote operation
|
|
||||||
*
|
|
||||||
* @param client Client object to reach an ownCloud server during the execution of the operation.
|
|
||||||
* @param listener Listener to be notified about the execution of the operation.
|
|
||||||
* @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called.
|
|
||||||
* @return Thread were the remote operation is executed.
|
|
||||||
*/
|
|
||||||
public final Thread execute(WebdavClient client, OnRemoteOperationListener listener, Handler listenerHandler) {
|
|
||||||
if (client == null) {
|
|
||||||
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL WebdavClient");
|
|
||||||
}
|
|
||||||
mClient = client;
|
|
||||||
|
|
||||||
if (listener == null) {
|
|
||||||
throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a listener to notiy the result");
|
|
||||||
}
|
|
||||||
mListener = listener;
|
|
||||||
|
|
||||||
if (listenerHandler == null) {
|
|
||||||
throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a handler to the listener's thread");
|
|
||||||
}
|
|
||||||
mListenerHandler = listenerHandler;
|
|
||||||
|
|
||||||
Thread runnerThread = new Thread(this);
|
|
||||||
runnerThread.start();
|
|
||||||
return runnerThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronously retries the remote operation using the same WebdavClient in the last call to {@link RemoteOperation#execute(WebdavClient)}
|
|
||||||
*
|
|
||||||
* @param listener Listener to be notified about the execution of the operation.
|
|
||||||
* @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called.
|
|
||||||
* @return Thread were the remote operation is executed.
|
|
||||||
*/
|
|
||||||
public final RemoteOperationResult retry() {
|
|
||||||
return execute(mClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronously retries the remote operation using the same WebdavClient in the last call to {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)}
|
|
||||||
*
|
|
||||||
* @param listener Listener to be notified about the execution of the operation.
|
|
||||||
* @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called.
|
|
||||||
* @return Thread were the remote operation is executed.
|
|
||||||
*/
|
|
||||||
public final Thread retry(OnRemoteOperationListener listener, Handler listenerHandler) {
|
|
||||||
return execute(mClient, listener, listenerHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronous execution of the operation
|
|
||||||
* started by {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)},
|
|
||||||
* and result posting.
|
|
||||||
*
|
|
||||||
* TODO refactor && clean the code; now it's a mess
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final void run() {
|
|
||||||
RemoteOperationResult result = null;
|
|
||||||
boolean repeat = false;
|
|
||||||
do {
|
|
||||||
try{
|
|
||||||
if (mClient == null) {
|
|
||||||
if (mAccount != null && mContext != null) {
|
|
||||||
if (mCallerActivity != null) {
|
|
||||||
mClient = OwnCloudClientFactory.createOwnCloudClient(mAccount, mContext, mCallerActivity);
|
|
||||||
} else {
|
|
||||||
mClient = OwnCloudClientFactory.createOwnCloudClient(mAccount, mContext);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "Error while trying to access to " + mAccount.name, new AccountsException("I/O exception while trying to authorize the account", e));
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
|
|
||||||
} catch (AccountsException e) {
|
|
||||||
Log.e(TAG, "Error while trying to access to " + mAccount.name, e);
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == null)
|
|
||||||
result = run(mClient);
|
|
||||||
|
|
||||||
repeat = false;
|
|
||||||
if (mCallerActivity != null && mAccount != null && mContext != null && !result.isSuccess() &&
|
|
||||||
// (result.getCode() == ResultCode.UNAUTHORIZED || (result.isTemporalRedirection() && result.isIdPRedirection()))) {
|
|
||||||
(result.getCode() == ResultCode.UNAUTHORIZED || result.isIdPRedirection())) {
|
|
||||||
/// possible fail due to lack of authorization in an operation performed in foreground
|
|
||||||
Credentials cred = mClient.getCredentials();
|
|
||||||
String ssoSessionCookie = mClient.getSsoSessionCookie();
|
|
||||||
if (cred != null || ssoSessionCookie != null) {
|
|
||||||
/// confirmed : unauthorized operation
|
|
||||||
AccountManager am = AccountManager.get(mContext);
|
|
||||||
boolean bearerAuthorization = (cred != null && cred instanceof BearerCredentials);
|
|
||||||
boolean samlBasedSsoAuthorization = (cred == null && ssoSessionCookie != null);
|
|
||||||
if (bearerAuthorization) {
|
|
||||||
am.invalidateAuthToken(mAccount.type, ((BearerCredentials)cred).getAccessToken());
|
|
||||||
} else if (samlBasedSsoAuthorization ) {
|
|
||||||
am.invalidateAuthToken(mAccount.type, ssoSessionCookie);
|
|
||||||
} else {
|
|
||||||
am.clearPassword(mAccount);
|
|
||||||
}
|
|
||||||
mClient = null;
|
|
||||||
repeat = true; // when repeated, the creation of a new OwnCloudClient after erasing the saved credentials will trigger the login activity
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (repeat);
|
|
||||||
|
|
||||||
final RemoteOperationResult resultToSend = result;
|
|
||||||
if (mListenerHandler != null && mListener != null) {
|
|
||||||
mListenerHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current client instance to access the remote server.
|
|
||||||
*
|
|
||||||
* @return Current client instance to access the remote server.
|
|
||||||
*/
|
|
||||||
public final WebdavClient getClient() {
|
|
||||||
return mClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,356 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLException;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.ConnectTimeoutException;
|
|
||||||
import org.apache.commons.httpclient.Header;
|
|
||||||
import org.apache.commons.httpclient.HttpException;
|
|
||||||
import org.apache.commons.httpclient.HttpStatus;
|
|
||||||
import org.apache.jackrabbit.webdav.DavException;
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.accounts.AccountUtils.AccountNotFoundException;
|
|
||||||
import com.owncloud.android.oc_framework.network.CertificateCombinedException;
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.accounts.AccountsException;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The result of a remote operation required to an ownCloud server.
|
|
||||||
*
|
|
||||||
* Provides a common classification of remote operation results for all the
|
|
||||||
* application.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
public class RemoteOperationResult implements Serializable {
|
|
||||||
|
|
||||||
/** Generated - should be refreshed every time the class changes!! */
|
|
||||||
private static final long serialVersionUID = -8257349554488668693L;
|
|
||||||
|
|
||||||
private static final String TAG = "RemoteOperationResult";
|
|
||||||
|
|
||||||
public enum ResultCode {
|
|
||||||
OK,
|
|
||||||
OK_SSL,
|
|
||||||
OK_NO_SSL,
|
|
||||||
UNHANDLED_HTTP_CODE,
|
|
||||||
UNAUTHORIZED,
|
|
||||||
FILE_NOT_FOUND,
|
|
||||||
INSTANCE_NOT_CONFIGURED,
|
|
||||||
UNKNOWN_ERROR,
|
|
||||||
WRONG_CONNECTION,
|
|
||||||
TIMEOUT,
|
|
||||||
INCORRECT_ADDRESS,
|
|
||||||
HOST_NOT_AVAILABLE,
|
|
||||||
NO_NETWORK_CONNECTION,
|
|
||||||
SSL_ERROR,
|
|
||||||
SSL_RECOVERABLE_PEER_UNVERIFIED,
|
|
||||||
BAD_OC_VERSION,
|
|
||||||
CANCELLED,
|
|
||||||
INVALID_LOCAL_FILE_NAME,
|
|
||||||
INVALID_OVERWRITE,
|
|
||||||
CONFLICT,
|
|
||||||
OAUTH2_ERROR,
|
|
||||||
SYNC_CONFLICT,
|
|
||||||
LOCAL_STORAGE_FULL,
|
|
||||||
LOCAL_STORAGE_NOT_MOVED,
|
|
||||||
LOCAL_STORAGE_NOT_COPIED,
|
|
||||||
OAUTH2_ERROR_ACCESS_DENIED,
|
|
||||||
QUOTA_EXCEEDED,
|
|
||||||
ACCOUNT_NOT_FOUND,
|
|
||||||
ACCOUNT_EXCEPTION,
|
|
||||||
ACCOUNT_NOT_NEW,
|
|
||||||
ACCOUNT_NOT_THE_SAME,
|
|
||||||
INVALID_CHARACTER_IN_NAME
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean mSuccess = false;
|
|
||||||
private int mHttpCode = -1;
|
|
||||||
private Exception mException = null;
|
|
||||||
private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
|
|
||||||
private String mRedirectedLocation;
|
|
||||||
|
|
||||||
private ArrayList<RemoteFile> mFiles;
|
|
||||||
|
|
||||||
public RemoteOperationResult(ResultCode code) {
|
|
||||||
mCode = code;
|
|
||||||
mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL || code == ResultCode.OK_NO_SSL);
|
|
||||||
mFiles = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private RemoteOperationResult(boolean success, int httpCode) {
|
|
||||||
mSuccess = success;
|
|
||||||
mHttpCode = httpCode;
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
mCode = ResultCode.OK;
|
|
||||||
|
|
||||||
} else if (httpCode > 0) {
|
|
||||||
switch (httpCode) {
|
|
||||||
case HttpStatus.SC_UNAUTHORIZED:
|
|
||||||
mCode = ResultCode.UNAUTHORIZED;
|
|
||||||
break;
|
|
||||||
case HttpStatus.SC_NOT_FOUND:
|
|
||||||
mCode = ResultCode.FILE_NOT_FOUND;
|
|
||||||
break;
|
|
||||||
case HttpStatus.SC_INTERNAL_SERVER_ERROR:
|
|
||||||
mCode = ResultCode.INSTANCE_NOT_CONFIGURED;
|
|
||||||
break;
|
|
||||||
case HttpStatus.SC_CONFLICT:
|
|
||||||
mCode = ResultCode.CONFLICT;
|
|
||||||
break;
|
|
||||||
case HttpStatus.SC_INSUFFICIENT_STORAGE:
|
|
||||||
mCode = ResultCode.QUOTA_EXCEEDED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mCode = ResultCode.UNHANDLED_HTTP_CODE;
|
|
||||||
Log.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + httpCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemoteOperationResult(boolean success, int httpCode, Header[] headers) {
|
|
||||||
this(success, httpCode);
|
|
||||||
if (headers != null) {
|
|
||||||
Header current;
|
|
||||||
for (int i=0; i<headers.length; i++) {
|
|
||||||
current = headers[i];
|
|
||||||
if ("Location".equals(current.getName())) {
|
|
||||||
mRedirectedLocation = current.getValue();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemoteOperationResult(Exception e) {
|
|
||||||
mException = e;
|
|
||||||
|
|
||||||
if (e instanceof OperationCancelledException) {
|
|
||||||
mCode = ResultCode.CANCELLED;
|
|
||||||
|
|
||||||
} else if (e instanceof SocketException) {
|
|
||||||
mCode = ResultCode.WRONG_CONNECTION;
|
|
||||||
|
|
||||||
} else if (e instanceof SocketTimeoutException) {
|
|
||||||
mCode = ResultCode.TIMEOUT;
|
|
||||||
|
|
||||||
} else if (e instanceof ConnectTimeoutException) {
|
|
||||||
mCode = ResultCode.TIMEOUT;
|
|
||||||
|
|
||||||
} else if (e instanceof MalformedURLException) {
|
|
||||||
mCode = ResultCode.INCORRECT_ADDRESS;
|
|
||||||
|
|
||||||
} else if (e instanceof UnknownHostException) {
|
|
||||||
mCode = ResultCode.HOST_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
} else if (e instanceof AccountNotFoundException) {
|
|
||||||
mCode = ResultCode.ACCOUNT_NOT_FOUND;
|
|
||||||
|
|
||||||
} else if (e instanceof AccountsException) {
|
|
||||||
mCode = ResultCode.ACCOUNT_EXCEPTION;
|
|
||||||
|
|
||||||
} else if (e instanceof SSLException || e instanceof RuntimeException) {
|
|
||||||
CertificateCombinedException se = getCertificateCombinedException(e);
|
|
||||||
if (se != null) {
|
|
||||||
mException = se;
|
|
||||||
if (se.isRecoverable()) {
|
|
||||||
mCode = ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
|
|
||||||
}
|
|
||||||
} else if (e instanceof RuntimeException) {
|
|
||||||
mCode = ResultCode.HOST_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
mCode = ResultCode.SSL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
mCode = ResultCode.UNKNOWN_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setData(ArrayList<RemoteFile> files){
|
|
||||||
mFiles = files;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<RemoteFile> getData(){
|
|
||||||
return mFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSuccess() {
|
|
||||||
return mSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCancelled() {
|
|
||||||
return mCode == ResultCode.CANCELLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHttpCode() {
|
|
||||||
return mHttpCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResultCode getCode() {
|
|
||||||
return mCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Exception getException() {
|
|
||||||
return mException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSslRecoverableException() {
|
|
||||||
return mCode == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CertificateCombinedException getCertificateCombinedException(Exception e) {
|
|
||||||
CertificateCombinedException result = null;
|
|
||||||
if (e instanceof CertificateCombinedException) {
|
|
||||||
return (CertificateCombinedException) e;
|
|
||||||
}
|
|
||||||
Throwable cause = mException.getCause();
|
|
||||||
Throwable previousCause = null;
|
|
||||||
while (cause != null && cause != previousCause && !(cause instanceof CertificateCombinedException)) {
|
|
||||||
previousCause = cause;
|
|
||||||
cause = cause.getCause();
|
|
||||||
}
|
|
||||||
if (cause != null && cause instanceof CertificateCombinedException) {
|
|
||||||
result = (CertificateCombinedException) cause;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLogMessage() {
|
|
||||||
|
|
||||||
if (mException != null) {
|
|
||||||
if (mException instanceof OperationCancelledException) {
|
|
||||||
return "Operation cancelled by the caller";
|
|
||||||
|
|
||||||
} else if (mException instanceof SocketException) {
|
|
||||||
return "Socket exception";
|
|
||||||
|
|
||||||
} else if (mException instanceof SocketTimeoutException) {
|
|
||||||
return "Socket timeout exception";
|
|
||||||
|
|
||||||
} else if (mException instanceof ConnectTimeoutException) {
|
|
||||||
return "Connect timeout exception";
|
|
||||||
|
|
||||||
} else if (mException instanceof MalformedURLException) {
|
|
||||||
return "Malformed URL exception";
|
|
||||||
|
|
||||||
} else if (mException instanceof UnknownHostException) {
|
|
||||||
return "Unknown host exception";
|
|
||||||
|
|
||||||
} else if (mException instanceof CertificateCombinedException) {
|
|
||||||
if (((CertificateCombinedException) mException).isRecoverable())
|
|
||||||
return "SSL recoverable exception";
|
|
||||||
else
|
|
||||||
return "SSL exception";
|
|
||||||
|
|
||||||
} else if (mException instanceof SSLException) {
|
|
||||||
return "SSL exception";
|
|
||||||
|
|
||||||
} else if (mException instanceof DavException) {
|
|
||||||
return "Unexpected WebDAV exception";
|
|
||||||
|
|
||||||
} else if (mException instanceof HttpException) {
|
|
||||||
return "HTTP violation";
|
|
||||||
|
|
||||||
} else if (mException instanceof IOException) {
|
|
||||||
return "Unrecovered transport exception";
|
|
||||||
|
|
||||||
} else if (mException instanceof AccountNotFoundException) {
|
|
||||||
Account failedAccount = ((AccountNotFoundException)mException).getFailedAccount();
|
|
||||||
return mException.getMessage() + " (" + (failedAccount != null ? failedAccount.name : "NULL") + ")";
|
|
||||||
|
|
||||||
} else if (mException instanceof AccountsException) {
|
|
||||||
return "Exception while using account";
|
|
||||||
|
|
||||||
} else if (mException instanceof JSONException) {
|
|
||||||
return "JSON exception";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return "Unexpected exception";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mCode == ResultCode.INSTANCE_NOT_CONFIGURED) {
|
|
||||||
return "The ownCloud server is not configured!";
|
|
||||||
|
|
||||||
} else if (mCode == ResultCode.NO_NETWORK_CONNECTION) {
|
|
||||||
return "No network connection";
|
|
||||||
|
|
||||||
} else if (mCode == ResultCode.BAD_OC_VERSION) {
|
|
||||||
return "No valid ownCloud version was found at the server";
|
|
||||||
|
|
||||||
} else if (mCode == ResultCode.LOCAL_STORAGE_FULL) {
|
|
||||||
return "Local storage full";
|
|
||||||
|
|
||||||
} else if (mCode == ResultCode.LOCAL_STORAGE_NOT_MOVED) {
|
|
||||||
return "Error while moving file to final directory";
|
|
||||||
|
|
||||||
} else if (mCode == ResultCode.ACCOUNT_NOT_NEW) {
|
|
||||||
return "Account already existing when creating a new one";
|
|
||||||
|
|
||||||
} else if (mCode == ResultCode.ACCOUNT_NOT_THE_SAME) {
|
|
||||||
return "Authenticated with a different account than the one updating";
|
|
||||||
} else if (mCode == ResultCode.INVALID_CHARACTER_IN_NAME) {
|
|
||||||
return "The file name contains an forbidden character";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Operation finished with HTTP status code " + mHttpCode + " (" + (isSuccess() ? "success" : "fail") + ")";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isServerFail() {
|
|
||||||
return (mHttpCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isException() {
|
|
||||||
return (mException != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTemporalRedirection() {
|
|
||||||
return (mHttpCode == 302 || mHttpCode == 307);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRedirectedLocation() {
|
|
||||||
return mRedirectedLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isIdPRedirection() {
|
|
||||||
return (mRedirectedLocation != null &&
|
|
||||||
(mRedirectedLocation.toUpperCase().contains("SAML") ||
|
|
||||||
mRedirectedLocation.toLowerCase().contains("wayf")));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations.remote;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.HttpException;
|
|
||||||
import org.apache.commons.httpclient.methods.PutMethod;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.ProgressiveDataTransferer;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.ChunkFromFileChannelRequestEntity;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavUtils;
|
|
||||||
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation {
|
|
||||||
|
|
||||||
public static final long CHUNK_SIZE = 1024000;
|
|
||||||
private static final String OC_CHUNKED_HEADER = "OC-Chunked";
|
|
||||||
private static final String TAG = ChunkedUploadRemoteFileOperation.class.getSimpleName();
|
|
||||||
|
|
||||||
public ChunkedUploadRemoteFileOperation(String storagePath, String remotePath, String mimeType) {
|
|
||||||
super(storagePath, remotePath, mimeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int uploadFile(WebdavClient client) throws HttpException, IOException {
|
|
||||||
int status = -1;
|
|
||||||
|
|
||||||
FileChannel channel = null;
|
|
||||||
RandomAccessFile raf = null;
|
|
||||||
try {
|
|
||||||
File file = new File(mStoragePath);
|
|
||||||
raf = new RandomAccessFile(file, "r");
|
|
||||||
channel = raf.getChannel();
|
|
||||||
mEntity = new ChunkFromFileChannelRequestEntity(channel, mMimeType, CHUNK_SIZE, file);
|
|
||||||
//((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(getDataTransferListeners());
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(mDataTransferListeners);
|
|
||||||
}
|
|
||||||
|
|
||||||
long offset = 0;
|
|
||||||
String uriPrefix = client.getBaseUri() + WebdavUtils.encodePath(mRemotePath) + "-chunking-" + Math.abs((new Random()).nextInt(9000)+1000) + "-" ;
|
|
||||||
long chunkCount = (long) Math.ceil((double)file.length() / CHUNK_SIZE);
|
|
||||||
for (int chunkIndex = 0; chunkIndex < chunkCount ; chunkIndex++, offset += CHUNK_SIZE) {
|
|
||||||
if (mPutMethod != null) {
|
|
||||||
mPutMethod.releaseConnection(); // let the connection available for other methods
|
|
||||||
}
|
|
||||||
mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex);
|
|
||||||
mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER);
|
|
||||||
((ChunkFromFileChannelRequestEntity)mEntity).setOffset(offset);
|
|
||||||
mPutMethod.setRequestEntity(mEntity);
|
|
||||||
status = client.executeMethod(mPutMethod);
|
|
||||||
client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
|
|
||||||
Log.d(TAG, "Upload of " + mStoragePath + " to " + mRemotePath + ", chunk index " + chunkIndex + ", count " + chunkCount + ", HTTP result status " + status);
|
|
||||||
if (!isSuccess(status))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if (channel != null)
|
|
||||||
channel.close();
|
|
||||||
if (raf != null)
|
|
||||||
raf.close();
|
|
||||||
if (mPutMethod != null)
|
|
||||||
mPutMethod.releaseConnection(); // let the connection available for other methods
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,111 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations.remote;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.HttpStatus;
|
|
||||||
import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavUtils;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult.ResultCode;
|
|
||||||
import com.owncloud.android.oc_framework.utils.FileUtils;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remote operation performing the creation of a new folder in the ownCloud server.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author masensio
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class CreateRemoteFolderOperation extends RemoteOperation {
|
|
||||||
|
|
||||||
private static final String TAG = CreateRemoteFolderOperation.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final int READ_TIMEOUT = 10000;
|
|
||||||
private static final int CONNECTION_TIMEOUT = 5000;
|
|
||||||
|
|
||||||
|
|
||||||
protected String mRemotePath;
|
|
||||||
protected boolean mCreateFullPath;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param remotePath Full path to the new directory to create in the remote server.
|
|
||||||
* @param createFullPath 'True' means that all the ancestor folders should be created if don't exist yet.
|
|
||||||
*/
|
|
||||||
public CreateRemoteFolderOperation(String remotePath, boolean createFullPath) {
|
|
||||||
mRemotePath = remotePath;
|
|
||||||
mCreateFullPath = createFullPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs the operation
|
|
||||||
*
|
|
||||||
* @param client Client object to communicate with the remote ownCloud server.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected RemoteOperationResult run(WebdavClient client) {
|
|
||||||
RemoteOperationResult result = null;
|
|
||||||
MkColMethod mkcol = null;
|
|
||||||
|
|
||||||
boolean noInvalidChars = FileUtils.isValidPath(mRemotePath);
|
|
||||||
if (noInvalidChars) {
|
|
||||||
try {
|
|
||||||
mkcol = new MkColMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
|
|
||||||
int status = client.executeMethod(mkcol, READ_TIMEOUT, CONNECTION_TIMEOUT);
|
|
||||||
if (!mkcol.succeeded() && mkcol.getStatusCode() == HttpStatus.SC_CONFLICT && mCreateFullPath) {
|
|
||||||
result = createParentFolder(FileUtils.getParentPath(mRemotePath), client);
|
|
||||||
status = client.executeMethod(mkcol, READ_TIMEOUT, CONNECTION_TIMEOUT); // second (and last) try
|
|
||||||
}
|
|
||||||
|
|
||||||
result = new RemoteOperationResult(mkcol.succeeded(), status, mkcol.getResponseHeaders());
|
|
||||||
Log.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
|
|
||||||
client.exhaustResponse(mkcol.getResponseBodyAsStream());
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
Log.e(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage(), e);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if (mkcol != null)
|
|
||||||
mkcol.releaseConnection();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private RemoteOperationResult createParentFolder(String parentPath, WebdavClient client) {
|
|
||||||
RemoteOperation operation = new CreateRemoteFolderOperation(parentPath,
|
|
||||||
mCreateFullPath);
|
|
||||||
return operation.execute(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,169 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations.remote;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.Header;
|
|
||||||
import org.apache.commons.httpclient.HttpException;
|
|
||||||
import org.apache.commons.httpclient.methods.GetMethod;
|
|
||||||
import org.apache.http.HttpStatus;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.OnDatatransferProgressListener;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavUtils;
|
|
||||||
import com.owncloud.android.oc_framework.operations.OperationCancelledException;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteFile;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remote operation performing the download of a remote file in the ownCloud server.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author masensio
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DownloadRemoteFileOperation extends RemoteOperation {
|
|
||||||
|
|
||||||
private static final String TAG = DownloadRemoteFileOperation.class.getSimpleName();
|
|
||||||
|
|
||||||
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
|
|
||||||
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
|
||||||
private long mModificationTimestamp = 0;
|
|
||||||
private GetMethod mGet;
|
|
||||||
|
|
||||||
private RemoteFile mRemoteFile;
|
|
||||||
private String mTemporalFolder;
|
|
||||||
|
|
||||||
public DownloadRemoteFileOperation(RemoteFile remoteFile, String temporalFolder) {
|
|
||||||
mRemoteFile = remoteFile;
|
|
||||||
mTemporalFolder = temporalFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RemoteOperationResult run(WebdavClient client) {
|
|
||||||
RemoteOperationResult result = null;
|
|
||||||
|
|
||||||
/// download will be performed to a temporal file, then moved to the final location
|
|
||||||
File tmpFile = new File(getTmpPath());
|
|
||||||
|
|
||||||
/// perform the download
|
|
||||||
try {
|
|
||||||
tmpFile.getParentFile().mkdirs();
|
|
||||||
int status = downloadFile(client, tmpFile);
|
|
||||||
result = new RemoteOperationResult(isSuccess(status), status, (mGet != null ? mGet.getResponseHeaders() : null));
|
|
||||||
Log.i(TAG, "Download of " + mRemoteFile.getRemotePath() + " to " + getTmpPath() + ": " + result.getLogMessage());
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
Log.e(TAG, "Download of " + mRemoteFile.getRemotePath() + " to " + getTmpPath() + ": " + result.getLogMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected int downloadFile(WebdavClient client, File targetFile) throws HttpException, IOException, OperationCancelledException {
|
|
||||||
int status = -1;
|
|
||||||
boolean savedFile = false;
|
|
||||||
mGet = new GetMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemoteFile.getRemotePath()));
|
|
||||||
Iterator<OnDatatransferProgressListener> it = null;
|
|
||||||
|
|
||||||
FileOutputStream fos = null;
|
|
||||||
try {
|
|
||||||
status = client.executeMethod(mGet);
|
|
||||||
if (isSuccess(status)) {
|
|
||||||
targetFile.createNewFile();
|
|
||||||
BufferedInputStream bis = new BufferedInputStream(mGet.getResponseBodyAsStream());
|
|
||||||
fos = new FileOutputStream(targetFile);
|
|
||||||
long transferred = 0;
|
|
||||||
|
|
||||||
byte[] bytes = new byte[4096];
|
|
||||||
int readResult = 0;
|
|
||||||
while ((readResult = bis.read(bytes)) != -1) {
|
|
||||||
synchronized(mCancellationRequested) {
|
|
||||||
if (mCancellationRequested.get()) {
|
|
||||||
mGet.abort();
|
|
||||||
throw new OperationCancelledException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fos.write(bytes, 0, readResult);
|
|
||||||
transferred += readResult;
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
it = mDataTransferListeners.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next().onTransferProgress(readResult, transferred, mRemoteFile.getLength(), targetFile.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
savedFile = true;
|
|
||||||
Header modificationTime = mGet.getResponseHeader("Last-Modified");
|
|
||||||
if (modificationTime != null) {
|
|
||||||
Date d = WebdavUtils.parseResponseDate((String) modificationTime.getValue());
|
|
||||||
mModificationTimestamp = (d != null) ? d.getTime() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
client.exhaustResponse(mGet.getResponseBodyAsStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if (fos != null) fos.close();
|
|
||||||
if (!savedFile && targetFile.exists()) {
|
|
||||||
targetFile.delete();
|
|
||||||
}
|
|
||||||
mGet.releaseConnection(); // let the connection available for other methods
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isSuccess(int status) {
|
|
||||||
return (status == HttpStatus.SC_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTmpPath() {
|
|
||||||
return mTemporalFolder + mRemoteFile.getRemotePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
mDataTransferListeners.add(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
mDataTransferListeners.remove(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancel() {
|
|
||||||
mCancellationRequested.set(true); // atomic set; there is no need of synchronizing it
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 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.oc_framework.operations.remote;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.HttpStatus;
|
|
||||||
import org.apache.commons.httpclient.methods.HeadMethod;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavUtils;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Operation to check the existence or absence of a path in a remote server.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
*/
|
|
||||||
public class ExistenceCheckRemoteOperation extends RemoteOperation {
|
|
||||||
|
|
||||||
/** Maximum time to wait for a response from the server in MILLISECONDs. */
|
|
||||||
public static final int TIMEOUT = 10000;
|
|
||||||
|
|
||||||
private static final String TAG = ExistenceCheckRemoteOperation.class.getSimpleName();
|
|
||||||
|
|
||||||
private String mPath;
|
|
||||||
private Context mContext;
|
|
||||||
private boolean mSuccessIfAbsent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full constructor. Success of the operation will depend upon the value of successIfAbsent.
|
|
||||||
*
|
|
||||||
* @param path Path to append to the URL owned by the client instance.
|
|
||||||
* @param context Android application context.
|
|
||||||
* @param successIfAbsent When 'true', the operation finishes in success if the path does NOT exist in the remote server (HTTP 404).
|
|
||||||
*/
|
|
||||||
public ExistenceCheckRemoteOperation(String path, Context context, boolean successIfAbsent) {
|
|
||||||
mPath = (path != null) ? path : "";
|
|
||||||
mContext = context;
|
|
||||||
mSuccessIfAbsent = successIfAbsent;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RemoteOperationResult run(WebdavClient client) {
|
|
||||||
if (!isOnline()) {
|
|
||||||
return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
|
|
||||||
}
|
|
||||||
RemoteOperationResult result = null;
|
|
||||||
HeadMethod head = null;
|
|
||||||
try {
|
|
||||||
head = new HeadMethod(client.getBaseUri() + WebdavUtils.encodePath(mPath));
|
|
||||||
int status = client.executeMethod(head, TIMEOUT, TIMEOUT);
|
|
||||||
client.exhaustResponse(head.getResponseBodyAsStream());
|
|
||||||
boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) || (status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
|
|
||||||
result = new RemoteOperationResult(success, status, head.getResponseHeaders());
|
|
||||||
Log.d(TAG, "Existence check for " + client.getBaseUri() + WebdavUtils.encodePath(mPath) + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":""));
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
Log.e(TAG, "Existence check for " + client.getBaseUri() + WebdavUtils.encodePath(mPath) + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + ": " + result.getLogMessage(), result.getException());
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if (head != null)
|
|
||||||
head.releaseConnection();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isOnline() {
|
|
||||||
ConnectivityManager cm = (ConnectivityManager) mContext
|
|
||||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
return cm != null && cm.getActiveNetworkInfo() != null
|
|
||||||
&& cm.getActiveNetworkInfo().isConnectedOrConnecting();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,127 +0,0 @@
|
||||||
|
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations.remote;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.HttpException;
|
|
||||||
import org.apache.commons.httpclient.methods.GetMethod;
|
|
||||||
import org.apache.http.HttpStatus;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author masensio
|
|
||||||
*
|
|
||||||
* Get the UserName for a SAML connection, from a JSON with the format:
|
|
||||||
* id
|
|
||||||
* display-name
|
|
||||||
* email
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class GetUserNameRemoteOperation extends RemoteOperation {
|
|
||||||
|
|
||||||
private static final String TAG = GetUserNameRemoteOperation.class.getSimpleName();
|
|
||||||
|
|
||||||
// HEADER
|
|
||||||
private static final String HEADER_OCS_API = "OCS-APIREQUEST";
|
|
||||||
private static final String HEADER_OCS_API_VALUE = "true";
|
|
||||||
|
|
||||||
// OCS Route
|
|
||||||
private static final String OCS_ROUTE ="/index.php/ocs/cloud/user?format=json";
|
|
||||||
|
|
||||||
// JSON Node names
|
|
||||||
private static final String NODE_OCS = "ocs";
|
|
||||||
private static final String NODE_DATA = "data";
|
|
||||||
private static final String NODE_ID = "id";
|
|
||||||
private static final String NODE_DISPLAY_NAME= "display-name";
|
|
||||||
private static final String NODE_EMAIL= "email";
|
|
||||||
|
|
||||||
private String mUserName;
|
|
||||||
|
|
||||||
public String getUserName() {
|
|
||||||
return mUserName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public GetUserNameRemoteOperation() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RemoteOperationResult run(WebdavClient client) {
|
|
||||||
RemoteOperationResult result = null;
|
|
||||||
int status = -1;
|
|
||||||
|
|
||||||
// Get Method
|
|
||||||
GetMethod get = new GetMethod(client.getBaseUri() + OCS_ROUTE);
|
|
||||||
Log.d(TAG, "URL ------> " + client.getBaseUri() + OCS_ROUTE);
|
|
||||||
// Add the Header
|
|
||||||
get.addRequestHeader(HEADER_OCS_API, HEADER_OCS_API_VALUE);
|
|
||||||
|
|
||||||
//Get the user
|
|
||||||
try {
|
|
||||||
status = client.executeMethod(get);
|
|
||||||
if(isSuccess(status)) {
|
|
||||||
Log.d(TAG, "Obtain RESPONSE");
|
|
||||||
String response = get.getResponseBodyAsString();
|
|
||||||
|
|
||||||
Log.d(TAG, "GET RESPONSE.................... " + response);
|
|
||||||
|
|
||||||
// Parse the response
|
|
||||||
JSONObject respJSON = new JSONObject(response);
|
|
||||||
JSONObject respOCS = respJSON.getJSONObject(NODE_OCS);
|
|
||||||
JSONObject respData = respOCS.getJSONObject(NODE_DATA);
|
|
||||||
String id = respData.getString(NODE_ID);
|
|
||||||
String displayName = respData.getString(NODE_DISPLAY_NAME);
|
|
||||||
String email = respData.getString(NODE_EMAIL);
|
|
||||||
|
|
||||||
// Result
|
|
||||||
result = new RemoteOperationResult(isSuccess(status), status, (get != null ? get.getResponseHeaders() : null));
|
|
||||||
mUserName = displayName;
|
|
||||||
|
|
||||||
Log.d(TAG, "Response: " + id + " - " + displayName + " - " + email);
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (HttpException e) {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (JSONException e) {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
get.releaseConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isSuccess(int status) {
|
|
||||||
return (status == HttpStatus.SC_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations.remote;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
|
||||||
import org.apache.jackrabbit.webdav.DavConstants;
|
|
||||||
import org.apache.jackrabbit.webdav.MultiStatus;
|
|
||||||
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavEntry;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavUtils;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteFile;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remote operation performing the read a file from the ownCloud server.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author masensio
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ReadRemoteFileOperation extends RemoteOperation {
|
|
||||||
|
|
||||||
private static final String TAG = ReadRemoteFileOperation.class.getSimpleName();
|
|
||||||
private static final int SYNC_READ_TIMEOUT = 10000;
|
|
||||||
private static final int SYNC_CONNECTION_TIMEOUT = 5000;
|
|
||||||
|
|
||||||
private String mRemotePath;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param remotePath Remote path of the file.
|
|
||||||
*/
|
|
||||||
public ReadRemoteFileOperation(String remotePath) {
|
|
||||||
mRemotePath = remotePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs the read operation.
|
|
||||||
*
|
|
||||||
* @param client Client object to communicate with the remote ownCloud server.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected RemoteOperationResult run(WebdavClient client) {
|
|
||||||
PropFindMethod propfind = null;
|
|
||||||
RemoteOperationResult result = null;
|
|
||||||
|
|
||||||
/// take the duty of check the server for the current state of the file there
|
|
||||||
try {
|
|
||||||
propfind = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath),
|
|
||||||
DavConstants.PROPFIND_ALL_PROP,
|
|
||||||
DavConstants.DEPTH_0);
|
|
||||||
int status;
|
|
||||||
status = client.executeMethod(propfind, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT);
|
|
||||||
|
|
||||||
boolean isMultiStatus = status == HttpStatus.SC_MULTI_STATUS;
|
|
||||||
if (isMultiStatus) {
|
|
||||||
// Parse response
|
|
||||||
MultiStatus resp = propfind.getResponseBodyAsMultiStatus();
|
|
||||||
WebdavEntry we = new WebdavEntry(resp.getResponses()[0], client.getBaseUri().getPath());
|
|
||||||
RemoteFile remoteFile = new RemoteFile(we);
|
|
||||||
ArrayList<RemoteFile> files = new ArrayList<RemoteFile>();
|
|
||||||
files.add(remoteFile);
|
|
||||||
|
|
||||||
// Result of the operation
|
|
||||||
result = new RemoteOperationResult(true, status, propfind.getResponseHeaders());
|
|
||||||
result.setData(files);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
client.exhaustResponse(propfind.getResponseBodyAsStream());
|
|
||||||
result = new RemoteOperationResult(false, status, propfind.getResponseHeaders());
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
Log.e(TAG, "Synchronizing file " + mRemotePath + ": " + result.getLogMessage(), result.getException());
|
|
||||||
} finally {
|
|
||||||
if (propfind != null)
|
|
||||||
propfind.releaseConnection();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,162 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations.remote;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
|
||||||
import org.apache.jackrabbit.webdav.DavConstants;
|
|
||||||
import org.apache.jackrabbit.webdav.MultiStatus;
|
|
||||||
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavEntry;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavUtils;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteFile;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remote operation performing the read of remote file or folder in the ownCloud server.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author masensio
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ReadRemoteFolderOperation extends RemoteOperation {
|
|
||||||
|
|
||||||
private static final String TAG = ReadRemoteFolderOperation.class.getSimpleName();
|
|
||||||
|
|
||||||
private String mRemotePath;
|
|
||||||
private ArrayList<RemoteFile> mFolderAndFiles;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param remotePath Remote path of the file.
|
|
||||||
*/
|
|
||||||
public ReadRemoteFolderOperation(String remotePath) {
|
|
||||||
mRemotePath = remotePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs the read operation.
|
|
||||||
*
|
|
||||||
* @param client Client object to communicate with the remote ownCloud server.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected RemoteOperationResult run(WebdavClient client) {
|
|
||||||
RemoteOperationResult result = null;
|
|
||||||
PropFindMethod query = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// remote request
|
|
||||||
query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath),
|
|
||||||
DavConstants.PROPFIND_ALL_PROP,
|
|
||||||
DavConstants.DEPTH_1);
|
|
||||||
int status = client.executeMethod(query);
|
|
||||||
|
|
||||||
// check and process response
|
|
||||||
if (isMultiStatus(status)) {
|
|
||||||
// get data from remote folder
|
|
||||||
MultiStatus dataInServer = query.getResponseBodyAsMultiStatus();
|
|
||||||
readData(dataInServer, client);
|
|
||||||
|
|
||||||
// Result of the operation
|
|
||||||
result = new RemoteOperationResult(true, status, query.getResponseHeaders());
|
|
||||||
// Add data to the result
|
|
||||||
if (result.isSuccess()) {
|
|
||||||
result.setData(mFolderAndFiles);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// synchronization failed
|
|
||||||
client.exhaustResponse(query.getResponseBodyAsStream());
|
|
||||||
result = new RemoteOperationResult(false, status, query.getResponseHeaders());
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if (query != null)
|
|
||||||
query.releaseConnection(); // let the connection available for other methods
|
|
||||||
if (result.isSuccess()) {
|
|
||||||
Log.i(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage());
|
|
||||||
} else {
|
|
||||||
if (result.isException()) {
|
|
||||||
Log.e(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage(), result.getException());
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMultiStatus(int status) {
|
|
||||||
return (status == HttpStatus.SC_MULTI_STATUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the data retrieved from the server about the contents of the target folder
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param dataInServer Full response got from the server with the data of the target
|
|
||||||
* folder and its direct children.
|
|
||||||
* @param client Client instance to the remote server where the data were
|
|
||||||
* retrieved.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private void readData(MultiStatus dataInServer, WebdavClient client) {
|
|
||||||
mFolderAndFiles = new ArrayList<RemoteFile>();
|
|
||||||
|
|
||||||
// parse data from remote folder
|
|
||||||
WebdavEntry we = new WebdavEntry(dataInServer.getResponses()[0], client.getBaseUri().getPath());
|
|
||||||
mFolderAndFiles.add(fillOCFile(we));
|
|
||||||
|
|
||||||
// loop to update every child
|
|
||||||
RemoteFile remoteFile = null;
|
|
||||||
for (int i = 1; i < dataInServer.getResponses().length; ++i) {
|
|
||||||
/// new OCFile instance with the data from the server
|
|
||||||
we = new WebdavEntry(dataInServer.getResponses()[i], client.getBaseUri().getPath());
|
|
||||||
remoteFile = fillOCFile(we);
|
|
||||||
mFolderAndFiles.add(remoteFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and populates a new {@link RemoteFile} object with the data read from the server.
|
|
||||||
*
|
|
||||||
* @param we WebDAV entry read from the server for a WebDAV resource (remote file or folder).
|
|
||||||
* @return New OCFile instance representing the remote resource described by we.
|
|
||||||
*/
|
|
||||||
private RemoteFile fillOCFile(WebdavEntry we) {
|
|
||||||
RemoteFile file = new RemoteFile(we.decodedPath());
|
|
||||||
file.setCreationTimestamp(we.createTimestamp());
|
|
||||||
file.setLength(we.contentLength());
|
|
||||||
file.setMimeType(we.contentType());
|
|
||||||
file.setModifiedTimestamp(we.modifiedTimestamp());
|
|
||||||
file.setEtag(we.etag());
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations.remote;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.HttpStatus;
|
|
||||||
import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavUtils;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remote operation performing the removal of a remote file or folder in the ownCloud server.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author masensio
|
|
||||||
*/
|
|
||||||
public class RemoveRemoteFileOperation extends RemoteOperation {
|
|
||||||
private static final String TAG = RemoveRemoteFileOperation.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final int REMOVE_READ_TIMEOUT = 10000;
|
|
||||||
private static final int REMOVE_CONNECTION_TIMEOUT = 5000;
|
|
||||||
|
|
||||||
private String mRemotePath;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param remotePath RemotePath of the remote file or folder to remove from the server
|
|
||||||
*/
|
|
||||||
public RemoveRemoteFileOperation(String remotePath) {
|
|
||||||
mRemotePath = remotePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs the rename operation.
|
|
||||||
*
|
|
||||||
* @param client Client object to communicate with the remote ownCloud server.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected RemoteOperationResult run(WebdavClient client) {
|
|
||||||
RemoteOperationResult result = null;
|
|
||||||
DeleteMethod delete = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
delete = new DeleteMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
|
|
||||||
int status = client.executeMethod(delete, REMOVE_READ_TIMEOUT, REMOVE_CONNECTION_TIMEOUT);
|
|
||||||
|
|
||||||
delete.getResponseBodyAsString(); // exhaust the response, although not interesting
|
|
||||||
result = new RemoteOperationResult((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), status, delete.getResponseHeaders());
|
|
||||||
Log.i(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage());
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
Log.e(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage(), e);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if (delete != null)
|
|
||||||
delete.releaseConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,146 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations.remote;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavUtils;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult.ResultCode;
|
|
||||||
import com.owncloud.android.oc_framework.utils.FileUtils;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remote operation performing the rename of a remote file or folder in the ownCloud server.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author masensio
|
|
||||||
*/
|
|
||||||
public class RenameRemoteFileOperation extends RemoteOperation {
|
|
||||||
|
|
||||||
private static final String TAG = RenameRemoteFileOperation.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final int RENAME_READ_TIMEOUT = 10000;
|
|
||||||
private static final int RENAME_CONNECTION_TIMEOUT = 5000;
|
|
||||||
|
|
||||||
private String mOldName;
|
|
||||||
private String mOldRemotePath;
|
|
||||||
private String mNewName;
|
|
||||||
private String mNewRemotePath;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param oldName Old name of the file.
|
|
||||||
* @param oldRemotePath Old remote path of the file.
|
|
||||||
* @param newName New name to set as the name of file.
|
|
||||||
* @param isFolder 'true' for folder and 'false' for files
|
|
||||||
*/
|
|
||||||
public RenameRemoteFileOperation(String oldName, String oldRemotePath, String newName, boolean isFolder) {
|
|
||||||
mOldName = oldName;
|
|
||||||
mOldRemotePath = oldRemotePath;
|
|
||||||
mNewName = newName;
|
|
||||||
|
|
||||||
String parent = (new File(mOldRemotePath)).getParent();
|
|
||||||
parent = (parent.endsWith(FileUtils.PATH_SEPARATOR)) ? parent : parent + FileUtils.PATH_SEPARATOR;
|
|
||||||
mNewRemotePath = parent + mNewName;
|
|
||||||
if (isFolder) {
|
|
||||||
mNewRemotePath += FileUtils.PATH_SEPARATOR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs the rename operation.
|
|
||||||
*
|
|
||||||
* @param client Client object to communicate with the remote ownCloud server.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected RemoteOperationResult run(WebdavClient client) {
|
|
||||||
RemoteOperationResult result = null;
|
|
||||||
|
|
||||||
LocalMoveMethod move = null;
|
|
||||||
|
|
||||||
boolean noInvalidChars = FileUtils.isValidPath(mNewRemotePath);
|
|
||||||
|
|
||||||
if (noInvalidChars) {
|
|
||||||
try {
|
|
||||||
|
|
||||||
if (mNewName.equals(mOldName)) {
|
|
||||||
return new RemoteOperationResult(ResultCode.OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// check if a file with the new name already exists
|
|
||||||
if (client.existsFile(mNewRemotePath)) {
|
|
||||||
return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
move = new LocalMoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mOldRemotePath),
|
|
||||||
client.getBaseUri() + WebdavUtils.encodePath(mNewRemotePath));
|
|
||||||
int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT);
|
|
||||||
|
|
||||||
move.getResponseBodyAsString(); // exhaust response, although not interesting
|
|
||||||
result = new RemoteOperationResult(move.succeeded(), status, move.getResponseHeaders());
|
|
||||||
Log.i(TAG, "Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " + result.getLogMessage());
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
Log.e(TAG, "Rename " + mOldRemotePath + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if (move != null)
|
|
||||||
move.releaseConnection();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move operation
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private class LocalMoveMethod extends DavMethodBase {
|
|
||||||
|
|
||||||
public LocalMoveMethod(String uri, String dest) {
|
|
||||||
super(uri);
|
|
||||||
addRequestHeader(new org.apache.commons.httpclient.Header("Destination", dest));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "MOVE";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isSuccess(int status) {
|
|
||||||
return status == 201 || status == 204;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,147 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.operations.remote;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
import org.apache.commons.httpclient.HttpException;
|
|
||||||
import org.apache.commons.httpclient.methods.PutMethod;
|
|
||||||
import org.apache.commons.httpclient.methods.RequestEntity;
|
|
||||||
import org.apache.http.HttpStatus;
|
|
||||||
|
|
||||||
import com.owncloud.android.oc_framework.network.ProgressiveDataTransferer;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.FileRequestEntity;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.OnDatatransferProgressListener;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
|
|
||||||
import com.owncloud.android.oc_framework.network.webdav.WebdavUtils;
|
|
||||||
import com.owncloud.android.oc_framework.operations.OperationCancelledException;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperation;
|
|
||||||
import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remote operation performing the upload of a remote file to the ownCloud server.
|
|
||||||
*
|
|
||||||
* @author David A. Velasco
|
|
||||||
* @author masensio
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class UploadRemoteFileOperation extends RemoteOperation {
|
|
||||||
|
|
||||||
|
|
||||||
protected String mStoragePath;
|
|
||||||
protected String mRemotePath;
|
|
||||||
protected String mMimeType;
|
|
||||||
protected PutMethod mPutMethod = null;
|
|
||||||
|
|
||||||
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
|
||||||
protected Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
|
|
||||||
|
|
||||||
protected RequestEntity mEntity = null;
|
|
||||||
|
|
||||||
public UploadRemoteFileOperation(String storagePath, String remotePath, String mimeType) {
|
|
||||||
mStoragePath = storagePath;
|
|
||||||
mRemotePath = remotePath;
|
|
||||||
mMimeType = mimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RemoteOperationResult run(WebdavClient client) {
|
|
||||||
RemoteOperationResult result = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// / perform the upload
|
|
||||||
synchronized (mCancellationRequested) {
|
|
||||||
if (mCancellationRequested.get()) {
|
|
||||||
throw new OperationCancelledException();
|
|
||||||
} else {
|
|
||||||
mPutMethod = new PutMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int status = uploadFile(client);
|
|
||||||
|
|
||||||
result = new RemoteOperationResult(isSuccess(status), status, (mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
// TODO something cleaner with cancellations
|
|
||||||
if (mCancellationRequested.get()) {
|
|
||||||
result = new RemoteOperationResult(new OperationCancelledException());
|
|
||||||
} else {
|
|
||||||
result = new RemoteOperationResult(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSuccess(int status) {
|
|
||||||
return ((status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int uploadFile(WebdavClient client) throws HttpException, IOException, OperationCancelledException {
|
|
||||||
int status = -1;
|
|
||||||
try {
|
|
||||||
File f = new File(mStoragePath);
|
|
||||||
mEntity = new FileRequestEntity(f, mMimeType);
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(mDataTransferListeners);
|
|
||||||
}
|
|
||||||
mPutMethod.setRequestEntity(mEntity);
|
|
||||||
status = client.executeMethod(mPutMethod);
|
|
||||||
client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
mPutMethod.releaseConnection(); // let the connection available for other methods
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<OnDatatransferProgressListener> getDataTransferListeners() {
|
|
||||||
return mDataTransferListeners;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
mDataTransferListeners.add(listener);
|
|
||||||
}
|
|
||||||
if (mEntity != null) {
|
|
||||||
((ProgressiveDataTransferer)mEntity).addDatatransferProgressListener(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
|
||||||
synchronized (mDataTransferListeners) {
|
|
||||||
mDataTransferListeners.remove(listener);
|
|
||||||
}
|
|
||||||
if (mEntity != null) {
|
|
||||||
((ProgressiveDataTransferer)mEntity).removeDatatransferProgressListener(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancel() {
|
|
||||||
synchronized (mCancellationRequested) {
|
|
||||||
mCancellationRequested.set(true);
|
|
||||||
if (mPutMethod != null)
|
|
||||||
mPutMethod.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.utils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
public class FileUtils {
|
|
||||||
|
|
||||||
public static final String PATH_SEPARATOR = "/";
|
|
||||||
|
|
||||||
|
|
||||||
public static String getParentPath(String remotePath) {
|
|
||||||
String parentPath = new File(remotePath).getParent();
|
|
||||||
parentPath = parentPath.endsWith(PATH_SEPARATOR) ? parentPath : parentPath + PATH_SEPARATOR;
|
|
||||||
return parentPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the fileName to detect if contains any forbidden character: / , \ , < , > , : , " , | , ? , *
|
|
||||||
* @param fileName
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean isValidName(String fileName) {
|
|
||||||
boolean result = true;
|
|
||||||
|
|
||||||
Log.d("FileUtils", "fileName =======" + fileName);
|
|
||||||
if (fileName.contains(PATH_SEPARATOR) ||
|
|
||||||
fileName.contains("\\") || fileName.contains("<") || fileName.contains(">") ||
|
|
||||||
fileName.contains(":") || fileName.contains("\"") || fileName.contains("|") ||
|
|
||||||
fileName.contains("?") || fileName.contains("*")) {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the path to detect if contains any forbidden character: \ , < , > , : , " , | , ? , *
|
|
||||||
* @param path
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean isValidPath(String path) {
|
|
||||||
boolean result = true;
|
|
||||||
|
|
||||||
Log.d("FileUtils", "path ....... " + path);
|
|
||||||
if (path.contains("\\") || path.contains("<") || path.contains(">") ||
|
|
||||||
path.contains(":") || path.contains("\"") || path.contains("|") ||
|
|
||||||
path.contains("?") || path.contains("*")) {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
/* ownCloud Android client application
|
|
||||||
* Copyright (C) 2012 Bartek Przybylski
|
|
||||||
* Copyright (C) 2012-2013 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.oc_framework.utils;
|
|
||||||
|
|
||||||
public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
|
|
||||||
public static final OwnCloudVersion owncloud_v1 = new OwnCloudVersion(
|
|
||||||
0x010000);
|
|
||||||
public static final OwnCloudVersion owncloud_v2 = new OwnCloudVersion(
|
|
||||||
0x020000);
|
|
||||||
public static final OwnCloudVersion owncloud_v3 = new OwnCloudVersion(
|
|
||||||
0x030000);
|
|
||||||
public static final OwnCloudVersion owncloud_v4 = new OwnCloudVersion(
|
|
||||||
0x040000);
|
|
||||||
public static final OwnCloudVersion owncloud_v4_5 = new OwnCloudVersion(
|
|
||||||
0x040500);
|
|
||||||
|
|
||||||
// format is in version
|
|
||||||
// 0xAABBCC
|
|
||||||
// for version AA.BB.CC
|
|
||||||
// ie version 2.0.3 will be stored as 0x030003
|
|
||||||
private int mVersion;
|
|
||||||
private boolean mIsValid;
|
|
||||||
|
|
||||||
public OwnCloudVersion(int version) {
|
|
||||||
mVersion = version;
|
|
||||||
mIsValid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OwnCloudVersion(String version) {
|
|
||||||
mVersion = 0;
|
|
||||||
mIsValid = false;
|
|
||||||
parseVersionString(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return ((mVersion >> 16) % 256) + "." + ((mVersion >> 8) % 256) + "."
|
|
||||||
+ ((mVersion) % 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVersionValid() {
|
|
||||||
return mIsValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(OwnCloudVersion another) {
|
|
||||||
return another.mVersion == mVersion ? 0
|
|
||||||
: another.mVersion < mVersion ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseVersionString(String version) {
|
|
||||||
try {
|
|
||||||
String[] nums = version.split("\\.");
|
|
||||||
if (nums.length > 0) {
|
|
||||||
mVersion += Integer.parseInt(nums[0]);
|
|
||||||
}
|
|
||||||
mVersion = mVersion << 8;
|
|
||||||
if (nums.length > 1) {
|
|
||||||
mVersion += Integer.parseInt(nums[1]);
|
|
||||||
}
|
|
||||||
mVersion = mVersion << 8;
|
|
||||||
if (nums.length > 2) {
|
|
||||||
mVersion += Integer.parseInt(nums[2]);
|
|
||||||
}
|
|
||||||
mIsValid = true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
mIsValid = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.owncloud.android.workaround.accounts"
|
package="com.owncloud.android.workaround.accounts"
|
||||||
android:versionCode="0100011"
|
android:versionCode="0100013"
|
||||||
android:versionName="1.0.11" >
|
android:versionName="1.0.13" >
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="16"
|
android:minSdkVersion="16"
|
||||||
|
|
1
owncloud-android-library
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 30acd4875dda3fd0bec83daaad522f3d5a02ead6
|
6
pom.xml
|
@ -13,7 +13,7 @@
|
||||||
<owncloud.version>1.5.1-SNAPSHOT</owncloud.version>
|
<owncloud.version>1.5.1-SNAPSHOT</owncloud.version>
|
||||||
<java-version>1.6</java-version>
|
<java-version>1.6</java-version>
|
||||||
<!-- Given by maven-android-sdk-deployer -->
|
<!-- Given by maven-android-sdk-deployer -->
|
||||||
<google.android-version>4.4_r1</google.android-version>
|
<google.android-version>4.4.2_r2</google.android-version>
|
||||||
<!-- Usually the latest Android API -->
|
<!-- Usually the latest Android API -->
|
||||||
<google.android-api>19</google.android-api>
|
<google.android-api>19</google.android-api>
|
||||||
<actionbarsherlock-version>4.2.0</actionbarsherlock-version>
|
<actionbarsherlock-version>4.2.0</actionbarsherlock-version>
|
||||||
|
@ -50,10 +50,10 @@
|
||||||
<type>apklib</type>
|
<type>apklib</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- MUST BE INSTALLED FIRST: cd oc_framework; mvn install -->
|
<!-- MUST BE INSTALLED FIRST: cd owncloud-android-library; mvn install -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.owncloud.android</groupId>
|
<groupId>com.owncloud.android</groupId>
|
||||||
<artifactId>oc_framework</artifactId>
|
<artifactId>owncloud-android-library</artifactId>
|
||||||
<version>${owncloud.version}</version>
|
<version>${owncloud.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
|
@ -10,4 +10,4 @@
|
||||||
# Project target.
|
# Project target.
|
||||||
target=android-19
|
target=android-19
|
||||||
android.library.reference.1=actionbarsherlock/library
|
android.library.reference.1=actionbarsherlock/library
|
||||||
android.library.reference.2=oc_framework
|
android.library.reference.2=owncloud-android-library
|
||||||
|
|
BIN
res/drawable-hdpi/copy_link.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
res/drawable-hdpi/sharedlink.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
res/drawable-ldpi/copy_link.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
res/drawable-mdpi/copy_link.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
res/drawable-mdpi/sharedlink.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
res/drawable-xhdpi/copy_link.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
res/drawable-xhdpi/icon.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
res/drawable-xhdpi/sharedlink.png
Normal file
After Width: | Height: | Size: 1.7 KiB |