1
0
mirror of https://github.com/owncloud/android-library.git synced 2025-06-07 16:06:08 +00:00

Initial commit of ownCloud Android library

This commit is contained in:
David A. Velasco 2014-01-20 13:51:09 +01:00
commit 1f3123b1b7
104 changed files with 7694 additions and 0 deletions

9
.classpath Normal file
View File

@ -0,0 +1,9 @@
<?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>

29
.gitignore vendored Normal file
View File

@ -0,0 +1,29 @@
# built application files
*.apk
*.ap_
# files for the dex VM
*.dex
# Java class files
*.class
# generated files
bin/
gen/
target/
# Local configuration files (sdk path, etc)
local.properties
sample_client/local.properties
tests/local.properties
tests/test_cases/local.properties
# Mac .DS_Store files
.DS_Store
# Proguard README
proguard-project.txt
sample_client/proguard-project.txt
tests/proguard-project.txt
tests/test_cases/proguard-project.txt

33
.project Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ownCloud Android Library</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>

35
AndroidManifest.xml Normal file
View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.owncloud.android.lib"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
</manifest>

92
build.xml Normal file
View File

@ -0,0 +1,92 @@
<?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>

Binary file not shown.

Binary file not shown.

BIN
libs/slf4j-api-1.7.5.jar Normal file

Binary file not shown.

75
pom.xml Normal file
View File

@ -0,0 +1,75 @@
<?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>

15
project.properties Normal file
View File

@ -0,0 +1,15 @@
# 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

26
res/values/empty.xml Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<resources/>

9
sample_client/.classpath Normal file
View File

@ -0,0 +1,9 @@
<?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>

33
sample_client/.project Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ownCloud Sample Client</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>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.owncloud.android.lib.sampleclient"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.INTERNET" />
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
<activity android:name="MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,17 @@
# This file is used to override default values used by the Ant build system.
#
# This file must be checked into Version Control Systems, as it is
# integral to the build system of your project.
# This file is only used by the Ant script.
# You can use this to override default values such as
# 'source.dir' for the location of your java source folder and
# 'out.dir' for the location of your output folder.
# You can also use it define how the release builds are signed by declaring
# the following properties:
# 'key.store' for the location of your keystore and
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

92
sample_client/build.xml Normal file
View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="MainActivity" 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>

View File

@ -0,0 +1,15 @@
# 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=..

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>

View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/button_refresh"
style="@style/ButtonStyle"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="@string/refresh"
android:onClick="onClickHandler"
/>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/button_refresh"
android:layout_above="@+id/button_upload"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
>
</ListView>
<Button
android:id="@+id/button_upload"
style="@style/ButtonStyle"
android:layout_alignParentLeft="true"
android:layout_above="@+id/frame"
android:text="@string/upload"
android:onClick="onClickHandler"
/>
<TextView
android:id="@+id/upload_progress"
style="@style/ProgressStyle"
android:layout_below="@id/list_view"
android:layout_above="@id/frame"
android:layout_toRightOf="@id/button_upload"
android:layout_toLeftOf="@+id/button_delete_remote"
android:gravity="center"
android:textSize="14sp"
android:text="0%"
/>
<Button
android:id="@id/button_delete_remote"
style="@style/ButtonStyle"
android:layout_alignParentRight="true"
android:layout_above="@id/frame"
android:text="@string/delete_remote_file"
android:onClick="onClickHandler"
/>
<FrameLayout
android:id="@id/frame"
android:layout_width="match_parent"
android:layout_height="@dimen/frame_height"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_above="@+id/button_download"
>
</FrameLayout>
<Button
android:id="@id/button_download"
style="@style/ButtonStyle"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="@string/download"
android:onClick="onClickHandler"
/>
<TextView
android:id="@+id/download_progress"
style="@style/ProgressStyle"
android:layout_below="@id/frame"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@id/button_download"
android:layout_toLeftOf="@+id/button_delete_local"
android:gravity="center"
android:textSize="14sp"
android:text="0%"
/>
<Button
android:id="@id/button_delete_local"
style="@style/ButtonStyle"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="@string/delete_local_file"
android:onClick="onClickHandler"
/>
</RelativeLayout>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="ButtonStyle" parent="@android:style/Widget.Holo.Button">
<item name="android:layout_width">120dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textSize">12sp</item>
</style>
<style name="ProgressStyle" parent="@android:style/Widget.Holo.TextView">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textSize">12sp</item>
</style>
</resources>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<resources>
<dimen name="frame_height">120dp</dimen>
</resources>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<resources>
<string name="server_base_url"></string>
<string name="username"></string>
<string name="password"></string>
</resources>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<resources>
<string name="app_name">ownCloud Sample Client</string>
<string name="refresh">Refresh</string>
<string name="upload">Upload</string>
<string name="delete_remote_file">Delete remote file</string>
<string name="download">Download</string>
<string name="delete_local_file">Delete local file</string>
<string name="youre_doing_it_wrong">You\'re doing it wrong</string>
<string name="todo_start_refresh">TODO: start refresh</string>
<string name="todo_start_upload">TODO: start upload</string>
<string name="todo_start_remote_deletion">TODO: start remote deletion</string>
<string name="todo_start_download">TODO: start download</string>
<string name="todo_start_local_deletion">TODO: start local deletion</string>
<string name="todo_operation_finished_in_success">TODO: operation finished in success</string>
<string name="todo_operation_finished_in_fail">TODO: operation finished in fail</string>
<string name="upload_folder_path">to_upload</string>
<string name="download_folder_path">downloaded</string>
<string name="error_copying_sample_file">Sample file could not be saved in temporal folder; upload will not work</string>
<string name="sample_file_name">oc_sample.png</string>
<string name="sample_file_mimetype">image/png</string>
<string name="error_deleting_local_file">Downloaded file could not be deleted</string>
</resources>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="ButtonStyle" parent="@android:style/Widget.Button">
<item name="android:layout_width">120dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textSize">12sp</item>
</style>
<style name="ProgressStyle" parent="@android:style/Widget.TextView">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textSize">12sp</item>
</style>
</resources>

View File

@ -0,0 +1,46 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.sampleclient;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import com.owncloud.android.lib.operations.common.RemoteFile;
public class FilesArrayAdapter extends ArrayAdapter<RemoteFile> {
public FilesArrayAdapter(Context context, int resource) {
super(context, resource);
}
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView = (TextView)super.getView(position, convertView, parent);
textView.setText(getItem(position).getRemotePath());
return textView;
}
}

View File

@ -0,0 +1,267 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.sampleclient;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import com.owncloud.android.lib.accounts.AccountUtils;
import com.owncloud.android.lib.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.network.OwnCloudClientFactory;
import com.owncloud.android.lib.network.OwnCloudClient;
import com.owncloud.android.lib.operations.common.OnRemoteOperationListener;
import com.owncloud.android.lib.operations.common.RemoteFile;
import com.owncloud.android.lib.operations.common.RemoteOperation;
import com.owncloud.android.lib.operations.common.RemoteOperationResult;
import com.owncloud.android.lib.operations.remote.DownloadRemoteFileOperation;
import com.owncloud.android.lib.operations.remote.ReadRemoteFolderOperation;
import com.owncloud.android.lib.operations.remote.RemoveRemoteFileOperation;
import com.owncloud.android.lib.operations.remote.UploadRemoteFileOperation;
import com.owncloud.android.lib.utils.FileUtils;
import android.app.Activity;
import android.content.res.AssetManager;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnRemoteOperationListener, OnDatatransferProgressListener {
private static String LOG_TAG = MainActivity.class.getCanonicalName();
private Handler mHandler;
private OwnCloudClient mClient;
private FilesArrayAdapter mFilesAdapter;
private View mFrame;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mHandler = new Handler();
Uri serverUri = Uri.parse(getString(R.string.server_base_url) + AccountUtils.WEBDAV_PATH_4_0);
mClient = OwnCloudClientFactory.createOwnCloudClient(serverUri, this, true);
mClient.setBasicCredentials(getString(R.string.username), getString(R.string.password));
mFilesAdapter = new FilesArrayAdapter(this, R.layout.file_in_list);
((ListView)findViewById(R.id.list_view)).setAdapter(mFilesAdapter);
// TODO move to background thread or task
AssetManager assets = getAssets();
try {
String sampleFileName = getString(R.string.sample_file_name);
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
upFolder.mkdir();
File upFile = new File(upFolder, sampleFileName);
FileOutputStream fos = new FileOutputStream(upFile);
InputStream is = assets.open(sampleFileName);
int count = 0;
byte[] buffer = new byte[1024];
while ((count = is.read(buffer, 0, buffer.length)) >= 0) {
fos.write(buffer, 0, count);
}
is.close();
fos.close();
} catch (IOException e) {
Toast.makeText(this, R.string.error_copying_sample_file, Toast.LENGTH_SHORT).show();
Log.e(LOG_TAG, getString(R.string.error_copying_sample_file), e);
}
mFrame = findViewById(R.id.frame);
}
@Override
public void onDestroy() {
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
File upFile = upFolder.listFiles()[0];
upFile.delete();
upFolder.delete();
super.onDestroy();
}
public void onClickHandler(View button) {
switch (button.getId()) {
case R.id.button_refresh:
startRefresh();
break;
case R.id.button_upload:
startUpload();
break;
case R.id.button_delete_remote:
startRemoteDeletion();
break;
case R.id.button_download:
startDownload();
break;
case R.id.button_delete_local:
startLocalDeletion();
break;
default:
Toast.makeText(this, R.string.youre_doing_it_wrong, Toast.LENGTH_SHORT).show();
}
}
private void startRefresh() {
ReadRemoteFolderOperation refreshOperation = new ReadRemoteFolderOperation(FileUtils.PATH_SEPARATOR);
refreshOperation.execute(mClient, this, mHandler);
}
private void startUpload() {
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
String mimeType = getString(R.string.sample_file_mimetype);
UploadRemoteFileOperation uploadOperation = new UploadRemoteFileOperation(fileToUpload.getAbsolutePath(), remotePath, mimeType);
uploadOperation.addDatatransferProgressListener(this);
uploadOperation.execute(mClient, this, mHandler);
}
private void startRemoteDeletion() {
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath);
removeOperation.execute(mClient, this, mHandler);
}
private void startDownload() {
File downFolder = new File(getCacheDir(), getString(R.string.download_folder_path));
downFolder.mkdir();
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
DownloadRemoteFileOperation downloadOperation = new DownloadRemoteFileOperation(remotePath, downFolder.getAbsolutePath());
downloadOperation.addDatatransferProgressListener(this);
downloadOperation.execute(mClient, this, mHandler);
}
@SuppressWarnings("deprecation")
private void startLocalDeletion() {
File downFolder = new File(getCacheDir(), getString(R.string.download_folder_path));
File downloadedFile = downFolder.listFiles()[0];
if (!downloadedFile.delete() && downloadedFile.exists()) {
Toast.makeText(this, R.string.error_deleting_local_file, Toast.LENGTH_SHORT).show();
} else {
((TextView) findViewById(R.id.download_progress)).setText("0%");
findViewById(R.id.frame).setBackgroundDrawable(null);
}
}
@Override
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
if (!result.isSuccess()) {
Toast.makeText(this, R.string.todo_operation_finished_in_fail, Toast.LENGTH_SHORT).show();
Log.e(LOG_TAG, result.getLogMessage(), result.getException());
} else if (operation instanceof ReadRemoteFolderOperation) {
onSuccessfulRefresh((ReadRemoteFolderOperation)operation, result);
} else if (operation instanceof UploadRemoteFileOperation ) {
onSuccessfulUpload((UploadRemoteFileOperation)operation, result);
} else if (operation instanceof RemoveRemoteFileOperation ) {
onSuccessfulRemoteDeletion((RemoveRemoteFileOperation)operation, result);
} else if (operation instanceof DownloadRemoteFileOperation ) {
onSuccessfulDownload((DownloadRemoteFileOperation)operation, result);
} else {
Toast.makeText(this, R.string.todo_operation_finished_in_success, Toast.LENGTH_SHORT).show();
}
}
private void onSuccessfulRefresh(ReadRemoteFolderOperation operation, RemoteOperationResult result) {
mFilesAdapter.clear();
List<RemoteFile> files = result.getData();
if (files != null) {
Iterator<RemoteFile> it = files.iterator();
while (it.hasNext()) {
mFilesAdapter.add(it.next());
}
mFilesAdapter.remove(mFilesAdapter.getItem(0));
}
mFilesAdapter.notifyDataSetChanged();
}
private void onSuccessfulUpload(UploadRemoteFileOperation operation, RemoteOperationResult result) {
startRefresh();
}
private void onSuccessfulRemoteDeletion(RemoveRemoteFileOperation operation, RemoteOperationResult result) {
startRefresh();
TextView progressView = (TextView) findViewById(R.id.upload_progress);
if (progressView != null) {
progressView.setText("0%");
}
}
@SuppressWarnings("deprecation")
private void onSuccessfulDownload(DownloadRemoteFileOperation operation, RemoteOperationResult result) {
File downFolder = new File(getCacheDir(), getString(R.string.download_folder_path));
File downloadedFile = downFolder.listFiles()[0];
BitmapDrawable bDraw = new BitmapDrawable(getResources(), downloadedFile.getAbsolutePath());
mFrame.setBackgroundDrawable(bDraw);
}
@Override
public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName) {
final long percentage = (totalToTransfer > 0 ? totalTransferredSoFar * 100 / totalToTransfer : 0);
final boolean upload = fileName.contains(getString(R.string.upload_folder_path));
Log.d(LOG_TAG, "progressRate " + percentage);
mHandler.post(new Runnable() {
@Override
public void run() {
TextView progressView = null;
if (upload) {
progressView = (TextView) findViewById(R.id.upload_progress);
} else {
progressView = (TextView) findViewById(R.id.download_progress);
}
if (progressView != null) {
progressView.setText(Long.toString(percentage) + "%");
}
}
});
}
}

View File

@ -0,0 +1,50 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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";
}
}

View File

@ -0,0 +1,112 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.accounts;
import com.owncloud.android.lib.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";
/**
* 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 supportsOAuth If true, access with OAuth 2 authorization is considered.
* @param supportsSamlSso If true, and supportsOAuth is false, access with SAML-based single-sign-on is considered.
* @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;
}
/**
* 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;
}
}
}

View File

@ -0,0 +1,112 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.accounts;
import android.accounts.Account;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Account with extra information specific for ownCloud accounts.
*
* TODO integrate in the main app
*
* @author David A. Velasco
*/
public class OwnCloudAccount extends Account {
public static class Constants {
/**
* Value under this key should handle path to webdav php script. Will be
* removed and usage should be replaced by combining
* {@link com.owncloud.android.authentication.AuthenticatorActivity.KEY_OC_BASE_URL} and
* {@link com.owncloud.android.lib.utils.utils.OwnCloudVersion}
*
* @deprecated
*/
public static final String KEY_OC_URL = "oc_url";
/**
* Version should be 3 numbers separated by dot so it can be parsed by
* {@link com.owncloud.android.lib.utils.utils.OwnCloudVersion}
*/
public static final String KEY_OC_VERSION = "oc_version";
/**
* Base url should point to owncloud installation without trailing / ie:
* http://server/path or https://owncloud.server
*/
public static final String KEY_OC_BASE_URL = "oc_base_url";
/**
* Flag signaling if the ownCloud server can be accessed with OAuth2 access tokens.
*/
public static final String KEY_SUPPORTS_OAUTH2 = "oc_supports_oauth2";
/**
* Flag signaling if the ownCloud server can be accessed with session cookies from SAML-based web single-sign-on.
*/
public static final String KEY_SUPPORTS_SAML_WEB_SSO = "oc_supports_saml_web_sso";
}
private String mAuthTokenType;
public OwnCloudAccount(String name, String type, String authTokenType) {
super(name, type);
// TODO validate authTokentype as supported
mAuthTokenType = authTokenType;
}
/**
* Reconstruct from parcel
*
* @param source The source parcel
*/
public OwnCloudAccount(Parcel source) {
super(source);
mAuthTokenType = source.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(mAuthTokenType);
}
public String getAuthTokenType() {
return mAuthTokenType;
}
public static final Parcelable.Creator<OwnCloudAccount> CREATOR = new Parcelable.Creator<OwnCloudAccount>() {
@Override
public OwnCloudAccount createFromParcel(Parcel source) {
return new OwnCloudAccount(source);
}
@Override
public OwnCloudAccount [] newArray(int size) {
return new OwnCloudAccount[size];
}
};
}

View File

@ -0,0 +1,296 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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;
}
}
}

View File

@ -0,0 +1,155 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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;
}
}
}

View File

@ -0,0 +1,278 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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");
}
}

View File

@ -0,0 +1,104 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.network;
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;
}
}

View File

@ -0,0 +1,137 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.network;
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);
}
}

View File

@ -0,0 +1,151 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.network;
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 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.getAbsolutePath());
}
}
}
} 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);
}
}
}

View File

@ -0,0 +1,138 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.network;
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;
/**
* 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.getAbsolutePath());
}
}
}
} 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();
}
}
}

View File

@ -0,0 +1,176 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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 OwnCloudClients */
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;
}
}

View File

@ -0,0 +1,30 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.network;
public interface OnDatatransferProgressListener {
public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileAbsoluteName);
}

View File

@ -0,0 +1,251 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.network;
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.lib.network.webdav.WebdavUtils;
import android.net.Uri;
import android.util.Log;
public class OwnCloudClient 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 = OwnCloudClient.class.getSimpleName();
public static final String USER_AGENT = "Android-ownCloud";
static private byte[] sExhaustBuffer = new byte[1024];
/**
* Constructor
*/
public OwnCloudClient(HttpConnectionManager connectionMgr) {
super(connectionMgr);
Log.d(TAG, "Creating OwnCloudClient");
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;
}
}

View File

@ -0,0 +1,158 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.network;
import java.io.IOException;
import java.security.GeneralSecurityException;
import com.owncloud.android.lib.accounts.AccountTypeUtils;
import com.owncloud.android.lib.accounts.AccountUtils;
import com.owncloud.android.lib.accounts.OwnCloudAccount;
import com.owncloud.android.lib.accounts.AccountUtils.AccountNotFoundException;
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 OwnCloudClient 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 OwnCloudClient 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 OwnCloudClient createOwnCloudClient (Account account, Context appContext) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException {
//Log_OC.d(TAG, "Creating OwnCloudClient 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;
OwnCloudClient 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 OwnCloudClient 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;
OwnCloudClient 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 OwnCloudClient 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 OwnCloudClient is being created.
* @return A OwnCloudClient object ready to be used
*/
public static OwnCloudClient 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);
}
OwnCloudClient client = new OwnCloudClient(NetworkUtils.getMultiThreadedConnManager());
client.setDefaultTimeouts(DEFAULT_DATA_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
client.setBaseUri(uri);
client.setFollowRedirects(followRedirects);
return client;
}
}

View File

@ -0,0 +1,39 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.network;
import java.util.Collection;
public interface ProgressiveDataTransferer {
public void addDatatransferProgressListener (OnDatatransferProgressListener listener);
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners);
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener);
}

View File

@ -0,0 +1,151 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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;
}
}

View File

@ -0,0 +1,158 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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;
}
}

View File

@ -0,0 +1,83 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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;
}
}

View File

@ -0,0 +1,33 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.operations.common;
public interface OnRemoteOperationListener {
void onRemoteOperationFinish(RemoteOperation caller, RemoteOperationResult result);
}

View File

@ -0,0 +1,35 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.operations.common;
public class OperationCancelledException extends Exception {
/**
* Generated serial version - to avoid Java warning
*/
private static final long serialVersionUID = -6350981497740424983L;
}

View File

@ -0,0 +1,187 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.operations.common;
import java.io.Serializable;
import android.os.Parcel;
import android.os.Parcelable;
import com.owncloud.android.lib.network.webdav.WebdavEntry;
import com.owncloud.android.lib.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);
}
}

View File

@ -0,0 +1,295 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.operations.common;
import java.io.IOException;
import org.apache.commons.httpclient.Credentials;
import com.owncloud.android.lib.network.BearerCredentials;
import com.owncloud.android.lib.network.OwnCloudClient;
import com.owncloud.android.lib.network.OwnCloudClientFactory;
import com.owncloud.android.lib.operations.common.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 OwnCloudClient 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(OwnCloudClient 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(OwnCloudClient)}.
*
* @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(OwnCloudClient client) {
if (client == null)
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL OwnCloudClient");
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(OwnCloudClient)}.
*
* @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(OwnCloudClient client, OnRemoteOperationListener listener, Handler listenerHandler) {
if (client == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL OwnCloudClient");
}
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 OwnCloudClient in the last call to {@link RemoteOperation#execute(OwnCloudClient)}
*
* @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 OwnCloudClient in the last call to {@link RemoteOperation#execute(OwnCloudClient, 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(OwnCloudClient, 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 OwnCloudClient getClient() {
return mClient;
}
}

View File

@ -0,0 +1,363 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.operations.common;
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.lib.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.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")));
}
}

View File

@ -0,0 +1,101 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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.lib.network.ChunkFromFileChannelRequestEntity;
import com.owncloud.android.lib.network.OwnCloudClient;
import com.owncloud.android.lib.network.ProgressiveDataTransferer;
import com.owncloud.android.lib.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(OwnCloudClient 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;
}
}

View File

@ -0,0 +1,118 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.operations.remote;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
import android.util.Log;
import com.owncloud.android.lib.network.OwnCloudClient;
import com.owncloud.android.lib.network.webdav.WebdavUtils;
import com.owncloud.android.lib.operations.common.RemoteOperation;
import com.owncloud.android.lib.operations.common.RemoteOperationResult;
import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.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(OwnCloudClient 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, OwnCloudClient client) {
RemoteOperation operation = new CreateRemoteFolderOperation(parentPath,
mCreateFullPath);
return operation.execute(client);
}
}

View File

@ -0,0 +1,179 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.operations.remote;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
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.lib.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.network.OwnCloudClient;
import com.owncloud.android.lib.network.webdav.WebdavUtils;
import com.owncloud.android.lib.operations.common.OperationCancelledException;
import com.owncloud.android.lib.operations.common.RemoteOperation;
import com.owncloud.android.lib.operations.common.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 String mRemotePath;
private String mDownloadFolderPath;
public DownloadRemoteFileOperation(String remotePath, String downloadFolderPath) {
mRemotePath = remotePath;
mDownloadFolderPath = downloadFolderPath;
}
@Override
protected RemoteOperationResult run(OwnCloudClient 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 " + mRemotePath + " to " + getTmpPath() + ": " + result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log.e(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " + result.getLogMessage(), e);
}
return result;
}
protected int downloadFile(OwnCloudClient client, File targetFile) throws HttpException, IOException, OperationCancelledException {
int status = -1;
boolean savedFile = false;
mGet = new GetMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
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;
Header contentLength = mGet.getResponseHeader("Content-Length");
long totalToTransfer = (contentLength != null && contentLength.getValue().length() >0) ? Long.parseLong(contentLength.getValue()) : 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, totalToTransfer, 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 mDownloadFolderPath + mRemotePath;
}
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
}
}

View File

@ -0,0 +1,104 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.operations.remote;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.HeadMethod;
import com.owncloud.android.lib.network.OwnCloudClient;
import com.owncloud.android.lib.network.webdav.WebdavUtils;
import com.owncloud.android.lib.operations.common.RemoteOperation;
import com.owncloud.android.lib.operations.common.RemoteOperationResult;
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(OwnCloudClient 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();
}
}

View File

@ -0,0 +1,127 @@
/* 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.lib.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.lib.network.OwnCloudClient;
import com.owncloud.android.lib.operations.common.RemoteOperation;
import com.owncloud.android.lib.operations.common.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(OwnCloudClient 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);
}
}

View File

@ -0,0 +1,115 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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.lib.network.OwnCloudClient;
import com.owncloud.android.lib.network.webdav.WebdavEntry;
import com.owncloud.android.lib.network.webdav.WebdavUtils;
import com.owncloud.android.lib.operations.common.RemoteFile;
import com.owncloud.android.lib.operations.common.RemoteOperation;
import com.owncloud.android.lib.operations.common.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(OwnCloudClient 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;
}
}

View File

@ -0,0 +1,169 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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.lib.network.OwnCloudClient;
import com.owncloud.android.lib.network.webdav.WebdavEntry;
import com.owncloud.android.lib.network.webdav.WebdavUtils;
import com.owncloud.android.lib.operations.common.RemoteFile;
import com.owncloud.android.lib.operations.common.RemoteOperation;
import com.owncloud.android.lib.operations.common.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(OwnCloudClient 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, OwnCloudClient 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;
}
}

View File

@ -0,0 +1,90 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.operations.remote;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
import android.util.Log;
import com.owncloud.android.lib.network.OwnCloudClient;
import com.owncloud.android.lib.network.webdav.WebdavUtils;
import com.owncloud.android.lib.operations.common.RemoteOperation;
import com.owncloud.android.lib.operations.common.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(OwnCloudClient 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;
}
}

View File

@ -0,0 +1,153 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.operations.remote;
import java.io.File;
import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
import android.util.Log;
import com.owncloud.android.lib.network.OwnCloudClient;
import com.owncloud.android.lib.network.webdav.WebdavUtils;
import com.owncloud.android.lib.operations.common.RemoteOperation;
import com.owncloud.android.lib.operations.common.RemoteOperationResult;
import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.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(OwnCloudClient 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;
}
}
}

View File

@ -0,0 +1,154 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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.lib.network.FileRequestEntity;
import com.owncloud.android.lib.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.network.OwnCloudClient;
import com.owncloud.android.lib.network.ProgressiveDataTransferer;
import com.owncloud.android.lib.network.webdav.WebdavUtils;
import com.owncloud.android.lib.operations.common.OperationCancelledException;
import com.owncloud.android.lib.operations.common.RemoteOperation;
import com.owncloud.android.lib.operations.common.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(OwnCloudClient 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(OwnCloudClient 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();
}
}
}

View File

@ -0,0 +1,78 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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;
}
}

View File

@ -0,0 +1,92 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.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;
}
}
}

9
tests/.classpath Normal file
View File

@ -0,0 +1,9 @@
<?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>

33
tests/.project Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ownCloud Android Library 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>

60
tests/AndroidManifest.xml Normal file
View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.owncloud.android.lib.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.lib.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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

BIN
tests/ic_launcher-web.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

15
tests/project.properties Normal file
View File

@ -0,0 +1,15 @@
# 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=..

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,39 @@
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<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>

32
tests/res/menu/test.xml Normal file
View File

@ -0,0 +1,32 @@
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<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>

View File

@ -0,0 +1,32 @@
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<resources>
<!--
Customize dimensions originally defined in res/values/dimens.xml (such as
screen margins) for sw600dp devices (e.g. 7" tablets) here.
-->
</resources>

View File

@ -0,0 +1,33 @@
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<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>

View File

@ -0,0 +1,35 @@
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<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>

View File

@ -0,0 +1,36 @@
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<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>

View File

@ -0,0 +1,30 @@
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<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>

View File

@ -0,0 +1,43 @@
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<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>

View File

@ -0,0 +1,174 @@
/* 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.lib.test_project;
import java.io.File;
import com.owncloud.android.lib.network.OwnCloudClientFactory;
import com.owncloud.android.lib.network.OwnCloudClient;
import com.owncloud.android.lib.operations.common.RemoteFile;
import com.owncloud.android.lib.operations.common.RemoteOperationResult;
import com.owncloud.android.lib.operations.remote.ChunkedUploadRemoteFileOperation;
import com.owncloud.android.lib.operations.remote.CreateRemoteFolderOperation;
import com.owncloud.android.lib.operations.remote.DownloadRemoteFileOperation;
import com.owncloud.android.lib.operations.remote.ReadRemoteFolderOperation;
import com.owncloud.android.lib.operations.remote.RemoveRemoteFileOperation;
import com.owncloud.android.lib.operations.remote.RenameRemoteFileOperation;
import com.owncloud.android.lib.operations.remote.UploadRemoteFileOperation;
import com.owncloud.android.lib.test_project.R;
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 OwnCloudClient 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.getRemotePath(), 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;
}
}

View File

@ -0,0 +1,10 @@
<?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="/ownCloud Android Library Test Project"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

33
tests/test_cases/.project Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ownCloud Android Library Tests</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>

View File

@ -0,0 +1,4 @@
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

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.owncloud.android.lib.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.lib.test_project"
android:targetPackage="com.owncloud.android.lib.test_project" />
</manifest>

View File

@ -0,0 +1,14 @@
# 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<resources>
<string name="app_name">Oc_framework-testTest</string>
</resources>

View File

@ -0,0 +1,119 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.test_project.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.owncloud.android.lib.operations.common.RemoteOperationResult;
import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.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);
}
}

View File

@ -0,0 +1,87 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.test_project.test;
import com.owncloud.android.lib.operations.common.RemoteOperationResult;
import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.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());
}
}

View File

@ -0,0 +1,130 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.test_project.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.owncloud.android.lib.operations.common.RemoteFile;
import com.owncloud.android.lib.operations.common.RemoteOperationResult;
import com.owncloud.android.lib.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());
}
}

Some files were not shown because too many files have changed in this diff Show More