initial commit
15
.classpath
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="src" path="gen"/>
|
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
|
<classpathentry kind="lib" path="lib/commons-codec-1.4.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/commons-logging-1.1.1.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/httpclient-4.1.1.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/httpclient-cache-4.1.1.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/httpcore-4.1.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/httpmime-4.1.1.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/commons-httpclient-3.0.1.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/commons-io-2.0.1.jar"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
19
.gitignore
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# built application files
|
||||||
|
*.apk
|
||||||
|
*.ap_
|
||||||
|
|
||||||
|
# files for the dex VM
|
||||||
|
*.dex
|
||||||
|
|
||||||
|
# Java class files
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# generated files
|
||||||
|
bin/
|
||||||
|
gen/
|
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc)
|
||||||
|
local.properties
|
||||||
|
|
||||||
|
# Mac .DS_Store files
|
||||||
|
.DS_Store
|
33
.project
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>ownCloud</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>
|
79
AndroidManifest.xml
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="eu.alefzero.owncloud"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0">
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.GET_ACCOUNTS" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.USE_CREDENTIALS" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.MANAGE_ACCOUNTS" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.WRITE_SETTINGS" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.READ_CONTACTS" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.WRITE_CONTACTS" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.READ_SYNC_STATS" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.READ_SYNC_SETTINGS" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.WRITE_SYNC_SETTINGS" />
|
||||||
|
<uses-sdk android:minSdkVersion="7"></uses-sdk>
|
||||||
|
<uses-permission android:name="android.permission.READ_SMS"></uses-permission>
|
||||||
|
|
||||||
|
<application android:icon="@drawable/icon" android:label="@string/app_name">
|
||||||
|
<activity android:name=".OwnCloudMainScreen"
|
||||||
|
android:label="@string/app_name">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity android:name="OwnCloudUploader">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND"></action>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"></category>
|
||||||
|
<data android:mimeType="*/*"></data>
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE"></action>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"></category>
|
||||||
|
<data android:mimeType="*/*"></data>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity android:name="Preferences"></activity>
|
||||||
|
<activity android:name="PreferencesNewSession">
|
||||||
|
</activity>
|
||||||
|
<service
|
||||||
|
android:exported="true" android:name=".authenticator.AccountAuthenticatorService">
|
||||||
|
<intent-filter>
|
||||||
|
<action
|
||||||
|
android:name="android.accounts.AccountAuthenticator" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.accounts.AccountAuthenticator"
|
||||||
|
android:resource="@xml/authenticator" />
|
||||||
|
</service>
|
||||||
|
<service
|
||||||
|
android:exported="true" android:name=".syncadapter.SyncService">
|
||||||
|
<intent-filter>
|
||||||
|
<action
|
||||||
|
android:name="android.content.SyncAdapter" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.content.SyncAdapter"
|
||||||
|
android:resource="@xml/syncadapter" />
|
||||||
|
</service>
|
||||||
|
<provider android:name="cp" android:authorities="org.owncloud" android:enabled="true" android:syncable="true" android:exported="false" android:label="@string/sync_string"></provider>
|
||||||
|
<activity android:name=".authenticator.AuthenticatorActivity"></activity>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
11
default.properties
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# 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 use,
|
||||||
|
# "build.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
|
||||||
|
# Project target.
|
||||||
|
target=android-7
|
BIN
lib/commons-codec-1.4.jar
Normal file
BIN
lib/commons-httpclient-3.0.1.jar
Normal file
BIN
lib/commons-io-2.0.1.jar
Normal file
BIN
lib/commons-logging-1.1.1.jar
Normal file
BIN
lib/httpclient-4.1.1.jar
Normal file
BIN
lib/httpclient-cache-4.1.1.jar
Normal file
BIN
lib/httpcore-4.1.jar
Normal file
BIN
lib/httpmime-4.1.1.jar
Normal file
36
proguard.cfg
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
-optimizationpasses 5
|
||||||
|
-dontusemixedcaseclassnames
|
||||||
|
-dontskipnonpubliclibraryclasses
|
||||||
|
-dontpreverify
|
||||||
|
-verbose
|
||||||
|
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||||
|
|
||||||
|
-keep public class * extends android.app.Activity
|
||||||
|
-keep public class * extends android.app.Application
|
||||||
|
-keep public class * extends android.app.Service
|
||||||
|
-keep public class * extends android.content.BroadcastReceiver
|
||||||
|
-keep public class * extends android.content.ContentProvider
|
||||||
|
-keep public class * extends android.app.backup.BackupAgentHelper
|
||||||
|
-keep public class * extends android.preference.Preference
|
||||||
|
-keep public class com.android.vending.licensing.ILicensingService
|
||||||
|
|
||||||
|
-keepclasseswithmembernames class * {
|
||||||
|
native <methods>;
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclasseswithmembernames class * {
|
||||||
|
public <init>(android.content.Context, android.util.AttributeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclasseswithmembernames class * {
|
||||||
|
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers enum * {
|
||||||
|
public static **[] values();
|
||||||
|
public static ** valueOf(java.lang.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keep class * implements android.os.Parcelable {
|
||||||
|
public static final android.os.Parcelable$Creator *;
|
||||||
|
}
|
9
res/anim/disappear.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/decelerate_interpolator"
|
||||||
|
android:fromAlpha="1.0" android:toAlpha="0.0"
|
||||||
|
android:duration="400"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/grow_from_bottom.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="0.3" android:toXScale="1.0"
|
||||||
|
android:fromYScale="0.3" android:toYScale="1.0"
|
||||||
|
android:pivotX="50%" android:pivotY="100%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/decelerate_interpolator"
|
||||||
|
android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/grow_from_bottomleft_to_topright.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="0.3" android:toXScale="1.0"
|
||||||
|
android:fromYScale="0.3" android:toYScale="1.0"
|
||||||
|
android:pivotX="0%" android:pivotY="50%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/decelerate_interpolator"
|
||||||
|
android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/grow_from_bottomright_to_topleft.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="0.3" android:toXScale="1.0"
|
||||||
|
android:fromYScale="0.3" android:toYScale="1.0"
|
||||||
|
android:pivotX="100%" android:pivotY="50%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/decelerate_interpolator"
|
||||||
|
android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/grow_from_top.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="0.3" android:toXScale="1.0"
|
||||||
|
android:fromYScale="0.3" android:toYScale="1.0"
|
||||||
|
android:pivotX="50%" android:pivotY="0%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/decelerate_interpolator"
|
||||||
|
android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/grow_from_topleft_to_bottomright.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="0.3" android:toXScale="1.0"
|
||||||
|
android:fromYScale="0.3" android:toYScale="1.0"
|
||||||
|
android:pivotX="0%" android:pivotY="0%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/decelerate_interpolator"
|
||||||
|
android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/grow_from_topright_to_bottomleft.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="0.3" android:toXScale="1.0"
|
||||||
|
android:fromYScale="0.3" android:toYScale="1.0"
|
||||||
|
android:pivotX="100%" android:pivotY="0%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/decelerate_interpolator"
|
||||||
|
android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/pump_bottom.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="1.1" android:toXScale="1.0"
|
||||||
|
android:fromYScale="1.1" android:toYScale="1.0"
|
||||||
|
android:pivotX="50%" android:pivotY="100%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/decelerate_interpolator"
|
||||||
|
android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/pump_top.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="1.1" android:toXScale="1.0"
|
||||||
|
android:fromYScale="1.1" android:toYScale="1.0"
|
||||||
|
android:pivotX="50%" android:pivotY="0%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/decelerate_interpolator"
|
||||||
|
android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
20
res/anim/push_left_in.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2007 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<translate android:fromXDelta="100%p" android:toXDelta="0" android:duration="300"/>
|
||||||
|
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />
|
||||||
|
</set>
|
20
res/anim/push_left_out.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2007 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<translate android:fromXDelta="0" android:toXDelta="-100%p" android:duration="300"/>
|
||||||
|
<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="300" />
|
||||||
|
</set>
|
14
res/anim/shrink_from_bottom.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="1.0" android:toXScale="0.3"
|
||||||
|
android:fromYScale="1.0" android:toYScale="0.3"
|
||||||
|
android:pivotX="50%" android:pivotY="0%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/accelerate_interpolator"
|
||||||
|
android:fromAlpha="1.0" android:toAlpha="0.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/shrink_from_bottomleft_to_topright.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="1.0" android:toXScale="0.3"
|
||||||
|
android:fromYScale="1.0" android:toYScale="0.3"
|
||||||
|
android:pivotX="100%" android:pivotY="0%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/accelerate_interpolator"
|
||||||
|
android:fromAlpha="1.0" android:toAlpha="0.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/shrink_from_bottomright_to_topleft.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="1.0" android:toXScale="0.3"
|
||||||
|
android:fromYScale="1.0" android:toYScale="0.3"
|
||||||
|
android:pivotX="0%" android:pivotY="0%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/accelerate_interpolator"
|
||||||
|
android:fromAlpha="1.0" android:toAlpha="0.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/shrink_from_top.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="1.0" android:toXScale="0.3"
|
||||||
|
android:fromYScale="1.0" android:toYScale="0.3"
|
||||||
|
android:pivotX="50%" android:pivotY="100%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/accelerate_interpolator"
|
||||||
|
android:fromAlpha="1.0" android:toAlpha="0.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/shrink_from_topleft_to_bottomright.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="1.0" android:toXScale="0.3"
|
||||||
|
android:fromYScale="1.0" android:toYScale="0.3"
|
||||||
|
android:pivotX="100%" android:pivotY="100%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/accelerate_interpolator"
|
||||||
|
android:fromAlpha="1.0" android:toAlpha="0.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
14
res/anim/shrink_from_topright_to_bottomleft.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<scale
|
||||||
|
android:fromXScale="1.0" android:toXScale="0.3"
|
||||||
|
android:fromYScale="1.0" android:toYScale="0.3"
|
||||||
|
android:pivotX="0%" android:pivotY="100%"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
<alpha
|
||||||
|
android:interpolator="@android:anim/accelerate_interpolator"
|
||||||
|
android:fromAlpha="1.0" android:toAlpha="0.0"
|
||||||
|
android:duration="@android:integer/config_shortAnimTime"
|
||||||
|
/>
|
||||||
|
</set>
|
BIN
res/drawable-hdpi/ic_menu_archive.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/drawable-hdpi/icon.png
Normal file
After Width: | Height: | Size: 8 KiB |
BIN
res/drawable-hdpi/owncloud_logo.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
res/drawable-ldpi/ic_menu_archive.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/drawable-ldpi/icon.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
res/drawable-ldpi/owncloud_logo.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
res/drawable-mdpi/ic_menu_archive.png
Normal file
After Width: | Height: | Size: 831 B |
BIN
res/drawable-mdpi/icon.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
res/drawable-mdpi/owncloud_logo.png
Normal file
After Width: | Height: | Size: 29 KiB |
17
res/drawable/action_item_btn.xml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:dither="true">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:state_window_focused="false"
|
||||||
|
android:drawable="@android:color/transparent" />
|
||||||
|
<item
|
||||||
|
android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/action_item_selected"/>
|
||||||
|
<item
|
||||||
|
android:state_focused="true"
|
||||||
|
android:drawable="@drawable/action_item_selected"/>
|
||||||
|
<item
|
||||||
|
android:drawable="@android:color/transparent"/>
|
||||||
|
|
||||||
|
</selector>
|
BIN
res/drawable/action_item_selected.9.png
Normal file
After Width: | Height: | Size: 909 B |
BIN
res/drawable/arrow_down.png
Normal file
After Width: | Height: | Size: 922 B |
BIN
res/drawable/arrow_left.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
res/drawable/arrow_right.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
res/drawable/arrow_up.png
Normal file
After Width: | Height: | Size: 893 B |
8
res/drawable/btn.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/btn_round_pressed" />
|
||||||
|
<item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/btn_round_pressed" />
|
||||||
|
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/btn_round_pressed" />
|
||||||
|
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/btn_round_pressed" />
|
||||||
|
<item android:drawable="@drawable/btn_round"/>
|
||||||
|
</selector>
|
8
res/drawable/btn_round.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="5dip" />
|
||||||
|
<solid android:color="#aac4d2" />
|
||||||
|
<padding android:left="15dp" android:top="5dp" android:right="15dp" android:bottom="5dp" />
|
||||||
|
<stroke android:width="2dip" android:color="#ffffff" />
|
||||||
|
</shape>
|
8
res/drawable/btn_round_pressed.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="5dip" />
|
||||||
|
<solid android:color="#aac4d2" />
|
||||||
|
<padding android:left="15dp" android:top="5dp" android:right="15dp" android:bottom="5dp" />
|
||||||
|
<stroke android:width="5dip" android:color="#ff8000" />
|
||||||
|
</shape>
|
BIN
res/drawable/dashboard.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
res/drawable/download.png
Normal file
After Width: | Height: | Size: 264 B |
BIN
res/drawable/file.png
Normal file
After Width: | Height: | Size: 391 B |
BIN
res/drawable/folder.png
Normal file
After Width: | Height: | Size: 386 B |
BIN
res/drawable/header.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
res/drawable/ic_menu_archive.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/drawable/owncloud_logo_small_white.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
res/drawable/popup.9.png
Normal file
After Width: | Height: | Size: 457 B |
BIN
res/drawable/share.png
Normal file
After Width: | Height: | Size: 478 B |
5
res/drawable/uploader_list_separator.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<gradient android:startColor="#fefefe" android:centerColor="#cccccc" android:endColor="#fefefe" android:angle="0"/>
|
||||||
|
</shape>
|
29
res/layout/account_setup.xml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent" android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical" android:background="#F7F7F7" android:focusable="true">
|
||||||
|
<LinearLayout android:id="@+id/linearLayout7" android:paddingBottom="2pt" android:gravity="center_vertical|top" android:layout_gravity="top" android:layout_height="wrap_content" android:paddingTop="2pt" android:orientation="vertical" android:layout_width="fill_parent" android:background="#1D2D44">
|
||||||
|
<ImageView android:id="@+id/main_header_small" android:src="@drawable/owncloud_logo_small_white" android:layout_gravity="center|center_vertical|center_horizontal" android:layout_height="wrap_content" android:layout_width="wrap_content" android:focusable="true"></ImageView>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:id="@+id/linearLayout2" android:layout_width="fill_parent" android:orientation="vertical" android:gravity="center_vertical" android:layout_gravity="center|center_vertical" android:layout_height="fill_parent">
|
||||||
|
<TableLayout android:id="@+id/tableLayout1" android:layout_height="wrap_content" android:gravity="center_horizontal" android:layout_width="fill_parent">
|
||||||
|
<TableRow android:layout_height="wrap_content" android:id="@+id/tableRow1" android:layout_width="wrap_content" android:gravity="center_horizontal">
|
||||||
|
<TextView android:id="@+id/textView1" android:text="@string/setup_title" android:layout_marginBottom="15dip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/black" android:textStyle="bold" android:layout_marginTop="15dip" android:textSize="7pt"></TextView>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow android:layout_height="wrap_content" android:weightSum="1.0" android:id="@+id/tableRow2" android:layout_width="wrap_content" android:gravity="center_horizontal">
|
||||||
|
<EditText android:id="@+id/host_URL" android:layout_weight="0.75" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="@string/setup_hint_address">
|
||||||
|
<requestFocus></requestFocus>
|
||||||
|
</EditText>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow android:layout_height="wrap_content" android:weightSum="1.0" android:id="@+id/tableRow3" android:layout_width="wrap_content" android:gravity="center_horizontal">
|
||||||
|
<EditText android:id="@+id/account_username" android:layout_weight=".75" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="@android:color/black" android:hint="@string/setup_hint_username"></EditText>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow android:layout_height="wrap_content" android:weightSum="1.0" android:id="@+id/tableRow4" android:layout_width="fill_parent" android:gravity="center_horizontal">
|
||||||
|
<EditText android:id="@+id/account_password" android:layout_weight=".75" android:layout_width="fill_parent" android:inputType="textPassword" android:layout_height="wrap_content" android:textColor="@android:color/black" android:hint="@string/setup_hint_password"></EditText>
|
||||||
|
</TableRow>
|
||||||
|
</TableLayout>
|
||||||
|
<LinearLayout android:layout_height="wrap_content" android:weightSum="1.0" android:id="@+id/linearLayout1" android:layout_width="fill_parent" android:gravity="center_horizontal" android:orientation="horizontal">
|
||||||
|
<Button android:id="@+id/buttonOK" android:text="@string/setup_btn_connect" android:layout_width="wrap_content" android:layout_weight=".50" android:layout_height="wrap_content" android:onClick="onOkClick"></Button>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
25
res/layout/action_item.xml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:background="@drawable/action_item_btn">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingLeft="5dip"
|
||||||
|
android:paddingRight="10dip"
|
||||||
|
android:text="Chart"
|
||||||
|
android:textColor="#fff"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
37
res/layout/file_display.xml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent" android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical" android:background="#F7F7F7">
|
||||||
|
<LinearLayout android:id="@+id/linearLayout7" android:paddingBottom="2pt" android:gravity="center_vertical|top" android:layout_gravity="top" android:layout_height="wrap_content" android:paddingTop="2pt" android:orientation="vertical" android:layout_width="fill_parent" android:background="#1D2D44">
|
||||||
|
<ImageView android:id="@+id/main_header_small" android:src="@drawable/owncloud_logo_small_white" android:layout_gravity="center|center_vertical|center_horizontal" android:layout_height="wrap_content" android:layout_width="wrap_content" android:focusable="true"></ImageView>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:layout_width="fill_parent"
|
||||||
|
android:id="@+id/linearLayout1" android:layout_height="wrap_content">
|
||||||
|
<LinearLayout android:layout_width="wrap_content"
|
||||||
|
android:id="@+id/linearLayout2" android:layout_height="fill_parent">
|
||||||
|
<ImageView android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:src="@drawable/icon"
|
||||||
|
android:id="@+id/imageView1"></ImageView>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:layout_width="wrap_content"
|
||||||
|
android:id="@+id/linearLayout3" android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<TextView android:id="@+id/textView1" android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content" android:text="TextView"></TextView>
|
||||||
|
<TextView android:id="@+id/textView2" android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content" android:text="TextView"></TextView>
|
||||||
|
<TextView android:id="@+id/textView3" android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content" android:text="TextView"></TextView>
|
||||||
|
<TextView android:id="@+id/textView4" android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content" android:text="TextView"></TextView>
|
||||||
|
<TextView android:id="@+id/textView5" android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content" android:text="TextView"></TextView>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:layout_width="fill_parent"
|
||||||
|
android:id="@+id/linearLayout4" android:layout_height="fill_parent">
|
||||||
|
<ListView android:layout_width="fill_parent" android:id="@android:id/list"
|
||||||
|
android:layout_height="fill_parent" android:divider="@drawable/uploader_list_separator"
|
||||||
|
android:dividerHeight="1dip"></ListView>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
10
res/layout/file_display_action_list_element.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_gravity="center_horizontal" android:gravity="center_horizontal">
|
||||||
|
<ImageView android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:src="@drawable/icon"
|
||||||
|
android:id="@+id/imageView1" android:layout_gravity="center_vertical"></ImageView>
|
||||||
|
<TextView android:text="TextView" android:id="@+id/textView1"
|
||||||
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical" android:textSize="11pt"></TextView>
|
||||||
|
</LinearLayout>
|
17
res/layout/list_layout.xml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:id="@+id/ListItemLayout" android:layout_width="fill_parent"
|
||||||
|
android:background="#F7F7F7" android:layout_height="wrap_content">
|
||||||
|
<ImageView android:layout_width="wrap_content" android:src="@drawable/ic_menu_archive"
|
||||||
|
android:id="@+id/imageView1" android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="15dip" android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"></ImageView>
|
||||||
|
<TextView android:layout_height="wrap_content"
|
||||||
|
android:textColor="#303030" android:layout_width="wrap_content"
|
||||||
|
android:text="TextView" android:layout_marginLeft="5dip"
|
||||||
|
android:layout_marginBottom="5dip" android:layout_marginRight="30dip"
|
||||||
|
android:id="@+id/Filename" android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false" android:textSize="20dip">
|
||||||
|
</TextView>
|
||||||
|
</LinearLayout>
|
27
res/layout/main.xml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent" android:background="#F7F7F7"
|
||||||
|
android:orientation="vertical" android:layout_height="fill_parent">
|
||||||
|
<LinearLayout android:layout_width="fill_parent"
|
||||||
|
android:id="@+id/linearLayout7" android:orientation="vertical"
|
||||||
|
android:background="#1D2D44" android:gravity="top"
|
||||||
|
android:layout_gravity="center_vertical" android:layout_height="wrap_content" android:paddingTop="2pt" android:paddingBottom="2pt">
|
||||||
|
<ImageView android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/owncloud_logo_small_white"
|
||||||
|
android:layout_width="wrap_content" android:layout_gravity="center_vertical|center_horizontal"
|
||||||
|
android:id="@+id/main_header_small"></ImageView>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/linearLayout1" android:layout_width="fill_parent"
|
||||||
|
android:layout_gravity="center_horizontal" android:gravity="center_horizontal">
|
||||||
|
<TextView android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:id="@+id/directory_name"
|
||||||
|
android:layout_gravity="center" android:gravity="center"></TextView>
|
||||||
|
</LinearLayout>
|
||||||
|
<FrameLayout android:layout_height="fill_parent"
|
||||||
|
android:layout_width="fill_parent" android:id="@+id/frameLayout1">
|
||||||
|
<ListView android:id="@android:id/list" android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" android:divider="@drawable/uploader_list_separator"
|
||||||
|
android:dividerHeight="1dip" android:fadingEdge="none"></ListView>
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
40
res/layout/popup.xml
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/scroller"
|
||||||
|
android:layout_marginTop="16dip"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/popup"
|
||||||
|
android:fadingEdgeLength="5dip"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/tracks"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="10dip"/>
|
||||||
|
|
||||||
|
</ScrollView >
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/arrow_up"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/arrow_up" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/arrow_down"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="-4dip"
|
||||||
|
android:src="@drawable/arrow_down" android:layout_below="@+id/scroller"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
22
res/layout/uploader_layout.xml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_height="wrap_content" android:orientation="vertical"
|
||||||
|
android:layout_width="wrap_content" android:background="#fefefe"
|
||||||
|
android:gravity="center">
|
||||||
|
<TextView android:layout_width="fill_parent" android:text="Choose upload directory"
|
||||||
|
android:layout_height="wrap_content" android:id="@+id/textView1" android:textColor="@android:color/black"
|
||||||
|
android:gravity="center_horizontal"></TextView>
|
||||||
|
<FrameLayout android:layout_height="fill_parent"
|
||||||
|
android:layout_width="fill_parent" android:id="@+id/frameLayout1"
|
||||||
|
android:layout_below="@+id/textView1" android:layout_above="@+id/linearLayout1">
|
||||||
|
<ListView android:id="@android:id/list" android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" android:divider="@drawable/uploader_list_separator"
|
||||||
|
android:dividerHeight="1dip"></ListView>
|
||||||
|
</FrameLayout>
|
||||||
|
<LinearLayout android:id="@+id/linearLayout1"
|
||||||
|
android:layout_width="fill_parent" android:layout_alignParentBottom="true" android:layout_height="wrap_content" android:orientation="vertical">
|
||||||
|
<Button android:layout_gravity="bottom" android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent" android:id="@+id/uploader_choose_folder"
|
||||||
|
android:text="@string/uploader_btn_upload_text"></Button>
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
9
res/layout/uploader_list_item_layout.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:background="#fefefe">
|
||||||
|
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_menu_archive" android:id="@+id/imageView1"></ImageView>
|
||||||
|
<TextView android:text="TextView" android:layout_width="fill_parent" android:id="@+id/textView1" android:layout_height="wrap_content" android:textColor="@android:color/black" android:textSize="20dip"/>
|
||||||
|
</LinearLayout>
|
6
res/menu/menu.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:title="Settings" android:icon="@android:drawable/ic_menu_preferences" android:id="@+id/settingsItem"></item>
|
||||||
|
<item android:id="@+id/item1" android:title="Create Directory" android:icon="@android:drawable/ic_menu_add"></item>
|
||||||
|
</menu>
|
5
res/menu/prefs_menu.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:id="@+id/addSessionItem" android:icon="@+android:drawable/ic_menu_add" android:title="@string/prefs_add_session"></item>
|
||||||
|
</menu>
|
6
res/menu/session_context_menu.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:id="@+id/SessionContextEdit" android:title="Edit"></item>
|
||||||
|
<item android:id="@+id/SessionContextRemove" android:title="REmove"></item>
|
||||||
|
</menu>
|
39
res/values/strings.xml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="hello">Hello World, OwnCloudMainScreen!</string>
|
||||||
|
<string name="app_name">ownCloud</string>
|
||||||
|
<string name="main_password">Password:</string>
|
||||||
|
<string name="main_login">Username:</string>
|
||||||
|
<string name="main_button_login">Login</string>
|
||||||
|
<string name="prefs_general">General</string>
|
||||||
|
<string name="prefs_sessions">Stored sessions</string>
|
||||||
|
<string name="prefs_add_session">Add new session</string>
|
||||||
|
<string name="new_session_id">Session Name</string>
|
||||||
|
<string name="new_session_url">URL</string>
|
||||||
|
<string name="new_session_username">Username</string>
|
||||||
|
<string name="new_session_password">Password</string>
|
||||||
|
<string name="new_session_save">OK</string>
|
||||||
|
<string name="new_session_cancel">Cancel</string>
|
||||||
|
<string name="new_session_uri_error">Wrong URL given</string>
|
||||||
|
<string name="new_session_session_name_error">Wrong session name</string>
|
||||||
|
<string name="sync_string">filelist and pinned files</string>
|
||||||
|
<string name="uploader_no_file_selected">No file selected for upload</string>
|
||||||
|
<string name="setup_hint_username">Username</string>
|
||||||
|
<string name="setup_hint_password">Password</string>
|
||||||
|
<string name="setup_hint_address">Web address</string>
|
||||||
|
<string name="setup_title">Connect to your ownCloud</string>
|
||||||
|
<string name="setup_btn_connect">Connect</string>
|
||||||
|
<string name="uploader_btn_upload_text">Upload</string>
|
||||||
|
<string name="uploader_wrn_no_account_title">No account found</string>
|
||||||
|
<string name="uploader_wrn_no_account_text">No correct ownCloud account found on device. Please setup account first.</string>
|
||||||
|
<string name="uploader_wrn_no_account_setup_btn_text">Setup</string>
|
||||||
|
<string name="uploader_wrn_no_account_quit_btn_text">Quit</string>
|
||||||
|
<string name="uploader_info_uploading">Uploading</string>
|
||||||
|
<string name="uploader_btn_create_dir_text">Create dir for upload</string>
|
||||||
|
<string name="common_ok">OK</string>
|
||||||
|
<string name="common_cancel">Cancel</string>
|
||||||
|
<string name="uploader_info_dirname">Directory name</string>
|
||||||
|
<string name="uploader_upload_succeed">Uploading completed successfully</string>
|
||||||
|
<string name="uploader_upload_failed">Upload failed: </string>
|
||||||
|
<string name="common_choose_account">Choose account</string>
|
||||||
|
</resources>
|
52
res/values/styles.xml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="Animations" />
|
||||||
|
|
||||||
|
<!-- PopDownMenu -->
|
||||||
|
<style name="Animations.PopDownMenu" />
|
||||||
|
|
||||||
|
<style name="Animations.PopDownMenu.Center">
|
||||||
|
<item name="@android:windowEnterAnimation">@anim/grow_from_top</item>
|
||||||
|
<item name="@android:windowExitAnimation">@anim/shrink_from_bottom</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Animations.PopDownMenu.Left">
|
||||||
|
<item name="@android:windowEnterAnimation">@anim/grow_from_topleft_to_bottomright</item>
|
||||||
|
<item name="@android:windowExitAnimation">@anim/shrink_from_bottomright_to_topleft</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Animations.PopDownMenu.Right">
|
||||||
|
<item name="@android:windowEnterAnimation">@anim/grow_from_topright_to_bottomleft</item>
|
||||||
|
<item name="@android:windowExitAnimation">@anim/shrink_from_bottomleft_to_topright</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Animations.PopDownMenu.Reflect">
|
||||||
|
<item name="@android:windowEnterAnimation">@anim/pump_top</item>
|
||||||
|
<item name="@android:windowExitAnimation">@anim/disappear</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- PopUpMenu -->
|
||||||
|
<style name="Animations.PopUpMenu" />
|
||||||
|
|
||||||
|
<style name="Animations.PopUpMenu.Center">
|
||||||
|
<item name="@android:windowEnterAnimation">@anim/grow_from_bottom</item>
|
||||||
|
<item name="@android:windowExitAnimation">@anim/shrink_from_top</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Animations.PopUpMenu.Left">
|
||||||
|
<item name="@android:windowEnterAnimation">@anim/grow_from_bottomleft_to_topright</item>
|
||||||
|
<item name="@android:windowExitAnimation">@anim/shrink_from_topright_to_bottomleft</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Animations.PopUpMenu.Right">
|
||||||
|
<item name="@android:windowEnterAnimation">@anim/grow_from_bottomright_to_topleft</item>
|
||||||
|
<item name="@android:windowExitAnimation">@anim/shrink_from_topleft_to_bottomright</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Animations.PopUpMenu.Reflect">
|
||||||
|
<item name="@android:windowEnterAnimation">@anim/pump_bottom</item>
|
||||||
|
<item name="@android:windowExitAnimation">@anim/disappear</item>
|
||||||
|
</style>
|
||||||
|
<color name="setup_text_hint">#777777</color>
|
||||||
|
<color name="setup_text_typed">#000000</color>
|
||||||
|
</resources>
|
7
res/xml/authenticator.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:accountType="owncloud"
|
||||||
|
android:icon="@drawable/icon"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:smallIcon="@drawable/icon">
|
||||||
|
</account-authenticator>
|
30
res/xml/contacts.xml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010, The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<ContactsSource xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<ContactsDataKind
|
||||||
|
android:mimeType="vnd.android.cursor.item/vnd.samplesyncadapter.profile"
|
||||||
|
android:icon="@drawable/icon"
|
||||||
|
android:summaryColumn="data2"
|
||||||
|
android:detailColumn="data3"
|
||||||
|
android:detailSocialSummary="true"
|
||||||
|
android:syncable="true"/>
|
||||||
|
|
||||||
|
</ContactsSource>
|
4
res/xml/preferences.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<CheckBoxPreference android:title="Create images thumbnails" android:key="create_thumbnails"></CheckBoxPreference>
|
||||||
|
</PreferenceScreen>
|
6
res/xml/preferences_new_session.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<EditTextPreference></EditTextPreference>
|
||||||
|
<EditTextPreference></EditTextPreference>
|
||||||
|
</PreferenceScreen>
|
27
res/xml/syncadapter.xml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010, The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- The attributes in this XML file provide configuration information -->
|
||||||
|
<!-- for the SyncAdapter. -->
|
||||||
|
|
||||||
|
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:contentAuthority="org.owncloud"
|
||||||
|
android:accountType="owncloud"
|
||||||
|
android:supportsUploading="true"
|
||||||
|
/>
|
37
src/eu/alefzero/owncloud/ActionItem.java
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
|
||||||
|
public class ActionItem {
|
||||||
|
private Drawable mIcon;
|
||||||
|
private String mTitle;
|
||||||
|
private OnClickListener mClickListener;
|
||||||
|
|
||||||
|
public ActionItem() { }
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
mTitle = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return mTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIcon(Drawable icon) {
|
||||||
|
mIcon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable getIcon() {
|
||||||
|
return mIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnClickListener(OnClickListener listener) {
|
||||||
|
mClickListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OnClickListener getOnClickListerner() {
|
||||||
|
return mClickListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
126
src/eu/alefzero/owncloud/CustomPopup.java
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.view.View.OnTouchListener;
|
||||||
|
import android.view.ViewGroup.LayoutParams;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
|
|
||||||
|
public class CustomPopup {
|
||||||
|
protected final View mAnchor;
|
||||||
|
protected final PopupWindow mWindow;
|
||||||
|
private View root;
|
||||||
|
private Drawable background = null;
|
||||||
|
protected final WindowManager mWManager;
|
||||||
|
|
||||||
|
public CustomPopup(View anchor) {
|
||||||
|
mAnchor = anchor;
|
||||||
|
mWindow = new PopupWindow(anchor.getContext());
|
||||||
|
|
||||||
|
mWindow.setTouchInterceptor(new OnTouchListener() {
|
||||||
|
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
|
||||||
|
CustomPopup.this.dismiss();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mWManager = (WindowManager) anchor.getContext().getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
onCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void onCreate() {}
|
||||||
|
public void onShow() {}
|
||||||
|
|
||||||
|
public void preShow() {
|
||||||
|
if (root == null) {
|
||||||
|
throw new IllegalStateException("setContentView called with a view to display");
|
||||||
|
}
|
||||||
|
|
||||||
|
onShow();
|
||||||
|
|
||||||
|
if (background == null) {
|
||||||
|
mWindow.setBackgroundDrawable(new BitmapDrawable());
|
||||||
|
} else {
|
||||||
|
mWindow.setBackgroundDrawable(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
|
||||||
|
mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
|
||||||
|
mWindow.setTouchable(true);
|
||||||
|
mWindow.setFocusable(true);
|
||||||
|
mWindow.setOutsideTouchable(true);
|
||||||
|
|
||||||
|
mWindow.setContentView(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackgroundDrawable(Drawable background) {
|
||||||
|
this.background = background;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentView(View root) {
|
||||||
|
this.root = root;
|
||||||
|
mWindow.setContentView(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentView(int layoutResId) {
|
||||||
|
LayoutInflater inflater =
|
||||||
|
(LayoutInflater) mAnchor.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
setContentView(inflater.inflate(layoutResId, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showDropDown() {
|
||||||
|
showDropDown(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showDropDown(int x, int y) {
|
||||||
|
preShow();
|
||||||
|
mWindow.setAnimationStyle(android.R.style.Animation_Dialog);
|
||||||
|
mWindow.showAsDropDown(mAnchor, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showLikeQuickAction() {
|
||||||
|
showLikeQuickAction(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showLikeQuickAction(int x, int y) {
|
||||||
|
preShow();
|
||||||
|
|
||||||
|
mWindow.setAnimationStyle(android.R.style.Animation_Dialog);
|
||||||
|
int[] location = new int[2];
|
||||||
|
mAnchor.getLocationOnScreen(location);
|
||||||
|
|
||||||
|
Rect anchorRect =
|
||||||
|
new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight());
|
||||||
|
|
||||||
|
root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
|
||||||
|
root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||||
|
|
||||||
|
int rootW = root.getWidth(), rootH = root.getHeight();
|
||||||
|
int screenW = mWManager.getDefaultDisplay().getWidth();
|
||||||
|
|
||||||
|
int xpos = ((screenW-rootW)/2) + x;
|
||||||
|
int ypos = anchorRect.top - rootH + y;
|
||||||
|
|
||||||
|
if (rootH > anchorRect.top) {
|
||||||
|
ypos = anchorRect.bottom + y;
|
||||||
|
}
|
||||||
|
mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xpos, ypos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dismiss() {
|
||||||
|
mWindow.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
79
src/eu/alefzero/owncloud/DbHandler.java
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class DbHandler {
|
||||||
|
private SQLiteDatabase mDB;
|
||||||
|
private OpenerHepler mHelper;
|
||||||
|
private final String mDatabaseName = "ownCloud";
|
||||||
|
private final String TABLE_SESSIONS = "sessions";
|
||||||
|
private final int mDatabaseVersion = 1;
|
||||||
|
|
||||||
|
public DbHandler(Context context) {
|
||||||
|
mHelper = new OpenerHepler(context);
|
||||||
|
mDB = mHelper.getWritableDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector<OwnCloudSession> getSessionList() {
|
||||||
|
Cursor c = mDB.query(TABLE_SESSIONS, null, null, null, null, null, null);
|
||||||
|
Vector<OwnCloudSession> v = new Vector<OwnCloudSession>();
|
||||||
|
if (!c.moveToFirst()) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
while (!c.isAfterLast()) {
|
||||||
|
v.add(new OwnCloudSession(c.getString(c.getColumnIndex("sessionName")),
|
||||||
|
c.getString(c.getColumnIndex("sessionUrl")),
|
||||||
|
c.getInt(c.getColumnIndex("_id"))));
|
||||||
|
c.moveToNext();
|
||||||
|
}
|
||||||
|
c.close();
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSession(String sessionName, String uri) {
|
||||||
|
ContentValues cv = new ContentValues();
|
||||||
|
cv.put("sessionName", sessionName);
|
||||||
|
cv.put("sessionUrl", uri);
|
||||||
|
mDB.insert(TABLE_SESSIONS, null, cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeSessionWithId(int sessionId) {
|
||||||
|
mDB.delete(TABLE_SESSIONS, "_id = ?", new String[] {String.valueOf(sessionId)});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeSessionFields(int id, String hostname, String uri) {
|
||||||
|
ContentValues cv = new ContentValues();
|
||||||
|
cv.put("sessionName", hostname);
|
||||||
|
cv.put("sessionUrl", uri);
|
||||||
|
mDB.update(TABLE_SESSIONS, cv, "_id = ?", new String[] {String.valueOf(id)});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
mDB.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class OpenerHepler extends SQLiteOpenHelper {
|
||||||
|
public OpenerHepler(Context context) {
|
||||||
|
super(context, mDatabaseName, null, mDatabaseVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(SQLiteDatabase db) {
|
||||||
|
db.execSQL("CREATE TABLE " + TABLE_SESSIONS + " (" +
|
||||||
|
" _id INTEGER PRIMARY KEY, " +
|
||||||
|
" sessionName TEXT, " +
|
||||||
|
" sessionUrl TEXT);");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
src/eu/alefzero/owncloud/DisplayUtils.java
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/* ownCloud Android client application
|
||||||
|
* Copyright (C) 2011 Bartek Przybylski
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class DisplayUtils {
|
||||||
|
public static String bitsToHumanReadable(long bitsLen) {
|
||||||
|
double result = bitsLen;
|
||||||
|
int attachedsuff = 0;
|
||||||
|
while (result > 1024 && attachedsuff < suffixes.length) {
|
||||||
|
result /= 1024.;
|
||||||
|
attachedsuff++;
|
||||||
|
}
|
||||||
|
result = ((int)(result * 100))/100.;
|
||||||
|
return result+suffixes[attachedsuff];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convertMIMEtoPrettyPrint(String mimetype) {
|
||||||
|
if (mimeType2HUmanReadable.containsKey(mimetype)) {
|
||||||
|
return mimeType2HUmanReadable.get(mimetype);
|
||||||
|
}
|
||||||
|
return mimetype.split("/")[1].toUpperCase() + " file";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String[] suffixes = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
|
||||||
|
|
||||||
|
private static HashMap<String, String> mimeType2HUmanReadable;
|
||||||
|
static {
|
||||||
|
mimeType2HUmanReadable = new HashMap<String, String>();
|
||||||
|
// images
|
||||||
|
mimeType2HUmanReadable.put("image/jpeg", "JPEG image");
|
||||||
|
mimeType2HUmanReadable.put("image/jpg", "JPEG image");
|
||||||
|
mimeType2HUmanReadable.put("image/png", "PNG image");
|
||||||
|
mimeType2HUmanReadable.put("image/bmp", "Bitmap image");
|
||||||
|
mimeType2HUmanReadable.put("image/gif", "GIF image");
|
||||||
|
mimeType2HUmanReadable.put("image/svg+xml", "JPEG image");
|
||||||
|
mimeType2HUmanReadable.put("image/tiff", "TIFF image");
|
||||||
|
// music
|
||||||
|
mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file");
|
||||||
|
mimeType2HUmanReadable.put("application/ogg", "OGG music file");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
158
src/eu/alefzero/owncloud/FileListActionListAdapter.java
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/* ownCloud Android client application
|
||||||
|
* Copyright (C) 2011 Bartek Przybylski
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta;
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.DataSetObserver;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.MediaStore.Images.Media;
|
||||||
|
import android.sax.StartElementListener;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ListAdapter;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
public class FileListActionListAdapter implements ListAdapter {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private Account mAccount;
|
||||||
|
private String mFilename, mFileType, mFilePath, mFileStoragePath, mItemId;
|
||||||
|
|
||||||
|
private final int ITEM_DOWNLOAD = 0;
|
||||||
|
private final int ITEM_SHARE = 1;
|
||||||
|
|
||||||
|
public FileListActionListAdapter(Cursor c, Context co, Account account) {
|
||||||
|
mContext = co;
|
||||||
|
mFilename = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_NAME));
|
||||||
|
mFileType = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE));
|
||||||
|
mFilePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH));
|
||||||
|
mFileStoragePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));
|
||||||
|
mItemId = c.getString(c.getColumnIndex(ProviderTableMeta._ID));
|
||||||
|
mAccount = account;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean areAllItemsEnabled() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled(int position) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getItem(int position) {
|
||||||
|
if (position == 0) {
|
||||||
|
AccountManager accm = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
|
||||||
|
String ocurl = accm.getUserData(mAccount, AccountAuthenticator.KEY_OC_URL);
|
||||||
|
ocurl += mFilePath + mFilename;
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
|
intent.setDataAndType(Uri.fromFile(new File(mFileStoragePath)), mFileType);
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getItemId(int position) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
View v = convertView;
|
||||||
|
if (v == null) {
|
||||||
|
LayoutInflater vi = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
v = vi.inflate(R.layout.file_display_action_list_element, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView tv;
|
||||||
|
ImageView iv;
|
||||||
|
switch (position) {
|
||||||
|
case ITEM_DOWNLOAD :
|
||||||
|
tv = (TextView) v.findViewById(R.id.textView1);
|
||||||
|
if (mFileStoragePath == null) {
|
||||||
|
tv.setText("Download");
|
||||||
|
} else {
|
||||||
|
setActionName(tv);
|
||||||
|
}
|
||||||
|
iv = (ImageView) v.findViewById(R.id.imageView1);
|
||||||
|
iv.setImageResource(R.drawable.download);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerDataSetObserver(DataSetObserver observer) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setActionName(TextView tv) {
|
||||||
|
if (mFileType.matches("image/.*")) {
|
||||||
|
tv.setText("View");
|
||||||
|
} else if (mFileType.matches("audio/.*") || mFileType.matches("video/.*")) {
|
||||||
|
tv.setText("Play");
|
||||||
|
} else {
|
||||||
|
tv.setText("Open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
103
src/eu/alefzero/owncloud/FileListListAdapter.java
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import java.security.Provider;
|
||||||
|
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta;
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.DataSetObserver;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.View.OnLongClickListener;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ListAdapter;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
|
|
||||||
|
public class FileListListAdapter implements ListAdapter {
|
||||||
|
|
||||||
|
private Cursor mCursor;
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
public FileListListAdapter(Cursor c, Context context) {
|
||||||
|
mCursor = c;
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean areAllItemsEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled(int position) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return mCursor.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getItem(int position) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getItemId(int position) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
View v = convertView;
|
||||||
|
if (v == null) {
|
||||||
|
LayoutInflater vi = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
v = vi.inflate(R.layout.list_layout, null);
|
||||||
|
}
|
||||||
|
if (mCursor.moveToPosition(position)) {
|
||||||
|
TextView tv = (TextView) v.findViewById(R.id.Filename);
|
||||||
|
tv.setText(mCursor.getString(mCursor.getColumnIndex(ProviderMeta.ProviderTableMeta.FILE_NAME)));
|
||||||
|
if (!mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)).equals("DIR")) {
|
||||||
|
ImageView iv = (ImageView) v.findViewById(R.id.imageView1);
|
||||||
|
iv.setImageResource(R.drawable.file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerDataSetObserver(DataSetObserver observer) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
281
src/eu/alefzero/owncloud/OwnCloudMainScreen.java
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
/* ownCloud Android client application
|
||||||
|
* Copyright (C) 2011 Bartek Przybylski
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.ListActivity;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.DialogInterface.OnCancelListener;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
|
||||||
|
|
||||||
|
public class OwnCloudMainScreen extends ListActivity {
|
||||||
|
private DbHandler mDBHandler;
|
||||||
|
private Stack<String> mParents;
|
||||||
|
private Account mAccount;
|
||||||
|
private Cursor mCursor;
|
||||||
|
private boolean mIsDisplayingFile;
|
||||||
|
|
||||||
|
private static final int DIALOG_CHOOSE_ACCOUNT = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
mParents = new Stack<String>();
|
||||||
|
mIsDisplayingFile = false;
|
||||||
|
mDBHandler = new DbHandler(getBaseContext());
|
||||||
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
setContentView(R.layout.main);
|
||||||
|
|
||||||
|
AccountManager accMan = AccountManager.get(this);
|
||||||
|
Account[] accounts = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
|
||||||
|
|
||||||
|
if (accounts.length == 0) {
|
||||||
|
// using string value since in API7 this constatn is not defined
|
||||||
|
// in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS
|
||||||
|
// and Settings.EXTRA_AUTHORITIES
|
||||||
|
Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
|
||||||
|
intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE});
|
||||||
|
startActivity(intent);
|
||||||
|
} else if (accounts.length > 1) {
|
||||||
|
showDialog(DIALOG_CHOOSE_ACCOUNT);
|
||||||
|
} else {
|
||||||
|
mAccount = accounts[0];
|
||||||
|
populateFileList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.settingsItem :
|
||||||
|
Intent i = new Intent(this, Preferences.class);
|
||||||
|
startActivity(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(int id) {
|
||||||
|
switch (id) {
|
||||||
|
case DIALOG_CHOOSE_ACCOUNT:
|
||||||
|
return createChooseAccountDialog();
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown dialog id: " + id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
inflater.inflate(R.menu.menu, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
mDBHandler.close();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dialog createChooseAccountDialog() {
|
||||||
|
final AccountManager accMan = AccountManager.get(this);
|
||||||
|
CharSequence[] items = new CharSequence[accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];
|
||||||
|
int i = 0;
|
||||||
|
for (Account a : accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)) {
|
||||||
|
items[i++] = a.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
|
builder.setTitle(R.string.common_choose_account);
|
||||||
|
builder.setCancelable(true);
|
||||||
|
builder.setItems(items, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int item) {
|
||||||
|
mAccount = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[item];
|
||||||
|
dialog.dismiss();
|
||||||
|
populateFileList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setOnCancelListener(new OnCancelListener() {
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
OwnCloudMainScreen.this.finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AlertDialog alert = builder.create();
|
||||||
|
return alert;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (mIsDisplayingFile) {
|
||||||
|
mIsDisplayingFile = false;
|
||||||
|
setContentView(R.layout.main);
|
||||||
|
Uri uri;
|
||||||
|
if (mParents.empty()) {
|
||||||
|
uri = ProviderTableMeta.CONTENT_URI;
|
||||||
|
} else {
|
||||||
|
uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek());
|
||||||
|
}
|
||||||
|
mCursor = managedQuery(uri,
|
||||||
|
null,
|
||||||
|
ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?",
|
||||||
|
new String[]{mAccount.name}, null);
|
||||||
|
|
||||||
|
if (mCursor.moveToFirst()) {
|
||||||
|
TextView tv = (TextView) findViewById(R.id.directory_name);
|
||||||
|
tv.setText(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)));
|
||||||
|
}
|
||||||
|
getListView().setAdapter(new FileListListAdapter(mCursor, this));
|
||||||
|
getListView().invalidate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mParents.size()==0) {
|
||||||
|
super.onBackPressed();
|
||||||
|
return;
|
||||||
|
} else if (mParents.size() == 1) {
|
||||||
|
mParents.pop();
|
||||||
|
mCursor = managedQuery(ProviderTableMeta.CONTENT_URI,
|
||||||
|
null,
|
||||||
|
ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?",
|
||||||
|
new String[]{mAccount.name},
|
||||||
|
null);
|
||||||
|
} else {
|
||||||
|
mParents.pop();
|
||||||
|
mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()),
|
||||||
|
null,
|
||||||
|
ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?",
|
||||||
|
new String[]{mAccount.name},
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
setListAdapter(new FileListListAdapter(mCursor, this));
|
||||||
|
getListView().invalidate();
|
||||||
|
|
||||||
|
TextView tv = (TextView) findViewById(R.id.directory_name);
|
||||||
|
String s = tv.getText().toString();
|
||||||
|
if (s.endsWith("/")) {
|
||||||
|
s = s.substring(0, s.length() - 1);
|
||||||
|
}
|
||||||
|
s = s.substring(0, s.lastIndexOf('/') + 1);
|
||||||
|
tv.setText(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||||
|
super.onListItemClick(l, v, position, id);
|
||||||
|
if (!mCursor.moveToPosition(position)) {
|
||||||
|
throw new IndexOutOfBoundsException("Incorrect item selected");
|
||||||
|
}
|
||||||
|
if (!mIsDisplayingFile) {
|
||||||
|
if (mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)).equals("DIR")) {
|
||||||
|
String id_ = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID));
|
||||||
|
String dirname = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME));
|
||||||
|
TextView tv = (TextView) findViewById(R.id.directory_name);
|
||||||
|
tv.setText(tv.getText().toString()+dirname+"/");
|
||||||
|
mParents.push(id_);
|
||||||
|
mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, id_),
|
||||||
|
null,
|
||||||
|
ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
|
||||||
|
new String[]{mAccount.name}, null);
|
||||||
|
setListAdapter(new FileListListAdapter(mCursor, this));
|
||||||
|
} else {
|
||||||
|
mIsDisplayingFile = true;
|
||||||
|
setContentView(R.layout.file_display);
|
||||||
|
String id_ = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID));
|
||||||
|
mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, id_),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
mCursor.moveToFirst();
|
||||||
|
// filename
|
||||||
|
TextView tv = (TextView) findViewById(R.id.textView1);
|
||||||
|
tv.setText(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)));
|
||||||
|
// filetype
|
||||||
|
tv = (TextView) findViewById(R.id.textView2);
|
||||||
|
tv.setText(DisplayUtils.convertMIMEtoPrettyPrint(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE))));
|
||||||
|
// size
|
||||||
|
tv = (TextView) findViewById(R.id.textView3);
|
||||||
|
tv.setText(DisplayUtils.bitsToHumanReadable(mCursor.getLong(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH))));
|
||||||
|
// modified
|
||||||
|
tv = (TextView) findViewById(R.id.textView4);
|
||||||
|
tv.setText(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_MODIFIED)));
|
||||||
|
if (!TextUtils.isEmpty(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)))) {
|
||||||
|
ImageView iv = (ImageView) findViewById(R.id.imageView1);
|
||||||
|
Bitmap bmp = BitmapFactory.decodeFile(mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
|
||||||
|
Matrix m = new Matrix();
|
||||||
|
float scale;
|
||||||
|
if (bmp.getWidth() > bmp.getHeight()) {
|
||||||
|
scale = (float) (200./bmp.getWidth());
|
||||||
|
} else {
|
||||||
|
scale = (float) (200./bmp.getHeight());
|
||||||
|
}
|
||||||
|
m.postScale(scale, scale);
|
||||||
|
Bitmap newBmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true);
|
||||||
|
iv.setImageBitmap(newBmp);
|
||||||
|
}
|
||||||
|
setListAdapter(new FileListActionListAdapter(mCursor, this, mAccount));
|
||||||
|
}
|
||||||
|
getListView().invalidate();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Intent i = (Intent) getListAdapter().getItem(position);
|
||||||
|
startActivity(i);
|
||||||
|
} catch (ClassCastException e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateFileList() {
|
||||||
|
TextView tv = (TextView) findViewById(R.id.directory_name);
|
||||||
|
tv.setText("/");
|
||||||
|
mCursor = getContentResolver().query(ProviderTableMeta.CONTENT_URI,
|
||||||
|
null,
|
||||||
|
ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?",
|
||||||
|
new String[]{mAccount.name},
|
||||||
|
null);
|
||||||
|
setListAdapter(new FileListListAdapter(mCursor, this));
|
||||||
|
getListView().invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
33
src/eu/alefzero/owncloud/OwnCloudSession.java
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
public class OwnCloudSession {
|
||||||
|
private String mSessionName;
|
||||||
|
private String mSessionUrl;
|
||||||
|
private int mEntryId;
|
||||||
|
|
||||||
|
public OwnCloudSession(String name, String url, int entryId) {
|
||||||
|
mSessionName = name;
|
||||||
|
mSessionUrl = url;
|
||||||
|
mEntryId = entryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
mSessionName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return mSessionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
mSessionUrl = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return mSessionUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEntryId() {
|
||||||
|
return mEntryId;
|
||||||
|
}
|
||||||
|
}
|
495
src/eu/alefzero/owncloud/OwnCloudUploader.java
Normal file
|
@ -0,0 +1,495 @@
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.sql.Date;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
|
import org.apache.http.auth.AuthScope;
|
||||||
|
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||||
|
import org.apache.http.client.methods.HttpPut;
|
||||||
|
import org.apache.http.entity.FileEntity;
|
||||||
|
import org.apache.http.entity.mime.MultipartEntity;
|
||||||
|
import org.apache.http.entity.mime.content.FileBody;
|
||||||
|
import org.apache.http.impl.auth.BasicScheme;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.apache.http.protocol.BasicHttpContext;
|
||||||
|
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.ListActivity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.app.AlertDialog.Builder;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.DialogInterface.OnCancelListener;
|
||||||
|
import android.content.DialogInterface.OnClickListener;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.provider.MediaStore.Images.Media;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.view.ViewGroup.LayoutParams;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.SimpleCursorAdapter;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
|
import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta;
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
|
||||||
|
import eu.alefzero.webdav.HttpMkCol;
|
||||||
|
import eu.alefzero.webdav.WebdavUtils;
|
||||||
|
|
||||||
|
public class OwnCloudUploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {
|
||||||
|
private static final String TAG = "ownCloudUploader";
|
||||||
|
|
||||||
|
private Account mAccount;
|
||||||
|
private AccountManager mAccountManager;
|
||||||
|
private String mUsername, mPassword;
|
||||||
|
private Cursor mCursor;
|
||||||
|
private Stack<String> mParents;
|
||||||
|
private Thread mUploadThread;
|
||||||
|
private Handler mHandler;
|
||||||
|
private ArrayList<Parcelable> mStreamsToUpload;
|
||||||
|
|
||||||
|
private final static int DIALOG_NO_ACCOUNT = 0;
|
||||||
|
private final static int DIALOG_WAITING = 1;
|
||||||
|
private final static int DIALOG_NO_STREAM = 2;
|
||||||
|
private final static int DIALOG_MULTIPLE_ACCOUNT = 3;
|
||||||
|
private final static int DIALOG_GET_DIRNAME = 4;
|
||||||
|
|
||||||
|
private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
mParents = new Stack<String>();
|
||||||
|
mHandler = new Handler();
|
||||||
|
if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {
|
||||||
|
prepareStreamsToUpload();
|
||||||
|
mAccountManager = (AccountManager)getSystemService(Context.ACCOUNT_SERVICE);
|
||||||
|
Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
|
||||||
|
if (accounts.length == 0) {
|
||||||
|
Log.i(TAG, "No ownCloud account is available");
|
||||||
|
showDialog(DIALOG_NO_ACCOUNT);
|
||||||
|
} else if (accounts.length > 1) {
|
||||||
|
Log.i(TAG, "More then one ownCloud is available");
|
||||||
|
showDialog(DIALOG_MULTIPLE_ACCOUNT);
|
||||||
|
} else {
|
||||||
|
mAccount = accounts[0];
|
||||||
|
setContentView(R.layout.uploader_layout);
|
||||||
|
populateDirectoryList();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showDialog(DIALOG_NO_STREAM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(final int id) {
|
||||||
|
final AlertDialog.Builder builder = new Builder(this);
|
||||||
|
switch (id) {
|
||||||
|
case DIALOG_WAITING:
|
||||||
|
ProgressDialog pDialog = new ProgressDialog(this);
|
||||||
|
pDialog.setIndeterminate(false);
|
||||||
|
pDialog.setCancelable(false);
|
||||||
|
pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));
|
||||||
|
return pDialog;
|
||||||
|
case DIALOG_NO_ACCOUNT:
|
||||||
|
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||||
|
builder.setTitle(R.string.uploader_wrn_no_account_title);
|
||||||
|
builder.setMessage(R.string.uploader_wrn_no_account_text);
|
||||||
|
builder.setCancelable(false);
|
||||||
|
builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
|
||||||
|
// using string value since in API7 this constatn is not defined
|
||||||
|
// in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS
|
||||||
|
// and Settings.EXTRA_AUTHORITIES
|
||||||
|
Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
|
||||||
|
intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE});
|
||||||
|
startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
|
||||||
|
} else {
|
||||||
|
// since in API7 there is no direct call for account setup, so we need to
|
||||||
|
// show our own AccountSetupAcricity, get desired results and setup
|
||||||
|
// everything for ourself
|
||||||
|
Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
|
||||||
|
startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return builder.create();
|
||||||
|
case DIALOG_GET_DIRNAME:
|
||||||
|
final EditText dirName = new EditText(getBaseContext());
|
||||||
|
builder.setView(dirName);
|
||||||
|
builder.setTitle(R.string.uploader_info_dirname);
|
||||||
|
String pathToUpload;
|
||||||
|
if (mParents.empty()) {
|
||||||
|
pathToUpload = "/";
|
||||||
|
} else {
|
||||||
|
mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
mCursor.moveToFirst();
|
||||||
|
pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) +
|
||||||
|
mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");
|
||||||
|
}
|
||||||
|
a a = new a(pathToUpload, dirName);
|
||||||
|
builder.setPositiveButton(R.string.common_ok, a);
|
||||||
|
builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return builder.create();
|
||||||
|
case DIALOG_MULTIPLE_ACCOUNT:
|
||||||
|
CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];
|
||||||
|
for (int i = 0; i < ac.length; ++i) {
|
||||||
|
ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;
|
||||||
|
}
|
||||||
|
builder.setTitle(R.string.common_choose_account);
|
||||||
|
builder.setItems(ac, new OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];
|
||||||
|
populateDirectoryList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setCancelable(true);
|
||||||
|
builder.setOnCancelListener(new OnCancelListener() {
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
dialog.cancel();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return builder.create();
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown dialog id: " + id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class a implements OnClickListener {
|
||||||
|
String mPath;
|
||||||
|
EditText mDirname;
|
||||||
|
public a(String path, EditText dirname) {
|
||||||
|
mPath = path; mDirname = dirname;
|
||||||
|
}
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
showDialog(DIALOG_WAITING);
|
||||||
|
mUploadThread = new Thread(new BackgroundUploader(mPath+mDirname.getText().toString(), mStreamsToUpload, mHandler, true));
|
||||||
|
mUploadThread.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
|
||||||
|
if (mParents.size()==0) {
|
||||||
|
super.onBackPressed();
|
||||||
|
return;
|
||||||
|
} else if (mParents.size() == 1) {
|
||||||
|
mParents.pop();
|
||||||
|
mCursor = managedQuery(ProviderTableMeta.CONTENT_URI,
|
||||||
|
null,
|
||||||
|
ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
|
||||||
|
new String[]{"DIR"},
|
||||||
|
null);
|
||||||
|
} else {
|
||||||
|
mParents.pop();
|
||||||
|
mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()),
|
||||||
|
null,
|
||||||
|
ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
|
||||||
|
new String[]{"DIR"},
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout,
|
||||||
|
mCursor,
|
||||||
|
new String[]{ProviderTableMeta.FILE_NAME},
|
||||||
|
new int[]{R.id.textView1});
|
||||||
|
setListAdapter(sca);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
if (!mCursor.moveToPosition(position)) {
|
||||||
|
throw new IndexOutOfBoundsException("Incorrect item selected");
|
||||||
|
}
|
||||||
|
String _id = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID));
|
||||||
|
mParents.push(_id);
|
||||||
|
|
||||||
|
mCursor.close();
|
||||||
|
mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, _id),
|
||||||
|
null,
|
||||||
|
ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
|
||||||
|
new String[]{"DIR"},
|
||||||
|
null);
|
||||||
|
SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout,
|
||||||
|
mCursor,
|
||||||
|
new String[]{ProviderTableMeta.FILE_NAME},
|
||||||
|
new int[]{R.id.textView1});
|
||||||
|
setListAdapter(sca);
|
||||||
|
getListView().invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onClick(View v) {
|
||||||
|
switch (v.getId()) {
|
||||||
|
case R.id.uploader_choose_folder:
|
||||||
|
String pathToUpload = null;
|
||||||
|
if (mParents.empty()) {
|
||||||
|
pathToUpload = "/";
|
||||||
|
} else {
|
||||||
|
mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
mCursor.moveToFirst();
|
||||||
|
pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) +
|
||||||
|
mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");
|
||||||
|
}
|
||||||
|
|
||||||
|
showDialog(DIALOG_WAITING);
|
||||||
|
mUploadThread = new Thread(new BackgroundUploader(pathToUpload, mStreamsToUpload, mHandler));
|
||||||
|
mUploadThread.start();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case android.R.id.button1: // dynamic action for create aditional dir
|
||||||
|
showDialog(DIALOG_GET_DIRNAME);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Wrong element clicked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onUploadComplete(boolean uploadSucc, String message) {
|
||||||
|
dismissDialog(DIALOG_WAITING);
|
||||||
|
Log.i(TAG, "UploadSucc: " + uploadSucc + " message: " + message);
|
||||||
|
if (uploadSucc) {
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.uploader_upload_succeed), Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, getResources().getString(R.string.uploader_upload_failed) + message, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
|
||||||
|
if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
|
||||||
|
dismissDialog(DIALOG_NO_ACCOUNT);
|
||||||
|
if (resultCode == RESULT_CANCELED) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);
|
||||||
|
if (accounts.length == 0) {
|
||||||
|
showDialog(DIALOG_NO_ACCOUNT);
|
||||||
|
} else {
|
||||||
|
// there is no need for checking for is there more then one account at this point
|
||||||
|
// since account setup can set only one account at time
|
||||||
|
mAccount = accounts[0];
|
||||||
|
populateDirectoryList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateDirectoryList() {
|
||||||
|
mUsername = mAccount.name.substring(0, mAccount.name.indexOf('@'));
|
||||||
|
mPassword = mAccountManager.getPassword(mAccount);
|
||||||
|
setContentView(R.layout.uploader_layout);
|
||||||
|
mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI,
|
||||||
|
null,
|
||||||
|
ProviderTableMeta.FILE_CONTENT_TYPE+"=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
|
||||||
|
new String[]{"DIR", mAccount.name},
|
||||||
|
null);
|
||||||
|
|
||||||
|
ListView lv = getListView();
|
||||||
|
lv.setOnItemClickListener(this);
|
||||||
|
SimpleCursorAdapter sca = new SimpleCursorAdapter(this,
|
||||||
|
R.layout.uploader_list_item_layout,
|
||||||
|
mCursor,
|
||||||
|
new String[]{ProviderTableMeta.FILE_NAME},
|
||||||
|
new int[]{R.id.textView1});
|
||||||
|
setListAdapter(sca);
|
||||||
|
Button btn = (Button) findViewById(R.id.uploader_choose_folder);
|
||||||
|
btn.setOnClickListener(this);
|
||||||
|
// insert create new directory for multiple items uploading
|
||||||
|
if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
|
||||||
|
Button createDirBtn = new Button(this);
|
||||||
|
createDirBtn.setId(android.R.id.button1);
|
||||||
|
createDirBtn.setText(R.string.uploader_btn_create_dir_text);
|
||||||
|
createDirBtn.setOnClickListener(this);
|
||||||
|
((LinearLayout)findViewById(R.id.linearLayout1)).addView(createDirBtn, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareStreamsToUpload() {
|
||||||
|
if (getIntent().getAction().equals(Intent.ACTION_SEND)) {
|
||||||
|
mStreamsToUpload = new ArrayList<Parcelable>();
|
||||||
|
mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
|
||||||
|
} else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
|
||||||
|
mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);
|
||||||
|
} else {
|
||||||
|
// unknow action inserted
|
||||||
|
throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PartialupdateUpload(String fileLocalPath, String filename, String filepath, String contentType, String contentLength) {
|
||||||
|
ContentValues cv = new ContentValues();
|
||||||
|
cv.put(ProviderTableMeta.FILE_NAME, filename);
|
||||||
|
cv.put(ProviderTableMeta.FILE_PATH, filepath);
|
||||||
|
cv.put(ProviderTableMeta.FILE_STORAGE_PATH, fileLocalPath);
|
||||||
|
cv.put(ProviderTableMeta.FILE_MODIFIED, WebdavUtils.DISPLAY_DATE_FORMAT.format(new java.util.Date()));
|
||||||
|
cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, contentType);
|
||||||
|
cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, contentLength);
|
||||||
|
cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
|
||||||
|
Log.d(TAG, filename+" ++ "+filepath+" ++ " + contentLength + " ++ " + contentType + " ++ " + fileLocalPath);
|
||||||
|
if (!mParents.empty()) {
|
||||||
|
Cursor c = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
c.moveToFirst();
|
||||||
|
cv.put(ProviderTableMeta.FILE_PARENT, c.getString(c.getColumnIndex(ProviderTableMeta._ID)));
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
getContentResolver().insert(ProviderTableMeta.CONTENT_URI_FILE, cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackgroundUploader implements Runnable {
|
||||||
|
private ArrayList<Parcelable> mUploadStreams;
|
||||||
|
private Handler mHandler;
|
||||||
|
private String mUploadPath;
|
||||||
|
private boolean mCreateDir;
|
||||||
|
|
||||||
|
public BackgroundUploader(String pathToUpload, ArrayList<Parcelable> streamsToUpload,
|
||||||
|
Handler handler) {
|
||||||
|
mUploadStreams = streamsToUpload;
|
||||||
|
mHandler = handler;
|
||||||
|
mUploadPath = pathToUpload.replace(" ", "%20");
|
||||||
|
mCreateDir = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BackgroundUploader(String pathToUpload, ArrayList<Parcelable> streamsToUpload,
|
||||||
|
Handler handler, boolean createDir) {
|
||||||
|
mUploadStreams = streamsToUpload;
|
||||||
|
mHandler = handler;
|
||||||
|
mUploadPath = pathToUpload.replace(" ", "%20");
|
||||||
|
mCreateDir = createDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
boolean any_failed = false;
|
||||||
|
DefaultHttpClient httpClient = new DefaultHttpClient();
|
||||||
|
Uri uri = Uri.parse(mAccountManager.getUserData(mAccount,
|
||||||
|
AccountAuthenticator.KEY_OC_URL));
|
||||||
|
httpClient.getCredentialsProvider().setCredentials(
|
||||||
|
new AuthScope(uri.getHost(), (uri.getPort() == -1) ? 80 : uri
|
||||||
|
.getPort()),
|
||||||
|
new UsernamePasswordCredentials(mUsername, mPassword));
|
||||||
|
BasicHttpContext httpContext = new BasicHttpContext();
|
||||||
|
BasicScheme basicAuth = new BasicScheme();
|
||||||
|
httpContext.setAttribute("preemptive-auth", basicAuth);
|
||||||
|
HttpHost targetHost = new HttpHost(uri.getHost(), (uri.getPort() == -1)
|
||||||
|
? 80
|
||||||
|
: uri.getPort(), (uri.getScheme() == "https") ? "https" : "http");
|
||||||
|
|
||||||
|
// create last directory in path if nessesary
|
||||||
|
if (mCreateDir) {
|
||||||
|
HttpMkCol method = new HttpMkCol(uri.toString() + mUploadPath + "/");
|
||||||
|
method.setHeader("User-Agent", "Android-ownCloud");
|
||||||
|
try {
|
||||||
|
httpClient.execute(targetHost, method, httpContext);
|
||||||
|
Log.i(TAG, "Creating dir completed");
|
||||||
|
} catch (final Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
mHandler.post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
OwnCloudUploader.this.onUploadComplete(false, e.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < mUploadStreams.size(); ++i) {
|
||||||
|
final Cursor c = getContentResolver().query((Uri)mUploadStreams.get(i), null, null, null, null);
|
||||||
|
c.moveToFirst();
|
||||||
|
|
||||||
|
HttpPut method = new HttpPut(uri.toString() + mUploadPath + "/"
|
||||||
|
+ c.getString(c.getColumnIndex(Media.DISPLAY_NAME)).replace(" ", "%20"));
|
||||||
|
method.setHeader("Content-type", c.getString(c.getColumnIndex(Media.MIME_TYPE)));
|
||||||
|
method.setHeader("User-Agent", "Android-ownCloud");
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileBody fb = new FileBody(new File(c.getString(c.getColumnIndex(Media.DATA))), c.getString(c.getColumnIndex(Media.MIME_TYPE)));
|
||||||
|
MultipartEntity entity = new MultipartEntity();
|
||||||
|
final FileEntity fileEntity = new FileEntity(new File(c.getString(c.getColumnIndex(Media.DATA))),
|
||||||
|
c.getString(c.getColumnIndex(Media.MIME_TYPE)));
|
||||||
|
|
||||||
|
entity.addPart(c.getString(c.getColumnIndex(Media.DISPLAY_NAME)).replace(" ", "%20"), fb);
|
||||||
|
|
||||||
|
method.setEntity(fileEntity);
|
||||||
|
Log.i(TAG, "executing:" + method.getRequestLine().toString());
|
||||||
|
|
||||||
|
httpClient.execute(targetHost, method, httpContext);
|
||||||
|
mHandler.post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
OwnCloudUploader.this.PartialupdateUpload(c.getString(c.getColumnIndex(Media.DATA)),
|
||||||
|
c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),
|
||||||
|
mUploadPath + (mUploadPath.equals("/")?"":"/"),
|
||||||
|
fileEntity.getContentType().getValue(),
|
||||||
|
fileEntity.getContentLength()+"");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Log.i(TAG, "Uploading, done");
|
||||||
|
|
||||||
|
} catch (final Exception e) {
|
||||||
|
any_failed = true;
|
||||||
|
mHandler.post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
OwnCloudUploader.this.onUploadComplete(false, c.getString(c.getColumnIndex(Media.DISPLAY_NAME))+ " " + e.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!any_failed) {
|
||||||
|
mHandler.post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
OwnCloudUploader.this.onUploadComplete(true, "Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
|
||||||
|
//ContentResolver.requestSync(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE, bundle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
139
src/eu/alefzero/owncloud/Preferences.java
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.Preference;
|
||||||
|
import android.preference.PreferenceActivity;
|
||||||
|
import android.preference.PreferenceScreen;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.ContextMenu;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
|
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||||
|
|
||||||
|
public class Preferences extends PreferenceActivity {
|
||||||
|
private String TAG = "OwnCloudPreferences";
|
||||||
|
private final int mNewSession = 47;
|
||||||
|
private final int mEditSession = 48;
|
||||||
|
private DbHandler mDbHandler;
|
||||||
|
private Vector<OwnCloudSession> mSessions;
|
||||||
|
private int mSelectedMenuItem;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState){
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
mDbHandler = new DbHandler(getBaseContext());
|
||||||
|
mSessions = new Vector<OwnCloudSession>();
|
||||||
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
|
registerForContextMenu(getListView());
|
||||||
|
//populateSessionList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateSessionList() {
|
||||||
|
mSessions.clear();
|
||||||
|
mSessions = mDbHandler.getSessionList();
|
||||||
|
PreferenceScreen ps = getPreferenceScreen();
|
||||||
|
ps.removeAll();
|
||||||
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
|
for (int i = 0; i < mSessions.size(); i++) {
|
||||||
|
Preference preference = new Preference(getBaseContext());
|
||||||
|
preference.setTitle(mSessions.get(i).getName());
|
||||||
|
URI uri;
|
||||||
|
try {
|
||||||
|
uri = new URI(mSessions.get(i).getUrl());
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
e.printStackTrace(); // should never happend
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
preference.setSummary(uri.getScheme() + "://" + uri.getHost()+uri.getPath());
|
||||||
|
ps.addPreference(preference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
super.onCreateOptionsMenu(menu);
|
||||||
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
inflater.inflate(R.menu.prefs_menu, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||||
|
super.onMenuItemSelected(featureId, item);
|
||||||
|
Intent intent;
|
||||||
|
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.addSessionItem:
|
||||||
|
intent = new Intent(this, PreferencesNewSession.class);
|
||||||
|
startActivityForResult(intent, mNewSession);
|
||||||
|
break;
|
||||||
|
case R.id.SessionContextEdit:
|
||||||
|
intent = new Intent(this, PreferencesNewSession.class);
|
||||||
|
intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem).getEntryId());
|
||||||
|
intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem).getName());
|
||||||
|
intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem).getUrl());
|
||||||
|
startActivityForResult(intent, mEditSession);
|
||||||
|
break;
|
||||||
|
case R.id.SessionContextRemove:
|
||||||
|
OwnCloudSession ocs = mSessions.get(mSelectedMenuItem);
|
||||||
|
mDbHandler.removeSessionWithId(ocs.getEntryId());
|
||||||
|
mSessions.remove(ocs);
|
||||||
|
getPreferenceScreen().removePreference(getPreferenceScreen().getPreference(mSelectedMenuItem+1));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.w(TAG, "Unknown menu item triggered");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
switch (requestCode) {
|
||||||
|
case mNewSession:
|
||||||
|
mDbHandler.addSession(data.getStringExtra("sessionName"),
|
||||||
|
data.getStringExtra("sessionURL"));
|
||||||
|
getPreferenceScreen().removeAll();
|
||||||
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
|
populateSessionList();
|
||||||
|
break;
|
||||||
|
case mEditSession:
|
||||||
|
mDbHandler.changeSessionFields(data.getIntExtra("sessionId", -1),
|
||||||
|
data.getStringExtra("sessionName"),
|
||||||
|
data.getStringExtra("sessionURL"));
|
||||||
|
populateSessionList();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||||
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
|
||||||
|
mSelectedMenuItem = info.position-1;
|
||||||
|
menu.setHeaderTitle(mSessions.get(mSelectedMenuItem).getName());
|
||||||
|
|
||||||
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
inflater.inflate(R.menu.session_context_menu, menu);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
mDbHandler.close();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
143
src/eu/alefzero/owncloud/PreferencesNewSession.java
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
import eu.alefzero.owncloud.authenticator.AccountAuthenticatorService;
|
||||||
|
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountAuthenticatorActivity;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
public class PreferencesNewSession extends AccountAuthenticatorActivity implements OnClickListener {
|
||||||
|
private Intent mReturnData;
|
||||||
|
private final String TAG = "OwnCloudPreferencesNewSession";
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState){
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
//setContentView(R.layout.add_new_session);
|
||||||
|
/*
|
||||||
|
EditText et;// = (EditText) findViewById(R.id.newSession_sessionName);
|
||||||
|
|
||||||
|
et = (EditText) findViewById(R.id.newSession_URL);
|
||||||
|
if (getIntent().hasExtra("sessionURL")) {
|
||||||
|
try {
|
||||||
|
URI uri = new URI(getIntent().getStringExtra("sessionURL"));
|
||||||
|
String url = uri.getHost();
|
||||||
|
if (uri.getPort() != -1) {
|
||||||
|
url += ":" + String.valueOf(uri.getPort());
|
||||||
|
}
|
||||||
|
if (uri.getPath() != null) {
|
||||||
|
url += uri.getPath();
|
||||||
|
} else {
|
||||||
|
url += "/";
|
||||||
|
}
|
||||||
|
et.setText(url);
|
||||||
|
et = (EditText) findViewById(R.id.newSession_username);
|
||||||
|
if (uri.getAuthority() != null) {
|
||||||
|
if (uri.getUserInfo().indexOf(':') != -1) {
|
||||||
|
et.setText(uri.getUserInfo().substring(0, uri.getUserInfo().indexOf(':')));
|
||||||
|
et = (EditText) findViewById(R.id.newSession_password);
|
||||||
|
et.setText(uri.getUserInfo().substring(uri.getUserInfo().indexOf(':')+1));
|
||||||
|
} else {
|
||||||
|
et.setText(uri.getUserInfo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
Log.e(TAG, "Incorrect URI syntax " + e.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mReturnData = new Intent();
|
||||||
|
setResult(Activity.RESULT_OK, mReturnData);
|
||||||
|
((Button) findViewById(R.id.button1)).setOnClickListener(this);
|
||||||
|
((Button) findViewById(R.id.button2)).setOnClickListener(this);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onClick(View v) {
|
||||||
|
/* switch (v.getId()) {
|
||||||
|
case R.id.button1:
|
||||||
|
Intent intent = new Intent();
|
||||||
|
if (getIntent().hasExtra("sessionId")) {
|
||||||
|
intent.putExtra("sessionId", getIntent().getIntExtra("sessionId", -1));
|
||||||
|
}
|
||||||
|
//String sessionName = ((EditText) findViewById(R.id.newSession_sessionName)).getText().toString();
|
||||||
|
// if (sessionName.trim().equals("") || !isNameValid(sessionName)) {
|
||||||
|
// Toast.makeText(this, R.string.new_session_session_name_error, Toast.LENGTH_LONG).show();
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
URI uri = prepareURI();
|
||||||
|
if (uri != null) {
|
||||||
|
//intent.putExtra("sessionName", sessionName);
|
||||||
|
intent.putExtra("sessionURL", uri.toString());
|
||||||
|
setResult(Activity.RESULT_OK, intent);
|
||||||
|
AccountManager accMgr = AccountManager.get(this);
|
||||||
|
Account a = new Account("OwnCloud", AccountAuthenticatorService.ACCOUNT_TYPE);
|
||||||
|
accMgr.addAccountExplicitly(a, "asd", null);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case R.id.button2:
|
||||||
|
setResult(Activity.RESULT_CANCELED);
|
||||||
|
finish();
|
||||||
|
break;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private URI prepareURI() {
|
||||||
|
URI uri = null;
|
||||||
|
/* String url = "";
|
||||||
|
try {
|
||||||
|
String username = ((EditText) findViewById(R.id.newSession_username)).getText().toString().trim();
|
||||||
|
String password = ((EditText) findViewById(R.id.newSession_password)).getText().toString().trim();
|
||||||
|
String hostname = ((EditText) findViewById(R.id.newSession_URL)).getText().toString().trim();
|
||||||
|
String scheme;
|
||||||
|
if (hostname.matches("[A-Za-z]://")) {
|
||||||
|
scheme = hostname.substring(0, hostname.indexOf("://")+3);
|
||||||
|
hostname = hostname.substring(hostname.indexOf("://")+3);
|
||||||
|
} else {
|
||||||
|
scheme = "http://";
|
||||||
|
}
|
||||||
|
if (!username.equals("")) {
|
||||||
|
if (!password.equals("")) {
|
||||||
|
username += ":" + password + "@";
|
||||||
|
} else {
|
||||||
|
username += "@";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
url = scheme + username + hostname;
|
||||||
|
Log.i(TAG, url);
|
||||||
|
uri = new URI(url);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
Log.e(TAG, "Incorrect URI syntax " + e.getLocalizedMessage());
|
||||||
|
Toast.makeText(this, R.string.new_session_uri_error, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
*/return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNameValid(String string) {
|
||||||
|
return string.matches("[A-Za-z0-9 _-]*");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
setResult(Activity.RESULT_CANCELED);
|
||||||
|
super.onBackPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
267
src/eu/alefzero/owncloud/QuickAction.java
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.ViewGroup.LayoutParams;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Popup window, shows action list as icon and text like the one in Gallery3D app.
|
||||||
|
*
|
||||||
|
* @author Lorensius. W. T
|
||||||
|
*/
|
||||||
|
public class QuickAction extends CustomPopup {
|
||||||
|
private final View root;
|
||||||
|
private final ImageView mArrowUp;
|
||||||
|
private final ImageView mArrowDown;
|
||||||
|
private final LayoutInflater inflater;
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
protected static final int ANIM_GROW_FROM_LEFT = 1;
|
||||||
|
protected static final int ANIM_GROW_FROM_RIGHT = 2;
|
||||||
|
protected static final int ANIM_GROW_FROM_CENTER = 3;
|
||||||
|
protected static final int ANIM_REFLECT = 4;
|
||||||
|
protected static final int ANIM_AUTO = 5;
|
||||||
|
|
||||||
|
private int animStyle;
|
||||||
|
private ViewGroup mTrack;
|
||||||
|
private ScrollView scroller;
|
||||||
|
private ArrayList<ActionItem> actionList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param anchor {@link View} on where the popup window should be displayed
|
||||||
|
*/
|
||||||
|
public QuickAction(View anchor) {
|
||||||
|
super(anchor);
|
||||||
|
|
||||||
|
actionList = new ArrayList<ActionItem>();
|
||||||
|
context = anchor.getContext();
|
||||||
|
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
|
||||||
|
root = (ViewGroup) inflater.inflate(R.layout.popup, null);
|
||||||
|
|
||||||
|
mArrowDown = (ImageView) root.findViewById(R.id.arrow_down);
|
||||||
|
mArrowUp = (ImageView) root.findViewById(R.id.arrow_up);
|
||||||
|
|
||||||
|
setContentView(root);
|
||||||
|
|
||||||
|
mTrack = (ViewGroup) root.findViewById(R.id.tracks);
|
||||||
|
scroller = (ScrollView) root.findViewById(R.id.scroller);
|
||||||
|
animStyle = ANIM_AUTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set animation style
|
||||||
|
*
|
||||||
|
* @param animStyle animation style, default is set to ANIM_AUTO
|
||||||
|
*/
|
||||||
|
public void setAnimStyle(int animStyle) {
|
||||||
|
this.animStyle = animStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add action item
|
||||||
|
*
|
||||||
|
* @param action {@link ActionItem} object
|
||||||
|
*/
|
||||||
|
public void addActionItem(ActionItem action) {
|
||||||
|
actionList.add(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show popup window. Popup is automatically positioned, on top or bottom of anchor view.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void show () {
|
||||||
|
preShow();
|
||||||
|
|
||||||
|
int xPos, yPos;
|
||||||
|
|
||||||
|
int[] location = new int[2];
|
||||||
|
|
||||||
|
mAnchor.getLocationOnScreen(location);
|
||||||
|
|
||||||
|
Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1]
|
||||||
|
+ mAnchor.getHeight());
|
||||||
|
|
||||||
|
createActionList();
|
||||||
|
|
||||||
|
root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
|
||||||
|
root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||||
|
|
||||||
|
int rootHeight = root.getMeasuredHeight();
|
||||||
|
int rootWidth = root.getMeasuredWidth();
|
||||||
|
|
||||||
|
int screenWidth = mWManager.getDefaultDisplay().getWidth();
|
||||||
|
int screenHeight = mWManager.getDefaultDisplay().getHeight();
|
||||||
|
|
||||||
|
//automatically get X coord of popup (top left)
|
||||||
|
if ((anchorRect.left + rootWidth) > screenWidth) {
|
||||||
|
xPos = anchorRect.left - (rootWidth-mAnchor.getWidth());
|
||||||
|
} else {
|
||||||
|
if (mAnchor.getWidth() > rootWidth) {
|
||||||
|
xPos = anchorRect.centerX() - (rootWidth/2);
|
||||||
|
} else {
|
||||||
|
xPos = anchorRect.left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dyTop = anchorRect.top;
|
||||||
|
int dyBottom = screenHeight - anchorRect.bottom;
|
||||||
|
|
||||||
|
boolean onTop = (dyTop > dyBottom) ? true : false;
|
||||||
|
|
||||||
|
if (onTop) {
|
||||||
|
if (rootHeight > dyTop) {
|
||||||
|
yPos = 15;
|
||||||
|
LayoutParams l = scroller.getLayoutParams();
|
||||||
|
l.height = dyTop - mAnchor.getHeight();
|
||||||
|
} else {
|
||||||
|
yPos = anchorRect.top - rootHeight;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
yPos = anchorRect.bottom;
|
||||||
|
|
||||||
|
if (rootHeight > dyBottom) {
|
||||||
|
LayoutParams l = scroller.getLayoutParams();
|
||||||
|
l.height = dyBottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), anchorRect.centerX()-xPos);
|
||||||
|
|
||||||
|
setAnimationStyle(screenWidth, anchorRect.centerX(), onTop);
|
||||||
|
|
||||||
|
mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xPos, yPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set animation style
|
||||||
|
*
|
||||||
|
* @param screenWidth screen width
|
||||||
|
* @param requestedX distance from left edge
|
||||||
|
* @param onTop flag to indicate where the popup should be displayed. Set TRUE if displayed on top of anchor view
|
||||||
|
* and vice versa
|
||||||
|
*/
|
||||||
|
private void setAnimationStyle(int screenWidth, int requestedX, boolean onTop) {
|
||||||
|
int arrowPos = requestedX - mArrowUp.getMeasuredWidth()/2;
|
||||||
|
|
||||||
|
switch (animStyle) {
|
||||||
|
case ANIM_GROW_FROM_LEFT:
|
||||||
|
mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ANIM_GROW_FROM_RIGHT:
|
||||||
|
mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ANIM_GROW_FROM_CENTER:
|
||||||
|
mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ANIM_REFLECT:
|
||||||
|
mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect : R.style.Animations_PopDownMenu_Reflect);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ANIM_AUTO:
|
||||||
|
if (arrowPos <= screenWidth/4) {
|
||||||
|
mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);
|
||||||
|
} else if (arrowPos > screenWidth/4 && arrowPos < 3 * (screenWidth/4)) {
|
||||||
|
mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);
|
||||||
|
} else {
|
||||||
|
mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create action list
|
||||||
|
*/
|
||||||
|
private void createActionList() {
|
||||||
|
View view;
|
||||||
|
String title;
|
||||||
|
Drawable icon;
|
||||||
|
OnClickListener listener;
|
||||||
|
|
||||||
|
for (int i = 0; i < actionList.size(); i++) {
|
||||||
|
title = actionList.get(i).getTitle();
|
||||||
|
icon = actionList.get(i).getIcon();
|
||||||
|
listener = actionList.get(i).getOnClickListerner();
|
||||||
|
|
||||||
|
view = getActionItem(title, icon, listener);
|
||||||
|
|
||||||
|
view.setFocusable(true);
|
||||||
|
view.setClickable(true);
|
||||||
|
|
||||||
|
mTrack.addView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get action item {@link View}
|
||||||
|
*
|
||||||
|
* @param title action item title
|
||||||
|
* @param icon {@link Drawable} action item icon
|
||||||
|
* @param listener {@link View.OnClickListener} action item listener
|
||||||
|
* @return action item {@link View}
|
||||||
|
*/
|
||||||
|
private View getActionItem(String title, Drawable icon, OnClickListener listener) {
|
||||||
|
LinearLayout container = (LinearLayout) inflater.inflate(R.layout.action_item, null);
|
||||||
|
|
||||||
|
ImageView img = (ImageView) container.findViewById(R.id.icon);
|
||||||
|
TextView text = (TextView) container.findViewById(R.id.title);
|
||||||
|
|
||||||
|
if (icon != null) {
|
||||||
|
img.setImageDrawable(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (title != null) {
|
||||||
|
text.setText(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listener != null) {
|
||||||
|
container.setOnClickListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show arrow
|
||||||
|
*
|
||||||
|
* @param whichArrow arrow type resource id
|
||||||
|
* @param requestedX distance from left screen
|
||||||
|
*/
|
||||||
|
private void showArrow(int whichArrow, int requestedX) {
|
||||||
|
final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp : mArrowDown;
|
||||||
|
final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown : mArrowUp;
|
||||||
|
|
||||||
|
final int arrowWidth = mArrowUp.getMeasuredWidth();
|
||||||
|
|
||||||
|
showArrow.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams)showArrow.getLayoutParams();
|
||||||
|
|
||||||
|
param.leftMargin = requestedX - arrowWidth / 2;
|
||||||
|
|
||||||
|
hideArrow.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
}
|
238
src/eu/alefzero/owncloud/authenticator/AccountAuthenticator.java
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
package eu.alefzero.owncloud.authenticator;
|
||||||
|
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
|
||||||
|
import android.accounts.AbstractAccountAuthenticator;
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountAuthenticatorResponse;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.accounts.NetworkErrorException;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class AccountAuthenticator extends AbstractAccountAuthenticator {
|
||||||
|
public static final String OPTIONS_USERNAME = "username";
|
||||||
|
public static final String OPTIONS_PASSWORD = "password";
|
||||||
|
public static final String OPTIONS_FILE_LIST_SYNC_ENABLED = "filelist";
|
||||||
|
public static final String OPTIONS_PINNED_FILE_SYNC_ENABLED = "pinned";
|
||||||
|
|
||||||
|
public static final String ACCOUNT_TYPE = "owncloud";
|
||||||
|
public static final String AUTH_TOKEN_TYPE = "org.owncloud";
|
||||||
|
|
||||||
|
public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";
|
||||||
|
public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";
|
||||||
|
public static final String KEY_LOGIN_OPTIONS = "loginOptions";
|
||||||
|
public static final String KEY_ACCOUNT = "account";
|
||||||
|
public static final String KEY_OC_URL = "oc_url";
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
public AccountAuthenticator(Context context) {
|
||||||
|
super(context);
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Bundle addAccount(AccountAuthenticatorResponse response,
|
||||||
|
String accountType, String authTokenType, String[] requiredFeatures,
|
||||||
|
Bundle options) throws NetworkErrorException {
|
||||||
|
Log.i(getClass().getName(), "Adding account with type " + accountType +
|
||||||
|
" and auth token " + authTokenType);
|
||||||
|
try {
|
||||||
|
validateAccountType(accountType);
|
||||||
|
//validateAuthTokenType(authTokenType);
|
||||||
|
validateRequiredFeatures(requiredFeatures);
|
||||||
|
} catch (AuthenticatorException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return e.getFailureBundle();
|
||||||
|
}
|
||||||
|
final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
|
||||||
|
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
|
||||||
|
intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
|
||||||
|
intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);
|
||||||
|
intent.putExtra(KEY_LOGIN_OPTIONS, options);
|
||||||
|
|
||||||
|
setIntentFlags(intent);
|
||||||
|
Log.i(getClass().getName(), intent.toString());
|
||||||
|
final Bundle bundle = new Bundle();
|
||||||
|
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Bundle confirmCredentials(AccountAuthenticatorResponse response,
|
||||||
|
Account account, Bundle options) throws NetworkErrorException {
|
||||||
|
try {
|
||||||
|
validateAccountType(account.type);
|
||||||
|
} catch (AuthenticatorException e) {
|
||||||
|
return e.getFailureBundle();
|
||||||
|
}
|
||||||
|
Intent intent = new Intent(mContext, AuthenticatorActivity.class);
|
||||||
|
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
|
||||||
|
intent.putExtra(KEY_ACCOUNT, account);
|
||||||
|
intent.putExtra(KEY_LOGIN_OPTIONS, options);
|
||||||
|
|
||||||
|
setIntentFlags(intent);
|
||||||
|
|
||||||
|
Bundle resultBundle = new Bundle();
|
||||||
|
resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);
|
||||||
|
return resultBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle editProperties(AccountAuthenticatorResponse response,
|
||||||
|
String accountType) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle getAuthToken(AccountAuthenticatorResponse response,
|
||||||
|
Account account, String authTokenType, Bundle options)
|
||||||
|
throws NetworkErrorException {
|
||||||
|
Log.i(getClass().getName(), "Getting authToken");
|
||||||
|
try {
|
||||||
|
validateAccountType(account.type);
|
||||||
|
validateAuthTokenType(authTokenType);
|
||||||
|
} catch (AuthenticatorException e) {
|
||||||
|
Log.w(getClass().getName(), "Validating failded in getAuthToken");
|
||||||
|
return e.getFailureBundle();
|
||||||
|
}
|
||||||
|
final AccountManager am = AccountManager.get(mContext);
|
||||||
|
final String password = am.getPassword(account);
|
||||||
|
if (password != null) {
|
||||||
|
final Bundle result = new Bundle();
|
||||||
|
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
|
||||||
|
result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
|
||||||
|
result.putString(AccountManager.KEY_AUTHTOKEN, password);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
|
||||||
|
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
|
||||||
|
intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
|
||||||
|
intent.putExtra(KEY_LOGIN_OPTIONS, options);
|
||||||
|
intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);
|
||||||
|
|
||||||
|
final Bundle bundle = new Bundle();
|
||||||
|
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAuthTokenLabel(String authTokenType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle hasFeatures(AccountAuthenticatorResponse response,
|
||||||
|
Account account, String[] features) throws NetworkErrorException {
|
||||||
|
final Bundle result = new Bundle();
|
||||||
|
result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle updateCredentials(AccountAuthenticatorResponse response,
|
||||||
|
Account account, String authTokenType, Bundle options)
|
||||||
|
throws NetworkErrorException {
|
||||||
|
final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
|
||||||
|
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
|
||||||
|
intent.putExtra(KEY_ACCOUNT, account);
|
||||||
|
intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
|
||||||
|
intent.putExtra(KEY_LOGIN_OPTIONS, options);
|
||||||
|
setIntentFlags(intent);
|
||||||
|
|
||||||
|
final Bundle bundle = new Bundle();
|
||||||
|
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response,
|
||||||
|
Account account) throws NetworkErrorException {
|
||||||
|
return super.getAccountRemovalAllowed(response, account);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setIntentFlags(Intent intent) {
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||||
|
intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateAccountType(String type) throws UnsupportedAccountTypeException {
|
||||||
|
if (!type.equals(ACCOUNT_TYPE)) {
|
||||||
|
throw new UnsupportedAccountTypeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateAuthTokenType(String authTokenType) throws UnsupportedAuthTokenTypeException {
|
||||||
|
if (!authTokenType.equals(AUTH_TOKEN_TYPE)) {
|
||||||
|
throw new UnsupportedAuthTokenTypeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateRequiredFeatures(String[] requiredFeatures) throws UnsupportedFeaturesException {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateCreaditials(String username, String password, String path) throws AccessDeniedException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AuthenticatorException extends Exception {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private Bundle mFailureBundle;
|
||||||
|
public AuthenticatorException(int code, String errorMsg) {
|
||||||
|
mFailureBundle = new Bundle();
|
||||||
|
mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);
|
||||||
|
mFailureBundle.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bundle getFailureBundle() {
|
||||||
|
return mFailureBundle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UnsupportedAccountTypeException extends AuthenticatorException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public UnsupportedAccountTypeException() {
|
||||||
|
super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported account type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UnsupportedAuthTokenTypeException extends AuthenticatorException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public UnsupportedAuthTokenTypeException() {
|
||||||
|
super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported auth token type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UnsupportedFeaturesException extends AuthenticatorException {
|
||||||
|
public static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public UnsupportedFeaturesException() {
|
||||||
|
super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported features");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AccessDeniedException extends AuthenticatorException {
|
||||||
|
public AccessDeniedException(int code, String errorMsg) {
|
||||||
|
super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* ownCloud Android client application
|
||||||
|
* Copyright (C) 2011 Bartek Przybylski
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.alefzero.owncloud.authenticator;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
public class AccountAuthenticatorService extends Service {
|
||||||
|
|
||||||
|
private AccountAuthenticator mAuthenticator;
|
||||||
|
static final public String ACCOUNT_TYPE = "owncloud";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
mAuthenticator = new AccountAuthenticator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return mAuthenticator.getIBinder();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
189
src/eu/alefzero/owncloud/authenticator/AuthUtils.java
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
/* ownCloud Android client application
|
||||||
|
* Copyright (C) 2011 Bartek Przybylski
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.alefzero.owncloud.authenticator;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.auth.AuthScope;
|
||||||
|
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||||
|
import org.apache.http.client.ClientProtocolException;
|
||||||
|
import org.apache.http.client.methods.HttpHead;
|
||||||
|
import org.apache.http.impl.auth.BasicScheme;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.apache.http.protocol.BasicHttpContext;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class AuthUtils {
|
||||||
|
public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";
|
||||||
|
public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";
|
||||||
|
|
||||||
|
private static String mResultMsg = "";
|
||||||
|
|
||||||
|
public static boolean authenticate(URL url, String username, String password,
|
||||||
|
Handler handler, Context context) {
|
||||||
|
String strippedPath = url.toString().endsWith("/") ?
|
||||||
|
url.toString().substring(0, url.toString().length()-1) :
|
||||||
|
url.toString();
|
||||||
|
String webdatPath = strippedPath + WEBDAV_PATH_2_0;
|
||||||
|
URL complete_url = null;
|
||||||
|
try {
|
||||||
|
complete_url = new URL(webdatPath);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
// should never happend
|
||||||
|
sendResult(false, handler, context, "URL error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// version 2.0 success
|
||||||
|
if (tryGetWebdav(complete_url, username, password, handler, context)) {
|
||||||
|
sendResult(true, handler, context, complete_url.toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mResultMsg.equals("401")) {
|
||||||
|
sendResult(false, handler, context, "Invalid login or/and password");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mResultMsg.equals("404")) {
|
||||||
|
sendResult(false, handler, context, "Server error: " + mResultMsg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
webdatPath = strippedPath + WEBDAV_PATH_1_2;
|
||||||
|
try {
|
||||||
|
complete_url = new URL(webdatPath);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
// should never happend
|
||||||
|
sendResult(false, handler, context, "URL error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// version 1.2 success
|
||||||
|
if (tryGetWebdav(complete_url, username, password, handler, context)) {
|
||||||
|
sendResult(true, handler, context, complete_url.toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mResultMsg.equals("401")) {
|
||||||
|
sendResult(false, handler, context, "Invalid login or/and password");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mResultMsg.equals("404")) {
|
||||||
|
sendResult(false, handler, context, "Wrong path given");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendResult(false, handler, context, "Server error: " + mResultMsg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean tryGetWebdav(URL url, String username, String pwd,
|
||||||
|
Handler handler, Context context) {
|
||||||
|
DefaultHttpClient c = new DefaultHttpClient();
|
||||||
|
c.getCredentialsProvider().setCredentials(
|
||||||
|
new AuthScope(url.getHost(), (url.getPort() == -1)?80:url.getPort()),
|
||||||
|
new UsernamePasswordCredentials(username, pwd));
|
||||||
|
|
||||||
|
BasicHttpContext localcontext = new BasicHttpContext();
|
||||||
|
BasicScheme basicAuth = new BasicScheme();
|
||||||
|
|
||||||
|
localcontext.setAttribute("preemptive-auth", basicAuth);
|
||||||
|
HttpHost targetHost = new HttpHost(url.getHost(), (url.getPort() == -1)
|
||||||
|
? 80
|
||||||
|
: url.getPort(), (url.getProtocol() == "https") ? "https" : "http");
|
||||||
|
HttpHead httpget = new HttpHead(url.toString());
|
||||||
|
HttpResponse response = null;
|
||||||
|
try {
|
||||||
|
response = c.execute(targetHost, httpget, localcontext);
|
||||||
|
} catch (ClientProtocolException e1) {
|
||||||
|
sendResult(false, handler, context, "Protocol error: "
|
||||||
|
+ e1.getLocalizedMessage());
|
||||||
|
return false;
|
||||||
|
} catch (UnknownHostException e1) {
|
||||||
|
mResultMsg = "Unknowh host: " + e1.getLocalizedMessage();
|
||||||
|
return false;
|
||||||
|
} catch (IOException e1) {
|
||||||
|
mResultMsg = "Error: " + e1.getLocalizedMessage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String status = response.getStatusLine().toString();
|
||||||
|
status = status.split(" ")[1];
|
||||||
|
Log.i("AuthUtils", "Status returned: " + status);
|
||||||
|
if (status.equals("200")) {
|
||||||
|
return true;
|
||||||
|
} else if (status.equals("404")) {
|
||||||
|
mResultMsg = "404";
|
||||||
|
return false;
|
||||||
|
} else if (status.equals("401")) {
|
||||||
|
mResultMsg = "401";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mResultMsg = status;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Thread performOnBackgroundThread(final Runnable r) {
|
||||||
|
final Thread t = new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
r.run();
|
||||||
|
} finally {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
t.start();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendResult(final Boolean result,
|
||||||
|
final Handler handler,
|
||||||
|
final Context context,
|
||||||
|
final String message) {
|
||||||
|
if (handler == null || context == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
((AuthenticatorActivity) context).onAuthenticationResult(result, message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Thread attemptAuth(final URL url, final String username,
|
||||||
|
final String password, final Handler handler,
|
||||||
|
final Context context) {
|
||||||
|
final Runnable r = new Runnable() {
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
authenticate(url, username, password, handler, context);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return performOnBackgroundThread(r);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
/* ownCloud Android client application
|
||||||
|
* Copyright (C) 2011 Bartek Przybylski
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.alefzero.owncloud.authenticator;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountAuthenticatorActivity;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import eu.alefzero.owncloud.R;
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
|
||||||
|
|
||||||
|
public class AuthenticatorActivity extends AccountAuthenticatorActivity {
|
||||||
|
private Thread mAuthThread;
|
||||||
|
private final Handler mHandler = new Handler();
|
||||||
|
|
||||||
|
public static final String PARAM_USERNAME = "param_Username";
|
||||||
|
public static final String PARAM_HOSTNAME = "param_Hostname";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
setContentView(R.layout.account_setup);
|
||||||
|
if (getIntent().hasExtra(PARAM_USERNAME)) {
|
||||||
|
String username = getIntent().getStringExtra(PARAM_HOSTNAME);
|
||||||
|
TextView host_text, user_text;
|
||||||
|
host_text = (TextView) findViewById(R.id.host_URL);
|
||||||
|
user_text = (TextView) findViewById(R.id.account_username);
|
||||||
|
host_text.setText(host_text.getText() + username.substring(username.lastIndexOf('@')));
|
||||||
|
user_text.setText(user_text.getText() + username.substring(0, username.lastIndexOf('@')-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(int id) {
|
||||||
|
final ProgressDialog dialog = new ProgressDialog(this);
|
||||||
|
dialog.setMessage("Trying to login");
|
||||||
|
dialog.setIndeterminate(true);
|
||||||
|
dialog.setCancelable(true);
|
||||||
|
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
Log.i(getClass().getName(), "Login canceled");
|
||||||
|
if (mAuthThread != null) {
|
||||||
|
mAuthThread.interrupt();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAuthenticationResult(boolean result, String message) {
|
||||||
|
if (result) {
|
||||||
|
TextView username_text = (TextView) findViewById(R.id.account_username),
|
||||||
|
password_text = (TextView) findViewById(R.id.account_password);
|
||||||
|
|
||||||
|
URL url = null;
|
||||||
|
try {
|
||||||
|
url = new URL(message);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
// should never happend
|
||||||
|
Log.e(getClass().getName(), "Malformed URL: " + message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Account account = new Account(username_text.getText().toString() + "@" + url.getHost(), AccountAuthenticator.ACCOUNT_TYPE);
|
||||||
|
AccountManager accManager = AccountManager.get(this);
|
||||||
|
accManager.addAccountExplicitly(account, password_text.getText().toString(),null);
|
||||||
|
|
||||||
|
final Intent intent = new Intent();
|
||||||
|
intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountAuthenticator.ACCOUNT_TYPE);
|
||||||
|
intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
|
||||||
|
intent.putExtra(AccountManager.KEY_AUTHTOKEN, AccountAuthenticator.ACCOUNT_TYPE);
|
||||||
|
accManager.setUserData(account, AccountAuthenticator.KEY_OC_URL, url.toString());
|
||||||
|
setAccountAuthenticatorResult(intent.getExtras());
|
||||||
|
setResult(RESULT_OK, intent);
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
|
||||||
|
getContentResolver().startSync(ProviderTableMeta.CONTENT_URI, bundle);
|
||||||
|
|
||||||
|
dismissDialog(0);
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
|
||||||
|
dismissDialog(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onCancelClick(View view) {
|
||||||
|
Log.i(getClass().getName(), "Account creating canceled");
|
||||||
|
this.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onOkClick(View view) {
|
||||||
|
TextView url_text = (TextView) findViewById(R.id.host_URL);
|
||||||
|
TextView username_text = (TextView) findViewById(R.id.account_username);
|
||||||
|
TextView password_text = (TextView) findViewById(R.id.account_password);
|
||||||
|
Log.i(getClass().getName(), "OK clicked");
|
||||||
|
boolean hasErrors = false;
|
||||||
|
|
||||||
|
URL uri = null;
|
||||||
|
if (url_text.getText().toString().trim().length() == 0) {
|
||||||
|
url_text.setTextColor(Color.RED);
|
||||||
|
hasErrors = true;
|
||||||
|
} else {
|
||||||
|
url_text.setTextColor(Color.BLACK);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String url_str = url_text.getText().toString();
|
||||||
|
if (!url_str.startsWith("http://") &&
|
||||||
|
!url_str.startsWith("https://")) {
|
||||||
|
url_str = "http://" + url_str;
|
||||||
|
}
|
||||||
|
uri = new URL(url_str);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
url_text.setTextColor(Color.RED);
|
||||||
|
e.printStackTrace();
|
||||||
|
hasErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (username_text.getText().toString().contains(" ") ||
|
||||||
|
username_text.getText().toString().trim().length() == 0) {
|
||||||
|
username_text.setTextColor(Color.RED);
|
||||||
|
hasErrors = true;
|
||||||
|
} else {
|
||||||
|
username_text.setTextColor(Color.BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password_text.getText().toString().trim().length() == 0) {
|
||||||
|
password_text.setTextColor(Color.RED);
|
||||||
|
hasErrors = true;
|
||||||
|
} else {
|
||||||
|
password_text.setTextColor(Color.BLACK);
|
||||||
|
}
|
||||||
|
if (hasErrors) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showDialog(0);
|
||||||
|
mAuthThread = AuthUtils.attemptAuth(uri,
|
||||||
|
username_text.getText().toString(),
|
||||||
|
password_text.getText().toString(),
|
||||||
|
mHandler,
|
||||||
|
AuthenticatorActivity.this);
|
||||||
|
}
|
||||||
|
}
|
210
src/eu/alefzero/owncloud/cp.java
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/* ownCloud Android client application
|
||||||
|
* Copyright (C) 2011 Bartek Przybylski
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.alefzero.owncloud;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta;
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
|
||||||
|
|
||||||
|
import android.content.ContentProvider;
|
||||||
|
import android.content.ContentUris;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.UriMatcher;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.SQLException;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.database.sqlite.SQLiteQueryBuilder;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
public class cp extends ContentProvider {
|
||||||
|
|
||||||
|
private DataBaseHelper mDbHelper;
|
||||||
|
|
||||||
|
private static HashMap<String, String> mProjectionMap;
|
||||||
|
static {
|
||||||
|
mProjectionMap = new HashMap<String, String>();
|
||||||
|
mProjectionMap.put(ProviderTableMeta._ID,
|
||||||
|
ProviderTableMeta._ID);
|
||||||
|
mProjectionMap.put(ProviderTableMeta.FILE_PARENT,
|
||||||
|
ProviderTableMeta.FILE_PARENT);
|
||||||
|
mProjectionMap.put(ProviderTableMeta.FILE_PATH,
|
||||||
|
ProviderTableMeta.FILE_PATH);
|
||||||
|
mProjectionMap.put(ProviderTableMeta.FILE_NAME,
|
||||||
|
ProviderTableMeta.FILE_NAME);
|
||||||
|
mProjectionMap.put(ProviderTableMeta.FILE_CREATION,
|
||||||
|
ProviderTableMeta.FILE_CREATION);
|
||||||
|
mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,
|
||||||
|
ProviderTableMeta.FILE_MODIFIED);
|
||||||
|
mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,
|
||||||
|
ProviderTableMeta.FILE_CONTENT_LENGTH);
|
||||||
|
mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,
|
||||||
|
ProviderTableMeta.FILE_CONTENT_TYPE);
|
||||||
|
mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,
|
||||||
|
ProviderTableMeta.FILE_STORAGE_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int SINGLE_FILE = 1;
|
||||||
|
private static final int DIRECTORY = 2;
|
||||||
|
private static final int ROOT_DIRECTORY = 3;
|
||||||
|
private static final UriMatcher mUriMatcher;
|
||||||
|
static {
|
||||||
|
mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||||
|
mUriMatcher.addURI(ProviderMeta.AUTHORITY, "/", ROOT_DIRECTORY);
|
||||||
|
mUriMatcher.addURI(ProviderMeta.AUTHORITY, "file/", SINGLE_FILE);
|
||||||
|
mUriMatcher.addURI(ProviderMeta.AUTHORITY, "file/#", SINGLE_FILE);
|
||||||
|
mUriMatcher.addURI(ProviderMeta.AUTHORITY, "dir/#", DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String TAG = "OC_ContentProvider";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int delete(Uri uri, String where, String[] whereArgs) {
|
||||||
|
SQLiteDatabase db = mDbHelper.getWritableDatabase();
|
||||||
|
int count = 0;
|
||||||
|
switch (mUriMatcher.match(uri)) {
|
||||||
|
case SINGLE_FILE:
|
||||||
|
count = db.delete(ProviderTableMeta.DB_NAME,
|
||||||
|
ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1)
|
||||||
|
+ (!TextUtils.isEmpty(where)?" AND (" + where +")" : ""),
|
||||||
|
whereArgs);
|
||||||
|
break;
|
||||||
|
case ROOT_DIRECTORY:
|
||||||
|
count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown uri: " + uri.toString());
|
||||||
|
}
|
||||||
|
getContext().getContentResolver().notifyChange(uri, null);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType(Uri uri) {
|
||||||
|
switch (mUriMatcher.match(uri)) {
|
||||||
|
case ROOT_DIRECTORY:
|
||||||
|
return ProviderTableMeta.CONTENT_TYPE;
|
||||||
|
case SINGLE_FILE:
|
||||||
|
return ProviderTableMeta.CONTENT_TYPE_ITEM;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown Uri id." + uri.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri insert(Uri uri, ContentValues values) {
|
||||||
|
if (mUriMatcher.match(uri) != SINGLE_FILE) {
|
||||||
|
throw new IllegalArgumentException("Unknown uri id: " + uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLiteDatabase db = mDbHelper.getWritableDatabase();
|
||||||
|
long rowId = db.insert(ProviderTableMeta.DB_NAME, ProviderTableMeta.FILE_NAME, values);
|
||||||
|
if (rowId > 0) {
|
||||||
|
Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
|
||||||
|
getContext().getContentResolver().notifyChange(insertedFileUri, null);
|
||||||
|
return insertedFileUri;
|
||||||
|
}
|
||||||
|
throw new SQLException("ERROR " + uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreate() {
|
||||||
|
mDbHelper = new DataBaseHelper(getContext());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor query(Uri uri, String[] projection, String selection,
|
||||||
|
String[] selectionArgs, String sortOrder) {
|
||||||
|
SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
|
||||||
|
|
||||||
|
sqlQuery.setTables(ProviderTableMeta.DB_NAME);
|
||||||
|
sqlQuery.setProjectionMap(mProjectionMap);
|
||||||
|
|
||||||
|
switch (mUriMatcher.match(uri)) {
|
||||||
|
case ROOT_DIRECTORY:
|
||||||
|
sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + " is null");
|
||||||
|
break;
|
||||||
|
case DIRECTORY:
|
||||||
|
sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="+uri.getPathSegments().get(1));
|
||||||
|
break;
|
||||||
|
case SINGLE_FILE:
|
||||||
|
if (uri.getPathSegments().size() > 1) {
|
||||||
|
sqlQuery.appendWhere(ProviderTableMeta._ID + "=" +
|
||||||
|
uri.getPathSegments().get(1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown uri id: " + uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
String order;
|
||||||
|
if (TextUtils.isEmpty(sortOrder)) {
|
||||||
|
order = ProviderTableMeta.DEFAULT_SORT_ORDER;
|
||||||
|
} else {
|
||||||
|
order = sortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLiteDatabase db = mDbHelper.getReadableDatabase();
|
||||||
|
Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, null, null, order);
|
||||||
|
|
||||||
|
c.setNotificationUri(getContext().getContentResolver(), uri);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int update(Uri uri, ContentValues values, String selection,
|
||||||
|
String[] selectionArgs) {
|
||||||
|
return mDbHelper.getWritableDatabase().update(ProviderTableMeta.DB_NAME, values, selection, selectionArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataBaseHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
|
public DataBaseHelper(Context context) {
|
||||||
|
super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(SQLiteDatabase db) {
|
||||||
|
db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "(" +
|
||||||
|
ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " +
|
||||||
|
ProviderTableMeta.FILE_NAME + " TEXT, " +
|
||||||
|
ProviderTableMeta.FILE_PATH + " TEXT, " +
|
||||||
|
ProviderTableMeta.FILE_PARENT + " INTEGER, " +
|
||||||
|
ProviderTableMeta.FILE_CREATION + " INTEGER, " +
|
||||||
|
ProviderTableMeta.FILE_MODIFIED + " INTEGER, " +
|
||||||
|
ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, " +
|
||||||
|
ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, " +
|
||||||
|
ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, " +
|
||||||
|
ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT);");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
src/eu/alefzero/owncloud/db/ProviderMeta.java
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/* ownCloud Android client application
|
||||||
|
* Copyright (C) 2011 Bartek Przybylski
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package eu.alefzero.owncloud.db;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.BaseColumns;
|
||||||
|
|
||||||
|
public class ProviderMeta {
|
||||||
|
|
||||||
|
public static final String AUTHORITY = "org.owncloud";
|
||||||
|
public static final String DB_FILE = "owncloud.db";
|
||||||
|
public static final String DB_NAME = "filelist";
|
||||||
|
public static final int DB_VERSION = 1;
|
||||||
|
|
||||||
|
private ProviderMeta() { }
|
||||||
|
|
||||||
|
static public class ProviderTableMeta implements BaseColumns {
|
||||||
|
public static final String DB_NAME = "filelist";
|
||||||
|
public static final Uri CONTENT_URI =
|
||||||
|
Uri.parse("content://" + AUTHORITY + "/");
|
||||||
|
public static final Uri CONTENT_URI_FILE =
|
||||||
|
Uri.parse("content://" + AUTHORITY + "/file");
|
||||||
|
public static final Uri CONTENT_URI_DIR =
|
||||||
|
Uri.parse("content://" + AUTHORITY + "/dir");
|
||||||
|
|
||||||
|
public static final String CONTENT_TYPE =
|
||||||
|
"vnd.android.cursor.dir/vnd.owncloud.file";
|
||||||
|
public static final String CONTENT_TYPE_ITEM =
|
||||||
|
"vnd.android.cursor.item/vnd.owncloud.file";
|
||||||
|
|
||||||
|
public static final String FILE_PARENT = "parent";
|
||||||
|
public static final String FILE_NAME = "filename";
|
||||||
|
public static final String FILE_CREATION = "created";
|
||||||
|
public static final String FILE_MODIFIED = "modified";
|
||||||
|
public static final String FILE_CONTENT_LENGTH = "content_length";
|
||||||
|
public static final String FILE_CONTENT_TYPE = "content_type";
|
||||||
|
public static final String FILE_STORAGE_PATH = "media_path";
|
||||||
|
public static final String FILE_PATH = "path";
|
||||||
|
public static final String FILE_ACCOUNT_OWNER = "file_owner";
|
||||||
|
|
||||||
|
public static final String DEFAULT_SORT_ORDER = FILE_NAME + " asc";
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
225
src/eu/alefzero/owncloud/syncadapter/SyncAdapter.java
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
/* ownCloud Android client application
|
||||||
|
* Copyright (C) 2011 Bartek Przybylski
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.alefzero.owncloud.syncadapter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.auth.AuthScope;
|
||||||
|
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||||
|
import org.apache.http.conn.ConnectionKeepAliveStrategy;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.auth.BasicScheme;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.apache.http.protocol.BasicHttpContext;
|
||||||
|
import org.apache.http.protocol.HttpContext;
|
||||||
|
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.accounts.AuthenticatorException;
|
||||||
|
import android.accounts.OperationCanceledException;
|
||||||
|
import android.content.AbstractThreadedSyncAdapter;
|
||||||
|
import android.content.ContentProviderClient;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SyncResult;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
|
||||||
|
import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
|
||||||
|
import eu.alefzero.webdav.HttpPropFind;
|
||||||
|
import eu.alefzero.webdav.TreeNode;
|
||||||
|
import eu.alefzero.webdav.WebdavUtils;
|
||||||
|
import eu.alefzero.webdav.TreeNode.NodeProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SyncAdapter implementation for syncing sample SyncAdapter contacts to the
|
||||||
|
* platform ContactOperations provider.
|
||||||
|
*/
|
||||||
|
public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
|
private static final String TAG = "SyncAdapter";
|
||||||
|
|
||||||
|
private final AccountManager mAccountManager;
|
||||||
|
private Account mAccount;
|
||||||
|
private ContentProviderClient mContentProvider;
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
private Date mLastUpdated;
|
||||||
|
|
||||||
|
public SyncAdapter(Context context, boolean autoInitialize) {
|
||||||
|
super(context, autoInitialize);
|
||||||
|
mContext = context;
|
||||||
|
mAccountManager = AccountManager.get(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void onPerformSync(Account account, Bundle extras, String authority,
|
||||||
|
ContentProviderClient provider, SyncResult syncResult) {
|
||||||
|
mAccount = account;
|
||||||
|
mContentProvider = provider;
|
||||||
|
try {
|
||||||
|
String username = account.name.split("@")[0];
|
||||||
|
String password = mAccountManager.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE, true);
|
||||||
|
if (mAccountManager.getUserData(account, AccountAuthenticator.KEY_OC_URL) == null) {
|
||||||
|
throw new UnknownHostException();
|
||||||
|
}
|
||||||
|
Uri uri = Uri.parse(mAccountManager.getUserData(account, AccountAuthenticator.KEY_OC_URL));
|
||||||
|
Log.i(TAG, "Syncing owncloud account: " + account.name + " on url: " + uri.toString());
|
||||||
|
|
||||||
|
DefaultHttpClient client = new DefaultHttpClient();
|
||||||
|
client.getCredentialsProvider().setCredentials(
|
||||||
|
new AuthScope(uri.getHost(), (uri.getPort() == -1)?80:uri.getPort()),
|
||||||
|
new UsernamePasswordCredentials(username, password));
|
||||||
|
client.setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {
|
||||||
|
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
|
||||||
|
// TODO: change keep alive straategy basing on response: ie forbidden/not found/etc
|
||||||
|
// should have keep alive 0
|
||||||
|
// default return: 5s
|
||||||
|
return 5 * 1000;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BasicHttpContext httpContext = new BasicHttpContext();
|
||||||
|
BasicScheme basicAuth = new BasicScheme();
|
||||||
|
httpContext.setAttribute("preemptive-auth", basicAuth);
|
||||||
|
HttpHost targetHost = new HttpHost(uri.getHost(), (uri.getPort() == -1)
|
||||||
|
? 80
|
||||||
|
: uri.getPort(), (uri.getScheme() == "https") ? "https" : "http");
|
||||||
|
|
||||||
|
HttpPropFind query = new HttpPropFind(uri.toString());
|
||||||
|
query.setHeader("Content-type", "text/xml");
|
||||||
|
query.setHeader("User-Agent", "Android-ownCloud");
|
||||||
|
HttpEntity entity = new StringEntity(WebdavUtils.prepareXmlForPropFind());
|
||||||
|
query.setEntity(entity);
|
||||||
|
HttpResponse response = client.execute(targetHost, query, httpContext);
|
||||||
|
/*try {
|
||||||
|
mContentProvider.delete(ProviderTableMeta.CONTENT_URI,
|
||||||
|
ProviderTableMeta.FILE_NAME + " LIKE '%' AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER +"=?"
|
||||||
|
, new String[]{account.name});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
TreeNode root = new TreeNode();
|
||||||
|
root.setProperty(TreeNode.NodeProperty.NAME, "/");
|
||||||
|
parseResponse(response, uri, client, targetHost, httpContext, root.getChildList());
|
||||||
|
|
||||||
|
commitToDatabase(root, null);
|
||||||
|
|
||||||
|
} catch (OperationCanceledException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (AuthenticatorException e) {
|
||||||
|
syncResult.stats.numAuthExceptions++;
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
syncResult.stats.numIoExceptions++;
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void commitToDatabase(TreeNode root, String parentId) throws RemoteException {
|
||||||
|
for (TreeNode n : root.getChildList()) {
|
||||||
|
Log.d(TAG, n.toString());
|
||||||
|
ContentValues cv = new ContentValues();
|
||||||
|
cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, n.getProperty(NodeProperty.CONTENT_LENGTH));
|
||||||
|
cv.put(ProviderTableMeta.FILE_MODIFIED, n.getProperty(NodeProperty.LAST_MODIFIED_DATE));
|
||||||
|
cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, n.getProperty(NodeProperty.RESOURCE_TYPE));
|
||||||
|
cv.put(ProviderTableMeta.FILE_PARENT, parentId);
|
||||||
|
|
||||||
|
String name = n.getProperty(NodeProperty.NAME),
|
||||||
|
path = n.getProperty(NodeProperty.PATH);
|
||||||
|
Cursor c = mContentProvider.query(ProviderTableMeta.CONTENT_URI_FILE,
|
||||||
|
null,
|
||||||
|
ProviderTableMeta.FILE_NAME+"=? AND " + ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
|
||||||
|
new String[]{name, path, mAccount.name},
|
||||||
|
null);
|
||||||
|
if (c.moveToFirst()) {
|
||||||
|
mContentProvider.update(ProviderTableMeta.CONTENT_URI,
|
||||||
|
cv,
|
||||||
|
ProviderTableMeta._ID+"=?",
|
||||||
|
new String[]{c.getString(c.getColumnIndex(ProviderTableMeta._ID))});
|
||||||
|
Log.d(TAG, "ID of: "+name+":"+c.getString(c.getColumnIndex(ProviderTableMeta._ID)));
|
||||||
|
} else {
|
||||||
|
cv.put(ProviderTableMeta.FILE_NAME, n.getProperty(NodeProperty.NAME));
|
||||||
|
cv.put(ProviderTableMeta.FILE_PATH, n.getProperty(NodeProperty.PATH));
|
||||||
|
cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
|
||||||
|
Uri entry = mContentProvider.insert(ProviderTableMeta.CONTENT_URI_FILE, cv);
|
||||||
|
Log.d(TAG, "Inserting new entry " + path + name);
|
||||||
|
c = mContentProvider.query(entry, null, null, null, null);
|
||||||
|
c.moveToFirst();
|
||||||
|
}
|
||||||
|
if (n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) {
|
||||||
|
commitToDatabase(n, c.getString(c.getColumnIndex(ProviderTableMeta._ID)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clean removed files
|
||||||
|
String[] selection = new String[root.getChildList().size()+2];
|
||||||
|
selection[0] = mAccount.name;
|
||||||
|
selection[1] = parentId;
|
||||||
|
String qm = "";
|
||||||
|
for (int i = 2; i < selection.length-1; ++i) {
|
||||||
|
qm += "?,";
|
||||||
|
selection[i] = root.getChildList().get(i-2).getProperty(NodeProperty.NAME);
|
||||||
|
}
|
||||||
|
if (selection.length >= 3) {
|
||||||
|
selection[selection.length-1] = root.getChildrenNames()[selection.length-3];
|
||||||
|
qm += "?";
|
||||||
|
}
|
||||||
|
for (int i = 0; i < selection.length; ++i) {
|
||||||
|
Log.d(TAG,selection[i]+"");
|
||||||
|
}
|
||||||
|
Log.d(TAG,"Removing files "+ parentId);
|
||||||
|
mContentProvider.delete(ProviderTableMeta.CONTENT_URI,
|
||||||
|
ProviderTableMeta.FILE_ACCOUNT_OWNER+"=? AND " + ProviderTableMeta.FILE_PARENT + (parentId==null?" IS ":"=")+"? AND " + ProviderTableMeta.FILE_NAME + " NOT IN ("+qm+")",
|
||||||
|
selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseResponse(HttpResponse resp, Uri uri, DefaultHttpClient client, HttpHost targetHost, BasicHttpContext httpContext, LinkedList<TreeNode> insertList) throws IOException {
|
||||||
|
boolean skipFirst = true;
|
||||||
|
for (TreeNode n :WebdavUtils.parseResponseToNodes(resp.getEntity().getContent())) {
|
||||||
|
String path = n.stripPathFromFilename(uri.getPath());
|
||||||
|
if (skipFirst) {
|
||||||
|
skipFirst = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
insertList.add(n);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(n.getProperty(NodeProperty.NAME)) &&
|
||||||
|
n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) {
|
||||||
|
HttpPropFind method = new HttpPropFind(uri.getPath() + path + n.getProperty(NodeProperty.NAME).replace(" ", "%20") + "/");
|
||||||
|
Log.i(TAG, uri.getPath() + path + n.getProperty(NodeProperty.NAME).replace(" ", "%20") + "/");
|
||||||
|
Log.i(TAG, method.getRequestLine().toString());
|
||||||
|
HttpResponse response = client.execute(targetHost, method, httpContext);
|
||||||
|
parseResponse(response, uri, client, targetHost, httpContext, n.getChildList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
src/eu/alefzero/owncloud/syncadapter/SyncService.java
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
package eu.alefzero.owncloud.syncadapter;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
public class SyncService extends Service {
|
||||||
|
private static final Object sSyncAdapterLock = new Object();
|
||||||
|
private static SyncAdapter sSyncAdapter = null;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
synchronized (sSyncAdapterLock) {
|
||||||
|
if (sSyncAdapter == null) {
|
||||||
|
sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return sSyncAdapter.getSyncAdapterBinder();
|
||||||
|
}
|
||||||
|
}
|
19
src/eu/alefzero/webdav/HttpMkCol.java
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package eu.alefzero.webdav;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||||
|
|
||||||
|
public class HttpMkCol extends HttpEntityEnclosingRequestBase {
|
||||||
|
|
||||||
|
public final static String METHOD_NAME = "MKCOL";
|
||||||
|
|
||||||
|
public HttpMkCol(final String uri) {
|
||||||
|
setURI(URI.create(uri));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethod() {
|
||||||
|
return METHOD_NAME;
|
||||||
|
}
|
||||||
|
}
|
32
src/eu/alefzero/webdav/HttpPropFind.java
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package eu.alefzero.webdav;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||||
|
import org.apache.http.protocol.HTTP;
|
||||||
|
|
||||||
|
public class HttpPropFind extends HttpEntityEnclosingRequestBase {
|
||||||
|
|
||||||
|
public final static String METHOD_NAME = "PROPFIND";
|
||||||
|
|
||||||
|
public HttpPropFind(final URI uri) {
|
||||||
|
super();
|
||||||
|
setURI(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpPropFind(final String uri) {
|
||||||
|
this.setDepth("1");
|
||||||
|
setURI(URI.create(uri));
|
||||||
|
this.setHeader(HTTP.CONTENT_TYPE, "text/xml" + HTTP.CHARSET_PARAM + HTTP.UTF_8.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethod() {
|
||||||
|
return METHOD_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDepth(String depth) {
|
||||||
|
this.setHeader("Depth", depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|