# generated files
bin/
+build/
+*.iml
gen/
target/
oc_framework-test-project/proguard-project.txt
tests/proguard-project.txt
-# Should not be commited inside this repo:
-actionbarsherlock/
\ No newline at end of file
+# Android Studio and Gradle specific entries
+.gradle
+.idea
+*.iml
+build
+
+# Actionbarsherlock is now ignored since scripts takes care of init the sub-modules.
+actionbarsherlock
\ No newline at end of file
-[submodule "actionbarsherlock"]
- path = actionbarsherlock
- url = git://github.com/JakeWharton/ActionBarSherlock.git
+
[submodule "owncloud-android-library"]
path = owncloud-android-library
url = git://github.com/owncloud/android-library.git
+ branch = develop
+[submodule "ocdoc"]
+ path = user_manual/ocdoc
+ url = https://github.com/owncloud/documentation
+ branch = master
language: android
android:
components:
- - build-tools-20.0.0
+ - build-tools-22.0.1
- android-19
- - android-17
- - android-14
- - extra-android-support
- licenses:
- - 'android-sdk-license-5be876d5'
- - 'android-sdk-license-598b93a6'
-
-jdk: oraclejdk7
-
+ - android-16
before_install:
- rm pom.xml
- - ./setup_env.sh
-
script:
+ - ./setup_env.sh ant
- ant clean
- ant debug
-
+
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2014 ownCloud Inc.
+ Copyright (C) 2012-2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest package="com.owncloud.android"
- android:versionCode="10600100"
- android:versionName="1.6.1" xmlns:android="http://schemas.android.com/apk/res/android">
+ android:versionCode="10700200"
+ android:versionName="1.7.2" xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-sdk
- android:minSdkVersion="8"
+ android:minSdkVersion="14"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
android:name=".ui.activity.Preferences"
android:theme="@style/Theme.ownCloud" >
</activity>
- <activity android:name=".ui.activity.PreferencesNewSessionewSession" >
- </activity>
-
<activity
android:name=".ui.preview.PreviewImageActivity"
/>
<service android:name=".files.services.FileUploader" />
<service android:name=".media.MediaService" />
- <activity android:name=".ui.activity.PinCodeActivity" />
+ <activity android:name=".ui.activity.PassCodeActivity" />
<activity android:name=".ui.activity.ConflictsResolveActivity"/>
<activity android:name=".ui.activity.GenericExplanationActivity"/>
<activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
android:icon="@drawable/copy_link"/>
<activity
- android:name=".ui.activity.MoveActivity"
+ android:name=".ui.activity.FolderPickerActivity"
+ android:label="@string/app_name"/>
+
+ <activity
+ android:name=".ui.activity.UploadPathActivity"
android:label="@string/app_name"/>
</application>
--- /dev/null
+## 1.7.2 (July 2015)
+- New navigation drawer
+- Improved Passcode
+- Automatic grid view just for folders full of images
+- More characters allowed in file names
+- Support for servers in same domain, different path
+- Bugs fixed:
+ + Frequent crashes in folder with several images
+ + Sync error in servers with huge quota and external storage enable
+ + Share by link error
+ + Some other crashes and minor bugs
+
+## 1.7.1 (April 2015)
+
+- Share link even with password enforced by server
+- Get the app ready for oc 8.1 servers
+- Added option to create new folder in uploads from external apps
+- Improved management of deleted users
+- Bugs fixed
+ + Fixed crash on Android 2.x devices
+ + Improvements on uploads
+
+## 1.7.0 (February 2015)
+
+- Download full folders
+- Grid view for images
+- Remote thumbnails (OC Server 8.0+)
+- Added number of files and folders at the end of the list
+- "Open with" in contextual menu
+- Downloads added to Media Provider
+- Uploads:
+ + Local thumbnails in section "Files"
+ + Multiple selection in "Content from other apps" (Android 4.3+)
+- Gallery:
+ + proper handling of EXIF
+ + obey sorting in the list of files
+- Settings view updated
+- Improved subjects in e-mails
+- Bugs fixed
+
+
+
[agreement]: http://owncloud.org/about/contributor-agreement/
+### 1. Fork and download android/develop repository:
+
+NOTE: You must have the git installation folder in your environment variable PATH to perform the next operations.
+
+* In a web browser, go to https://github.com/owncloud/android, and click the 'Fork' button near the top right corner.
+* In a command line prompt, clone your new repo: ```git clone git@github.com:YOURGITHUBNAME/android.git```.
+* Move to the project folder with ```cd android```.
+* Checkout the remote branch 'develop' in your own local branch: ```git checkout -b develop remotes/origin/develop```.
+* Pull any changes from your remote branch 'develop': ```git pull origin develop```
+* Make official ownCloud repo known as upstream: ```git remote add upstream git@github.com:owncloud/android.git```
+* Make sure to get the latest changes from official android/develop branch: ```git pull upstream develop```
+
+
+### 7. Create pull request:
+
+NOTE: You must sign the [Contributor Agreement][1] before your changes can be accepted!
+
+* Commit your changes locally: "git commit -a"
+* Push your changes to your GitHub repo: "git push"
+* Browse to https://github.com/YOURGITHUBNAME/android/pulls and issue pull request
+* Click "Edit" and set "base:develop"
+* Again, click "Edit" and set "compare:develop"
+* Enter description and send pull request.
+
+### 8. Create another pull request:
+
+To make sure your new pull request does not contain commits which are already contained in previous PRs, create a new branch which is a clone of upstream/develop.
+
+* git fetch upstream
+* git checkout -b my_new_develop_branch upstream/develop
+* If you want to rename that branch later: "git checkout -b my_new_develop_branch_with_new_name"
+* Push branch to server: "git push -u origin name_of_local_develop_branch"
+* Use GitHub to issue PR
+
+
+
## Translations
Please submit translations via [Transifex][transifex].
[transifex]: https://www.transifex.com/projects/p/owncloud/
+
Make sure you read [SETUP.md][1] when you start working on this project.
[0]: https://github.com/owncloud/core
-[1]: https://raw.github.com/owncloud/android/master/SETUP.md
\ No newline at end of file
+[1]: https://github.com/owncloud/android/blob/master/SETUP.md
-
-If you want to start help developing ownCloud please follow the [contribution guidelines][0] and observe these instructions.
-If you have any problems, start again with 1) and work your way down. If something still does not work as described here, please open a new issue describing exactly what you did, what happened, and what should have happened.
-
-### 1) Fork and download android/develop repository:
+These instructions will help you to set up your development environment, get the source code of the ownCloud for Android app and build it by yourself. If you want to help developing the app take a look to the [contribution guidelines][0].
-NOTE: Android SDK with platforms 8, 14 and 19 (and maybe others) need to be installed.
- You must have the Android SDK 'tools/', and 'platforms-tools/' folders in your environment path variable.
- "git" need to be installed and in your environment path variable.
+Sections 1) and 2) are common for any environment. The rest of the sections describe how to set up a project in different tool environments. Choose the build tool or IDE you prefer and follow the instructions in its specific section. Nowadays we recommend to use Android Studio (section 2), but the decision is up to you.
-* Navigate to https://github.com/owncloud/android, click fork.
-* Clone your new repo: "git clone git@github.com:YOURGITHUBNAME/android.git"
-* Move to the project folder with "cd android"
-* Checkout remote develop branch: "git checkout -b develop remotes/origin/develop"
-* Pull changes from your develop branch: "git pull origin develop"
-* Make official ownCloud repo known as upstream: "git remote add upstream git@github.com:owncloud/android.git"
-* Make sure to get the latest changes from official android/develop branch: "git pull upstream develop"
-* Complete the setup of project properties and resolve pending dependencies running "setup_env.bat" or "./setup_env.sh" .
+If you have any problem, remove the 'android' folder, start again from 1) and work your way down. If something still does not work as described here, please open a new issue describing exactly what you did, what happened, and what should have happened.
-At this point you can continue using different tools to build the project. Sections 2a), 2b), and 2c) describe some of the existing alternatives.
-### 2a) Building with Ant:
-
-NOTE: You must have the Android SDK 'tools/', and 'platforms-tools/' folders in your environment path variable.
+### 0. Common software dependencies.
-* Run "ant clean" .
-* Run "ant debug" to generate a debuggable version of the ownCloud app.
+There are some tools needed, no matter what is your specific IDE or build tool of preference.
-### 2b) Building with console/maven:
+[git][1] is used to access to the different versions of the ownCloud's source code. Download and install the version appropiate for your operating system from [here][2]. Add the full path to the 'bin/' directory from your git installation into the PATH variable of your environment so that it can be used from any location.
+
+The [Android SDK][3] is necessary to build the app. There are different options to install it in your system, depending of the IDE you decide to use. Check Google documentation about [installation][4] for more details on these options. After installing it, add the full path to the directories 'tools/' and 'platform-tools/' from your Android SDK installation into the PATH variable of your environment.
+
+Open a terminal and type 'android' to start the Android SDK Manager. To build the ownCloud for Android app you will need to install at least the next SDK packages:
+
+* Android SDK Tools and Android SDK Platform-tools (already installed); upgrade to their last versions is usually a good idea.
+* Android SDK Build-Tools; any version from 20 or later should work fine; avoid preview versions, if any available.
+* Android 4.4.2 (API 19), SDK Platform; needed to build the ownCloud app.
+* Android 4.1.2 (API 16), SDK Platform; needed to build the Android Support Library (not neeeded if working with Android Studio or gradle).
+
+Install any other package you consider interesting, such as emulators.
+
+For other software dependencies check the details in the section corresponding to your preferred IDE or build system.
+
+
+### 1. Fork and download the owncloud/android repository.
+
+You will need [git][1] to access to the different versions of the ownCloud's source code. The source code is hosted in Github and may be read by anybody without needing a Github account. You will need a Github account if you want to contribute to the development of the app with your own code.
+
+Next steps will assume you have a Github account and that you will get the code from your own fork.
+
+* In a web browser, go to https://github.com/owncloud/android, and click the 'Fork' button near the top right corner.
+* Open a terminal and go on with the next steps in it.
+* Clone your forked repository: ```git clone git@github.com:YOURGITHUBNAME/android.git```.
+* Move to the project folder with ```cd android```.
+* Checkout the remote branch 'develop' in your own local branch 'develop': ```git checkout -b develop remotes/origin/develop```.
+* Pull any changes from your remote branch 'develop': ```git pull origin develop```
+* Make official ownCloud repo known as upstream: ```git remote add upstream git@github.com:owncloud/android.git```
+* Make sure to get the latest changes from official android/develop branch: ```git pull upstream develop```
+
+At this point you can continue using different tools to build the project. Section 2, 3, 4, 5 and 6 describe the existing alternatives.
+
+
+### 2. Working with Android Studio.
+
+[Android Studio][5] is currently the official Android IDE. Due to this, we recommend it as the IDE to use in your development environment. Follow the installation instructions [here][6].
+
+We recommend to use the last version available in the stable channel of Android Studio updates. See what update channel is your Android Studio checking for updates in the menu path 'Help'/'Check for Update...'/link 'Updates' in the dialog.
+
+To set up the project in Android Studio follow the next steps:
+
+* Complete the setup of project properties running:
+ - Windows: ```setup_env.bat gradle```
+ - Mac OS/Linux: ```./setup_env.sh gradle```
+* Open Android Studio and select 'Import Project (Eclipse ADT, Gradle, etc)'. Browse through your file system to the folder 'android' where the project is located. Android Studio will then create the '.iml' files it needs. If you ever close the project but the files are still there, you just select 'Open Project...'. The file chooser will show an Android face as the folder icon, which you can select to reopen the project.
+* Android Studio will try to build the project directly after importing it. To build it manually, follow the menu path 'Build'/'Make Project', or just click the 'Play' button in the tool bar to build and run it in a mobile device or an emulator. The resulting APK file will be saved in the 'build/outputs/apk/' subdirectory in the project folder.
+
+
+### 3. Working in a terminal with Gradle:
+
+[Gradle][7] is the build system used by Android Studio to manage the building operations on Android apps. You do not need to install Gradle in your system, and Google recommends not to do it, but instead trusting on the Graddle wrapper included in the project [8].
+
+* Open a terminal and go to the 'android' directory that contains the repository.
+* Complete the setup of project properties running:
+ - Windows: ```setup_env.bat gradle```
+ - Mac OS/Linux: ```./setup_env.sh gradle```
+* Run the 'clean' and 'build' tasks using the Gradle wrapper provided
+ - Windows: ```gradlew.bat clean build```
+ - Mac OS/Linux: ```./gradlew clean build```
+
+The first time the Gradle wrapper is called, the correct Gradle version will be downloaded automatically. An Internet connection is needed for it works.
+
+The generated APK file is saved in android/build/outputs/apk as android-debug.apk
+
+
+### 4. Building with Eclipse:
+
+[Eclipse][9] is still an option to work with Android apps, although the [ADT Plugin][10] needed is not in active development anymore. Next steps have been tested in Eclipse Luna.
+
+* Open a terminal and go to the 'android' directory that contains the repository.
+* Resolve necessary dependencies running:
+ - Windows: ```setup_env.bat ant```
+ - Mac OS/Linux: ```./setup_env.sh ant```
+* Open Eclipse and follow the menu path 'File'/'New'/'Project'
+* Choose the option 'Android'/'Android Project from Existing Code' and click 'Next'
+* Choose 'android/' folder as root
+* Choose the projects with the next names under the 'New Project Name' column:
+** owncloud-android
+** android-support-appcompat-v7-exploded-aar
+** owncloud-android-workaround-accounts (optional)
+** ownCloud Android Library
+** ownCloud Sample Client (optional)
+** ownCloud Android library test project (optional)
+** ownCloud Android library test cases (optional)
+* Do not choose the project owncloud-android-tests; it's obsolete.
+* Do not enable 'Copy projects into workspace'.
+* Click the 'Finish' button.
+* Wait for a while; if 'Build automatically' is enabled in Eclipse, some errors could appear during the creation of the projects, but all of them should finally disappear.
+* If any error persists, clean and build manually the next projects in order:
+** ownCloud Android Library
+** android-support-appcompat-v7-exploded-aar
+** owncloud-android
+* If any error on those projects persists, check the project properties. In the 'Android' section, API Level should be
+** ownCloud Android Library -> API level 19
+** android-support-appcompat-v7-exploded-aa -> API level 16
+** owncloud-android -> API level 19 ; in this project, two library projects should appear referred in the bottom of the dialog: libs\android-support-appcompat-v7-exploded-aar and owncloud-android-library. Add them if needed.
+* After those actions you should be good to go. HAVE FUN!
+
+
+### 5. Building in command line with Ant:
+
+[Ant][10] can be used to build the ownCloud for Android app in a terminal. Be sure that the PATH variable in your environment contains the full path to the 'bin/' subdirectory in your Ant installation. Define also an ANDROID_HOME variable in your environment with the full path to your Android SDK (see section 1). Then follow the next steps:
+
+* Open a terminal and go to the 'android' directory that contains the repository.
+* Resolve necessary dependencies running:
+ - Windows: ```setup_env.bat ant```
+ - Mac OS/Linux: ```./setup_env.sh ant```
+* Run ```ant clean```.
+* Run ```ant debug``` to generate a debuggable version of the ownCloud app.
+
+The resulting APKs will be saved in the 'bin/' subdirectory of the project.
+
+
+### 6. Building in command line with maven:
+
+** Currently these build instructions DO NOT WORK. There is no estimation time to fix it. Unless some volunteer contributor fixes this build option, and given that Maven is a minority option in Android environments, we will probably remove this option.
NOTE: You must have mvn (version >= 3.1.1) in your environment path. Current Android 'platforms-tools' need to be installed.
-Download/install Android plugin for Maven, install owncloud-android-library, then build ownCloud with mvn:
+Download/install Android plugin for Maven, then build ownCloud with mvn:
+* Resolve necessary dependencies running:
+ - Windows: "setup_env.bat maven"
+ - Mac OS/Linux: "./setup_env.sh maven"
+
* cd ..
* git clone https://github.com/mosabua/maven-android-sdk-deployer.git
* cd maven-android-sdk-deployer
* mvn install
* cd ..
-Now you can create ownCloud APK using "mvn package"
-
-### 2c) Building with Eclipse:
-
-NOTE: You must have the Android SDK 'tools/', and 'platforms-tools/' folders in your environment path variable.
-
-* Complete the setup of project properties and resolve pending dependencies running "setup_env.bat" or "./setup_env.sh" .
-* Open Eclipse and create new "Android Project from Existing Code". Choose android/actionbarsherlock/library as root.
-* Clean project and compile.
-* If any error appear, check the project properties; in the 'Android' section, API Level should be greater or equal than 14.
-* If "error loading libz.so.1" appears, try "sudo apt-get install lib32z1"
-* Make sure android/actionbarsherlock/library/bin/library.jar was created.
-* Create a new "Android Project from Existing Code". Choose android/owncloud-android-library as root. (test and sample clients are not required.)
-* Clean project and compile.
-* If any error appear, check the project properties; in the 'Android' section, API Level should be 19 or greater.
-* Make sure 'android/owncloud-android-library/bin/owncloud android library.jar' was created.
-* Import ownCloud Android project.
-* Clean project and compile.
-* If any error appears, check the project properties of owncloud-android project; in the 'Android' section:
- - API Level should be 19 or greater.
- - Two library projects should appear referred in the bottom square: actionbarsherlock/library and owncloud-android-library. Add them if needed.
-* After those actions you should be good to go. HAVE FUN!
-
-NOTE: Even though API level is set to 19, APK also runs on older devices because in AndroidManifest.xml minSdkVersion is set to 8.
-
-### 3) Create pull request:
-
-NOTE: You must sign the [Contributor Agreement][1] before your changes can be accepted!
-
-* Commit your changes locally: "git commit -a"
-* Push your changes to your Github repo: "git push"
-* Browse to https://github.com/YOURGITHUBNAME/android/pulls and issue pull request
-* Click "Edit" and set "base:develop"
-* Again, click "Edit" and set "compare:develop"
-* Enter description and send pull request.
-
-### 4) Create another pull request:
-
-To make sure your new pull request does not contain commits which are already contained in previous PRs, create a new branch which is a clone of upstream/develop.
-
-* git fetch upstream
-* git checkout -b my_new_develop_branch upstream/develop
-* If you want to rename that branch later: "git checkout -b my_new_develop_branch_with_new_name"
-* Push branch to server: "git push -u origin name_of_local_develop_branch"
-* Use Github to issue PR
+Now you can create ownCloud APK using "mvn package" and find it as ownCloud.apk under the target
[0]: https://github.com/owncloud/android/blob/master/CONTRIBUTING.md
-[1]: http://owncloud.org/about/contributor-agreement/
+[1]: https://git-scm.com/
+[2]: https://git-scm.com/downloads
+[3]: https://developer.android.com/sdk/index.html
+[4]: https://developer.android.com/sdk/installing/index.html
+[5]: https://developer.android.com/tools/studio/index.html
+[6]: https://developer.android.com/sdk/installing/index.html?pkg=studio
+[7]: https://gradle.org/
+[8]: https://docs.gradle.org/current/userguide/gradle_wrapper.html
+[9]: https://eclipse.org/
+[10]: http://developer.android.com/sdk/installing/installing-adt.html
Used as a helper tool, not included in the ownCloud client APK.
Original license document included at third_party/transifex-client/LICENSE.
See http://help.transifex.com/features/client/
-
- * ActionBarSherlock, master branch.
- Copyright (C) 2012 Jake Wharton.
- Licensed under Apache License, Version 2.0.
- The official repository is linked as a submodule in the
- ownCloud/android repository.
- A binary JAR file must be generated from this linked project
- and included in the ownCloud client APK.
- See http://http://actionbarsherlock.com/
* TouchImageView, commit 6dbeac4f11936185ba374c73144ac431c23c9aab
Copyright (c) 2012 Michael Ortiz
+++ /dev/null
-Subproject commit 9598f2bb2ceed4a834cd5586a903f270ca4c0ccc
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" output="target/classes" path="src/main/java">
+ <attributes>
+ <attribute name="optional" value="true"/>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="src" path="resources"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+ <attributes>
+ <attribute name="optional" value="true"/>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
--- /dev/null
+
+target/
+ScreenShots/
+.DS_Store
+Users/
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>androidtest</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.7
--- /dev/null
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
--- /dev/null
+** Work in progress
+
+This project contains a set of automatic tests operating in the UI level.
+
+Tests are to be run with the tool Appium. Check [here][0] to install it and all its dependencies (including Maven).
+
+You will need to modify the constants in automationTest/src/test/java/com/owncloud/android/test/ui/testSuites/Config.java to assign appropiate values for your test server and accounts.
+You will need to include the ownCloud.apk to test in automationTest/src/test/resources/.
+
+To run the tests from command line, plug a device to your computer or start and emulator. Then type
+
+mvn clean tests
+
+To run only one category of the test
+
+mvn clean -Dtest=RunSmokeTests test
+
+The project may also be imported in Eclipse, with the appropiate plug-ins, and run from it.
+
+[0]: http://appium.io/slate/en/master/?java#about-appium
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<modelVersion>4.0.0</modelVersion>
+
+<groupId>com.owncloud</groupId>
+<artifactId>androidtest</artifactId>
+<version>1.0-SNAPSHOT</version>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.18.1</version>
+ <configuration>
+ <includes>
+ <include>**/*Test**.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.3</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+<dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ </dependency>
+ <dependency>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-java</artifactId>
+ <version>2.45.0</version>
+ </dependency>
+ <dependency>
+ <groupId>io.selendroid</groupId>
+ <version>0.9.0</version>
+ <artifactId>selendroid-standalone</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.selendroid</groupId>
+ <version>0.9.0</version>
+ <artifactId>selendroid-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.appium</groupId>
+ <artifactId>java-client</artifactId>
+ <version>2.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.android</groupId>
+ <artifactId>android</artifactId>
+ <version>4.1.1.4</version>
+ <scope>provided</scope>
+ </dependency>
+</dependencies>
+</project>
\ No newline at end of file
--- /dev/null
+# Ignore everything in this directory
+*
+# Except this file
+!.gitignore
\ No newline at end of file
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.actions;
+
+import java.util.HashMap;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.ScreenOrientation;
+import org.openqa.selenium.remote.RemoteWebElement;
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import com.owncloud.android.test.ui.models.CertificatePopUp;
+import com.owncloud.android.test.ui.models.ElementMenuOptions;
+import com.owncloud.android.test.ui.models.GmailSendMailView;
+import com.owncloud.android.test.ui.models.ShareView;
+import com.owncloud.android.test.ui.models.UploadFilesView;
+import com.owncloud.android.test.ui.models.LoginForm;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.MenuList;
+import com.owncloud.android.test.ui.models.NewFolderPopUp;
+import com.owncloud.android.test.ui.models.RemoveConfirmationView;
+import com.owncloud.android.test.ui.models.SettingsView;
+import com.owncloud.android.test.ui.models.WaitAMomentPopUp;
+import com.owncloud.android.test.ui.testSuites.Common;
+import com.owncloud.android.test.ui.testSuites.Config;
+
+public class Actions {
+
+ public static FileListView login(String url, String user, String password,
+ Boolean isTrusted, AndroidDriver driver)
+ throws InterruptedException {
+ LoginForm loginForm = new LoginForm(driver);
+ CertificatePopUp certificatePopUp = loginForm.typeHostUrl(url);
+ if(!isTrusted){
+ WebDriverWait wait = new WebDriverWait(driver, 30);
+ //sometimes the certificate has been already accept
+ //and it doesn't appear again
+ try {
+ wait.until(ExpectedConditions
+ .visibilityOf(certificatePopUp.getOkButtonElement()));
+ //we need to repaint the screen
+ //because of some element are misplaced
+ driver.rotate(ScreenOrientation.LANDSCAPE);
+ driver.rotate(ScreenOrientation.PORTRAIT);
+ certificatePopUp.clickOnOkButton();
+ }catch (NoSuchElementException e) {
+
+ }
+
+ }
+ loginForm.typeUserName(user);
+ loginForm.typePassword(password);
+ //TODO. Assert related to check the connection?
+ return loginForm.clickOnConnectButton();
+ }
+
+ public static WaitAMomentPopUp createFolder(String folderName,
+ FileListView fileListView){
+ NewFolderPopUp newFolderPopUp = fileListView.clickOnNewFolderButton();
+ newFolderPopUp.typeNewFolderName(folderName);
+ WaitAMomentPopUp waitAMomentPopUp = newFolderPopUp
+ .clickOnNewFolderOkButton();
+ //TODO. assert here
+ return waitAMomentPopUp;
+ }
+
+
+ public static AndroidElement scrollTillFindElement (String elementName,
+ AndroidElement element, AndroidDriver driver) {
+ AndroidElement fileElement;
+
+ if(element.getAttribute("scrollable").equals("true")){
+ HashMap<String, String> scrollObject = new HashMap<String,String>();
+ scrollObject.put("text", elementName);
+ scrollObject.put("element", ( (RemoteWebElement) element).getId());
+ driver.executeScript("mobile: scrollTo", scrollObject);
+ }
+ try {
+ fileElement = (AndroidElement) driver
+ .findElementByName(elementName);
+ } catch (NoSuchElementException e) {
+ fileElement = null;
+ }
+ return fileElement;
+ }
+
+
+ public static void deleteAccount (int accountPosition,FileListView fileListView) {
+ MenuList menulist = fileListView.clickOnMenuButton();
+ SettingsView settingView = menulist.clickOnSettingsButton();
+ deleteAccount(accountPosition,settingView);
+ }
+
+ public static void deleteAccount (int accountPosition, SettingsView settingsView) {
+ settingsView.tapOnAccountElement(accountPosition,1, 1000);
+ settingsView.clickOnDeleteAccountElement();
+ }
+
+ public static void clickOnMainLayout(AndroidDriver driver){
+ driver.tap(1, 0, 0, 1);
+ }
+
+
+ public static AndroidElement deleteElement(String elementName,
+ FileListView fileListView, AndroidDriver driver) throws Exception{
+ AndroidElement fileElement;
+ WaitAMomentPopUp waitAMomentPopUp;
+ try{
+ //To open directly the "file list view" and
+ //we don't need to know in which view we are
+ driver.startActivity("com.owncloud.android",
+ ".ui.activity.FileDisplayActivity");
+ fileElement = (AndroidElement) driver
+ .findElementByName(elementName);
+ ElementMenuOptions menuOptions = fileListView
+ .longPressOnElement(elementName);
+ RemoveConfirmationView removeConfirmationView = menuOptions
+ .clickOnRemove();;
+ waitAMomentPopUp = removeConfirmationView
+ .clickOnRemoteAndLocalButton();
+ Common.waitTillElementIsNotPresent(
+ waitAMomentPopUp.getWaitAMomentTextElement(), 100);
+ }catch(NoSuchElementException e){
+ fileElement=null;
+ }
+ return fileElement;
+ }
+
+ public static AndroidElement shareLinkElementByGmail(String elementName,
+ FileListView fileListView, AndroidDriver driver, Common common)
+ throws Exception{
+ try{
+ //To open directly the "file list view" and
+ //we don't need to know in which view we are
+ driver.startActivity("com.owncloud.android",
+ ".ui.activity.FileDisplayActivity");
+ ElementMenuOptions menuOptions = fileListView
+ .longPressOnElement(elementName);
+ ShareView shareView = menuOptions.clickOnShareLinkElement();
+ Actions.scrollTillFindElement("Gmail", shareView
+ .getListViewLayout(), driver).click();
+ GmailSendMailView gmailSendMailView = new GmailSendMailView(driver);
+ gmailSendMailView.typeToEmailAdress(Config.gmailAccount);
+ gmailSendMailView.clickOnSendButton();
+ Common.waitTillElementIsNotPresentWithoutTimeout(fileListView
+ .getProgressCircular(), 1000);
+ common.wait.until(ExpectedConditions.visibilityOf(
+ fileListView.getFileElementLayout()
+ .findElement(By.id(FileListView
+ .getSharedElementIndicator()))));
+
+ }catch(NoSuchElementException e){
+ return null;
+ }
+ return (AndroidElement) fileListView.getFileElementLayout()
+ .findElement(By.id(FileListView.getSharedElementIndicator()));
+ }
+
+ public static AndroidElement shareLinkElementByCopyLink(String elementName,
+ FileListView fileListView, AndroidDriver driver, Common common)
+ throws Exception{
+ try{
+ //To open directly the "file list view" and
+ //we don't need to know in which view we are
+ driver.startActivity("com.owncloud.android",
+ ".ui.activity.FileDisplayActivity");
+ ElementMenuOptions menuOptions = fileListView
+ .longPressOnElement(elementName);
+ ShareView shareView = menuOptions.clickOnShareLinkElement();
+ Actions.scrollTillFindElement("Copy link", shareView.getListViewLayout(),
+ driver).click();
+ WaitAMomentPopUp waitAMomentPopUp = new WaitAMomentPopUp(driver);
+ Common.waitTillElementIsNotPresentWithoutTimeout(waitAMomentPopUp
+ .getWaitAMomentTextElement(), 100);
+ common.wait.until(ExpectedConditions.visibilityOf(
+ fileListView.getFileElementLayout()
+ .findElement(By.id(FileListView.getSharedElementIndicator()))));
+ }catch(NoSuchElementException e){
+ return null;
+ }
+ return (AndroidElement) fileListView.getFileElementLayout()
+ .findElement(By.id(FileListView.getSharedElementIndicator()));
+ }
+
+
+ public static void unshareLinkElement(String elementName,
+ FileListView fileListView, AndroidDriver driver, Common common)
+ throws Exception{
+ try{
+ //To open directly the "file list view" and
+ //we don't need to know in which view we are
+ driver.startActivity("com.owncloud.android",
+ ".ui.activity.FileDisplayActivity");
+ ElementMenuOptions menuOptions = fileListView
+ .longPressOnElement(elementName);
+ WaitAMomentPopUp waitAMomentPopUp = menuOptions
+ .clickOnUnshareLinkElement();
+ Common.waitTillElementIsNotPresentWithoutTimeout(waitAMomentPopUp
+ .getWaitAMomentTextElement(), 100);
+ Common.waitTillElementIsNotPresent((AndroidElement) fileListView
+ .getFileElementLayout()
+ .findElement(By.id(FileListView.getSharedElementIndicator())
+ ),100);
+ }catch(NoSuchElementException e){
+
+ }
+ }
+
+
+ public static FileListView uploadFile(String elementName,
+ FileListView fileListView) throws InterruptedException{
+ fileListView.clickOnUploadButton();
+ UploadFilesView uploadFilesView = fileListView
+ .clickOnFilesElementUploadFile();
+ uploadFilesView.clickOnFileName(elementName);
+ FileListView fileListViewAfterUploadFile = uploadFilesView
+ .clickOnUploadButton();
+ //TO DO. detect when the file is successfully uploaded
+ Thread.sleep(15000);
+ return fileListViewAfterUploadFile;
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.test.ui.groups;
+
+public interface FailingTestCategory extends IgnoreTestCategory {}
--- /dev/null
+package com.owncloud.android.test.ui.groups;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Categories.CategoryFilter;
+import org.junit.experimental.categories.Categories.ExcludeCategory;
+import org.junit.experimental.categories.Categories.IncludeCategory;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.Description;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * This class is based on org.junit.experimental.categories.Categories from JUnit 4.10.
+ *
+ * All anotations and inner classes from the original class Categories are removed,
+ * since they will be re-used.
+ * Unfortunately sub-classing Categories did not work.
+ */
+public class FlexibleCategories extends Suite {
+
+ /**
+ * Specifies the package which should be scanned for test classes (e.g. @TestScanPackage("my.package")).
+ * This annotation is required.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface TestScanPackage {
+ public String value();
+ }
+
+ /**
+ * Specifies the prefix of matching class names (e.g. @TestClassPrefix("Test")).
+ * This annotation is optional (default: "").
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface TestClassPrefix {
+ public String value();
+ }
+
+ /**
+ * Specifies the suffix of matching class names (e.g. @TestClassSuffix("Test")).
+ * This annotation is optional (default: "Test").
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface TestClassSuffix {
+ public String value();
+ }
+
+ /**
+ * Specifies an annotation for methods which must be present in a matching class (e.g. @TestMethodAnnotationFilter(Test.class)).
+ * This annotation is optional (default: org.junit.Test.class).
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface TestMethodAnnotation {
+ public Class<? extends Annotation> value();
+ }
+
+ public FlexibleCategories(Class<?> clazz, RunnerBuilder builder)
+ throws InitializationError {
+ this(builder, clazz, PatternClasspathClassesFinder.getSuiteClasses(
+ getTestScanPackage(clazz), getTestClassPrefix(clazz), getTestClassSuffix(clazz),
+ getTestMethodAnnotation(clazz)));
+ try {
+ filter(new CategoryFilter(getIncludedCategory(clazz),
+ getExcludedCategory(clazz)));
+ } catch (NoTestsRemainException e) {
+ // Ignore all classes with no matching tests.
+ }
+ assertNoCategorizedDescendentsOfUncategorizeableParents(getDescription());
+ }
+
+ public FlexibleCategories(RunnerBuilder builder, Class<?> clazz,
+ Class<?>[] suiteClasses) throws InitializationError {
+ super(builder, clazz, suiteClasses);
+ }
+
+ private static String getTestScanPackage(Class<?> clazz) throws InitializationError {
+ TestScanPackage annotation = clazz.getAnnotation(TestScanPackage.class);
+ if (annotation == null) {
+ throw new InitializationError("No package given to scan for tests!\nUse the annotation @TestScanPackage(\"my.package\") on the test suite " + clazz + ".");
+ }
+ return annotation.value();
+ }
+
+ private static String getTestClassPrefix(Class<?> clazz) {
+ TestClassPrefix annotation = clazz.getAnnotation(TestClassPrefix.class);
+ return annotation == null ? "" : annotation.value();
+ }
+
+ private static String getTestClassSuffix(Class<?> clazz) {
+ TestClassSuffix annotation = clazz.getAnnotation(TestClassSuffix.class);
+ return annotation == null ? "Test" : annotation.value();
+ }
+
+ private static Class<? extends Annotation> getTestMethodAnnotation(Class<?> clazz) {
+ TestMethodAnnotation annotation = clazz.getAnnotation(TestMethodAnnotation.class);
+ return annotation == null ? Test.class : annotation.value();
+ }
+
+ private Class<?> getIncludedCategory(Class<?> clazz) {
+ IncludeCategory annotation= clazz.getAnnotation(IncludeCategory.class);
+ return annotation == null ? null : annotation.value();
+ }
+
+ private Class<?> getExcludedCategory(Class<?> clazz) {
+ ExcludeCategory annotation= clazz.getAnnotation(ExcludeCategory.class);
+ return annotation == null ? null : annotation.value();
+ }
+
+ private void assertNoCategorizedDescendentsOfUncategorizeableParents(Description description) throws InitializationError {
+ if (!canHaveCategorizedChildren(description))
+ assertNoDescendantsHaveCategoryAnnotations(description);
+ for (Description each : description.getChildren())
+ assertNoCategorizedDescendentsOfUncategorizeableParents(each);
+ }
+
+ private void assertNoDescendantsHaveCategoryAnnotations(Description description) throws InitializationError {
+ for (Description each : description.getChildren()) {
+ if (each.getAnnotation(Category.class) != null)
+ throw new InitializationError("Category annotations on Parameterized classes are not supported on individual methods.");
+ assertNoDescendantsHaveCategoryAnnotations(each);
+ }
+ }
+
+ // If children have names like [0], our current magical category code can't determine their
+ // parentage.
+ private static boolean canHaveCategorizedChildren(Description description) {
+ for (Description each : description.getChildren())
+ if (each.getTestClass() == null)
+ return false;
+ return true;
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.groups;
+
+public interface IgnoreTestCategory {}
+
--- /dev/null
+package com.owncloud.android.test.ui.groups;
+
+public interface InProgressCategory extends IgnoreTestCategory{
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.groups;
+
+public interface NoIgnoreTestCategory {
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.groups;
+
+public interface OtherTestCategory extends IgnoreTestCategory {}
--- /dev/null
+package com.owncloud.android.test.ui.groups;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ *
+ * Modified version of ClasspathClassesFinder from:
+ * http://linsolas.free.fr/wordpress/index.php/2011/02/how-to-categorize-junit-tests-with-maven/
+ *
+ * The difference is, that it does not search for annotated classes but for classes with a certain
+ * class name prefix and suffix.
+ */
+public final class PatternClasspathClassesFinder {
+
+ /**
+ * Get the list of classes of a given package name, and that are annotated
+ * by a given annotation.
+ *
+ * @param packageName
+ * The package name of the classes.
+ * @param classPrefix
+ * The prefix of the class name.
+ * @param classSuffix
+ * The suffix of the class name.
+ * @param methodAnnotation
+ * Only return classes containing methods annotated with methodAnnotation.
+ * @return The List of classes that matches the requirements.
+ */
+ public static Class<?>[] getSuiteClasses(String packageName,
+ String classPrefix, String classSuffix,
+ Class<? extends Annotation> methodAnnotation) {
+ try {
+ return getClasses(packageName, classPrefix, classSuffix, methodAnnotation);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * Get the list of classes of a given package name, and that are annotated
+ * by a given annotation.
+ *
+ * @param packageName
+ * The package name of the classes.
+ * @param classPrefix
+ * The prefix of the class name.
+ * @param classSuffix
+ * The suffix of the class name.
+ * @param methodAnnotation
+ * Only return classes containing methods annotated with methodAnnotation.
+ * @return The List of classes that matches the requirements.
+ * @throws ClassNotFoundException
+ * If something goes wrong...
+ * @throws IOException
+ * If something goes wrong...
+ */
+ private static Class<?>[] getClasses(String packageName,
+ String classPrefix, String classSuffix,
+ Class<? extends Annotation> methodAnnotation)
+ throws ClassNotFoundException, IOException {
+ ClassLoader classLoader = Thread.currentThread()
+ .getContextClassLoader();
+ String path = packageName.replace('.', '/');
+ // Get classpath
+ Enumeration<URL> resources = classLoader.getResources(path);
+ List<File> dirs = new ArrayList<File>();
+ while (resources.hasMoreElements()) {
+ URL resource = resources.nextElement();
+ dirs.add(new File(resource.getFile()));
+ }
+ // For each classpath, get the classes.
+ ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
+ for (File directory : dirs) {
+ classes.addAll(findClasses(directory, packageName, classPrefix, classSuffix, methodAnnotation));
+ }
+ return classes.toArray(new Class[classes.size()]);
+ }
+
+ /**
+ * Find classes, in a given directory (recursively), for a given package
+ * name, that are annotated by a given annotation.
+ *
+ * @param directory
+ * The directory where to look for.
+ * @param packageName
+ * The package name of the classes.
+ * @param classPrefix
+ * The prefix of the class name.
+ * @param classSuffix
+ * The suffix of the class name.
+ * @param methodAnnotation
+ * Only return classes containing methods annotated with methodAnnotation.
+ * @return The List of classes that matches the requirements.
+ * @throws ClassNotFoundException
+ * If something goes wrong...
+ */
+ private static List<Class<?>> findClasses(File directory,
+ String packageName, String classPrefix, String classSuffix,
+ Class<? extends Annotation> methodAnnotation)
+ throws ClassNotFoundException {
+ List<Class<?>> classes = new ArrayList<Class<?>>();
+ if (!directory.exists()) {
+ return classes;
+ }
+ File[] files = directory.listFiles();
+ for (File file : files) {
+ if (file.isDirectory()) {
+ classes.addAll(findClasses(file,
+ packageName + "." + file.getName(), classPrefix, classSuffix, methodAnnotation));
+ } else if (file.getName().startsWith(classPrefix) && file.getName().endsWith(classSuffix + ".class")) {
+ // We remove the .class at the end of the filename to get the
+ // class name...
+ Class<?> clazz = Class.forName(packageName
+ + '.'
+ + file.getName().substring(0,
+ file.getName().length() - 6));
+
+ // Check, if class contains test methods (prevent "No runnable methods" exception):
+ boolean classHasTest = false;
+ for (Method method : clazz.getMethods()) {
+ if (method.getAnnotation(methodAnnotation) != null) {
+ classHasTest = true;
+ break;
+ }
+ }
+ if (classHasTest) {
+ classes.add(clazz);
+ }
+ }
+ }
+ return classes;
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.groups;
+
+public interface SmokeTestCategory {
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.groups;
+
+public interface UnfinishedTestCategory extends IgnoreTestCategory{
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.PageFactory;
+
+public class CertificatePopUp {
+ final AndroidDriver driver;
+
+ @AndroidFindBy(name = "OK")
+ private AndroidElement okButton;
+
+ public CertificatePopUp (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public void clickOnOkButton () {
+ okButton.click();
+ }
+
+ public AndroidElement getOkButtonElement () {
+ return okButton;
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.PageFactory;
+
+public class ElementMenuOptions {
+
+ final AndroidDriver driver;
+
+ @AndroidFindBy(name = "Share link")
+ private AndroidElement shareLinkElement;
+
+ @AndroidFindBy(name = "Unshare link")
+ private AndroidElement unshareLinkElement;
+
+ @AndroidFindBy(name = "Details")
+ private AndroidElement detailsFileElement;
+
+ @AndroidFindBy(name = "Rename")
+ private AndroidElement renameFileElement;
+
+ @AndroidFindBy(name = "Remove")
+ private AndroidElement removeFileElement;
+
+ @AndroidFindBy(name = "Move")
+ private AndroidElement moveElement;
+
+ public ElementMenuOptions (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public FileDetailsView clickOnDetails () {
+ detailsFileElement.click();
+ FileDetailsView fileDetailsView = new FileDetailsView(driver);
+ return fileDetailsView;
+ }
+
+ public RemoveConfirmationView clickOnRemove () {
+ removeFileElement.click();
+ RemoveConfirmationView removeConfirmationView =
+ new RemoveConfirmationView(driver);
+ return removeConfirmationView;
+ }
+
+
+ public MoveView clickOnMove () {
+ moveElement.click();
+ MoveView moveView = new MoveView(driver);
+ return moveView;
+ }
+
+ public NewFolderPopUp clickOnRename () {
+ renameFileElement.click();
+ NewFolderPopUp newFolderPopUp = new NewFolderPopUp(driver);
+ return newFolderPopUp;
+ }
+
+ public ShareView clickOnShareLinkElement () {
+ shareLinkElement.click();
+ ShareView shareView = new ShareView(driver);
+ return shareView;
+ }
+
+ public WaitAMomentPopUp clickOnUnshareLinkElement () {
+ unshareLinkElement.click();
+ WaitAMomentPopUp waitAMomentPopUp = new WaitAMomentPopUp(driver);
+ return waitAMomentPopUp;
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.PageFactory;
+
+public class FileDetailsView {
+ final AndroidDriver driver;
+
+ @CacheLookup
+ @AndroidFindBy(name = "Keep file up to date")
+ private AndroidElement keepFileUpToDateCheckbox;
+
+ @AndroidFindBy(id = "com.owncloud.android:id/fdProgressBar")
+ private AndroidElement progressBar;
+
+ public FileDetailsView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public void checkKeepFileUpToDateCheckbox () {
+ if(keepFileUpToDateCheckbox.getAttribute("checked").equals("false")){
+ keepFileUpToDateCheckbox.click();
+ }
+ }
+
+ public void unCheckKeepFileUpToDateCheckbox () {
+ if(keepFileUpToDateCheckbox.getAttribute("checked").equals("true")){
+ keepFileUpToDateCheckbox.click();
+ }
+ }
+
+ public AndroidElement getProgressBar (){
+ return progressBar;
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import java.util.List;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.android.AndroidKeyCode;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.PageFactory;
+import org.openqa.selenium.Point;
+
+import com.owncloud.android.test.ui.actions.Actions;
+
+public class FileListView {
+ final AndroidDriver driver;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".description(\"More options\")")
+ private AndroidElement menuButton;
+
+ @CacheLookup
+ @AndroidFindBy(id = "com.owncloud.android:id/list_root")
+ private AndroidElement filesLayout;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".resourceId(\"android:id/action_bar_title\")")
+ private AndroidElement titleText;
+
+ @AndroidFindBy(id = "android:id/progress_circular")
+ private AndroidElement progressCircular;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".description(\"New folder\")")
+ private AndroidElement newFolderButton;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector().description(\"Upload\")")
+ private AndroidElement uploadButton;
+
+ private AndroidElement waitAMomentText;
+
+ @AndroidFindBy(id = "com.owncloud.android:id/ListItemLayout")
+ private List<AndroidElement> listItemLayout;
+
+ @AndroidFindBy(id = "com.owncloud.android:id/list_root")
+ private AndroidElement listRootLayout;
+
+ @AndroidFindBy(name = "Files")
+ private AndroidElement filesElementUploadFile;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".description(\"List Layout\")")
+ private AndroidElement listLayout;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector().className(\"android.widget.FrameLayout\").index(0)")
+ private AndroidElement deviceScreen;
+
+ private AndroidElement fileElement;
+
+ private AndroidElement fileElementLayout;
+
+ private static String localFileIndicator =
+ "com.owncloud.android:id/localFileIndicator";
+ private static String favoriteFileIndicator =
+ "com.owncloud.android:id/favoriteIcon";
+ private static String sharedElementIndicator =
+ "com.owncloud.android:id/sharedIcon";
+
+
+ public FileListView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public MenuList clickOnMenuButton () {
+ //if the menu option is not in the actionBar, it is opening again
+ try {
+ menuButton.click();
+ } catch (NoSuchElementException e){
+ driver.sendKeyEvent(AndroidKeyCode.MENU);
+ }
+ MenuList menuList = new MenuList (driver);
+ return menuList;
+ }
+
+ public SettingsView getSettingsView () {
+ SettingsView settingsView = new SettingsView(driver);
+ return settingsView;
+ }
+
+ public NewFolderPopUp clickOnNewFolderButton () {
+ newFolderButton.click();
+ NewFolderPopUp newFolderPopUp = new NewFolderPopUp(driver);
+ return newFolderPopUp;
+ }
+
+ public void clickOnUploadButton () {
+ uploadButton.click();
+ }
+
+ public UploadFilesView clickOnFilesElementUploadFile () {
+ filesElementUploadFile.click();
+ UploadFilesView uploadFilesView = new UploadFilesView(driver);
+ return uploadFilesView;
+ }
+
+ public AndroidElement getTitleTextElement () {
+ return titleText;
+ }
+
+ public AndroidElement getUploadButton () {
+ return uploadButton;
+ }
+
+ public AndroidElement getWaitAMomentTextElement () {
+ return waitAMomentText;
+ }
+
+ public AndroidElement getListRootElement () {
+ return listRootLayout;
+ }
+
+ public List<AndroidElement> getListItemLayout () {
+ return listItemLayout;
+ }
+
+ public AndroidElement getFileElement () {
+ return fileElement;
+ }
+
+ public ElementMenuOptions longPressOnElement (String elementName) {
+ scrollTillFindElement(elementName).tap(1, 1000);
+ //fileElement.tap(1, 1000);
+ ElementMenuOptions menuOptions = new ElementMenuOptions(driver);
+ return menuOptions;
+ }
+
+ public AndroidElement scrollTillFindElement (String elementName) {
+ fileElement = Actions
+ .scrollTillFindElement (elementName,filesLayout,driver);
+ try {
+ fileElementLayout = (AndroidElement) driver
+ .findElementByAndroidUIAutomator("new UiSelector()"
+ + ".description(\"LinearLayout-"+ elementName +"\")");
+ } catch (NoSuchElementException e) {
+ fileElementLayout = null;
+ }
+ return fileElement;
+ }
+
+ public AndroidElement getFileElementLayout () {
+ return fileElementLayout;
+ }
+
+ public AndroidElement getProgressCircular () {
+ return progressCircular;
+ }
+
+ public static String getLocalFileIndicator() {
+ return localFileIndicator;
+ }
+
+ public static String getFavoriteFileIndicator() {
+ return favoriteFileIndicator;
+ }
+
+ public static String getSharedElementIndicator() {
+ return sharedElementIndicator;
+ }
+ public void pulldownToRefresh () throws InterruptedException {
+ Point listLocation = listLayout.getLocation();
+ driver.swipe(listLocation.getX(),listLocation.getY(),
+ listLocation.getX(),listLocation.getY()+1000, 5000);
+ }
+
+
+
+ public void pulldownToSeeNotification () throws InterruptedException {
+ Point listLocation = deviceScreen.getLocation();
+ driver.swipe(listLocation.getX(),listLocation.getY(),
+ listLocation.getX(),listLocation.getY()+1000, 5000);
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.support.PageFactory;
+
+public class GmailEmailListView {
+
+ final AndroidDriver driver;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector().description(\""
+ + "me about UploadFile, on May 11, conversation read\")")
+ private AndroidElement emailAmericanFormatDate;
+ @AndroidFindBy(uiAutomator = "new UiSelector().description(\""
+ + "me about UploadFile, on 11 May, conversation read\")")
+ private AndroidElement emailEuropeanFormatDate;
+
+
+ public GmailEmailListView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public GmailEmailView clickOnEmail (){
+ try{
+ emailAmericanFormatDate.click();
+ }catch (NoSuchElementException e) {
+ emailEuropeanFormatDate.click();
+ }
+ GmailEmailView gmailEmailView = new GmailEmailView(driver);
+ return gmailEmailView;
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.PageFactory;
+
+import com.owncloud.android.test.ui.testSuites.Config;
+
+public class GmailEmailView {
+ final AndroidDriver driver;
+
+ @CacheLookup
+ @AndroidFindBy(name = Config.fileToTestSendByEmailName)
+ private AndroidElement fileButton;
+
+ public GmailEmailView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public ImageView clickOnfileButton (){
+ fileButton.click();
+ ImageView imageView = new ImageView(driver);
+ return imageView;
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.PageFactory;
+
+public class GmailSendMailView {
+ final AndroidDriver driver;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector().description(\"To\")")
+ private AndroidElement toTextField;
+
+ @CacheLookup
+ @AndroidFindBy(name = "Subject")
+ private AndroidElement subjectTextField;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector().description(\"Send\")")
+ private AndroidElement sendButton;
+
+ public GmailSendMailView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public void typeToEmailAdress (String email) {
+ toTextField.sendKeys(email + "\n");
+ }
+
+ public void clickOnSendButton () {
+ sendButton.click();
+ }
+
+ public void typeSubject (String subject) {
+ subjectTextField.clear();
+ subjectTextField.sendKeys(subject);
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.PageFactory;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.testSuites.Common;
+
+
+public class ImageView {
+ final AndroidDriver driver;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".description(\"More options\")")
+ private AndroidElement optionsButton;
+
+ @AndroidFindBy(name = "Share")
+ private AndroidElement shareButton;
+
+ @AndroidFindBy(name = "ownCloud")
+ private AndroidElement ownCloudButton;
+
+ @AndroidFindBy(name = "Share with ownCloud")
+ private AndroidElement shareWithOwnCloudButton;
+
+ @AndroidFindBy(name = "Just once")
+ private AndroidElement justOnceButton;
+
+ @AndroidFindBy(id = "android:id/resolver_list")
+ private AndroidElement sharingAppsLayout;
+
+ public ImageView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public void clickOnOptionsButton(){
+ optionsButton.click();
+ }
+
+ public void clickOnShareButton(){
+ shareButton.click();
+ }
+
+ public void clickOnOwnCloudButton(){
+ if(Common.isElementPresent(ownCloudButton)){
+ Actions.scrollTillFindElement("ownCloud",sharingAppsLayout,driver);
+ ownCloudButton.click();
+ }else if(Common.isElementPresent(shareWithOwnCloudButton)){}
+ }
+
+ public void clickOnJustOnceButton(){
+ justOnceButton.click();
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.PageFactory;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+public class LoginForm {
+ final AndroidDriver driver;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".description(\"Server address\")")
+ private AndroidElement hostUrlInput;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector().description(\"Username\")")
+ private AndroidElement userNameInput;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector().description(\"Password\")")
+ private AndroidElement passwordInput;
+
+ @CacheLookup
+ @AndroidFindBy(uiAutomator = "new UiSelector().description(\"Connect\")")
+ private AndroidElement connectButton;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".description(\"Testing connection\")")
+ private AndroidElement serverStatusText;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".description(\"Wrong username or password\")")
+ private AndroidElement authStatusText;
+
+ public LoginForm (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public CertificatePopUp typeHostUrl (String hostUrl) {
+ hostUrlInput.clear();
+ hostUrlInput.sendKeys(hostUrl + "\n");
+ CertificatePopUp certificatePopUp = new CertificatePopUp(driver);
+ return certificatePopUp;
+ }
+
+ public void clickOnUserName () {
+ userNameInput.click();
+ }
+
+ public void typeUserName (String userName) {
+ userNameInput.clear();
+ //using the \n , it not need to hide the keyboard
+ //which sometimes gives problems
+ userNameInput.sendKeys(userName + "\n");
+ //driver.hideKeyboard();
+ }
+
+ public void typePassword (String password) {
+ passwordInput.clear();
+ passwordInput.sendKeys(password + "\n");
+ //driver.hideKeyboard();
+ }
+
+ public FileListView clickOnConnectButton () {
+ connectButton.click();
+ FileListView fileListView = new FileListView(driver);
+ return fileListView;
+ }
+
+ public AndroidElement gethostUrlInput () {
+ return hostUrlInput;
+ }
+
+ public AndroidElement getUserNameInput () {
+ return userNameInput;
+ }
+
+ public AndroidElement getPasswordInput () {
+ return passwordInput;
+ }
+
+
+ public AndroidElement getServerStatusTextElement () {
+ return serverStatusText;
+ }
+
+ public AndroidElement getAuthStatusText () {
+ return authStatusText;
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import org.openqa.selenium.support.PageFactory;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+public class MenuList {
+
+ final AndroidDriver driver;
+
+ @AndroidFindBy(name = "Settings")
+ private AndroidElement settingsButton;
+
+ public MenuList (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public SettingsView clickOnSettingsButton () {
+ settingsButton.click();
+ SettingsView settingsView = new SettingsView(driver);
+ return settingsView;
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.PageFactory;
+
+import com.owncloud.android.test.ui.actions.Actions;
+
+public class MoveView {
+ final AndroidDriver driver;
+
+ @CacheLookup
+ @AndroidFindBy(id = "com.owncloud.android:id/list_root")
+ private AndroidElement filesLayout;
+
+ @AndroidFindBy(name = "Choose")
+ private AndroidElement chooseButton;
+
+ public MoveView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public WaitAMomentPopUp clickOnChoose () {
+ chooseButton.click();
+ WaitAMomentPopUp waitAMomentPopUp = new WaitAMomentPopUp(driver);
+ return waitAMomentPopUp;
+ }
+
+ public AndroidElement scrollTillFindElement (String elementName) {
+ return Actions.scrollTillFindElement (elementName,filesLayout,driver);
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import org.openqa.selenium.support.PageFactory;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+public class NewFolderPopUp {
+
+ final AndroidDriver driver;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".resourceId(\"android:id/button1\")")
+ private AndroidElement newFolderOkButton;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".resourceId(\"com.owncloud.android:id/user_input\")")
+ private AndroidElement newFolderNameField;
+
+ public NewFolderPopUp (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public void typeNewFolderName (String newFolderName) {
+ newFolderNameField.clear();
+ newFolderNameField.sendKeys(newFolderName + "\n");
+ //driver.hideKeyboard();
+ }
+
+ public WaitAMomentPopUp clickOnNewFolderOkButton () {
+ newFolderOkButton.click();
+ WaitAMomentPopUp waitAMomentPopUp = new WaitAMomentPopUp(driver);
+ return waitAMomentPopUp;
+ }
+}
--- /dev/null
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.PageFactory;
+
+public class NotificationView {
+final AndroidDriver driver;
+
+ @AndroidFindBy(name = "Upload succeeded")
+ private static AndroidElement uploadSucceededNotification;
+
+ @AndroidFindBy(name = "Uploading ?")
+ private static AndroidElement uploadingNotification;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector().description(\"Clear all notifications.\")")
+ private AndroidElement clearAllNotificationButton;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector().className(\"android.widget.FrameLayout\").index(0)")
+ private AndroidElement notificationArea;
+
+
+ public NotificationView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+
+ public AndroidElement getUploadSucceededNotification() {
+ return uploadSucceededNotification;
+ }
+
+ public AndroidElement getUploadingNotification() {
+ return uploadingNotification;
+ }
+
+ public AndroidElement getClearAllNotificationButton() {
+ return clearAllNotificationButton;
+ }
+
+ public void tapOnClearAllNotification () {
+ clearAllNotificationButton.tap(1, 1000);
+ }
+
+ public void tapOnBottomNotificationArea(){
+ //TODO. it is not working
+ notificationArea.getSize();
+ notificationArea.tap(1, 1000);
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import org.openqa.selenium.support.PageFactory;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+public class PassCodeRequestView {
+final AndroidDriver driver;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".className(\"android.widget.EditText\").index(0)")
+ private AndroidElement codeElement1;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".className(\"android.widget.EditText\").index(1)")
+ private AndroidElement codeElement2;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".className(\"android.widget.EditText\").index(2)")
+ private AndroidElement codeElement3;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".className(\"android.widget.EditText\").index(3)")
+ private AndroidElement codeElement4;
+
+ public PassCodeRequestView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public void enterPasscode(String codeNumber1, String codeNumber2,
+ String codeNumber3, String codeNumber4){
+ codeElement1
+ .sendKeys(codeNumber1 + codeNumber1 + codeNumber1 + codeNumber1);
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.PageFactory;
+
+public class PassCodeView {
+ final AndroidDriver driver;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".className(\"android.widget.EditText\").index(0)")
+ private AndroidElement codeElement1;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".className(\"android.widget.EditText\").index(1)")
+ private AndroidElement codeElement2;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".className(\"android.widget.EditText\").index(2)")
+ private AndroidElement codeElement3;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".className(\"android.widget.EditText\").index(3)")
+ private AndroidElement codeElement4;
+
+ @AndroidFindBy(name = "Cancel")
+ private AndroidElement cancelButton;
+
+ public PassCodeView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public PassCodeView enterPasscode(String codeNumber1, String codeNumber2,
+ String codeNumber3, String codeNumber4){
+ codeElement1
+ .sendKeys(codeNumber1 + codeNumber1 + codeNumber1 + codeNumber1);
+ return this;
+ }
+ public SettingsView reenterPasscode(String codeNumber1,
+ String codeNumber2, String codeNumber3, String codeNumber4){
+ codeElement1
+ .sendKeys(codeNumber1 + codeNumber1 + codeNumber1 + codeNumber1);
+ SettingsView settingsView = new SettingsView(driver);
+ return settingsView;
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.PageFactory;
+
+public class RemoveConfirmationView {
+ final AndroidDriver driver;
+
+ @AndroidFindBy(name = "Remote and local")
+ private AndroidElement remoteAndLocalButton;
+
+ public RemoveConfirmationView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public WaitAMomentPopUp clickOnRemoteAndLocalButton () {
+ remoteAndLocalButton.click();
+ WaitAMomentPopUp waitAMomentPopUp = new WaitAMomentPopUp(driver);
+ return waitAMomentPopUp;
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.PageFactory;
+
+import com.owncloud.android.test.ui.testSuites.Config;
+
+public class SettingsView {
+ final AndroidDriver driver;
+
+ @CacheLookup
+ @AndroidFindBy(name = Config.userAccount)
+ private AndroidElement accountElement;
+
+ @CacheLookup
+ @AndroidFindBy(name = Config.userAccount2)
+ private AndroidElement accountElement2;
+
+ @AndroidFindBy(name = "Delete account")
+ private AndroidElement deleteAccountElement;
+
+ @AndroidFindBy(name = "Change password")
+ private AndroidElement changePasswordElement;
+
+ @AndroidFindBy(name = "Add account")
+ private AndroidElement addAccountElement;
+
+ @AndroidFindBy(uiAutomator = "new UiSelector()"
+ + ".className(\"android.widget.CheckBox\").index(0)")
+ private AndroidElement passcodeCheckbox;
+
+ public SettingsView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public void tapOnAccountElement (int accountPosition, int fingers, int milliSeconds) {
+ if(accountPosition==1)
+ accountElement.tap(fingers, milliSeconds);
+ else
+ accountElement2.tap(fingers, milliSeconds);
+ }
+
+ public void tapOnAddAccount (int fingers, int milliSeconds) {
+ addAccountElement.tap(fingers, milliSeconds);
+ }
+
+ public LoginForm clickOnDeleteAccountElement () {
+ deleteAccountElement.click();
+ LoginForm loginForm = new LoginForm(driver);
+ return loginForm;
+ }
+
+ public LoginForm clickOnChangePasswordElement () {
+ changePasswordElement.click();
+ LoginForm loginForm = new LoginForm(driver);
+ return loginForm;
+ }
+
+ public PassCodeView EnablePassCode(){
+ if(!passcodeCheckbox.isSelected()){
+ passcodeCheckbox.click();
+ }
+ PassCodeView passcodeview = new PassCodeView(driver);
+ return passcodeview;
+ }
+
+ public PassCodeView DisablePassCode(){
+ if(passcodeCheckbox.isSelected()){
+ passcodeCheckbox.click();
+ }
+ PassCodeView passcodeview = new PassCodeView(driver);
+ return passcodeview;
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.PageFactory;
+
+public class ShareView {
+ final AndroidDriver driver;
+
+ @CacheLookup
+ @FindBy(id = "android:id/select_dialog_listview")
+ private AndroidElement listViewLayout;
+
+ public ShareView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public AndroidElement getListViewLayout () {
+ return listViewLayout;
+ }
+
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.PageFactory;
+
+import com.owncloud.android.test.ui.actions.Actions;
+
+public class UploadFilesView{
+ final AndroidDriver driver;
+
+ @CacheLookup
+ @AndroidFindBy(id = "com.owncloud.android:id/list_root")
+ private AndroidElement filesLayout;
+
+ @CacheLookup
+ @AndroidFindBy(id = "com.owncloud.android:id/upload_files_btn_upload")
+ private AndroidElement uploadButton;
+
+ private AndroidElement fileElement;
+
+ public UploadFilesView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public FileListView clickOnUploadButton () {
+ uploadButton.click();
+ FileListView fileListView = new FileListView (driver);
+ return fileListView;
+ }
+
+ //change to scrollTillFindElement
+ public void scrollTillFindFile (String fileName) {
+ fileElement = Actions
+ .scrollTillFindElement(fileName,filesLayout,driver);
+ }
+
+ public void clickOnFileName (String fileName) {
+ scrollTillFindFile(fileName);
+ fileElement.click();
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+import org.openqa.selenium.support.CacheLookup;
+import org.openqa.selenium.support.PageFactory;
+
+public class UploadView {
+ final AndroidDriver driver;
+
+ @CacheLookup
+ @AndroidFindBy(name = "Upload")
+ private AndroidElement uploadButton;
+
+ public UploadView (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public void clickOUploadButton () {
+ uploadButton.click();
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.models;
+
+import org.openqa.selenium.support.PageFactory;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+import io.appium.java_client.pagefactory.AndroidFindBy;
+import io.appium.java_client.pagefactory.AppiumFieldDecorator;
+
+public class WaitAMomentPopUp {
+ final AndroidDriver driver;
+
+ @AndroidFindBy(name = "Wait a moment")
+ private AndroidElement waitAMomentText;
+
+ public WaitAMomentPopUp (AndroidDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(new AppiumFieldDecorator(driver), this);
+ }
+
+ public AndroidElement getWaitAMomentTextElement () {
+ return waitAMomentText;
+ }
+}
--- /dev/null
+Config.java
\ No newline at end of file
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.io.FileUtils;
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.OutputType;
+import org.openqa.selenium.TimeoutException;
+import org.openqa.selenium.remote.DesiredCapabilities;
+import org.openqa.selenium.remote.RemoteWebDriver;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+
+public class Common{
+ AndroidDriver driver;
+ static int waitingTime = 30;
+
+ public WebDriverWait wait;
+
+ protected AndroidDriver setUpCommonDriver () throws Exception {
+ File rootPath = new File(System.getProperty("user.dir"));
+ File appDir = new File(rootPath,"src/test/resources");
+ File app = new File(appDir,"ownCloud.apk");
+ DesiredCapabilities capabilities = new DesiredCapabilities();
+ capabilities.setCapability("platformName", "Android");
+ capabilities.setCapability("deviceName", "test");
+ capabilities.setCapability("app", app.getAbsolutePath());
+ capabilities.setCapability("appPackage", "com.owncloud.android");
+ capabilities.setCapability("appActivity",
+ ".ui.activity.FileDisplayActivity");
+ capabilities.setCapability("appWaitActivity",
+ ".authentication.AuthenticatorActivity");
+ driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"),
+ capabilities);
+ driver.manage().timeouts().implicitlyWait(waitingTime,
+ TimeUnit.SECONDS);
+ wait = new WebDriverWait(driver, waitingTime, 50);
+ return driver;
+
+ }
+
+ protected boolean waitForTextPresent(String text, AndroidElement element)
+ throws InterruptedException{
+ for (int second = 0;;second++){
+ if (second >= waitingTime)
+ return false;
+ try{
+ if (text.equals(element.getText()))
+ break;
+ } catch (Exception e){
+
+ }
+ Thread.sleep(1000);
+ }
+ return true;
+ }
+
+ protected boolean isElementPresent(AndroidElement element, By by) {
+ try {
+ element.findElement(by);
+ return true;
+ } catch (NoSuchElementException e) {
+ return false;
+ }
+ }
+
+ public static boolean isElementPresent(AndroidElement element) {
+ try{
+ element.isDisplayed();
+ } catch (NoSuchElementException e){
+ return false;
+ }
+ return true;
+ }
+
+ //pollingTime in milliseconds
+ public static void waitTillElementIsNotPresent (AndroidElement element,
+ int pollingTime) throws Exception {
+ for (int time = 0;time <= waitingTime * 1000;time += pollingTime){
+ try{
+ element.isDisplayed();
+ } catch (NoSuchElementException e){
+ return;
+ }
+ Thread.sleep(pollingTime);
+ }
+ throw new TimeoutException();
+ }
+
+ public static void waitTillElementIsNotPresentWithoutTimeout (
+ AndroidElement element,int pollingTime)
+ throws InterruptedException {
+ for (int time = 0;time <= waitingTime * 1000;time += pollingTime){
+ try{
+ element.isDisplayed();
+ } catch (NoSuchElementException e){
+ return;
+ }
+ Thread.sleep(pollingTime);
+ }
+ }
+
+ public static void waitTillElementIsPresent (
+ AndroidElement element,int pollingTime)
+ throws InterruptedException {
+ for (int time = 0;time <= waitingTime * 1000;time += pollingTime){
+ try{
+ if(element.isDisplayed()){
+ return;
+ }
+ } catch (NoSuchElementException e){
+
+ }
+ Thread.sleep(pollingTime);
+ }
+ }
+
+ protected void takeScreenShotOnFailed (String testName)
+ throws IOException {
+ File file = ((RemoteWebDriver) driver)
+ .getScreenshotAs(OutputType.FILE);
+ SimpleDateFormat dt1 = new SimpleDateFormat("yyyy-MM-dd");
+ Date today = Calendar.getInstance().getTime();
+ String screenShotName = "ScreenShots/" + dt1.format(today) + "/"
+ + testName + ".png";
+ FileUtils.copyFile(file, new File(screenShotName));
+ }
+
+ protected void assertIsInFileListView() throws InterruptedException {
+ //waitForTextPresent("Wrong username or password",
+ // changePasswordForm.getAuthStatusText());
+ Thread.sleep(2000);
+ assertTrue(waitForTextPresent("ownCloud", (AndroidElement) driver
+ .findElementByAndroidUIAutomator("new UiSelector()"
+ + ".resourceId(\"android:id/action_bar_title\")")));
+ assertTrue(isElementPresent((AndroidElement) driver
+ .findElementByAndroidUIAutomator("new UiSelector()"
+ + ".description(\"Upload\")")));
+ }
+
+ protected void assertIsNotInFileListView() throws InterruptedException {
+ AndroidElement fileElement;
+ assertTrue(waitForTextPresent("ownCloud", (AndroidElement) driver
+ .findElementByAndroidUIAutomator("new UiSelector()"
+ + ".resourceId(\"android:id/action_bar_title\")")));
+ try {
+ fileElement = (AndroidElement) driver
+ .findElementByAndroidUIAutomator("new UiSelector()"
+ + ".description(\"Upload\")");
+ } catch (NoSuchElementException e) {
+ fileElement = null;
+ }
+ assertNull(fileElement);
+ }
+
+ protected void assertIsPasscodeRequestView() throws InterruptedException {
+ assertTrue(waitForTextPresent("ownCloud", (AndroidElement) driver
+ .findElementByAndroidUIAutomator("new UiSelector()"
+ + ".resourceId(\"android:id/action_bar_title\")")));
+ assertTrue(((AndroidElement) driver.findElementByAndroidUIAutomator(
+ "new UiSelector().text(\"Please, insert your pass code\")"))
+ .isDisplayed());
+
+ }
+
+ protected void assertIsInSettingsView() throws InterruptedException {
+ assertTrue(waitForTextPresent("Settings", (AndroidElement) driver
+ .findElementByAndroidUIAutomator("new UiSelector()"
+ + ".resourceId(\"android:id/action_bar_title\")")));
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+public final class Config {
+
+ //without http or https
+ public static final String URL = "owncloudServerVar";
+ public static boolean isTrusted = true;
+
+ //without http or https
+ public static final String URL2 = "owncloudServer2Var";
+ public static boolean isTrusted2 = true;
+
+ public static final String user = "owncloudUserVar";
+ public static final String password = "owncloudPasswordVar";
+ public static final String user2 = "owncloudUser2Var";
+ public static final String password2 = "owncloudPassword2Var";
+ public static final String userAccount = user + "@"+ URL;
+ public static final String userAccount2 = user2 + "@"+ URL2;
+
+ public static final String gmailAccount = "gmailAccountVar";
+
+ public static final String fileWhichIsInTheServer1 ="test";
+ public static final String fileWhichIsInTheServer2 ="test";
+
+ public static final String fileToTestName = "test";
+ public static final String fileToTestSendByEmailName = "test";
+ public static final String bigFileToTestName = "test";
+
+ public static final String passcode1 = "passcode1";
+ public static final String passcode2 = "passcode2";
+ public static final String passcode3 = "passcode3";
+ public static final String passcode4 = "passcode4";
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.WaitAMomentPopUp;
+
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class CreateFolderTestSuite{
+
+ AndroidDriver driver;
+ Common common;
+ private Boolean folderHasBeenCreated = false;
+ private final String FOLDER_NAME = "testCreateFolder";
+ private String CurrentCreatedFolder = "";
+
+ @Rule public TestName name = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testCreateNewFolder () throws Exception {
+ String NEW_FOLDER_NAME = "testCreateFolder";
+
+ FileListView fileListView = Actions.login(Config.URL,
+ Config.user,Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //check if the folder already exists and if true, delete them
+ Actions.deleteElement(NEW_FOLDER_NAME, fileListView, driver);
+
+ WaitAMomentPopUp waitAMomentPopUp = Actions
+ .createFolder(NEW_FOLDER_NAME, fileListView);
+ Common.waitTillElementIsNotPresentWithoutTimeout(waitAMomentPopUp
+ .getWaitAMomentTextElement(), 100);
+ fileListView.scrollTillFindElement(FOLDER_NAME);
+ assertNotNull(fileListView.getFileElement());
+ assertTrue(
+ folderHasBeenCreated=fileListView.getFileElement().isDisplayed());
+ CurrentCreatedFolder = FOLDER_NAME;
+ assertEquals(FOLDER_NAME , fileListView.getFileElement().getText());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ if (folderHasBeenCreated) {
+ FileListView fileListView = new FileListView(driver);
+ Actions.deleteElement(CurrentCreatedFolder, fileListView, driver);
+ }
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.models.FileListView;
+
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class DeleteFileTestSuite{
+
+ AndroidDriver driver;
+ Common common;
+ private final String FILE_NAME = Config.fileToTestName;
+
+ @Rule public TestName name = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testDeleteFile () throws Exception {
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //TODO. if the file already exists, do not upload
+ FileListView fileListViewAfterUploadFile = Actions
+ .uploadFile(FILE_NAME, fileListView);
+
+ fileListViewAfterUploadFile.scrollTillFindElement(FILE_NAME);
+ Common.waitTillElementIsNotPresentWithoutTimeout(
+ fileListViewAfterUploadFile.getProgressCircular(), 1000);
+ common.wait.until(ExpectedConditions.visibilityOf(
+ fileListViewAfterUploadFile.getFileElementLayout()
+ .findElement(By.id(FileListView.getLocalFileIndicator()))));
+
+ Actions.deleteElement(FILE_NAME,fileListViewAfterUploadFile, driver);
+ assertFalse(fileListViewAfterUploadFile.getFileElement().isDisplayed());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.WaitAMomentPopUp;
+
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class DeleteFolderTestSuite{
+ AndroidDriver driver;
+ Common common;
+ private Boolean folderHasBeenCreated = false;
+ private final String FOLDER_NAME = "testCreateFolder";
+
+ @Rule public TestName name = new TestName();
+
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testDeleteFolder () throws Exception {
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //TODO. if the folder already exists, do no created
+ //create the folder
+ WaitAMomentPopUp waitAMomentPopUp = Actions
+ .createFolder(FOLDER_NAME, fileListView);
+ Common.waitTillElementIsNotPresentWithoutTimeout(
+ waitAMomentPopUp.getWaitAMomentTextElement(), 100);
+ fileListView.scrollTillFindElement(FOLDER_NAME);
+ assertTrue(
+ folderHasBeenCreated = fileListView.getFileElement().isDisplayed());
+
+ //delete the folder
+ Actions.deleteElement(FOLDER_NAME, fileListView, driver);
+ assertFalse(
+ folderHasBeenCreated =fileListView.getFileElement().isDisplayed());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ if(folderHasBeenCreated){
+ FileListView fileListView = new FileListView(driver);
+ Actions.deleteElement(FOLDER_NAME, fileListView, driver);
+ }
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.openqa.selenium.ScreenOrientation;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.*;
+import com.owncloud.android.test.ui.models.LoginForm;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.MenuList;
+import com.owncloud.android.test.ui.models.SettingsView;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class LoginTestSuite{
+ AndroidDriver driver;
+ Common common;
+
+ @Rule public TestName name = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class})
+ public void test1LoginPortrait () throws Exception {
+ driver.rotate(ScreenOrientation.PORTRAIT);
+
+ Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class})
+ public void test2LoginLandscape () throws Exception {
+ driver.rotate(ScreenOrientation.LANDSCAPE);
+ Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testLoginAndShowFiles () throws Exception {
+ driver.rotate(ScreenOrientation.PORTRAIT);
+
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ fileListView.scrollTillFindElement(Config.fileWhichIsInTheServer1);
+ assertTrue(fileListView.getFileElement().isDisplayed());
+ }
+
+
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void test3MultiAccountRotate () throws Exception {
+ driver.rotate(ScreenOrientation.LANDSCAPE);
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ driver.rotate(ScreenOrientation.PORTRAIT);
+ MenuList menu = fileListView.clickOnMenuButton();
+ SettingsView settingsView = menu.clickOnSettingsButton();
+
+ settingsView.tapOnAddAccount(1, 1000);
+ fileListView = Actions.login(Config.URL2, Config.user2,
+ Config.password2, Config.isTrusted2, driver);
+ common.assertIsInSettingsView();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testMultiAccountAndShowFiles () throws Exception {
+ driver.rotate(ScreenOrientation.LANDSCAPE);
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+ fileListView.scrollTillFindElement(Config.fileWhichIsInTheServer1);
+ assertTrue(fileListView.getFileElement().isDisplayed());
+
+ driver.rotate(ScreenOrientation.PORTRAIT);
+ MenuList menu = fileListView.clickOnMenuButton();
+ SettingsView settingsView = menu.clickOnSettingsButton();
+
+ settingsView.tapOnAddAccount(1, 1000);
+ fileListView = Actions.login(Config.URL2, Config.user2,
+ Config.password2, Config.isTrusted2, driver);
+ common.assertIsInSettingsView();
+ settingsView.tapOnAccountElement(2,1, 100);
+ common.assertIsInFileListView();
+
+ fileListView.scrollTillFindElement(Config.fileWhichIsInTheServer2);
+ assertTrue(fileListView.getFileElement().isDisplayed());
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class})
+ public void test4ExistingAccountRotate () throws Exception {
+ driver.rotate(ScreenOrientation.PORTRAIT);
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ driver.rotate(ScreenOrientation.LANDSCAPE);
+ MenuList menu = fileListView.clickOnMenuButton();
+ SettingsView settingsView = menu.clickOnSettingsButton();
+ settingsView.tapOnAddAccount(1, 1000);
+
+ LoginForm loginForm = new LoginForm(driver);
+ fileListView = Actions.login(Config.URL, Config.user,Config.password,
+ Config.isTrusted, driver);
+ assertTrue(common.waitForTextPresent("An account for the same user and"
+ + " server already exists in the device",
+ loginForm.getAuthStatusText()));
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class})
+ public void test5ChangePasswordWrong () throws Exception {
+ driver.rotate(ScreenOrientation.PORTRAIT);
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+ MenuList menu = fileListView.clickOnMenuButton();
+ SettingsView settingsView = menu.clickOnSettingsButton();
+ settingsView.tapOnAccountElement(1,1, 1000);
+ LoginForm changePasswordForm = settingsView
+ .clickOnChangePasswordElement();
+ changePasswordForm.typePassword("WrongPassword");
+ changePasswordForm.clickOnConnectButton();
+ assertTrue(common.waitForTextPresent("Wrong username or password",
+ changePasswordForm.getAuthStatusText()));
+ }
+
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.models.LoginForm;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.MenuList;
+import com.owncloud.android.test.ui.models.SettingsView;
+
+public class LogoutTestSuite{
+
+ AndroidDriver driver;
+ Common common;
+
+ @Rule public TestName name = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testLogout () throws Exception {
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+ MenuList menulist = fileListView.clickOnMenuButton();
+ SettingsView settingsView = menulist.clickOnSettingsButton();
+ settingsView.tapOnAccountElement(1,1, 1000);
+ LoginForm loginForm = settingsView.clickOnDeleteAccountElement();
+ assertEquals("Server address https://…",
+ loginForm.gethostUrlInput().getText());
+ assertEquals("Username", loginForm.getUserNameInput().getText());
+ assertEquals("", loginForm.getPasswordInput().getText());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ //driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.models.ElementMenuOptions;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.MoveView;
+import com.owncloud.android.test.ui.models.WaitAMomentPopUp;
+
+
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class MoveFileTestSuite{
+ AndroidDriver driver;
+ Common common;
+ private String FOLDER_WHERE_MOVE = "folderWhereMove";
+ private String FILE_NAME = Config.fileToTestName;
+ @Rule public TestName name = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testMoveFile () throws Exception {
+ WaitAMomentPopUp waitAMomentPopUp;
+
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //Common.waitTillElementIsNotPresentWithoutTimeout(
+ //fileListView.getProgressCircular(), 1000);
+
+ //check if the folder already exists and if true, delete them
+ Actions.deleteElement(FOLDER_WHERE_MOVE, fileListView, driver);
+ Actions.deleteElement(FILE_NAME, fileListView, driver);
+
+ //Create the folder where the other is gone to be moved
+ waitAMomentPopUp = Actions
+ .createFolder(FOLDER_WHERE_MOVE, fileListView);
+ Common.waitTillElementIsNotPresentWithoutTimeout(
+ waitAMomentPopUp.getWaitAMomentTextElement(), 100);
+ fileListView.scrollTillFindElement(FOLDER_WHERE_MOVE);
+ assertTrue(fileListView.getFileElement().isDisplayed());
+
+ FileListView fileListViewAfterUploadFile = Actions
+ .uploadFile(FILE_NAME, fileListView);
+ fileListViewAfterUploadFile.scrollTillFindElement(FILE_NAME);
+ assertTrue(fileListViewAfterUploadFile.getFileElement().isDisplayed());
+
+ //select to move the file
+ ElementMenuOptions menuOptions = fileListView
+ .longPressOnElement(FILE_NAME);
+ MoveView moveView = menuOptions.clickOnMove();
+
+ //to move to a folder
+ moveView.scrollTillFindElement(FOLDER_WHERE_MOVE).tap(1,1);
+ waitAMomentPopUp = moveView.clickOnChoose();
+ Common.waitTillElementIsNotPresentWithoutTimeout(
+ waitAMomentPopUp.getWaitAMomentTextElement(), 100);
+
+ //check that the folder moved is inside the other
+ fileListView.scrollTillFindElement(FOLDER_WHERE_MOVE).tap(1,1);
+ Common.waitTillElementIsNotPresentWithoutTimeout(fileListView.getProgressCircular(),
+ 1000);
+ Thread.sleep(1000);
+ fileListView.scrollTillFindElement(FILE_NAME);
+ assertEquals(FILE_NAME , fileListView.getFileElement().getText());
+
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ FileListView fileListView = new FileListView(driver);
+ driver.sendKeyEvent(android.view.KeyEvent.KEYCODE_BACK);
+ Actions.deleteElement(FOLDER_WHERE_MOVE, fileListView, driver);
+ Actions.deleteElement(FILE_NAME, fileListView, driver);
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.models.ElementMenuOptions;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.MoveView;
+import com.owncloud.android.test.ui.models.WaitAMomentPopUp;
+
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class MoveFolderTestSuite{
+ AndroidDriver driver;
+ Common common;
+ private String FOLDER_TO_MOVE = "folderToMove";
+ private String FOLDER_WHERE_MOVE = "folderWhereMove";
+
+ @Rule public TestName name = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testMoveFolder () throws Exception {
+ WaitAMomentPopUp waitAMomentPopUp;
+
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //Common.waitTillElementIsNotPresentWithoutTimeout(
+ //fileListView.getProgressCircular(), 1000);
+
+ //check if the folder already exists and if true, delete them
+ Actions.deleteElement(FOLDER_WHERE_MOVE, fileListView, driver);
+ Actions.deleteElement(FOLDER_TO_MOVE, fileListView, driver);
+
+ //Create the folder where the other is gone to be moved
+ waitAMomentPopUp = Actions
+ .createFolder(FOLDER_WHERE_MOVE, fileListView);
+ Common.waitTillElementIsNotPresentWithoutTimeout(
+ waitAMomentPopUp.getWaitAMomentTextElement(), 100);
+ fileListView.scrollTillFindElement(FOLDER_WHERE_MOVE);
+ assertTrue(fileListView.getFileElement().isDisplayed());
+
+ //Create the folder which is going to be moved
+ waitAMomentPopUp = Actions.createFolder(FOLDER_TO_MOVE, fileListView);
+ Common.waitTillElementIsNotPresent(
+ waitAMomentPopUp.getWaitAMomentTextElement(), 100);
+ fileListView.scrollTillFindElement(FOLDER_TO_MOVE);
+ assertTrue(fileListView.getFileElement().isDisplayed());
+
+ //select to move the folder
+ ElementMenuOptions menuOptions = fileListView
+ .longPressOnElement(FOLDER_TO_MOVE);
+ MoveView moveView = menuOptions.clickOnMove();
+
+ //to move to a folder
+ moveView.scrollTillFindElement(FOLDER_WHERE_MOVE).tap(1,1);
+ waitAMomentPopUp = moveView.clickOnChoose();
+ Common.waitTillElementIsNotPresentWithoutTimeout(waitAMomentPopUp
+ .getWaitAMomentTextElement(), 100);
+
+ //check that the folder moved is inside the other
+ fileListView.scrollTillFindElement(FOLDER_WHERE_MOVE).tap(1,1);
+ Common.waitTillElementIsNotPresentWithoutTimeout(fileListView.getProgressCircular(),
+ 1000);
+ Thread.sleep(1000);
+ fileListView.scrollTillFindElement(FOLDER_TO_MOVE);
+ assertEquals(FOLDER_TO_MOVE , fileListView.getFileElement().getText());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ FileListView fileListView = new FileListView(driver);
+ driver.sendKeyEvent(android.view.KeyEvent.KEYCODE_BACK);
+ Actions.deleteElement(FOLDER_WHERE_MOVE, fileListView, driver);
+ Actions.deleteElement(FOLDER_TO_MOVE, fileListView, driver);
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+import org.openqa.selenium.ScreenOrientation;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.MenuList;
+import com.owncloud.android.test.ui.models.PassCodeRequestView;
+import com.owncloud.android.test.ui.models.PassCodeView;
+import com.owncloud.android.test.ui.models.SettingsView;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class PasscodeTestSuite {
+ AndroidDriver driver;
+ Common common;
+
+ @Rule public TestName name = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class})
+ public void testPincodeEnable () throws Exception {
+ driver.rotate(ScreenOrientation.PORTRAIT);
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ MenuList menu = fileListView.clickOnMenuButton();
+ SettingsView settingsView = menu.clickOnSettingsButton();
+
+ PassCodeView passCodeview = settingsView.EnablePassCode();
+ PassCodeView passCodeview2 = passCodeview.enterPasscode(
+ Config.passcode1, Config.passcode2, Config.passcode3,
+ Config.passcode4);
+ passCodeview2.reenterPasscode(Config.passcode1, Config.passcode2,
+ Config.passcode3, Config.passcode4);
+
+ driver.sendKeyEvent(android.view.KeyEvent.KEYCODE_HOME);
+ //TO DO. Open the app instead of start an activity
+ driver.startActivity("com.owncloud.android",
+ ".ui.activity.FileDisplayActivity");
+ //here we check that we are not in the fileDisplayActivity,
+ //because pincode is asked
+ common.assertIsNotInFileListView();
+ common.assertIsPasscodeRequestView();
+
+ PassCodeRequestView passCodeReequestView = new
+ PassCodeRequestView(driver);
+ passCodeReequestView.enterPasscode(Config.passcode1, Config.passcode2,
+ Config.passcode3, Config.passcode4);
+ common.assertIsInFileListView();
+ }
+
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.UnfinishedTestCategory;
+import com.owncloud.android.test.ui.models.FileListView;
+
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class RefreshFolderTestSuite{
+ AndroidDriver driver;
+ Common common;
+
+ @Rule public TestName name = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+
+ @Test
+ @Category({UnfinishedTestCategory.class})
+ public void testPulldownToRefreshFolder () throws Exception {
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+ //TODO. Remove the sleep and check why is not working the assert
+ //when using waitTillElementIsNotPresent
+ Thread.sleep(5000);
+ //waitTillElementIsNotPresentWithoutTimeout(fileListView.getProgressCircular(), 1000);
+ fileListView.pulldownToRefresh();
+ assertTrue(fileListView.getProgressCircular().isDisplayed());
+ //TODO insert a file in the web, and check that it's shown here
+ }
+
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.models.ElementMenuOptions;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.NewFolderPopUp;
+import com.owncloud.android.test.ui.models.WaitAMomentPopUp;
+
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class RenameFileTestSuite{
+
+ AndroidDriver driver;
+ Common common;
+ private Boolean fileHasBeenCreated = false;
+ private final String OLD_FILE_NAME = Config.fileToTestName;
+ private final String FILE_NAME = "newNameFile";
+ private String CurrentCreatedFile = "";
+
+ @Rule public TestName name = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testRenameFile () throws Exception {
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //TODO. if the file already exists, do not upload
+ FileListView fileListViewAfterUploadFile = Actions
+ .uploadFile(OLD_FILE_NAME, fileListView);
+
+ //check if the file with the new name already exists, if true delete it
+ Actions.deleteElement(FILE_NAME, fileListView, driver);
+
+ fileListViewAfterUploadFile.scrollTillFindElement(OLD_FILE_NAME);
+ assertTrue(fileHasBeenCreated = fileListViewAfterUploadFile
+ .getFileElement().isDisplayed());
+ CurrentCreatedFile = OLD_FILE_NAME;
+ Common.waitTillElementIsNotPresentWithoutTimeout(fileListViewAfterUploadFile
+ .getProgressCircular(), 1000);
+ common.wait.until(ExpectedConditions.visibilityOf(
+ fileListViewAfterUploadFile.getFileElementLayout()
+ .findElement(By.id(FileListView.getLocalFileIndicator()))));
+ ElementMenuOptions menuOptions = fileListViewAfterUploadFile
+ .longPressOnElement(OLD_FILE_NAME);
+ NewFolderPopUp newFolderPopUp = menuOptions.clickOnRename();
+ newFolderPopUp.typeNewFolderName(FILE_NAME);
+ WaitAMomentPopUp waitAMomentPopUp = newFolderPopUp
+ .clickOnNewFolderOkButton();
+ Common.waitTillElementIsNotPresentWithoutTimeout(waitAMomentPopUp
+ .getWaitAMomentTextElement(), 100);
+ fileListViewAfterUploadFile.scrollTillFindElement(FILE_NAME);
+ assertNotNull(fileListViewAfterUploadFile.getFileElement());
+ assertTrue(fileListViewAfterUploadFile.getFileElement().isDisplayed());
+ assertEquals(FILE_NAME , fileListViewAfterUploadFile.getFileElement()
+ .getText());
+ CurrentCreatedFile = FILE_NAME;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ if (fileHasBeenCreated) {
+ FileListView fileListView = new FileListView(driver);
+ Actions.deleteElement(CurrentCreatedFile,fileListView, driver);
+ }
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.models.ElementMenuOptions;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.NewFolderPopUp;
+import com.owncloud.android.test.ui.models.WaitAMomentPopUp;
+
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class RenameFolderTestSuite{
+
+ AndroidDriver driver;
+ Common common;
+ private Boolean folderHasBeenCreated = false;
+ private final String OLD_FOLDER_NAME = "beforeRemoving";
+ private final String FOLDER_NAME = "testCreateFolder";
+ private String CurrentCreatedFolder = "";
+
+ @Rule public TestName name = new TestName();
+
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testRenameFolder () throws Exception {
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //TODO. if the folder already exists, do no created
+ //create the folder to rename
+ WaitAMomentPopUp waitAMomentPopUp = Actions
+ .createFolder(OLD_FOLDER_NAME, fileListView);
+ Common.waitTillElementIsNotPresentWithoutTimeout(
+ waitAMomentPopUp.getWaitAMomentTextElement(), 100);
+ fileListView.scrollTillFindElement(OLD_FOLDER_NAME);
+
+ assertTrue(
+ folderHasBeenCreated = fileListView.getFileElement().isDisplayed());
+
+ //check if the folder with the new name already exists
+ //and if true, delete them
+ Actions.deleteElement(FOLDER_NAME, fileListView, driver);
+
+ CurrentCreatedFolder = OLD_FOLDER_NAME;
+ ElementMenuOptions menuOptions = fileListView
+ .longPressOnElement(OLD_FOLDER_NAME);
+ NewFolderPopUp FolderPopUp = menuOptions.clickOnRename();
+ FolderPopUp.typeNewFolderName(FOLDER_NAME);
+ FolderPopUp.clickOnNewFolderOkButton();
+ CurrentCreatedFolder = FOLDER_NAME;
+ Common.waitTillElementIsNotPresentWithoutTimeout(waitAMomentPopUp
+ .getWaitAMomentTextElement(), 100);
+ fileListView.scrollTillFindElement(FOLDER_NAME);
+ assertNotNull(fileListView.getFileElement());
+ assertTrue(
+ folderHasBeenCreated = fileListView.getFileElement().isDisplayed());
+ assertEquals(FOLDER_NAME , fileListView.getFileElement().getText());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ if(folderHasBeenCreated){
+ FileListView fileListView = new FileListView(driver);
+ Actions.deleteElement(CurrentCreatedFolder, fileListView, driver);
+ }
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+
+import org.junit.experimental.categories.Categories.ExcludeCategory;
+import org.junit.experimental.categories.Categories.IncludeCategory;
+import org.junit.runner.RunWith;
+
+import com.owncloud.android.test.ui.groups.FailingTestCategory;
+import com.owncloud.android.test.ui.groups.FlexibleCategories;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestClassPrefix;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestClassSuffix;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestScanPackage;
+
+
+@RunWith(FlexibleCategories.class)
+@ExcludeCategory(NoIgnoreTestCategory.class)
+@IncludeCategory(FailingTestCategory.class)
+@TestScanPackage("com.owncloud.android.test.ui.testSuites")
+@TestClassPrefix("")
+@TestClassSuffix("TestSuite")
+public class RunFailingTests {
+
+}
--- /dev/null
+package com.owncloud.android.test.ui.testSuites;
+
+import org.junit.experimental.categories.Categories.IncludeCategory;
+import org.junit.runner.RunWith;
+import com.owncloud.android.test.ui.groups.FlexibleCategories;
+import com.owncloud.android.test.ui.groups.InProgressCategory;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestClassPrefix;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestClassSuffix;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestScanPackage;
+
+
+@RunWith(FlexibleCategories.class)
+@IncludeCategory(InProgressCategory.class)
+@TestScanPackage("com.owncloud.android.test.ui.testSuites")
+@TestClassPrefix("")
+@TestClassSuffix("TestSuite")
+public class RunInProgressTest {
+
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import org.junit.experimental.categories.Categories.ExcludeCategory;
+import org.junit.experimental.categories.Categories.IncludeCategory;
+import org.junit.runner.RunWith;
+
+import com.owncloud.android.test.ui.groups.FlexibleCategories;
+import com.owncloud.android.test.ui.groups.IgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestClassPrefix;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestClassSuffix;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestScanPackage;
+
+
+@RunWith(FlexibleCategories.class)
+@ExcludeCategory(IgnoreTestCategory.class)
+@IncludeCategory(NoIgnoreTestCategory.class)
+@TestScanPackage("com.owncloud.android.test.ui.testSuites")
+@TestClassPrefix("")
+@TestClassSuffix("TestSuite")
+public class RunNoIgnoreTests {
+}
\ No newline at end of file
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import org.junit.experimental.categories.Categories.ExcludeCategory;
+import org.junit.experimental.categories.Categories.IncludeCategory;
+import org.junit.runner.RunWith;
+
+import com.owncloud.android.test.ui.groups.FlexibleCategories;
+import com.owncloud.android.test.ui.groups.IgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestClassPrefix;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestClassSuffix;
+import com.owncloud.android.test.ui.groups.FlexibleCategories.TestScanPackage;
+
+
+@RunWith(FlexibleCategories.class)
+@ExcludeCategory(IgnoreTestCategory.class)
+@IncludeCategory(SmokeTestCategory.class)
+@TestScanPackage("com.owncloud.android.test.ui.testSuites")
+@TestClassPrefix("")
+@TestClassSuffix("TestSuite")
+public class RunSmokeTests {
+}
\ No newline at end of file
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+import static org.junit.Assert.*;
+import io.appium.java_client.android.AndroidDriver;
+import io.appium.java_client.android.AndroidElement;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.IgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.InProgressCategory;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.models.FileListView;;
+
+public class ShareLinkFileTestSuite{
+
+ AndroidDriver driver;
+ Common common;
+ private final String FILE_NAME = Config.fileToTestName;
+ private Boolean fileHasBeenCreated = false;
+
+ @Rule public TestName name = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class})
+ public void testShareLinkFileByGmail () throws Exception {
+ AndroidElement sharedElementIndicator;
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //TODO. if the file already exists, do not upload
+ FileListView fileListViewAfterUploadFile = Actions
+ .uploadFile(FILE_NAME, fileListView);
+
+ fileListViewAfterUploadFile.scrollTillFindElement(FILE_NAME);
+ assertTrue(fileHasBeenCreated = fileListViewAfterUploadFile
+ .getFileElement().isDisplayed());
+
+ sharedElementIndicator = Actions.shareLinkElementByGmail(FILE_NAME,
+ fileListViewAfterUploadFile,driver,common);
+ assertTrue(sharedElementIndicator.isDisplayed());
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testShareLinkFileByCopyLink () throws Exception {
+ AndroidElement sharedElementIndicator;
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //TODO. if the file already exists, do not upload
+ FileListView fileListViewAfterUploadFile = Actions
+ .uploadFile(FILE_NAME, fileListView);
+
+ fileListViewAfterUploadFile.scrollTillFindElement(FILE_NAME);
+ assertTrue(fileHasBeenCreated = fileListViewAfterUploadFile
+ .getFileElement().isDisplayed());
+
+ sharedElementIndicator = Actions.shareLinkElementByCopyLink(FILE_NAME,
+ fileListViewAfterUploadFile,driver,common);
+ assertTrue(sharedElementIndicator.isDisplayed());
+ }
+
+ @Test
+ @Category({IgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testUnshareLinkFile () throws Exception {
+ AndroidElement sharedElementIndicator;
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //TODO. if the file already exists, do not upload
+ FileListView fileListViewAfterUploadFile = Actions
+ .uploadFile(FILE_NAME, fileListView);
+
+ fileListViewAfterUploadFile.scrollTillFindElement(FILE_NAME);
+ assertTrue(fileHasBeenCreated = fileListViewAfterUploadFile
+ .getFileElement().isDisplayed());
+
+ sharedElementIndicator = Actions.shareLinkElementByCopyLink(FILE_NAME,
+ fileListViewAfterUploadFile,driver,common);
+ assertTrue(sharedElementIndicator.isDisplayed());
+ Actions.unshareLinkElement(FILE_NAME,
+ fileListViewAfterUploadFile,driver,common);
+ assertFalse(sharedElementIndicator.isDisplayed());
+
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ if (fileHasBeenCreated) {
+ FileListView fileListView = new FileListView(driver);
+ Actions.deleteElement(FILE_NAME,fileListView, driver);
+ }
+ driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author purigarcia
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.test.ui.testSuites;
+
+
+import static org.junit.Assert.*;
+import io.appium.java_client.MobileBy;
+import io.appium.java_client.android.AndroidDriver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.junit.runners.MethodSorters;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+
+import com.owncloud.android.test.ui.actions.Actions;
+import com.owncloud.android.test.ui.groups.FailingTestCategory;
+import com.owncloud.android.test.ui.groups.InProgressCategory;
+import com.owncloud.android.test.ui.groups.NoIgnoreTestCategory;
+import com.owncloud.android.test.ui.groups.SmokeTestCategory;
+import com.owncloud.android.test.ui.groups.UnfinishedTestCategory;
+import com.owncloud.android.test.ui.models.FileDetailsView;
+import com.owncloud.android.test.ui.models.ElementMenuOptions;
+import com.owncloud.android.test.ui.models.GmailEmailListView;
+import com.owncloud.android.test.ui.models.GmailEmailView;
+import com.owncloud.android.test.ui.models.ImageView;
+import com.owncloud.android.test.ui.models.FileListView;
+import com.owncloud.android.test.ui.models.NotificationView;
+import com.owncloud.android.test.ui.models.SettingsView;
+import com.owncloud.android.test.ui.models.UploadView;
+
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({NoIgnoreTestCategory.class})
+public class UploadTestSuite{
+
+ AndroidDriver driver;
+ Common common;
+ String FILE_NAME = Config.fileToTestName;
+ String BIG_FILE_NAME = Config.bigFileToTestName;
+ String FILE_GMAIL_NAME = Config.fileToTestSendByEmailName;
+ private Boolean fileHasBeenUploadedFromGmail = false;
+ private Boolean fileHasBeenUploaded = false;
+
+ @Rule public TestName name = new TestName();
+
+
+ @Before
+ public void setUp() throws Exception {
+ common=new Common();
+ driver=common.setUpCommonDriver();
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class, SmokeTestCategory.class})
+ public void testUploadFile () throws Exception {
+
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //check if the file already exists and if true, delete it
+ Actions.deleteElement(FILE_NAME, fileListView, driver);
+
+ FileListView fileListViewAfterUploadFile = Actions
+ .uploadFile(FILE_NAME, fileListView);
+
+ fileListViewAfterUploadFile.scrollTillFindElement(FILE_NAME);
+ assertTrue(fileListViewAfterUploadFile.getFileElement().isDisplayed());
+ Common.waitTillElementIsNotPresentWithoutTimeout(
+ fileListViewAfterUploadFile.getProgressCircular(), 1000);
+ common.wait.until(ExpectedConditions.visibilityOf(
+ fileListViewAfterUploadFile.getFileElementLayout()
+ .findElement(By.id(FileListView.getLocalFileIndicator()))));
+ assertTrue(fileListViewAfterUploadFile.getFileElementLayout()
+ .findElement(By.id(FileListView.getLocalFileIndicator()))
+ .isDisplayed());
+ fileListView = new FileListView(driver);
+ fileListView.scrollTillFindElement(FILE_NAME);
+ assertTrue(
+ fileHasBeenUploaded = fileListView.getFileElement().isDisplayed());
+ }
+
+
+
+ @Test
+ @Category({UnfinishedTestCategory.class})
+ public void testUploadBigFile () throws Exception {
+
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ //check if the file already exists and if true, delete it
+ Actions.deleteElement(BIG_FILE_NAME, fileListView, driver);
+
+ FileListView fileListViewAfterUploadFile = Actions
+ .uploadFile(BIG_FILE_NAME, fileListView);
+
+
+ driver.openNotifications();
+ NotificationView notificationView = new NotificationView(driver);
+
+ try{
+ if(notificationView.getUploadingNotification().isDisplayed()){
+ Common.waitTillElementIsPresent(
+ notificationView.getUploadSucceededNotification(),300000);
+ driver.sendKeyEvent(android.view.KeyEvent.KEYCODE_HOME);
+ driver.startActivity("com.owncloud.android",
+ ".ui.activity.FileDisplayActivity");
+
+ }
+ } catch (NoSuchElementException e) {
+ driver.sendKeyEvent(android.view.KeyEvent.KEYCODE_HOME);
+ driver.startActivity("com.owncloud.android",
+ ".ui.activity.FileDisplayActivity");
+ }
+
+ fileListViewAfterUploadFile.scrollTillFindElement(BIG_FILE_NAME);
+
+ assertTrue(fileListViewAfterUploadFile.getFileElement().isDisplayed());
+
+ Common.waitTillElementIsNotPresentWithoutTimeout(
+ fileListViewAfterUploadFile.getProgressCircular(), 1000);
+ common.wait.until(ExpectedConditions.visibilityOf(
+ fileListViewAfterUploadFile.getFileElementLayout()
+ .findElement(By.id(FileListView.getLocalFileIndicator()))));
+ assertTrue(fileListViewAfterUploadFile.getFileElementLayout()
+ .findElement(By.id(FileListView.getLocalFileIndicator()))
+ .isDisplayed());
+ fileListView = new FileListView(driver);
+ fileListView.scrollTillFindElement(BIG_FILE_NAME);
+ assertTrue(
+ fileHasBeenUploaded = fileListView.getFileElement().isDisplayed());
+ }
+
+
+ @Test
+ @Category(UnfinishedTestCategory.class)
+ public void testUploadFromGmail () throws Exception {
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ driver.startActivity("com.google.android.gm",
+ ".ConversationListActivityGmail");
+ GmailEmailListView gmailEmailListView = new GmailEmailListView(driver);
+ Thread.sleep(3000);
+ GmailEmailView gmailEmailView = gmailEmailListView.clickOnEmail();
+ ImageView imageView = gmailEmailView.clickOnfileButton();
+ imageView.clickOnOptionsButton();
+ imageView.clickOnShareButton();
+ imageView.clickOnOwnCloudButton();
+ //justonce button do not appear always
+ try{
+ imageView.clickOnJustOnceButton();
+ }catch (NoSuchElementException e) {
+ }
+ UploadView uploadView = new UploadView(driver);
+ uploadView.clickOUploadButton();
+ driver.sendKeyEvent(android.view.KeyEvent.KEYCODE_HOME);
+ driver.startActivity("com.owncloud.android",
+ ".ui.activity.FileDisplayActivity");
+ common.wait.until(ExpectedConditions
+ .visibilityOfAllElementsLocatedBy(By.name(FILE_GMAIL_NAME)));
+ assertEquals(Config.fileToTestSendByEmailName ,
+ driver.findElementByName(FILE_GMAIL_NAME).getText());
+ fileListView = new FileListView(driver);
+ fileListView.scrollTillFindElement(FILE_GMAIL_NAME);
+ assertTrue(fileHasBeenUploadedFromGmail = fileListView
+ .getFileElement().isDisplayed());
+ //TODO. correct assert if fileListView is shown in grid mode
+ }
+
+
+ @Test
+ @Category({FailingTestCategory.class})
+ public void testKeepFileUpToDate () throws Exception {
+
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ Common.waitTillElementIsNotPresentWithoutTimeout(fileListView.getProgressCircular(),
+ 1000);
+
+ FileListView fileListViewAfterUploadFile = Actions
+ .uploadFile(FILE_NAME, fileListView);
+ fileListViewAfterUploadFile.scrollTillFindElement(FILE_NAME);
+ assertTrue(fileHasBeenUploaded = fileListViewAfterUploadFile
+ .getFileElement().isDisplayed());
+
+ ElementMenuOptions menuOptions = fileListViewAfterUploadFile
+ .longPressOnElement(FILE_NAME);
+ FileDetailsView fileDetailsView = menuOptions.clickOnDetails();
+ fileDetailsView.checkKeepFileUpToDateCheckbox();
+ Thread.sleep(3000);
+ driver.sendKeyEvent(android.view.KeyEvent.KEYCODE_BACK);
+ assertTrue(common.isElementPresent(
+ fileListViewAfterUploadFile.getFileElementLayout(),
+ MobileBy.id(FileListView.getFavoriteFileIndicator())));
+ assertTrue(fileListViewAfterUploadFile.getFileElementLayout()
+ .findElement(By.id(FileListView.getFavoriteFileIndicator()))
+ .isDisplayed());
+ }
+
+ @Test
+ @Category({NoIgnoreTestCategory.class})
+ public void testKeepFileUpToDateAndRefresh () throws Exception {
+
+ FileListView fileListView = Actions.login(Config.URL, Config.user,
+ Config.password, Config.isTrusted, driver);
+ common.assertIsInFileListView();
+
+ Common.waitTillElementIsNotPresentWithoutTimeout(fileListView.getProgressCircular(),
+ 1000);
+
+ FileListView fileListViewAfterUploadFile = Actions
+ .uploadFile(FILE_NAME, fileListView);
+ fileListViewAfterUploadFile.scrollTillFindElement(FILE_NAME);
+ assertTrue(fileHasBeenUploaded = fileListViewAfterUploadFile
+ .getFileElement().isDisplayed());
+
+ ElementMenuOptions menuOptions = fileListViewAfterUploadFile
+ .longPressOnElement(FILE_NAME);
+ FileDetailsView fileDetailsView = menuOptions.clickOnDetails();
+ fileDetailsView.checkKeepFileUpToDateCheckbox();
+ Thread.sleep(3000);
+ driver.sendKeyEvent(android.view.KeyEvent.KEYCODE_BACK);
+
+ fileListViewAfterUploadFile.pulldownToRefresh();
+ //assertTrue(fileListView.getProgressCircular().isDisplayed());
+ Common.waitTillElementIsNotPresentWithoutTimeout(fileListView.getProgressCircular(),
+ 100);
+
+ assertTrue(common.isElementPresent(
+ fileListViewAfterUploadFile.getFileElementLayout(),
+ MobileBy.id(FileListView.getFavoriteFileIndicator())));
+ assertTrue(fileListViewAfterUploadFile.getFileElementLayout()
+ .findElement(By.id(FileListView.getFavoriteFileIndicator()))
+ .isDisplayed());
+ }
+
+
+ @After
+ public void tearDown() throws Exception {
+ common.takeScreenShotOnFailed(name.getMethodName());
+ FileListView fileListView = new FileListView(driver);
+ if (fileHasBeenUploadedFromGmail) {
+ Actions.deleteElement(FILE_GMAIL_NAME,fileListView, driver);
+ }
+ if(fileHasBeenUploaded){
+ Actions.deleteElement(FILE_NAME,fileListView, driver);
+ Actions.deleteElement(BIG_FILE_NAME,fileListView, driver);
+ }
+
+ //driver.removeApp("com.owncloud.android");
+ driver.quit();
+ }
+
+
+}
+
--- /dev/null
+# Ignore everything in this directory
+*
+# Except this file
+!.gitignore
\ No newline at end of file
--- /dev/null
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.0.0'
+ }
+}
+
+apply plugin: 'com.android.application'
+
+
+repositories {
+ mavenCentral()
+
+ flatDir {
+ dirs 'libs'
+ }
+}
+
+dependencies {
+ compile name: 'touch-image-view'
+ compile 'com.android.support:support-v4:19.1.0'
+ compile project(':owncloud-android-library')
+ compile 'com.jakewharton:disklrucache:2.0.2'
+ compile 'com.android.support:appcompat-v7:19.1.0'
+}
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion "20.0.0"
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ resources.srcDirs = ['src']
+ aidl.srcDirs = ['src']
+ renderscript.srcDirs = ['src']
+ res.srcDirs = ['res']
+ assets.srcDirs = ['res']
+ }
+
+ // Move the tests to tests/java, tests/res, etc...
+ instrumentTest.setRoot('tests')
+
+ // Move the build types to build-types/<type>
+ // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
+ // This moves them out of them default location under src/<type>/... which would
+ // conflict with src/ being used by the main source set.
+ // Adding new build types or product flavors should be accompanied
+ // by a similar customization.
+ debug.setRoot('build-types/debug')
+ release.setRoot('build-types/release')
+ }
+
+ android {
+ lintOptions {
+ abortOnError false
+ }
+ }
+
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+
+ productFlavors {
+ }
+
+ packagingOptions {
+ exclude 'META-INF/LICENSE.txt'
+ }
+}
+
+
--- /dev/null
+#Sun Jan 18 17:01:43 CET 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
--- /dev/null
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
--- /dev/null
+@if "%DEBUG%" == "" @echo off\r
+@rem ##########################################################################\r
+@rem\r
+@rem Gradle startup script for Windows\r
+@rem\r
+@rem ##########################################################################\r
+\r
+@rem Set local scope for the variables with windows NT shell\r
+if "%OS%"=="Windows_NT" setlocal\r
+\r
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r
+set DEFAULT_JVM_OPTS=\r
+\r
+set DIRNAME=%~dp0\r
+if "%DIRNAME%" == "" set DIRNAME=.\r
+set APP_BASE_NAME=%~n0\r
+set APP_HOME=%DIRNAME%\r
+\r
+@rem Find java.exe\r
+if defined JAVA_HOME goto findJavaFromJavaHome\r
+\r
+set JAVA_EXE=java.exe\r
+%JAVA_EXE% -version >NUL 2>&1\r
+if "%ERRORLEVEL%" == "0" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:findJavaFromJavaHome\r
+set JAVA_HOME=%JAVA_HOME:"=%\r
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe\r
+\r
+if exist "%JAVA_EXE%" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:init\r
+@rem Get command-line arguments, handling Windowz variants\r
+\r
+if not "%OS%" == "Windows_NT" goto win9xME_args\r
+if "%@eval[2+2]" == "4" goto 4NT_args\r
+\r
+:win9xME_args\r
+@rem Slurp the command line arguments.\r
+set CMD_LINE_ARGS=\r
+set _SKIP=2\r
+\r
+:win9xME_args_slurp\r
+if "x%~1" == "x" goto execute\r
+\r
+set CMD_LINE_ARGS=%*\r
+goto execute\r
+\r
+:4NT_args\r
+@rem Get arguments from the 4NT Shell from JP Software\r
+set CMD_LINE_ARGS=%$\r
+\r
+:execute\r
+@rem Setup the command line\r
+\r
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar\r
+\r
+@rem Execute Gradle\r
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r
+\r
+:end\r
+@rem End local scope for the variables with windows NT shell\r
+if "%ERRORLEVEL%"=="0" goto mainEnd\r
+\r
+:fail\r
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r
+rem the _cmd.exe /c_ return code!\r
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1\r
+exit /b 1\r
+\r
+:mainEnd\r
+if "%OS%"=="Windows_NT" endlocal\r
+\r
+:omega\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="output" path="bin/classes"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>android-support-appcompat-v7-exploded-aar</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>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.support.v7.appcompat">
+ <uses-sdk android:minSdkVersion="7"/>
+ <application />
+</manifest>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/AndroidManifest.xml -->
\ No newline at end of file
--- /dev/null
+int anim abc_fade_in 0x7f040000
+int anim abc_fade_out 0x7f040001
+int anim abc_slide_in_bottom 0x7f040002
+int anim abc_slide_in_top 0x7f040003
+int anim abc_slide_out_bottom 0x7f040004
+int anim abc_slide_out_top 0x7f040005
+int attr actionBarDivider 0x7f010000
+int attr actionBarItemBackground 0x7f010001
+int attr actionBarSize 0x7f010002
+int attr actionBarSplitStyle 0x7f010003
+int attr actionBarStyle 0x7f010004
+int attr actionBarTabBarStyle 0x7f010005
+int attr actionBarTabStyle 0x7f010006
+int attr actionBarTabTextStyle 0x7f010007
+int attr actionBarWidgetTheme 0x7f010008
+int attr actionButtonStyle 0x7f010009
+int attr actionDropDownStyle 0x7f010066
+int attr actionLayout 0x7f01005d
+int attr actionMenuTextAppearance 0x7f01000a
+int attr actionMenuTextColor 0x7f01000b
+int attr actionModeBackground 0x7f01000c
+int attr actionModeCloseButtonStyle 0x7f01000d
+int attr actionModeCloseDrawable 0x7f01000e
+int attr actionModeCopyDrawable 0x7f01000f
+int attr actionModeCutDrawable 0x7f010010
+int attr actionModeFindDrawable 0x7f010011
+int attr actionModePasteDrawable 0x7f010012
+int attr actionModePopupWindowStyle 0x7f010013
+int attr actionModeSelectAllDrawable 0x7f010014
+int attr actionModeShareDrawable 0x7f010015
+int attr actionModeSplitBackground 0x7f010016
+int attr actionModeStyle 0x7f010017
+int attr actionModeWebSearchDrawable 0x7f010018
+int attr actionOverflowButtonStyle 0x7f010019
+int attr actionProviderClass 0x7f01005f
+int attr actionViewClass 0x7f01005e
+int attr activityChooserViewStyle 0x7f01001a
+int attr background 0x7f010047
+int attr backgroundSplit 0x7f010049
+int attr backgroundStacked 0x7f010048
+int attr buttonBarButtonStyle 0x7f01001b
+int attr buttonBarStyle 0x7f01001c
+int attr customNavigationLayout 0x7f01004a
+int attr disableChildrenWhenDisabled 0x7f010065
+int attr displayOptions 0x7f010040
+int attr divider 0x7f010046
+int attr dividerHorizontal 0x7f01001d
+int attr dividerPadding 0x7f01005b
+int attr dividerVertical 0x7f01001e
+int attr dropDownListViewStyle 0x7f01001f
+int attr dropdownListPreferredItemHeight 0x7f010067
+int attr expandActivityOverflowButtonDrawable 0x7f010058
+int attr height 0x7f010020
+int attr homeAsUpIndicator 0x7f010021
+int attr homeLayout 0x7f01004b
+int attr icon 0x7f010044
+int attr iconifiedByDefault 0x7f010060
+int attr indeterminateProgressStyle 0x7f01004d
+int attr initialActivityCount 0x7f010057
+int attr isLightTheme 0x7f010022
+int attr itemPadding 0x7f01004f
+int attr listChoiceBackgroundIndicator 0x7f01006b
+int attr listPopupWindowStyle 0x7f010023
+int attr listPreferredItemHeight 0x7f010024
+int attr listPreferredItemHeightLarge 0x7f010025
+int attr listPreferredItemHeightSmall 0x7f010026
+int attr listPreferredItemPaddingLeft 0x7f010027
+int attr listPreferredItemPaddingRight 0x7f010028
+int attr logo 0x7f010045
+int attr navigationMode 0x7f01003f
+int attr paddingEnd 0x7f01006d
+int attr paddingStart 0x7f01006c
+int attr panelMenuListTheme 0x7f01006a
+int attr panelMenuListWidth 0x7f010069
+int attr popupMenuStyle 0x7f010068
+int attr popupPromptView 0x7f010064
+int attr progressBarPadding 0x7f01004e
+int attr progressBarStyle 0x7f01004c
+int attr prompt 0x7f010062
+int attr queryHint 0x7f010061
+int attr searchDropdownBackground 0x7f010029
+int attr searchResultListItemHeight 0x7f01002a
+int attr searchViewAutoCompleteTextView 0x7f01002b
+int attr searchViewCloseIcon 0x7f01002c
+int attr searchViewEditQuery 0x7f01002d
+int attr searchViewEditQueryBackground 0x7f01002e
+int attr searchViewGoIcon 0x7f01002f
+int attr searchViewSearchIcon 0x7f010030
+int attr searchViewTextField 0x7f010031
+int attr searchViewTextFieldRight 0x7f010032
+int attr searchViewVoiceIcon 0x7f010033
+int attr selectableItemBackground 0x7f010034
+int attr showAsAction 0x7f01005c
+int attr showDividers 0x7f01005a
+int attr spinnerDropDownItemStyle 0x7f010035
+int attr spinnerMode 0x7f010063
+int attr spinnerStyle 0x7f010036
+int attr subtitle 0x7f010041
+int attr subtitleTextStyle 0x7f010043
+int attr textAllCaps 0x7f010059
+int attr textAppearanceLargePopupMenu 0x7f010037
+int attr textAppearanceListItem 0x7f010038
+int attr textAppearanceListItemSmall 0x7f010039
+int attr textAppearanceSearchResultSubtitle 0x7f01003a
+int attr textAppearanceSearchResultTitle 0x7f01003b
+int attr textAppearanceSmallPopupMenu 0x7f01003c
+int attr textColorSearchUrl 0x7f01003d
+int attr title 0x7f01003e
+int attr titleTextStyle 0x7f010042
+int attr windowActionBar 0x7f010050
+int attr windowActionBarOverlay 0x7f010051
+int attr windowFixedHeightMajor 0x7f010056
+int attr windowFixedHeightMinor 0x7f010054
+int attr windowFixedWidthMajor 0x7f010053
+int attr windowFixedWidthMinor 0x7f010055
+int attr windowSplitActionBar 0x7f010052
+int bool abc_action_bar_embed_tabs_pre_jb 0x7f050000
+int bool abc_action_bar_expanded_action_views_exclusive 0x7f050001
+int bool abc_config_actionMenuItemAllCaps 0x7f050002
+int bool abc_config_allowActionMenuItemTextWithIcon 0x7f050003
+int bool abc_config_showMenuShortcutsWhenKeyboardPresent 0x7f050004
+int bool abc_split_action_bar_is_narrow 0x7f050005
+int color abc_search_url_text_holo 0x7f060003
+int color abc_search_url_text_normal 0x7f060000
+int color abc_search_url_text_pressed 0x7f060001
+int color abc_search_url_text_selected 0x7f060002
+int dimen abc_action_bar_default_height 0x7f080000
+int dimen abc_action_bar_icon_vertical_padding 0x7f080001
+int dimen abc_action_bar_progress_bar_size 0x7f080002
+int dimen abc_action_bar_stacked_max_height 0x7f080003
+int dimen abc_action_bar_stacked_tab_max_width 0x7f080004
+int dimen abc_action_bar_subtitle_bottom_margin 0x7f080005
+int dimen abc_action_bar_subtitle_text_size 0x7f080006
+int dimen abc_action_bar_subtitle_top_margin 0x7f080007
+int dimen abc_action_bar_title_text_size 0x7f080008
+int dimen abc_action_button_min_width 0x7f080009
+int dimen abc_config_prefDialogWidth 0x7f08000a
+int dimen abc_dropdownitem_icon_width 0x7f08000b
+int dimen abc_dropdownitem_text_padding_left 0x7f08000c
+int dimen abc_dropdownitem_text_padding_right 0x7f08000d
+int dimen abc_panel_menu_list_width 0x7f08000e
+int dimen abc_search_view_preferred_width 0x7f08000f
+int dimen abc_search_view_text_min_width 0x7f080010
+int dimen dialog_fixed_height_major 0x7f080011
+int dimen dialog_fixed_height_minor 0x7f080012
+int dimen dialog_fixed_width_major 0x7f080013
+int dimen dialog_fixed_width_minor 0x7f080014
+int drawable abc_ab_bottom_solid_dark_holo 0x7f020000
+int drawable abc_ab_bottom_solid_light_holo 0x7f020001
+int drawable abc_ab_bottom_transparent_dark_holo 0x7f020002
+int drawable abc_ab_bottom_transparent_light_holo 0x7f020003
+int drawable abc_ab_share_pack_holo_dark 0x7f020004
+int drawable abc_ab_share_pack_holo_light 0x7f020005
+int drawable abc_ab_solid_dark_holo 0x7f020006
+int drawable abc_ab_solid_light_holo 0x7f020007
+int drawable abc_ab_stacked_solid_dark_holo 0x7f020008
+int drawable abc_ab_stacked_solid_light_holo 0x7f020009
+int drawable abc_ab_stacked_transparent_dark_holo 0x7f02000a
+int drawable abc_ab_stacked_transparent_light_holo 0x7f02000b
+int drawable abc_ab_transparent_dark_holo 0x7f02000c
+int drawable abc_ab_transparent_light_holo 0x7f02000d
+int drawable abc_cab_background_bottom_holo_dark 0x7f02000e
+int drawable abc_cab_background_bottom_holo_light 0x7f02000f
+int drawable abc_cab_background_top_holo_dark 0x7f020010
+int drawable abc_cab_background_top_holo_light 0x7f020011
+int drawable abc_ic_ab_back_holo_dark 0x7f020012
+int drawable abc_ic_ab_back_holo_light 0x7f020013
+int drawable abc_ic_cab_done_holo_dark 0x7f020014
+int drawable abc_ic_cab_done_holo_light 0x7f020015
+int drawable abc_ic_clear 0x7f020016
+int drawable abc_ic_clear_disabled 0x7f020017
+int drawable abc_ic_clear_holo_light 0x7f020018
+int drawable abc_ic_clear_normal 0x7f020019
+int drawable abc_ic_clear_search_api_disabled_holo_light 0x7f02001a
+int drawable abc_ic_clear_search_api_holo_light 0x7f02001b
+int drawable abc_ic_commit_search_api_holo_dark 0x7f02001c
+int drawable abc_ic_commit_search_api_holo_light 0x7f02001d
+int drawable abc_ic_go 0x7f02001e
+int drawable abc_ic_go_search_api_holo_light 0x7f02001f
+int drawable abc_ic_menu_moreoverflow_normal_holo_dark 0x7f020020
+int drawable abc_ic_menu_moreoverflow_normal_holo_light 0x7f020021
+int drawable abc_ic_menu_share_holo_dark 0x7f020022
+int drawable abc_ic_menu_share_holo_light 0x7f020023
+int drawable abc_ic_search 0x7f020024
+int drawable abc_ic_search_api_holo_light 0x7f020025
+int drawable abc_ic_voice_search 0x7f020026
+int drawable abc_ic_voice_search_api_holo_light 0x7f020027
+int drawable abc_item_background_holo_dark 0x7f020028
+int drawable abc_item_background_holo_light 0x7f020029
+int drawable abc_list_divider_holo_dark 0x7f02002a
+int drawable abc_list_divider_holo_light 0x7f02002b
+int drawable abc_list_focused_holo 0x7f02002c
+int drawable abc_list_longpressed_holo 0x7f02002d
+int drawable abc_list_pressed_holo_dark 0x7f02002e
+int drawable abc_list_pressed_holo_light 0x7f02002f
+int drawable abc_list_selector_background_transition_holo_dark 0x7f020030
+int drawable abc_list_selector_background_transition_holo_light 0x7f020031
+int drawable abc_list_selector_disabled_holo_dark 0x7f020032
+int drawable abc_list_selector_disabled_holo_light 0x7f020033
+int drawable abc_list_selector_holo_dark 0x7f020034
+int drawable abc_list_selector_holo_light 0x7f020035
+int drawable abc_menu_dropdown_panel_holo_dark 0x7f020036
+int drawable abc_menu_dropdown_panel_holo_light 0x7f020037
+int drawable abc_menu_hardkey_panel_holo_dark 0x7f020038
+int drawable abc_menu_hardkey_panel_holo_light 0x7f020039
+int drawable abc_search_dropdown_dark 0x7f02003a
+int drawable abc_search_dropdown_light 0x7f02003b
+int drawable abc_spinner_ab_default_holo_dark 0x7f02003c
+int drawable abc_spinner_ab_default_holo_light 0x7f02003d
+int drawable abc_spinner_ab_disabled_holo_dark 0x7f02003e
+int drawable abc_spinner_ab_disabled_holo_light 0x7f02003f
+int drawable abc_spinner_ab_focused_holo_dark 0x7f020040
+int drawable abc_spinner_ab_focused_holo_light 0x7f020041
+int drawable abc_spinner_ab_holo_dark 0x7f020042
+int drawable abc_spinner_ab_holo_light 0x7f020043
+int drawable abc_spinner_ab_pressed_holo_dark 0x7f020044
+int drawable abc_spinner_ab_pressed_holo_light 0x7f020045
+int drawable abc_tab_indicator_ab_holo 0x7f020046
+int drawable abc_tab_selected_focused_holo 0x7f020047
+int drawable abc_tab_selected_holo 0x7f020048
+int drawable abc_tab_selected_pressed_holo 0x7f020049
+int drawable abc_tab_unselected_pressed_holo 0x7f02004a
+int drawable abc_textfield_search_default_holo_dark 0x7f02004b
+int drawable abc_textfield_search_default_holo_light 0x7f02004c
+int drawable abc_textfield_search_right_default_holo_dark 0x7f02004d
+int drawable abc_textfield_search_right_default_holo_light 0x7f02004e
+int drawable abc_textfield_search_right_selected_holo_dark 0x7f02004f
+int drawable abc_textfield_search_right_selected_holo_light 0x7f020050
+int drawable abc_textfield_search_selected_holo_dark 0x7f020051
+int drawable abc_textfield_search_selected_holo_light 0x7f020052
+int drawable abc_textfield_searchview_holo_dark 0x7f020053
+int drawable abc_textfield_searchview_holo_light 0x7f020054
+int drawable abc_textfield_searchview_right_holo_dark 0x7f020055
+int drawable abc_textfield_searchview_right_holo_light 0x7f020056
+int id action_bar 0x7f07001c
+int id action_bar_activity_content 0x7f070014
+int id action_bar_container 0x7f07001b
+int id action_bar_overlay_layout 0x7f07001f
+int id action_bar_root 0x7f07001a
+int id action_bar_subtitle 0x7f070023
+int id action_bar_title 0x7f070022
+int id action_context_bar 0x7f07001d
+int id action_menu_divider 0x7f070015
+int id action_menu_presenter 0x7f070016
+int id action_mode_close_button 0x7f070024
+int id activity_chooser_view_content 0x7f070025
+int id always 0x7f07000f
+int id beginning 0x7f07000a
+int id checkbox 0x7f07002d
+int id collapseActionView 0x7f070011
+int id default_activity_button 0x7f070028
+int id dialog 0x7f070012
+int id disableHome 0x7f070008
+int id dropdown 0x7f070013
+int id edit_query 0x7f070030
+int id end 0x7f07000c
+int id expand_activities_button 0x7f070026
+int id expanded_menu 0x7f07002c
+int id home 0x7f070017
+int id homeAsUp 0x7f070005
+int id icon 0x7f07002a
+int id ifRoom 0x7f07000e
+int id image 0x7f070027
+int id listMode 0x7f070001
+int id list_item 0x7f070029
+int id middle 0x7f07000b
+int id never 0x7f07000d
+int id none 0x7f070009
+int id normal 0x7f070000
+int id progress_circular 0x7f070018
+int id progress_horizontal 0x7f070019
+int id radio 0x7f07002f
+int id search_badge 0x7f070032
+int id search_bar 0x7f070031
+int id search_button 0x7f070033
+int id search_close_btn 0x7f070038
+int id search_edit_frame 0x7f070034
+int id search_go_btn 0x7f07003a
+int id search_mag_icon 0x7f070035
+int id search_plate 0x7f070036
+int id search_src_text 0x7f070037
+int id search_voice_btn 0x7f07003b
+int id shortcut 0x7f07002e
+int id showCustom 0x7f070007
+int id showHome 0x7f070004
+int id showTitle 0x7f070006
+int id split_action_bar 0x7f07001e
+int id submit_area 0x7f070039
+int id tabMode 0x7f070002
+int id title 0x7f07002b
+int id top_action_bar 0x7f070020
+int id up 0x7f070021
+int id useLogo 0x7f070003
+int id withText 0x7f070010
+int integer abc_max_action_buttons 0x7f090000
+int layout abc_action_bar_decor 0x7f030000
+int layout abc_action_bar_decor_include 0x7f030001
+int layout abc_action_bar_decor_overlay 0x7f030002
+int layout abc_action_bar_home 0x7f030003
+int layout abc_action_bar_tab 0x7f030004
+int layout abc_action_bar_tabbar 0x7f030005
+int layout abc_action_bar_title_item 0x7f030006
+int layout abc_action_bar_view_list_nav_layout 0x7f030007
+int layout abc_action_menu_item_layout 0x7f030008
+int layout abc_action_menu_layout 0x7f030009
+int layout abc_action_mode_bar 0x7f03000a
+int layout abc_action_mode_close_item 0x7f03000b
+int layout abc_activity_chooser_view 0x7f03000c
+int layout abc_activity_chooser_view_include 0x7f03000d
+int layout abc_activity_chooser_view_list_item 0x7f03000e
+int layout abc_expanded_menu_layout 0x7f03000f
+int layout abc_list_menu_item_checkbox 0x7f030010
+int layout abc_list_menu_item_icon 0x7f030011
+int layout abc_list_menu_item_layout 0x7f030012
+int layout abc_list_menu_item_radio 0x7f030013
+int layout abc_popup_menu_item_layout 0x7f030014
+int layout abc_search_dropdown_item_icons_2line 0x7f030015
+int layout abc_search_view 0x7f030016
+int layout abc_simple_decor 0x7f030017
+int layout support_simple_spinner_dropdown_item 0x7f030018
+int string abc_action_bar_home_description 0x7f0a0000
+int string abc_action_bar_up_description 0x7f0a0001
+int string abc_action_menu_overflow_description 0x7f0a0002
+int string abc_action_mode_done 0x7f0a0003
+int string abc_activity_chooser_view_see_all 0x7f0a0004
+int string abc_activitychooserview_choose_application 0x7f0a0005
+int string abc_searchview_description_clear 0x7f0a0006
+int string abc_searchview_description_query 0x7f0a0007
+int string abc_searchview_description_search 0x7f0a0008
+int string abc_searchview_description_submit 0x7f0a0009
+int string abc_searchview_description_voice 0x7f0a000a
+int string abc_shareactionprovider_share_with 0x7f0a000b
+int string abc_shareactionprovider_share_with_application 0x7f0a000c
+int style TextAppearance_AppCompat_Base_CompactMenu_Dialog 0x7f0b0000
+int style TextAppearance_AppCompat_Base_SearchResult 0x7f0b0001
+int style TextAppearance_AppCompat_Base_SearchResult_Subtitle 0x7f0b0002
+int style TextAppearance_AppCompat_Base_SearchResult_Title 0x7f0b0003
+int style TextAppearance_AppCompat_Base_Widget_PopupMenu_Large 0x7f0b0004
+int style TextAppearance_AppCompat_Base_Widget_PopupMenu_Small 0x7f0b0005
+int style TextAppearance_AppCompat_Light_Base_SearchResult 0x7f0b0006
+int style TextAppearance_AppCompat_Light_Base_SearchResult_Subtitle 0x7f0b0007
+int style TextAppearance_AppCompat_Light_Base_SearchResult_Title 0x7f0b0008
+int style TextAppearance_AppCompat_Light_Base_Widget_PopupMenu_Large 0x7f0b0009
+int style TextAppearance_AppCompat_Light_Base_Widget_PopupMenu_Small 0x7f0b000a
+int style TextAppearance_AppCompat_Light_SearchResult_Subtitle 0x7f0b000b
+int style TextAppearance_AppCompat_Light_SearchResult_Title 0x7f0b000c
+int style TextAppearance_AppCompat_Light_Widget_PopupMenu_Large 0x7f0b000d
+int style TextAppearance_AppCompat_Light_Widget_PopupMenu_Small 0x7f0b000e
+int style TextAppearance_AppCompat_SearchResult_Subtitle 0x7f0b000f
+int style TextAppearance_AppCompat_SearchResult_Title 0x7f0b0010
+int style TextAppearance_AppCompat_Widget_ActionBar_Menu 0x7f0b0011
+int style TextAppearance_AppCompat_Widget_ActionBar_Subtitle 0x7f0b0012
+int style TextAppearance_AppCompat_Widget_ActionBar_Subtitle_Inverse 0x7f0b0013
+int style TextAppearance_AppCompat_Widget_ActionBar_Title 0x7f0b0014
+int style TextAppearance_AppCompat_Widget_ActionBar_Title_Inverse 0x7f0b0015
+int style TextAppearance_AppCompat_Widget_ActionMode_Subtitle 0x7f0b0016
+int style TextAppearance_AppCompat_Widget_ActionMode_Subtitle_Inverse 0x7f0b0017
+int style TextAppearance_AppCompat_Widget_ActionMode_Title 0x7f0b0018
+int style TextAppearance_AppCompat_Widget_ActionMode_Title_Inverse 0x7f0b0019
+int style TextAppearance_AppCompat_Widget_Base_ActionBar_Menu 0x7f0b001a
+int style TextAppearance_AppCompat_Widget_Base_ActionBar_Subtitle 0x7f0b001b
+int style TextAppearance_AppCompat_Widget_Base_ActionBar_Subtitle_Inverse 0x7f0b001c
+int style TextAppearance_AppCompat_Widget_Base_ActionBar_Title 0x7f0b001d
+int style TextAppearance_AppCompat_Widget_Base_ActionBar_Title_Inverse 0x7f0b001e
+int style TextAppearance_AppCompat_Widget_Base_ActionMode_Subtitle 0x7f0b001f
+int style TextAppearance_AppCompat_Widget_Base_ActionMode_Subtitle_Inverse 0x7f0b0020
+int style TextAppearance_AppCompat_Widget_Base_ActionMode_Title 0x7f0b0021
+int style TextAppearance_AppCompat_Widget_Base_ActionMode_Title_Inverse 0x7f0b0022
+int style TextAppearance_AppCompat_Widget_Base_DropDownItem 0x7f0b0023
+int style TextAppearance_AppCompat_Widget_DropDownItem 0x7f0b0024
+int style TextAppearance_AppCompat_Widget_PopupMenu_Large 0x7f0b0025
+int style TextAppearance_AppCompat_Widget_PopupMenu_Small 0x7f0b0026
+int style TextAppearance_Widget_AppCompat_Base_ExpandedMenu_Item 0x7f0b0027
+int style TextAppearance_Widget_AppCompat_ExpandedMenu_Item 0x7f0b0028
+int style Theme_AppCompat 0x7f0b0029
+int style Theme_AppCompat_Base_CompactMenu 0x7f0b002a
+int style Theme_AppCompat_Base_CompactMenu_Dialog 0x7f0b002b
+int style Theme_AppCompat_CompactMenu 0x7f0b002c
+int style Theme_AppCompat_CompactMenu_Dialog 0x7f0b002d
+int style Theme_AppCompat_DialogWhenLarge 0x7f0b002e
+int style Theme_AppCompat_Light 0x7f0b002f
+int style Theme_AppCompat_Light_DarkActionBar 0x7f0b0030
+int style Theme_AppCompat_Light_DialogWhenLarge 0x7f0b0031
+int style Theme_Base 0x7f0b0032
+int style Theme_Base_AppCompat 0x7f0b0033
+int style Theme_Base_AppCompat_Dialog_FixedSize 0x7f0b0034
+int style Theme_Base_AppCompat_Dialog_Light_FixedSize 0x7f0b0035
+int style Theme_Base_AppCompat_DialogWhenLarge 0x7f0b0036
+int style Theme_Base_AppCompat_DialogWhenLarge_Base 0x7f0b0089
+int style Theme_Base_AppCompat_Light 0x7f0b0037
+int style Theme_Base_AppCompat_Light_DarkActionBar 0x7f0b0038
+int style Theme_Base_AppCompat_Light_DialogWhenLarge 0x7f0b0039
+int style Theme_Base_AppCompat_Light_DialogWhenLarge_Base 0x7f0b008a
+int style Theme_Base_Light 0x7f0b003a
+int style Widget_AppCompat_ActionBar 0x7f0b003b
+int style Widget_AppCompat_ActionBar_Solid 0x7f0b003c
+int style Widget_AppCompat_ActionBar_TabBar 0x7f0b003d
+int style Widget_AppCompat_ActionBar_TabText 0x7f0b003e
+int style Widget_AppCompat_ActionBar_TabView 0x7f0b003f
+int style Widget_AppCompat_ActionButton 0x7f0b0040
+int style Widget_AppCompat_ActionButton_CloseMode 0x7f0b0041
+int style Widget_AppCompat_ActionButton_Overflow 0x7f0b0042
+int style Widget_AppCompat_ActionMode 0x7f0b0043
+int style Widget_AppCompat_ActivityChooserView 0x7f0b0044
+int style Widget_AppCompat_AutoCompleteTextView 0x7f0b0045
+int style Widget_AppCompat_Base_ActionBar 0x7f0b0046
+int style Widget_AppCompat_Base_ActionBar_Solid 0x7f0b0047
+int style Widget_AppCompat_Base_ActionBar_TabBar 0x7f0b0048
+int style Widget_AppCompat_Base_ActionBar_TabText 0x7f0b0049
+int style Widget_AppCompat_Base_ActionBar_TabView 0x7f0b004a
+int style Widget_AppCompat_Base_ActionButton 0x7f0b004b
+int style Widget_AppCompat_Base_ActionButton_CloseMode 0x7f0b004c
+int style Widget_AppCompat_Base_ActionButton_Overflow 0x7f0b004d
+int style Widget_AppCompat_Base_ActionMode 0x7f0b004e
+int style Widget_AppCompat_Base_ActivityChooserView 0x7f0b004f
+int style Widget_AppCompat_Base_AutoCompleteTextView 0x7f0b0050
+int style Widget_AppCompat_Base_DropDownItem_Spinner 0x7f0b0051
+int style Widget_AppCompat_Base_ListPopupWindow 0x7f0b0052
+int style Widget_AppCompat_Base_ListView_DropDown 0x7f0b0053
+int style Widget_AppCompat_Base_ListView_Menu 0x7f0b0054
+int style Widget_AppCompat_Base_PopupMenu 0x7f0b0055
+int style Widget_AppCompat_Base_ProgressBar 0x7f0b0056
+int style Widget_AppCompat_Base_ProgressBar_Horizontal 0x7f0b0057
+int style Widget_AppCompat_Base_Spinner 0x7f0b0058
+int style Widget_AppCompat_DropDownItem_Spinner 0x7f0b0059
+int style Widget_AppCompat_Light_ActionBar 0x7f0b005a
+int style Widget_AppCompat_Light_ActionBar_Solid 0x7f0b005b
+int style Widget_AppCompat_Light_ActionBar_Solid_Inverse 0x7f0b005c
+int style Widget_AppCompat_Light_ActionBar_TabBar 0x7f0b005d
+int style Widget_AppCompat_Light_ActionBar_TabBar_Inverse 0x7f0b005e
+int style Widget_AppCompat_Light_ActionBar_TabText 0x7f0b005f
+int style Widget_AppCompat_Light_ActionBar_TabText_Inverse 0x7f0b0060
+int style Widget_AppCompat_Light_ActionBar_TabView 0x7f0b0061
+int style Widget_AppCompat_Light_ActionBar_TabView_Inverse 0x7f0b0062
+int style Widget_AppCompat_Light_ActionButton 0x7f0b0063
+int style Widget_AppCompat_Light_ActionButton_CloseMode 0x7f0b0064
+int style Widget_AppCompat_Light_ActionButton_Overflow 0x7f0b0065
+int style Widget_AppCompat_Light_ActionMode_Inverse 0x7f0b0066
+int style Widget_AppCompat_Light_ActivityChooserView 0x7f0b0067
+int style Widget_AppCompat_Light_AutoCompleteTextView 0x7f0b0068
+int style Widget_AppCompat_Light_Base_ActionBar 0x7f0b0069
+int style Widget_AppCompat_Light_Base_ActionBar_Solid 0x7f0b006a
+int style Widget_AppCompat_Light_Base_ActionBar_Solid_Inverse 0x7f0b006b
+int style Widget_AppCompat_Light_Base_ActionBar_TabBar 0x7f0b006c
+int style Widget_AppCompat_Light_Base_ActionBar_TabBar_Inverse 0x7f0b006d
+int style Widget_AppCompat_Light_Base_ActionBar_TabText 0x7f0b006e
+int style Widget_AppCompat_Light_Base_ActionBar_TabText_Inverse 0x7f0b006f
+int style Widget_AppCompat_Light_Base_ActionBar_TabView 0x7f0b0070
+int style Widget_AppCompat_Light_Base_ActionBar_TabView_Inverse 0x7f0b0071
+int style Widget_AppCompat_Light_Base_ActionButton 0x7f0b0072
+int style Widget_AppCompat_Light_Base_ActionButton_CloseMode 0x7f0b0073
+int style Widget_AppCompat_Light_Base_ActionButton_Overflow 0x7f0b0074
+int style Widget_AppCompat_Light_Base_ActionMode_Inverse 0x7f0b0075
+int style Widget_AppCompat_Light_Base_ActivityChooserView 0x7f0b0076
+int style Widget_AppCompat_Light_Base_AutoCompleteTextView 0x7f0b0077
+int style Widget_AppCompat_Light_Base_DropDownItem_Spinner 0x7f0b0078
+int style Widget_AppCompat_Light_Base_ListPopupWindow 0x7f0b0079
+int style Widget_AppCompat_Light_Base_ListView_DropDown 0x7f0b007a
+int style Widget_AppCompat_Light_Base_PopupMenu 0x7f0b007b
+int style Widget_AppCompat_Light_Base_Spinner 0x7f0b007c
+int style Widget_AppCompat_Light_DropDownItem_Spinner 0x7f0b007d
+int style Widget_AppCompat_Light_ListPopupWindow 0x7f0b007e
+int style Widget_AppCompat_Light_ListView_DropDown 0x7f0b007f
+int style Widget_AppCompat_Light_PopupMenu 0x7f0b0080
+int style Widget_AppCompat_Light_Spinner_DropDown_ActionBar 0x7f0b0081
+int style Widget_AppCompat_ListPopupWindow 0x7f0b0082
+int style Widget_AppCompat_ListView_DropDown 0x7f0b0083
+int style Widget_AppCompat_ListView_Menu 0x7f0b0084
+int style Widget_AppCompat_PopupMenu 0x7f0b0085
+int style Widget_AppCompat_ProgressBar 0x7f0b0086
+int style Widget_AppCompat_ProgressBar_Horizontal 0x7f0b0087
+int style Widget_AppCompat_Spinner_DropDown_ActionBar 0x7f0b0088
+int[] styleable ActionBar { 0x7f010020, 0x7f01003e, 0x7f01003f, 0x7f010040, 0x7f010041, 0x7f010042, 0x7f010043, 0x7f010044, 0x7f010045, 0x7f010046, 0x7f010047, 0x7f010048, 0x7f010049, 0x7f01004a, 0x7f01004b, 0x7f01004c, 0x7f01004d, 0x7f01004e, 0x7f01004f }
+int styleable ActionBar_background 10
+int styleable ActionBar_backgroundSplit 12
+int styleable ActionBar_backgroundStacked 11
+int styleable ActionBar_customNavigationLayout 13
+int styleable ActionBar_displayOptions 3
+int styleable ActionBar_divider 9
+int styleable ActionBar_height 0
+int styleable ActionBar_homeLayout 14
+int styleable ActionBar_icon 7
+int styleable ActionBar_indeterminateProgressStyle 16
+int styleable ActionBar_itemPadding 18
+int styleable ActionBar_logo 8
+int styleable ActionBar_navigationMode 2
+int styleable ActionBar_progressBarPadding 17
+int styleable ActionBar_progressBarStyle 15
+int styleable ActionBar_subtitle 4
+int styleable ActionBar_subtitleTextStyle 6
+int styleable ActionBar_title 1
+int styleable ActionBar_titleTextStyle 5
+int[] styleable ActionBarLayout { 0x010100b3 }
+int styleable ActionBarLayout_android_layout_gravity 0
+int[] styleable ActionBarWindow { 0x7f010050, 0x7f010051, 0x7f010052, 0x7f010053, 0x7f010054, 0x7f010055, 0x7f010056 }
+int styleable ActionBarWindow_windowActionBar 0
+int styleable ActionBarWindow_windowActionBarOverlay 1
+int styleable ActionBarWindow_windowFixedHeightMajor 6
+int styleable ActionBarWindow_windowFixedHeightMinor 4
+int styleable ActionBarWindow_windowFixedWidthMajor 3
+int styleable ActionBarWindow_windowFixedWidthMinor 5
+int styleable ActionBarWindow_windowSplitActionBar 2
+int[] styleable ActionMenuItemView { 0x0101013f }
+int styleable ActionMenuItemView_android_minWidth 0
+int[] styleable ActionMenuView { }
+int[] styleable ActionMode { 0x7f010020, 0x7f010042, 0x7f010043, 0x7f010047, 0x7f010049 }
+int styleable ActionMode_background 3
+int styleable ActionMode_backgroundSplit 4
+int styleable ActionMode_height 0
+int styleable ActionMode_subtitleTextStyle 2
+int styleable ActionMode_titleTextStyle 1
+int[] styleable ActivityChooserView { 0x7f010057, 0x7f010058 }
+int styleable ActivityChooserView_expandActivityOverflowButtonDrawable 1
+int styleable ActivityChooserView_initialActivityCount 0
+int[] styleable CompatTextView { 0x7f010059 }
+int styleable CompatTextView_textAllCaps 0
+int[] styleable LinearLayoutICS { 0x7f010046, 0x7f01005a, 0x7f01005b }
+int styleable LinearLayoutICS_divider 0
+int styleable LinearLayoutICS_dividerPadding 2
+int styleable LinearLayoutICS_showDividers 1
+int[] styleable MenuGroup { 0x0101000e, 0x010100d0, 0x01010194, 0x010101de, 0x010101df, 0x010101e0 }
+int styleable MenuGroup_android_checkableBehavior 5
+int styleable MenuGroup_android_enabled 0
+int styleable MenuGroup_android_id 1
+int styleable MenuGroup_android_menuCategory 3
+int styleable MenuGroup_android_orderInCategory 4
+int styleable MenuGroup_android_visible 2
+int[] styleable MenuItem { 0x01010002, 0x0101000e, 0x010100d0, 0x01010106, 0x01010194, 0x010101de, 0x010101df, 0x010101e1, 0x010101e2, 0x010101e3, 0x010101e4, 0x010101e5, 0x0101026f, 0x7f01005c, 0x7f01005d, 0x7f01005e, 0x7f01005f }
+int styleable MenuItem_actionLayout 14
+int styleable MenuItem_actionProviderClass 16
+int styleable MenuItem_actionViewClass 15
+int styleable MenuItem_android_alphabeticShortcut 9
+int styleable MenuItem_android_checkable 11
+int styleable MenuItem_android_checked 3
+int styleable MenuItem_android_enabled 1
+int styleable MenuItem_android_icon 0
+int styleable MenuItem_android_id 2
+int styleable MenuItem_android_menuCategory 5
+int styleable MenuItem_android_numericShortcut 10
+int styleable MenuItem_android_onClick 12
+int styleable MenuItem_android_orderInCategory 6
+int styleable MenuItem_android_title 7
+int styleable MenuItem_android_titleCondensed 8
+int styleable MenuItem_android_visible 4
+int styleable MenuItem_showAsAction 13
+int[] styleable MenuView { 0x010100ae, 0x0101012c, 0x0101012d, 0x0101012e, 0x0101012f, 0x01010130, 0x01010131, 0x01010435 }
+int styleable MenuView_android_headerBackground 4
+int styleable MenuView_android_horizontalDivider 2
+int styleable MenuView_android_itemBackground 5
+int styleable MenuView_android_itemIconDisabledAlpha 6
+int styleable MenuView_android_itemTextAppearance 1
+int styleable MenuView_android_preserveIconSpacing 7
+int styleable MenuView_android_verticalDivider 3
+int styleable MenuView_android_windowAnimationStyle 0
+int[] styleable SearchView { 0x0101011f, 0x01010220, 0x01010264, 0x7f010060, 0x7f010061 }
+int styleable SearchView_android_imeOptions 2
+int styleable SearchView_android_inputType 1
+int styleable SearchView_android_maxWidth 0
+int styleable SearchView_iconifiedByDefault 3
+int styleable SearchView_queryHint 4
+int[] styleable Spinner { 0x010100af, 0x01010175, 0x01010176, 0x01010262, 0x010102ac, 0x010102ad, 0x7f010062, 0x7f010063, 0x7f010064, 0x7f010065 }
+int styleable Spinner_android_dropDownHorizontalOffset 4
+int styleable Spinner_android_dropDownSelector 1
+int styleable Spinner_android_dropDownVerticalOffset 5
+int styleable Spinner_android_dropDownWidth 3
+int styleable Spinner_android_gravity 0
+int styleable Spinner_android_popupBackground 2
+int styleable Spinner_disableChildrenWhenDisabled 9
+int styleable Spinner_popupPromptView 8
+int styleable Spinner_prompt 6
+int styleable Spinner_spinnerMode 7
+int[] styleable Theme { 0x7f010066, 0x7f010067, 0x7f010068, 0x7f010069, 0x7f01006a, 0x7f01006b }
+int styleable Theme_actionDropDownStyle 0
+int styleable Theme_dropdownListPreferredItemHeight 1
+int styleable Theme_listChoiceBackgroundIndicator 5
+int styleable Theme_panelMenuListTheme 4
+int styleable Theme_panelMenuListWidth 3
+int styleable Theme_popupMenuStyle 2
+int[] styleable View { 0x010100da, 0x7f01006c, 0x7f01006d }
+int styleable View_android_focusable 0
+int styleable View_paddingEnd 2
+int styleable View_paddingStart 1
--- /dev/null
+# Ignore everything in this directory
+*
+# Except this file
+!.gitignore
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="android-support-appcompat-v7-exploded-aar" default="help">
+
+ <!-- The local.properties file is created and updated by the 'android' tool.
+ It contains the path to the SDK. It should *NOT* be checked into
+ Version Control Systems. -->
+ <property file="local.properties" />
+
+ <!-- The ant.properties file can be created by you. It is only edited by the
+ 'android' tool to add properties to it.
+ This is the place to change some Ant specific build properties.
+ Here are some properties you may want to change/update:
+
+ source.dir
+ The name of the source directory. Default is 'src'.
+ out.dir
+ The name of the output directory. Default is 'bin'.
+
+ For other overridable properties, look at the beginning of the rules
+ files in the SDK, at tools/ant/build.xml
+
+ Properties related to the SDK location or the project target should
+ be updated using the 'android' tool with the 'update' action.
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems.
+
+ -->
+ <property file="ant.properties" />
+
+ <!-- if sdk.dir was not set from one of the property file, then
+ get it from the ANDROID_HOME env var.
+ This must be done before we load project.properties since
+ the proguard config can use sdk.dir -->
+ <property environment="env" />
+ <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+ <isset property="env.ANDROID_HOME" />
+ </condition>
+
+ <!-- The project.properties file is created and updated by the 'android'
+ tool, as well as ADT.
+
+ This contains project specific properties such as project target, and library
+ dependencies. Lower level build properties are stored in ant.properties
+ (or in .classpath for Eclipse projects).
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems. -->
+ <loadproperties srcFile="project.properties" />
+
+ <!-- quick check on sdk.dir -->
+ <fail
+ message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+ unless="sdk.dir"
+ />
+
+ <!--
+ Import per project custom build rules if present at the root of the project.
+ This is the place to put custom intermediary targets such as:
+ -pre-build
+ -pre-compile
+ -post-compile (This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir})
+ -post-package
+ -post-build
+ -pre-clean
+ -->
+ <import file="custom_rules.xml" optional="true" />
+
+ <!-- Import the actual build file.
+
+ To customize existing targets, there are two options:
+ - Customize only one target:
+ - copy/paste the target into this file, *before* the
+ <import> task.
+ - customize it to your needs.
+ - Customize the whole content of build.xml
+ - copy/paste the content of the rules files (minus the top node)
+ into this file, replacing the <import> task.
+ - customize to your needs.
+
+ ***********************
+ ****** IMPORTANT ******
+ ***********************
+ In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+ in order to avoid having your file be overridden by tools such as "android update project"
+ -->
+ <!-- version-tag: 1 -->
+ <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
--- /dev/null
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-16
+android.library=true
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" /><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/anim/abc_fade_in.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" /><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/anim/abc_fade_out.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:fromYDelta="50%p" android:toYDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/anim/abc_slide_in_bottom.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:fromYDelta="-50%p" android:toYDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/anim/abc_slide_in_top.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:fromYDelta="0" android:toYDelta="50%p"
+ android:duration="@android:integer/config_mediumAnimTime"/><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/anim/abc_slide_out_bottom.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:fromYDelta="0" android:toYDelta="-50%p"
+ android:duration="@android:integer/config_mediumAnimTime"/><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/anim/abc_slide_out_top.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:color="@color/abc_search_url_text_pressed"/>
+ <item android:state_selected="true" android:color="@color/abc_search_url_text_selected"/>
+ <item android:color="@color/abc_search_url_text_normal"/> <!-- not selected -->
+</selector><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/color/abc_search_url_text_holo.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:drawable="@drawable/abc_ic_clear_disabled" />
+ <item
+ android:drawable="@drawable/abc_ic_clear_normal" />
+</selector>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_ic_clear.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:drawable="@drawable/abc_ic_clear_search_api_disabled_holo_light" />
+ <item
+ android:drawable="@drawable/abc_ic_clear_search_api_holo_light" />
+</selector>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_ic_clear_holo_light.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+ <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_disabled_holo_dark" />
+ <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/abc_list_selector_disabled_holo_dark" />
+ <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_background_transition_holo_dark" />
+ <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_background_transition_holo_dark" />
+ <item android:state_focused="true" android:drawable="@drawable/abc_list_focused_holo" />
+ <item android:drawable="@android:color/transparent" />
+</selector>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_item_background_holo_dark.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+ <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_disabled_holo_light" />
+ <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/abc_list_selector_disabled_holo_light" />
+ <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_background_transition_holo_light" />
+ <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_background_transition_holo_light" />
+ <item android:state_focused="true" android:drawable="@drawable/abc_list_focused_holo" />
+ <item android:drawable="@android:color/transparent" />
+</selector>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_item_background_holo_light.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/abc_list_pressed_holo_dark" />
+ <item android:drawable="@drawable/abc_list_longpressed_holo" />
+</transition>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_list_selector_background_transition_holo_dark.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/abc_list_pressed_holo_light" />
+ <item android:drawable="@drawable/abc_list_longpressed_holo" />
+</transition>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_list_selector_background_transition_holo_light.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
+
+ <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+ <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_disabled_holo_dark" />
+ <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/abc_list_selector_disabled_holo_dark" />
+ <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_background_transition_holo_dark" />
+ <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_background_transition_holo_dark" />
+ <item android:state_focused="true" android:drawable="@drawable/abc_list_focused_holo" />
+</selector>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_list_selector_holo_dark.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
+
+ <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+ <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_disabled_holo_light" />
+ <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/abc_list_selector_disabled_holo_light" />
+ <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_background_transition_holo_light" />
+ <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_background_transition_holo_light" />
+ <item android:state_focused="true" android:drawable="@drawable/abc_list_focused_holo" />
+
+</selector>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_list_selector_holo_light.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="#F0A0A0A0"/>
+ <stroke android:width="2dp" color="#A00080FF"/>
+ <padding android:left="5dp" android:top="0dp"
+ android:right="5dp" android:bottom="1dp" />
+</shape>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_search_dropdown_dark.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="#F0FFFFFF"/>
+ <stroke android:width="1dp" color="#A00080FF"/>
+ <padding android:left="5dp" android:top="0dp"
+ android:right="5dp" android:bottom="1dp" />
+</shape>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_search_dropdown_light.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:drawable="@drawable/abc_spinner_ab_disabled_holo_dark" />
+ <item android:state_pressed="true"
+ android:drawable="@drawable/abc_spinner_ab_pressed_holo_dark" />
+ <item android:state_pressed="false" android:state_focused="true"
+ android:drawable="@drawable/abc_spinner_ab_focused_holo_dark" />
+ <item android:drawable="@drawable/abc_spinner_ab_default_holo_dark" />
+</selector>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_spinner_ab_holo_dark.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:drawable="@drawable/abc_spinner_ab_disabled_holo_light" />
+ <item android:state_pressed="true"
+ android:drawable="@drawable/abc_spinner_ab_pressed_holo_light" />
+ <item android:state_pressed="false" android:state_focused="true"
+ android:drawable="@drawable/abc_spinner_ab_focused_holo_light" />
+ <item android:drawable="@drawable/abc_spinner_ab_default_holo_light" />
+</selector>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_spinner_ab_holo_light.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Non focused states -->
+ <item android:state_focused="false" android:state_selected="false" android:state_pressed="false" android:drawable="@android:color/transparent" />
+ <item android:state_focused="false" android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/abc_tab_selected_holo" />
+
+ <!-- Focused states -->
+ <item android:state_focused="true" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/abc_list_focused_holo" />
+ <item android:state_focused="true" android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/abc_tab_selected_focused_holo" />
+
+ <!-- Pressed -->
+ <!-- Non focused states -->
+ <item android:state_focused="false" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/abc_list_pressed_holo_dark" />
+ <item android:state_focused="false" android:state_selected="true" android:state_pressed="true" android:drawable="@drawable/abc_tab_selected_pressed_holo" />
+
+ <!-- Focused states -->
+ <item android:state_focused="true" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/abc_tab_unselected_pressed_holo" />
+ <item android:state_focused="true" android:state_selected="true" android:state_pressed="true" android:drawable="@drawable/abc_tab_selected_pressed_holo" />
+</selector>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_tab_indicator_ab_holo.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true"
+ android:drawable="@drawable/abc_textfield_search_selected_holo_dark" />
+ <item android:drawable="@drawable/abc_textfield_search_default_holo_dark" />
+</selector>
+
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_textfield_searchview_holo_dark.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true"
+ android:drawable="@drawable/abc_textfield_search_selected_holo_light" />
+ <item android:drawable="@drawable/abc_textfield_search_default_holo_light" />
+</selector>
+
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_textfield_searchview_holo_light.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true"
+ android:drawable="@drawable/abc_textfield_search_right_selected_holo_dark" />
+ <item android:drawable="@drawable/abc_textfield_search_right_default_holo_dark" />
+</selector>
+
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_textfield_searchview_right_holo_dark.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true"
+ android:drawable="@drawable/abc_textfield_search_right_selected_holo_light" />
+ <item android:drawable="@drawable/abc_textfield_search_right_default_holo_light" />
+</selector>
+
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/drawable/abc_textfield_searchview_right_holo_light.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<android.support.v7.internal.widget.NativeActionModeAwareLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/action_bar_root"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+
+ <include layout="@layout/abc_action_bar_decor_include" />
+
+</android.support.v7.internal.widget.NativeActionModeAwareLayout>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout-v11/abc_action_bar_decor.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<android.support.v7.internal.widget.NativeActionModeAwareLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/action_bar_root"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+
+ <FrameLayout
+ android:id="@id/action_bar_activity_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:foreground="?android:attr/windowContentOverlay"/>
+
+</android.support.v7.internal.widget.NativeActionModeAwareLayout>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout-v11/abc_simple_decor.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2013, 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.
+*/
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/activity_chooser_view_content"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ style="?attr/activityChooserViewStyle">
+
+ <include layout="@layout/abc_activity_chooser_view_include" />
+
+</LinearLayout><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout-v14/abc_activity_chooser_view.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+
+ <include layout="@layout/abc_action_bar_decor_include" />
+
+</LinearLayout>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_bar_decor.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <android.support.v7.internal.widget.ActionBarContainer
+ android:id="@+id/action_bar_container"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="?attr/actionBarStyle">
+
+ <android.support.v7.internal.widget.ActionBarView
+ android:id="@+id/action_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="?attr/actionBarStyle" />
+
+ <android.support.v7.internal.widget.ActionBarContextView
+ android:id="@+id/action_context_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ style="?attr/actionModeStyle" />
+ </android.support.v7.internal.widget.ActionBarContainer>
+
+ <FrameLayout
+ android:id="@id/action_bar_activity_content"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:foregroundGravity="fill_horizontal|top"
+ android:foreground="?android:attr/windowContentOverlay" />
+
+ <android.support.v7.internal.widget.ActionBarContainer
+ android:id="@+id/split_action_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="?attr/actionBarSplitStyle"
+ android:visibility="gone"
+ android:gravity="center" />
+
+</merge>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_bar_decor_include.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<android.support.v7.internal.widget.ActionBarOverlayLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/action_bar_overlay_layout"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <FrameLayout android:id="@id/action_bar_activity_content"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"/>
+ <LinearLayout android:id="@+id/top_action_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top">
+ <android.support.v7.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ style="?attr/actionBarStyle"
+ android:gravity="top">
+ <android.support.v7.internal.widget.ActionBarView
+ android:id="@+id/action_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="?attr/actionBarStyle"/>
+ <android.support.v7.internal.widget.ActionBarContextView
+ android:id="@+id/action_context_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ style="?attr/actionModeStyle"/>
+ </android.support.v7.internal.widget.ActionBarContainer>
+ <ImageView android:src="?android:attr/windowContentOverlay"
+ android:scaleType="fitXY"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
+ <android.support.v7.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ style="?attr/actionBarSplitStyle"
+ android:visibility="gone"
+ android:gravity="center"/>
+</android.support.v7.internal.widget.ActionBarOverlayLayout>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_bar_decor_overlay.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+ class="android.support.v7.internal.widget.ActionBarView$HomeView"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:background="?attr/actionBarItemBackground">
+ <ImageView android:id="@+id/up"
+ android:src="?attr/homeAsUpIndicator"
+ android:layout_gravity="center_vertical|left"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="-8dip"/>
+ <ImageView android:id="@id/home"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="8dip"
+ android:layout_marginTop="@dimen/abc_action_bar_icon_vertical_padding"
+ android:layout_marginBottom="@dimen/abc_action_bar_icon_vertical_padding"
+ android:layout_gravity="center"
+ android:adjustViewBounds="true"
+ android:scaleType="fitCenter"/>
+</view>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_bar_home.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+ class="android.support.v7.internal.widget.ScrollingTabContainerView$TabView"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ style="?attr/actionBarTabStyle"/>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_bar_tab.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<android.support.v7.internal.widget.LinearLayoutICS
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ style="?attr/actionBarTabBarStyle"/>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_bar_tabbar.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingRight="8dip"
+ android:background="?attr/actionBarItemBackground"
+ android:enabled="false">
+
+ <ImageView android:id="@+id/up"
+ android:src="?attr/homeAsUpIndicator"
+ android:layout_gravity="center_vertical|left"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <LinearLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|left"
+ android:orientation="vertical">
+ <TextView android:id="@+id/action_bar_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"/>
+ <TextView android:id="@+id/action_bar_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/abc_action_bar_subtitle_top_margin"
+ android:layout_marginBottom="@dimen/abc_action_bar_subtitle_bottom_margin"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"/>
+ </LinearLayout>
+</LinearLayout>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_bar_title_item.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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
+ dd
+ 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.
+-->
+
+<!-- Styled linear layout, compensating for the lack of a defStyle parameter
+ in pre-Honeycomb LinearLayout's constructor. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ style="?attr/actionBarTabBarStyle">
+</LinearLayout><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_bar_view_list_nav_layout.xml -->
\ No newline at end of file
--- /dev/null
+<?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
+ dd
+ 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.
+-->
+
+<android.support.v7.internal.view.menu.ActionMenuItemView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:focusable="true"
+ android:paddingTop="4dip"
+ android:paddingBottom="4dip"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:textAppearance="?attr/actionMenuTextAppearance"
+ android:textColor="?attr/actionMenuTextColor"
+ style="?attr/actionButtonStyle"/>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_menu_item_layout.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<android.support.v7.internal.view.menu.ActionMenuView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:divider="?attr/actionBarDivider"
+ app:dividerPadding="12dip"
+ android:gravity="center_vertical"/>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_menu_layout.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, 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.
+*/
+-->
+<android.support.v7.internal.widget.ActionBarContextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ style="?attr/actionModeStyle"/>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_mode_bar.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/action_mode_close_button"
+ android:focusable="true"
+ android:clickable="true"
+ android:paddingLeft="8dip"
+ android:contentDescription="@string/abc_action_mode_done"
+ style="?attr/actionModeCloseButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:layout_marginRight="16dip">
+ <ImageView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:scaleType="fitCenter"
+ android:src="?attr/actionModeCloseDrawable"/>
+</LinearLayout>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_action_mode_close_item.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2013, 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.
+*/
+-->
+<android.support.v7.internal.widget.LinearLayoutICS
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/activity_chooser_view_content"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ style="?attr/activityChooserViewStyle">
+
+ <include layout="@layout/abc_activity_chooser_view_include" />
+
+</android.support.v7.internal.widget.LinearLayoutICS><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_activity_chooser_view.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2013, 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.
+*/
+-->
+<merge
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <FrameLayout
+ android:id="@+id/expand_activities_button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:focusable="true"
+ android:addStatesFromChildren="true"
+ android:background="?attr/actionBarItemBackground">
+
+ <ImageView
+ android:id="@+id/image"
+ android:layout_width="56dip"
+ android:layout_height="36dip"
+ android:layout_gravity="center"
+ android:paddingTop="2dip"
+ android:paddingBottom="2dip"
+ android:paddingLeft="12dip"
+ android:paddingRight="12dip"
+ android:scaleType="fitCenter"
+ android:adjustViewBounds="true" />
+
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/default_activity_button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:focusable="true"
+ android:addStatesFromChildren="true"
+ android:background="?attr/actionBarItemBackground">
+
+ <ImageView
+ android:id="@+id/image"
+ android:layout_width="56dip"
+ android:layout_height="36dip"
+ android:layout_gravity="center"
+ android:paddingTop="2dip"
+ android:paddingBottom="2dip"
+ android:paddingLeft="12dip"
+ android:paddingRight="12dip"
+ android:scaleType="fitCenter"
+ android:adjustViewBounds="true" />
+
+ </FrameLayout>
+
+</merge><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_activity_chooser_view_include.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/list_item"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/dropdownListPreferredItemHeight"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:minWidth="196dip"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:duplicateParentState="true" >
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="32dip"
+ android:layout_height="32dip"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="8dip"
+ android:duplicateParentState="true"/>
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?attr/textAppearanceLargePopupMenu"
+ android:duplicateParentState="true"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"/>
+
+ </LinearLayout>
+
+</LinearLayout><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_activity_chooser_view_list_item.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<android.support.v7.internal.view.menu.ExpandedMenuView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/expanded_menu"
+ android:layout_width="?attr/panelMenuListWidth"
+ android:layout_height="wrap_content"/>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_expanded_menu_layout.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:focusable="false"
+ android:clickable="false"
+ android:duplicateParentState="true"/>
+
+
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_list_menu_item_checkbox.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="-8dip"
+ android:layout_marginTop="8dip"
+ android:layout_marginBottom="8dip"
+ android:scaleType="centerInside"
+ android:duplicateParentState="true"/>
+
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_list_menu_item_icon.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<android.support.v7.internal.view.menu.ListMenuItemView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/listPreferredItemHeightSmall">
+
+ <!-- Icon will be inserted here. -->
+
+ <!-- The title and summary have some gap between them, and this 'group' should be centered vertically. -->
+ <RelativeLayout
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
+ android:layout_marginRight="?attr/listPreferredItemPaddingRight"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:duplicateParentState="true">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:textAppearance="?attr/textAppearanceListItemSmall"
+ android:singleLine="true"
+ android:duplicateParentState="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView
+ android:id="@+id/shortcut"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/title"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:singleLine="true"
+ android:duplicateParentState="true" />
+
+ </RelativeLayout>
+
+ <!-- Checkbox, and/or radio button will be inserted here. -->
+
+</android.support.v7.internal.view.menu.ListMenuItemView>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_list_menu_item_layout.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/radio"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:focusable="false"
+ android:clickable="false"
+ android:duplicateParentState="true"/>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_list_menu_item_radio.xml -->
\ No newline at end of file
--- /dev/null
+<?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.
+-->
+
+<android.support.v7.internal.view.menu.ListMenuItemView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?attr/dropdownListPreferredItemHeight"
+ android:minWidth="196dip"
+ android:paddingRight="16dip">
+
+ <!-- Icon will be inserted here. -->
+
+ <!-- The title and summary have some gap between them, and this 'group' should be centered vertically. -->
+ <RelativeLayout
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="16dip"
+ android:duplicateParentState="true">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:textAppearance="?attr/textAppearanceLargePopupMenu"
+ android:singleLine="true"
+ android:duplicateParentState="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"/>
+
+ <TextView
+ android:id="@+id/shortcut"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/title"
+ android:layout_alignParentLeft="true"
+ android:textAppearance="?attr/textAppearanceSmallPopupMenu"
+ android:singleLine="true"
+ android:duplicateParentState="true"/>
+
+ </RelativeLayout>
+
+ <!-- Checkbox, and/or radio button will be inserted here. -->
+
+</android.support.v7.internal.view.menu.ListMenuItemView>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2013 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.
+ */
+
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingLeft="@dimen/abc_dropdownitem_text_padding_left"
+ android:paddingRight="4dip"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/searchResultListItemHeight" >
+
+ <!-- Icons come first in the layout, since their placement doesn't depend on
+ the placement of the text views. -->
+ <ImageView android:id="@android:id/icon1"
+ android:layout_width="@dimen/abc_dropdownitem_icon_width"
+ android:layout_height="48dip"
+ android:scaleType="centerInside"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:visibility="invisible" />
+
+ <ImageView android:id="@+id/edit_query"
+ android:layout_width="48dip"
+ android:layout_height="48dip"
+ android:scaleType="centerInside"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:src="?attr/searchViewEditQuery"
+ android:background="?attr/searchViewEditQueryBackground"
+ android:visibility="gone" />
+
+ <ImageView android:id="@android:id/icon2"
+ android:layout_width="48dip"
+ android:layout_height="48dip"
+ android:scaleType="centerInside"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_toLeftOf="@id/edit_query"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:visibility="gone" />
+
+
+ <!-- The subtitle comes before the title, since the height of the title depends on whether the
+ subtitle is visible or gone. -->
+ <TextView android:id="@android:id/text2"
+ style="?android:attr/dropDownItemStyle"
+ android:textAppearance="?attr/textAppearanceSearchResultSubtitle"
+ android:singleLine="true"
+ android:layout_width="match_parent"
+ android:layout_height="29dip"
+ android:paddingBottom="4dip"
+ android:gravity="top"
+ android:layout_toRightOf="@android:id/icon1"
+ android:layout_toLeftOf="@android:id/icon2"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_alignParentBottom="true"
+ android:visibility="gone" />
+
+ <!-- The title is placed above the subtitle, if there is one. If there is no
+ subtitle, it fills the parent. -->
+ <TextView android:id="@android:id/text1"
+ style="?android:attr/dropDownItemStyle"
+ android:textAppearance="?attr/textAppearanceSearchResultTitle"
+ android:singleLine="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@android:id/icon1"
+ android:layout_toLeftOf="@android:id/icon2"
+ android:layout_above="@android:id/text2" />
+
+</RelativeLayout><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2013 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.
+ */
+
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/search_bar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ >
+
+ <!-- This is actually used for the badge icon *or* the badge label (or neither) -->
+ <TextView
+ android:id="@+id/search_badge"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:layout_marginBottom="2dip"
+ android:drawablePadding="0dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorPrimary"
+ android:visibility="gone"
+ />
+
+ <ImageView
+ android:id="@+id/search_button"
+ style="?attr/actionButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:src="?attr/searchViewSearchIcon"
+ android:focusable="true"
+ android:contentDescription="@string/abc_searchview_description_search"
+ />
+
+ <LinearLayout
+ android:id="@+id/search_edit_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:layout_marginTop="4dip"
+ android:layout_marginBottom="4dip"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="8dip"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/search_mag_icon"
+ android:layout_width="@dimen/abc_dropdownitem_icon_width"
+ android:layout_height="wrap_content"
+ android:scaleType="centerInside"
+ android:layout_marginLeft="@dimen/abc_dropdownitem_text_padding_left"
+ android:layout_gravity="center_vertical"
+ android:src="?attr/searchViewSearchIcon"
+ android:visibility="gone"
+ />
+
+ <!-- Inner layout contains the app icon, button(s) and EditText -->
+ <LinearLayout
+ android:id="@+id/search_plate"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:orientation="horizontal"
+ android:background="?attr/searchViewTextField">
+
+ <view class="android.support.v7.widget.SearchView$SearchAutoComplete"
+ style="?attr/searchViewAutoCompleteTextView"
+ android:id="@+id/search_src_text"
+ android:layout_height="36dip"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:minWidth="@dimen/abc_search_view_text_min_width"
+ android:layout_gravity="bottom"
+ android:paddingLeft="@dimen/abc_dropdownitem_text_padding_left"
+ android:paddingRight="@dimen/abc_dropdownitem_text_padding_right"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:background="@null"
+ android:inputType="text|textAutoComplete|textNoSuggestions"
+ android:imeOptions="actionSearch"
+ android:dropDownHeight="wrap_content"
+ android:dropDownAnchor="@id/search_edit_frame"
+ android:dropDownVerticalOffset="0dip"
+ android:dropDownHorizontalOffset="0dip"
+ android:contentDescription="@string/abc_searchview_description_query"
+ />
+
+ <ImageView
+ android:id="@+id/search_close_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:layout_gravity="center_vertical"
+ android:background="?attr/selectableItemBackground"
+ android:src="?attr/searchViewCloseIcon"
+ android:focusable="true"
+ android:contentDescription="@string/abc_searchview_description_clear"
+ />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/submit_area"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="?attr/searchViewTextFieldRight">
+
+ <ImageView
+ android:id="@+id/search_go_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:background="?attr/selectableItemBackground"
+ android:src="?attr/searchViewGoIcon"
+ android:visibility="gone"
+ android:focusable="true"
+ android:contentDescription="@string/abc_searchview_description_submit"
+ />
+
+ <ImageView
+ android:id="@+id/search_voice_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:src="?attr/searchViewVoiceIcon"
+ android:background="?attr/selectableItemBackground"
+ android:visibility="gone"
+ android:focusable="true"
+ android:contentDescription="@string/abc_searchview_description_voice"
+ />
+ </LinearLayout>
+ </LinearLayout>
+
+</LinearLayout><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_search_view.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/action_bar_root"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+
+ <FrameLayout
+ android:id="@id/action_bar_activity_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:foreground="?android:attr/windowContentOverlay"/>
+
+</LinearLayout>
+<!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/abc_simple_decor.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2008, 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.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ style="?attr/spinnerDropDownItemStyle"
+ android:singleLine="true"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/dropdownListPreferredItemHeight"
+ android:ellipsize="marquee"/><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/layout/support_simple_spinner_dropdown_item.xml -->
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-af/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navigeer tuis"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navigeer op"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Nog opsies"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Klaar"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Sien alles"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Kies \'n program"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Vee navraag uit"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Soeknavraag"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Soek"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Dien navraag in"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Stemsoektog"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Deel met"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Deel met %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-am/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"ወደ መነሻ ይዳስሱ"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ወደ ላይ ይዳስሱ"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"ተጨማሪ አማራጮች"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"ተከናውኗል"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"ሁሉንም ይመልከቱ"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"መተግበሪያ ይምረጡ"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"መጠይቅ አጽዳ"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"የፍለጋ ጥያቄ"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"ፍለጋ"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"መጠይቅ ያስረክቡ"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"የድምፅ ፍለጋ"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ከሚከተለው ጋር ያጋሩ"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"ከ%s ጋር ያጋሩ"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-ar/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"التنقل إلى الشاشة الرئيسية"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"التنقل إلى أعلى"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"خيارات إضافية"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"تم"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"عرض الكل"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"اختيار تطبيق"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"محو طلب البحث"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"طلب البحث"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"بحث"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"إرسال طلب البحث"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"البحث الصوتي"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"مشاركة مع"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"مشاركة مع %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-bg/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Придвижване към „Начало“"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Придвижване нагоре"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Още опции"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Готово"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Вижте всички"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Изберете приложение"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Изчистване на заявката"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Заявка за търсене"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Търсене"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Изпращане на заявката"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Гласово търсене"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Споделяне със:"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Споделяне със: %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-ca/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navega a la pàgina d\'inici"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navega cap a dalt"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Més opcions"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Fet"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Mostra\'ls tots"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Selecciona una aplicació"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Esborra la consulta"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Consulta de cerca"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Cerca"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Envia la consulta"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Cerca per veu"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Comparteix amb"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Comparteix amb %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-cs/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Přejít na plochu"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Přejít nahoru"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Více možností"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Hotovo"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Zobrazit vše"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Vybrat aplikaci"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Smazat dotaz"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Vyhledávací dotaz"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Hledat"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Odeslat dotaz"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Hlasové vyhledávání"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Sdílet pomocí"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Sdílet pomocí %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-da/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Naviger hjem"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Naviger op"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Flere muligheder"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Luk"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Se alle"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Vælg en app"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Ryd forespørgslen"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Søgeforespørgsel"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Søg"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Indsend forespørgslen"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Stemmesøgning"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Del med"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Del med %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-de/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Zur Startseite"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Nach oben"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Weitere Optionen"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Fertig"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Alle ansehen"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"App auswählen"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Suchanfrage löschen"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Suchanfrage"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Suchen"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Suchanfrage senden"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Sprachsuche"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Freigeben für"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Freigeben für %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-el/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Πλοήγηση στην αρχική σελίδα"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Πλοήγηση προς τα επάνω"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Περισσότερες επιλογές"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Τέλος"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Προβολή όλων"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Επιλέξτε κάποια εφαρμογή"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Διαγραφή ερωτήματος"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Ερώτημα αναζήτησης"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Αναζήτηση"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Υποβολή ερωτήματος"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Φωνητική αναζήτηση"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Κοινή χρήση με"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Κοινή χρήση με %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-en-rGB/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navigate home"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navigate up"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"More options"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Finished"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"See all"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Choose an app"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Clear query"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Search query"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Search"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Submit query"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Voice search"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Share with"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Share with %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-en-rIN/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navigate home"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navigate up"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"More options"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Finished"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"See all"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Choose an app"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Clear query"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Search query"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Search"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Submit query"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Voice search"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Share with"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Share with %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-es-rUS/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navegar a la página principal"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navegar hacia arriba"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Más opciones"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Listo"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Ver todo"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Elige una aplicación."</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Eliminar la consulta"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Consulta de búsqueda"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Búsqueda"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Enviar consulta"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Búsqueda por voz"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartir con"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartir con %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-es/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Ir a la pantalla de inicio"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Desplazarse hacia arriba"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Más opciones"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Listo"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Ver todo"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Seleccionar una aplicación"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Borrar consulta"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Consulta"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Buscar"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Enviar consulta"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Búsqueda por voz"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartir con"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartir con %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-et-rEE/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navigeerimine avaekraanile"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navigeerimine üles"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Rohkem valikuid"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Valmis"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Kuva kõik"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Valige rakendus"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Päringu tühistamine"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Otsingupäring"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Otsing"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Päringu esitamine"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Häälotsing"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Jagamine:"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Jagamine kasutajaga %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-fa/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"پیمایش به صفحه اصلی"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"پیمایش به بالا"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"گزینههای بیشتر"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"انجام شد"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"مشاهده همه"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"انتخاب برنامه"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"پاک کردن عبارت جستجو"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"عبارت جستجو"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"جستجو"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ارسال عبارت جستجو"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"جستجوی شفاهی"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"اشتراکگذاری با"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"اشتراکگذاری با %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-fi/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Siirry etusivulle"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Siirry ylös"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Lisää"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Valmis"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Näytä kaikki"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Valitse sovellus"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Tyhjennä kysely"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Hakulauseke"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Haku"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Lähetä kysely"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Puhehaku"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Jakaminen:"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Jakaminen: %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-fr-rCA/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Revenir à l\'accueil"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Revenir en haut de la page"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Plus d\'options"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Terminé"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Voir toutes les chaînes"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Sélectionnez une application"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Effacer la requête"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Requête de recherche"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Rechercher"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Envoyer la requête"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Recherche vocale"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partager avec"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partager avec %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-fr/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Revenir à l\'accueil"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Revenir en haut de la page"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Plus d\'options"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"OK"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Tout afficher"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Sélectionner une application"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Effacer la requête"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Requête de recherche"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Rechercher"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Envoyer la requête"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Recherche vocale"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partager avec"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partager avec %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-hi/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"मुखपृष्ठ पर नेविगेट करें"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ऊपर नेविगेट करें"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"अधिक विकल्प"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"पूर्ण"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"सभी देखें"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"कोई एप्लिकेशन चुनें"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"क्वेरी साफ़ करें"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"खोज क्वेरी"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"खोजें"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"क्वेरी सबमिट करें"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"ध्वनि खोज"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"इसके द्वारा साझा करें"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s के साथ साझा करें"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-hr/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Idi na početnu"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Idi gore"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Dodatne opcije"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Gotovo"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Prikaži sve"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Odabir aplikacije"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Izbriši upit"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Upit za pretraživanje"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Pretraživanje"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Pošalji upit"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Glasovno pretraživanje"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Dijeljenje sa"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Dijeljenje sa: %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-hu/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Ugrás a főoldalra"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Felfelé mozgatás"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"További lehetőségek"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Kész"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Összes megtekintése"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Válasszon ki egy alkalmazást"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Lekérdezés törlése"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Keresési lekérdezés"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Keresés"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Lekérdezés küldése"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Hangalapú keresés"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Megosztás a következővel:"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Megosztás a következővel: %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-hy-rAM/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Ուղղվել տուն"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Ուղղվել վերև"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Այլ ընտրանքներ"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Կատարված է"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Տեսնել բոլորը"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Ընտրել ծրագիր"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Մաքրել հարցումը"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Որոնման հարցում"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Որոնել"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Ուղարկել հարցումը"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Ձայնային որոնում"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Տարածել"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Տարածել ըստ %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-in/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navigasi ke beranda"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navigasi naik"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Opsi lain"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Selesai"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Lihat semua"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Pilih aplikasi"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Hapus kueri"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Kueri penelusuran"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Telusuri"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Kirim kueri"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Penelusuran suara"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bagikan dengan"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Bagikan dengan %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-it/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Vai alla home page"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Vai in alto"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Altre opzioni"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Fine"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Visualizza tutte"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Scegli un\'applicazione"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Cancella query"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Query di ricerca"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Cerca"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Invia query"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Ricerca vocale"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Condividi con"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Condividi con %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-iw/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"נווט לדף הבית"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"נווט למעלה"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"עוד אפשרויות"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"בוצע"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"ראה הכול"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"בחר אפליקציה"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"מחק שאילתה"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"שאילתת חיפוש"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"חפש"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"שלח שאילתה"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"חיפוש קולי"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"שתף עם"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"שתף עם %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-ja/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"ホームへ移動"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"上へ移動"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"その他のオプション"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"完了"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"すべて表示"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"アプリの選択"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"検索キーワードを削除"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"検索キーワード"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"検索"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"検索キーワードを送信"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"音声検索"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"共有"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%sと共有"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-ka-rGE/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"მთავარზე ნავიგაცია"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ზემოთ ნავიგაცია"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"მეტი ვარიანტები"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"დასრულდა"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"ყველას ნახვა"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"აპის არჩევა"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"მოთხოვნის გასუფთავება"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"ძიების მოთხოვნა"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"ძიება"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"მოთხოვნის გადაგზავნა"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"ხმოვანი ძიება"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"გაზიარება:"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s-თან გაზიარება"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-km-rKH/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"រកមើលទៅដើម"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"រកមើលឡើងលើ"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"ជម្រើសច្រើនទៀត"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"រួចរាល់"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"មើលទាំងអស់"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"ជ្រើសកម្មវិធី"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"សម្អាតសំណួរ"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"ស្វែងរកសំណួរ"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"ស្វែងរក"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ដាក់ស្នើសំណួរ"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"ការស្វែងរកសំឡេង"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ចែករំលែកជាមួយ"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"ចែករំលែកជាមួយ %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-ko/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"홈 탐색"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"위로 탐색"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"옵션 더보기"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"완료"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"전체 보기"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"앱 선택"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"검색어 삭제"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"검색어"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"검색"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"검색어 보내기"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"음성 검색"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"공유 대상"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s와(과) 공유"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-land/bools.xml -->
+ <eat-comment />
+
+ <bool name="abc_action_bar_embed_tabs_pre_jb">true</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-land/config.xml -->
+ <eat-comment />
+
+ <bool name="abc_config_allowActionMenuItemTextWithIcon">true</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-land/bools.xml -->
+ <eat-comment />
+
+ <bool name="abc_split_action_bar_is_narrow">false</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-land/dimens.xml -->
+ <eat-comment />
+
+ <dimen name="abc_action_bar_default_height">40dip</dimen>
+ <dimen name="abc_action_bar_icon_vertical_padding">4dip</dimen>
+ <dimen name="abc_action_bar_progress_bar_size">32dp</dimen>
+ <dimen name="abc_action_bar_subtitle_bottom_margin">4dip</dimen>
+ <dimen name="abc_action_bar_subtitle_text_size">12dp</dimen>
+ <dimen name="abc_action_bar_subtitle_top_margin">-2dp</dimen>
+ <dimen name="abc_action_bar_title_text_size">16dp</dimen>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-large-v14/themes_base.xml -->
+ <eat-comment />
+
+ <style name="Theme.Base.AppCompat.DialogWhenLarge" parent="Theme.Base.AppCompat.DialogWhenLarge.Base" />
+
+ <style name="Theme.Base.AppCompat.Light.DialogWhenLarge" parent="Theme.Base.AppCompat.Light.DialogWhenLarge.Base" />
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-large/bools.xml -->
+ <eat-comment />
+
+ <bool name="abc_action_bar_embed_tabs_pre_jb">true</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-large/config.xml -->
+ <eat-comment />
+
+ <bool name="abc_config_allowActionMenuItemTextWithIcon">true</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-large/bools.xml -->
+ <eat-comment />
+
+ <bool name="abc_split_action_bar_is_narrow">false</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-large/config.xml -->
+ <eat-comment />
+
+ <dimen name="abc_config_prefDialogWidth">440dp</dimen>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-large/dimens.xml -->
+ <eat-comment />
+
+ <dimen name="abc_search_view_text_min_width">192dip</dimen>
+
+ <item name="dialog_fixed_height_major" type="dimen">60%</item>
+ <item name="dialog_fixed_height_minor" type="dimen">90%</item>
+ <item name="dialog_fixed_width_major" type="dimen">60%</item>
+ <item name="dialog_fixed_width_minor" type="dimen">90%</item>
+
+ <integer name="abc_max_action_buttons">4</integer>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-large/themes_base.xml -->
+ <eat-comment />
+
+ <style name="Theme.Base.AppCompat.DialogWhenLarge" parent="Theme.Base.AppCompat.Dialog.FixedSize" />
+
+ <style name="Theme.Base.AppCompat.Light.DialogWhenLarge" parent="Theme.Base.AppCompat.Dialog.Light.FixedSize" />
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-lo-rLA/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"ກັບໄປໜ້າຫຼັກ"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ຂຶ້ນເທິງ"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"ໂຕເລືອກອື່ນ"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"ແລ້ວໆ"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"ເບິ່ງທັງຫມົດ"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"ເລືອກແອັບຯ"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"ລຶບຂໍ້ຄວາມຊອກຫາ"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"ຊອກຫາ"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"ຊອກຫາ"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ສົ່ງການຊອກຫາ"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"ຊອກຫາດ້ວຍສຽງ"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ແບ່ງປັນກັບ"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"ແບ່ງປັນກັບ %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-lt/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Eiti į pagrindinį puslapį"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Eiti į viršų"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Daugiau parinkčių"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Atlikta"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Peržiūrėti viską"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Pasirinkti programą"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Išvalyti užklausą"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Paieškos užklausa"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Paieška"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Pateikti užklausą"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Paieška balsu"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bendrinti naudojant"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Bendrinti naudojant „%s“"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-lv/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Pārvietoties uz sākuma ekrānu"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Pārvietoties augšup"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Vairāk opciju"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Gatavs"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Skatīt visu"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Izvēlieties lietotni"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Notīrīt vaicājumu"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Meklēšanas vaicājums"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Meklēt"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Iesniegt vaicājumu"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Meklēšana ar balsi"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Kopīgot ar:"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Kopīgot ar %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-mn-rMN/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Нүүр хуудас руу шилжих"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Дээш шилжих"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Нэмэлт сонголтууд"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Дууссан"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Бүгдийг харах"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Апп сонгох"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Асуулгыг цэвэрлэх"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Хайх асуулга"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Хайх"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Асуулгыг илгээх"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Дуут хайлт"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Хуваалцах"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s-тай хуваалцах"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-ms-rMY/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navigasi skrin utama"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navigasi ke atas"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Lagi pilihan"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Selesai"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Lihat semua"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Pilih apl"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Kosongkan pertanyaan"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Pertanyaan carian"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Cari"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Serah pertanyaan"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Carian suara"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Kongsi dengan"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Kongsi dengan %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-nb/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Gå til startsiden"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Gå opp"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Flere alternativer"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Fullført"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Se alle"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Velg en app"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Slett søket"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Søkeord"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Søk"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Utfør søket"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Talesøk"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Del med"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Del med %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-nl/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navigeren naar startpositie"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Omhoog navigeren"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Meer opties"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Gereed"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Alles weergeven"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Een app selecteren"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Zoekopdracht wissen"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Zoekopdracht"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Zoeken"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Zoekopdracht verzenden"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Gesproken zoekopdracht"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Delen met"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Delen met %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-pl/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Przejdź do strony głównej"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Przejdź wyżej"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Więcej opcji"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Gotowe"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Zobacz wszystkie"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Wybierz aplikację"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Wyczyść zapytanie"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Wyszukiwane hasło"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Szukaj"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Wyślij zapytanie"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Wyszukiwanie głosowe"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Udostępnij dla"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Udostępnij dla %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-pt-rPT/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navegar para a página inicial"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navegar para cima"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Mais opções"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Concluído"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Ver tudo"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Escolher uma aplicação"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Limpar consulta"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Consulta de pesquisa"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Pesquisar"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Enviar consulta"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Pesquisa por voz"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partilhar com"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partilhar com %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-pt/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navegar para a página inicial"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navegar para cima"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Mais opções"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Concluído"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Ver tudo"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Selecione um aplicativo"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Limpar consulta"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Consulta de pesquisa"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Pesquisar"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Enviar consulta"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Pesquisa por voz"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartilhar com"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartilhar com %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-ro/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Navigați la ecranul de pornire"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navigați în sus"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Mai multe opțiuni"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Terminat"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Afișați-le pe toate"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Alegeți o aplicaţie"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Ștergeți interogarea"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Interogare de căutare"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Căutați"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Trimiteți interogarea"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Căutare vocală"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Trimiteți la"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Trimiteți la %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-ru/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Перейти на главный экран"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Перейти вверх"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Другие параметры"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Готово"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Показать все"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Выбрать приложение"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Удалить запрос"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Поисковый запрос"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Поиск"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Отправить запрос"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Голосовой поиск"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Открыть доступ"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Открыть доступ пользователю %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-sk/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Prejsť na plochu"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Prejsť hore"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Ďalšie možnosti"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Hotovo"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Zobraziť všetko"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Zvoľte aplikáciu"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Vymazať dopyt"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Vyhľadávací dopyt"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Hľadať"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Odoslať dopyt"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Hlasové vyhľadávanie"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Zdieľať pomocou"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Zdieľať pomocou %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-sl/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Krmarjenje domov"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Krmarjenje navzgor"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Več možnosti"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Končano"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Pokaži vse"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Izbira aplikacije"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Izbris poizvedbe"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Iskalna poizvedba"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Iskanje"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Pošiljanje poizvedbe"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Glasovno iskanje"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Deljenje z"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Deljenje z:"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-sr/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Одлазак на Почетну"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Кретање нагоре"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Још опција"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Готово"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Прикажи све"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Избор апликације"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Брисање упита"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Упит за претрагу"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Претрага"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Слање упита"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Гласовна претрага"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Дели са"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Дели са апликацијом %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-sv/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Visa startsidan"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navigera uppåt"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Fler alternativ"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Klart"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Visa alla"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Välj en app"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Ta bort frågan"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Sökfråga"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Sök"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Skicka fråga"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Röstsökning"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Dela med"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Dela med %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-sw/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Nenda mwanzo"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Nenda juu"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Chaguo zaidi"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Nimemaliza"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Angalia zote"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Chagua programu"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Futa hoja"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Hoja ya utafutaji"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Tafuta"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Wasilisha hoja"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Tafuta kwa kutamka"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Shiriki na:"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Shiriki na %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-sw600dp/dimens.xml -->
+ <eat-comment />
+
+ <dimen name="abc_action_bar_default_height">56dip</dimen>
+ <dimen name="abc_action_bar_icon_vertical_padding">4dip</dimen>
+ <dimen name="abc_action_bar_subtitle_bottom_margin">9dip</dimen>
+ <dimen name="abc_action_bar_subtitle_text_size">14dp</dimen>
+ <dimen name="abc_action_bar_subtitle_top_margin">-3dp</dimen>
+ <dimen name="abc_action_bar_title_text_size">18dp</dimen>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-sw600dp/config.xml -->
+ <eat-comment />
+
+ <dimen name="abc_config_prefDialogWidth">580dp</dimen>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-sw600dp/dimens.xml -->
+ <eat-comment />
+
+ <integer name="abc_max_action_buttons">5</integer>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-th/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"นำทางไปหน้าแรก"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"นำทางขึ้น"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"ตัวเลือกอื่น"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"เสร็จสิ้น"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"ดูทั้งหมด"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"เลือกแอป"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"ล้างข้อความค้นหา"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"ข้อความค้นหา"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"ค้นหา"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ส่งข้อความค้นหา"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"ค้นหาด้วยเสียง"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"แชร์กับ"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"แชร์กับ %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-tl/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Mag-navigate patungo sa home"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Mag-navigate pataas"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Higit pang mga opsyon"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Tapos na"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Tingnan lahat"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Pumili ng isang app"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"I-clear ang query"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Query sa paghahanap"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Maghanap"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Isumite ang query"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Paghahanap gamit ang boses"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Ibahagi sa/kay"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Ibahagi sa/kay %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-tr/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Ana ekrana git"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Yukarı git"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Diğer seçenekler"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Tamamlandı"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Tümünü göster"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Bir uygulama seçin"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Sorguyu temizle"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Arama sorgusu"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Ara"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Sorguyu gönder"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Sesli arama"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Şununla paylaş"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s ile paylaş"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-uk/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Перейти на головний"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Перейти вгору"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Інші опції"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Готово"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Переглянути всі"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Вибрати програму"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Очистити запит"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Пошуковий запит"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Пошук"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Надіслати запит"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Голосовий пошук"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Надіслати через"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Надіслати через %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-v11/themes_base.xml -->
+ <eat-comment />
+
+ <style name="Theme.Base" parent="android:Theme.Holo">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowActionBar">false</item>
+
+ <!--
+ A native Action Mode could be displayed (for text selection, etc) so we need to ensure
+ that it is positioned correctly, so we request windowActionModeOverlay so that it
+ displays over the compat Action Bar.
+ -->
+ <item name="android:windowActionModeOverlay">true</item>
+
+ <!-- Attributes populated from the framework to be read by apps -->
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
+ </style>
+
+ <style name="Theme.Base.AppCompat.Dialog.FixedSize" parent="android:Theme.Holo.Dialog">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ <item name="windowActionBar">false</item>
+
+ <!-- Attributes populated from the framework to be read by apps -->
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
+ </style>
+
+ <style name="Theme.Base.AppCompat.Dialog.Light.FixedSize" parent="android:Theme.Holo.Light.Dialog">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ <item name="windowActionBar">false</item>
+
+ <!-- Attributes populated from the framework to be read by apps -->
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
+ </style>
+
+ <style name="Theme.Base.Light" parent="android:Theme.Holo.Light">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowActionBar">false</item>
+
+ <!--
+ A native Action Mode could be displayed (for text selection, etc) so we need to ensure
+ that it is positioned correctly, so we request windowActionModeOverlay so that it
+ displays over the compat Action Bar.
+ -->
+ <item name="android:windowActionModeOverlay">true</item>
+
+ <!-- Attributes populated from the framework to be read by apps -->
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
+ </style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-v11/styles_base.xml -->
+ <eat-comment />
+
+ <style name="Widget.AppCompat.Base.AutoCompleteTextView" parent="android:Widget.Holo.AutoCompleteTextView"></style>
+
+ <style name="Widget.AppCompat.Base.ProgressBar" parent="android:Widget.Holo.ProgressBar"></style>
+
+ <style name="Widget.AppCompat.Base.ProgressBar.Horizontal" parent="android:Widget.Holo.ProgressBar.Horizontal"></style>
+
+ <style name="Widget.AppCompat.Light.Base.AutoCompleteTextView" parent="android:Widget.Holo.Light.AutoCompleteTextView"></style>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-v14/styles_base.xml -->
+ <eat-comment />
+
+ <style name="TextAppearance.AppCompat.Base.SearchResult.Subtitle" parent="@android:TextAppearance.Holo.SearchResult.Subtitle"></style>
+
+ <style name="TextAppearance.AppCompat.Base.SearchResult.Title" parent="@android:TextAppearance.Holo.SearchResult.Title"></style>
+
+ <style name="TextAppearance.AppCompat.Base.Widget.PopupMenu.Large" parent="android:TextAppearance.Holo.Widget.PopupMenu.Large"></style>
+
+ <style name="TextAppearance.AppCompat.Base.Widget.PopupMenu.Small" parent="android:TextAppearance.Holo.Widget.PopupMenu.Small"></style>
+
+ <style name="TextAppearance.AppCompat.Light.Base.SearchResult.Subtitle" parent="@android:TextAppearance.Holo.SearchResult.Subtitle"></style>
+
+ <style name="TextAppearance.AppCompat.Light.Base.SearchResult.Title" parent="@android:TextAppearance.Holo.SearchResult.Title"></style>
+
+ <style name="TextAppearance.AppCompat.Light.Base.Widget.PopupMenu.Large" parent="android:TextAppearance.Holo.Widget.PopupMenu.Large"></style>
+
+ <style name="TextAppearance.AppCompat.Light.Base.Widget.PopupMenu.Small" parent="android:TextAppearance.Holo.Widget.PopupMenu.Small"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Menu" parent="android:TextAppearance.Holo.Widget.ActionBar.Menu"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Subtitle" parent="android:TextAppearance.Holo.Widget.ActionBar.Subtitle"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Subtitle.Inverse" parent="android:TextAppearance.Holo.Widget.ActionBar.Subtitle.Inverse"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Title" parent="android:TextAppearance.Holo.Widget.ActionBar.Title"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Title.Inverse" parent="android:TextAppearance.Holo.Widget.ActionBar.Title.Inverse"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Subtitle" parent="android:TextAppearance.Holo.Widget.ActionMode.Subtitle"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Subtitle.Inverse" parent="android:TextAppearance.Holo.Widget.ActionMode.Subtitle.Inverse"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Title" parent="android:TextAppearance.Holo.Widget.ActionMode.Title"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Title.Inverse" parent="android:TextAppearance.Holo.Widget.ActionMode.Title.Inverse"></style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-v14/themes_base.xml -->
+ <eat-comment />
+
+ <style name="Theme.Base.AppCompat" parent="android:Theme.Holo">
+
+ <!-- Copy system flag values for our use -->
+ <item name="windowActionBar">?android:attr/windowActionBar</item>
+ <item name="actionBarSize">?android:attr/actionBarSize</item>
+ <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+ <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
+ <item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
+ <item name="dividerVertical">?android:attr/dividerVertical</item>
+ <item name="dividerHorizontal">?android:attr/dividerHorizontal</item>
+ <item name="actionBarWidgetTheme">@null</item>
+ <item name="android:actionBarWidgetTheme">?attr/actionBarWidgetTheme</item>
+
+ <!-- Required for use of support_simple_spinner_dropdown_item.xml -->
+ <item name="listPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="listPreferredItemHeightSmall">?android:attr/listPreferredItemHeightSmall</item>
+ <item name="listPreferredItemHeightLarge">?android:attr/listPreferredItemHeightLarge</item>
+ <item name="listPreferredItemPaddingLeft">?android:attr/listPreferredItemPaddingLeft</item>
+ <item name="listPreferredItemPaddingRight">?android:attr/listPreferredItemPaddingRight</item>
+
+ <!-- Attributes populated from the framework to be read by apps -->
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ </style>
+
+ <style name="Theme.Base.AppCompat.DialogWhenLarge" parent="Theme.Base.AppCompat.DialogWhenLarge.Base" />
+
+ <style name="Theme.Base.AppCompat.DialogWhenLarge.Base" parent="android:Theme.Holo.DialogWhenLarge">
+
+ <!-- Copy system flag values for our use -->
+ <item name="windowActionBar">?android:attr/windowActionBar</item>
+ <item name="actionBarSize">?android:attr/actionBarSize</item>
+ <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+ <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
+ <item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
+ <item name="dividerVertical">?android:attr/dividerVertical</item>
+ <item name="dividerHorizontal">?android:attr/dividerHorizontal</item>
+ <item name="actionBarWidgetTheme">@null</item>
+ <item name="android:actionBarWidgetTheme">?attr/actionBarWidgetTheme</item>
+
+ <!-- Required for use of support_simple_spinner_dropdown_item.xml -->
+ <item name="listPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="listPreferredItemHeightSmall">?android:attr/listPreferredItemHeightSmall</item>
+ <item name="listPreferredItemHeightLarge">?android:attr/listPreferredItemHeightLarge</item>
+ <item name="listPreferredItemPaddingLeft">?android:attr/listPreferredItemPaddingLeft</item>
+ <item name="listPreferredItemPaddingRight">?android:attr/listPreferredItemPaddingRight</item>
+
+ <!-- Attributes populated from the framework to be read by apps -->
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ </style>
+
+ <style name="Theme.Base.AppCompat.Light" parent="android:Theme.Holo.Light">
+
+ <!-- Copy system flag values for our use -->
+ <item name="windowActionBar">?android:attr/windowActionBar</item>
+ <item name="actionBarSize">?android:attr/actionBarSize</item>
+ <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+ <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
+ <item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
+ <item name="dividerVertical">?android:attr/dividerVertical</item>
+ <item name="dividerHorizontal">?android:attr/dividerHorizontal</item>
+ <item name="actionBarWidgetTheme">@null</item>
+ <item name="android:actionBarWidgetTheme">?attr/actionBarWidgetTheme</item>
+
+ <!-- Required for use of support_simple_spinner_dropdown_item.xml -->
+ <item name="listPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="listPreferredItemHeightSmall">?android:attr/listPreferredItemHeightSmall</item>
+ <item name="listPreferredItemHeightLarge">?android:attr/listPreferredItemHeightLarge</item>
+ <item name="listPreferredItemPaddingLeft">?android:attr/listPreferredItemPaddingLeft</item>
+ <item name="listPreferredItemPaddingRight">?android:attr/listPreferredItemPaddingRight</item>
+
+ <!-- Attributes populated from the framework to be read by apps -->
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ </style>
+
+ <style name="Theme.Base.AppCompat.Light.DarkActionBar" parent="android:Theme.Holo.Light.DarkActionBar">
+
+ <!-- Copy system flag values for our use -->
+ <item name="windowActionBar">?android:attr/windowActionBar</item>
+ <item name="actionBarSize">?android:attr/actionBarSize</item>
+ <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+ <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
+ <item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
+ <item name="dividerVertical">?android:attr/dividerVertical</item>
+ <item name="dividerHorizontal">?android:attr/dividerHorizontal</item>
+ <item name="actionBarWidgetTheme">@style/Theme.AppCompat</item>
+ <item name="android:actionBarWidgetTheme">?attr/actionBarWidgetTheme</item>
+
+ <!-- Required for use of support_simple_spinner_dropdown_item.xml -->
+ <item name="listPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="listPreferredItemHeightSmall">?android:attr/listPreferredItemHeightSmall</item>
+ <item name="listPreferredItemHeightLarge">?android:attr/listPreferredItemHeightLarge</item>
+ <item name="listPreferredItemPaddingLeft">?android:attr/listPreferredItemPaddingLeft</item>
+ <item name="listPreferredItemPaddingRight">?android:attr/listPreferredItemPaddingRight</item>
+
+ <!-- Attributes populated from the framework to be read by apps -->
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ </style>
+
+ <style name="Theme.Base.AppCompat.Light.DialogWhenLarge" parent="Theme.Base.AppCompat.Light.DialogWhenLarge.Base" />
+
+ <style name="Theme.Base.AppCompat.Light.DialogWhenLarge.Base" parent="android:Theme.Holo.Light.DialogWhenLarge">
+
+ <!-- Copy system flag values for our use -->
+ <item name="windowActionBar">?android:attr/windowActionBar</item>
+ <item name="actionBarSize">?android:attr/actionBarSize</item>
+ <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+ <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
+ <item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
+ <item name="dividerVertical">?android:attr/dividerVertical</item>
+ <item name="dividerHorizontal">?android:attr/dividerHorizontal</item>
+ <item name="actionBarWidgetTheme">@null</item>
+ <item name="android:actionBarWidgetTheme">?attr/actionBarWidgetTheme</item>
+
+ <!-- Required for use of support_simple_spinner_dropdown_item.xml -->
+ <item name="listPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="listPreferredItemHeightSmall">?android:attr/listPreferredItemHeightSmall</item>
+ <item name="listPreferredItemHeightLarge">?android:attr/listPreferredItemHeightLarge</item>
+ <item name="listPreferredItemPaddingLeft">?android:attr/listPreferredItemPaddingLeft</item>
+ <item name="listPreferredItemPaddingRight">?android:attr/listPreferredItemPaddingRight</item>
+
+ <!-- Attributes populated from the framework to be read by apps -->
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ </style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-v14/styles_base.xml -->
+ <eat-comment />
+
+ <style name="Widget.AppCompat.Base.ActionBar" parent="android:Widget.Holo.ActionBar"></style>
+
+ <style name="Widget.AppCompat.Base.ActionBar.Solid" parent="android:Widget.Holo.ActionBar.Solid"></style>
+
+ <style name="Widget.AppCompat.Base.ActionBar.TabBar" parent="android:Widget.Holo.ActionBar.TabBar"></style>
+
+ <style name="Widget.AppCompat.Base.ActionBar.TabText" parent="android:Widget.Holo.ActionBar.TabText"></style>
+
+ <style name="Widget.AppCompat.Base.ActionBar.TabView" parent="android:Widget.Holo.ActionBar.TabView"></style>
+
+ <style name="Widget.AppCompat.Base.ActionButton" parent="android:Widget.Holo.ActionButton"></style>
+
+ <style name="Widget.AppCompat.Base.ActionButton.CloseMode" parent="android:Widget.Holo.ActionButton.CloseMode"></style>
+
+ <style name="Widget.AppCompat.Base.ActionButton.Overflow" parent="android:Widget.Holo.ActionButton.Overflow"></style>
+
+ <style name="Widget.AppCompat.Base.ActivityChooserView" parent="">
+ <item name="android:gravity">center</item>
+ <item name="android:background">@drawable/abc_ab_share_pack_holo_dark</item>
+ <item name="android:divider">?attr/dividerVertical</item>
+ <item name="android:showDividers">middle</item>
+ <item name="android:dividerPadding">6dip</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.DropDownItem.Spinner" parent="android:Widget.Holo.DropDownItem.Spinner" />
+
+ <style name="Widget.AppCompat.Base.ListPopupWindow" parent="android:Widget.Holo.ListPopupWindow"></style>
+
+ <style name="Widget.AppCompat.Base.ListView.DropDown" parent="android:Widget.Holo.ListView.DropDown" />
+
+ <style name="Widget.AppCompat.Base.ListView.Menu" parent="android:Widget.ListView.Menu" />
+
+ <style name="Widget.AppCompat.Base.PopupMenu" parent="android:Widget.Holo.PopupMenu"></style>
+
+ <style name="Widget.AppCompat.Base.Spinner" parent="android:Widget.Holo.Spinner" />
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar" parent="android:Widget.Holo.Light.ActionBar"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.Solid" parent="android:Widget.Holo.Light.ActionBar.Solid"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.Solid.Inverse" parent="android:Widget.Holo.Light.ActionBar.Solid.Inverse"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabBar" parent="android:Widget.Holo.Light.ActionBar.TabBar"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabBar.Inverse" parent="android:Widget.Holo.Light.ActionBar.TabBar.Inverse"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabText" parent="android:Widget.Holo.Light.ActionBar.TabText"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabText.Inverse" parent="android:Widget.Holo.Light.ActionBar.TabText.Inverse"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabView" parent="android:Widget.Holo.Light.ActionBar.TabView"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabView.Inverse" parent="android:Widget.Holo.Light.ActionBar.TabView.Inverse"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionButton" parent="android:Widget.Holo.Light.ActionButton"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionButton.CloseMode" parent="android:Widget.Holo.Light.ActionButton.CloseMode"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionButton.Overflow" parent="android:Widget.Holo.Light.ActionButton.Overflow"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionMode.Inverse" parent="android:Widget.Holo.Light.ActionMode.Inverse"></style>
+
+ <style name="Widget.AppCompat.Light.Base.DropDownItem.Spinner" parent="android:Widget.Holo.Light.DropDownItem.Spinner" />
+
+ <style name="Widget.AppCompat.Light.Base.ListPopupWindow" parent="android:Widget.Holo.Light.ListPopupWindow"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ListView.DropDown" parent="android:Widget.Holo.ListView.DropDown" />
+
+ <style name="Widget.AppCompat.Light.Base.PopupMenu" parent="android:Widget.Holo.Light.PopupMenu"></style>
+
+ <style name="Widget.AppCompat.Light.Base.Spinner" parent="android:Widget.Holo.Light.Spinner" />
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-vi/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Điều hướng về trang chủ"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Điều hướng lên trên"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Thêm tùy chọn"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Xong"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Xem tất cả"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Chọn một ứng dụng"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Xóa truy vấn"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Tìm kiếm truy vấn"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Tìm kiếm"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Gửi truy vấn"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Tìm kiếm bằng giọng nói"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Chia sẻ với"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Chia sẻ với %s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-w360dp/dimens.xml -->
+ <eat-comment />
+
+ <integer name="abc_max_action_buttons">3</integer>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-w480dp/bools.xml -->
+ <eat-comment />
+
+ <bool name="abc_action_bar_embed_tabs_pre_jb">true</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-w480dp/config.xml -->
+ <eat-comment />
+
+ <bool name="abc_config_allowActionMenuItemTextWithIcon">true</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-w480dp/bools.xml -->
+ <eat-comment />
+
+ <bool name="abc_split_action_bar_is_narrow">false</bool>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-w500dp/dimens.xml -->
+ <eat-comment />
+
+ <integer name="abc_max_action_buttons">4</integer>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-w600dp/dimens.xml -->
+ <eat-comment />
+
+ <dimen name="abc_action_bar_default_height">56dip</dimen>
+ <dimen name="abc_action_bar_icon_vertical_padding">4dip</dimen>
+ <dimen name="abc_action_bar_subtitle_bottom_margin">9dip</dimen>
+ <dimen name="abc_action_bar_subtitle_text_size">14dp</dimen>
+ <dimen name="abc_action_bar_subtitle_top_margin">-3dp</dimen>
+ <dimen name="abc_action_bar_title_text_size">18dp</dimen>
+ <dimen name="abc_action_button_min_width">64dip</dimen>
+ <dimen name="abc_search_view_text_min_width">192dip</dimen>
+
+ <integer name="abc_max_action_buttons">5</integer>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-w720dp/bools.xml -->
+ <eat-comment />
+
+ <bool name="abc_action_bar_expanded_action_views_exclusive">false</bool>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-xlarge/bools.xml -->
+ <eat-comment />
+
+ <bool name="abc_action_bar_expanded_action_views_exclusive">false</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-xlarge/dimens.xml -->
+ <eat-comment />
+
+ <dimen name="abc_action_bar_default_height">56dip</dimen>
+ <dimen name="abc_action_bar_icon_vertical_padding">4dip</dimen>
+ <dimen name="abc_action_bar_subtitle_bottom_margin">9dip</dimen>
+ <dimen name="abc_action_bar_subtitle_text_size">14dp</dimen>
+ <dimen name="abc_action_bar_subtitle_top_margin">-3dp</dimen>
+ <dimen name="abc_action_bar_title_text_size">18dp</dimen>
+ <dimen name="abc_action_button_min_width">64dip</dimen>
+ <dimen name="abc_search_view_text_min_width">192dip</dimen>
+
+ <item name="dialog_fixed_height_major" type="dimen">60%</item>
+ <item name="dialog_fixed_height_minor" type="dimen">90%</item>
+ <item name="dialog_fixed_width_major" type="dimen">50%</item>
+ <item name="dialog_fixed_width_minor" type="dimen">70%</item>
+
+ <integer name="abc_max_action_buttons">5</integer>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-zh-rCN/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"转到主屏幕"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"转到上一层级"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"更多选项"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"完成"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"查看全部"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"选择应用"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"清除查询"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"搜索查询"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"搜索"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"提交查询"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"语音搜索"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"分享方式"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"通过%s分享"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-zh-rHK/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"瀏覽主頁"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"向上瀏覽"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"更多選項"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"完成"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"顯示全部"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"選擇應用程式"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"清除查詢"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"搜尋查詢"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"搜尋"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"提交查詢"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"語音搜尋"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"分享對象"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"與「%s」分享"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-zh-rTW/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"瀏覽首頁"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"向上瀏覽"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"更多選項"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"完成"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"查看全部"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"選擇應用程式"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"清除查詢"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"搜尋查詢"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"搜尋"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"提交查詢"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"語音搜尋"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"選擇分享對象"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"與「%s」分享"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values-zu/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Zulazulela ekhaya"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Zulazulela phezulu"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Izinketho eziningi"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Kwenziwe"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Buka konke"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Khetha uhlelo lokusebenza"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Sula inkinga"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Umbuzo wosesho"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Sesha"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Hambisa umbuzo"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Ukusesha ngezwi"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Yabelana no-"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Yabelana no-%s"</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/attrs.xml -->
+ <eat-comment />
+
+ <attr name="actionBarDivider" format="reference" />
+ <attr name="actionBarItemBackground" format="reference" />
+ <attr name="actionBarSize" format="dimension" />
+ <attr name="actionBarSplitStyle" format="reference" />
+ <attr name="actionBarStyle" format="reference" />
+ <attr name="actionBarTabBarStyle" format="reference" />
+ <attr name="actionBarTabStyle" format="reference" />
+ <attr name="actionBarTabTextStyle" format="reference" />
+ <attr name="actionBarWidgetTheme" format="reference" />
+ <attr name="actionButtonStyle" format="reference" />
+ <attr name="actionMenuTextAppearance" format="reference" />
+ <attr name="actionMenuTextColor" format="color|reference" />
+ <attr name="actionModeBackground" format="reference" />
+ <attr name="actionModeCloseButtonStyle" format="reference" />
+ <attr name="actionModeCloseDrawable" format="reference" />
+ <attr name="actionModeCopyDrawable" format="reference" />
+ <attr name="actionModeCutDrawable" format="reference" />
+ <attr name="actionModeFindDrawable" format="reference" />
+ <attr name="actionModePasteDrawable" format="reference" />
+ <attr name="actionModePopupWindowStyle" format="reference" />
+ <attr name="actionModeSelectAllDrawable" format="reference" />
+ <attr name="actionModeShareDrawable" format="reference" />
+ <attr name="actionModeSplitBackground" format="reference" />
+ <attr name="actionModeStyle" format="reference" />
+ <attr name="actionModeWebSearchDrawable" format="reference" />
+ <attr name="actionOverflowButtonStyle" format="reference" />
+ <attr name="activityChooserViewStyle" format="reference" />
+ <attr name="buttonBarButtonStyle" format="reference" />
+ <attr name="buttonBarStyle" format="reference" />
+ <attr name="dividerHorizontal" format="reference" />
+ <attr name="dividerVertical" format="reference" />
+ <attr name="dropDownListViewStyle" format="reference" />
+ <attr name="height" format="dimension" />
+ <attr name="homeAsUpIndicator" format="reference" />
+ <attr name="isLightTheme" format="boolean" />
+ <attr name="listPopupWindowStyle" format="reference" />
+ <attr name="listPreferredItemHeight" format="dimension" />
+ <attr name="listPreferredItemHeightLarge" format="dimension" />
+ <attr name="listPreferredItemHeightSmall" format="dimension" />
+ <attr name="listPreferredItemPaddingLeft" format="dimension" />
+ <attr name="listPreferredItemPaddingRight" format="dimension" />
+ <attr name="searchDropdownBackground" format="reference" />
+ <attr name="searchResultListItemHeight" format="dimension" />
+ <attr name="searchViewAutoCompleteTextView" format="reference" />
+ <attr name="searchViewCloseIcon" format="reference" />
+ <attr name="searchViewEditQuery" format="reference" />
+ <attr name="searchViewEditQueryBackground" format="reference" />
+ <attr name="searchViewGoIcon" format="reference" />
+ <attr name="searchViewSearchIcon" format="reference" />
+ <attr name="searchViewTextField" format="reference" />
+ <attr name="searchViewTextFieldRight" format="reference" />
+ <attr name="searchViewVoiceIcon" format="reference" />
+ <attr name="selectableItemBackground" format="reference" />
+ <attr name="spinnerDropDownItemStyle" format="reference" />
+ <attr name="spinnerStyle" format="reference" />
+ <attr name="textAppearanceLargePopupMenu" format="reference" />
+ <attr name="textAppearanceListItem" format="reference" />
+ <attr name="textAppearanceListItemSmall" format="reference" />
+ <attr name="textAppearanceSearchResultSubtitle" format="reference" />
+ <attr name="textAppearanceSearchResultTitle" format="reference" />
+ <attr name="textAppearanceSmallPopupMenu" format="reference" />
+ <attr name="textColorSearchUrl" format="reference|color" />
+ <attr name="title" format="string" />
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/bools.xml -->
+ <eat-comment />
+
+ <bool name="abc_action_bar_embed_tabs_pre_jb">false</bool>
+ <bool name="abc_action_bar_expanded_action_views_exclusive">true</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/config.xml -->
+ <eat-comment />
+
+ <bool name="abc_config_actionMenuItemAllCaps">true</bool>
+ <bool name="abc_config_allowActionMenuItemTextWithIcon">false</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/bools.xml -->
+ <eat-comment />
+
+ <bool name="abc_config_showMenuShortcutsWhenKeyboardPresent">false</bool>
+ <bool name="abc_split_action_bar_is_narrow">true</bool>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/colors.xml -->
+ <eat-comment />
+
+ <color name="abc_search_url_text_normal">#7fa87f</color>
+ <color name="abc_search_url_text_pressed">@android:color/black</color>
+ <color name="abc_search_url_text_selected">@android:color/black</color>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/attrs.xml -->
+ <eat-comment />
+
+ <declare-styleable name="ActionBar">
+
+ <!-- The type of navigation to use. -->
+ <attr name="navigationMode">
+
+ <!-- Normal static title text -->
+ <enum name="normal" value="0" />
+ <!-- The action bar will use a selection list for navigation. -->
+ <enum name="listMode" value="1" />
+ <!-- The action bar will use a series of horizontal tabs for navigation. -->
+ <enum name="tabMode" value="2" />
+ </attr>
+ <!-- Options affecting how the action bar is displayed. -->
+ <attr name="displayOptions">
+ <flag name="useLogo" value="0x1" />
+ <flag name="showHome" value="0x2" />
+ <flag name="homeAsUp" value="0x4" />
+ <flag name="showTitle" value="0x8" />
+ <flag name="showCustom" value="0x10" />
+ <flag name="disableHome" value="0x20" />
+ </attr>
+ <!-- Specifies title text used for navigationMode="normal" -->
+ <attr name="title" />
+ <!-- Specifies subtitle text used for navigationMode="normal" -->
+ <attr name="subtitle" format="string" />
+ <!-- Specifies a style to use for title text. -->
+ <attr name="titleTextStyle" format="reference" />
+ <!-- Specifies a style to use for subtitle text. -->
+ <attr name="subtitleTextStyle" format="reference" />
+ <!-- Specifies the drawable used for the application icon. -->
+ <attr name="icon" format="reference" />
+ <!-- Specifies the drawable used for the application logo. -->
+ <attr name="logo" format="reference" />
+ <!-- Specifies the drawable used for item dividers. -->
+ <attr name="divider" format="reference" />
+ <!-- Specifies a background drawable for the action bar. -->
+ <attr name="background" format="reference" />
+ <!-- Specifies a background drawable for a second stacked row of the action bar. -->
+ <attr name="backgroundStacked" format="reference|color" />
+ <!-- Specifies a background drawable for the bottom component of a split action bar. -->
+ <attr name="backgroundSplit" format="reference|color" />
+ <!-- Specifies a layout for custom navigation. Overrides navigationMode. -->
+ <attr name="customNavigationLayout" format="reference" />
+ <!-- Specifies a fixed height. -->
+ <attr name="height" />
+ <!-- Specifies a layout to use for the "home" section of the action bar. -->
+ <attr name="homeLayout" format="reference" />
+ <!-- Specifies a style resource to use for an embedded progress bar. -->
+ <attr name="progressBarStyle" format="reference" />
+ <!-- Specifies a style resource to use for an indeterminate progress spinner. -->
+ <attr name="indeterminateProgressStyle" format="reference" />
+ <!-- Specifies the horizontal padding on either end for an embedded progress bar. -->
+ <attr name="progressBarPadding" format="dimension" />
+ <!--
+ Specifies padding that should be applied to the left and right sides of
+ system-provided items in the bar.
+ -->
+ <attr name="itemPadding" format="dimension" />
+ </declare-styleable>
+ <declare-styleable name="ActionBarLayout">
+ <attr name="android:layout_gravity" />
+ </declare-styleable>
+ <declare-styleable name="ActionBarWindow">
+ <attr name="windowActionBar" format="boolean" />
+ <attr name="windowActionBarOverlay" format="boolean" />
+ <attr name="windowSplitActionBar" format="boolean" />
+
+ <!--
+ A fixed width for the window along the major axis of the screen,
+ that is, when in landscape. Can be either an absolute dimension
+ or a fraction of the screen size in that dimension.
+ -->
+ <attr name="windowFixedWidthMajor" format="dimension|fraction" />
+ <!--
+ A fixed height for the window along the minor axis of the screen,
+ that is, when in landscape. Can be either an absolute dimension
+ or a fraction of the screen size in that dimension.
+ -->
+ <attr name="windowFixedHeightMinor" format="dimension|fraction" />
+
+ <!--
+ A fixed width for the window along the minor axis of the screen,
+ that is, when in portrait. Can be either an absolute dimension
+ or a fraction of the screen size in that dimension.
+ -->
+ <attr name="windowFixedWidthMinor" format="dimension|fraction" />
+ <!--
+ A fixed height for the window along the major axis of the screen,
+ that is, when in portrait. Can be either an absolute dimension
+ or a fraction of the screen size in that dimension.
+ -->
+ <attr name="windowFixedHeightMajor" format="dimension|fraction" />
+ </declare-styleable>
+ <declare-styleable name="ActionMenuItemView">
+ <attr name="android:minWidth" />
+ </declare-styleable>
+ <declare-styleable name="ActionMenuView">
+ <!-- Size of padding on either end of a divider. -->
+ </declare-styleable>
+ <declare-styleable name="ActionMode">
+
+ <!-- Specifies a style to use for title text. -->
+ <attr name="titleTextStyle" />
+ <!-- Specifies a style to use for subtitle text. -->
+ <attr name="subtitleTextStyle" />
+ <!-- Specifies a background for the action mode bar. -->
+ <attr name="background" />
+ <!-- Specifies a background for the split action mode bar. -->
+ <attr name="backgroundSplit" />
+ <!-- Specifies a fixed height for the action mode bar. -->
+ <attr name="height" />
+ </declare-styleable>
+ <declare-styleable name="ActivityChooserView">
+
+ <!-- The maximal number of items initially shown in the activity list. -->
+ <attr name="initialActivityCount" format="string" />
+ <!--
+ The drawable to show in the button for expanding the activities overflow popup.
+ <strong>Note:</strong> Clients would like to set this drawable
+ as a clue about the action the chosen activity will perform. For
+ example, if share activity is to be chosen the drawable should
+ give a clue that sharing is to be performed.
+ -->
+ <attr name="expandActivityOverflowButtonDrawable" format="reference" />
+ </declare-styleable>
+ <declare-styleable name="CompatTextView">
+
+ <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
+ <attr name="textAllCaps" format="reference|boolean" />
+ </declare-styleable>
+ <declare-styleable name="LinearLayoutICS">
+
+ <!-- Drawable to use as a vertical divider between buttons. -->
+ <attr name="divider" />
+ <!-- Setting for which dividers to show. -->
+ <attr name="showDividers">
+ <flag name="none" value="0" />
+ <flag name="beginning" value="1" />
+ <flag name="middle" value="2" />
+ <flag name="end" value="4" />
+ </attr>
+ <!-- Size of padding on either end of a divider. -->
+ <attr name="dividerPadding" format="dimension" />
+ </declare-styleable>
+ <declare-styleable name="MenuGroup">
+
+ <!-- The ID of the group. -->
+ <attr name="android:id" />
+
+ <!--
+ The category applied to all items within this group.
+ (This will be or'ed with the orderInCategory attribute.)
+ -->
+ <attr name="android:menuCategory" />
+
+ <!--
+ The order within the category applied to all items within this group.
+ (This will be or'ed with the category attribute.)
+ -->
+ <attr name="android:orderInCategory" />
+
+ <!-- Whether the items are capable of displaying a check mark. -->
+ <attr name="android:checkableBehavior" />
+
+ <!-- Whether the items are shown/visible. -->
+ <attr name="android:visible" />
+
+ <!-- Whether the items are enabled. -->
+ <attr name="android:enabled" />
+ </declare-styleable>
+ <declare-styleable name="MenuItem">
+
+ <!-- The ID of the item. -->
+ <attr name="android:id" />
+
+ <!--
+ The category applied to the item.
+ (This will be or'ed with the orderInCategory attribute.)
+ -->
+ <attr name="android:menuCategory" />
+
+ <!--
+ The order within the category applied to the item.
+ (This will be or'ed with the category attribute.)
+ -->
+ <attr name="android:orderInCategory" />
+
+ <!-- The title associated with the item. -->
+ <attr name="android:title" />
+
+ <!--
+ The condensed title associated with the item. This is used in situations where the
+ normal title may be too long to be displayed.
+ -->
+ <attr name="android:titleCondensed" />
+
+ <!--
+ The icon associated with this item. This icon will not always be shown, so
+ the title should be sufficient in describing this item.
+ -->
+ <attr name="android:icon" />
+
+ <!--
+ The alphabetic shortcut key. This is the shortcut when using a keyboard
+ with alphabetic keys.
+ -->
+ <attr name="android:alphabeticShortcut" />
+
+ <!--
+ The numeric shortcut key. This is the shortcut when using a numeric (e.g., 12-key)
+ keyboard.
+ -->
+ <attr name="android:numericShortcut" />
+
+ <!-- Whether the item is capable of displaying a check mark. -->
+ <attr name="android:checkable" />
+
+ <!--
+ Whether the item is checked. Note that you must first have enabled checking with
+ the checkable attribute or else the check mark will not appear.
+ -->
+ <attr name="android:checked" />
+
+ <!-- Whether the item is shown/visible. -->
+ <attr name="android:visible" />
+
+ <!-- Whether the item is enabled. -->
+ <attr name="android:enabled" />
+
+ <!--
+ Name of a method on the Context used to inflate the menu that will be
+ called when the item is clicked.
+ -->
+ <attr name="android:onClick" />
+
+ <!-- How this item should display in the Action Bar, if present. -->
+ <attr name="showAsAction">
+
+ <!--
+ Never show this item in an action bar, show it in the overflow menu instead.
+ Mutually exclusive with "ifRoom" and "always".
+ -->
+ <flag name="never" value="0" />
+ <!--
+ Show this item in an action bar if there is room for it as determined
+ by the system. Favor this option over "always" where possible.
+ Mutually exclusive with "never" and "always".
+ -->
+ <flag name="ifRoom" value="1" />
+ <!--
+ Always show this item in an actionbar, even if it would override
+ the system's limits of how much stuff to put there. This may make
+ your action bar look bad on some screens. In most cases you should
+ use "ifRoom" instead. Mutually exclusive with "ifRoom" and "never".
+ -->
+ <flag name="always" value="2" />
+ <!--
+ When this item is shown as an action in the action bar, show a text
+ label with it even if it has an icon representation.
+ -->
+ <flag name="withText" value="4" />
+ <!--
+ This item's action view collapses to a normal menu
+ item. When expanded, the action view takes over a
+ larger segment of its container.
+ -->
+ <flag name="collapseActionView" value="8" />
+ </attr>
+
+ <!--
+ An optional layout to be used as an action view.
+ See {@link android.view.MenuItem#setActionView(android.view.View)}
+ for more info.
+ -->
+ <attr name="actionLayout" format="reference" />
+
+ <!--
+ The name of an optional View class to instantiate and use as an
+ action view. See {@link android.view.MenuItem#setActionView(android.view.View)}
+ for more info.
+ -->
+ <attr name="actionViewClass" format="string" />
+
+ <!--
+ The name of an optional ActionProvider class to instantiate an action view
+ and perform operations such as default action for that menu item.
+ See {@link android.view.MenuItem#setActionProvider(android.view.ActionProvider)}
+ for more info.
+ -->
+ <attr name="actionProviderClass" format="string" />
+ </declare-styleable>
+ <declare-styleable name="MenuView">
+
+ <!-- Default appearance of menu item text. -->
+ <attr name="android:itemTextAppearance" />
+ <!-- Default horizontal divider between rows of menu items. -->
+ <attr name="android:horizontalDivider" />
+ <!-- Default vertical divider between menu items. -->
+ <attr name="android:verticalDivider" />
+ <!-- Default background for the menu header. -->
+ <attr name="android:headerBackground" />
+ <!-- Default background for each menu item. -->
+ <attr name="android:itemBackground" />
+ <!-- Default animations for the menu. -->
+ <attr name="android:windowAnimationStyle" />
+ <!-- Default disabled icon alpha for each menu item that shows an icon. -->
+ <attr name="android:itemIconDisabledAlpha" />
+ <!-- Whether space should be reserved in layout when an icon is missing. -->
+ <attr name="android:preserveIconSpacing" />
+ </declare-styleable>
+ <declare-styleable name="SearchView">
+
+ <!--
+ The default state of the SearchView. If true, it will be iconified when not in
+ use and expanded when clicked.
+ -->
+ <attr name="iconifiedByDefault" format="boolean" />
+ <!-- An optional maximum width of the SearchView. -->
+ <attr name="android:maxWidth" />
+ <!-- An optional query hint string to be displayed in the empty query field. -->
+ <attr name="queryHint" format="string" />
+ <!-- The IME options to set on the query text field. -->
+ <attr name="android:imeOptions" />
+ <!-- The input type to set on the query text field. -->
+ <attr name="android:inputType" />
+ </declare-styleable>
+ <declare-styleable name="Spinner">
+
+ <!-- The prompt to display when the spinner's dialog is shown. -->
+ <attr name="prompt" format="reference" />
+ <!-- Display mode for spinner options. -->
+ <attr name="spinnerMode" format="enum">
+
+ <!-- Spinner options will be presented to the user as a dialog window. -->
+ <enum name="dialog" value="0" />
+ <!--
+ Spinner options will be presented to the user as an inline dropdown
+ anchored to the spinner widget itself.
+ -->
+ <enum name="dropdown" value="1" />
+ </attr>
+ <!-- List selector to use for spinnerMode="dropdown" display. -->
+ <attr name="android:dropDownSelector" />
+ <!-- Background drawable to use for the dropdown in spinnerMode="dropdown". -->
+ <attr name="android:popupBackground" />
+ <!--
+ Vertical offset from the spinner widget for positioning the dropdown in
+ spinnerMode="dropdown".
+ -->
+ <attr name="android:dropDownVerticalOffset" />
+ <!--
+ Horizontal offset from the spinner widget for positioning the dropdown
+ in spinnerMode="dropdown".
+ -->
+ <attr name="android:dropDownHorizontalOffset" />
+ <!-- Width of the dropdown in spinnerMode="dropdown". -->
+ <attr name="android:dropDownWidth" />
+ <!--
+ Reference to a layout to use for displaying a prompt in the dropdown for
+ spinnerMode="dropdown". This layout must contain a TextView with the id
+ {@code @android:id/text1} to be populated with the prompt text.
+ -->
+ <attr name="popupPromptView" format="reference" />
+ <!-- Gravity setting for positioning the currently selected item. -->
+ <attr name="android:gravity" />
+ <!--
+ Whether this spinner should mark child views as enabled/disabled when
+ the spinner itself is enabled/disabled.
+ -->
+ <attr name="disableChildrenWhenDisabled" format="boolean" />
+ </declare-styleable>
+ <declare-styleable name="Theme">
+
+ <!-- Default ActionBar dropdown style. -->
+ <attr name="actionDropDownStyle" format="reference" />
+ <!-- The preferred item height for dropdown lists. -->
+ <attr name="dropdownListPreferredItemHeight" format="dimension" />
+ <!-- Default PopupMenu style. -->
+ <attr name="popupMenuStyle" format="reference" />
+
+ <!-- ============ -->
+ <!-- Panel styles -->
+ <!-- ============ -->
+ <eat-comment />
+
+ <!-- Default Panel Menu width. -->
+ <attr name="panelMenuListWidth" format="dimension" />
+
+ <!-- Default Panel Menu style. -->
+ <attr name="panelMenuListTheme" format="reference" />
+
+ <!-- Drawable used as a background for selected list items. -->
+ <attr name="listChoiceBackgroundIndicator" format="reference" />
+ </declare-styleable>
+ <declare-styleable name="View">
+
+ <!-- Sets the padding, in pixels, of the start edge; see {@link android.R.attr#padding}. -->
+ <attr name="paddingStart" format="dimension" />
+ <!-- Sets the padding, in pixels, of the end edge; see {@link android.R.attr#padding}. -->
+ <attr name="paddingEnd" format="dimension" />
+
+ <!--
+ Boolean that controls whether a view can take focus. By default the user can not
+ move focus to a view; by setting this attribute to true the view is
+ allowed to take focus. This value does not impact the behavior of
+ directly calling {@link android.view.View#requestFocus}, which will
+ always request focus regardless of this view. It only impacts where
+ focus navigation will try to move focus.
+ -->
+ <attr name="android:focusable" />
+ </declare-styleable>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/dimens.xml -->
+ <eat-comment />
+
+ <dimen name="abc_action_bar_default_height">48dip</dimen>
+ <dimen name="abc_action_bar_icon_vertical_padding">8dip</dimen>
+ <dimen name="abc_action_bar_progress_bar_size">40dp</dimen>
+ <dimen name="abc_action_bar_stacked_max_height">48dp</dimen>
+ <dimen name="abc_action_bar_stacked_tab_max_width">180dp</dimen>
+ <dimen name="abc_action_bar_subtitle_bottom_margin">5dip</dimen>
+ <dimen name="abc_action_bar_subtitle_text_size">14dp</dimen>
+ <dimen name="abc_action_bar_subtitle_top_margin">-3dp</dimen>
+ <dimen name="abc_action_bar_title_text_size">18dp</dimen>
+ <dimen name="abc_action_button_min_width">56dip</dimen>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/config.xml -->
+ <eat-comment />
+
+ <dimen name="abc_config_prefDialogWidth">320dp</dimen>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/dimens.xml -->
+ <eat-comment />
+
+ <dimen name="abc_dropdownitem_icon_width">32dip</dimen>
+ <dimen name="abc_dropdownitem_text_padding_left">8dip</dimen>
+ <dimen name="abc_dropdownitem_text_padding_right">8dip</dimen>
+ <dimen name="abc_panel_menu_list_width">296dp</dimen>
+ <dimen name="abc_search_view_preferred_width">320dip</dimen>
+ <dimen name="abc_search_view_text_min_width">160dip</dimen>
+
+ <item name="dialog_fixed_height_major" type="dimen">80%</item>
+ <item name="dialog_fixed_height_minor" type="dimen">100%</item>
+ <item name="dialog_fixed_width_major" type="dimen">320dp</item>
+ <item name="dialog_fixed_width_minor" type="dimen">320dp</item>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/ids.xml -->
+ <eat-comment />
+
+ <item name="action_bar_activity_content" type="id"/>
+ <item name="action_menu_divider" type="id"/>
+ <item name="action_menu_presenter" type="id"/>
+ <item name="home" type="id"/>
+ <item name="progress_circular" type="id"/>
+ <item name="progress_horizontal" type="id"/>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/dimens.xml -->
+ <eat-comment />
+
+ <integer name="abc_max_action_buttons">2</integer>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/strings.xml -->
+ <eat-comment />
+
+ <string name="abc_action_bar_home_description">Navigate home</string>
+ <string name="abc_action_bar_up_description">Navigate up</string>
+ <string name="abc_action_menu_overflow_description">More options</string>
+ <string name="abc_action_mode_done">Done</string>
+ <string name="abc_activity_chooser_view_see_all">See all</string>
+ <string name="abc_activitychooserview_choose_application">Choose an app</string>
+ <string name="abc_searchview_description_clear">Clear query</string>
+ <string name="abc_searchview_description_query">Search query</string>
+ <string name="abc_searchview_description_search">Search</string>
+ <string name="abc_searchview_description_submit">Submit query</string>
+ <string name="abc_searchview_description_voice">Voice search</string>
+ <string name="abc_shareactionprovider_share_with">Share with</string>
+ <string name="abc_shareactionprovider_share_with_application">Share with %s</string>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles_base.xml -->
+ <eat-comment />
+
+ <style name="TextAppearance.AppCompat.Base.CompactMenu.Dialog" parent="android:TextAppearance.Medium">
+ <item name="android:textColor">@android:color/primary_text_light</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Base.SearchResult" parent="">
+ <item name="android:textStyle">normal</item>
+ <item name="android:textColor">?android:textColorPrimary</item>
+ <item name="android:textColorHint">?android:textColorHint</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Base.SearchResult.Subtitle">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Base.SearchResult.Title">
+ <item name="android:textSize">18sp</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Base.Widget.PopupMenu.Large" parent="android:TextAppearance.Widget">
+ <item name="android:textColor">?android:attr/textColorPrimaryDisableOnly</item>
+ <item name="android:textSize">18sp</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Base.Widget.PopupMenu.Small" parent="android:TextAppearance.Widget">
+ <item name="android:textColor">?android:attr/textColorPrimaryDisableOnly</item>
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Light.Base.SearchResult" parent="TextAppearance.AppCompat.Base.SearchResult">
+ <item name="android:textColor">?android:textColorPrimary</item>
+ <item name="android:textColorHint">?android:textColorHint</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Light.Base.SearchResult.Subtitle">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Light.Base.SearchResult.Title">
+ <item name="android:textSize">18sp</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Light.Base.Widget.PopupMenu.Large" parent="TextAppearance.AppCompat.Base.Widget.PopupMenu.Large"></style>
+
+ <style name="TextAppearance.AppCompat.Light.Base.Widget.PopupMenu.Small" parent="TextAppearance.AppCompat.Base.Widget.PopupMenu.Small"></style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles.xml -->
+ <eat-comment />
+
+ <style name="TextAppearance.AppCompat.Light.SearchResult.Subtitle" parent="TextAppearance.AppCompat.Light.Base.SearchResult.Subtitle"></style>
+
+ <style name="TextAppearance.AppCompat.Light.SearchResult.Title" parent="TextAppearance.AppCompat.Light.Base.SearchResult.Title"></style>
+
+ <style name="TextAppearance.AppCompat.Light.Widget.PopupMenu.Large" parent="TextAppearance.AppCompat.Light.Base.Widget.PopupMenu.Large"></style>
+
+ <style name="TextAppearance.AppCompat.Light.Widget.PopupMenu.Small" parent="TextAppearance.AppCompat.Light.Base.Widget.PopupMenu.Small"></style>
+
+ <style name="TextAppearance.AppCompat.SearchResult.Subtitle" parent="TextAppearance.AppCompat.Base.SearchResult.Subtitle"></style>
+
+ <style name="TextAppearance.AppCompat.SearchResult.Title" parent="TextAppearance.AppCompat.Base.SearchResult.Title"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.ActionBar.Menu" parent="TextAppearance.AppCompat.Widget.Base.ActionBar.Menu"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.ActionBar.Subtitle" parent="TextAppearance.AppCompat.Widget.Base.ActionBar.Subtitle"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.AppCompat.Widget.Base.ActionBar.Subtitle.Inverse"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.ActionBar.Title" parent="TextAppearance.AppCompat.Widget.Base.ActionBar.Title"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse" parent="TextAppearance.AppCompat.Widget.Base.ActionBar.Title.Inverse"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.ActionMode.Subtitle" parent="TextAppearance.AppCompat.Widget.Base.ActionMode.Subtitle"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.AppCompat.Widget.Base.ActionMode.Subtitle.Inverse"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.ActionMode.Title" parent="TextAppearance.AppCompat.Widget.Base.ActionMode.Title"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.ActionMode.Title.Inverse" parent="TextAppearance.AppCompat.Widget.Base.ActionMode.Title.Inverse"></style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles_base.xml -->
+ <eat-comment />
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Menu" parent="android:TextAppearance.Small">
+ <item name="android:textSize">12sp</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textColor">?attr/actionMenuTextColor</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Subtitle" parent="android:TextAppearance.Small">
+ <item name="android:textSize">@dimen/abc_action_bar_subtitle_text_size</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Subtitle.Inverse" parent="android:TextAppearance.Small.Inverse">
+ <item name="android:textSize">@dimen/abc_action_bar_subtitle_text_size</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Title" parent="android:TextAppearance.Medium">
+ <item name="android:textSize">@dimen/abc_action_bar_title_text_size</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Title.Inverse" parent="android:TextAppearance.Medium.Inverse">
+ <item name="android:textSize">@dimen/abc_action_bar_title_text_size</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Subtitle" parent="android:TextAppearance.Small">
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Subtitle.Inverse" parent="android:TextAppearance.Small.Inverse">
+ <item name="android:textColor">?android:attr/textColorSecondaryInverse</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Title" parent="android:TextAppearance.Medium"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Title.Inverse" parent="android:TextAppearance.Medium.Inverse"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.Base.DropDownItem" parent="android:TextAppearance.Small">
+ <item name="android:textColor">?android:attr/textColorPrimaryDisableOnly</item>
+ </style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles.xml -->
+ <eat-comment />
+
+ <style name="TextAppearance.AppCompat.Widget.DropDownItem" parent="TextAppearance.AppCompat.Widget.Base.DropDownItem"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.PopupMenu.Large" parent="TextAppearance.AppCompat.Base.Widget.PopupMenu.Large"></style>
+
+ <style name="TextAppearance.AppCompat.Widget.PopupMenu.Small" parent="TextAppearance.AppCompat.Base.Widget.PopupMenu.Small"></style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles_base.xml -->
+ <eat-comment />
+
+ <style name="TextAppearance.Widget.AppCompat.Base.ExpandedMenu.Item" parent="android:TextAppearance.Medium">
+ <item name="android:textColor">?android:attr/textColorPrimaryDisableOnly</item>
+ </style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles.xml -->
+ <eat-comment />
+
+ <style name="TextAppearance.Widget.AppCompat.ExpandedMenu.Item" parent="TextAppearance.Widget.AppCompat.Base.ExpandedMenu.Item"></style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/themes.xml -->
+ <eat-comment />
+
+ <style name="Theme.AppCompat" parent="Theme.Base.AppCompat">
+ <item name="isLightTheme">false</item>
+
+ <!-- Required for use of support_simple_spinner_dropdown_item.xml -->
+ <item name="spinnerDropDownItemStyle"> @style/Widget.AppCompat.DropDownItem.Spinner</item>
+ <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
+ <item name="searchResultListItemHeight">58dip</item>
+
+ <!-- Popup Menu styles -->
+ <item name="popupMenuStyle">@style/Widget.AppCompat.PopupMenu</item>
+ <item name="textAppearanceLargePopupMenu"> @style/TextAppearance.AppCompat.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu"> @style/TextAppearance.AppCompat.Widget.PopupMenu.Small</item>
+ <item name="listPopupWindowStyle">@style/Widget.AppCompat.ListPopupWindow</item>
+ <item name="dropDownListViewStyle">@style/Widget.AppCompat.ListView.DropDown</item>
+
+ <!-- SearchView attributes -->
+ <item name="searchDropdownBackground">@drawable/abc_search_dropdown_dark</item>
+ <item name="searchViewTextField">@drawable/abc_textfield_searchview_holo_dark</item>
+ <item name="searchViewTextFieldRight">@drawable/abc_textfield_searchview_right_holo_dark</item>
+ <item name="searchViewCloseIcon">@drawable/abc_ic_clear</item>
+ <item name="searchViewSearchIcon">@drawable/abc_ic_search</item>
+ <item name="searchViewGoIcon">@drawable/abc_ic_go</item>
+ <item name="searchViewVoiceIcon">@drawable/abc_ic_voice_search</item>
+ <item name="searchViewEditQuery">@drawable/abc_ic_commit_search_api_holo_dark</item>
+ <item name="searchViewEditQueryBackground">?attr/selectableItemBackground</item>
+ <item name="searchViewAutoCompleteTextView"> @style/Widget.AppCompat.AutoCompleteTextView</item>
+ <item name="textColorSearchUrl">@color/abc_search_url_text_holo</item>
+ <item name="textAppearanceSearchResultTitle"> @style/TextAppearance.AppCompat.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle"> @style/TextAppearance.AppCompat.SearchResult.Subtitle</item>
+ <item name="actionModeShareDrawable">@drawable/abc_ic_menu_share_holo_dark</item>
+
+ <!-- ShareActionProvider attributes -->
+ <item name="activityChooserViewStyle">@style/Widget.AppCompat.ActivityChooserView</item>
+ </style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/themes_base.xml -->
+ <eat-comment />
+
+ <style name="Theme.AppCompat.Base.CompactMenu" parent="">
+ <item name="android:itemTextAppearance"> @style/TextAppearance.Widget.AppCompat.ExpandedMenu.Item</item>
+ <item name="android:listViewStyle">@style/Widget.AppCompat.ListView.Menu</item>
+ </style>
+
+ <style name="Theme.AppCompat.Base.CompactMenu.Dialog" parent="">
+ <item name="android:itemTextAppearance"> @style/TextAppearance.AppCompat.Base.CompactMenu.Dialog</item>
+ <item name="android:listViewStyle">@android:style/Widget.ListView.Menu</item>
+ </style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/themes.xml -->
+ <eat-comment />
+
+ <style name="Theme.AppCompat.CompactMenu" parent="Theme.AppCompat.Base.CompactMenu"></style>
+
+ <style name="Theme.AppCompat.CompactMenu.Dialog" parent="Theme.AppCompat.Base.CompactMenu.Dialog"></style>
+
+ <style name="Theme.AppCompat.DialogWhenLarge" parent="Theme.Base.AppCompat.DialogWhenLarge"></style>
+
+ <style name="Theme.AppCompat.Light" parent="Theme.Base.AppCompat.Light">
+ <item name="isLightTheme">true</item>
+
+ <!-- Required for use of support_simple_spinner_dropdown_item.xml -->
+ <item name="spinnerDropDownItemStyle"> @style/Widget.AppCompat.Light.DropDownItem.Spinner</item>
+ <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
+ <item name="searchResultListItemHeight">58dip</item>
+
+ <!-- Popup Menu styles -->
+ <item name="popupMenuStyle">@style/Widget.AppCompat.Light.PopupMenu</item>
+ <item name="textAppearanceLargePopupMenu"> @style/TextAppearance.AppCompat.Light.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu"> @style/TextAppearance.AppCompat.Light.Widget.PopupMenu.Small</item>
+ <item name="listPopupWindowStyle">@style/Widget.AppCompat.Light.ListPopupWindow</item>
+ <item name="dropDownListViewStyle">@style/Widget.AppCompat.Light.ListView.DropDown</item>
+
+ <!-- SearchView attributes -->
+ <item name="searchDropdownBackground">@drawable/abc_search_dropdown_light</item>
+ <item name="searchViewTextField">@drawable/abc_textfield_searchview_holo_light</item>
+ <item name="searchViewTextFieldRight">@drawable/abc_textfield_searchview_right_holo_light</item>
+ <item name="searchViewCloseIcon">@drawable/abc_ic_clear_holo_light</item>
+ <item name="searchViewSearchIcon">@drawable/abc_ic_search_api_holo_light</item>
+ <item name="searchViewGoIcon">@drawable/abc_ic_go_search_api_holo_light</item>
+ <item name="searchViewVoiceIcon">@drawable/abc_ic_voice_search_api_holo_light</item>
+ <item name="searchViewEditQuery">@drawable/abc_ic_commit_search_api_holo_light</item>
+ <item name="searchViewEditQueryBackground">?attr/selectableItemBackground</item>
+ <item name="searchViewAutoCompleteTextView"> @style/Widget.AppCompat.Light.AutoCompleteTextView</item>
+ <item name="textColorSearchUrl">@color/abc_search_url_text_holo</item>
+ <item name="textAppearanceSearchResultTitle"> @style/TextAppearance.AppCompat.Light.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle"> @style/TextAppearance.AppCompat.Light.SearchResult.Subtitle</item>
+ <item name="actionModeShareDrawable">@drawable/abc_ic_menu_share_holo_light</item>
+
+ <!-- ShareActionProvider attributes -->
+ <item name="activityChooserViewStyle">@style/Widget.AppCompat.Light.ActivityChooserView</item>
+ </style>
+
+ <style name="Theme.AppCompat.Light.DarkActionBar" parent="Theme.Base.AppCompat.Light.DarkActionBar">
+ <item name="isLightTheme">true</item>
+
+ <!-- Required for use of support_simple_spinner_dropdown_item.xml -->
+ <item name="spinnerDropDownItemStyle"> @style/Widget.AppCompat.Light.DropDownItem.Spinner</item>
+ <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
+ <item name="searchResultListItemHeight">58dip</item>
+
+ <!-- Popup Menu styles -->
+ <item name="popupMenuStyle">@style/Widget.AppCompat.Light.PopupMenu</item>
+ <item name="textAppearanceLargePopupMenu"> @style/TextAppearance.AppCompat.Light.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu"> @style/TextAppearance.AppCompat.Light.Widget.PopupMenu.Small</item>
+ <item name="listPopupWindowStyle">@style/Widget.AppCompat.ListPopupWindow</item>
+ <item name="dropDownListViewStyle">@style/Widget.AppCompat.ListView.DropDown</item>
+
+ <!-- SearchView attributes -->
+ <item name="searchDropdownBackground">@drawable/abc_search_dropdown_dark</item>
+ <item name="searchViewTextField">@drawable/abc_textfield_searchview_holo_dark</item>
+ <item name="searchViewTextFieldRight">@drawable/abc_textfield_searchview_right_holo_dark</item>
+ <item name="searchViewCloseIcon">@drawable/abc_ic_clear</item>
+ <item name="searchViewSearchIcon">@drawable/abc_ic_search</item>
+ <item name="searchViewGoIcon">@drawable/abc_ic_go</item>
+ <item name="searchViewVoiceIcon">@drawable/abc_ic_voice_search</item>
+ <item name="searchViewEditQuery">@drawable/abc_ic_commit_search_api_holo_dark</item>
+ <item name="searchViewEditQueryBackground">?attr/selectableItemBackground</item>
+ <item name="searchViewAutoCompleteTextView"> @style/Widget.AppCompat.AutoCompleteTextView</item>
+ <item name="textColorSearchUrl">@color/abc_search_url_text_holo</item>
+ <item name="textAppearanceSearchResultTitle"> @style/TextAppearance.AppCompat.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle"> @style/TextAppearance.AppCompat.SearchResult.Subtitle</item>
+ <item name="actionModeShareDrawable">@drawable/abc_ic_menu_share_holo_dark</item>
+
+ <!-- ShareActionProvider attributes -->
+ <item name="activityChooserViewStyle">@style/Widget.AppCompat.ActivityChooserView</item>
+ </style>
+
+ <style name="Theme.AppCompat.Light.DialogWhenLarge" parent="Theme.Base.AppCompat.Light.DialogWhenLarge"></style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/themes_base.xml -->
+ <eat-comment />
+
+ <style name="Theme.Base" parent="android:Theme"></style>
+
+ <style name="Theme.Base.AppCompat" parent="Theme.Base">
+ <item name="windowActionBar">true</item>
+ <!-- Remove system title bars; we will add the action bar ourselves. -->
+ <item name="android:windowNoTitle">true</item>
+ <item name="buttonBarStyle">@android:style/ButtonBar</item>
+ <item name="buttonBarButtonStyle">@android:style/Widget.Button</item>
+ <item name="selectableItemBackground">@drawable/abc_item_background_holo_dark</item>
+ <item name="homeAsUpIndicator">@drawable/abc_ic_ab_back_holo_dark</item>
+ <item name="dividerVertical">@drawable/abc_list_divider_holo_dark</item>
+ <item name="dividerHorizontal">@drawable/abc_list_divider_holo_dark</item>
+ <item name="listPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="listPreferredItemHeightSmall">48dp</item>
+ <item name="listPreferredItemHeightLarge">80dp</item>
+ <item name="listPreferredItemPaddingLeft">8dip</item>
+ <item name="listPreferredItemPaddingRight">8dip</item>
+ <item name="textAppearanceListItem">?android:attr/textAppearanceMedium</item>
+ <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+ <item name="actionBarTabStyle">@style/Widget.AppCompat.ActionBar.TabView</item>
+ <item name="actionBarTabBarStyle">@style/Widget.AppCompat.ActionBar.TabBar</item>
+ <item name="actionBarTabTextStyle">@style/Widget.AppCompat.ActionBar.TabText</item>
+ <item name="actionButtonStyle">@style/Widget.AppCompat.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.AppCompat.ActionButton.Overflow</item>
+ <item name="actionBarStyle">@style/Widget.AppCompat.ActionBar</item>
+ <item name="actionBarSplitStyle">?attr/actionBarStyle</item>
+ <item name="actionBarWidgetTheme">@null</item>
+ <item name="actionBarSize">@dimen/abc_action_bar_default_height</item>
+ <item name="actionBarDivider">?attr/dividerVertical</item>
+ <item name="actionBarItemBackground">?attr/selectableItemBackground</item>
+ <item name="actionMenuTextAppearance"> @style/TextAppearance.AppCompat.Widget.ActionBar.Menu</item>
+ <item name="actionMenuTextColor">?android:attr/textColorPrimaryDisableOnly</item>
+
+ <!-- Dropdown Spinner Attributes -->
+ <item name="actionDropDownStyle">@style/Widget.AppCompat.Spinner.DropDown.ActionBar</item>
+
+ <!-- Action Mode -->
+ <item name="actionModeStyle">@style/Widget.AppCompat.ActionMode</item>
+ <item name="actionModeBackground">@drawable/abc_cab_background_top_holo_dark</item>
+ <item name="actionModeSplitBackground">@drawable/abc_cab_background_bottom_holo_dark</item>
+ <item name="actionModeCloseDrawable">@drawable/abc_ic_cab_done_holo_dark</item>
+ <item name="actionModeCloseButtonStyle">@style/Widget.AppCompat.ActionButton.CloseMode</item>
+
+ <!-- Panel attributes -->
+ <item name="panelMenuListWidth">@dimen/abc_panel_menu_list_width</item>
+ <item name="panelMenuListTheme">@style/Theme.AppCompat.CompactMenu</item>
+ <item name="android:panelBackground">@drawable/abc_menu_hardkey_panel_holo_dark</item>
+ <item name="listChoiceBackgroundIndicator">@drawable/abc_list_selector_holo_dark</item>
+ </style>
+
+ <style name="Theme.Base.AppCompat.Dialog.FixedSize" parent="android:Theme.Dialog">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ <item name="windowActionBar">true</item>
+ <!-- Remove system title bars; we will add the action bar ourselves. -->
+ <item name="android:windowNoTitle">true</item>
+ <item name="buttonBarStyle">@android:style/ButtonBar</item>
+ <item name="buttonBarButtonStyle">@android:style/Widget.Button</item>
+ <item name="selectableItemBackground">@drawable/abc_item_background_holo_dark</item>
+ <item name="dividerVertical">@drawable/abc_list_divider_holo_dark</item>
+ <item name="dividerHorizontal">@drawable/abc_list_divider_holo_dark</item>
+ <item name="listPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="listPreferredItemHeightSmall">48dp</item>
+ <item name="listPreferredItemHeightLarge">80dp</item>
+ <item name="listPreferredItemPaddingLeft">8dip</item>
+ <item name="listPreferredItemPaddingRight">8dip</item>
+ <item name="textAppearanceListItem">?android:attr/textAppearanceMedium</item>
+ <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+
+ <!-- Action Mode -->
+ <item name="actionModeStyle">@style/Widget.AppCompat.ActionMode</item>
+ <item name="actionModeBackground">@drawable/abc_cab_background_top_holo_dark</item>
+ <item name="actionModeSplitBackground">@drawable/abc_cab_background_bottom_holo_dark</item>
+ <item name="actionModeCloseDrawable">@drawable/abc_ic_cab_done_holo_dark</item>
+ <item name="actionModeCloseButtonStyle">@style/Widget.AppCompat.ActionButton.CloseMode</item>
+
+ <!-- Panel attributes -->
+ <item name="panelMenuListWidth">@dimen/abc_panel_menu_list_width</item>
+ <item name="panelMenuListTheme">@style/Theme.AppCompat.CompactMenu</item>
+ <item name="android:panelBackground">@drawable/abc_menu_hardkey_panel_holo_dark</item>
+ <item name="listChoiceBackgroundIndicator">@drawable/abc_list_selector_holo_dark</item>
+ </style>
+
+ <style name="Theme.Base.AppCompat.Dialog.Light.FixedSize" parent="Theme.Base.AppCompat.Dialog.FixedSize" />
+
+ <style name="Theme.Base.AppCompat.DialogWhenLarge" parent="Theme.Base.AppCompat"></style>
+
+ <style name="Theme.Base.AppCompat.Light" parent="Theme.Base.Light">
+ <item name="windowActionBar">true</item>
+ <!-- Remove system title bars; we will add the action bar ourselves. -->
+ <item name="android:windowNoTitle">true</item>
+ <item name="buttonBarStyle">@android:style/ButtonBar</item>
+ <item name="buttonBarButtonStyle">@android:style/Widget.Button</item>
+ <item name="selectableItemBackground">@drawable/abc_item_background_holo_light</item>
+ <item name="homeAsUpIndicator">@drawable/abc_ic_ab_back_holo_light</item>
+ <item name="dividerVertical">@drawable/abc_list_divider_holo_light</item>
+ <item name="dividerHorizontal">@drawable/abc_list_divider_holo_light</item>
+ <item name="listPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="listPreferredItemHeightSmall">48dp</item>
+ <item name="listPreferredItemHeightLarge">80dp</item>
+ <item name="listPreferredItemPaddingLeft">8dip</item>
+ <item name="listPreferredItemPaddingRight">8dip</item>
+ <item name="textAppearanceListItem">?android:attr/textAppearanceMedium</item>
+ <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+
+ <!-- Action Bar Styles -->
+ <item name="actionBarTabStyle">@style/Widget.AppCompat.Light.ActionBar.TabView</item>
+ <item name="actionBarTabBarStyle">@style/Widget.AppCompat.Light.ActionBar.TabBar</item>
+ <item name="actionBarTabTextStyle">@style/Widget.AppCompat.Light.ActionBar.TabText</item>
+ <item name="actionButtonStyle">@style/Widget.AppCompat.Light.ActionButton</item>
+ <item name="actionOverflowButtonStyle"> @style/Widget.AppCompat.Light.ActionButton.Overflow</item>
+ <item name="actionBarStyle">@style/Widget.AppCompat.Light.ActionBar</item>
+ <item name="actionBarSplitStyle">?attr/actionBarStyle</item>
+ <item name="actionBarWidgetTheme">@null</item>
+ <item name="actionBarSize">@dimen/abc_action_bar_default_height</item>
+ <item name="actionBarDivider">?attr/dividerVertical</item>
+ <item name="actionBarItemBackground">?attr/selectableItemBackground</item>
+ <item name="actionMenuTextAppearance"> @style/TextAppearance.AppCompat.Widget.ActionBar.Menu</item>
+ <item name="actionMenuTextColor">?android:attr/textColorPrimaryDisableOnly</item>
+
+ <!-- Action Mode -->
+ <item name="actionModeStyle">@style/Widget.AppCompat.ActionMode</item>
+ <item name="actionModeBackground">@drawable/abc_cab_background_top_holo_light</item>
+ <item name="actionModeSplitBackground">@drawable/abc_cab_background_bottom_holo_light</item>
+ <item name="actionModeCloseDrawable">@drawable/abc_ic_cab_done_holo_light</item>
+ <item name="actionModeCloseButtonStyle">@style/Widget.AppCompat.Light.ActionButton.CloseMode</item>
+
+ <!-- Dropdown Spinner Attributes -->
+ <item name="actionDropDownStyle"> @style/Widget.AppCompat.Light.Spinner.DropDown.ActionBar</item>
+
+ <!-- Panel attributes -->
+ <item name="panelMenuListWidth">@dimen/abc_panel_menu_list_width</item>
+ <item name="panelMenuListTheme">@style/Theme.AppCompat.CompactMenu</item>
+ <item name="android:panelBackground">@drawable/abc_menu_hardkey_panel_holo_light</item>
+ <item name="listChoiceBackgroundIndicator">@drawable/abc_list_selector_holo_light</item>
+ </style>
+
+ <style name="Theme.Base.AppCompat.Light.DarkActionBar" parent="Theme.Base.AppCompat.Light">
+ <item name="homeAsUpIndicator">@drawable/abc_ic_ab_back_holo_dark</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.AppCompat.ActionButton.Overflow</item>
+ <item name="actionBarStyle">@style/Widget.AppCompat.Light.ActionBar.Solid.Inverse</item>
+ <item name="actionBarWidgetTheme">@style/Theme.AppCompat</item>
+ <item name="actionBarDivider">@drawable/abc_list_divider_holo_dark</item>
+ <item name="actionBarItemBackground">@drawable/abc_item_background_holo_dark</item>
+ <item name="actionBarTabStyle">@style/Widget.AppCompat.Light.ActionBar.TabView.Inverse</item>
+ <item name="actionBarTabBarStyle">@style/Widget.AppCompat.Light.ActionBar.TabBar.Inverse</item>
+ <item name="actionBarTabTextStyle">@style/Widget.AppCompat.Light.ActionBar.TabText.Inverse</item>
+ <item name="actionMenuTextColor">?android:attr/textColorPrimaryInverseDisableOnly</item>
+
+ <!-- Action Mode -->
+ <item name="actionModeStyle">@style/Widget.AppCompat.Light.ActionMode.Inverse</item>
+ <item name="actionModeBackground">@drawable/abc_cab_background_top_holo_dark</item>
+ <item name="actionModeSplitBackground">@drawable/abc_cab_background_bottom_holo_dark</item>
+ <item name="actionModeCloseDrawable">@drawable/abc_ic_cab_done_holo_dark</item>
+ <item name="actionModeCloseButtonStyle">@style/Widget.AppCompat.ActionButton.CloseMode</item>
+
+ <!-- Dropdown Spinner Attributes -->
+ <item name="actionDropDownStyle">@style/Widget.AppCompat.Spinner.DropDown.ActionBar</item>
+
+ <!-- Panel attributes -->
+ <item name="android:panelBackground">@drawable/abc_menu_hardkey_panel_holo_dark</item>
+ <item name="listChoiceBackgroundIndicator">@drawable/abc_list_selector_holo_dark</item>
+ </style>
+
+ <style name="Theme.Base.AppCompat.Light.DialogWhenLarge" parent="Theme.Base.AppCompat.Light"></style>
+
+ <style name="Theme.Base.Light" parent="android:Theme.Light"></style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles.xml -->
+ <eat-comment />
+
+ <style name="Widget.AppCompat.ActionBar" parent="Widget.AppCompat.Base.ActionBar"></style>
+
+ <style name="Widget.AppCompat.ActionBar.Solid" parent="Widget.AppCompat.Base.ActionBar.Solid"></style>
+
+ <style name="Widget.AppCompat.ActionBar.TabBar" parent="Widget.AppCompat.Base.ActionBar.TabBar"></style>
+
+ <style name="Widget.AppCompat.ActionBar.TabText" parent="Widget.AppCompat.Base.ActionBar.TabText"></style>
+
+ <style name="Widget.AppCompat.ActionBar.TabView" parent="Widget.AppCompat.Base.ActionBar.TabView"></style>
+
+ <style name="Widget.AppCompat.ActionButton" parent="Widget.AppCompat.Base.ActionButton"></style>
+
+ <style name="Widget.AppCompat.ActionButton.CloseMode" parent="Widget.AppCompat.Base.ActionButton.CloseMode"></style>
+
+ <style name="Widget.AppCompat.ActionButton.Overflow" parent="Widget.AppCompat.Base.ActionButton.Overflow"></style>
+
+ <style name="Widget.AppCompat.ActionMode" parent="Widget.AppCompat.Base.ActionMode"></style>
+
+ <style name="Widget.AppCompat.ActivityChooserView" parent="Widget.AppCompat.Base.ActivityChooserView"></style>
+
+ <style name="Widget.AppCompat.AutoCompleteTextView" parent="Widget.AppCompat.Base.AutoCompleteTextView"></style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles_base.xml -->
+ <eat-comment />
+
+ <style name="Widget.AppCompat.Base.ActionBar" parent="">
+ <item name="displayOptions">useLogo|showHome|showTitle</item>
+ <item name="divider">?attr/dividerVertical</item>
+ <item name="height">?attr/actionBarSize</item>
+ <item name="homeLayout">@layout/abc_action_bar_home</item>
+ <item name="titleTextStyle">@style/TextAppearance.AppCompat.Widget.ActionBar.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle</item>
+ <item name="background">@drawable/abc_ab_transparent_dark_holo</item>
+ <item name="backgroundStacked">@drawable/abc_ab_stacked_transparent_dark_holo</item>
+ <item name="backgroundSplit">@drawable/abc_ab_bottom_transparent_dark_holo</item>
+ <item name="actionButtonStyle">@style/Widget.AppCompat.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.AppCompat.ActionButton.Overflow</item>
+ <item name="progressBarStyle">@style/Widget.AppCompat.ProgressBar.Horizontal</item>
+ <item name="indeterminateProgressStyle">@style/Widget.AppCompat.ProgressBar</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ActionBar.Solid" parent="Widget.AppCompat.Base.ActionBar">
+ <item name="background">@drawable/abc_ab_solid_dark_holo</item>
+ <item name="backgroundStacked">@drawable/abc_ab_stacked_solid_dark_holo</item>
+ <item name="backgroundSplit">@drawable/abc_ab_bottom_solid_dark_holo</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ActionBar.TabBar" parent="">
+ <item name="divider">?attr/actionBarDivider</item>
+ <item name="showDividers">middle</item>
+ <item name="dividerPadding">12dip</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ActionBar.TabText" parent="">
+ <item name="android:textAppearance">@null</item>
+ <item name="android:textColor">?android:attr/textColorPrimaryDisableOnly</item>
+ <item name="android:textSize">12sp</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:maxLines">2</item>
+ <item name="textAllCaps">true</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ActionBar.TabView" parent="">
+ <item name="android:background">@drawable/abc_tab_indicator_ab_holo</item>
+ <item name="android:gravity">center_horizontal</item>
+ <item name="android:paddingLeft">16dip</item>
+ <item name="android:paddingRight">16dip</item>
+ <item name="android:minWidth">80dip</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ActionButton" parent="">
+ <item name="android:background">?attr/actionBarItemBackground</item>
+ <item name="android:paddingLeft">12dip</item>
+ <item name="android:paddingRight">12dip</item>
+ <item name="android:minWidth">@dimen/abc_action_button_min_width</item>
+ <item name="android:minHeight">?attr/actionBarSize</item>
+ <item name="android:gravity">center</item>
+ <item name="android:maxLines">2</item>
+ <item name="textAllCaps">@bool/abc_config_actionMenuItemAllCaps</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ActionButton.CloseMode" parent="Widget.AppCompat.Base.ActionButton"></style>
+
+ <style name="Widget.AppCompat.Base.ActionButton.Overflow" parent="Widget.AppCompat.Base.ActionButton">
+ <item name="android:src">@drawable/abc_ic_menu_moreoverflow_normal_holo_dark</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ActionMode" parent="">
+ <item name="background">?attr/actionModeBackground</item>
+ <item name="backgroundSplit">?attr/actionModeSplitBackground</item>
+ <item name="height">?attr/actionBarSize</item>
+ <item name="titleTextStyle">@style/TextAppearance.AppCompat.Widget.ActionMode.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.AppCompat.Widget.ActionMode.Subtitle</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ActivityChooserView" parent="">
+ <item name="android:gravity">center</item>
+ <item name="android:background">@drawable/abc_ab_share_pack_holo_dark</item>
+ <item name="divider">?attr/dividerVertical</item>
+ <item name="showDividers">middle</item>
+ <item name="dividerPadding">6dip</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.AutoCompleteTextView" parent="android:Widget.AutoCompleteTextView">
+ <item name="android:textColor">?attr/actionMenuTextColor</item>
+ <item name="android:dropDownSelector">@drawable/abc_list_selector_holo_dark</item>
+ <item name="android:popupBackground">@drawable/abc_menu_dropdown_panel_holo_dark</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.DropDownItem.Spinner" parent="">
+ <item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.DropDownItem</item>
+ <item name="android:paddingLeft">8dp</item>
+ <item name="android:paddingRight">8dp</item>
+ <item name="android:gravity">center_vertical</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ListPopupWindow" parent="">
+ <item name="android:dropDownSelector">@drawable/abc_list_selector_holo_dark</item>
+ <item name="android:popupBackground">@drawable/abc_menu_dropdown_panel_holo_dark</item>
+ <item name="android:dropDownVerticalOffset">0dip</item>
+ <item name="android:dropDownHorizontalOffset">0dip</item>
+ <item name="android:dropDownWidth">wrap_content</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ListView.DropDown" parent="android:Widget.ListView">
+ <item name="android:listSelector">@drawable/abc_list_selector_holo_dark</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ListView.Menu" parent="android:Widget.ListView.Menu">
+ <item name="android:listSelector">?attr/listChoiceBackgroundIndicator</item>
+ <item name="android:divider">?attr/dividerHorizontal</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.PopupMenu" parent="@style/Widget.AppCompat.Base.ListPopupWindow"></style>
+
+ <style name="Widget.AppCompat.Base.ProgressBar" parent="android:Widget.ProgressBar">
+ <item name="android:minWidth">@dimen/abc_action_bar_progress_bar_size</item>
+ <item name="android:maxWidth">@dimen/abc_action_bar_progress_bar_size</item>
+ <item name="android:minHeight">@dimen/abc_action_bar_progress_bar_size</item>
+ <item name="android:maxHeight">@dimen/abc_action_bar_progress_bar_size</item>
+ </style>
+
+ <style name="Widget.AppCompat.Base.ProgressBar.Horizontal" parent="android:Widget.ProgressBar.Horizontal"></style>
+
+ <style name="Widget.AppCompat.Base.Spinner" parent="">
+ <item name="spinnerMode">dropdown</item>
+ <item name="android:popupBackground">@drawable/abc_menu_dropdown_panel_holo_dark</item>
+ <item name="android:dropDownSelector">@drawable/abc_list_selector_holo_dark</item>
+ <item name="android:dropDownVerticalOffset">0dip</item>
+ <item name="android:dropDownHorizontalOffset">0dip</item>
+ <item name="android:dropDownWidth">wrap_content</item>
+ <item name="android:gravity">left|center_vertical</item>
+ <item name="android:clickable">true</item>
+ <item name="android:background">@drawable/abc_spinner_ab_holo_dark</item>
+ </style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles.xml -->
+ <eat-comment />
+
+ <style name="Widget.AppCompat.DropDownItem.Spinner" parent="Widget.AppCompat.Base.DropDownItem.Spinner"></style>
+
+ <style name="Widget.AppCompat.Light.ActionBar" parent="Widget.AppCompat.Light.Base.ActionBar"></style>
+
+ <style name="Widget.AppCompat.Light.ActionBar.Solid" parent="Widget.AppCompat.Light.Base.ActionBar.Solid"></style>
+
+ <style name="Widget.AppCompat.Light.ActionBar.Solid.Inverse" parent="Widget.AppCompat.Light.Base.ActionBar.Solid.Inverse"></style>
+
+ <style name="Widget.AppCompat.Light.ActionBar.TabBar" parent="Widget.AppCompat.Light.Base.ActionBar.TabBar"></style>
+
+ <style name="Widget.AppCompat.Light.ActionBar.TabBar.Inverse" parent="Widget.AppCompat.Light.Base.ActionBar.TabBar.Inverse" />
+
+ <style name="Widget.AppCompat.Light.ActionBar.TabText" parent="Widget.AppCompat.Light.Base.ActionBar.TabText"></style>
+
+ <style name="Widget.AppCompat.Light.ActionBar.TabText.Inverse" parent="Widget.AppCompat.Light.Base.ActionBar.TabText.Inverse"></style>
+
+ <style name="Widget.AppCompat.Light.ActionBar.TabView" parent="Widget.AppCompat.Light.Base.ActionBar.TabView"></style>
+
+ <style name="Widget.AppCompat.Light.ActionBar.TabView.Inverse" parent="Widget.AppCompat.Light.Base.ActionBar.TabView.Inverse"></style>
+
+ <style name="Widget.AppCompat.Light.ActionButton" parent="Widget.AppCompat.Light.Base.ActionButton"></style>
+
+ <style name="Widget.AppCompat.Light.ActionButton.CloseMode" parent="Widget.AppCompat.Light.Base.ActionButton.CloseMode"></style>
+
+ <style name="Widget.AppCompat.Light.ActionButton.Overflow" parent="Widget.AppCompat.Light.Base.ActionButton.Overflow"></style>
+
+ <style name="Widget.AppCompat.Light.ActionMode.Inverse" parent="Widget.AppCompat.Light.Base.ActionMode.Inverse"></style>
+
+ <style name="Widget.AppCompat.Light.ActivityChooserView" parent="Widget.AppCompat.Light.Base.ActivityChooserView"></style>
+
+ <style name="Widget.AppCompat.Light.AutoCompleteTextView" parent="Widget.AppCompat.Light.Base.AutoCompleteTextView"></style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles_base.xml -->
+ <eat-comment />
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar" parent="Widget.AppCompat.Base.ActionBar">
+ <item name="background">@drawable/abc_ab_transparent_light_holo</item>
+ <item name="backgroundStacked">@drawable/abc_ab_stacked_transparent_light_holo</item>
+ <item name="backgroundSplit">@drawable/abc_ab_bottom_transparent_light_holo</item>
+ <item name="actionButtonStyle">@style/Widget.AppCompat.Light.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.AppCompat.Light.ActionButton.Overflow</item>
+ <item name="progressBarStyle">@style/Widget.AppCompat.ProgressBar.Horizontal</item>
+ <item name="indeterminateProgressStyle">@style/Widget.AppCompat.ProgressBar</item>
+ </style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.Solid" parent="Widget.AppCompat.Light.Base.ActionBar">
+ <item name="background">@drawable/abc_ab_solid_light_holo</item>
+ <item name="backgroundStacked">@drawable/abc_ab_stacked_solid_light_holo</item>
+ <item name="backgroundSplit">@drawable/abc_ab_bottom_solid_light_holo</item>
+ </style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.Solid.Inverse" parent="Widget.AppCompat.Base.ActionBar.Solid">
+ <item name="titleTextStyle"> @style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse</item>
+ <item name="subtitleTextStyle"> @style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle.Inverse</item>
+ <item name="actionButtonStyle">@style/Widget.AppCompat.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.AppCompat.ActionButton.Overflow</item>
+ </style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabBar" parent="Widget.AppCompat.Base.ActionBar.TabBar"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabBar.Inverse" parent="Widget.AppCompat.Light.Base.ActionBar.TabBar"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabText" parent="Widget.AppCompat.Base.ActionBar.TabText"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabText.Inverse" parent="Widget.AppCompat.Light.Base.ActionBar.TabText">
+ <item name="android:textColor">?android:attr/textColorPrimaryInverseDisableOnly</item>
+ </style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabView" parent="Widget.AppCompat.Base.ActionBar.TabView"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionBar.TabView.Inverse" parent="Widget.AppCompat.Light.Base.ActionBar.TabView"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionButton" parent="Widget.AppCompat.Base.ActionButton"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionButton.CloseMode" parent="Widget.AppCompat.Light.Base.ActionButton"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionButton.Overflow" parent="Widget.AppCompat.Light.Base.ActionButton">
+ <item name="android:src">@drawable/abc_ic_menu_moreoverflow_normal_holo_light</item>
+ </style>
+
+ <style name="Widget.AppCompat.Light.Base.ActionMode.Inverse" parent="Widget.AppCompat.Base.ActionMode">
+ <item name="titleTextStyle"> @style/TextAppearance.AppCompat.Widget.ActionMode.Title.Inverse</item>
+ <item name="subtitleTextStyle"> @style/TextAppearance.AppCompat.Widget.ActionMode.Subtitle.Inverse</item>
+ </style>
+
+ <style name="Widget.AppCompat.Light.Base.ActivityChooserView" parent="Widget.AppCompat.Base.ActivityChooserView">
+ <item name="android:background">@drawable/abc_ab_share_pack_holo_light</item>
+ </style>
+
+ <style name="Widget.AppCompat.Light.Base.AutoCompleteTextView" parent="android:Widget.AutoCompleteTextView">
+ <item name="android:textColor">?attr/actionMenuTextColor</item>
+ <item name="android:dropDownSelector">@drawable/abc_list_selector_holo_light</item>
+ <item name="android:popupBackground">@drawable/abc_menu_dropdown_panel_holo_light</item>
+ </style>
+
+ <style name="Widget.AppCompat.Light.Base.DropDownItem.Spinner" parent="Widget.AppCompat.Base.DropDownItem.Spinner"></style>
+
+ <style name="Widget.AppCompat.Light.Base.ListPopupWindow" parent="">
+ <item name="android:dropDownSelector">@drawable/abc_list_selector_holo_light</item>
+ <item name="android:popupBackground">@drawable/abc_menu_dropdown_panel_holo_light</item>
+ <item name="android:dropDownVerticalOffset">0dip</item>
+ <item name="android:dropDownHorizontalOffset">0dip</item>
+ <item name="android:dropDownWidth">wrap_content</item>
+ </style>
+
+ <style name="Widget.AppCompat.Light.Base.ListView.DropDown" parent="android:Widget.ListView">
+ <item name="android:listSelector">@drawable/abc_list_selector_holo_light</item>
+ </style>
+
+ <style name="Widget.AppCompat.Light.Base.PopupMenu" parent="@style/Widget.AppCompat.Light.Base.ListPopupWindow"></style>
+
+ <style name="Widget.AppCompat.Light.Base.Spinner" parent="Widget.AppCompat.Base.Spinner">
+ <item name="android:dropDownSelector">@drawable/abc_list_selector_holo_light</item>
+ <item name="android:popupBackground">@drawable/abc_menu_dropdown_panel_holo_light</item>
+ <item name="android:background">@drawable/abc_spinner_ab_holo_light</item>
+ </style>
+ <!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/klp-ub-dev/frameworks/support/v7/appcompat/res/values/styles.xml -->
+ <eat-comment />
+
+ <style name="Widget.AppCompat.Light.DropDownItem.Spinner" parent="Widget.AppCompat.Light.Base.DropDownItem.Spinner"></style>
+
+ <style name="Widget.AppCompat.Light.ListPopupWindow" parent="Widget.AppCompat.Light.Base.ListPopupWindow"></style>
+
+ <style name="Widget.AppCompat.Light.ListView.DropDown" parent="Widget.AppCompat.Light.Base.ListView.DropDown"></style>
+
+ <style name="Widget.AppCompat.Light.PopupMenu" parent="Widget.AppCompat.Light.Base.PopupMenu"></style>
+
+ <style name="Widget.AppCompat.Light.Spinner.DropDown.ActionBar" parent="Widget.AppCompat.Light.Base.Spinner"></style>
+
+ <style name="Widget.AppCompat.ListPopupWindow" parent="Widget.AppCompat.Base.ListPopupWindow"></style>
+
+ <style name="Widget.AppCompat.ListView.DropDown" parent="Widget.AppCompat.Base.ListView.DropDown"></style>
+
+ <style name="Widget.AppCompat.ListView.Menu" parent="Widget.AppCompat.Base.ListView.Menu"></style>
+
+ <style name="Widget.AppCompat.PopupMenu" parent="Widget.AppCompat.Base.PopupMenu"></style>
+
+ <style name="Widget.AppCompat.ProgressBar" parent="Widget.AppCompat.Base.ProgressBar"></style>
+
+ <style name="Widget.AppCompat.ProgressBar.Horizontal" parent="Widget.AppCompat.Base.ProgressBar.Horizontal"></style>
+
+ <style name="Widget.AppCompat.Spinner.DropDown.ActionBar" parent="Widget.AppCompat.Base.Spinner"></style>
+
+</resources>
--- /dev/null
+# Ignore everything in this directory
+*
+# Except this file
+!.gitignore
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.owncloud.android.workaround.accounts"
- android:versionCode="0100019"
- android:versionName="1.0.19" >
+ android:versionCode="0100024"
+ android:versionName="1.0.24" >
<uses-sdk
android:minSdkVersion="16"
--- /dev/null
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.13.0'
+ }
+}
+apply plugin: 'com.android.library'
+
+dependencies {
+ compile fileTree(dir: 'libs', include: '*.jar')
+}
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion "20.0.0"
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ resources.srcDirs = ['src']
+ aidl.srcDirs = ['src']
+ renderscript.srcDirs = ['src']
+ res.srcDirs = ['res']
+ assets.srcDirs = ['assets']
+ }
+
+ // Move the tests to tests/java, tests/res, etc...
+ instrumentTest.setRoot('tests')
+
+ // Move the build types to build-types/<type>
+ // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
+ // This moves them out of them default location under src/<type>/... which would
+ // conflict with src/ being used by the main source set.
+ // Adding new build types or product flavors should be accompanied
+ // by a similar customization.
+ debug.setRoot('build-types/debug')
+ release.setRoot('build-types/release')
+ }
+}
--- /dev/null
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
--- /dev/null
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
--- /dev/null
+@if "%DEBUG%" == "" @echo off\r
+@rem ##########################################################################\r
+@rem\r
+@rem Gradle startup script for Windows\r
+@rem\r
+@rem ##########################################################################\r
+\r
+@rem Set local scope for the variables with windows NT shell\r
+if "%OS%"=="Windows_NT" setlocal\r
+\r
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r
+set DEFAULT_JVM_OPTS=\r
+\r
+set DIRNAME=%~dp0\r
+if "%DIRNAME%" == "" set DIRNAME=.\r
+set APP_BASE_NAME=%~n0\r
+set APP_HOME=%DIRNAME%\r
+\r
+@rem Find java.exe\r
+if defined JAVA_HOME goto findJavaFromJavaHome\r
+\r
+set JAVA_EXE=java.exe\r
+%JAVA_EXE% -version >NUL 2>&1\r
+if "%ERRORLEVEL%" == "0" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:findJavaFromJavaHome\r
+set JAVA_HOME=%JAVA_HOME:"=%\r
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe\r
+\r
+if exist "%JAVA_EXE%" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:init\r
+@rem Get command-line arguments, handling Windowz variants\r
+\r
+if not "%OS%" == "Windows_NT" goto win9xME_args\r
+if "%@eval[2+2]" == "4" goto 4NT_args\r
+\r
+:win9xME_args\r
+@rem Slurp the command line arguments.\r
+set CMD_LINE_ARGS=\r
+set _SKIP=2\r
+\r
+:win9xME_args_slurp\r
+if "x%~1" == "x" goto execute\r
+\r
+set CMD_LINE_ARGS=%*\r
+goto execute\r
+\r
+:4NT_args\r
+@rem Get arguments from the 4NT Shell from JP Software\r
+set CMD_LINE_ARGS=%$\r
+\r
+:execute\r
+@rem Setup the command line\r
+\r
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar\r
+\r
+@rem Execute Gradle\r
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r
+\r
+:end\r
+@rem End local scope for the variables with windows NT shell\r
+if "%ERRORLEVEL%"=="0" goto mainEnd\r
+\r
+:fail\r
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r
+rem the _cmd.exe /c_ return code!\r
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1\r
+exit /b 1\r
+\r
+:mainEnd\r
+if "%OS%"=="Windows_NT" endlocal\r
+\r
+:omega\r
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
-target=android-17
+target=android-19
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
/* ownCloud Jelly Bean Workaround for lost credentials
- * Copyright (C) 2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
-Subproject commit 5bd0d7387712ce3f53869294761ac4d8537841cd
+Subproject commit 02c24c8a3bd87382590ece0e0744ad430718b51a
<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.owncloud.android</groupId>
<owncloud.version>1.5.1-SNAPSHOT</owncloud.version>
<java-version>1.6</java-version>
<!-- Given by maven-android-sdk-deployer -->
- <google.android-version>4.4.2_r3</google.android-version>
+ <google.android-version>4.4.2_r4</google.android-version>
<!-- Usually the latest Android API -->
<google.android-api>19</google.android-api>
<actionbarsherlock-version>4.2.0</actionbarsherlock-version>
<developerConnection>scm:git:git@github.com:owncloud/android.git</developerConnection>
<url>https://github.com/owncloud/android</url>
</scm>
-
+
+
+ <!--<repositories>-->
+ <!--<repository>-->
+ <!--<id>android-support</id>-->
+ <!--<url>file://${env.ANDROID_HOME}/extras/android/m2repository</url>-->
+ <!--</repository>-->
+ <!--</repositories>-->
+
<dependencies>
+
<!-- Dirty trick, but it works. TouchImageView library is not available as Maven project. -->
<dependency>
<groupId>touch-image-view.jar</groupId>
<version>19.1.0</version>
</dependency>-->
<!-- Instead we need to include the exact same version -->
+
+ <dependency>
+ <groupId>com.jakewharton</groupId>
+ <artifactId>disklrucache</artifactId>
+ <version>2.0.2</version>
+ </dependency>
+
<dependency>
<groupId>android-support-v4.jar</groupId>
<artifactId>android-support-v4.jar</artifactId>
<scope>system</scope>
<systemPath>${basedir}/third_party/android-support-library/android-support-v4.jar</systemPath>
</dependency>
-
- <dependency>
- <groupId>android</groupId>
- <artifactId>android</artifactId>
- <version>${google.android-version}</version>
- <scope>provided</scope>
- </dependency>
+
<dependency>
<groupId>com.actionbarsherlock</groupId>
- <artifactId>actionbarsherlock</artifactId>
+ <artifactId>library</artifactId>
<version>${actionbarsherlock-version}</version>
- <scope>provided</scope>
+ <type>apklib</type>
</dependency>
<dependency>
- <groupId>com.actionbarsherlock</groupId>
- <artifactId>actionbarsherlock</artifactId>
- <version>${actionbarsherlock-version}</version>
- <type>apklib</type>
+ <groupId>android</groupId>
+ <artifactId>android</artifactId>
+ <version>${google.android-version}</version>
+ <scope>provided</scope>
</dependency>
+ <!--<dependency>-->
+ <!--<groupId>android.support</groupId>-->
+ <!--<artifactId>compatibility-v4</artifactId>-->
+ <!--<version>19.1.0</version>-->
+ <!--</dependency>-->
+
+
<!-- MUST BE INSTALLED FIRST: cd owncloud-android-library; mvn install -->
<dependency>
- <groupId>com.owncloud.android</groupId>
- <artifactId>owncloud-android-library</artifactId>
- <version>${owncloud.version}</version>
- </dependency>
+ <groupId>com.owncloud.android</groupId>
+ <artifactId>owncloud-android-library</artifactId>
+ <version>${owncloud.version}</version>
+ </dependency>
</dependencies>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.0</version>
+ <version>3.1</version>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
- <version>3.8.0</version>
+ <version>3.8.2</version>
<configuration>
<sdk>
<path>${env.ANDROID_HOME}</path>
# Project target.
target=android-19
-android.library.reference.1=actionbarsherlock/library
-android.library.reference.2=owncloud-android-library
+android.library.reference.1=owncloud-android-library
+android.library.reference.2=libs/android-support-appcompat-v7-exploded-aar
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
android:orientation="horizontal" >\r
\r
<ImageView\r
- android:id="@+id/imageView1"\r
+ android:id="@+id/thumbnail"\r
android:layout_width="0dp"\r
android:layout_height="wrap_content"\r
android:layout_weight="1"\r
android:layout_gravity="center"\r
android:background="@color/login_logo_background_color"\r
- android:src="@drawable/logo" \r
+ android:src="@drawable/logo"\r
+ android:contentDescription="@string/app_name"\r
/>\r
\r
<ScrollView\r
android:layout_marginBottom="10dp"\r
android:onClick="onRefreshClick"\r
android:text="@string/auth_check_server"\r
- android:visibility="gone" />\r
+ android:visibility="gone"\r
+ android:contentDescription="@string/auth_check_server"/>\r
<TextView\r
android:id="@+id/instructions_message"\r
android:layout_width="wrap_content"\r
android:layout_gravity="fill_horizontal"\r
android:text="@string/auth_expired_basic_auth_toast" \r
android:visibility="gone"\r
- android:layout_marginBottom="10dp"/>\r
+ android:layout_marginBottom="10dp"\r
+ android:contentDescription="@string/auth_expired_basic_auth_toast"/>\r
<FrameLayout \r
android:id="@+id/hostUrlFrame"\r
android:layout_width="match_parent"\r
android:inputType="textUri"\r
android:drawablePadding="5dp"\r
android:paddingRight="55dp"\r
+ android:contentDescription="@string/auth_host_address"\r
>\r
<requestFocus />\r
</EditText>\r
android:onClick="onRefreshClick"\r
android:visibility="gone"\r
android:background="@android:color/transparent"\r
+ android:contentDescription="@string/auth_refresh_button"\r
/>\r
</FrameLayout>\r
\r
android:drawableLeft="@android:drawable/stat_notify_sync"\r
android:drawablePadding="5dp"\r
android:gravity="center_vertical"\r
- android:text="@string/auth_testing_connection" />\r
+ android:text="@string/auth_testing_connection"\r
+ android:contentDescription="@string/auth_testing_connection"/>\r
\r
<CheckBox\r
android:id="@+id/oauth_onOff_check"\r
android:onClick="onCheckClick"\r
android:text="@string/oauth_check_onoff"\r
android:textAppearance="?android:attr/textAppearanceSmall"\r
+ android:contentDescription="@string/oauth_check_onoff"\r
/>\r
\r
<EditText\r
android:text="@string/oauth2_url_endpoint_auth"\r
android:singleLine="true"\r
android:inputType="textUri"\r
- android:visibility="gone" >\r
+ android:visibility="gone">\r
</EditText> \r
\r
<EditText\r
android:text="@string/oauth2_url_endpoint_access"\r
android:singleLine="true"\r
android:inputType="textUri"\r
- android:visibility="gone" >\r
+ android:visibility="gone">\r
<requestFocus />\r
</EditText> \r
\r
android:layout_height="wrap_content"\r
android:ems="10"\r
android:hint="@string/auth_username"\r
- android:inputType="textNoSuggestions" />\r
+ android:inputType="textNoSuggestions"\r
+ android:contentDescription="@string/auth_username"\r
+ />\r
\r
<EditText\r
android:id="@+id/account_password"\r
android:hint="@string/auth_password"\r
android:inputType="textPassword"\r
android:drawablePadding="5dp"\r
+ android:contentDescription="@string/auth_password"\r
/>\r
\r
<TextView\r
android:text="@string/auth_unauthorized"\r
android:drawableLeft="@android:drawable/stat_notify_sync"\r
android:drawablePadding="5dip"\r
+ android:contentDescription="@string/auth_unauthorized"\r
/>\r
\r
</LinearLayout>\r
android:layout_gravity="center_horizontal"\r
android:enabled="false"\r
android:onClick="onOkClick"\r
- android:text="@string/setup_btn_connect" />\r
+ android:text="@string/setup_btn_connect"\r
+ android:contentDescription="@string/setup_btn_connect"/>\r
\r
<Button\r
android:id="@+id/welcome_link"\r
android:paddingBottom="5dp"\r
android:paddingTop="5dp"\r
android:text="@string/auth_register"\r
- android:textColor="#0000FF"/>\r
+ android:textColor="#0000FF"\r
+ android:contentDescription="@string/auth_register"/>\r
</LinearLayout>\r
\r
</RelativeLayout>\r
<!--
ownCloud Android client application
- Copyright (C) 2012-2014 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<?xml version="1.0" encoding="utf-8"?>
<!--
ownCloud Android client application
- Copyright (C) 2014 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
android:padding="8dp" >\r
\r
<ImageView\r
- android:id="@+id/imageView1"\r
+ android:id="@+id/thumbnail"\r
android:layout_width="match_parent"\r
android:layout_height="wrap_content"\r
android:layout_marginBottom="10dp"\r
android:layout_marginTop="10dp"\r
android:background="@color/login_logo_background_color"\r
- android:src="@drawable/logo" />\r
+ android:src="@drawable/logo"\r
+ android:contentDescription="@string/app_name"/>\r
\r
<Button\r
android:id="@+id/centeredRefreshButton"\r
android:layout_marginBottom="10dp"\r
android:onClick="onRefreshClick"\r
android:text="@string/auth_check_server"\r
- android:visibility="gone" />\r
+ android:visibility="gone"\r
+ android:contentDescription="@string/auth_check_server"/>\r
\r
<TextView\r
android:id="@+id/instructions_message"\r
android:layout_gravity="fill_horizontal"\r
android:text="@string/auth_expired_basic_auth_toast"\r
android:visibility="gone"\r
- android:layout_marginBottom="10dp" />\r
+ android:layout_marginBottom="10dp"\r
+ android:contentDescription="@string/auth_expired_basic_auth_toast"/>\r
\r
<FrameLayout \r
android:id="@+id/hostUrlFrame"\r
android:inputType="textUri"\r
android:drawablePadding="5dp"\r
android:paddingRight="55dp"\r
- >\r
+ android:contentDescription="@string/auth_host_address"\r
+ >\r
<requestFocus />\r
</EditText>\r
<ImageButton\r
android:onClick="onRefreshClick"\r
android:visibility="gone"\r
android:background="@android:color/transparent"\r
+ android:contentDescription="@string/auth_refresh_button"\r
/>\r
</FrameLayout>\r
\r
android:drawableLeft="@android:drawable/stat_notify_sync"\r
android:drawablePadding="5dp"\r
android:gravity="center_vertical"\r
- android:text="@string/auth_testing_connection" />\r
+ android:text="@string/auth_testing_connection"\r
+ android:contentDescription="@string/auth_testing_connection"/>\r
\r
<CheckBox\r
android:id="@+id/oauth_onOff_check"\r
android:onClick="onCheckClick"\r
android:text="@string/oauth_check_onoff"\r
android:textAppearance="?android:attr/textAppearanceSmall"\r
+ android:contentDescription="@string/oauth_check_onoff"\r
/>\r
\r
<EditText\r
android:text="@string/oauth2_url_endpoint_auth"\r
android:singleLine="true"\r
android:inputType="textUri"\r
- android:visibility="gone" >\r
+ android:visibility="gone">\r
</EditText>\r
\r
<EditText\r
android:text="@string/oauth2_url_endpoint_access"\r
android:singleLine="true"\r
android:inputType="textUri"\r
- android:visibility="gone" />\r
+ android:visibility="gone"/>\r
\r
<EditText\r
android:id="@+id/account_username"\r
android:layout_height="wrap_content"\r
android:ems="10"\r
android:hint="@string/auth_username"\r
- android:inputType="textNoSuggestions" \r
- />\r
+ android:inputType="textNoSuggestions"\r
+ android:contentDescription="@string/auth_username"\r
+ />\r
\r
<EditText\r
android:id="@+id/account_password"\r
android:drawablePadding="5dp"\r
android:ems="10"\r
android:hint="@string/auth_password"\r
- android:inputType="textPassword" \r
+ android:inputType="textPassword"\r
+ android:contentDescription="@string/auth_password"\r
/>\r
\r
<TextView\r
android:drawableLeft="@android:drawable/stat_notify_sync"\r
android:drawablePadding="5dp"\r
android:gravity="center_vertical"\r
- android:text="@string/auth_unauthorized" />\r
+ android:text="@string/auth_unauthorized"\r
+ android:contentDescription="@string/auth_unauthorized"/>\r
\r
<Button\r
android:id="@+id/buttonOK"\r
android:layout_gravity="center_horizontal"\r
android:enabled="false"\r
android:onClick="onOkClick"\r
- android:text="@string/setup_btn_connect" />\r
+ android:text="@string/setup_btn_connect"\r
+ android:contentDescription="@string/setup_btn_connect"/>\r
\r
<Button\r
android:id="@+id/welcome_link"\r
android:paddingBottom="5dp"\r
android:paddingTop="5dp"\r
android:text="@string/auth_register"\r
- android:textColor="#0000FF"/>\r
+ android:textColor="#0000FF"\r
+ android:contentDescription="@string/auth_register"/>\r
\r
</LinearLayout>\r
\r
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
<!--
ownCloud Android client application
- Copyright (C) 2012-2014 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/left_drawer"
+ android:layout_width="240dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:background="@color/background_color"
+ android:baselineAligned="false"
+ android:clickable="true"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<LinearLayout-->
+ <!--android:layout_width="match_parent"-->
+ <!--android:layout_height="wrap_content"-->
+ <!--android:layout_margin="5dp">-->
+
+ <!--<ImageView-->
+ <!--android:id="@+id/drawer_userIcon"-->
+ <!--android:layout_width="40dp"-->
+ <!--android:layout_height="40dp"-->
+ <!--android:src="@drawable/abc_ab_bottom_solid_dark_holo" />-->
+
+ <!--<TextView-->
+ <!--android:id="@+id/drawer_username"-->
+ <!--android:layout_width="wrap_content"-->
+ <!--android:layout_height="wrap_content"-->
+ <!--android:layout_gravity="center_vertical"-->
+ <!--android:layout_marginLeft="5dp"-->
+ <!--android:layout_marginStart="5dp"-->
+ <!--android:textAppearance="?android:attr/textAppearanceLarge" />-->
+
+ <!--</LinearLayout>-->
+
+ <!--<TextView-->
+ <!--android:layout_width="fill_parent"-->
+ <!--android:layout_height="2dip"-->
+ <!--android:background="@color/list_item_lastmod_and_filesize_text" />-->
+
+ <ListView
+ android:id="@+id/drawer_list"
+ android:layout_width="fill_parent"
+ android:layout_height="match_parent"
+ android:background="@color/background_color"
+ android:choiceMode="singleChoice"
+ />
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<!--
+ Copyright 2013 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.
+ -->
+ <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drawer_radio_group"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:orientation="vertical" >
+ </RadioGroup>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/itemLayout"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:orientation="horizontal"
+ android:background="@color/background_color"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="10dp">
+
+ <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/itemTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:textColor="@color/textColor"
+ android:text="@string/app_name"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"/>
+</LinearLayout>
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drawer_radiobutton"
+ android:layout_width="fill_parent"
+ android:layout_height="56dp"
+ android:gravity="center_vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:textColor="#000"
+ android:textSize="18dp" />
\ No newline at end of file
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F7F7F7"
- android:orientation="vertical" >
+ android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
as published by the Free Software Foundation.
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<?xml version="1.0" encoding="utf-8"?>\r
-<!-- \r
+<!--\r
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
\r
You should have received a copy of the GNU General Public License\r
along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- -->\r
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+ -->\r
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+ android:id="@+id/drawer_layout"\r
android:layout_width="match_parent"\r
android:layout_height="match_parent"\r
- android:background="@color/background_color"\r
- android:orientation="horizontal"\r
- android:baselineAligned="false"\r
- >\r
-\r
- <FrameLayout \r
- android:layout_width="0dp"\r
- android:layout_height="match_parent"\r
- android:layout_weight="1"\r
- android:id="@+id/left_fragment_container"\r
- />\r
- \r
- <FrameLayout \r
- android:layout_width="0dp"\r
- android:layout_height="match_parent"\r
- android:layout_weight="2"\r
- android:id="@+id/right_fragment_container"\r
- />\r
- \r
- </LinearLayout>
\ No newline at end of file
+ android:clickable="true" >\r
+\r
+ <!-- The main content view -->\r
+ <LinearLayout\r
+ xmlns:android="http://schemas.android.com/apk/res/android"\r
+ android:layout_width="match_parent"\r
+ android:layout_height="match_parent"\r
+ android:background="@color/background_color"\r
+ android:baselineAligned="false"\r
+ android:orientation="horizontal"\r
+ android:id="@+id/ListLayout"\r
+ android:contentDescription="@string/list_layout"\r
+ >\r
+\r
+\r
+ <FrameLayout\r
+ android:id="@+id/left_fragment_container"\r
+ android:layout_width="0dp"\r
+ android:layout_height="match_parent"\r
+ android:layout_weight="1" />\r
+\r
+ <FrameLayout\r
+ android:id="@+id/right_fragment_container"\r
+ android:layout_width="0dp"\r
+ android:layout_height="match_parent"\r
+ android:layout_weight="2" />\r
+ </LinearLayout>\r
+\r
+ <include\r
+ layout="@layout/drawer"\r
+ android:layout_width="240dp"\r
+ android:layout_height="match_parent"\r
+ android:layout_gravity="start"/>\r
+\r
+</android.support.v4.widget.DrawerLayout>\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/background_color"
+ android:orientation="vertical" >
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:id="@+id/fragment_container" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="horizontal" >
+
+ <Button
+ android:id="@+id/folder_picker_btn_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/common_cancel" />
+
+ <Button
+ android:id="@+id/folder_picker_btn_choose"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/folder_picker_choose_button_text" />
+
+ </LinearLayout>
+
+ </LinearLayout>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/background_color"
- android:orientation="vertical" >
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:id="@+id/fragment_container" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="horizontal" >
-
- <Button
- android:id="@+id/move_files_btn_cancel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/common_cancel" />
-
- <Button
- android:id="@+id/move_files_btn_choose"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/move_choose_button_text" />
-
- </LinearLayout>
-
- </LinearLayout>
\ No newline at end of file
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--\r
+ ownCloud Android client application\r
+ Copyright (C) 2015 ownCloud Inc.\r
+\r
+ This program is free software: you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License version 2,\r
+ as published by the Free Software Foundation.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ \r
+-->\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+ android:id="@+id/ListItemLayout"\r
+ android:layout_width="match_parent"\r
+ android:layout_height="match_parent"\r
+ android:layout_gravity="center_horizontal"\r
+ android:background="@drawable/list_selector"\r
+ android:gravity="center_horizontal"\r
+ android:orientation="vertical" >\r
+\r
+ <FrameLayout\r
+ android:layout_width="match_parent"\r
+ android:layout_height="wrap_content" >\r
+\r
+ <com.owncloud.android.ui.SquareImageView\r
+ android:id="@+id/thumbnail"\r
+ android:layout_width="match_parent"\r
+ android:layout_height="match_parent"\r
+ android:paddingLeft="10dp"\r
+ android:paddingRight="10dp"\r
+ android:scaleType="centerCrop"\r
+ android:src="@drawable/ic_menu_archive"/>\r
+\r
+ <LinearLayout\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="top|right"\r
+ android:orientation="vertical"\r
+ android:layout_margin="4dp">\r
+\r
+ <ImageView\r
+ android:id="@+id/sharedIcon"\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="center"\r
+ android:layout_marginBottom="4dp"\r
+ android:src="@drawable/sharedlink" />\r
+\r
+ <ImageView\r
+ android:id="@+id/sharedWithMeIcon"\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="center"\r
+ android:layout_marginTop="4dp"\r
+ android:src="@drawable/shared_with_me"\r
+ android:visibility="invisible" />\r
+ </LinearLayout>\r
+\r
+ <ImageView\r
+ android:id="@+id/localFileIndicator"\r
+ android:layout_width="@dimen/file_icon_size"\r
+ android:layout_height="@dimen/file_icon_size"\r
+ android:layout_gravity="bottom|right"\r
+ android:layout_marginTop="4dp"\r
+ android:layout_marginBottom="4dp"\r
+ android:layout_marginRight="4dp"\r
+ android:src="@drawable/local_file_indicator" />\r
+\r
+ <ImageView\r
+ android:id="@+id/favoriteIcon"\r
+ android:layout_width="15dp"\r
+ android:layout_height="15dp"\r
+ android:layout_gravity="bottom|right"\r
+ android:layout_marginBottom="4dp"\r
+ android:layout_marginRight="4dp"\r
+ android:src="@drawable/ic_favorite" />\r
+ </FrameLayout>\r
+\r
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--\r
+ ownCloud Android client application\r
+ Copyright (C) 2015 ownCloud Inc.\r
+\r
+ This program is free software: you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License version 2,\r
+ as published by the Free Software Foundation.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ \r
+-->\r
+<com.owncloud.android.ui.SquareLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+ android:id="@+id/ListItemLayout"\r
+ android:layout_width="match_parent"\r
+ android:layout_height="match_parent"\r
+ android:layout_gravity="center_horizontal"\r
+ android:background="@drawable/list_selector"\r
+ android:gravity="center"\r
+ android:orientation="vertical" >\r
+\r
+ <FrameLayout\r
+ android:layout_width="match_parent"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="center_horizontal" >\r
+\r
+ <ImageView\r
+ android:id="@+id/thumbnail"\r
+ android:layout_width="72dp"\r
+ android:layout_height="72dp"\r
+ android:layout_gravity="center_horizontal"\r
+ android:layout_marginLeft="10dp"\r
+ android:layout_marginRight="10dp"\r
+ android:src="@drawable/ic_menu_archive" />\r
+\r
+ <LinearLayout\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="top|right"\r
+ android:orientation="vertical"\r
+ android:layout_margin="2dp">\r
+\r
+ <ImageView\r
+ android:id="@+id/sharedIcon"\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="center"\r
+ android:layout_marginBottom="2dp"\r
+ android:src="@drawable/sharedlink" />\r
+\r
+ <ImageView\r
+ android:id="@+id/sharedWithMeIcon"\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="center"\r
+ android:layout_marginTop="2dp"\r
+ android:src="@drawable/shared_with_me"\r
+ android:visibility="invisible" />\r
+ </LinearLayout>\r
+\r
+ <ImageView\r
+ android:id="@+id/localFileIndicator"\r
+ android:layout_width="@dimen/file_icon_size"\r
+ android:layout_height="@dimen/file_icon_size"\r
+ android:layout_gravity="bottom|right"\r
+ android:layout_marginTop="2dp"\r
+ android:layout_marginRight="2dp"\r
+ android:src="@drawable/local_file_indicator" />\r
+\r
+ <ImageView\r
+ android:id="@+id/favoriteIcon"\r
+ android:layout_width="15dp"\r
+ android:layout_height="15dp"\r
+ android:layout_gravity="bottom|right"\r
+ android:layout_marginBottom="2dp"\r
+ android:layout_marginRight="2dp"\r
+ android:src="@drawable/ic_favorite" />\r
+\r
+\r
+\r
+ </FrameLayout>\r
+\r
+ <TextView\r
+ android:id="@+id/Filename"\r
+ android:layout_width="match_parent"\r
+ android:layout_height="wrap_content"\r
+ android:layout_marginLeft="4dp"\r
+ android:layout_marginRight="4dp"\r
+ android:ellipsize="middle"\r
+ android:gravity="center_horizontal"\r
+ android:singleLine="true"\r
+ android:text="TextView"\r
+ android:textColor="@color/textColor"\r
+ android:textSize="16dip" />\r
+\r
+</com.owncloud.android.ui.SquareLinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="56dp"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:orientation="vertical"
+ android:showDividers="none" >
+
+ <TextView
+ android:id="@+id/footerText"
+ android:layout_width="match_parent"
+ android:layout_height="56dp"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textColor="@color/setup_text_hint" />
+
+</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
-<!--
+<!--
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
- -->
+-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1" >
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1" >
<android.support.v4.widget.SwipeRefreshLayout
- android:id="@+id/swipe_refresh_files"
+ android:id="@+id/swipe_containing_list"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:footerDividersEnabled="false"
+ android:visibility="visible" >
+
<com.owncloud.android.ui.ExtendedListView
android:id="@+id/list_root"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
+ android:layout_height="match_parent"
+ android:visibility="visible" />
+
</android.support.v4.widget.SwipeRefreshLayout>
<android.support.v4.widget.SwipeRefreshLayout
- android:id="@+id/swipe_refresh_files_emptyView"
+ android:id="@+id/swipe_containing_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:footerDividersEnabled="false"
android:visibility="gone" >
- <ScrollView
+ <third_parties.in.srain.cube.GridViewWithHeaderAndFooter
+ android:id="@+id/grid_root"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <TextView
- android:id="@+id/empty_list_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical|center_horizontal"
- android:text="@string/empty"
- android:layout_gravity="center"
- android:visibility="visible" />
-
- </ScrollView>
+ android:layout_height="match_parent"
+ android:columnWidth="100dp"
+ android:gravity="center"
+ android:horizontalSpacing="2dp"
+ android:stretchMode="columnWidth"
+ android:verticalSpacing="2dp"
+ android:visibility="visible" />
+
+ </android.support.v4.widget.SwipeRefreshLayout>
+
+ <android.support.v4.widget.SwipeRefreshLayout
+ android:id="@+id/swipe_containing_empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone" >
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ <TextView
+ android:id="@+id/empty_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center_vertical|center_horizontal"
+ android:text="@string/empty"
+ android:visibility="visible" />
+ </ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
-</FrameLayout>
+
+</FrameLayout>
\ No newline at end of file
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
-->\r
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
android:id="@+id/ListItemLayout"\r
- android:layout_width="fill_parent"\r
+ android:layout_width="match_parent"\r
android:background="@drawable/list_selector"\r
- android:orientation="horizontal"\r
+ android:orientation="vertical"\r
android:layout_height="56dp">\r
\r
- <FrameLayout\r
- android:layout_width="56dp"\r
- android:layout_height="56dp"\r
- android:focusable="false"\r
- android:focusableInTouchMode="false">\r
-\r
- <ImageView\r
- android:id="@+id/imageView2"\r
- android:layout_width="@dimen/file_icon_size"\r
- android:layout_height="@dimen/file_icon_size"\r
- android:layout_gravity="center_vertical"\r
- android:layout_marginLeft="22dp"\r
- android:src="@drawable/local_file_indicator" />\r
-\r
- <ImageView\r
- android:id="@+id/imageView1"\r
- android:layout_width="@dimen/file_icon_size"\r
- android:layout_height="@dimen/file_icon_size"\r
- android:layout_gravity="center_vertical"\r
- android:layout_marginLeft="9dp"\r
- android:src="@drawable/ic_menu_archive" />\r
-\r
- <ImageView\r
- android:id="@+id/imageView3"\r
- android:layout_width="wrap_content"\r
- android:layout_height="wrap_content"\r
- android:layout_gravity="bottom|right"\r
- android:layout_marginBottom="10dp"\r
- android:layout_marginRight="2dp"\r
- android:src="@drawable/ic_favorite" />\r
- </FrameLayout>\r
-\r
<LinearLayout\r
- android:layout_width="0dp"\r
+ android:layout_width="match_parent"\r
android:layout_height="match_parent"\r
- android:layout_weight="1"\r
- android:gravity="center_vertical"\r
- android:orientation="vertical" >\r
-\r
- <TextView\r
- android:id="@+id/Filename"\r
- android:layout_width="wrap_content"\r
- android:layout_height="wrap_content"\r
- android:layout_gravity="center_vertical"\r
- android:layout_marginLeft="4dp"\r
- android:layout_marginRight="4dp"\r
- android:ellipsize="middle"\r
- android:singleLine="true"\r
- android:text="TextView"\r
- android:textColor="#303030"\r
- android:textSize="16dip" />\r
+ android:orientation="horizontal">\r
+\r
+ <FrameLayout\r
+ android:layout_width="56dp"\r
+ android:layout_height="56dp"\r
+ android:focusable="false"\r
+ android:focusableInTouchMode="false">\r
+\r
+ <ImageView\r
+ android:id="@+id/localFileIndicator"\r
+ android:layout_width="@dimen/file_icon_size"\r
+ android:layout_height="@dimen/file_icon_size"\r
+ android:layout_gravity="center_vertical"\r
+ android:layout_marginLeft="22dp"\r
+ android:src="@drawable/local_file_indicator" />\r
+\r
+ <ImageView\r
+ android:id="@+id/thumbnail"\r
+ android:layout_width="@dimen/file_icon_size"\r
+ android:layout_height="@dimen/file_icon_size"\r
+ android:layout_gravity="center_vertical"\r
+ android:layout_marginLeft="9dp"\r
+ android:src="@drawable/ic_menu_archive" />\r
+\r
+ <ImageView\r
+ android:id="@+id/favoriteIcon"\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="bottom|right"\r
+ android:layout_marginBottom="10dp"\r
+ android:layout_marginRight="2dp"\r
+ android:src="@drawable/ic_favorite" />\r
+ </FrameLayout>\r
\r
<LinearLayout\r
- android:layout_width="match_parent"\r
- android:layout_height="wrap_content"\r
- android:layout_marginLeft="4dp"\r
- android:layout_marginRight="4dp"\r
- android:weightSum="1">\r
+ android:layout_width="0dp"\r
+ android:layout_height="match_parent"\r
+ android:layout_weight="1"\r
+ android:gravity="center_vertical"\r
+ android:orientation="vertical" >\r
\r
<TextView\r
- android:id="@+id/last_mod"\r
+ android:id="@+id/Filename"\r
android:layout_width="wrap_content"\r
android:layout_height="wrap_content"\r
+ android:layout_gravity="center_vertical"\r
+ android:layout_marginLeft="4dp"\r
+ android:layout_marginRight="4dp"\r
+ android:ellipsize="middle"\r
+ android:singleLine="true"\r
android:text="TextView"\r
- android:layout_weight=".5"\r
- android:textColor="@color/list_item_lastmod_and_filesize_text"\r
- android:textSize="12dip"/>\r
+ android:textColor="#303030"\r
+ android:textSize="16dip" />\r
\r
- <TextView\r
- android:id="@+id/file_size"\r
- android:layout_width="wrap_content"\r
+ <LinearLayout\r
+ android:layout_width="match_parent"\r
android:layout_height="wrap_content"\r
- android:gravity="right"\r
- android:text="TextView"\r
- android:textColor="@color/list_item_lastmod_and_filesize_text"\r
- android:layout_weight=".5"\r
- android:textSize="12dip"/>\r
+ android:layout_marginLeft="4dp"\r
+ android:layout_marginRight="4dp"\r
+ android:weightSum="1">\r
+\r
+ <TextView\r
+ android:id="@+id/last_mod"\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:text="TextView"\r
+ android:layout_weight=".5"\r
+ android:textColor="@color/list_item_lastmod_and_filesize_text"\r
+ android:textSize="12dip"/>\r
+\r
+ <TextView\r
+ android:id="@+id/file_size"\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:gravity="right"\r
+ android:text="TextView"\r
+ android:textColor="@color/list_item_lastmod_and_filesize_text"\r
+ android:layout_weight=".5"\r
+ android:textSize="12dip"/>\r
+\r
+ </LinearLayout>\r
\r
</LinearLayout>\r
\r
- </LinearLayout>\r
+ <LinearLayout\r
+ android:layout_width="25dp"\r
+ android:layout_height="match_parent"\r
+ android:gravity="center_vertical"\r
+ android:orientation="vertical">\r
\r
- <LinearLayout\r
- android:layout_width="25dp"\r
- android:layout_height="match_parent"\r
- android:gravity="center_vertical"\r
- android:orientation="vertical">\r
-\r
- <ImageView\r
- android:id="@+id/sharedIcon"\r
- android:layout_width="wrap_content"\r
- android:layout_height="wrap_content"\r
- android:layout_gravity="center"\r
- android:layout_marginLeft="4dp"\r
- android:layout_marginBottom="4dp"\r
- android:layout_marginRight="4dp"\r
- android:src="@drawable/sharedlink" />\r
-\r
- <ImageView\r
- android:id="@+id/sharedWithMeIcon"\r
- android:layout_width="wrap_content"\r
- android:layout_height="wrap_content"\r
- android:layout_gravity="center"\r
- android:layout_marginLeft="4dp"\r
- android:layout_marginRight="4dp"\r
- android:layout_marginTop="4dp"\r
- android:src="@drawable/shared_with_me" />\r
+ <ImageView\r
+ android:id="@+id/sharedIcon"\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="center"\r
+ android:layout_marginLeft="4dp"\r
+ android:layout_marginBottom="4dp"\r
+ android:layout_marginRight="4dp"\r
+ android:src="@drawable/sharedlink" />\r
+\r
+ <ImageView\r
+ android:id="@+id/sharedWithMeIcon"\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="center"\r
+ android:layout_marginLeft="4dp"\r
+ android:layout_marginRight="4dp"\r
+ android:layout_marginTop="4dp"\r
+ android:src="@drawable/shared_with_me"\r
+ android:visibility="invisible" />\r
\r
+ </LinearLayout>\r
+\r
+ <ImageView\r
+ android:id="@+id/custom_checkbox"\r
+ android:layout_width="wrap_content"\r
+ android:layout_height="wrap_content"\r
+ android:layout_gravity="center_vertical"\r
+ android:layout_marginLeft="4dp"\r
+ android:layout_marginRight="4dp"\r
+ android:gravity=""\r
+ android:src="@android:drawable/checkbox_off_background" />\r
</LinearLayout>\r
\r
- <ImageView\r
- android:id="@+id/custom_checkbox"\r
- android:layout_width="wrap_content"\r
- android:layout_height="wrap_content"\r
- android:layout_gravity="center_vertical"\r
- android:layout_marginLeft="4dp"\r
- android:layout_marginRight="4dp"\r
- android:gravity=""\r
- android:src="@android:drawable/checkbox_off_background" />\r
+ <View\r
+ android:layout_width="match_parent"\r
+ android:layout_height="1dp"\r
+ android:background="@color/list_divider_background"></View>\r
\r
</LinearLayout>\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="56dp"
+ android:clickable="true"
+ android:orientation="vertical"
+ android:background="#fff"
+ android:paddingLeft="16dp"
+ tools:context=".MainActivity" >
+
+ <TextView
+ android:id="@+id/textView1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawablePadding="5dp"
+ android:gravity="center_vertical"
+ android:paddingLeft="16dp"
+ android:textSize="16dp" >
+
+ </TextView>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/black" />
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/textView1"
+ android:layout_width="wrap_content"
+ android:background="#fff"
+ android:layout_height="56dp"
+ android:layout_marginLeft="8dp"
+ android:gravity="left"
+ android:paddingLeft="16dp"
+ android:paddingTop="8dp"
+ android:textSize="16dp"
+ android:groupIndicator="@android:color/transparent"
+/>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/loadingLayout"
android:layout_width="match_parent"
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<?xml version="1.0" encoding="utf-8"?>
<!--
ownCloud Android client application
- Copyright (C) 2014 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2012 Bartek Przybylski
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical"
+ android:padding="20dp" >
+
+
+ <TextView
+ android:id="@+id/header"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/pass_code_enter_pass_code"
+ android:textColor="@android:color/black"
+ android:gravity="center_horizontal"
+ />
+
+ <TextView
+ android:id="@+id/explanation"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/pass_code_configure_your_pass_code_explanation"
+ android:textAppearance="@android:style/TextAppearance.Small"
+ android:gravity="center_horizontal"
+ />
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal" >
+
+ <EditText
+ android:id="@+id/txt0"
+ android:focusable="true"
+ style="@style/PassCodeStyle"
+ android:cursorVisible="true"
+ android:imeOptions="flagNoExtractUi"
+ ><requestFocus/></EditText>
+
+ <EditText
+ android:id="@+id/txt1"
+ style="@style/PassCodeStyle"
+ android:cursorVisible="true"
+ android:imeOptions="flagNoExtractUi"
+ />
+
+ <EditText
+ android:id="@+id/txt2"
+ style="@style/PassCodeStyle"
+ android:cursorVisible="true"
+ android:imeOptions="flagNoExtractUi"
+ />
+
+ <EditText
+ android:id="@+id/txt3"
+ style="@style/PassCodeStyle"
+ android:cursorVisible="true"
+ android:imeOptions="flagNoExtractUi"
+ />
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/common_cancel" />
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <EditText
+ android:id="@+id/share_password"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ems="10"
+ android:inputType="textPassword">
+ </EditText>
+
+</LinearLayout>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<!--\r
- ownCloud Android client application\r
-\r
- Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
-\r
- This program is free software: you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License version 2,\r
- as published by the Free Software Foundation.\r
-\r
- This program is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
- You should have received a copy of the GNU General Public License\r
- along with this program. If not, see <http://www.gnu.org/licenses/>.\r
--->\r
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
- xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"\r
- android:layout_width="fill_parent"\r
- android:layout_height="fill_parent"\r
- android:gravity="center_horizontal"\r
- android:orientation="vertical"\r
- android:padding="20dp" >\r
-\r
-\r
- <TextView\r
- android:id="@+id/pinHdr"\r
- android:layout_width="wrap_content"\r
- android:layout_height="wrap_content"\r
- android:text="@string/pincode_enter_pin_code"\r
- android:textColor="@android:color/black"\r
- android:gravity="center_horizontal"\r
- />\r
-\r <TextView\r
- android:id="@+id/pinHdrExpl"\r
- android:layout_width="wrap_content"\r
- android:layout_height="wrap_content"\r
- android:text="@string/pincode_configure_your_pin_explanation"\r
- android:textAppearance="@android:style/TextAppearance.Small"\r
- android:gravity="center_horizontal"\r
- />\r
- \r
- <LinearLayout\r
- android:layout_width="fill_parent"\r
- android:layout_height="wrap_content"\r
- android:gravity="center_horizontal" >\r
-\r
- <EditText\r
- android:id="@+id/txt1"\r
- android:focusable="true"\r
- style="@style/PassCodeStyle"\r
- android:cursorVisible="true"\r
- ><requestFocus/></EditText>\r
-\r
- <EditText\r
- android:id="@+id/txt2"\r
- style="@style/PassCodeStyle" />\r
-\r
- <EditText\r
- android:id="@+id/txt3"\r
- style="@style/PassCodeStyle" />\r
-\r
- <EditText\r
- android:id="@+id/txt4"\r
- style="@style/PassCodeStyle" />\r
- </LinearLayout>\r
-\r
- <Button\r
- android:id="@+id/cancel"\r
- android:layout_width="wrap_content"\r
- android:layout_height="wrap_content"\r
- android:text="@string/common_cancel" />\r
-\r
-</LinearLayout>\r
ownCloud Android client application\r
\r
Copyright (C) 2012 Bartek Przybylski\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 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.
+-->
+<!-- Layout used by CheckBoxPreference for the checkbox style. This is inflated
+inside android.R.layout.preference. -->
+<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
+android:id="@+android:id/checkbox"
+android:layout_width="wrap_content"
+android:layout_height="wrap_content"
+android:layout_gravity="center"
+android:focusable="false"
+android:clickable="false" />
\ No newline at end of file
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical" >
+ android:clickable="true" >
<com.ortiz.touch.ExtendedViewPager
android:id="@+id/fragmentPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
+
+ <include
+ layout="@layout/drawer"
+ android:layout_width="240dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"/>
<!-- LinearLayout
android:id="@+id/fragment"
<!- - Preview: layout=@layout/preview_image_fragment - ->
</LinearLayout -->
-</LinearLayout>
\ No newline at end of file
+</android.support.v4.widget.DrawerLayout>
\ No newline at end of file
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/top"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:background="#000000"
tools:context=".ui.fragment.PreviewImageFragment" >
android:layout_centerInParent="true"
/>
- <com.owncloud.android.utils.TouchImageViewCustom
+ <third_parties.michaelOrtiz.TouchImageViewCustom
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
- android:layout_below="@id/image"
+ android:layout_alignParentBottom="true"
android:layout_margin="40dp"
android:text="@string/placeholder_sentence"
+ android:textColor="@color/owncloud_blue_bright"
/>
</RelativeLayout>
\ No newline at end of file
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<!-- \r
ownCloud Android client application\r
\r
- Copyright (C) 2012-2013 ownCloud Inc.\r
+ Copyright (C) 2015 ownCloud Inc.\r
\r
This program is free software: you can redistribute it and/or modify\r
it under the terms of the GNU General Public License version 2,\r
android:layout_height="fill_parent"\r
android:background="@color/background_color"\r
android:orientation="vertical" >\r
-
+\r
<fragment\r
android:id="@+id/local_files_list"\r
android:layout_width="match_parent"\r
android:layout_height="0dip"\r
android:layout_weight="1"\r
class="com.owncloud.android.ui.fragment.LocalFileListFragment" />\r
-
+\r
<LinearLayout\r
android:layout_width="match_parent"\r
android:layout_height="wrap_content"\r
android:gravity="center"\r
android:orientation="horizontal" >\r
-\r <Button\r
+\r
+ <Button\r
android:id="@+id/upload_files_btn_cancel"\r
android:layout_width="wrap_content"\r
android:layout_height="wrap_content"\r
android:layout_weight="1"\r
android:text="@string/common_cancel" />\r
-\r <Button\r
+\r
+ <Button\r
android:id="@+id/upload_files_btn_upload"\r
android:layout_width="wrap_content"\r
android:layout_height="wrap_content"\r
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
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="@string/uploader_top_message"
- android:layout_height="wrap_content" android:id="@+id/textView1" android:textColor="@android:color/black"
- android:gravity="center_horizontal"></TextView>
+
+ <TextView android:layout_width="fill_parent"
+ android:text="@string/uploader_top_message"
+ android:layout_height="wrap_content"
+ android:id="@+id/drawer_username"
+ 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>
+ android:layout_width="fill_parent"
+ android:id="@+id/frameLayout1"
+ android:layout_below="@+id/drawer_username"
+ 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"/>
+
+ <LinearLayout
+ android:id="@+id/linearLayout1"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:orientation="horizontal" >
+
+ <Button
+ android:id="@+id/uploader_new_folder"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:layout_weight="1"
+ android:text="@string/uploader_btn_new_folder_text" />
+
+ <Button
+ android:id="@+id/uploader_choose_folder"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:layout_weight="1"
+ android:text="@string/uploader_btn_upload_text" />
+
</LinearLayout>
</RelativeLayout>
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
android:layout_gravity="center_vertical|center"
android:layout_margin="4dp"
android:src="@drawable/ic_menu_archive"
- android:id="@+id/imageView1" />
+ android:id="@+id/thumbnail" />
<TextView
android:text="TextView"
android:layout_width="fill_parent"
- android:id="@+id/textView1"
+ android:id="@+id/filename"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:layout_gravity="center_vertical"
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
-<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_upload"
android:icon="@drawable/ic_action_upload"
android:orderInCategory="2"
- android:showAsAction="always"
- android:title="@string/actionbar_upload"/>
+ app:showAsAction="always"
+ android:title="@string/actionbar_upload"
+ android:contentDescription="@string/actionbar_upload"/>
<item
android:id="@+id/action_create_dir"
android:icon="@drawable/ic_action_create_dir"
android:orderInCategory="2"
- android:showAsAction="always"
- android:title="@string/actionbar_mkdir"/>
+ app:showAsAction="always"
+ android:title="@string/actionbar_mkdir"
+ android:contentDescription="@string/actionbar_mkdir"/>
<item
android:id="@+id/action_sync_account"
android:icon="@drawable/ic_action_refresh"
android:orderInCategory="2"
- android:showAsAction="never"
- android:title="@string/actionbar_sync"/>
- <item
- android:id="@+id/action_settings"
- android:icon="@drawable/ic_action_settings"
- android:orderInCategory="2"
- android:showAsAction="never"
- android:title="@string/actionbar_settings"/>
- <item
- android:id="@+id/action_logger"
- android:icon="@drawable/ic_action_settings"
- android:orderInCategory="2"
- android:showAsAction="never"
- android:title="@string/actionbar_logger"/>
+ app:showAsAction="never"
+ android:title="@string/actionbar_sync"
+ android:contentDescription="@string/actionbar_sync"/>
<item
android:id="@+id/action_sort"
- android:icon="@android:drawable/ic_menu_sort_alphabetically"
+ android:icon="@android:drawable/ic_menu_sort_by_size"
android:orderInCategory="2"
- android:showAsAction="never"
- android:title="@string/actionbar_sort"/>
+ app:showAsAction="never"
+ android:title="@string/actionbar_sort"
+ android:contentDescription="@string/actionbar_sort"/>
- <!-- <item android:id="@+id/search" android:title="@string/actionbar_search" android:icon="@drawable/ic_action_search"></item> -->
+ <!-- <item android:id="@+id/search"
+ android:title="@string/actionbar_search"
+ android:icon="@drawable/ic_action_search"></item> -->
</menu>
\ No newline at end of file
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
-->
<body>
<p>
- Dieses Gerät läuft mit Android 4.1.x.
+ Dieses Ger�t l�uft mit Android 4.1.x.
</p>
<p>
- In dieser Version von Android existiert ein Bug, der nach jedem Neustart eine erneute Eingabe der ownCloud Login-Informationen nötig macht. Um das zu umgehen installieren Sie bitte diese kostenlose Hilfs-App:
+ In dieser Version von Android existiert ein Bug, der nach jedem Neustart eine erneute Eingabe der ownCloud Login-Informationen n�tig macht. Um das zu umgehen installieren Sie bitte diese kostenlose Hilfs-App:
</p>
<p style="text-align:center">
<a href="http://play.google.com/store/apps/details?id=com.owncloud.android.workaround.accounts">ownCloud Jelly Bean Workaround</a>
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
Su dispositivo ejecuta Android 4.1.x.
</p>
<p>
- Para prevenir la pérdida de las credenciales de sus cuentas ownCloud en cada reinicio, por favor, instale esta app gratuita que evita el problema en Jelly Bean:
+ Para prevenir la p�rdida de las credenciales de sus cuentas ownCloud en cada reinicio, por favor, instale esta app gratuita que evita el problema en Jelly Bean:
</p>
<p style="text-align:center">
<a href="http://play.google.com/store/apps/details?id=com.owncloud.android.workaround.accounts">ownCloud Jelly Bean Workaround</a>
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<string name="actionbar_settings">Instellings</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_help">Hulp</string>
<string name="auth_username">Gebruikersnaam</string>
<string name="auth_password">Wagwoord</string>
<string name="file_list_seconds_ago">sekondes gelede</string>
+ <string name="common_yes">Ja</string>
+ <string name="common_no">Nee</string>
<string name="common_ok">OK</string>
<string name="common_cancel">Kanseleer</string>
+ <string name="common_error">Fout</string>
<string name="empty"></string>
- <string name="move_choose_button_text">Kies</string>
+ <string name="folder_picker_choose_button_text">Kies</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_send_file">أرسل</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">عام</string>
<string name="prefs_category_more">المزيد</string>
<string name="prefs_accounts">حسابات</string>
<string name="prefs_manage_accounts">إدارة الحسابات</string>
- <string name="prefs_pincode">كلمة سر التطبيق</string>
- <string name="prefs_pincode_summary">حماية العميل</string>
<string name="prefs_instant_upload">رفع الصورة مباشرة</string>
<string name="prefs_instant_upload_summary">رفع صورة المؤخذة عبر الكاميرا</string>
<string name="prefs_instant_video_upload">رفع فيديو مباشرة</string>
<string name="sync_string_files">الملفات</string>
<string name="setup_btn_connect">اتصال</string>
<string name="uploader_btn_upload_text">رفع</string>
+ <string name="uploader_btn_new_folder_text">مجلد جديد</string>
<string name="uploader_top_message">اختر مجلد الرفع</string>
<string name="uploader_wrn_no_account_title">لم يتم العثور على أي حساب</string>
<string name="uploader_wrn_no_account_text">لا توجد حسابات %1$s على جهازك. يرجى تهيئة حساب أولاً.</string>
<string name="uploader_info_uploading">يتم الرفع</string>
<string name="file_list_seconds_ago">منذ ثواني</string>
<string name="file_list_empty">لا يوجد شيء هنا. إرفع بعض الملفات!</string>
- <string name="file_list_loading">جاري التحميل ...</string>
<string name="filedetails_select_file">اضغظ على الملف ليتم عرض خيارات أكثر</string>
<string name="filedetails_size">الحجم :</string>
<string name="filedetails_type">النوع :</string>
<string name="foreign_files_local_text">محلي :%1$s</string>
<string name="foreign_files_remote_text">خارجي : %1$s</string>
<string name="upload_query_move_foreign_files">لا يوجد مساحة كافية لنسخ الملفات المحددة لمجلد %1$s . هل ترغب بنقلهم بدلاً من ذلك؟</string>
- <string name="pincode_enter_pin_code">يرجى إدخال كلمة السر</string>
- <string name="pincode_configure_your_pin">أدخل كلمة السر</string>
- <string name="pincode_configure_your_pin_explanation">سيتم طلب PIN في كل مرة يتم فيها تشغيل التطبيق</string>
- <string name="pincode_reenter_your_pincode">يرجى إدخال كلمة السر مرة أخرى</string>
- <string name="pincode_remove_your_pincode">إزالة كلمة السر</string>
- <string name="pincode_mismatch">كلمتا السر غير متطابقتين</string>
- <string name="pincode_wrong">كلمه السر غير صحيحة</string>
- <string name="pincode_removed">تمت إزالة كلمه السر</string>
- <string name="pincode_stored">تم تسجيل كلمت السر</string>
<string name="media_notif_ticker">مشغل الموسيقى %1$s </string>
<string name="media_state_playing">%1$s (يتم التشغيل)</string>
<string name="media_state_loading">%1$s (يتم التحميل)</string>
<string name="auth_no_net_conn_title">لا يتوفر اتصال</string>
<string name="auth_nossl_plain_ok_title">الاتصال الآمن غير متاح</string>
<string name="auth_connection_established">تم الاتصال</string>
- <string name="auth_testing_connection">اختبار الاتصال ...</string>
<string name="auth_not_configured_title">إعداد الخادم غير صحيحة</string>
<string name="auth_account_not_new">الحساب لنفس المستخدم والخادم موجود مسبقا على الجهاز </string>
<string name="auth_account_not_the_same">المستخدم المدخل لا يتوافق مع المستخدم الموجود في الحساب </string>
<string name="empty"></string>
<string name="prefs_category_accounts">حسابات</string>
<string name="saml_authentication_wrong_pass">كلمة مرور خاطئة</string>
- <string name="move_choose_button_text">اختيار</string>
+ <string name="folder_picker_choose_button_text">اختيار</string>
<string name="prefs_category_security">الأمان</string>
+ <string name="auth_host_address">عنوان الخادم</string>
</resources>
<string name="actionbar_settings">Quraşdırmalar</string>
<string name="actionbar_see_details">Detallar</string>
<string name="actionbar_send_file">Göndər</string>
+ <string name="actionbar_sort">Çeşidləmək</string>
+ <string name="actionbar_sort_title">Təyinata görə çeşidləmək </string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Yenisi - Köhnəsi</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Ümumi</string>
<string name="prefs_category_more">Daha da</string>
<string name="prefs_accounts">Hesablar</string>
<string name="prefs_manage_accounts">İstifadəçilərin idarəedilməsi</string>
- <string name="prefs_pincode">Proqram təminatının PİN-i</string>
- <string name="prefs_pincode_summary">Müştərini qoru</string>
<string name="prefs_instant_upload">Ani şəkil yükləmələri</string>
<string name="prefs_instant_upload_summary">Kamera vasitəsi ilə götürülmüş şəkillərin tez yüklənməsi</string>
<string name="prefs_instant_video_upload">Ani video yükləmələri</string>
<string name="prefs_recommend">Dostuna məsləhət gör</string>
<string name="prefs_feedback">Geriyə cavab</string>
<string name="prefs_imprint">İşarələmək</string>
+ <string name="prefs_remember_last_share_location">Paylaşma ünvanını yadda saxla</string>
+ <string name="prefs_remember_last_upload_location_summary">Son paylaşılmış yüklənmə ünvanını yadda saxla</string>
<string name="recommend_subject">%1$s-i ağıllı telefonunuzda yoxlayın!</string>
<string name="recommend_text">Mən sizi öz smartfonunuzda %1$s istifadə etmək üçün dəvət etmək istəyirəm! Burdan endirin: %2$s</string>
<string name="auth_check_server">Serveri yoxla</string>
<string name="sync_string_files">Fayllar</string>
<string name="setup_btn_connect">Qoşul</string>
<string name="uploader_btn_upload_text">Serverə yüklə</string>
+ <string name="uploader_btn_new_folder_text">Yeni qovluq</string>
<string name="uploader_top_message">Yüklənmə qovluöunu seçin:</string>
<string name="uploader_wrn_no_account_title">Hesab tapılmadı</string>
<string name="uploader_wrn_no_account_text">Sizin alətinizda %1$s hesabi tapılmadı. Xahiş olunur öncə hesabi quraşdırasınız.</string>
<string name="uploader_wrn_no_content_text">Heç bir kontent gəlmədi. Yukləmək üçün heçnə yoxdur.</string>
<string name="uploader_error_forbidden_content">%1$s yayımlanmış kontent üçün yetkili deyil</string>
<string name="uploader_info_uploading">Yüklənmə gedir</string>
+ <string name="file_list_seconds_ago">saniyələr öncə</string>
<string name="file_list_empty">Burda heçnə yoxdur. Nese yükləyin!</string>
- <string name="file_list_loading">Yüklənir...</string>
<string name="local_file_list_empty">Bu qovluqda heç bir fayl movcud deyil.</string>
<string name="filedetails_select_file">Faylın üstünə sıxın ki, əlavə məlumat ekrana çıxsın.</string>
<string name="filedetails_size">Həcm:</string>
<string name="foreign_files_local_text">Daxili: %1$s</string>
<string name="foreign_files_remote_text">Uzaq: %1$s</string>
<string name="upload_query_move_foreign_files">Seçdiyiniz faylların %1$s qovluğuna köçüçrülməsi üçün kifayət qədər yer yoxdur. Əvəzinə onları köçürmək istəyirsinizmi?</string>
- <string name="pincode_enter_pin_code">Xahiş olunur öz proqramınızın PİN-ni daxil edəsiniz</string>
- <string name="pincode_configure_your_pin">Proqramınızın PİN-ni daxil edin</string>
- <string name="pincode_configure_your_pin_explanation">Proqram hər dəfə işə düşdükdə PİN yenidən istəniləcək</string>
- <string name="pincode_reenter_your_pincode">Öz proqramınızn PİN-ni yenidən daxil etməyi xahiş edirik</string>
- <string name="pincode_remove_your_pincode">Öz proqramınızın PİN-ni silin</string>
- <string name="pincode_mismatch">Proqram PİN-ləri eyni deyil</string>
- <string name="pincode_wrong">Yalnış proqram PİN-i</string>
- <string name="pincode_removed">Proqram PİN-i silindi</string>
- <string name="pincode_stored">Proqram PİN-i saxlanıldı </string>
<string name="media_notif_ticker">%1$s musiqi oxuducusu</string>
<string name="media_state_playing">%1$s (oxuyur)</string>
<string name="media_state_loading">%1$s (yüklənir)</string>
<string name="auth_no_net_conn_title">Şəbəkə qoşulması yoxdur</string>
<string name="auth_nossl_plain_ok_title">Təhlükəsiz qoşulma mümkün deyil.</string>
<string name="auth_connection_established">Əlaqə quruldu</string>
- <string name="auth_testing_connection">Qoşulma test edilir...</string>
+ <string name="auth_testing_connection">Qoşulma test edilir</string>
<string name="auth_not_configured_title">Yalnış qurulmuş server konfiqurasiyası</string>
<string name="auth_account_not_new">Avadanlıqda eyni istifadəçi və server üçün artıq hesab mövcuddur</string>
<string name="auth_account_not_the_same">Daxil edilən hesab bu hesabla üst-üstə düşmür</string>
<string name="auth_unsupported_multiaccount">%1$s çoxlu hesab dəstəkləmir</string>
<string name="auth_fail_get_user_name">Sizin server düzgün istifadəçi id-si qaytarmır, xahiş olunur inzibatçı ilə əlaqə saxlayasınız</string>
<string name="auth_can_not_auth_against_server">Bu serverdə yenidən qeydiyyatdan keçmək olmur</string>
+ <string name="auth_account_does_not_exist">Hesab göstərilən avadanlıqda mövcud deyil</string>
<string name="fd_keep_in_sync">Faylı gündəmdə saxla</string>
<string name="common_rename">Adı dəyiş</string>
<string name="common_remove">Sil</string>
<string name="ssl_validator_reason_cert_not_trusted">Server sertifikati inamlı deyil</string>
<string name="ssl_validator_reason_cert_expired">- Server sertifikatının vaxtı bitmişdir</string>
<string name="ssl_validator_reason_cert_not_yet_valid">- Server sertifikatının düzgün tarixi gələcəkdədir</string>
+ <string name="ssl_validator_reason_hostname_not_verified">URL sertifikatda olan host adına uyğun deyil</string>
+ <string name="ssl_validator_question">İstənilən halda bu sertifikata inanmaq istəyirsinizmi?</string>
+ <string name="ssl_validator_not_saved">Sertifikat saxlanıla bilməz</string>
<string name="ssl_validator_btn_details_see">Detallar</string>
+ <string name="ssl_validator_btn_details_hide">Gizlə</string>
+ <string name="ssl_validator_label_subject">Verilir:</string>
+ <string name="ssl_validator_label_issuer">Tərəfindən verilib:</string>
+ <string name="ssl_validator_label_CN">Ümumi ad:</string>
+ <string name="ssl_validator_label_O">Təşkilat:</string>
+ <string name="ssl_validator_label_OU">Alt təşkilatOrganizational unit:</string>
+ <string name="ssl_validator_label_C">Ölkə:</string>
+ <string name="ssl_validator_label_ST">Dövlət:</string>
+ <string name="ssl_validator_label_L">Ərazi:</string>
+ <string name="ssl_validator_label_validity">Etibarlılıq:</string>
+ <string name="ssl_validator_label_validity_from">Kimdən:</string>
+ <string name="ssl_validator_label_validity_to">Kimə:</string>
+ <string name="ssl_validator_label_signature">İmza:</string>
+ <string name="ssl_validator_label_signature_algorithm">Alqıritm:</string>
+ <string name="ssl_validator_null_cert">Sertifikat görünə bilməz.</string>
+ <string name="ssl_validator_no_info_about_error">- Səhv haqqında məlumat yoxdur</string>
+ <string name="placeholder_sentence">Bu bir yer doldurucusudur</string>
+ <string name="placeholder_filename">yerdoldurucusu.txt</string>
+ <string name="placeholder_filetype">PNG Şəkil</string>
+ <string name="placeholder_filesize">389 KB</string>
+ <string name="placeholder_timestamp">2012/05/18 12:23</string>
+ <string name="placeholder_media_time">12:23:45</string>
+ <string name="instant_upload_on_wifi">Şəkilləri yalnız WiFi üzərindən yüklə</string>
+ <string name="instant_video_upload_on_wifi">Videoları yalnız WiFi üzərindən yüklə</string>
+ <string name="instant_upload_path">/CəldYükləmə</string>
+ <string name="conflict_title">Yüklənmə konflikti</string>
+ <string name="conflict_message">Uzaq fayl %s local faylla sinxronizasiya edilmədi. Faylın kontentinin serverdə dəyişdirilməsinə davam edirik.</string>
+ <string name="conflict_keep_both">Birlikdə saxla</string>
+ <string name="conflict_overwrite">Sil yenidən yaz</string>
+ <string name="conflict_dont_upload">Yükləmə</string>
+ <string name="preview_image_description">Şəkili göstər</string>
+ <string name="preview_image_error_unknown_format">Bu şəkil göstərilə bilməz</string>
+ <string name="error__upload__local_file_not_copied">%1$s nüsxələnə bilməz %2$s local qovluğa</string>
+ <string name="prefs_instant_upload_path_title">Yüklənmə ünvanı</string>
+ <string name="share_link_no_support_share_api">Üzr istəyirik, sizin yerverdə paylaşıma izin verilmir. Xahiş olunur
+inzibatçınızla əlaqə saxlayasınız.</string>
+ <string name="share_link_file_no_exist">Paylaşa bilinmir.</string>
+ <string name="share_link_file_error">Bu faylın yada qovluğun paylaşımı zamanı səhv baş verdi </string>
+ <string name="unshare_link_file_no_exist">Paylaşımı dayandırmaq olmur. Xahiş olunur fayl mövcudluğunu yoxlayasınız</string>
<string name="unshare_link_file_error">Bu fayl və ya qovluğun yayımlanmasının dayandırılmasında səhv baş verdi</string>
+ <string name="share_link_password_title">Şifrəni daxil et</string>
+ <string name="share_link_empty_password">Siz şifrəni daxil etməlisiniz</string>
<string name="activity_chooser_send_file_title">Göndər</string>
<string name="copy_link">linki nüsxələ</string>
<string name="clipboard_text_copied">Mübadilə buferinə nüsxələndi</string>
+ <string name="error_cant_bind_to_operations_service">Kritik səhv: əməliyyat yerinə yetirilə bilinmir</string>
+ <string name="network_error_socket_exception">Serverlə əlaqəyə girdikdə səhv baş verdi.</string>
+ <string name="network_error_socket_timeout_exception">Serveri gözlədiyimiz müddətdə səhv baş verdi, əməliyyat bitə bilməz</string>
+ <string name="network_error_connect_timeout_exception">Serveri gözlədiyimiz müddətdə səhv baş verdi, əməliyyat bitə bilməz</string>
+ <string name="network_host_not_available">Əməliyyat bitə bilməz, serverə çatmaq mümkün deyil </string>
<string name="empty"></string>
<string name="forbidden_permissions">Sizin yetkiniz yoxdur %s</string>
+ <string name="forbidden_permissions_rename">faylın adını dəyişmək</string>
<string name="forbidden_permissions_delete">bu faylı silmək üçün</string>
<string name="share_link_forbidden_permissions">bu faylı yayımlamaq üçün</string>
+ <string name="unshare_link_forbidden_permissions">fayl paylaşımını dayandırmaq</string>
<string name="forbidden_permissions_create">fayl yaratmaq üçün</string>
<string name="uploader_upload_forbidden_permissions">bu qovluğa yükləmək üçün</string>
+ <string name="downloader_download_file_not_found">Bu fayla serverdə artıq uzun müddətdir ki, çatmaq mümkün deyil</string>
<string name="prefs_category_accounts">Hesablar</string>
<string name="prefs_add_account">Hesab əlavə et</string>
+ <string name="auth_redirect_non_secure_connection_title">Təhlükəsiz qoşulma, təhlükəsiz olmayan istiqamətə yönlədirilmişdir</string>
+ <string name="actionbar_logger">Jurnallar</string>
+ <string name="log_send_history_button">Tarixçəni göndər</string>
+ <string name="log_send_no_mail_app">Jurnalların ötürülməsi üçün proqram təminatı tapılmadı!</string>
+ <string name="log_send_mail_subject">%1$s Android proqram jurnalları</string>
+ <string name="log_progress_dialog_text">Data yüklənir...</string>
+ <string name="saml_authentication_required_text">Qeydiyyat tələb edilir</string>
<string name="saml_authentication_wrong_pass">Yalnış şifrə</string>
+ <string name="actionbar_move">Köçürmək</string>
+ <string name="file_list_empty_moving">Burda heçnə yoxdur. Siz qovluq əlavə edə bilərsiniz!</string>
+ <string name="folder_picker_choose_button_text">Seç</string>
+ <string name="move_file_not_found">Köçürmə mümkün olmur. Xahiş olunur faylın mövcudluğunu yoxlayasınız.</string>
+ <string name="move_file_invalid_into_descendent">Qovluğu bu nəsilə köçürmək mümkün deyil</string>
+ <string name="move_file_invalid_overwrite">Fayl artıq mənsəb qovluğunda mövcuddur</string>
+ <string name="move_file_error">Fayl və ya qovluğun köçürülməsi müddətində səhv baş verdi</string>
+ <string name="forbidden_permissions_move">bu faylı köçürtmək</string>
+ <string name="prefs_category_instant_uploading">Anında yükləmələr</string>
+ <string name="prefs_category_security">Təhlükəsizlik</string>
+ <string name="prefs_instant_video_upload_path_title">Video ünvanını yüklə</string>
+ <string name="download_folder_failed_content">Qovluğun endirilməsinin %1$s hissəsi tamamlana bilməz </string>
+ <string name="auth_refresh_button">Qoşulmanı yenilə</string>
+ <string name="auth_host_address">Server ünvanı</string>
</resources>
<string name="actionbar_settings">Налады</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="file_list_seconds_ago">Секунд таму</string>
<string name="common_yes">Так</string>
<string name="common_no">Не</string>
<string name="common_ok">Добра</string>
<string name="common_error">Памылка</string>
<string name="empty"></string>
- <string name="move_choose_button_text">Выбар</string>
+ <string name="folder_picker_choose_button_text">Выбар</string>
</resources>
<resources>
<string name="about_android">%1$s Android приложение</string>
<string name="about_version">версия %1$s</string>
- <string name="actionbar_sync">Ð\9eбновÑ\8fване на профила</string>
+ <string name="actionbar_sync">Ð\9eбновÑ\8fви профила</string>
<string name="actionbar_upload">Качване</string>
<string name="actionbar_upload_from_apps">Съдържание от други приложения</string>
<string name="actionbar_upload_files">Файлове</string>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Всички файлове</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Настройки</string>
+ <string name="drawer_item_logs">Логове</string>
+ <string name="drawer_close">Затвори</string>
<string name="prefs_category_general">Общи</string>
<string name="prefs_category_more">Още</string>
<string name="prefs_accounts">Профили</string>
<string name="prefs_manage_accounts">Управление на профилите</string>
- <string name="prefs_pincode">App PIN</string>
- <string name="prefs_pincode_summary">Подсигури програмата</string>
+ <string name="prefs_passcode">Заключваща парола</string>
<string name="prefs_instant_upload">Незабавно качване на снимки</string>
<string name="prefs_instant_upload_summary">Незабвано качване на снимки направени с камерата</string>
<string name="prefs_instant_video_upload">Незабавно качване на видео</string>
<string name="sync_string_files">Файлове</string>
<string name="setup_btn_connect">Свързване</string>
<string name="uploader_btn_upload_text">Качване</string>
+ <string name="uploader_btn_new_folder_text">Нова папка</string>
<string name="uploader_top_message">Избери папка за качване:</string>
<string name="uploader_wrn_no_account_title">Няма открит профил</string>
<string name="uploader_wrn_no_account_text">Няма %1$s профили на устройстото ти. Моля, първо настрой профил.</string>
<string name="uploader_info_uploading">Качване</string>
<string name="file_list_seconds_ago">преди секунди</string>
<string name="file_list_empty">Тук няма нищо. Качете нещо!</string>
- <string name="file_list_loading">Зареждане...</string>
+ <string name="file_list_loading">Зарежда…</string>
<string name="local_file_list_empty">Няма файлове в тази папка.</string>
<string name="filedetails_select_file">Натисни върху файл, за да видиш допълнителна информация.</string>
<string name="filedetails_size">Размер:</string>
<string name="filedetails_download">Изтегляне</string>
<string name="filedetails_sync_file">Обновяване на файла</string>
<string name="filedetails_renamed_in_upload_msg">Файлът беше преименуван на %1$s по време на качването.</string>
+ <string name="list_layout">Списък с изгледи</string>
<string name="action_share_file">Връзка за споделяне</string>
<string name="action_unshare_file">Премахване връзка за споделяне</string>
<string name="common_yes">Да</string>
<string name="foreign_files_local_text">Локален: %1$s</string>
<string name="foreign_files_remote_text">Отдалечен: %1$s</string>
<string name="upload_query_move_foreign_files">Няма достатъчно място за копирането на избраните файлове до папка %1$s. Да се преместят ли вместо това?</string>
- <string name="pincode_enter_pin_code">Въведете своя App ПИН</string>
- <string name="pincode_configure_your_pin">Въведете своя App ПИН</string>
- <string name="pincode_configure_your_pin_explanation">ПИН-ът ще бъде поискан всеки път, когато програмата стартира.</string>
- <string name="pincode_reenter_your_pincode">Въведете своя App ПИН отново.</string>
- <string name="pincode_remove_your_pincode">Премахнете своя App ПИН</string>
- <string name="pincode_mismatch">App ПИН-овете не съвпадат</string>
- <string name="pincode_wrong">Неправилен App ПИН</string>
- <string name="pincode_removed">App ПИН премахнат</string>
- <string name="pincode_stored">App ПИН запазен</string>
+ <string name="pass_code_enter_pass_code">Моля, въведи парола за достъп</string>
+ <string name="pass_code_configure_your_pass_code">Въведи парола за достъп</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Паролата ще се изисква при всяко стартиране на приложението</string>
+ <string name="pass_code_reenter_your_pass_code">Моля, въведи парола за достъп отново</string>
+ <string name="pass_code_remove_your_pass_code">Премахни парола</string>
+ <string name="pass_code_mismatch">Паролите не съвпадат</string>
+ <string name="pass_code_wrong">Грешна парола</string>
+ <string name="pass_code_removed">Паролата премахната</string>
+ <string name="pass_code_stored">Паролата е запаметена</string>
<string name="media_notif_ticker">%1$s музикален плеър</string>
<string name="media_state_playing">%1$s (пусната)</string>
<string name="media_state_loading">%1$s (се зарежда)</string>
<string name="auth_no_net_conn_title">Няма интернет връзка</string>
<string name="auth_nossl_plain_ok_title">Няма сигурна връзка</string>
<string name="auth_connection_established">Осъществена връзка</string>
- <string name="auth_testing_connection">Проверка на свързаност...</string>
+ <string name="auth_testing_connection">Проверка на свързаност</string>
<string name="auth_not_configured_title">Неправилно зададена сървърна конфигурация.</string>
<string name="auth_account_not_new">Профил за същия потребител на същия сървър е вече настроен на устройството.</string>
<string name="auth_account_not_the_same">Въведният потребител не съвпада с потребителя на профила.</string>
<string name="auth_fail_get_user_name">Вашият сървър не връща правилен потребителски индентификатор.
Моля, свържете се с администратора.</string>
<string name="auth_can_not_auth_against_server">Неуспешен опит за оторизиране с този сървър.</string>
+ <string name="auth_account_does_not_exist">Профила не съществува на устройството все още</string>
<string name="fd_keep_in_sync">Поддържане на файла обновен.</string>
<string name="common_rename">Преименуване</string>
<string name="common_remove">Премахване</string>
<string name="sync_file_nothing_to_do_msg">Съдържанието на файла е вече синхронизирано</string>
<string name="create_dir_fail_msg">Папката не може да бъде създадена</string>
<string name="filename_forbidden_characters">Забранени символи: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Името на файла съдържа поне един невалиден символ</string>
<string name="filename_empty">Името на файла не може да бъде празно</string>
<string name="wait_a_moment">Изчакайте малко</string>
<string name="filedisplay_unexpected_bad_get_content">Неочакван проблем; моля, изберете файла от друга програма.</string>
<string name="filedisplay_no_file_selected">Не е избран файл</string>
<string name="activity_chooser_title">Изпращане на връзката до...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Копира файла от личното хранилище</string>
<string name="oauth_check_onoff">Вписване с oAuth2</string>
<string name="oauth_login_connection">Свързване с оАутх2 сървър...</string>
<string name="ssl_validator_header">Самоличността на сайта не може да бъде проверена.</string>
<string name="share_link_file_error">Настъпи грешка при опита за споделяне на този файл или папка.</string>
<string name="unshare_link_file_no_exist">Неуспешен опит за прекратяване на споделянето. Моля, провери дали файла съществува.</string>
<string name="unshare_link_file_error">Настъпи грешка при опита за премахване на споделянето на този файл или папка.</string>
+ <string name="share_link_password_title">Въведи Парола</string>
+ <string name="share_link_empty_password">Вие трябва да въведете парола</string>
<string name="activity_chooser_send_file_title">Изпращане</string>
<string name="copy_link">Копиране на връзката</string>
<string name="clipboard_text_copied">Копирана</string>
<string name="auth_redirect_non_secure_connection_title">Сигурна връзка е пренасочена по несигурен път.</string>
<string name="actionbar_logger">Доклади</string>
<string name="log_send_history_button">Изпрати История</string>
- <string name="log_mail_subject">ownCloud Android доклади</string>
- <string name="log_progress_dialog_text">Зареждане на информация...</string>
+ <string name="log_send_no_mail_app">Не са намерени журнали за изпращане от приложението. Инсталирайте приложението за електронна поща!</string>
+ <string name="log_send_mail_subject">%1$s Android журнали на приложенията</string>
+ <string name="log_progress_dialog_text">Зареждане на данни...</string>
<string name="saml_authentication_required_text">Нужна е идентификация</string>
<string name="saml_authentication_wrong_pass">Грешна парола</string>
<string name="actionbar_move">Премести</string>
<string name="file_list_empty_moving">Тук няма нищо. Можеш да добавиш папка!</string>
- <string name="move_choose_button_text">Избери</string>
+ <string name="folder_picker_choose_button_text">Избери</string>
<string name="move_file_not_found">Неуспешно преместване. Моля, провери дали файла съществува.</string>
<string name="move_file_invalid_into_descendent">Не е възможно да преместиш папка в нейна под папка.</string>
<string name="move_file_invalid_overwrite">Файлът вече съществува в отдалечената папка.</string>
<string name="forbidden_permissions_move">за да преместиш този файл</string>
<string name="prefs_category_instant_uploading">Незабавно качване</string>
<string name="prefs_category_security">Сигурност</string>
+ <string name="prefs_instant_video_upload_path_title">Качване на видео път</string>
+ <string name="download_folder_failed_content">Свалянето на директорията %1$s не може да бъде завършено</string>
+ <string name="shared_subject_header">споделен</string>
+ <string name="with_you_subject_header">с теб</string>
+ <string name="subject_token">%1$s споделен \"%2$s\" с теб</string>
+ <string name="auth_refresh_button">Обнови връзката</string>
+ <string name="auth_host_address">Адрес на сървъра</string>
+ <string name="common_error_out_memory">Няма достатъчно памет</string>
+ <string name="username">Потребителско име</string>
+ <string name="file_list__footer__folder">1 папка</string>
+ <string name="file_list__footer__folders">%1$d папки</string>
+ <string name="file_list__footer__file">1 файл</string>
+ <string name="file_list__footer__file_and_folder">1 файл, 1 папка</string>
+ <string name="file_list__footer__file_and_folders">1 файл, %1$d папки</string>
+ <string name="file_list__footer__files">%1$d файла</string>
+ <string name="file_list__footer__files_and_folder">%1$d файла, 1 папка</string>
+ <string name="file_list__footer__files_and_folders">%1$d файла, %2$d папки</string>
</resources>
<string name="actionbar_send_file">পাঠাও</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">সাধারণ</string>
<string name="prefs_category_more">বেশী</string>
<string name="prefs_accounts">একাউন্ট</string>
<string name="prefs_manage_accounts">একাউন্ট সামলাও</string>
- <string name="prefs_pincode">অ্যাপ PIN</string>
- <string name="prefs_pincode_summary">আপনার ক্লায়েন্ট সামলান</string>
<string name="prefs_instant_upload">দ্রুত ছবি আপলোড</string>
<string name="prefs_instant_upload_summary">ক্যামেরা থেকে তোলা ছবি তৎক্ষণাৎ আপলোড</string>
<string name="prefs_instant_video_upload">দ্রুত ভিডিও আপলোড</string>
<string name="sync_string_files">ফাইল</string>
<string name="setup_btn_connect">সংযুক্ত হও</string>
<string name="uploader_btn_upload_text">আপলোড</string>
+ <string name="uploader_btn_new_folder_text">নব ফােলডার</string>
<string name="uploader_top_message">আপলোডের ফোলডার পছনদ করেন</string>
<string name="uploader_wrn_no_account_title">কোন একাউন্ট খুঁজে পাওয়া গেল না</string>
<string name="uploader_wrn_no_account_text">আপনার ডিভাইসে কোন %1$s একাউন্ট নেই। দয়া করে প্রথমে একাউন্ট খুলুন।</string>
<string name="uploader_info_uploading">আপলোড করা হচ্ছে</string>
<string name="file_list_seconds_ago">সেকেন্ড পূর্বে</string>
<string name="file_list_empty">এখানে কিছুই নেই। কিছু আপলোড করুন !</string>
- <string name="file_list_loading">লোড হচ্ছে....</string>
<string name="local_file_list_empty">এই ফোলডারে কোন ফাইল নেই</string>
<string name="filedetails_select_file">অতিরিক্ত তথ্য প্রদর্শন করতে চাইলে ফাইলে ট্যাপ দিন</string>
<string name="filedetails_size">আয়তনঃ</string>
<string name="foreign_files_local_text">স্থানীয়: %1$s</string>
<string name="foreign_files_remote_text">দুরবর্তী: %1$s</string>
<string name="upload_query_move_foreign_files">%1$s ফোল্ডারে ফাইল কপি করার মত যথেষ্ট জায়গা নেই। এগুলো অন্যত্র রাখবেন? </string>
- <string name="pincode_enter_pin_code">দয়া করে আপনার App PIN দিন</string>
- <string name="pincode_configure_your_pin">আপনার App PIN দিন</string>
- <string name="pincode_configure_your_pin_explanation">প্রতিবার অ্যাপ চালু করার সময় PIN এর জন্য অনুরোধ করা হবে</string>
- <string name="pincode_reenter_your_pincode">দয়া করে আবার App PIN দিন</string>
- <string name="pincode_remove_your_pincode">আপনার অ্যাপ PIN সরিয়ে নিন</string>
- <string name="pincode_mismatch">অ্যাপ PINগুলো একরকম নয়</string>
- <string name="pincode_wrong">অশুদ্ধ অ্যাপ PIN</string>
- <string name="pincode_removed">অ্যাপ PIN সরানো হয়েছে</string>
- <string name="pincode_stored">অ্যাপ PIN সংরক্ষণ করা হয়েছে</string>
<string name="media_notif_ticker">%1$s মিউজিক প্লেয়ার</string>
<string name="media_state_playing">%1$s (বাজানো হচ্ছে)</string>
<string name="media_state_loading">%1$s (লোড করা হচ্ছে)</string>
<string name="auth_no_net_conn_title">নেটওয়ার্ক সংযোগ নেই</string>
<string name="auth_nossl_plain_ok_title">নিরাপদ যোগাযোগ পাওয়া গেলনা</string>
<string name="auth_connection_established">যোগাযোগ স্থাপিত হয়েছে</string>
- <string name="auth_testing_connection">যোগাযোগ পরীক্ষা করা হচ্ছে...</string>
<string name="auth_not_configured_title">সার্ভারের কনফিগারেশনে ভুল রয়েছে</string>
<string name="auth_account_not_new">এই যন্ত্রে ইতোমধ্যে এই ব্যবহারকারী এবং সার্ভারের নামে একটি একাউন্ট রয়েছে</string>
<string name="auth_account_not_the_same">এই একাউন্টের ব্যবহারকারীর সঙ্গে প্রদত্ত ব্যবহারকারী মেলেনা</string>
<string name="saml_authentication_wrong_pass">ভুল কুটশব্দ</string>
<string name="actionbar_move">সরাও</string>
<string name="file_list_empty_moving">এখানে কিছু নেই। একটি ফোল্ডার যোগ করতে পারেন!</string>
- <string name="move_choose_button_text">বেছে নিন</string>
+ <string name="folder_picker_choose_button_text">বেছে নিন</string>
<string name="move_file_not_found">সরাতে ব্যার্থ হলো। ফাইলটি রয়েছে কিনা দেখুন।</string>
<string name="prefs_category_security">নিরাপত্তা</string>
+ <string name="auth_host_address">সার্ভার ঠিকানা</string>
</resources>
<string name="actionbar_settings">সেটিংস</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_imprint">অঙ্কিত করা</string>
<string name="auth_username">ইউজারনেম</string>
<string name="sync_string_files">ফাইলস</string>
- <string name="file_list_loading">লোড করা হচ্ছে...</string>
+ <string name="uploader_btn_new_folder_text">নতুন ফোল্ডার</string>
<string name="filedetails_download">ডাউনলোড করুন</string>
<string name="common_cancel">বাতিল করা</string>
<string name="common_error">ভুল</string>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="actionbar_upload">Učitaj</string>
+ <string name="actionbar_upload_files">Datoteke</string>
<string name="actionbar_mkdir">Nova fascikla</string>
+ <string name="actionbar_settings">Postavke</string>
+ <string name="actionbar_send_file">Pošalji</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="prefs_category_more">Više</string>
+ <string name="prefs_help">Pomoć</string>
+ <string name="auth_username">Korisničko ime</string>
+ <string name="auth_password">Lozinka</string>
+ <string name="sync_string_files">Datoteke</string>
+ <string name="uploader_btn_upload_text">Učitaj</string>
+ <string name="uploader_btn_new_folder_text">Novi direktorij</string>
+ <string name="filedetails_download">Preuzmite</string>
+ <string name="action_share_file">Podijelite vezu</string>
+ <string name="common_yes">Da</string>
+ <string name="common_no">Ne</string>
+ <string name="common_ok">Ok</string>
+ <string name="common_cancel_upload">Prekini učitavanje</string>
+ <string name="common_cancel">Odustani</string>
+ <string name="common_error">Greška</string>
+ <string name="common_error_unknown">Nepoznata greška</string>
+ <string name="change_password">Promijeni lozinku</string>
+ <string name="create_account">Kreiraj račun</string>
+ <string name="common_rename">Preimenuj</string>
+ <string name="activity_chooser_send_file_title">Pošalji</string>
<string name="empty"></string>
+ <string name="saml_authentication_required_text">Potrebna autentifikacija</string>
+ <string name="saml_authentication_wrong_pass">Pogrešna lozinka</string>
+ <string name="folder_picker_choose_button_text">Izaberite</string>
+ <string name="prefs_category_security">Sigurnost</string>
+ <string name="auth_host_address">Adresa servera</string>
</resources>
<string name="actionbar_settings">Configuració</string>
<string name="actionbar_see_details">Detalls</string>
<string name="actionbar_send_file">Envia</string>
+ <string name="actionbar_sort">Ordena</string>
+ <string name="actionbar_sort_title">Ordena per</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Més nou - Més antic</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">General</string>
<string name="prefs_category_more">Més</string>
<string name="prefs_accounts">Comptes</string>
<string name="prefs_manage_accounts">Gestió de comptes</string>
- <string name="prefs_pincode">PIN de l\'aplicació</string>
- <string name="prefs_pincode_summary">Protegiu el client</string>
+ <string name="prefs_passcode">Contrasenya</string>
<string name="prefs_instant_upload">Pujada instantànies de fotografies</string>
<string name="prefs_instant_upload_summary">Puja instantàniament les fotografies preses amb la càmera</string>
<string name="prefs_instant_video_upload">Pujades de vídeos instantanies</string>
<string name="sync_string_files">Fitxers</string>
<string name="setup_btn_connect">Connecta</string>
<string name="uploader_btn_upload_text">Puja</string>
+ <string name="uploader_btn_new_folder_text">Carpeta nova</string>
<string name="uploader_top_message">Seleccioneu la carpeta de pujada:</string>
<string name="uploader_wrn_no_account_title">No s\'ha trobat el compte</string>
<string name="uploader_wrn_no_account_text">No hi ha comptes %1$s en el dispositiu. Configureu un compte primer</string>
<string name="uploader_info_uploading">S\'està pujant</string>
<string name="file_list_seconds_ago">segons enrere</string>
<string name="file_list_empty">Res per aquí. Pugeu alguna cosa!</string>
- <string name="file_list_loading">Carregant...</string>
<string name="local_file_list_empty">No hi ha arxius a aquesta carpeta</string>
<string name="filedetails_select_file">Feu clic en un fitxer per mostrar informació addicional.</string>
<string name="filedetails_size">Mida:</string>
<string name="foreign_files_local_text">Local: %1$s</string>
<string name="foreign_files_remote_text">Remot: %1$s</string>
<string name="upload_query_move_foreign_files">No hi ha prou espai per copiar els fitxers seleccionats a la carpeta %1$s. Els hi voleu moure?</string>
- <string name="pincode_enter_pin_code">Escriviu el PIN de l\'aplicació</string>
- <string name="pincode_configure_your_pin">Escriviu el PIN de l\'aplicació</string>
- <string name="pincode_configure_your_pin_explanation">es requerirà el PIN cada vegada que s\'iniciï l\'aplicació</string>
- <string name="pincode_reenter_your_pincode">Torneu a escriure el PIN de l\'aplicació </string>
- <string name="pincode_remove_your_pincode">Elimina el PIN de l\'aplicació</string>
- <string name="pincode_mismatch">Els PINs de l\'aplicació no coincideixen</string>
- <string name="pincode_wrong">El PIN de l\'aplicació no és correcte</string>
- <string name="pincode_removed">S\'ha eliminat el PIN de l\'aplicació </string>
- <string name="pincode_stored">S\'ha desat el PIN de l\'aplicació </string>
<string name="media_notif_ticker">reproductor de música %1$s</string>
<string name="media_state_playing">%1$s (sonant)</string>
<string name="media_state_loading">%1$s (carregant)</string>
<string name="auth_no_net_conn_title">Sense connexió de xarxa</string>
<string name="auth_nossl_plain_ok_title">La connexió segura no està disponible.</string>
<string name="auth_connection_established">S\'ha establert la connexió</string>
- <string name="auth_testing_connection">S\'està comprovant la connexió...</string>
<string name="auth_not_configured_title">La configuració del servidor està malformada</string>
<string name="auth_account_not_new">Ja hi ha un compte al dispositiu pel mateix usuari i mateix servidor</string>
<string name="auth_account_not_the_same">L\'usuari introduït no coincideix amb l\'usuari d\'aquest compte</string>
<string name="downloader_download_file_not_found">El fitxer ja no està disponible en el servidor</string>
<string name="prefs_category_accounts">Comptes</string>
<string name="prefs_add_account">Afegeix compte</string>
+ <string name="log_progress_dialog_text">Carregant dades...</string>
<string name="saml_authentication_required_text">Es requereix autenticació</string>
<string name="saml_authentication_wrong_pass">Contrasenya incorrecta</string>
- <string name="move_choose_button_text">Escull</string>
+ <string name="actionbar_move">Moure</string>
+ <string name="folder_picker_choose_button_text">Escull</string>
<string name="prefs_category_security">Seguretat</string>
+ <string name="auth_host_address">Adreça del servidor</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Všechny soubory</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Nastavení</string>
+ <string name="drawer_item_logs">Logy</string>
+ <string name="drawer_close">Zavřít</string>
<string name="prefs_category_general">Obecné</string>
<string name="prefs_category_more">Více</string>
<string name="prefs_accounts">Účty</string>
<string name="prefs_manage_accounts">Spravovat účty</string>
- <string name="prefs_pincode">PIN do aplikace</string>
- <string name="prefs_pincode_summary">Chraňte svého klienta</string>
+ <string name="prefs_passcode">Zámek bezpečnostního kódu</string>
<string name="prefs_instant_upload">Okamžité nahrávání obrázků</string>
<string name="prefs_instant_upload_summary">Okamžitě nahrávat vytvořené fotografie</string>
<string name="prefs_instant_video_upload">Okamžité nahrávání videa</string>
<string name="prefs_imprint">Imprint</string>
<string name="prefs_remember_last_share_location">Zapamatovat umístění sdílení</string>
<string name="prefs_remember_last_upload_location_summary">Zapamatovat poslední umístění pro nahrání sdílených souborů</string>
- <string name="recommend_subject">Zkuste %1$s na vašem smartphonu!</string>
+ <string name="recommend_subject">Zkuste %1$s na svém chytrém telefonu!</string>
<string name="recommend_text">Chtěl bych vás pozvat k používání %1$s na vašem chytrém telefonu!\nKe stažení zde: %2$s</string>
<string name="auth_check_server">Zkontrolovat server</string>
<string name="auth_host_url">Adresa serveru https://...</string>
<string name="sync_string_files">Soubory</string>
<string name="setup_btn_connect">Připojit</string>
<string name="uploader_btn_upload_text">Odeslat</string>
+ <string name="uploader_btn_new_folder_text">Nová složka</string>
<string name="uploader_top_message">Vyberte adresář pro nahrání:</string>
<string name="uploader_wrn_no_account_title">Nenalezen žádný účet</string>
<string name="uploader_wrn_no_account_text">Nemáte žádné %1$s účty. Vytvořte si, prosím, nejdříve účet.</string>
<string name="uploader_info_uploading">Odesílání</string>
<string name="file_list_seconds_ago">před pár sekundami</string>
<string name="file_list_empty">Žádný obsah. Nahrajte něco!</string>
- <string name="file_list_loading">Načítám...</string>
+ <string name="file_list_loading">Načítání...</string>
<string name="local_file_list_empty">V tomto adresáři nejsou žádné soubory.</string>
<string name="filedetails_select_file">Více informací získáte klepnutím na soubor.</string>
<string name="filedetails_size">Velikost:</string>
<string name="filedetails_download">Stáhnout</string>
<string name="filedetails_sync_file">Obnovit soubor</string>
<string name="filedetails_renamed_in_upload_msg">Soubor byl v průběhu odesílání přejmenován na %1$s</string>
+ <string name="list_layout">Náhled seznamu</string>
<string name="action_share_file">Sdílet odkaz</string>
<string name="action_unshare_file">Zrušit sdílení odkazu</string>
<string name="common_yes">Ano</string>
<string name="foreign_files_local_text">Místní: %1$s</string>
<string name="foreign_files_remote_text">Vzdálené: %1$s</string>
<string name="upload_query_move_foreign_files">Není dostatek místa pro zkopírování vybraných souborů do adresáře %1$s. Přejete si je místo kopírování přesunout?</string>
- <string name="pincode_enter_pin_code">Zadejte PIN aplikace</string>
- <string name="pincode_configure_your_pin">Zadat PIN aplikace</string>
- <string name="pincode_configure_your_pin_explanation">Při každém spuštění aplikace bude vyžadováno zadání PIN</string>
- <string name="pincode_reenter_your_pincode">Zadejte znovu PIN aplikace</string>
- <string name="pincode_remove_your_pincode">Odstranit PIN aplikace</string>
- <string name="pincode_mismatch">PINy aplikace se neshodují</string>
- <string name="pincode_wrong">Neplatný PIN aplikace</string>
- <string name="pincode_removed">PIN aplikace odstraněn</string>
- <string name="pincode_stored">PIN aplikace uložen</string>
+ <string name="pass_code_enter_pass_code">Zadejte prosím svůj bezpečnostní kód</string>
+ <string name="pass_code_configure_your_pass_code">Zadejte svůj bezpečnostní kód</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Bezpečnostní kód bude vyžadován při každém spuštění aplikace</string>
+ <string name="pass_code_reenter_your_pass_code">Zopakujte bezpečnostní kód</string>
+ <string name="pass_code_remove_your_pass_code">Odstraňte svůj bezpečnostní kód</string>
+ <string name="pass_code_mismatch">Bezpečnostní kód se liší</string>
+ <string name="pass_code_wrong">Nesprávný bezpečnostní kód</string>
+ <string name="pass_code_removed">Bezpečnostní kód odstraněn</string>
+ <string name="pass_code_stored">Bezpečnostní kód uložen</string>
<string name="media_notif_ticker">Hudební přehrávač %1$s</string>
<string name="media_state_playing">%1$s (přehrává)</string>
<string name="media_state_loading">%1$s (načítá)</string>
<string name="auth_no_net_conn_title">Žádné síťové spojení</string>
<string name="auth_nossl_plain_ok_title">Zabezpečené spojení není k dispozici</string>
<string name="auth_connection_established">Spojení navázáno</string>
- <string name="auth_testing_connection">Zkouším spojení...</string>
+ <string name="auth_testing_connection">Testuje se připojení</string>
<string name="auth_not_configured_title">Neplatné nastavení serveru</string>
<string name="auth_account_not_new">Účet pro stejného uživatele a server již v zařízení existuje</string>
<string name="auth_account_not_the_same">Zadaný uživatel neodpovídá uživateli tohoto účtu</string>
<string name="auth_oauth_error">Neúspěšné přihlášení</string>
<string name="auth_oauth_error_access_denied">Přístup zamítnut autorizačním serverem</string>
<string name="auth_wtf_reenter_URL">Neočekávaný stav; prosím vložte znovu URL adresu serveru</string>
- <string name="auth_expired_oauth_token_toast">Vaše přihlášení vypršelo. Přihlašte se, prosím, znovu</string>
+ <string name="auth_expired_oauth_token_toast">Vaše přihlášení vypršelo. Přihlaste se prosím znovu</string>
<string name="auth_expired_basic_auth_toast">Zadejte prosím aktuální heslo</string>
- <string name="auth_expired_saml_sso_token_toast">Vaše přihlášení vypršelo. Přihlašte se, prosím, znovu</string>
+ <string name="auth_expired_saml_sso_token_toast">Vaše přihlášení vypršelo. Přihlaste se prosím znovu</string>
<string name="auth_connecting_auth_server">Připojuji se k přihlašovacímu serveru...</string>
<string name="auth_unsupported_auth_method">Server nepodporuje tuto přihlašovací metodu</string>
<string name="auth_unsupported_multiaccount">%1$s nepodporuje více účtů</string>
<string name="auth_fail_get_user_name">Váš server nevrací správné přihlašovací ID, kontaktujte prosím svého správce systému</string>
<string name="auth_can_not_auth_against_server">Není možné provést ověření </string>
+ <string name="auth_account_does_not_exist">V zařízení není zatím nastaven účet</string>
<string name="fd_keep_in_sync">Udržovat soubor aktuální</string>
<string name="common_rename">Přejmenovat</string>
<string name="common_remove">Odstranit</string>
<string name="sync_file_nothing_to_do_msg">Obsah souboru je již synchronizován</string>
<string name="create_dir_fail_msg">Adresář nemohl být vytvořen</string>
<string name="filename_forbidden_characters">Zakázané znaky: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Jméno souboru obsahuje aelspoň jeden neplatný znak</string>
<string name="filename_empty">Název nemůže být prázdný</string>
<string name="wait_a_moment">Počkejte chvíli</string>
<string name="filedisplay_unexpected_bad_get_content">Neočekávaný problém - zkuste zvolit soubor jinou aplikací</string>
<string name="filedisplay_no_file_selected">Žádný soubor nebyl vybrán</string>
<string name="activity_chooser_title">Odeslat odkaz ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Kopírování souboru z privátního úložiště</string>
<string name="oauth_check_onoff">Přihlásit se s oAuth2</string>
<string name="oauth_login_connection">Připojuji se k oAuth2 serveru...</string>
<string name="ssl_validator_header">Identitu stránky nelze ověřit</string>
<string name="share_link_file_error">Při pokusu o sdílení tohoto souboru či složky nastala chyba</string>
<string name="unshare_link_file_no_exist">Nelze ukončit sdílení. Zkontrolujte prosím že soubor existuje</string>
<string name="unshare_link_file_error">Při pokusu o zrušení sdílení tohoto souboru či složky nastala chyba</string>
+ <string name="share_link_password_title">Zadejte heslo</string>
+ <string name="share_link_empty_password">Musíte zadat heslo</string>
<string name="activity_chooser_send_file_title">Odeslat</string>
<string name="copy_link">Zkopírovat odkaz</string>
<string name="clipboard_text_copied">Zkopírováno do schránky</string>
<string name="auth_redirect_non_secure_connection_title">Bezpečné spojení je přesměrováno na nezabezpečenou trasu.</string>
<string name="actionbar_logger">Logy</string>
<string name="log_send_history_button">Odeslat historii</string>
- <string name="log_mail_subject">Logy aplikace ownCloud pro Android</string>
- <string name="log_progress_dialog_text">Načítám data...</string>
+ <string name="log_send_no_mail_app">Nebyla nalezena žádná aplikace pro odesílání logů. Nainstalujte poštovní aplikaci!</string>
+ <string name="log_send_mail_subject">%1$s logy aplikace pro Android</string>
+ <string name="log_progress_dialog_text">Načítání dat…</string>
<string name="saml_authentication_required_text">Vyžadováno přihlášení</string>
<string name="saml_authentication_wrong_pass">Nesprávné heslo</string>
<string name="actionbar_move">Přesunout</string>
<string name="file_list_empty_moving">Zde nic není. Můžete přidat adresář!</string>
- <string name="move_choose_button_text">Vybrat</string>
+ <string name="folder_picker_choose_button_text">Vybrat</string>
<string name="move_file_not_found">Nelze přesunout. Zkontrolujte prosím že soubor existuje</string>
<string name="move_file_invalid_into_descendent">Není možné adresář přesunout do vlastního podadresáře</string>
<string name="move_file_invalid_overwrite">Soubor již v cílovém adresáři existuje</string>
<string name="forbidden_permissions_move">pro přesun tohoto souboru</string>
<string name="prefs_category_instant_uploading">Okamžitá odesílání</string>
<string name="prefs_category_security">Zabezpečení</string>
+ <string name="prefs_instant_video_upload_path_title">Cesta pro nahrávání videí</string>
+ <string name="download_folder_failed_content">Stažení adresáře %1$s nemohlo být dokončeno</string>
+ <string name="shared_subject_header">sdílené</string>
+ <string name="with_you_subject_header">s vámi</string>
+ <string name="subject_token">%1$s s vámi sdílí \"%2$s\"</string>
+ <string name="auth_refresh_button">Obnovit připojení</string>
+ <string name="auth_host_address">Adresa serveru</string>
+ <string name="common_error_out_memory">Nedostatek paměti</string>
+ <string name="username">Uživatelské jméno</string>
+ <string name="file_list__footer__folder">1 adresář</string>
+ <string name="file_list__footer__folders">%1$d adresáře(ů)</string>
+ <string name="file_list__footer__file">1 soubor</string>
+ <string name="file_list__footer__file_and_folder">1 soubor, 1 adresář</string>
+ <string name="file_list__footer__file_and_folders">1 soubor, %1$d adresáře(ů)</string>
+ <string name="file_list__footer__files">%1$d soubory(ů)</string>
+ <string name="file_list__footer__files_and_folder">%1$d soubory(ů), 1 adresář</string>
+ <string name="file_list__footer__files_and_folders">%1$d soubory(ů), %2$d adresáře(ů)</string>
</resources>
<string name="actionbar_send_file">Anfon</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Cyffredinol</string>
<string name="prefs_accounts">Cyfrifon</string>
<string name="prefs_manage_accounts">Rheoli Cyfrifon</string>
- <string name="prefs_pincode">PIN Ap</string>
- <string name="prefs_pincode_summary">Amddiffyn eich cleient</string>
<string name="prefs_help">Cymorth</string>
<string name="prefs_imprint">Imprint</string>
<string name="auth_username">Enw defnyddiwr</string>
<string name="foreign_files_fail">Methwyd symud rhai ffeiliau</string>
<string name="foreign_files_local_text">Lleol: %1$s</string>
<string name="foreign_files_remote_text">Pell: %1$s</string>
- <string name="pincode_enter_pin_code">Cyflwynwch PIN eich Ap</string>
- <string name="pincode_configure_your_pin">Cyflwynwch PIN eich Ap</string>
- <string name="pincode_configure_your_pin_explanation">Bydd cais am y PIN bob tro mae\'r ap yn cychwyn</string>
- <string name="pincode_reenter_your_pincode">Ailgyflwynwch PIN eich Ap</string>
- <string name="pincode_remove_your_pincode">Gwaredwch PIN eich Ap</string>
- <string name="pincode_mismatch">Nid yw PINau yr Ap yr un fath</string>
- <string name="pincode_wrong">PIN Ap anghywir</string>
- <string name="pincode_removed">Gwaredwyd PIN Ap</string>
- <string name="pincode_stored">Cadwyd PIN Ap</string>
<string name="auth_no_net_conn_title">Dim cysylltiad rhwydwaith</string>
<string name="auth_nossl_plain_ok_title">Nid oes cysylltiad diogel ar gael.</string>
<string name="auth_connection_established">Sefydlwyd y cysylltiad</string>
<string name="activity_chooser_send_file_title">Anfon</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Cyfrifon</string>
- <string name="move_choose_button_text">Dewisiwch</string>
+ <string name="folder_picker_choose_button_text">Dewisiwch</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Alle filer</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Indstillinger</string>
+ <string name="drawer_item_logs">Logregistreringer</string>
+ <string name="drawer_close">Luk</string>
<string name="prefs_category_general">Generel</string>
<string name="prefs_category_more">Mere</string>
<string name="prefs_accounts">Konti</string>
<string name="prefs_manage_accounts">Administrér konti</string>
- <string name="prefs_pincode">App PIN</string>
- <string name="prefs_pincode_summary">Beskyt din klient</string>
+ <string name="prefs_passcode">Passcode-lås</string>
<string name="prefs_instant_upload">Upload billeder straks</string>
<string name="prefs_instant_upload_summary">Upload straks billeder taget med kameraet</string>
<string name="prefs_instant_video_upload">Upload videoer straks</string>
<string name="prefs_help">Hjælp</string>
<string name="prefs_recommend">Anbefal til en ven</string>
<string name="prefs_feedback">Feedback</string>
- <string name="prefs_imprint">Imprint</string>
+ <string name="prefs_imprint">Aftryk</string>
<string name="prefs_remember_last_share_location">Husk delt placering</string>
<string name="prefs_remember_last_upload_location_summary">Husk seneste delte placering for overførsel</string>
<string name="recommend_subject">Prøv %1$s på din smartphone!</string>
<string name="auth_host_url">Serveradresse https://…</string>
<string name="auth_username">Brugernavn</string>
<string name="auth_password">Kodeord</string>
- <string name="auth_register">Uvant med %1$s</string>
+ <string name="auth_register">Ny med %1$s</string>
<string name="sync_string_files">Filer</string>
<string name="setup_btn_connect">Tilslut</string>
<string name="uploader_btn_upload_text">Upload</string>
+ <string name="uploader_btn_new_folder_text">Ny mappe</string>
<string name="uploader_top_message">Vælg upload-mappe:</string>
<string name="uploader_wrn_no_account_title">Ingen konto fundet</string>
<string name="uploader_wrn_no_account_text">Der er ingen %1$s brugere på din enhed. Sæt venligst en bruger op først.</string>
<string name="filedetails_download">Hent</string>
<string name="filedetails_sync_file">Genopfrisk fil</string>
<string name="filedetails_renamed_in_upload_msg">Filen blev omdøbt til %1$s under upload</string>
+ <string name="list_layout">Listevisning</string>
<string name="action_share_file">Del link</string>
<string name="action_unshare_file">Ophæv deling</string>
<string name="common_yes">Ja</string>
<string name="foreign_files_local_text">Lokal: %1$s</string>
<string name="foreign_files_remote_text">Fjernplacering: %1$s</string>
<string name="upload_query_move_foreign_files">Der er ikke plads nok til at kopiere de valgte filer ind i mappen %1$s. Vil du flytte dem i stedet?</string>
- <string name="pincode_enter_pin_code">Indsæt venligst din App PIN</string>
- <string name="pincode_configure_your_pin">Indtast App PIN</string>
- <string name="pincode_configure_your_pin_explanation">PIN koden vil blive anmodet om hver gang applikationen bliver startet</string>
- <string name="pincode_reenter_your_pincode">Indtast venligst App PIN igen</string>
- <string name="pincode_remove_your_pincode">Fjern din App PIN</string>
- <string name="pincode_mismatch">App PIN er ikke ens</string>
- <string name="pincode_wrong">Forkert App PIN</string>
- <string name="pincode_removed">App PIN fjernet</string>
- <string name="pincode_stored">App PIN gemt</string>
+ <string name="pass_code_enter_pass_code">Indsæt venligst din passcode</string>
+ <string name="pass_code_configure_your_pass_code">Angiv din passcode</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Denne passcode vil blive forespurgt hver gang app\'en startes</string>
+ <string name="pass_code_reenter_your_pass_code">Angiv venligst din passcode påny</string>
+ <string name="pass_code_remove_your_pass_code">Fjern din passcode</string>
+ <string name="pass_code_mismatch">Passcode\'erne er ikke ens</string>
+ <string name="pass_code_wrong">Ukorrekt passcode</string>
+ <string name="pass_code_removed">Passcode blev fjernet</string>
+ <string name="pass_code_stored">Passcode blev gendannet</string>
<string name="media_notif_ticker">%1$s musikafspiller</string>
<string name="media_state_playing">%1$s (afspiller)</string>
<string name="media_state_loading">%1$s (indlæser)</string>
<string name="media_err_not_in_owncloud">Fil er ikke en gyldig konto</string>
<string name="media_err_unsupported">Ikke-understøttet medie codec</string>
<string name="media_err_io">Mediefilen kunne ikke læses</string>
- <string name="media_err_malformed">Mediefilen er ikke korrekt kodet</string>
+ <string name="media_err_malformed">Mediefilen er ikke korrekt \"encoded\"</string>
<string name="media_err_timeout">Tiden udløb under forsøg på at afspille</string>
<string name="media_err_invalid_progressive_playback">Mediefilen kan ikke streames</string>
<string name="media_err_unknown">Mediefil kan ikke afspilles med tilgængelige medieafspiller</string>
<string name="auth_no_net_conn_title">Ingen netværksforbindelse</string>
<string name="auth_nossl_plain_ok_title">Sikker forbindelse ikke tilgængelig.</string>
<string name="auth_connection_established">Forbindelse oprettet</string>
- <string name="auth_testing_connection">Afprøver forbindelse ...</string>
+ <string name="auth_testing_connection">Tester forbindelsen</string>
<string name="auth_not_configured_title">Misdannet server konfiguration</string>
<string name="auth_account_not_new">En konto for den samme bruger og server eksisterer allerede på enheden</string>
<string name="auth_account_not_the_same">Den indtastede bruger passer ikke til brugeren for denne konto</string>
<string name="auth_ssl_general_error_title">SSL-initialiseringen fejlede</string>
<string name="auth_ssl_unverified_server_title">Kunne ikke bekræfte SSl-serverens identitet</string>
<string name="auth_bad_oc_version_title">Ikke genkendt serverversion</string>
- <string name="auth_wrong_connection_title">Ikke ikke oprette forbindelse</string>
+ <string name="auth_wrong_connection_title">Kunne ikke oprette forbindelse</string>
<string name="auth_secure_connection">Sikker forbindelse oprettet</string>
<string name="auth_unauthorized">Forkert brugernavn eller kodeord</string>
<string name="auth_oauth_error">Mislykket godkendelse</string>
<string name="auth_expired_saml_sso_token_toast">Din session udløb. Forbind venligst igen</string>
<string name="auth_connecting_auth_server">Forbinder til godkendelsesserver ...</string>
<string name="auth_unsupported_auth_method">Serveren understøtter ikke denne godkendelsesmetode</string>
- <string name="auth_unsupported_multiaccount">%1$s understøtter ikke multiple konti</string>
+ <string name="auth_unsupported_multiaccount">%1$s understøtter ikke flere konti</string>
<string name="auth_fail_get_user_name">Din server retunere ikke et korrekt bruger-id. Kontakt venligst din administrator</string>
<string name="auth_can_not_auth_against_server">Kan ikke autentificere mod denne server</string>
+ <string name="auth_account_does_not_exist">Kontoen findes endnu ikke på enheden</string>
<string name="fd_keep_in_sync">Hold filen opdateret</string>
<string name="common_rename">Omdøb</string>
<string name="common_remove">Fjern</string>
<string name="sync_file_nothing_to_do_msg">Filindholdet allerede synkroniseret</string>
<string name="create_dir_fail_msg">Kunne ikke oprette mappe</string>
<string name="filename_forbidden_characters">Ugyldige tegn: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Filnavnet indeholder mindst ét ugyldigt tegn</string>
<string name="filename_empty">Filnavnet kan ikke stå tomt.</string>
<string name="wait_a_moment">Vent et øjeblik</string>
- <string name="filedisplay_unexpected_bad_get_content">Uforventet problem; prøv venligst anden applikation til at vælge filen</string>
+ <string name="filedisplay_unexpected_bad_get_content">Uventet problem; prøv venligst en anden applikation til at vælge filen</string>
<string name="filedisplay_no_file_selected">Ingen fil blev valgt</string>
<string name="activity_chooser_title">Send link til ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Kopierer fil fra privat lager.</string>
<string name="oauth_check_onoff">Log på med oAuth2</string>
<string name="oauth_login_connection">Forbinder til oAuth2-server...</string>
<string name="ssl_validator_header">Sidens identitet kunne ikke verificeres</string>
<string name="preview_image_error_unknown_format">Dette billede kan ikke vises</string>
<string name="error__upload__local_file_not_copied">%1$s kunne ikke kopieres til %2$s lokale mappe</string>
<string name="prefs_instant_upload_path_title">Sti til upload</string>
- <string name="share_link_no_support_share_api">Beklager, deling er ikke slået til på din server. Kontakt venligst din administrator.</string>
+ <string name="share_link_no_support_share_api">Beklager, deling er ikke slået til på din server. Kontakt venligst din
+⇥⇥administrator.</string>
<string name="share_link_file_no_exist">Kan ikke dele. Tjek venligst om filen findes.</string>
<string name="share_link_file_error">Der opstod en fejl ved deling af denne fil eller mappe</string>
<string name="unshare_link_file_no_exist">Kan ikke fjerne deling. Tjek venligst om filen findes.</string>
<string name="unshare_link_file_error">Der opstod en fejl ved stopning af deling af denne mappe.</string>
+ <string name="share_link_password_title">Angiv et kodeord</string>
+ <string name="share_link_empty_password">Du skal angive et kodeord</string>
<string name="activity_chooser_send_file_title">Send</string>
<string name="copy_link">Kopiér link</string>
<string name="clipboard_text_copied">Kopieret til udklipsholder</string>
<string name="auth_redirect_non_secure_connection_title">Sikker forbindelse videredirigeres til en usikker rute.</string>
<string name="actionbar_logger">Logge</string>
<string name="log_send_history_button">Send historik</string>
- <string name="log_mail_subject">App-logregistreringer for ownCloud Android</string>
- <string name="log_progress_dialog_text">Indlæser data...</string>
+ <string name="log_send_no_mail_app">Der blev ikke fundet apps, der kan sende logge. Installér mail-app\'en!</string>
+ <string name="log_send_mail_subject">%1$s Android-app - logge</string>
+ <string name="log_progress_dialog_text">Indlæser data ...</string>
<string name="saml_authentication_required_text">Godkendelse påkrævet</string>
<string name="saml_authentication_wrong_pass">Forkert kodeord</string>
<string name="actionbar_move">Flyt</string>
<string name="file_list_empty_moving">Der er intet her. Du kan tilføje en mappe!</string>
- <string name="move_choose_button_text">Vælg</string>
+ <string name="folder_picker_choose_button_text">Vælg</string>
<string name="move_file_not_found">Kan ikke flytte. Tjek venligst om filen findes</string>
<string name="move_file_invalid_into_descendent">Det er ikke muligt at flytte en mappe til en undermappe</string>
<string name="move_file_invalid_overwrite">Filen findes allerede i destinationsmappen</string>
<string name="forbidden_permissions_move">til at flytte denne fil</string>
<string name="prefs_category_instant_uploading">Øjeblikkelige uploads</string>
<string name="prefs_category_security">Sikkerhed</string>
+ <string name="prefs_instant_video_upload_path_title">Sti til videoupload</string>
+ <string name="download_folder_failed_content">Download af %1$s mappe kunne ikke fuldføres</string>
+ <string name="shared_subject_header">delt</string>
+ <string name="with_you_subject_header">med dig</string>
+ <string name="subject_token">%1$s delte \"%2$s\" med dig</string>
+ <string name="auth_refresh_button">Genopfrisk forbindelsen</string>
+ <string name="auth_host_address">Serveradresse</string>
+ <string name="common_error_out_memory">Ikke tilstrækkelig hukommelse</string>
+ <string name="username">Brugernavn</string>
+ <string name="file_list__footer__folder">1 mappe</string>
+ <string name="file_list__footer__folders">%1$d mapper</string>
+ <string name="file_list__footer__file">1 fil</string>
+ <string name="file_list__footer__file_and_folder">1 fil, 1 mappe</string>
+ <string name="file_list__footer__file_and_folders">1 fil, %1$d mapper</string>
+ <string name="file_list__footer__files">%1$d filer</string>
+ <string name="file_list__footer__files_and_folder">%1$d filer, 1 mape</string>
+ <string name="file_list__footer__files_and_folders">%1$d filer, %2$d mapper</string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="actionbar_upload">Hochladen</string>
<string name="actionbar_upload_files">Dateien</string>
+ <string name="actionbar_open_with">Öffnen mit</string>
+ <string name="actionbar_mkdir">Neuer Ordner</string>
<string name="actionbar_settings">Einstellungen</string>
+ <string name="actionbar_see_details">Details</string>
+ <string name="actionbar_send_file">Senden</string>
+ <string name="actionbar_sort">Sortieren</string>
+ <string name="actionbar_sort_title">Sortieren nach</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Neueste - Älteste</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Allgemein</string>
+ <string name="prefs_accounts">Konten</string>
+ <string name="prefs_manage_accounts">Konten verwalten</string>
+ <string name="prefs_instant_upload_summary">Videos, die mit der Kamera aufgenommen werden sofort hochladen</string>
+ <string name="prefs_instant_video_upload_summary">Videos, die mit der Kamera aufgenommen werden sofort hochladen</string>
+ <string name="prefs_log_title">Logging einschalten</string>
+ <string name="prefs_log_summary">Dies wird verwendet um Probleme aufzuzeichnen</string>
+ <string name="prefs_log_title_history">Logging Verlauf</string>
+ <string name="prefs_log_summary_history">Dies zeigt die aufgenommenen Logs</string>
+ <string name="prefs_log_delete_history_button">Verlauf löschen</string>
<string name="prefs_help">Hilfe</string>
+ <string name="prefs_recommend">Einem Freund empfehlen</string>
+ <string name="prefs_feedback">Rückmeldung</string>
+ <string name="recommend_subject">Versuch %1$s auf deinem Handy!</string>
+ <string name="recommend_text">Ich lade dich ein %1$s auf deinem Handy zu verwenden!\nDownloade es hier: %2$s</string>
+ <string name="auth_check_server">Server überprüfen</string>
+ <string name="auth_host_url">Server Adresse https://...</string>
+ <string name="auth_username">Benutzername</string>
<string name="auth_password">Passwort</string>
+ <string name="auth_register">Neu bei %1$s?</string>
<string name="sync_string_files">Dateien</string>
+ <string name="setup_btn_connect">Verbinden</string>
+ <string name="uploader_btn_upload_text">Hochladen</string>
+ <string name="uploader_btn_new_folder_text">Neuer Ordner</string>
+ <string name="uploader_wrn_no_account_title">Kein Benutzerkonto gefunden</string>
+ <string name="uploader_wrn_no_account_text">Es existieren keine %1$s Konten auf deinem Gerät. Bitte erstelle zuerst ein Konto.</string>
+ <string name="uploader_wrn_no_account_quit_btn_text">Schließen</string>
+ <string name="uploader_wrn_no_content_title">Kein Inhalt zum hochladen</string>
+ <string name="uploader_wrn_no_content_text">Es wurde kein Inhalt empfangen. Nichts zum hochladen.</string>
+ <string name="uploader_error_forbidden_content">%1$s ist es nicht erlaubt auf den geiteilten Inhalt zuzugreifen</string>
+ <string name="uploader_info_uploading">Lade hoch</string>
+ <string name="file_list_seconds_ago">Sekunden zuvor</string>
+ <string name="file_list_empty">Es ist nichts hier. Lade etwas hoch!</string>
+ <string name="local_file_list_empty">Es sind keine Dateien in diesem Ordner.</string>
+ <string name="filedetails_select_file">Auf eine Datei drücken, um mehr Informationen zu erhalten.</string>
+ <string name="filedetails_size">Größe:</string>
+ <string name="filedetails_type">Typ:</string>
+ <string name="filedetails_created">Erstellt am:</string>
+ <string name="filedetails_modified">Verändert am:</string>
<string name="filedetails_download">Herunterladen</string>
+ <string name="filedetails_sync_file">Datei neu laden</string>
+ <string name="action_share_file">Link teilen</string>
+ <string name="action_unshare_file">Link nicht mehr teilen</string>
+ <string name="common_yes">Ja</string>
+ <string name="common_no">Nein</string>
+ <string name="common_ok">OK</string>
+ <string name="common_cancel_download">Herunterladen abbrechen</string>
+ <string name="common_cancel_upload">Hochladen abbrechen</string>
<string name="common_cancel">Abbrechen</string>
+ <string name="common_save_exit">Speichern & Schließen</string>
<string name="common_error">Fehler</string>
+ <string name="common_loading">Lade ...</string>
+ <string name="common_error_unknown">Unbekannter Fehler</string>
+ <string name="about_title">Über</string>
+ <string name="change_password">Passwort ändern</string>
+ <string name="delete_account">Konto löschen</string>
+ <string name="create_account">Konto erstellen</string>
+ <string name="upload_chooser_title">Hochladen von ...</string>
+ <string name="uploader_info_dirname">Ordner Name</string>
+ <string name="uploader_upload_in_progress_ticker">Lade hoch ...</string>
+ <string name="uploader_upload_succeeded_ticker">Hochladen erfolgreich</string>
+ <string name="uploader_upload_succeeded_content_single">%1$s wurde erfolgreich hochgeladen</string>
+ <string name="uploader_upload_failed_ticker">Hochladen fehlgeschlagen</string>
+ <string name="uploader_upload_failed_content_single">Hochladen von %1$s konnte nicht fertig gestellt werden</string>
+ <string name="uploader_upload_failed_credentials_error">Hochladen fehlgeschlagen, du musst dich erneut anmelden</string>
+ <string name="downloader_download_in_progress_ticker">Lade herunter ...</string>
+ <string name="downloader_download_succeeded_ticker">Herunterladen erfolgreich</string>
+ <string name="downloader_download_succeeded_content">%1$s wurde erfolgreich heruntergeladen</string>
+ <string name="downloader_download_failed_ticker">Herunterladen fehlgeschlagen</string>
+ <string name="downloader_download_failed_content">Herunterladen von %1$s konnte nicht fertig gestellt werden</string>
+ <string name="downloader_not_downloaded_yet">Noch nicht heruntergeladen</string>
+ <string name="downloader_download_failed_credentials_error">Herunterladen fehlgeschlagen, du musst dich erneut anmelden</string>
+ <string name="common_choose_account">Konto wählen</string>
+ <string name="sync_fail_ticker">Synchronisierung fehlgeschlagen</string>
+ <string name="sync_fail_ticker_unauthorized">Synchronisierung fehlgeschlagen, du musst dich erneut anmelden</string>
+ <string name="sync_fail_content">Synchronisation von %1$s konnte nicht fertig gestellt werden</string>
+ <string name="sync_fail_content_unauthorized">Falsches passwort für %1$s</string>
+ <string name="sync_conflicts_in_favourites_ticker">Konflikte entdeckt</string>
+ <string name="sync_conflicts_in_favourites_content">%1$d synchronisierte Dateien konnten nicht synchronisiert werden </string>
+ <string name="sync_fail_in_favourites_content">Inhalte von %1$d Dateien konnten nicht synchronisiert werden (%2$d Konflikte)</string>
+ <string name="sync_foreign_files_forgotten_explanation">Ab Version 1.3.16 werden alle Dateien, die von diesem Gerät hochgeladen werden, in den lokalen Ordner %1$s kopiert um zu vermeiden, dass Datenverlust entsteht, wenn eine einzelne Datei mit mehreren Konten synchronisiert wird.\n\nWegen dieser Änderung wurden alle Dateien, die mit einer früheren Version der App hochgeladen wurden, in den Ordner %2$s kopiert. Jedoch verhinderte ein Fehler, dass die Operation, während der synchronisation des Kontos, erfolgreich beendet wurde. Du kannst die Datei(en) entweder so lassen, wie sie sind und den Link zu %3$s löschen oder die Datei(en) in den Ordner %1$s verschieben und den Link zu %4$s behalten.\n\nUnten aufgelistet findest du die lokalen und die dazugehörigen hochgeladenen Dateien in %5$s.</string>
+ <string name="sync_current_folder_was_removed">Ordner %1$s existiert nicht mehr</string>
+ <string name="foreign_files_move">Alle verschieben</string>
+ <string name="foreign_files_success">Alle Dateien wurden verschoben</string>
+ <string name="foreign_files_fail">Ein paar Dateien konnten nicht verschoben werden</string>
+ <string name="foreign_files_local_text">Lokal: %1$s</string>
+ <string name="ssl_validator_btn_details_see">Details</string>
+ <string name="activity_chooser_send_file_title">Senden</string>
<string name="empty"></string>
+ <string name="prefs_category_accounts">Konten</string>
+ <string name="auth_host_address">Adresse des Servers</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Alle Dateien</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Einstellungen</string>
+ <string name="drawer_item_logs">Protokolle</string>
+ <string name="drawer_close">Schließen</string>
<string name="prefs_category_general">Allgemein</string>
<string name="prefs_category_more">Mehr</string>
<string name="prefs_accounts">Konten</string>
<string name="prefs_manage_accounts">Konten verwalten</string>
- <string name="prefs_pincode">App-PIN</string>
- <string name="prefs_pincode_summary">Schützen Sie Ihren Client</string>
+ <string name="prefs_passcode">PIN gesperrt</string>
<string name="prefs_instant_upload">Sofortiger Bilderupload</string>
<string name="prefs_instant_upload_summary">Fotos von der Kamera sofort hochladen</string>
<string name="prefs_instant_video_upload">Sofortiger Videoupload</string>
<string name="sync_string_files">Dateien</string>
<string name="setup_btn_connect">Verbinden</string>
<string name="uploader_btn_upload_text">Hochladen</string>
+ <string name="uploader_btn_new_folder_text">Neuer Ordner</string>
<string name="uploader_top_message">Uploadordner auswählen:</string>
<string name="uploader_wrn_no_account_title">Kein Konto gefunden</string>
<string name="uploader_wrn_no_account_text">Es sind keine %1$s-Konten auf Ihrem Gerät eingerichtet. Bitte richten Sie zuerst ein Konto ein.</string>
<string name="uploader_info_uploading">Lade hoch</string>
<string name="file_list_seconds_ago">Gerade eben</string>
<string name="file_list_empty">Alles leer. Laden Sie etwas hoch!</string>
- <string name="file_list_loading">Ladevorgang …</string>
+ <string name="file_list_loading">Lade…</string>
<string name="local_file_list_empty">Es befinden sich keine Dateien in diesem Ordner.</string>
<string name="filedetails_select_file">Klicken Sie auf eine Datei für weitere Informationen.</string>
<string name="filedetails_size">Größe:</string>
<string name="filedetails_download">Herunterladen</string>
<string name="filedetails_sync_file">Datei aktualisieren</string>
<string name="filedetails_renamed_in_upload_msg">Datei wurde wärend des Uploads zu %1$s umbenannt</string>
+ <string name="list_layout">Listen-Layout</string>
<string name="action_share_file">Link teilen</string>
<string name="action_unshare_file">Link nicht mehr teilen</string>
<string name="common_yes">Ja</string>
<string name="foreign_files_local_text">Lokal: %1$s</string>
<string name="foreign_files_remote_text">Remote: %1$s</string>
<string name="upload_query_move_foreign_files">Es steht nicht genügend Speicherplatz zur Verfügung um die ausgewählten Dateien in den Ordner %1$s zu kopieren. Möchten Sie diese stattdessen verschieben?</string>
- <string name="pincode_enter_pin_code">Bitte geben Sie Ihre App-PIN ein</string>
- <string name="pincode_configure_your_pin">Bitte geben Sie Ihre App-PIN ein</string>
- <string name="pincode_configure_your_pin_explanation">PIN-Abfrage erfolgt nach Starten der App.</string>
- <string name="pincode_reenter_your_pincode">Bitte geben Sie Ihre App-PIN erneut ein.</string>
- <string name="pincode_remove_your_pincode">App-PIN entfernen</string>
- <string name="pincode_mismatch">Die App-PINs stimmen nicht überein</string>
- <string name="pincode_wrong">Falsche App-PIN</string>
- <string name="pincode_removed">Die App-PIN wurde entfernt</string>
- <string name="pincode_stored">Die App-PIN wurde gespeichert</string>
+ <string name="pass_code_enter_pass_code">Bitte PIN eingeben</string>
+ <string name="pass_code_configure_your_pass_code">Bitte PIN eingeben</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Die PIN wird jedes mal wenn die App gestartet wird abgefragt</string>
+ <string name="pass_code_reenter_your_pass_code">Bitte PIN erneut eingeben</string>
+ <string name="pass_code_remove_your_pass_code">PIN entfernen</string>
+ <string name="pass_code_mismatch">Die PINs stimmen nicht überein</string>
+ <string name="pass_code_wrong">PIN nicht korrekt</string>
+ <string name="pass_code_removed">PIN entfernt</string>
+ <string name="pass_code_stored">PIN gespeichert</string>
<string name="media_notif_ticker">%1$s Musikplayer</string>
<string name="media_state_playing">%1$s (abspielend)</string>
<string name="media_state_loading">%1$s (lädt)</string>
<string name="auth_no_net_conn_title">Keine Netzwerkverbindung</string>
<string name="auth_nossl_plain_ok_title">Sichere Verbindung nicht verfügbar.</string>
<string name="auth_connection_established">Verbindung hergestellt</string>
- <string name="auth_testing_connection">Verbindungstest …</string>
+ <string name="auth_testing_connection">Verbindung testen</string>
<string name="auth_not_configured_title">Fehlerhafte Server Konfiguration</string>
<string name="auth_account_not_new">Ein Benutzerkonto für den gleichen Benutzer und Server existiert auf diesem Gerät bereits</string>
<string name="auth_account_not_the_same">Der eingegebene Benutzer passt nicht zu dem Benutzer dieses Benutzerkontos</string>
<string name="auth_fail_get_user_name">Ihr Server gibt keine richtige Benutzerkennung zurück, bitte kontaktieren Sie einen Administrator
⇥</string>
<string name="auth_can_not_auth_against_server">Die Legitimierung gegenüber dem Server konnte nicht durchgeführt werden</string>
+ <string name="auth_account_does_not_exist">Das Benutzerkonto ist bis jetzt noch nicht auf dem Gerät vorhanden</string>
<string name="fd_keep_in_sync">Datei aktuell halten</string>
<string name="common_rename">Umbenennen</string>
<string name="common_remove">Löschen</string>
<string name="sync_file_nothing_to_do_msg">Dateiinhalte bereits synchronisiert</string>
<string name="create_dir_fail_msg">Ordner konnte nicht erstellt werden</string>
<string name="filename_forbidden_characters">Verbotene Zeichen: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Der Dateiname enthält mindestens ein ungültiges Zeichen</string>
<string name="filename_empty">Dateiname darf nicht leer sein</string>
<string name="wait_a_moment">Bitte warten Sie einen Moment.</string>
<string name="filedisplay_unexpected_bad_get_content">Ein unerwartetes Problem ist aufgetreten. Bitte versuchen Sie, die Datei in einer anderen App zu öffnen.</string>
<string name="filedisplay_no_file_selected">Es wurde keine Datei ausgewählt.</string>
<string name="activity_chooser_title">Link senden an …</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Kopiere Datei vom privatem Speicher</string>
<string name="oauth_check_onoff">Anmelden mit oAuth2</string>
<string name="oauth_login_connection">Mit dem oAuth2-Server wird verbunden …</string>
<string name="ssl_validator_header">Die Identität der Website konnte nicht überprüft werden</string>
<string name="share_link_file_error">Es ist ein Fehler beim Freigeben der Datei oder des Ordners aufgetreten.</string>
<string name="unshare_link_file_no_exist">Entfernen der Freigabe nicht möglich. Prüfen Sie, ob die Datei existiert</string>
<string name="unshare_link_file_error">Es ist ein Fehler beim Entfernen der Freigabe für diese Datei oder den Ordner aufgetreten.</string>
+ <string name="share_link_password_title">Passwort eingeben</string>
+ <string name="share_link_empty_password">Sie müssen ein Passwort eingeben</string>
<string name="activity_chooser_send_file_title">Senden</string>
<string name="copy_link">Link kopieren</string>
<string name="clipboard_text_copied">In die Zwischenablage kopiert</string>
<string name="auth_redirect_non_secure_connection_title">Die gesicherte Verbindung wird auf eine unsichere Route weitergeleitet.</string>
<string name="actionbar_logger">Protokolle</string>
<string name="log_send_history_button">Verlauf senden</string>
- <string name="log_mail_subject">Protokolle der ownCloud-Android-App</string>
- <string name="log_progress_dialog_text">Daten werden geladen …</string>
+ <string name="log_send_no_mail_app">Keine App zum Versenden der Meldungen gefunden. Bitte installieren Sie die Mail-App!</string>
+ <string name="log_send_mail_subject">%1$s Android-App Meldungen</string>
+ <string name="log_progress_dialog_text">Lade Daten…</string>
<string name="saml_authentication_required_text">Legitimierung benötigt</string>
<string name="saml_authentication_wrong_pass">Falsches Passwort</string>
<string name="actionbar_move">Verschieben</string>
<string name="file_list_empty_moving">Nichts vorhanden. Sie können einen Ordner hinzufügen!</string>
- <string name="move_choose_button_text">Auswählen</string>
+ <string name="folder_picker_choose_button_text">Auswählen</string>
<string name="move_file_not_found">Verschieben nicht möglich. Bitte überprüfen Sie, ob die Datei existiert</string>
<string name="move_file_invalid_into_descendent">Es ist nicht möglich einen Ordner eine Ebene tiefer zu verschieben</string>
<string name="move_file_invalid_overwrite">Die Datei ist bereits im Zielordner vorhanden</string>
<string name="forbidden_permissions_move">um diese Datei zu verschieben</string>
<string name="prefs_category_instant_uploading">Sofortiges Hochladen</string>
<string name="prefs_category_security">Sicherheit</string>
+ <string name="prefs_instant_video_upload_path_title">Verzeichnis zum Hochladen der Videos</string>
+ <string name="download_folder_failed_content">Herunterladen des %1$s - Ordners konnte nicht abgeschlossen werden</string>
+ <string name="shared_subject_header">geteilt</string>
+ <string name="with_you_subject_header">Mit Ihnen</string>
+ <string name="subject_token">%1$s hat \"%2$s\" mit Ihnen geteilt</string>
+ <string name="auth_refresh_button">Verbindung aktualisieren</string>
+ <string name="auth_host_address">Serveradresse</string>
+ <string name="common_error_out_memory">Nicht genügend Speicher</string>
+ <string name="username">Benutzername</string>
+ <string name="file_list__footer__folder">1 Ordner</string>
+ <string name="file_list__footer__folders">%1$d Ordner</string>
+ <string name="file_list__footer__file">1 Datei</string>
+ <string name="file_list__footer__file_and_folder">1 Datei, 1 Ordner</string>
+ <string name="file_list__footer__file_and_folders">1 Datei, %1$d Ordner</string>
+ <string name="file_list__footer__files">%1$d Dateien</string>
+ <string name="file_list__footer__files_and_folder">%1$d Dateien, 1 Ordner</string>
+ <string name="file_list__footer__files_and_folders">%1$d Dateien, %2$d Ordner</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Alle Dateien</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Einstellungen</string>
+ <string name="drawer_item_logs">Protokolle</string>
+ <string name="drawer_close">Schließen</string>
<string name="prefs_category_general">Allgemein</string>
<string name="prefs_category_more">Mehr</string>
<string name="prefs_accounts">Konten</string>
<string name="prefs_manage_accounts">Konten verwalten</string>
- <string name="prefs_pincode">App-PIN</string>
- <string name="prefs_pincode_summary">Schütze Deinen Client</string>
+ <string name="prefs_passcode">PIN gesperrt</string>
<string name="prefs_instant_upload">Sofortiger Bilder-Upload</string>
<string name="prefs_instant_upload_summary">Lade Fotos von der Kamera sofort hoch</string>
<string name="prefs_instant_video_upload">Sofortiger Video-Upload</string>
<string name="recommend_subject">Probiere %1$s auf Deinem Smartphone!</string>
<string name="recommend_text">Ich möchte Dich zum Benutzen von %1$s auf Deinem Smartphone einladen!\nLade es hier herunter: %2$s</string>
<string name="auth_check_server">Überprüfe den Server</string>
- <string name="auth_host_url">Server-Adresse https://…</string>
+ <string name="auth_host_url">Serveradresse https://…</string>
<string name="auth_username">Benutzername</string>
<string name="auth_password">Passwort</string>
<string name="auth_register">Ist %1$s neu für dich?</string>
<string name="sync_string_files">Dateien</string>
<string name="setup_btn_connect">Verbinden</string>
<string name="uploader_btn_upload_text">Hochladen</string>
+ <string name="uploader_btn_new_folder_text">Neuer Ordner</string>
<string name="uploader_top_message">Wähle Zielordner:</string>
<string name="uploader_wrn_no_account_title">Kein Account gefunden</string>
<string name="uploader_wrn_no_account_text">Es sind keine %1$s-Accounts auf Deinem Gerät eingerichtet. Bitte richte zuerst ein Konto ein.</string>
<string name="uploader_info_uploading">Lade hoch</string>
<string name="file_list_seconds_ago">Gerade eben</string>
<string name="file_list_empty">Alles leer. Lade etwas hoch!</string>
- <string name="file_list_loading">Ladevorgang …</string>
+ <string name="file_list_loading">Lade…</string>
<string name="local_file_list_empty">Es befinden sich keine Dateien in diesem Ordner.</string>
<string name="filedetails_select_file">Klicken Sie auf eine Datei für weitere Informationen.</string>
<string name="filedetails_size">Größe:</string>
<string name="filedetails_download">Herunterladen</string>
<string name="filedetails_sync_file">Datei aktualisieren</string>
<string name="filedetails_renamed_in_upload_msg">Datei wurde wärend des Uploads zu %1$s umbenannt</string>
- <string name="action_share_file">Link Teilen</string>
+ <string name="list_layout">Listen-Layout</string>
+ <string name="action_share_file">Link teilen</string>
<string name="action_unshare_file">Link nicht mehr freigeben</string>
<string name="common_yes">Ja</string>
<string name="common_no">Nein</string>
<string name="common_cancel">Abbrechen</string>
<string name="common_save_exit">Speichern & schließen</string>
<string name="common_error">Fehler</string>
- <string name="common_loading">Lädt ...</string>
+ <string name="common_loading">Lade…</string>
<string name="common_error_unknown">Unbekannter Fehler</string>
<string name="about_title">Über</string>
<string name="change_password">Passwort ändern</string>
<string name="delete_account">Account löschen</string>
<string name="create_account">Account erstellen</string>
- <string name="upload_chooser_title">Dateien hochladen von...</string>
+ <string name="upload_chooser_title">Dateien hochladen von…</string>
<string name="uploader_info_dirname">Ordnername</string>
- <string name="uploader_upload_in_progress_ticker">Hochladen...</string>
+ <string name="uploader_upload_in_progress_ticker">Hochladen…</string>
<string name="uploader_upload_in_progress_content">%1$d%% Hochladen %2$s</string>
<string name="uploader_upload_succeeded_ticker">Hochladen erfolgreich</string>
<string name="uploader_upload_succeeded_content_single">%1$s wurde(n) erfolgreich hochgeladen</string>
<string name="uploader_upload_failed_ticker">Hochladen fehlgeschlagen</string>
<string name="uploader_upload_failed_content_single">Hochladen von %1$s konnte nicht abgeschlossen werden</string>
<string name="uploader_upload_failed_credentials_error">Hochladen fehlgeschlagen, Du musst dich nochmals anmelden</string>
- <string name="downloader_download_in_progress_ticker">Herunterladen...</string>
+ <string name="downloader_download_in_progress_ticker">Herunterladen…</string>
<string name="downloader_download_in_progress_content">%1$d%% Herunterladen %2$s</string>
<string name="downloader_download_succeeded_ticker">Herunterladen erfolgreich</string>
<string name="downloader_download_succeeded_content">%1$s wurde erfolgreich heruntergeladen</string>
<string name="foreign_files_local_text">Lokal: %1$s</string>
<string name="foreign_files_remote_text">Remote: %1$s</string>
<string name="upload_query_move_foreign_files">Es steht nicht genügend Speicherplatz zur Verfügung um die ausgewählten Dateien in den %1$s Ordner zu kopieren. Möchtest du diese stattdessen verschieben?</string>
- <string name="pincode_enter_pin_code">Bitte gib Deine App-PIN ein</string>
- <string name="pincode_configure_your_pin">Bitte gib Deine App-PIN ein</string>
- <string name="pincode_configure_your_pin_explanation">PIN-Abfrage erfolgt nach Starten der App.</string>
- <string name="pincode_reenter_your_pincode">Bitte gib Deine App-PIN erneut ein.</string>
- <string name="pincode_remove_your_pincode">App-PIN entfernen</string>
- <string name="pincode_mismatch">Die App-PINs stimmen nicht überein</string>
- <string name="pincode_wrong">Falsche App-PIN</string>
- <string name="pincode_removed">Die App-PIN wurde entfernt</string>
- <string name="pincode_stored">Die App-PIN wurde gespeichert</string>
+ <string name="pass_code_enter_pass_code">Bitte PIN eingeben</string>
+ <string name="pass_code_configure_your_pass_code">Bitte PIN eingeben</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Die PIN wird jedes mal beim Start der App abgefragt</string>
+ <string name="pass_code_reenter_your_pass_code">Bitte PIN nochmals eingeben</string>
+ <string name="pass_code_remove_your_pass_code">PIN entfernen</string>
+ <string name="pass_code_mismatch">Die PINs stimmen nicht überein</string>
+ <string name="pass_code_wrong">PIN nicht korrekt</string>
+ <string name="pass_code_removed">PIN entfernt</string>
+ <string name="pass_code_stored">PIN gespeichert</string>
<string name="media_notif_ticker">%1$s Musik Player</string>
<string name="media_state_playing">%1$s (playing)</string>
<string name="media_state_loading">%1$s (loading)</string>
<string name="media_rewind_description">Zurückspielen Knopf</string>
<string name="media_play_pause_description">Play-/Pause Knopf</string>
<string name="media_forward_description">Vorspulen Knopf</string>
- <string name="auth_getting_authorization">Autorisierung empfangen...</string>
- <string name="auth_trying_to_login">Anmeldungsversuch...</string>
+ <string name="auth_getting_authorization">Autorisierung empfangen…</string>
+ <string name="auth_trying_to_login">Anmeldeversuch…</string>
<string name="auth_no_net_conn_title">Keine Netzwerkverbindung</string>
<string name="auth_nossl_plain_ok_title">Sichere Verbindung nicht verfügbar.</string>
<string name="auth_connection_established">Verbindung hergestellt</string>
- <string name="auth_testing_connection">Verbindung testen...</string>
+ <string name="auth_testing_connection">Verbindung testen</string>
<string name="auth_not_configured_title">Fehlerhafte Server Konfiguration</string>
<string name="auth_account_not_new">Ein Benutzerkonto für den gleichen Benutzer und Server existiert auf diesem Gerät bereits</string>
<string name="auth_account_not_the_same">Der eingegebene Benutzer passt nicht zu dem Benutzer dieses Benutzerkontos</string>
<string name="auth_fail_get_user_name">Dein Server gibt keine korrekte Benutzer-ID zurück, bitte kontaktiere einen Administrator
</string>
<string name="auth_can_not_auth_against_server">Die Authentifizierung gegenüber dem Server konnte nicht durchgeführt werden</string>
+ <string name="auth_account_does_not_exist">Das Benutzerkonto ist bis jetzt noch nicht auf dem Gerät vorhanden</string>
<string name="fd_keep_in_sync">Datei aktuell halten</string>
<string name="common_rename">Umbenennen</string>
<string name="common_remove">Löschen</string>
<string name="sync_file_nothing_to_do_msg">Dateiinhalte bereits synchronisiert</string>
<string name="create_dir_fail_msg">Verzeichnis konnte nicht erstellt werden</string>
<string name="filename_forbidden_characters">Verbotene Zeichen: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Der Dateiname enthält mindestens ein ungültiges Zeichen</string>
<string name="filename_empty">Dateiname darf nicht leer sein</string>
<string name="wait_a_moment">Bitte warte einen Moment.</string>
<string name="filedisplay_unexpected_bad_get_content">Ein unerwartetes Problem ist aufgetreten. Bitte versuche, die Datei in einer anderen App zu öffnen</string>
<string name="filedisplay_no_file_selected">Es wurde keine Datei ausgewählt.</string>
- <string name="activity_chooser_title">Link senden an ...</string>
+ <string name="activity_chooser_title">Link senden an…</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Kopiere Datei vom privatem Speicher</string>
<string name="oauth_check_onoff">Anmelden mit oAuth2</string>
<string name="oauth_login_connection">Verbinde mit dem oAuth2-Server.</string>
<string name="ssl_validator_header">Die Identität der Website konnte nicht überprüft werden</string>
<string name="share_link_file_error">Es ist ein Fehler beim Freigeben der Datei oder des Ordners aufgetreten.</string>
<string name="unshare_link_file_no_exist">Entfernen der Freigabe nicht möglich. Prüfe, dass die Datei existiert</string>
<string name="unshare_link_file_error">Es ist ein Fehler beim Entfernen der Freigabe für diese Datei oder den Ordner aufgetreten.</string>
+ <string name="share_link_password_title">Passwort eingeben</string>
+ <string name="share_link_empty_password">Du musst ein Passwort eingeben</string>
<string name="activity_chooser_send_file_title">Senden</string>
<string name="copy_link">Link kopieren</string>
<string name="clipboard_text_copied">In die Zwischenablage kopiert</string>
<string name="auth_redirect_non_secure_connection_title">Die gesicherte Verbindung wird auf eine unsichere Route weitergeleitet.</string>
<string name="actionbar_logger">Protokolle</string>
<string name="log_send_history_button">Verlauf senden</string>
- <string name="log_mail_subject">Protokolle der ownCloud-Android-App</string>
- <string name="log_progress_dialog_text">Daten werden geladen …</string>
+ <string name="log_send_no_mail_app">Keine App zum Versenden der Meldungen gefunden. Bitte installiere die Mail-App!</string>
+ <string name="log_send_mail_subject">%1$s Android-App Meldungen</string>
+ <string name="log_progress_dialog_text">Lade Daten…</string>
<string name="saml_authentication_required_text">Legitimierung benötigt</string>
<string name="saml_authentication_wrong_pass">Falsches Passwort</string>
<string name="actionbar_move">Verschieben</string>
<string name="file_list_empty_moving">Nichts vorhanden. Du kannst einen Ordner hinzufügen!</string>
- <string name="move_choose_button_text">Auswählen</string>
+ <string name="folder_picker_choose_button_text">Auswählen</string>
<string name="move_file_not_found">Verschieben nicht möglich. Prüfe, dass die Datei existiert</string>
<string name="move_file_invalid_into_descendent">Es ist nicht möglich, einen Ordner in einen seiner Unterordner zu verschieben</string>
<string name="move_file_invalid_overwrite">Die Datei ist bereits im Zielordner vorhanden</string>
<string name="forbidden_permissions_move">um diese Datei zu verschieben</string>
<string name="prefs_category_instant_uploading">Sofortiges Hochladen</string>
<string name="prefs_category_security">Sicherheit</string>
+ <string name="prefs_instant_video_upload_path_title">Verzeichnis zum Hochladen der Videos</string>
+ <string name="download_folder_failed_content">Herunterladen des %1$s - Ordners konnte nicht abgeschlossen werden</string>
+ <string name="shared_subject_header">geteilt</string>
+ <string name="with_you_subject_header">Mit Dir</string>
+ <string name="subject_token">%1$s hat \"%2$s\" mit Dir geteilt</string>
+ <string name="auth_refresh_button">Verbindung aktualisieren</string>
+ <string name="auth_host_address">Serveradresse</string>
+ <string name="common_error_out_memory">Nicht genügend Speicher</string>
+ <string name="username">Benutzername</string>
+ <string name="file_list__footer__folder">1 Ordner</string>
+ <string name="file_list__footer__folders">%1$d Ordner</string>
+ <string name="file_list__footer__file">1 Datei</string>
+ <string name="file_list__footer__file_and_folder">1 Datei, 1 Ordner</string>
+ <string name="file_list__footer__file_and_folders">1 Datei, %1$d Ordner</string>
+ <string name="file_list__footer__files">%1$d Dateien</string>
+ <string name="file_list__footer__files_and_folder">%1$d Dateien, 1 Ordner</string>
+ <string name="file_list__footer__files_and_folders">%1$d Dateien, %2$d Ordner</string>
</resources>
<string name="actionbar_settings">Ρυθμίσεις</string>
<string name="actionbar_see_details">Λεπτομέρειες</string>
<string name="actionbar_send_file">Αποστολή</string>
+ <string name="actionbar_sort">Ταξινόμηση</string>
+ <string name="actionbar_sort_title">Ταξινόμηση κατά</string>
<string-array name="actionbar_sortby">
- <item>A-Z</item>
+ <item>A-Ω</item>
<item>Νεότερο - Παλαιότερο</item>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Όλα τα αρχεία</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Ρυθμίσεις</string>
+ <string name="drawer_item_logs">Αρχεία καταγραφών</string>
+ <string name="drawer_close">Κλείσιμο</string>
<string name="prefs_category_general">Γενικά</string>
<string name="prefs_category_more">Περισσότερα</string>
<string name="prefs_accounts">Λογαριασμοί</string>
<string name="prefs_manage_accounts">Διαχείριση Λογαριασμών</string>
- <string name="prefs_pincode">PIN εφαρμογής</string>
- <string name="prefs_pincode_summary">Προστατέψτε το δέκτη σας</string>
+ <string name="prefs_passcode">Κλείδωμα με κωδικό πρόσβασης</string>
<string name="prefs_instant_upload">Στιγμιαίες μεταφορτώσεις εικόνων</string>
<string name="prefs_instant_upload_summary">Μεταφορτώστε απευθείας φωτογραφίες από την κάμερα</string>
<string name="prefs_instant_video_upload">Στιγμιαίες μεταφορτώσεις βίντεο</string>
<string name="prefs_recommend">Προτείνετε σε φίλο</string>
<string name="prefs_feedback">Σχόλια </string>
<string name="prefs_imprint">Αποτύπωμα</string>
+ <string name="prefs_remember_last_share_location">Αποθήκευση σημείου διαμοιρασμού</string>
+ <string name="prefs_remember_last_upload_location_summary">Αποθήκευση τελευταίου σημείου διαμοιρασμού μεταφόρτωσης</string>
<string name="recommend_subject">Δοκιμάστε %1$s στο κινητό σας!</string>
<string name="recommend_text">Θα ήθελα να σε προσκαλέσω να χρησιμοποιήσεις το %1$s στο κινητό σου!\nΛήψη εδώ: %2$s</string>
<string name="auth_check_server">Έλεγχος Διακομιστή</string>
<string name="sync_string_files">Αρχεία</string>
<string name="setup_btn_connect">Σύνδεση</string>
<string name="uploader_btn_upload_text">Μεταφόρτωση</string>
+ <string name="uploader_btn_new_folder_text">Νέος φάκελος</string>
<string name="uploader_top_message">Επιλέξτε φάκελο μεταφορτώσεων:</string>
<string name="uploader_wrn_no_account_title">Δεν βρέθηκε λογαριασμός</string>
<string name="uploader_wrn_no_account_text">Δεν υπάρχουν λογαριασμοί %1$s στη συσκευή σας. Παρακαλώ ρυθμίστε πρώτα ένα λογαριασμό.</string>
<string name="uploader_error_forbidden_content">Ο %1$s δεν επιτρέπεται να έχει πρόσβαση στο κοινόχρηστο περιεχόμενο</string>
<string name="uploader_info_uploading">Μεταφόρτωση</string>
<string name="file_list_seconds_ago">δευτερόλεπτα πριν</string>
- <string name="file_list_empty">Î\94εν Ï\85Ï\80άÏ\81Ï\87ει Ï\84ίÏ\80οÏ\84α εδÏ\8e. Î\91νεβάστε κάτι!</string>
- <string name="file_list_loading">Φόρτωση ...</string>
+ <string name="file_list_empty">Î\94εν Ï\85Ï\80άÏ\81Ï\87ει Ï\84ίÏ\80οÏ\84α εδÏ\8e. Î\9cεÏ\84αÏ\86οÏ\81Ï\84Ï\8eστε κάτι!</string>
+ <string name="file_list_loading">Φόρτωση...</string>
<string name="local_file_list_empty">Δεν υπάρχουν αρχεία σε αυτό τον φάκελο.</string>
<string name="filedetails_select_file">Αγγίξτε κάποιο αρχείο για να προβάλετε περισσότερες πληροφορίες.</string>
<string name="filedetails_size">Μέγεθος:</string>
<string name="filedetails_download">Λήψη</string>
<string name="filedetails_sync_file">Ανανέωση αρχείου</string>
<string name="filedetails_renamed_in_upload_msg">Το αρχείο μετονομάστηκε σε %1$s κατά τη μεταφόρτωση</string>
+ <string name="list_layout">Διάταξη Λίστας</string>
<string name="action_share_file">Διαμοιρασμός συνδέσμου</string>
<string name="action_unshare_file">Ακύρωση διαμοιρασμού συνδέσμου</string>
<string name="common_yes">Ναι</string>
<string name="foreign_files_local_text">Τοπικά: %1$s</string>
<string name="foreign_files_remote_text">Απομακρυσμένα: %1$s</string>
<string name="upload_query_move_foreign_files">Δεν υπάρχει αρκετός διαθέσιμος αποθηκευτικός χώρος για να αντιγραφούν τα επιλεγμένα αρχεία στον φάκελο %1$s. Θα θέλατε να τα μετακινήσετε αντί αυτού;</string>
- <string name="pincode_enter_pin_code">Παρακαλώ, εισάγετε το PIN εφαρμογής σας</string>
- <string name="pincode_configure_your_pin">Εισάγετε το PIN της εφαρμογής</string>
- <string name="pincode_configure_your_pin_explanation">Το PIN θα ζητείται κάθε φορά που εκκινείται η εφαρμογή</string>
- <string name="pincode_reenter_your_pincode">Παρακαλώ επανεισάγετε το PIN της εφαρμογής</string>
- <string name="pincode_remove_your_pincode">Αφαιρέστε τον PIN της εφαρμογής</string>
- <string name="pincode_mismatch">Δεν ταιριάζουν τα PIN της εφαρμογής </string>
- <string name="pincode_wrong">Εσφαλμένο PIN της εφαρμογής</string>
- <string name="pincode_removed">Αφαιρέθηκε το PIN της εφαρμογής</string>
- <string name="pincode_stored">Το PIN της εφαρμογής αποθηκεύτηκε</string>
+ <string name="pass_code_enter_pass_code">Παρακαλώ, εισάγετε τον κωδικό σας πρόσβασης</string>
+ <string name="pass_code_configure_your_pass_code">Εισάγετε τον κωδικό πρόσβασης</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Ο κωδικός πρόσβασης θα ζητείται κάθε φορά που εκκινεί η εφαρμογή</string>
+ <string name="pass_code_reenter_your_pass_code">Παρακαλώ, επανεισάγετε τον κωδικό σας πρόσβασης</string>
+ <string name="pass_code_remove_your_pass_code">Αφαίρεση του κωδικού σας πρόσβασης</string>
+ <string name="pass_code_mismatch">Οι κωδικοί πρόσβασης δεν ταιριάζουν</string>
+ <string name="pass_code_wrong">Εσφαλμένος κωδικός πρόσβασης</string>
+ <string name="pass_code_removed">Ο κωδικός πρόσβασης αφαιρέθηκε</string>
+ <string name="pass_code_stored">Ο κωδικός πρόσβασης αποθηκεύτηκε</string>
<string name="media_notif_ticker">%1$s αναπαραγωγή μουσικής</string>
<string name="media_state_playing">%1$s (αναπαραγωγή)</string>
<string name="media_state_loading">%1$s (φόρτωση)</string>
<string name="auth_no_net_conn_title">Δεν υπάρχει σύνδεση στο δίκτυο</string>
<string name="auth_nossl_plain_ok_title">Μη διαθέσιμη ασφαλής σύνδεση.</string>
<string name="auth_connection_established">Επετεύχθη σύνδεση</string>
- <string name="auth_testing_connection">Έλεγχος σύνδεσης...</string>
+ <string name="auth_testing_connection">Έλεγχος σύνδεσης</string>
<string name="auth_not_configured_title">Λανθασμένες ρυθμίσεις διακομιστή</string>
<string name="auth_account_not_new">Ένας λογαριασμός για τον ίδιο χρήστη και διακομιστή υπάρχει ήδη στη συσκευή</string>
<string name="auth_account_not_the_same">Ο χρήστης που εισάγατε δεν ταιριάζει με το χρήστη αυτού του λογαριασμού</string>
<string name="auth_fail_get_user_name">Ο διακομιστής σας δεν επιστρέφει το σωστό αναγνωριστικό χρήστη, παρακαλώ επικοινωνήστε με ένα διαχειριστή
⇥</string>
<string name="auth_can_not_auth_against_server">Δεν είναι δυνατή η πιστοποίηση με αυτόν το διακομιστή</string>
+ <string name="auth_account_does_not_exist">Ο λογαριασμός δεν υπάρχει στη συσκευή ακόμα.</string>
<string name="fd_keep_in_sync">Διατήρηση αρχείου σε ενημέρωση</string>
<string name="common_rename">Μετονομασία</string>
<string name="common_remove">Αφαίρεση</string>
<string name="sync_file_nothing_to_do_msg">Τα περιεχόμενα του αρχείου έχουν ήδη συγχρονιστεί</string>
<string name="create_dir_fail_msg">Η δημιουργία φακέλου απέτυχε</string>
<string name="filename_forbidden_characters">Μη-επιτρεπόμενοι χαρακτήρες: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Το όνομα αρχείου περιέχει έναν τουλάχιστον μη έγκυρο χαρακτήρα</string>
<string name="filename_empty">Το όνομα αρχείου δεν μπορεί να είναι κενό.</string>
<string name="wait_a_moment">Παρακαλούμε περιμένετε</string>
<string name="filedisplay_unexpected_bad_get_content">Απροσδόκητο σφάλμα - παρακαλώ επιλέξτε το αρχείο από μια άλλη εφαρμογή</string>
<string name="filedisplay_no_file_selected">Δεν επιλέχθηκαν αρχεία </string>
<string name="activity_chooser_title">Αποστολή συνδέσμου σε ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Αντιγραφή αρχείου από ιδιωτική αποθήκευση</string>
<string name="oauth_check_onoff">Σύνδεση με oAuth2</string>
<string name="oauth_login_connection">Σύνδεση με το διακομιστή oAuth2 σε εξέλιξη...</string>
<string name="ssl_validator_header">Η ταυτότητα της σελίδας δεν μπορεί να επληθευτεί</string>
διαχειριστή σας.</string>
<string name="share_link_file_no_exist">Αδύνατη η κοινή χρήση. Παρακαλώ ελέγξτε αν ο φάκελος υπάρχει</string>
<string name="share_link_file_error">Ένα σφάλμα προέκυψε κατά την προσπάθεια διαμοιρασμού αυτού του αρχείου ή φακέλου</string>
- <string name="unshare_link_file_no_exist">Αδύνατη η διακοπή κοινής χρήσης. Παρακαλώ ελέγξτε αν ο φάκελος υπάρχει</string>
+ <string name="unshare_link_file_no_exist">Αδύνατη η διακοπή κοινής χρήσης. Παρακαλώ ελέγξτε αν το αρχείο υπάρχει</string>
<string name="unshare_link_file_error">Ένα σφάλμα προέκυψε κατά τη διάρκεια ακύρωσης διαμοιρασμού αυτού του αρχείου ή φακέλου</string>
+ <string name="share_link_password_title">Εισάγετε ένα κωδικό πρόσβασης.</string>
+ <string name="share_link_empty_password">Πρέπει να εισάγετε ένα κωδικό πρόσβασης.</string>
<string name="activity_chooser_send_file_title">Αποστολή</string>
<string name="copy_link">Αντιγραφή συνδέσμου</string>
<string name="clipboard_text_copied">Αντιγραφθηκε στο πρόχειρο</string>
<string name="forbidden_permissions_rename">για να μετονομάσετε αυτό το αρχείο</string>
<string name="forbidden_permissions_delete">για να διαγράψετε αυτό το αρχείο</string>
<string name="share_link_forbidden_permissions">για να μοιραστείτε αυτό το αρχείο</string>
- <string name="unshare_link_forbidden_permissions">για να μη μοιÏ\81αÏ\83Ï\84είÏ\84ε αÏ\85Ï\84Ï\8c Ï\84ο αÏ\81Ï\87είο</string>
+ <string name="unshare_link_forbidden_permissions">για να διακÏ\8cÏ\88εÏ\84ε Ï\84ο διαμοιÏ\81αÏ\83μÏ\8c αÏ\85Ï\84οÏ\8d Ï\84οÏ\85 αÏ\81Ï\87είοÏ\85</string>
<string name="forbidden_permissions_create">για να δημιουργήσετε το αρχείο</string>
- <string name="uploader_upload_forbidden_permissions">για να μεταφορτώσετε σε αυτό τον κατάλογο</string>
+ <string name="uploader_upload_forbidden_permissions">για να μεταφορτώσετε σε αυτό το φάκελο</string>
<string name="downloader_download_file_not_found">Αυτό το αρχείο δεν είναι πια διαθέσιμο στο διακομιστή</string>
<string name="prefs_category_accounts">Λογαριασμοί</string>
<string name="prefs_add_account">Προσθήκη λογαριασμού</string>
<string name="auth_redirect_non_secure_connection_title">Ασφαλής σύνδεση ανακατευθύνεται σε μια μη ασφαλή διαδρομή.</string>
<string name="actionbar_logger">Αρχεία καταγραφών</string>
- <string name="log_send_history_button">Αποστολή ιστορικού</string>
- <string name="log_mail_subject">αρχεία καταγραφής της εφαρμογής ownCloud Android</string>
+ <string name="log_send_history_button">Αποστολή Ιστορικού</string>
+ <string name="log_send_no_mail_app">Δεν εντοπίστηκε εφαρμογή αποστολής αναφορών συστήματος. Εγκαταστήστε την εφαρμογή Ηλ. Ταχυδρομείου!!</string>
+ <string name="log_send_mail_subject">%1$s αναφορές της εφαρμογής Android</string>
<string name="log_progress_dialog_text">Φόρτωση δεδομένων....</string>
<string name="saml_authentication_required_text">Απαιτείται πιστοποίηση</string>
- <string name="saml_authentication_wrong_pass">Εσφαλμένο συνθηματικό</string>
+ <string name="saml_authentication_wrong_pass">Εσφαλμένος κωδικός πρόσβασης</string>
<string name="actionbar_move">Μετακίνηση</string>
<string name="file_list_empty_moving">Δεν υπάρχει τίποτα εδώ. Μπορείτε να προσθέσετε ένα φάκελο!</string>
- <string name="move_choose_button_text">Επιλέξτε</string>
- <string name="move_file_not_found">Αδύνατη η μετακίνηση. Παρακαλώ ελέγξτε αν ο φάκελος υπάρχει</string>
+ <string name="folder_picker_choose_button_text">Επιλέξτε</string>
+ <string name="move_file_not_found">Αδύνατη η μετακίνηση. Παρακαλώ ελέγξτε αν το αρχείο υπάρχει</string>
<string name="move_file_invalid_into_descendent">Δεν είναι δυνατό να μετακινηθεί ο φάκελος σε έναν απογονικό</string>
<string name="move_file_invalid_overwrite">Το αρχείο υπάρχει ήδη στο φάκελο προορισμού</string>
<string name="move_file_error">Ένα σφάλμα προέκυψε κατά την προσπάθεια μετακίνησης αυτού του αρχείου ή φακέλου</string>
<string name="forbidden_permissions_move">για μετακίνηση αυτού του αρχείου</string>
<string name="prefs_category_instant_uploading">Στιγμιαίες Μεταφορτώσεις</string>
<string name="prefs_category_security">Ασφάλεια</string>
+ <string name="prefs_instant_video_upload_path_title">Διαδρομή Μεταφόρτωσης Βίντεο</string>
+ <string name="download_folder_failed_content">Η λήψη του φακέλου %1$s δεν ολοκληρώθηκε με επιτυχία.</string>
+ <string name="shared_subject_header">διαμοιρασμένα</string>
+ <string name="with_you_subject_header">με εσάς</string>
+ <string name="subject_token">Ο %1$s διαμοιράστηκε το \"%2$s\" με εσάς</string>
+ <string name="auth_refresh_button">Ανανέωση σύνδεσης</string>
+ <string name="auth_host_address">Διεύθυνση διακομιστή</string>
+ <string name="common_error_out_memory">Δεν υπάρχει αρκετή μνήμη</string>
+ <string name="username">Όνομα χρήστη</string>
+ <string name="file_list__footer__folder">1 φάκελος</string>
+ <string name="file_list__footer__folders">%1$d φάκελοι</string>
+ <string name="file_list__footer__file">1 αρχείο</string>
+ <string name="file_list__footer__file_and_folder">1 αρχείο, 1 φάκελος</string>
+ <string name="file_list__footer__file_and_folders">1 αρχείο, %1$d φάκελοι</string>
+ <string name="file_list__footer__files">%1$d αρχεία</string>
+ <string name="file_list__footer__files_and_folder">%1$d αρχεία, 1 φάκελος</string>
+ <string name="file_list__footer__files_and_folders">%1$d αρχεία, %2$d φάκελοι</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">General</string>
<string name="prefs_category_more">More</string>
<string name="prefs_accounts">Accounts</string>
<string name="prefs_manage_accounts">Manage Accounts</string>
- <string name="prefs_pincode">App PIN</string>
- <string name="prefs_pincode_summary">Protect your client</string>
+ <string name="prefs_passcode">Passcode lock</string>
<string name="prefs_instant_upload">Instant picture uploads</string>
<string name="prefs_instant_upload_summary">Instantly upload pictures taken by camera</string>
<string name="prefs_instant_video_upload">Instant video uploads</string>
<string name="sync_string_files">Files</string>
<string name="setup_btn_connect">Connect</string>
<string name="uploader_btn_upload_text">Upload</string>
+ <string name="uploader_btn_new_folder_text">New folder</string>
<string name="uploader_top_message">Choose upload folder:</string>
<string name="uploader_wrn_no_account_title">No account found</string>
<string name="uploader_wrn_no_account_text">There are no %1$s accounts on your device. Please setup an account first.</string>
<string name="uploader_info_uploading">Uploading</string>
<string name="file_list_seconds_ago">seconds ago</string>
<string name="file_list_empty">Nothing in here. Upload something!</string>
- <string name="file_list_loading">Loading...</string>
<string name="local_file_list_empty">There are no files in this folder.</string>
<string name="filedetails_select_file">Tap on a file to display additional information.</string>
<string name="filedetails_size">Size:</string>
<string name="foreign_files_local_text">Local: %1$s</string>
<string name="foreign_files_remote_text">Remote: %1$s</string>
<string name="upload_query_move_foreign_files">There is not enough space to copy the selected files into the %1$s folder. Would you like to move them instead? </string>
- <string name="pincode_enter_pin_code">Please, insert your App PIN</string>
- <string name="pincode_configure_your_pin">Enter your App PIN</string>
- <string name="pincode_configure_your_pin_explanation">The PIN will be requested every time the app is started</string>
- <string name="pincode_reenter_your_pincode">Please, re-enter your App PIN</string>
- <string name="pincode_remove_your_pincode">Remove your App PIN</string>
- <string name="pincode_mismatch">The App PINs are not the same</string>
- <string name="pincode_wrong">Incorrect App PIN</string>
- <string name="pincode_removed">App PIN removed</string>
- <string name="pincode_stored">App PIN stored</string>
+ <string name="pass_code_enter_pass_code">Please, insert your passcode</string>
+ <string name="pass_code_configure_your_pass_code">Enter your passcode</string>
+ <string name="pass_code_configure_your_pass_code_explanation">The passcode will be requested every time the app is started</string>
+ <string name="pass_code_reenter_your_pass_code">Please, reenter your passcode</string>
+ <string name="pass_code_remove_your_pass_code">Remove your passcode</string>
+ <string name="pass_code_mismatch">The passcodes are not the same</string>
+ <string name="pass_code_wrong">Incorrect passcode</string>
+ <string name="pass_code_removed">Passcode removed</string>
+ <string name="pass_code_stored">Passcode stored</string>
<string name="media_notif_ticker">%1$s music player</string>
<string name="media_state_playing">%1$s (playing)</string>
<string name="media_state_loading">%1$s (loading)</string>
<string name="auth_no_net_conn_title">No network connection</string>
<string name="auth_nossl_plain_ok_title">Secure connection unavailable.</string>
<string name="auth_connection_established">Connection established</string>
- <string name="auth_testing_connection">Testing connection…</string>
+ <string name="auth_testing_connection">Testing connection</string>
<string name="auth_not_configured_title">Malformed server configuration</string>
<string name="auth_account_not_new">An account for the same user and server already exists on the device</string>
<string name="auth_account_not_the_same">The entered user does not match the user of this account</string>
<string name="auth_fail_get_user_name">Your server is not returning a correct user id, please contact an administrator
</string>
<string name="auth_can_not_auth_against_server">Cannot authenticate against this server</string>
+ <string name="auth_account_does_not_exist">Account does not exist in the device yet</string>
<string name="fd_keep_in_sync">Keep file up to date</string>
<string name="common_rename">Rename</string>
<string name="common_remove">Remove</string>
<string name="filedisplay_unexpected_bad_get_content">Unexpected problem; please select the file from a different app</string>
<string name="filedisplay_no_file_selected">No file was selected</string>
<string name="activity_chooser_title">Send link to …</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Copying file from private storage</string>
<string name="oauth_check_onoff">Log in with oAuth2</string>
<string name="oauth_login_connection">Connecting to oAuth2 server…</string>
<string name="ssl_validator_header">The identity of the site could not be verified</string>
<string name="share_link_file_error">An error occurred while trying to share this file or folder</string>
<string name="unshare_link_file_no_exist">Unable to unshare. Please check whether the file exists</string>
<string name="unshare_link_file_error">An error occurred while trying to unshare this file or folder</string>
+ <string name="share_link_password_title">Enter a password</string>
+ <string name="share_link_empty_password">You must enter a password</string>
<string name="activity_chooser_send_file_title">Send</string>
<string name="copy_link">Copy link</string>
<string name="clipboard_text_copied">Copied to clipboard</string>
<string name="auth_redirect_non_secure_connection_title">Secure connection is redirected to an unsecured route.</string>
<string name="actionbar_logger">Logs</string>
<string name="log_send_history_button">Send History</string>
- <string name="log_mail_subject">ownCloud Android app logs</string>
- <string name="log_progress_dialog_text">Loading data...</string>
+ <string name="log_send_no_mail_app">No app for sending logs found. Install mail app!</string>
+ <string name="log_send_mail_subject">%1$s Android app logs</string>
+ <string name="log_progress_dialog_text">Loading data…</string>
<string name="saml_authentication_required_text">Authentication required</string>
<string name="saml_authentication_wrong_pass">Incorrect password</string>
<string name="actionbar_move">Move</string>
<string name="file_list_empty_moving">Nothing in here. You can add a folder!</string>
- <string name="move_choose_button_text">Choose</string>
+ <string name="folder_picker_choose_button_text">Choose</string>
<string name="move_file_not_found">Unable to move. Please check whether the file exists</string>
<string name="move_file_invalid_into_descendent">It is not possible to move a folder into a descendant</string>
<string name="move_file_invalid_overwrite">The file exists already in the destination folder</string>
<string name="forbidden_permissions_move">to move this file</string>
<string name="prefs_category_instant_uploading">Instant Uploads</string>
<string name="prefs_category_security">Security</string>
+ <string name="prefs_instant_video_upload_path_title">Upload Video Path</string>
+ <string name="download_folder_failed_content">Download of %1$s folder could not be completed</string>
+ <string name="auth_refresh_button">Refresh connection</string>
+ <string name="auth_host_address">Server address</string>
+ <string name="common_error_out_memory">Not enough memory</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_send_file">Sendi</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Ĝeneralo</string>
<string name="prefs_category_more">Pli</string>
<string name="prefs_accounts">Kontoj</string>
<string name="prefs_manage_accounts">Administri kontojn</string>
- <string name="prefs_pincode">PIN de App-aplikaĵo</string>
- <string name="prefs_pincode_summary">Protekti vian klienton</string>
<string name="prefs_help">Helpo</string>
<string name="prefs_recommend">Rekomendi al amiko</string>
<string name="auth_check_server">Kontroli servilon</string>
<string name="sync_string_files">Dosieroj</string>
<string name="setup_btn_connect">Konekti</string>
<string name="uploader_btn_upload_text">Alŝuti</string>
+ <string name="uploader_btn_new_folder_text">Nova dosierujo</string>
<string name="uploader_top_message">Elektu alŝutan dosierujon:</string>
<string name="uploader_wrn_no_account_title">Neniu konto troviĝis</string>
<string name="uploader_wrn_no_account_text">Estas neniu $1%s-konto en via aparato. Bonvolu agordi konton unue.</string>
<string name="foreign_files_fail">Iuj dosieroj ne povis moviĝi</string>
<string name="foreign_files_local_text">Loka: %1$s</string>
<string name="foreign_files_remote_text">Malloka: %1$s</string>
- <string name="pincode_enter_pin_code">Bonvolu enigi vian PIN-on de aplikaĵo</string>
- <string name="pincode_configure_your_pin">Enigu PIN-on de aplikaĵo</string>
- <string name="pincode_reenter_your_pincode">Bonvolu reenigi PIN-on de aplikaĵo</string>
- <string name="pincode_remove_your_pincode">Forigu vian PIN-on de aplikaĵo</string>
- <string name="pincode_mismatch">La du PIN-oj de aplikaĵo malsamas</string>
- <string name="pincode_wrong">Malĝusta PIN de aplikaĵo</string>
- <string name="pincode_removed">PIN de aplikaĵo foriĝis</string>
- <string name="pincode_stored">PIN de aplikaĵo konserviĝis</string>
<string name="media_state_playing">%1$s (ludanta)</string>
<string name="media_state_loading">%1$s (ŝarganta)</string>
<string name="auth_getting_authorization">Ekhavante rajtigon...</string>
<string name="auth_no_net_conn_title">Neniu reta konekto</string>
<string name="auth_nossl_plain_ok_title">Sekura konekto ne haveblas.</string>
<string name="auth_connection_established">Konekto stariĝis</string>
- <string name="auth_testing_connection">Testante konekton...</string>
<string name="auth_not_configured_title">Malĝuste formita servilo-agordo</string>
<string name="auth_unknown_error_title">Nekonata eraro okazis</string>
<string name="auth_unknown_host_title">Ne eblis trovi gastigon</string>
<string name="preview_image_description">Antaŭvido de bildo</string>
<string name="preview_image_error_unknown_format">Ĉi tiu bildo ne povas montriĝi</string>
<string name="error__upload__local_file_not_copied">%1$s ne povis kopiiĝi al la loka dosierujo %2$s</string>
+ <string name="share_link_password_title">Enigu pasvorton</string>
+ <string name="share_link_empty_password">Vi devas enigi pasvorton</string>
<string name="activity_chooser_send_file_title">Sendi</string>
<string name="copy_link">Kopii ligilon</string>
<string name="clipboard_text_copied">Kopiita en la tondejon</string>
<string name="prefs_category_accounts">Kontoj</string>
<string name="saml_authentication_required_text">Aŭtentiĝo nepras</string>
<string name="saml_authentication_wrong_pass">Malĝusta pasvorto</string>
- <string name="move_choose_button_text">Elekti</string>
+ <string name="actionbar_move">Movi</string>
+ <string name="folder_picker_choose_button_text">Elekti</string>
+ <string name="move_file_invalid_overwrite">La dosiero jam ekzistas en la cela dosierujo</string>
<string name="prefs_category_security">Sekuro</string>
+ <string name="auth_host_address">Servila adreso</string>
</resources>
<string name="actionbar_settings">Configuración</string>
<string name="actionbar_see_details">Detalles</string>
<string name="actionbar_send_file">Mandar</string>
+ <string name="actionbar_sort">Orden</string>
+ <string name="actionbar_sort_title">Ordenar por</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Nuevos - Viejos</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">General</string>
<string name="prefs_category_more">Más</string>
<string name="prefs_accounts">Cuentas</string>
<string name="prefs_manage_accounts">Gestionar cuentas</string>
- <string name="prefs_pincode">PIN de aplicación</string>
- <string name="prefs_pincode_summary">Protejé tu cliente</string>
<string name="prefs_instant_upload">Subir fotos instantáneamente. </string>
<string name="prefs_instant_upload_summary">Subir instantáneamente fotos tomadas por la cámara.</string>
<string name="prefs_instant_video_upload">Subir videos instantáneamente. </string>
<string name="prefs_recommend">Recomendar a un amigo</string>
<string name="prefs_feedback">Sugerencias</string>
<string name="prefs_imprint">Imprint</string>
+ <string name="prefs_remember_last_share_location">Recordar compartir ubicación </string>
+ <string name="prefs_remember_last_upload_location_summary">Recordar la ultima ubicación compartida de subida</string>
<string name="recommend_subject">¡Intento %1$s en tu teléfono inteligente!</string>
+ <string name="recommend_text">Quiero invitarte a usar %1$s en tu teléfono inteligente!\nDescárgalo aquí: %2$s</string>
<string name="auth_check_server">Verificar Servidor</string>
<string name="auth_host_url">Dirección del servidor https://...</string>
<string name="auth_username">Nombre de usuario</string>
<string name="sync_string_files">Archivos</string>
<string name="setup_btn_connect">Conectar</string>
<string name="uploader_btn_upload_text">Subir</string>
+ <string name="uploader_btn_new_folder_text">Nueva Carpeta</string>
<string name="uploader_top_message">Elija la carpeta de subida:</string>
<string name="uploader_wrn_no_account_title">No se encontraron cuentas</string>
<string name="uploader_wrn_no_account_text">No hay cuentas de %1$s en tu dispositivo. Creá una cuenta primero.</string>
<string name="uploader_info_uploading">Subiendo</string>
<string name="file_list_seconds_ago">segundos atrás</string>
<string name="file_list_empty">No hay nada. ¡Subí contenido!</string>
- <string name="file_list_loading">Cargando...</string>
<string name="local_file_list_empty">No existen archivos en esta carpeta.</string>
<string name="filedetails_select_file">Pulsá sobre un archivo para mostrar información adicional.</string>
<string name="filedetails_size">Tamaño:</string>
<string name="foreign_files_local_text">Local: %1$s</string>
<string name="foreign_files_remote_text">Remote: %1$s</string>
<string name="upload_query_move_foreign_files">No hay espacio suficiente para copiar los archivos seleccionados dentro de la carpeta %1$s. ¿Te gustaría en su lugar moverlos?</string>
- <string name="pincode_enter_pin_code">Por favor, escribí el PIN de la aplicación</string>
- <string name="pincode_configure_your_pin">Ingresá el PIN de la aplicación</string>
- <string name="pincode_configure_your_pin_explanation">Se te pedirá el PIN cada vez que esta app sea iniciada.</string>
- <string name="pincode_reenter_your_pincode">Por favor, ingresá nuevamente el PIN de la aplicación</string>
- <string name="pincode_remove_your_pincode">Borrar tu PIN de la aplicación</string>
- <string name="pincode_mismatch">Los PIN no son iguales</string>
- <string name="pincode_wrong">El PIN de la aplicación es incorrecto</string>
- <string name="pincode_removed">El PIN de la aplicación fue borrado</string>
- <string name="pincode_stored">El PIN de la aplicación fue almacenado</string>
<string name="media_notif_ticker">Reproductor de música %1$s</string>
<string name="media_state_playing">%1$s (reproduciendo)</string>
<string name="media_state_loading">%1$s (cargando)</string>
<string name="auth_no_net_conn_title">Sin conexión de red</string>
<string name="auth_nossl_plain_ok_title">Conexión segura no disponible.</string>
<string name="auth_connection_established">Conexión establecida</string>
- <string name="auth_testing_connection">Probando conexión...</string>
<string name="auth_not_configured_title">Configuración de servidor en formato incorrecto</string>
<string name="auth_account_not_new">Una cuenta para el mismo usuario y servidor ya existe en el dispositivo</string>
<string name="auth_account_not_the_same">El usuario ingresado no concuerda con el usuario de esta cuenta</string>
<string name="conflict_dont_upload">No subir</string>
<string name="preview_image_description">Previsualización de imagen</string>
<string name="preview_image_error_unknown_format">Esta imagen no puede ser mostrada</string>
+ <string name="error__upload__local_file_not_copied">%1$s no pudo ser copiado a la carpeta local %2$s </string>
+ <string name="prefs_instant_upload_path_title">Dirección de subida</string>
+ <string name="share_link_no_support_share_api">Lo sentimos, compartir no esta activado en su servidor. Por favor contacte a su
+⇥⇥administrator.</string>
+ <string name="share_link_file_no_exist">Imposible compartir. Por favor revise si el archivo existe</string>
+ <string name="share_link_file_error">Un error ocurrió cuando se intentaba compartir el archivo o carpeta</string>
+ <string name="unshare_link_file_no_exist">Imposible dejar de compartir. Por favor revise si los archivos existen</string>
+ <string name="unshare_link_file_error">Un error ocurrió cuando se intentaba dejar de compartir el archivo o carpeta</string>
<string name="activity_chooser_send_file_title">Mandar</string>
+ <string name="copy_link">Copiar dirección url</string>
<string name="clipboard_text_copied">Copiado al portapapeles</string>
+ <string name="error_cant_bind_to_operations_service">Error critico: no se puede realizar operaciones</string>
+ <string name="network_error_socket_exception">Un error ocurrió mientras se conectaba con el Servidor.</string>
+ <string name="network_error_socket_timeout_exception">Un error ocurrió mientras se conectaba con el Servidor. La operación no se realizó </string>
+ <string name="network_error_connect_timeout_exception">Un error ocurrió esperando al Servidor, la operación no se realizó</string>
+ <string name="network_host_not_available">Operación no completada, Servidor no disponible.</string>
<string name="empty"></string>
+ <string name="forbidden_permissions">Tu no tienes permiso %s</string>
+ <string name="forbidden_permissions_rename">para renombrar este archivo</string>
+ <string name="forbidden_permissions_delete">para borrar este archivo</string>
+ <string name="share_link_forbidden_permissions">para compartir este archivo</string>
+ <string name="unshare_link_forbidden_permissions">para dejar de compartir este archivo</string>
+ <string name="forbidden_permissions_create">para crear el archivo</string>
+ <string name="uploader_upload_forbidden_permissions">para subir en esta carpeta</string>
+ <string name="downloader_download_file_not_found">El archivo no esta mas disponible en este Servidor</string>
<string name="prefs_category_accounts">Cuentas</string>
+ <string name="prefs_add_account">Añadir cuenta</string>
+ <string name="auth_redirect_non_secure_connection_title">Conexión segura redireccionada a una ruta insegura.</string>
+ <string name="actionbar_logger">Registro</string>
+ <string name="log_send_history_button">Enviar Historial</string>
+ <string name="log_send_no_mail_app">Aplicación para enviar registros no encontrada. Instale una aplicación de correo!</string>
+ <string name="log_send_mail_subject">%1$s Registros de la aplicación Android</string>
+ <string name="log_progress_dialog_text">Cargando datos...</string>
<string name="saml_authentication_required_text">Autentificación requerida</string>
<string name="saml_authentication_wrong_pass">Clave incorrecta</string>
- <string name="move_choose_button_text">Elegir</string>
+ <string name="actionbar_move">Mover</string>
+ <string name="file_list_empty_moving">Nada aquí. Puedes agregar una carpeta!</string>
+ <string name="folder_picker_choose_button_text">Elegir</string>
+ <string name="move_file_not_found">Imposible mover. Por favor revisa si el archivo existe</string>
+ <string name="move_file_invalid_overwrite">El archivo ya existe en la carpeta destino</string>
+ <string name="move_file_error">Un error ocurrió intentando mover el archivo o carpeta</string>
+ <string name="forbidden_permissions_move">para mover este archivo</string>
+ <string name="prefs_category_instant_uploading">Subida Instantánea </string>
<string name="prefs_category_security">Seguridad</string>
+ <string name="prefs_instant_video_upload_path_title">Dirección de subida del video</string>
+ <string name="download_folder_failed_content">La descarga de la carpeta %1$s no pudo ser completada</string>
+ <string name="auth_host_address">Dirección del servidor</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_see_details">detalles</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">General</string>
<string name="prefs_accounts">Cuentas</string>
<string name="prefs_manage_accounts">Administrar Cuentas</string>
- <string name="prefs_pincode">PIN de la aplicación</string>
- <string name="prefs_pincode_summary">Proteger su cliente</string>
<string name="prefs_instant_upload">Subida instantánea de imagenes</string>
<string name="prefs_instant_upload_summary">Subida instantánea de imágenes tomadas con la cámara</string>
<string name="prefs_help">Ayuda</string>
<string name="sync_string_files">Archivos</string>
<string name="setup_btn_connect">Conectar</string>
<string name="uploader_btn_upload_text">Subir</string>
+ <string name="uploader_btn_new_folder_text">Nuevo directorio</string>
<string name="uploader_top_message">Elija el directorio donde subir los archivos:</string>
<string name="uploader_wrn_no_account_title">No se encuentra la cuenta</string>
<string name="uploader_wrn_no_account_text">No existe la cuenta %1$s en su dispositivo. Por favor configure una cuenta primero.</string>
<string name="foreign_files_fail">algunos archivos no pueden ser transferidos</string>
<string name="foreign_files_local_text">Local: %1$s</string>
<string name="foreign_files_remote_text">Remoto: %1$s</string>
- <string name="pincode_enter_pin_code">Por favor, ingreses su PIN de aplicación</string>
- <string name="pincode_configure_your_pin">Ingrese su PIN de aplicación</string>
- <string name="pincode_configure_your_pin_explanation">El PIN será solicitado cada vez que la aplicación se inicie</string>
- <string name="pincode_reenter_your_pincode">Por favor, reingrese su PIN de aplicación</string>
- <string name="pincode_remove_your_pincode">Remover el PIN de su aplicación</string>
- <string name="pincode_mismatch">Los PINs de su aplicación no coinciden</string>
- <string name="pincode_wrong">PIN de aplicación incorrecto</string>
- <string name="pincode_removed">PIN de aplicación removido</string>
- <string name="pincode_stored">PIN de aplicación almacenada</string>
<string name="media_notif_ticker">Reproductor de música %1$s</string>
<string name="media_state_playing">(sonando) %1$s</string>
<string name="media_state_loading">(cargando) %1$s</string>
<string name="auth_no_net_conn_title">Sin conexión de red</string>
<string name="auth_nossl_plain_ok_title">Conexión segura no disponible.</string>
<string name="auth_connection_established">Conexión establecida</string>
- <string name="auth_testing_connection">Probando conexión...</string>
<string name="auth_not_configured_title">La configuración del servidor está mal formada</string>
<string name="auth_unknown_error_title">Ocurrió un error desconocido</string>
<string name="auth_unknown_host_title">No se puede encontrar el host</string>
<string name="error__upload__local_file_not_copied">%1$s no pudo ser copiado a la carpeta local %2$s</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Cuentas</string>
- <string name="move_choose_button_text">Choose</string>
+ <string name="folder_picker_choose_button_text">Choose</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="actionbar_upload_files">Archivos</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="sync_string_files">Archivos</string>
<string name="empty"></string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_send_file">Enviar</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">General</string>
<string name="prefs_category_more">Más</string>
<string name="prefs_accounts">Cuentas</string>
<string name="prefs_manage_accounts">Gestionar cuentas</string>
- <string name="prefs_pincode">PIN de aplicación </string>
- <string name="prefs_pincode_summary">Proteja su cliente</string>
<string name="prefs_log_title">Habilitar registro</string>
<string name="prefs_log_summary">Esto es usado para registrar problemas</string>
<string name="prefs_log_title_history">Historia del Registro</string>
<string name="sync_string_files">Archivos</string>
<string name="setup_btn_connect">Conectar</string>
<string name="uploader_btn_upload_text">Subir</string>
+ <string name="uploader_btn_new_folder_text">Nueva carpeta</string>
<string name="uploader_wrn_no_account_title">No se encontraron cuentas</string>
<string name="uploader_wrn_no_account_text">No hay cuentas de %1$s en tu dispositivo. Por favor configura una cuenta primero.</string>
<string name="uploader_wrn_no_account_setup_btn_text">Configuración</string>
<string name="foreign_files_fail">Algunos archivos no han podido ser movidos</string>
<string name="foreign_files_local_text">Local: %1$s</string>
<string name="foreign_files_remote_text">Remoto: %1$s</string>
- <string name="pincode_enter_pin_code">Por favor, inserta tu PIN de aplicación</string>
- <string name="pincode_configure_your_pin">Introduzca un PIN para la aplicación</string>
- <string name="pincode_configure_your_pin_explanation">Se solicitará el PIN cada vez que se inicie la aplicación</string>
- <string name="pincode_reenter_your_pincode">Repita el PIN para la aplicación, por favor</string>
- <string name="pincode_remove_your_pincode">Borre su PIN de aplicación</string>
- <string name="pincode_mismatch">Los PIN introducidos no son iguales</string>
- <string name="pincode_wrong">PIN de aplicación incorrecto</string>
- <string name="pincode_removed">PIN de aplicación borrado</string>
- <string name="pincode_stored">PIN de aplicación guardado</string>
<string name="media_notif_ticker">Reproductor de música %1$s</string>
<string name="media_state_playing">%1$s (reproduciendo)</string>
<string name="media_state_loading">%1$s (cargando)</string>
<string name="auth_no_net_conn_title">Sin conexión de red</string>
<string name="auth_nossl_plain_ok_title">Conexión segura no disponible.</string>
<string name="auth_connection_established">Conexión establecida</string>
- <string name="auth_testing_connection">Probando conexión...</string>
<string name="auth_not_configured_title">Configuración de servidor en formato incorrecto</string>
<string name="auth_account_not_new">Una cuenta para el mismo usuario y servidor ya existen en el dispositivo</string>
<string name="auth_account_not_the_same">El usuario introducido no concuerda con el usuario de esta cuenta</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Cuentas</string>
<string name="saml_authentication_wrong_pass">Contraseña incorrecta</string>
- <string name="move_choose_button_text">Seleccionar</string>
+ <string name="folder_picker_choose_button_text">Seleccionar</string>
<string name="prefs_category_security">Seguridad</string>
+ <string name="auth_host_address">Dirección del servidor</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_upload_files">Archivos</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="sync_string_files">Archivos</string>
<string name="empty"></string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_upload_from_apps">Contenido de otras aplicaciones</string>
<string name="actionbar_upload_files">Archivos</string>
<string name="actionbar_open_with">Abrir con</string>
- <string name="actionbar_mkdir">Nueva Carpeta</string>
+ <string name="actionbar_mkdir">Nueva carpeta</string>
<string name="actionbar_settings">Configuración</string>
<string name="actionbar_see_details">Detalles</string>
<string name="actionbar_send_file">Enviar</string>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Todos los archivos</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Ajustes</string>
+ <string name="drawer_item_logs">Registros</string>
+ <string name="drawer_close">Cerrar</string>
<string name="prefs_category_general">General</string>
<string name="prefs_category_more">Más</string>
<string name="prefs_accounts">Cuentas</string>
<string name="prefs_manage_accounts">Gestionar cuentas</string>
- <string name="prefs_pincode">PIN de aplicación </string>
- <string name="prefs_pincode_summary">Proteja su cliente</string>
+ <string name="prefs_passcode">Contraseña</string>
<string name="prefs_instant_upload">Subida instantánea de imágenes</string>
<string name="prefs_instant_upload_summary">Sube instantáneamente las fotos tomadas con la cámara</string>
<string name="prefs_instant_video_upload">Subidas instantáneas de video</string>
<string name="prefs_imprint">pie de imprenta</string>
<string name="prefs_remember_last_share_location">Recordar la ubicación de los archivos compartidos</string>
<string name="prefs_remember_last_upload_location_summary">Recordar la ubicación de los últimos archivos compartidos subidos</string>
- <string name="recommend_subject">Prueba %1$s en tu smarthphone!</string>
+ <string name="recommend_subject">¡Prueba %1$s en su smarthphone!</string>
<string name="recommend_text">¡Quiero invitarle a usar %1$s en su smartphone!\nDescárguelo aquí: %2$s</string>
<string name="auth_check_server">Compruebe el servidor.</string>
<string name="auth_host_url">Dirección del servidor https://…</string>
<string name="auth_username">Nombre de usuario</string>
<string name="auth_password">Contraseña</string>
- <string name="auth_register">Nuevo para %1$s?</string>
+ <string name="auth_register">¿Nuevo en %1$s?</string>
<string name="sync_string_files">Archivos</string>
<string name="setup_btn_connect">Conectar</string>
<string name="uploader_btn_upload_text">Subir</string>
+ <string name="uploader_btn_new_folder_text">Nueva carpeta</string>
<string name="uploader_top_message">Escoger carpeta de carga:</string>
<string name="uploader_wrn_no_account_title">No se encontró la cuenta</string>
- <string name="uploader_wrn_no_account_text">No hay cuentas de %1$s en tu dispositivo. Por favor configura una cuenta primero.</string>
+ <string name="uploader_wrn_no_account_text">No hay cuentas de %1$s en su dispositivo. Por favor, configure una cuenta primero.</string>
<string name="uploader_wrn_no_account_setup_btn_text">Configuración</string>
<string name="uploader_wrn_no_account_quit_btn_text">Salir</string>
<string name="uploader_wrn_no_content_title">No hay contenido para subir</string>
<string name="filedetails_download">Descargar</string>
<string name="filedetails_sync_file">Actualizar archivo</string>
<string name="filedetails_renamed_in_upload_msg">El fichero fue renombrado como %1$s durante la subida</string>
+ <string name="list_layout">Diseño de lista</string>
<string name="action_share_file">Compartir con enlace</string>
<string name="action_unshare_file">Dejar de compartir</string>
<string name="common_yes">Sí</string>
<string name="common_cancel">Cancelar</string>
<string name="common_save_exit">Guardar & Salir</string>
<string name="common_error">Error</string>
- <string name="common_loading">Cargando ...</string>
+ <string name="common_loading">Cargando...</string>
<string name="common_error_unknown">Error desconocido</string>
<string name="about_title">Acerca de</string>
<string name="change_password">Cambiar contraseña</string>
<string name="uploader_upload_failed_ticker">Error en la subida</string>
<string name="uploader_upload_failed_content_single">La subida de %1$s no se pudo completar</string>
<string name="uploader_upload_failed_credentials_error">La carga falló, necesita volver a iniciar sesión</string>
- <string name="downloader_download_in_progress_ticker">Descargando ...</string>
+ <string name="downloader_download_in_progress_ticker">Descargando...</string>
<string name="downloader_download_in_progress_content">%1$d%% Descargado de %2$s</string>
<string name="downloader_download_succeeded_ticker">Descarga completa</string>
<string name="downloader_download_succeeded_content">%1$s se ha descargado con éxito</string>
<string name="downloader_download_failed_content">La descarga de %1$s no se pudo completar</string>
<string name="downloader_not_downloaded_yet">No descargado</string>
<string name="downloader_download_failed_credentials_error">Descarga fallida, necesita reinicar la sesión</string>
- <string name="common_choose_account">Elige una cuenta</string>
+ <string name="common_choose_account">Elija una cuenta</string>
<string name="sync_fail_ticker">Falló la sincronización</string>
<string name="sync_fail_ticker_unauthorized">La sincronización falló, debe reiniciar la sesión</string>
<string name="sync_fail_content">La sincronización de %1$s s no se pudo completar</string>
<string name="foreign_files_local_text">Local: %1$s</string>
<string name="foreign_files_remote_text">Remoto: %1$s</string>
<string name="upload_query_move_foreign_files">No hay suficiente espacio para copiar los archivos seleccionados a la carpeta %1$s. ¿Desea moverlos en vez de copiarlos?</string>
- <string name="pincode_enter_pin_code">Por favor, inserta tu PIN de aplicación</string>
- <string name="pincode_configure_your_pin">Introduzca un PIN para la aplicación</string>
- <string name="pincode_configure_your_pin_explanation">Se solicitará el PIN cada vez que se inicie la aplicación</string>
- <string name="pincode_reenter_your_pincode">Repita el PIN para la aplicación, por favor</string>
- <string name="pincode_remove_your_pincode">Borre su PIN de aplicación</string>
- <string name="pincode_mismatch">Los PIN introducidos no son iguales</string>
- <string name="pincode_wrong">PIN de aplicación incorrecto</string>
- <string name="pincode_removed">PIN de aplicación borrado</string>
- <string name="pincode_stored">PIN de aplicación guardado</string>
+ <string name="pass_code_enter_pass_code">Por favor, introduzca su contraseña</string>
+ <string name="pass_code_configure_your_pass_code">Introduzca su contraseña</string>
+ <string name="pass_code_configure_your_pass_code_explanation">La contraseña será requerida cada vez que la aplicación sea iniciada</string>
+ <string name="pass_code_reenter_your_pass_code">Reintroduzca la contraseña, por favor.</string>
+ <string name="pass_code_remove_your_pass_code">Borre su contraseña</string>
+ <string name="pass_code_mismatch">Las contraseñas no son identicas</string>
+ <string name="pass_code_wrong">Contraseña incorrecta</string>
+ <string name="pass_code_removed">Contraseña borrada</string>
+ <string name="pass_code_stored">Contraseña almacenada</string>
<string name="media_notif_ticker">Reproductor de música %1$s</string>
<string name="media_state_playing">%1$s (reproduciendo)</string>
<string name="media_state_loading">%1$s (cargando)</string>
<string name="media_event_done">%1$s reproducción finalizada</string>
<string name="media_err_nothing_to_play">No se encontró el archivo multimedia</string>
<string name="media_err_no_account">No se ha proporcionado cuenta</string>
- <string name="media_err_not_in_owncloud">El archivo no esta en una cuenta valida </string>
- <string name="media_err_unsupported">Codec No Soportado</string>
+ <string name="media_err_not_in_owncloud">El archivo no está en una cuenta válida </string>
+ <string name="media_err_unsupported">Codec no soportado</string>
<string name="media_err_io">El archivo de medios no pudo ser leído </string>
<string name="media_err_malformed">Archivo no codificado correctamente</string>
<string name="media_err_timeout">Tiempo de espera agotado en el intento de reproducción</string>
<string name="media_err_unknown">El archivo de medios no se puede reproducir con el reproductor de medios por defecto </string>
<string name="media_err_security_ex">Error de seguridad al intentar reproducir %1$s</string>
<string name="media_err_io_ex">Error de entrada al intentar reproducir %1$s</string>
- <string name="media_err_unexpected">Error inesperado intentando reproducir %1$s</string>
- <string name="media_rewind_description">Botón Rebobinado</string>
+ <string name="media_err_unexpected">Error inesperado al intentar reproducir %1$s</string>
+ <string name="media_rewind_description">Botón de rebobinado</string>
<string name="media_play_pause_description">Botón de reproducción o pausa </string>
<string name="media_forward_description">Botón avance rápido</string>
<string name="auth_getting_authorization">Consiguiendo autorización...</string>
<string name="auth_no_net_conn_title">Sin conexión de red</string>
<string name="auth_nossl_plain_ok_title">Conexión segura no disponible.</string>
<string name="auth_connection_established">Conexión establecida</string>
- <string name="auth_testing_connection">Probando conexión...</string>
+ <string name="auth_testing_connection">Comprobando la conexión</string>
<string name="auth_not_configured_title">Configuración de servidor en formato incorrecto</string>
<string name="auth_account_not_new">Ya existe una cuenta en este dispositivo con los mismos datos de Usuario y Servidor</string>
<string name="auth_account_not_the_same">El usuario introducido no concuerda con el usuario de esta cuenta</string>
<string name="auth_bad_oc_version_title">No se reconoce la versión del servidor </string>
<string name="auth_wrong_connection_title">No se ha podido establecer la conexión</string>
<string name="auth_secure_connection">Conexión segura establecida</string>
- <string name="auth_unauthorized">Nombre de usuario o contraseña incorrecta</string>
+ <string name="auth_unauthorized">Nombre de usuario o contraseña incorrectos</string>
<string name="auth_oauth_error">Autorización no satisfactoria</string>
<string name="auth_oauth_error_access_denied">Acceso denegado por servidor de autorización</string>
<string name="auth_wtf_reenter_URL">Estado inesperado; por favor, introduzca la URL del servidor de nuevo</string>
<string name="auth_fail_get_user_name">Su servidor no está retornando una identificación de usuario correcta; contacte a un administrador
</string>
<string name="auth_can_not_auth_against_server">No puede autenticarse en este servidor.</string>
+ <string name="auth_account_does_not_exist">Aún no existe la cuenta en el dispositivo</string>
<string name="fd_keep_in_sync">Mantener el archivo actualizado</string>
<string name="common_rename">Renombrar</string>
<string name="common_remove">Borrar</string>
<string name="sync_file_nothing_to_do_msg">Ya está sincronizado</string>
<string name="create_dir_fail_msg">No se pudo crear la carpeta</string>
<string name="filename_forbidden_characters">Carácteres ilegales: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Nombre de archivo contiene al menos un caracter no válido</string>
<string name="filename_empty">El nombre de archivo no puede estar vacío</string>
<string name="wait_a_moment">Espere un momento</string>
- <string name="filedisplay_unexpected_bad_get_content">Problema inesperado; por favor, prueba otra app para seleccionar el archivo</string>
+ <string name="filedisplay_unexpected_bad_get_content">Problema inesperado; por favor, pruebe otra app para seleccionar el archivo</string>
<string name="filedisplay_no_file_selected">No hay ficheros seleccionados.</string>
<string name="activity_chooser_title">Enviar enlace a...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Copiando el archivo desde el almacenamiento privado.</string>
<string name="oauth_check_onoff">Ingresar con oAuth2</string>
<string name="oauth_login_connection">Conectando al servidor oAuth2...</string>
<string name="ssl_validator_header">La identidad del sitio no puede ser verificada</string>
<string name="ssl_validator_reason_cert_not_trusted">- El certificado del servidor no es de confianza</string>
<string name="ssl_validator_reason_cert_expired">- El certificado del servidor expiró</string>
- <string name="ssl_validator_reason_cert_not_yet_valid">- El certificado del servidor es de una fecha que aún no llega</string>
+ <string name="ssl_validator_reason_cert_not_yet_valid">- El certificado del servidor es de una fecha que aún no ha llegado</string>
<string name="ssl_validator_reason_hostname_not_verified">- La URL no coincide con el nombre de dominio del certificado</string>
- <string name="ssl_validator_question">¿Confías de todas formas en este certificado?</string>
+ <string name="ssl_validator_question">¿Confía de todas formas en este certificado?</string>
<string name="ssl_validator_not_saved">El certificado no pudo ser guardado</string>
<string name="ssl_validator_btn_details_see">Detalles</string>
<string name="ssl_validator_btn_details_hide">Ocultar</string>
<string name="share_link_file_error">Ocurrió un error al tratar de compartir este archivo o carpeta</string>
<string name="unshare_link_file_no_exist">No se puede dejar de compartir. Revise si el archivo existe</string>
<string name="unshare_link_file_error">Ocurrió un error al tratar de ya no compartir este archivo o carpeta</string>
+ <string name="share_link_password_title">Introduzca una contraseña</string>
+ <string name="share_link_empty_password">Debe introducir una contraseña</string>
<string name="activity_chooser_send_file_title">Enviar</string>
<string name="copy_link">Copiar enlace</string>
<string name="clipboard_text_copied">Copiado al portapapeles</string>
<string name="prefs_category_accounts">Cuentas</string>
<string name="prefs_add_account">Agregar cuenta</string>
<string name="auth_redirect_non_secure_connection_title">La conexión segura está siendo desviada por una ruta insegura.</string>
- <string name="actionbar_logger">Logs</string>
+ <string name="actionbar_logger">Registros</string>
<string name="log_send_history_button">Enviar historial</string>
- <string name="log_mail_subject">Logs de las apps ownCloud Android</string>
+ <string name="log_send_no_mail_app">No se ha encontrado una app para enviar logs. Instale la app mail!</string>
+ <string name="log_send_mail_subject">Se han encontrado %1$s logs de la app Android</string>
<string name="log_progress_dialog_text">Cargando datos...</string>
<string name="saml_authentication_required_text">Se necesita autenticación</string>
<string name="saml_authentication_wrong_pass">Contraseña incorrecta</string>
<string name="actionbar_move">Mover</string>
<string name="file_list_empty_moving">Aquí no hay nada. ¡Puede agregar una carpeta!</string>
- <string name="move_choose_button_text">Seleccionar</string>
+ <string name="folder_picker_choose_button_text">Elegir</string>
<string name="move_file_not_found">No se puede mover. Revise si el archivo existe</string>
- <string name="move_file_invalid_into_descendent">No se puede mover una carpeta dentro de una de SUS subcarpetas.</string>
+ <string name="move_file_invalid_into_descendent">No se puede mover una carpeta dentro de una de sus subcarpetas.</string>
<string name="move_file_invalid_overwrite">El archivo ya existe en la carpeta de destino</string>
<string name="move_file_error">Hubo un error al tratar de mover este archivo o carpeta</string>
<string name="forbidden_permissions_move">para mover este archivo</string>
<string name="prefs_category_instant_uploading">Subidas instantáneas</string>
<string name="prefs_category_security">Seguridad</string>
+ <string name="prefs_instant_video_upload_path_title">Guardar videos subidos en la carpeta:</string>
+ <string name="download_folder_failed_content">La descarga de la carpeta %1$s no ha podido ser completada</string>
+ <string name="shared_subject_header">compartido</string>
+ <string name="with_you_subject_header">con usted</string>
+ <string name="subject_token">%1$s compartió \"%2$s\" conmigo</string>
+ <string name="auth_refresh_button">Refrescar la conexión</string>
+ <string name="auth_host_address">Dirección del servidor</string>
+ <string name="common_error_out_memory">No hay suficiente memoria</string>
+ <string name="username">Nombre de usuario</string>
+ <string name="file_list__footer__folder">1 carpeta</string>
+ <string name="file_list__footer__folders">%1$d carpetas</string>
+ <string name="file_list__footer__file">1 archivo</string>
+ <string name="file_list__footer__file_and_folder">1 archivo, 1 carpeta</string>
+ <string name="file_list__footer__file_and_folders">1 archivo %1$d carpetas</string>
+ <string name="file_list__footer__files">%1$d archivos</string>
+ <string name="file_list__footer__files_and_folder">%1$d archivos, 1 carpeta</string>
+ <string name="file_list__footer__files_and_folders">%1$d archivos, %2$d carpetas</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Kõik failid</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Seaded</string>
+ <string name="drawer_item_logs">Logid</string>
+ <string name="drawer_close">Sulge</string>
<string name="prefs_category_general">Üldine</string>
<string name="prefs_category_more">Rohkem</string>
<string name="prefs_accounts">Kontod</string>
<string name="prefs_manage_accounts">Halda kontosid</string>
- <string name="prefs_pincode">Rakenduse PIN</string>
- <string name="prefs_pincode_summary">Kaitse oma klienti</string>
+ <string name="prefs_passcode">Parooli lukk</string>
<string name="prefs_instant_upload">Piltide kohene üleslaadimine</string>
<string name="prefs_instant_upload_summary">Laadi koheselt üles kaameraga tehtud pildid</string>
<string name="prefs_instant_video_upload">Videote kohene üleslaadimine</string>
<string name="sync_string_files">Failid</string>
<string name="setup_btn_connect">Ühenda</string>
<string name="uploader_btn_upload_text">Lae üles</string>
+ <string name="uploader_btn_new_folder_text">Uus kaust</string>
<string name="uploader_top_message">Vali kataloog serveris: </string>
<string name="uploader_wrn_no_account_title">Kontot ei leitud</string>
<string name="uploader_wrn_no_account_text">Selles seadmes pole ühtegi %1$si kontot. Palun seadista esmalt konto.</string>
<string name="uploader_info_uploading">Üleslaadimine</string>
<string name="file_list_seconds_ago">sekundit tagasi</string>
<string name="file_list_empty">Siin pole midagi. Lae midagi üles!</string>
- <string name="file_list_loading">Laen ...</string>
<string name="local_file_list_empty">Kaustas pole faile.</string>
<string name="filedetails_select_file">Lisainfo vaatamiseks vajuta failile.</string>
<string name="filedetails_size">Suurus:</string>
<string name="filedetails_download">Lae alla</string>
<string name="filedetails_sync_file">Värskenda faili</string>
<string name="filedetails_renamed_in_upload_msg">Fail nimetati üleslaadimise käigus ümber %1$ </string>
+ <string name="list_layout">Nimekirja paigutus</string>
<string name="action_share_file">Jaga linki</string>
<string name="action_unshare_file">Tühista lingi jagamine</string>
<string name="common_yes">Jah</string>
<string name="foreign_files_local_text">Kohalik: %1$s</string>
<string name="foreign_files_remote_text">Serveris: %1$s</string>
<string name="upload_query_move_foreign_files">Pole piisavalt ruumi kopeerimaks valitud faile kataloogi %1$s. Kas soovid kopeerimise asemel neid ümber tõsta?</string>
- <string name="pincode_enter_pin_code">Palun sisesta oma rakenduse PIN</string>
- <string name="pincode_configure_your_pin">Sisesta oma rakenduse PIN</string>
- <string name="pincode_configure_your_pin_explanation">PIN-i nõutakse iga kord, kui rakendus käivitatakse</string>
- <string name="pincode_reenter_your_pincode">Palun sisesta oma rakenduse PIN uuesti</string>
- <string name="pincode_remove_your_pincode">Eemalda oma rakenduse PIN</string>
- <string name="pincode_mismatch">Mõlemad rakenduse PIN-id pole samad</string>
- <string name="pincode_wrong">Vigane rakenduse PIN</string>
- <string name="pincode_removed">Rakenduse PIN on eemaldatud</string>
- <string name="pincode_stored">Rakenduse PIN on salvestatud</string>
+ <string name="pass_code_enter_pass_code">Palun sisestaoma parool</string>
+ <string name="pass_code_configure_your_pass_code">Sisesta oma parool</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Parooli küsitakse iga kord, kui sa selle rakenduse käivitad</string>
+ <string name="pass_code_reenter_your_pass_code">Palun sisesta oma parool uuesti</string>
+ <string name="pass_code_remove_your_pass_code">Eemalda oma parool</string>
+ <string name="pass_code_mismatch">Paroolid pole samad</string>
+ <string name="pass_code_wrong">Vale parool</string>
+ <string name="pass_code_removed">Parool on eemaldatud</string>
+ <string name="pass_code_stored">Parool on salvestatud</string>
<string name="media_notif_ticker">%1$s muusika mängija</string>
<string name="media_state_playing">%1$s (mängib)</string>
<string name="media_state_loading">%1$s (laeb)</string>
<string name="auth_no_net_conn_title">Võrguühendust pole</string>
<string name="auth_nossl_plain_ok_title">Turvaline ühendus pole saadaval</string>
<string name="auth_connection_established">Saadi ühendus</string>
- <string name="auth_testing_connection">Ühenduse testimine...</string>
+ <string name="auth_testing_connection">Ühenduse testimine</string>
<string name="auth_not_configured_title">Vigases vormingus server seadistus</string>
<string name="auth_account_not_new">Sama konto kasutaja ja server on juba selles seadmes olemas</string>
<string name="auth_account_not_the_same">Sisestatud kasutaja ei kattu selle konto kasutajaga</string>
<string name="auth_fail_get_user_name">Server ei tagasta korrektset kasutaja ID-d. Palun kontakteeru administraatoriga.
⇥</string>
<string name="auth_can_not_auth_against_server">Ei suuda autoriseerida selle serveriga.</string>
+ <string name="auth_account_does_not_exist">Kontot pole veel seadmes</string>
<string name="fd_keep_in_sync">Hoia faili ajakohasena</string>
<string name="common_rename">Nimeta ümber</string>
<string name="common_remove">Eemalda</string>
<string name="sync_file_nothing_to_do_msg">Faili sisu on juba sünkroniseeritud</string>
<string name="create_dir_fail_msg">Kataloogi ei saa tekitada</string>
<string name="filename_forbidden_characters">Keelatud sümbolid: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Faili nimesonvähemalt üks keelatud märk</string>
<string name="filename_empty">Faili nime lahter ei saa olla tühi</string>
<string name="wait_a_moment">Oota hetk</string>
<string name="filedisplay_unexpected_bad_get_content">Ootamatu tõrge ; palun kasuta faili valimiseks mõnda teist rakendust</string>
<string name="filedisplay_no_file_selected">Ühtegi faili pole valitud</string>
<string name="activity_chooser_title">Saada link</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Faili kopeerimine privaatsest salvestusalast</string>
<string name="oauth_check_onoff">Logi sisse oAuth2-ga</string>
<string name="oauth_login_connection">oAuth2 serveriga ühendumine...</string>
<string name="ssl_validator_header">Saidi identiteeti ei suudetud kinnitada</string>
<string name="share_link_file_error">Faili või kausta jagamisel esines viga</string>
<string name="unshare_link_file_no_exist">Liigutamise lõpetamine ebaõnnestus. Palun kontrolli, kas fail on olemas</string>
<string name="unshare_link_file_error">Faili või kausta jagamise tühistamisel esines viga</string>
+ <string name="share_link_password_title">Sisesta parool</string>
+ <string name="share_link_empty_password">Sa pead parooli sisestama</string>
<string name="activity_chooser_send_file_title">Saada</string>
<string name="copy_link">Kopeeri link</string>
<string name="clipboard_text_copied">Kopeeritud lõikepuhvrisse</string>
<string name="auth_redirect_non_secure_connection_title">Turvaline ühendus suunatakse läbi turvamata ühenduse.</string>
<string name="actionbar_logger">Logid</string>
<string name="log_send_history_button">Saada ajalugu</string>
- <string name="log_mail_subject">ownCloud Android rakenduse logid</string>
+ <string name="log_send_no_mail_app">Logide saatmise rakendust ei leitud. Paigalda postirakendus!</string>
+ <string name="log_send_mail_subject">%1$s Androidi rakenduse logid</string>
<string name="log_progress_dialog_text">Andmete laadimine...</string>
<string name="saml_authentication_required_text">Autentimine on vajalik</string>
<string name="saml_authentication_wrong_pass">Vale parool</string>
<string name="actionbar_move">Tõsta ümber</string>
<string name="file_list_empty_moving">Siin pole midagi. Sa võid lisada kausta!</string>
- <string name="move_choose_button_text">Vali</string>
+ <string name="folder_picker_choose_button_text">Vali</string>
<string name="move_file_not_found">Liigutamine ebaõnnestus. Palun kontrolli, kas fail on olemas</string>
<string name="move_file_invalid_into_descendent">Kausta ei saa liigutada selle alamkausta</string>
<string name="move_file_invalid_overwrite">See fail on juba sihtkaustas olemas</string>
<string name="forbidden_permissions_move">selle faili liigutamiseks</string>
<string name="prefs_category_instant_uploading">Kohesed üleslaadimised</string>
<string name="prefs_category_security">Turvalisus</string>
+ <string name="prefs_instant_video_upload_path_title">Video üleslaadimise asukoht</string>
+ <string name="download_folder_failed_content">Kausta %1$s allalaadimine ei õnnestunud</string>
+ <string name="shared_subject_header">jagatud</string>
+ <string name="with_you_subject_header">sinuga</string>
+ <string name="subject_token">%1$s jagas sinuga \"%2$s\"</string>
+ <string name="auth_refresh_button">Värskenda ühendust</string>
+ <string name="auth_host_address">Serveri aadress</string>
+ <string name="common_error_out_memory">Mälu pole piisavalt</string>
+ <string name="username">Kasutajanimi</string>
</resources>
<string name="actionbar_see_details">Xehetasunak</string>
<string name="actionbar_send_file">Bidali</string>
<string name="actionbar_sort">Ordenatu</string>
+ <string name="actionbar_sort_title">Ordenatu honen arabera</string>
<string-array name="actionbar_sortby">
<item>A-Z</item>
<item>Berrienak - Zaharrenak</item>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Orokorra</string>
<string name="prefs_category_more">Gehiago</string>
<string name="prefs_accounts">Kontuak</string>
<string name="prefs_manage_accounts">Kontuak kudeatu</string>
- <string name="prefs_pincode">App PIN</string>
- <string name="prefs_pincode_summary">Babestu zure bezeroa</string>
<string name="prefs_instant_upload">Uneko irudi igoerak</string>
<string name="prefs_instant_upload_summary">Igo berehala kamerak ateratako argazkiak</string>
<string name="prefs_instant_video_upload">Uneko bideo igoerak</string>
<string name="prefs_feedback">Oharrak</string>
<string name="prefs_imprint">Imprint</string>
<string name="recommend_subject">Probatu %1$s zure telefono adimentsuan!</string>
+ <string name="recommend_text">Nik %1$s zure telefono adimentsuan erabitzera gonbidatu nahi zaitut!\nDeskargatu hemen: %2$s</string>
<string name="auth_check_server">Egiaztatu zerbitzaria</string>
<string name="auth_host_url">Zerbitzariaren helbidea https://</string>
<string name="auth_username">Erabiltzaile izena</string>
<string name="sync_string_files">Fitxategiak</string>
<string name="setup_btn_connect">Konektatu</string>
<string name="uploader_btn_upload_text">Igo</string>
+ <string name="uploader_btn_new_folder_text">Karpeta berria</string>
<string name="uploader_top_message">Hautatu igoera karpeta:</string>
<string name="uploader_wrn_no_account_title">Ez da konturik aurkitu</string>
<string name="uploader_wrn_no_account_text">Zure gailuan ez dago %1$s konturik. Mesedez konfiguratu kontu bat lehenengo.</string>
<string name="uploader_info_uploading">Igotzen</string>
<string name="file_list_seconds_ago">segundu</string>
<string name="file_list_empty">Ez dago ezer. Igo zerbait!</string>
- <string name="file_list_loading">Kargatzen...</string>
<string name="local_file_list_empty">Ez dago fitxategirik karpeta honetan.</string>
<string name="filedetails_select_file">Sakatu fitxategi baten gainean informazio gehiago lortzeko</string>
<string name="filedetails_size">Tamaina:</string>
<string name="sync_fail_in_favourites_content">%1$d fitxategien edukiak ezin dira sinkronizatu (%2$d gatazka)</string>
<string name="sync_foreign_files_forgotten_ticker">Bertako fitxategi batzuk ahaztu dira</string>
<string name="sync_foreign_files_forgotten_content">%2$s karpetako %1$d fitxategi ezin dira dira kopiatu</string>
+ <string name="sync_foreign_files_forgotten_explanation">1.3.16 bertsioan, gailu honetatik igotzen diren fitxategiak bertako %1$s karpetara mugitzen dira datu galera ekiditeko fitxategi bat kontu ezberdinekin sinkronizatzen denean.\n\n Aldaketa hau dela eta, programa honen aurreko bertsioetan igotako fitxategi guztiak %2$s karpetara kopiatu dira. Hala ere, errore batek hau burutzea ekidin du kontuaren sinkronizazioa egiten ari zen bitartean. Orain fitxategiak dauden bezala utz ditzakezu eta %3$s rako lotura ezabatu, edo fitxategiak %1$s karpetara mugi ditzakezu eta %4$srako lotura mantendu.\n\nBehean bertako fitxategien zerrenda eta %5$s era lotuta zeuden urruneko fitxategiena.</string>
<string name="sync_current_folder_was_removed">%1$s karpeta dagoeneko ez da existitzen</string>
<string name="foreign_files_move">Mugitu denak</string>
<string name="foreign_files_success">Fitxategi guztiak mugitu dira</string>
<string name="foreign_files_local_text">Bertakoa: %1$s</string>
<string name="foreign_files_remote_text">Urrunekoa: %1$s</string>
<string name="upload_query_move_foreign_files">Ez dago leku nahikorik hautatutako fitxategiak %1$s karpetan kopiatzeko. Nahi al duzu kopiatu ordez bertara mugitzea?</string>
- <string name="pincode_enter_pin_code">Mesedez, sartu zure aplikazioaren PINa</string>
- <string name="pincode_configure_your_pin">Sartu aplikazioaren PINa</string>
- <string name="pincode_configure_your_pin_explanation">PINa aplikazioa abiarazten den bakoitzean eskatuko da</string>
- <string name="pincode_reenter_your_pincode">Sartu berriz aplikazioarenPINa, mesedez</string>
- <string name="pincode_remove_your_pincode">Ezabatu zure aplikazioaren PINa</string>
- <string name="pincode_mismatch">Aplikazioko bi PINak ez dira berdinak</string>
- <string name="pincode_wrong">Aplikazioaren PINa ezda zuzena</string>
- <string name="pincode_removed">Aplikazioaren PINa kendu da</string>
- <string name="pincode_stored">Aplikazioaren PINa gorde da</string>
<string name="media_notif_ticker">%1$s musika erreproduzigailua</string>
<string name="media_state_playing">%1$s (jotzen)</string>
<string name="media_state_loading">%1$s (kargatzen)</string>
<string name="auth_no_net_conn_title">Ez dago sare konexiorik</string>
<string name="auth_nossl_plain_ok_title">Konexio segurua ez dago eskuragarri</string>
<string name="auth_connection_established">Konexioa ezarri da</string>
- <string name="auth_testing_connection">Konexioa probatzen...</string>
<string name="auth_not_configured_title">gaizki egindako server konfigurazioa</string>
<string name="auth_account_not_new">Erabiltzaile eta zerbitzari hauendako dagoeneko kontu bat existitzen da gailu honetan</string>
<string name="auth_account_not_the_same">Sartutako erabiltzaileak ez du bat egiten kontu honetako erabiltzailearekin</string>
<string name="error__upload__local_file_not_copied">%1$s ezin da %2$s karpeta lokalera kopiatu</string>
<string name="prefs_instant_upload_path_title">Igotzetarako Bidea</string>
<string name="share_link_no_support_share_api">Sentitzen dut, partekatzea ez dago zure zerbitzarian gaituta. Mesedez jarri harremanetan zure administratzailearekin.</string>
+ <string name="share_link_file_no_exist">Ezin izan da partekatu. Mesedez egiaztatu fitxategia existitzen dela</string>
<string name="share_link_file_error">Errore bat egon da fitxategaia edo karpeta partekatzerakoan</string>
+ <string name="unshare_link_file_no_exist">Ezin izan da partekatzea desegin. Mesedez egiaztatu fitxategia existitzen dela</string>
<string name="unshare_link_file_error">Errore bat egon da fitxategaia edo karpeta partekatzeari uzterakoan</string>
<string name="activity_chooser_send_file_title">Bidali</string>
<string name="copy_link">Lotura kopiatu</string>
<string name="downloader_download_file_not_found">Fitxategia jadanik ez dago eskuragarri zerbitzarian</string>
<string name="prefs_category_accounts">Kontuak</string>
<string name="prefs_add_account">Gehitu kontua</string>
- <string name="log_mail_subject">ownCloud Android programaren egunerokoak</string>
+ <string name="auth_redirect_non_secure_connection_title">Konexio segurua birbideratu da segurua ez den bide batera.</string>
+ <string name="actionbar_logger">Egunkariak</string>
+ <string name="log_send_history_button">Bidali Historia</string>
+ <string name="log_send_no_mail_app">Egunkariak bidaltzeko aplikaziorik ez da aurkitu. Instalatu posta aplikazioa!</string>
+ <string name="log_send_mail_subject">%1$s Android aplikazioaren egunerokoak</string>
<string name="log_progress_dialog_text">Datuak kargatzen...</string>
<string name="saml_authentication_required_text">Autentikazioa beharrezkoa</string>
<string name="saml_authentication_wrong_pass">Pasahitz okerra</string>
<string name="actionbar_move">Mugitu</string>
- <string name="move_choose_button_text">Aukeratu</string>
+ <string name="file_list_empty_moving">Hemen ez dago ezer. Karpeta bat gehi dezakezu!</string>
+ <string name="folder_picker_choose_button_text">Aukeratu</string>
+ <string name="move_file_not_found">Ezin izan da mugitu. Mesedez egiaztatu fitxategia existitzen dela</string>
+ <string name="move_file_invalid_overwrite">Fitxategia dagoeneko existitzen da helburuko karpetan</string>
+ <string name="move_file_error">Errore bat gertatu da fitxategi edo karpeta hau mugitzen saiatzerakoan</string>
+ <string name="forbidden_permissions_move">fitxategi hau mugitzeko</string>
<string name="prefs_category_instant_uploading">Berehalako Igoerak</string>
<string name="prefs_category_security">Segurtasuna</string>
+ <string name="prefs_instant_video_upload_path_title">Bideo Igoera Bidea</string>
+ <string name="download_folder_failed_content">%1$s karpetaren deskarga ezin izan da burutu</string>
+ <string name="auth_host_address">Zerbitzariaren helbidea</string>
</resources>
<string name="actionbar_send_file">ارسال</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">عمومی</string>
<string name="prefs_category_more">بیشتر</string>
<string name="prefs_accounts">حسابها</string>
<string name="prefs_manage_accounts">مدیریت حسابها</string>
- <string name="prefs_pincode">PIN برنامه</string>
- <string name="prefs_pincode_summary">حفاظت از مشتری</string>
<string name="prefs_log_title">فعال کردن ورود</string>
<string name="prefs_log_summary">این برای مشکلات ورود استفاده شده است.</string>
<string name="prefs_log_title_history">تاریخچه ورود</string>
<string name="sync_string_files">پروندهها</string>
<string name="setup_btn_connect">اتصال</string>
<string name="uploader_btn_upload_text">بارگزاری</string>
+ <string name="uploader_btn_new_folder_text">پوشه جدید</string>
<string name="uploader_top_message">انتخاب پوشه آپلود:</string>
<string name="uploader_wrn_no_account_title">هیچ حسابی یافت نشد</string>
<string name="uploader_wrn_no_account_text">هیچ حسابی در %1$s بر روی دستگاه شما موجود نیست.لطفا اول یک حساب ترتیب دهید.</string>
<string name="uploader_info_uploading">در حال بارگزاری</string>
<string name="file_list_seconds_ago">ثانیهها پیش</string>
<string name="file_list_empty">اینجا هیچ چیز نیست.</string>
- <string name="file_list_loading">درحال بارگذاری...</string>
<string name="local_file_list_empty">هیچ فایلی در این پوشه نیست.</string>
<string name="filedetails_select_file">روی هر فایل کلیک کنید تا اطلاعات اضافی نمایش داده شود.</string>
<string name="filedetails_size">اندازه</string>
<string name="foreign_files_fail">بعضی از فایل ها نمی توانند انتقال یابند</string>
<string name="foreign_files_local_text">محلی: %1$s</string>
<string name="foreign_files_remote_text">دور از دسترس: %1$s</string>
- <string name="pincode_enter_pin_code">لطفا PIN برنامه خودتان را وارد کنید</string>
- <string name="pincode_configure_your_pin">PIN برنامه را وارد کنید</string>
- <string name="pincode_configure_your_pin_explanation">هر زمان که برنامه آغاز شود PIN درخواست خواهد شد.</string>
- <string name="pincode_reenter_your_pincode">لطفا PIN برنامه خودتان را دوباره وارد کنید</string>
- <string name="pincode_remove_your_pincode">PIN برنامه خودتان را حذف کنید</string>
- <string name="pincode_mismatch">PIN های برنامه یکسان نیستند</string>
- <string name="pincode_wrong">PIN برنامه نادرست است</string>
- <string name="pincode_removed">PIN برنامه حذف شده است</string>
- <string name="pincode_stored">PIN برنامه ذخیره شده است</string>
<string name="media_notif_ticker">%1$s پخش کننده موسیقی</string>
<string name="media_state_playing">%1$s ( در حال پخش موسیقی )</string>
<string name="media_state_loading">%1$s (درحال بارگذاری)</string>
<string name="auth_no_net_conn_title">هیچ ارتباطی به شبکه موجود نیست</string>
<string name="auth_nossl_plain_ok_title">اتصال امن در دسترس نیست</string>
<string name="auth_connection_established">اتصال برقرار شد</string>
- <string name="auth_testing_connection">آزمایش اتصال...</string>
<string name="auth_not_configured_title">پیکربندی سرور ناقص است</string>
<string name="auth_account_not_new">یک اکانت با همین نام کاربری و سرور بر روی این دستگاه موجود میباشد.</string>
<string name="auth_account_not_the_same">نام کاربری وارد شده با نام کاربری این اکانت مطابقت ندارد</string>
<string name="prefs_category_accounts">حسابها</string>
<string name="saml_authentication_required_text">احراز هویت مورد نیاز است</string>
<string name="saml_authentication_wrong_pass">رمز عبور اشتباه است</string>
- <string name="move_choose_button_text">انتخاب کردن</string>
+ <string name="folder_picker_choose_button_text">انتخاب کردن</string>
<string name="prefs_category_security">امنیت</string>
+ <string name="auth_host_address">آدرس سرور</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Kaikki tiedostot</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Asetukset</string>
+ <string name="drawer_item_logs">Lokit</string>
+ <string name="drawer_close">Sulje</string>
<string name="prefs_category_general">Yleiset</string>
<string name="prefs_category_more">Enemmän</string>
<string name="prefs_accounts">Tilit</string>
<string name="prefs_manage_accounts">Tilien hallinta</string>
- <string name="prefs_pincode">Sovelluksen PIN-koodi</string>
- <string name="prefs_pincode_summary">Suojaa asiakasohjelmasi</string>
+ <string name="prefs_passcode">Suojakoodilukitus</string>
<string name="prefs_instant_upload">Kuvien välitön lähetys</string>
<string name="prefs_instant_upload_summary">Lähetä kameralla otetut kuvat välittömästi</string>
<string name="prefs_instant_video_upload">Välittömät videolähetykset</string>
<string name="prefs_help">Ohje</string>
<string name="prefs_recommend">Suosittele kaverille</string>
<string name="prefs_feedback">Palaute</string>
+ <string name="prefs_imprint">Tiedot</string>
<string name="prefs_remember_last_share_location">Muista jaon sijainti</string>
<string name="prefs_remember_last_upload_location_summary">Muista viimeisin jaon lähetyssijainti</string>
<string name="recommend_subject">Kokeile %1$sia älypuhelimellasi!</string>
<string name="sync_string_files">Tiedostot</string>
<string name="setup_btn_connect">Yhdistä</string>
<string name="uploader_btn_upload_text">Lähetä</string>
+ <string name="uploader_btn_new_folder_text">Luo kansio</string>
<string name="uploader_top_message">Valitse lähetyskansio:</string>
<string name="uploader_wrn_no_account_title">Tiliä ei löytynyt</string>
<string name="uploader_wrn_no_account_text">Laitteelle ei ole asetettu %1$s-tiliä. Luo tili ensin.</string>
<string name="uploader_info_uploading">Lähetetään</string>
<string name="file_list_seconds_ago">sekuntia sitten</string>
<string name="file_list_empty">Täällä ei ole mitään. Lähetä tänne jotakin!</string>
- <string name="file_list_loading">Ladataan...</string>
<string name="local_file_list_empty">Tässä kansiossa ei ole tiedostoja</string>
<string name="filedetails_select_file">Napauta tiedostoa nähdäksesi lisätietoja.</string>
<string name="filedetails_size">Koko:</string>
<string name="filedetails_download">Lataa</string>
<string name="filedetails_sync_file">Päivitä tiedosto</string>
<string name="filedetails_renamed_in_upload_msg">Tiedoston nimeksi muutettiin %1$s siirron yhteydessä</string>
+ <string name="list_layout">Luettelon asettelu</string>
<string name="action_share_file">Jaa linkki</string>
+ <string name="action_unshare_file">Poista linkin jako</string>
<string name="common_yes">Kyllä</string>
<string name="common_no">Ei</string>
<string name="common_ok">OK</string>
<string name="foreign_files_fail">Joidenkin tiedostojen siirtäminen epäonnistui</string>
<string name="foreign_files_local_text">Paikallinen: %1$s</string>
<string name="foreign_files_remote_text">Etä: %1$s</string>
- <string name="pincode_enter_pin_code">Aseta sovelluksesi PIN</string>
- <string name="pincode_configure_your_pin">Anna sovelluksen PIN</string>
- <string name="pincode_configure_your_pin_explanation">PIN kysytään joka kerta, kun sovellus käynnistetään</string>
- <string name="pincode_reenter_your_pincode">Anna sovelluksen PIN uudestaan</string>
- <string name="pincode_remove_your_pincode">Poista sovelluksen PIN</string>
- <string name="pincode_mismatch">Sovelluksen PIN-koodit eivät täsmää</string>
- <string name="pincode_wrong">Väärä sovelluksen PIN</string>
- <string name="pincode_removed">Sovelluksen PIN poistettu</string>
- <string name="pincode_stored">Sovelluksen PIN-koodi tallennettu</string>
+ <string name="pass_code_enter_pass_code">Anna suojakoodisi</string>
+ <string name="pass_code_configure_your_pass_code">Anna suojakoodisi</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Suojakoodi kysytään joka kerta, kun sovellus käynnistetään</string>
+ <string name="pass_code_reenter_your_pass_code">Anna suojakoodi uudelleen</string>
+ <string name="pass_code_remove_your_pass_code">Poista suojakoodi käytöstä</string>
+ <string name="pass_code_mismatch">Suojakoodit eivät täsmää</string>
+ <string name="pass_code_wrong">Virheellinen suojakoodi</string>
+ <string name="pass_code_removed">Suojakoodi poistettu</string>
+ <string name="pass_code_stored">Suojakoodi tallennettu</string>
+ <string name="media_notif_ticker">%1$s-musiikkisoitin</string>
<string name="media_state_playing">%1$s (toistetaan)</string>
<string name="media_state_loading">%1$s (ladataan)</string>
<string name="media_err_nothing_to_play">Mediatiedostoa ei löytynyt</string>
<string name="media_err_no_account">Tiliä ei määritetty</string>
<string name="media_err_not_in_owncloud">Tiedosto ei ole kelvollisella tilillä</string>
+ <string name="media_err_unsupported">Mediakoodekki ei ole tuettu</string>
<string name="media_err_io">Mediatiedoston luku ei onnistunut</string>
+ <string name="media_err_malformed">Mediatiedostoa ei ole koodattu kelvollisesti</string>
<string name="media_err_timeout">Aikakatkaisu toistoa yrittäessä</string>
<string name="media_err_invalid_progressive_playback">Mediatiedostoa ei voi suoratoistaa</string>
<string name="media_err_security_ex">Turvallisuusvirhe yrittäessä toistaa kohdetta %1$s</string>
<string name="auth_no_net_conn_title">Ei verkkoyhteyttä</string>
<string name="auth_nossl_plain_ok_title">Salattu yhteys ei ole käytettävissä.</string>
<string name="auth_connection_established">Yhteys muodostettu</string>
- <string name="auth_testing_connection">Testataan yhteyttä...</string>
+ <string name="auth_testing_connection">Testataan yhteyttä</string>
<string name="auth_not_configured_title">Väärin tehdyt palvelin-asetukset</string>
<string name="auth_account_not_new">Laitteella on jo tili samalle käyttäjälle ja palvelimelle</string>
+ <string name="auth_account_not_the_same">Syötetty käyttäjä ei täsmää tämän tilin käyttäjän kanssa</string>
<string name="auth_unknown_error_title">Tuntematon virhe</string>
<string name="auth_unknown_host_title">Isäntää ei löydy</string>
<string name="auth_incorrect_path_title">Palvelin-instanssia ei löydetty</string>
<string name="auth_unsupported_auth_method">Palvelin ei tue tätä tunnistautumistapaa</string>
<string name="auth_unsupported_multiaccount">%1$s ei tue useita tilejä</string>
<string name="auth_can_not_auth_against_server">Tunnistautuminen palvelinta vastaan ei onnistu</string>
+ <string name="auth_account_does_not_exist">Tiliä ei ole olemassa vielä laitteella</string>
<string name="fd_keep_in_sync">Pidä tiedosto ajan tasalla</string>
<string name="common_rename">Nimeä uudelleen</string>
<string name="common_remove">Poista</string>
<string name="sync_file_nothing_to_do_msg">Tiedoston sisältö on jo synkronoitu</string>
<string name="create_dir_fail_msg">Kansion luominen epäonnistui</string>
<string name="filename_forbidden_characters">Kielletyt merkit: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Tiedoston nimi sisältää ainakin yhden virheellisen merkin</string>
<string name="filename_empty">Tiedoston nimi ei voi olla tyhjä</string>
<string name="wait_a_moment">Odota hetki</string>
<string name="filedisplay_unexpected_bad_get_content">Odottamaton ongelma; kokeile valita tiedosto toisella sovelluksella</string>
<string name="filedisplay_no_file_selected">Tiedostoa ei valittu</string>
<string name="activity_chooser_title">Lähetä linkki…</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Kopioidaan tiedostoa yksityisestä tallennustilasta</string>
<string name="oauth_check_onoff">Kirjaudu oAuth2:lla</string>
<string name="oauth_login_connection">Yhdistetään oAuth2-palvelimeen…</string>
<string name="ssl_validator_header">Sivuston identiteetin vahvistaminen ei onnistunut</string>
<string name="ssl_validator_no_info_about_error">- Ei lisätietoja virheestä</string>
<string name="placeholder_filetype">PNG-kuva</string>
<string name="placeholder_filesize">389 kt</string>
+ <string name="placeholder_media_time">12:23:45</string>
<string name="instant_upload_on_wifi">Lähetä kuvat vain WiFi-verkossa</string>
<string name="instant_video_upload_on_wifi">Lähetä videot vain wifi-yhteydellä</string>
<string name="instant_upload_path">/InstantUpload</string>
<string name="prefs_instant_upload_path_title">Lähetyspolku</string>
<string name="share_link_no_support_share_api">Jakaminen ei ole käytössä palvelimellasi. Ota yhteys
ylläpitäjään.</string>
+ <string name="share_link_file_no_exist">Jakaminen epäonnistui. Varmista, että tiedosto on olemassa</string>
<string name="share_link_file_error">Virhe tiedoston tai kansion jakamista yrittäessä</string>
+ <string name="share_link_password_title">Anna salasana</string>
+ <string name="share_link_empty_password">Salasana on pakko antaa</string>
<string name="activity_chooser_send_file_title">Lähetä</string>
<string name="copy_link">Kopioi linkki</string>
<string name="clipboard_text_copied">Kopioitu leikepöydälle</string>
<string name="auth_redirect_non_secure_connection_title">Salattu yhteys on ohjattu uudelleen salaamatonta reittiä pitkin.</string>
<string name="actionbar_logger">Lokit</string>
<string name="log_send_history_button">Lähetä historia</string>
- <string name="log_mail_subject">ownCloudin Android-sovelluksen lokit</string>
- <string name="log_progress_dialog_text">Ladataan tietoja...</string>
+ <string name="log_send_no_mail_app">Lokien lähettämistä varten ei löytynyt sovellusta. Asenna sähköpostisovellus!</string>
+ <string name="log_send_mail_subject">%1$sin Android-sovelluksen lokit</string>
+ <string name="log_progress_dialog_text">Ladataan tietoja…</string>
<string name="saml_authentication_required_text">Tunnistautuminen vaaditaan</string>
<string name="saml_authentication_wrong_pass">Väärä salasana</string>
<string name="actionbar_move">Siirrä</string>
<string name="file_list_empty_moving">Täällä ei ole mitään. Voit lisätä kansion!</string>
- <string name="move_choose_button_text">Valitse</string>
+ <string name="folder_picker_choose_button_text">Valitse</string>
<string name="move_file_not_found">Siirto ei onnistu. Tarkista, ettei tiedostoa ole jo olemassa</string>
<string name="move_file_invalid_overwrite">Tiedosto on jo olemassa kohdekansiossa</string>
<string name="move_file_error">Tämän tiedoston tai kansion siirtoa yrittäessä tapahtui virhe</string>
<string name="prefs_category_instant_uploading">Välittömät lähetykset</string>
<string name="prefs_category_security">Tietoturva</string>
+ <string name="shared_subject_header">jaettu</string>
+ <string name="with_you_subject_header">kanssasi</string>
+ <string name="subject_token">%1$s jakoi kohteen \"%2$s\" kanssasi</string>
+ <string name="auth_refresh_button">Päivitä yhteys</string>
+ <string name="auth_host_address">Palvelimen osoite</string>
+ <string name="common_error_out_memory">Muistia ei ole riittävästi</string>
+ <string name="username">Käyttäjätunnus</string>
</resources>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <string name="actionbar_upload">Lähetä</string>
+ <string name="actionbar_open_with">Avaa sovelluksessa</string>
+ <string name="actionbar_mkdir">Luo kansio</string>
+ <string name="actionbar_settings">Asetukset</string>
+ <!--TODO re-enable when server-side folder size calculation is available
+ <item>Biggest - Smallest</item>-->
+ <string name="prefs_category_more">Lisää</string>
+ <string name="prefs_manage_accounts">Hallitse tilejä</string>
+ <string name="prefs_pincode">Sovelluksen PIN</string>
+ <string name="prefs_help">Apua</string>
+ <string name="auth_host_url">http://esimerkki.fi/palvelu/</string>
+ <string name="auth_username">Käyttäjätunnus</string>
+ <string name="auth_password">Salasana</string>
+ <string name="uploader_btn_upload_text">Lähetä</string>
+ <string name="file_list_empty">Ei sisältöä. Siirrä tänne jotakin!</string>
+ <string name="file_list_loading">Ladataan...</string>
+ <string name="file_list_folder">kansio</string>
+ <string name="file_list_folders">kansiot</string>
+ <string name="file_list_file">tiedosto</string>
+ <string name="file_list_files">Tiedostot</string>
+ <string name="action_share_file">Jaa linkki</string>
+ <string name="action_unshare_file">Poista linkin jako</string>
+ <string name="common_yes">KYLLÄ</string>
+ <string name="common_no">EI</string>
+ <string name="common_ok">Ok</string>
+ <string name="common_cancel">Peruuta</string>
+ <string name="common_error">Virhe</string>
+ <string name="pincode_wrong">Virheellinen PIN</string>
+ <string name="pincode_removed">Sovelluksen PIN poistettu</string>
+ <string name="pincode_stored">Sovelluksen PIN tallennettu</string>
+ <string name="auth_account_not_the_same">Syötetty käyttäjä ei täsmää tämän tilin käyttäjän kanssa</string>
+ <string name="auth_unsupported_auth_method">Palvelin ei tue tätä autentikointitapaa</string>
+ <string name="common_rename">Nimeä uudelleen</string>
+ <string name="ssl_validator_label_L">Sijainti:</string>
+ <string name="conflict_overwrite">Ylikirjoita</string>
+ <string name="copy_link">Kopioi linkki</string>
+ <string name="empty"></string>
+ <string name="actionbar_move">Siirrä</string>
+ <string name="folder_picker_choose_button_text">Valitse</string>
+ <string name="move_file_invalid_overwrite">Tiedosto on jo kohdekansiossa.</string>
+</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_upload_files">Ficheiros</string>
<string name="actionbar_open_with">Abrir con</string>
<string name="actionbar_mkdir">Novo cartafol</string>
- <string name="actionbar_settings">Preferencias</string>
+ <string name="actionbar_settings">Axustes</string>
<string name="actionbar_see_details">Detalles</string>
<string name="actionbar_send_file">Enviar</string>
+ <string name="actionbar_sort">Ordenar</string>
+ <string name="actionbar_sort_title">Ordenar por</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Máis novo - Máis antigo</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Todos os ficheiros</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Axustes</string>
+ <string name="drawer_item_logs">Rexistros</string>
+ <string name="drawer_close">Pechar</string>
<string name="prefs_category_general">Xeral</string>
<string name="prefs_category_more">Máis</string>
<string name="prefs_accounts">Contas</string>
- <string name="prefs_manage_accounts">Xestionar as contas</string>
- <string name="prefs_pincode">PIN da aplicación</string>
- <string name="prefs_pincode_summary">Protexe o seu cliente</string>
+ <string name="prefs_manage_accounts">Administrar as contas</string>
+ <string name="prefs_passcode">Código de bloqueo</string>
<string name="prefs_instant_upload">Envío instantáneo de fotos</string>
<string name="prefs_instant_upload_summary">Enviar instantaneamente as fotos tiradas coa cámara</string>
<string name="prefs_instant_video_upload">Envío instantáneo de vídeos</string>
<string name="prefs_recommend">Recomendar a un amigo</string>
<string name="prefs_feedback">Comentarios</string>
<string name="prefs_imprint">Impresión</string>
+ <string name="prefs_remember_last_share_location">Lembrar a localización da compartición</string>
+ <string name="prefs_remember_last_upload_location_summary">Lembrar a localización do envío da última compartición</string>
<string name="recommend_subject">Tente %1$s no seu teléfono intelixente!</string>
+ <string name="recommend_text">Quero convidalo a empregar %1$s no seu teléfono intelixente!
+Descárgueo de aquí: %2$s</string>
<string name="auth_check_server">Comprobar o servidor</string>
<string name="auth_host_url">Enderezo do servidor https://…</string>
<string name="auth_username">Nome de usuario</string>
<string name="sync_string_files">Ficheiros</string>
<string name="setup_btn_connect">Conectar</string>
<string name="uploader_btn_upload_text">Enviar</string>
+ <string name="uploader_btn_new_folder_text">Novo cartafol</string>
<string name="uploader_top_message">Escolla o cartafol de envío:</string>
<string name="uploader_wrn_no_account_title">Non se atoparon contas</string>
<string name="uploader_wrn_no_account_text">Non hai contas de %1$s no seu dispositivo. Cree unha nova conta primeiro.</string>
<string name="filedetails_download">Descargar</string>
<string name="filedetails_sync_file">Actualizar o ficheiro</string>
<string name="filedetails_renamed_in_upload_msg">O ficheiro foi renomeado a %1$s durante o envío</string>
+ <string name="list_layout">Deseño da lista</string>
<string name="action_share_file">Ligazón para compartir</string>
<string name="action_unshare_file">Deixar de compartir a ligazón</string>
<string name="common_yes">Si</string>
<string name="sync_fail_in_favourites_content">Non foi posíbel sincronizar o contido de %1$d ficheiros (%2$d conflitos)</string>
<string name="sync_foreign_files_forgotten_ticker">Algúns ficheiros locais foron esquecidos</string>
<string name="sync_foreign_files_forgotten_content">Non é posíbel copiar %1$d ficheiros do cartafol %2$s en</string>
+ <string name="sync_foreign_files_forgotten_explanation">Desde a versión 1.3.16, os ficheiros enviados desde este dispositivo cópianse no cartafol local %1$s para evitar a perda de datos cando se sincroniza un ficheiro con varias contas.\n\nPor mor deste cambio, todos os ficheiros enviados coas versións anteriores desta aplicación cópianse no cartafol %2$s. Porén, un erro impediu a finalización desta operación durante a sincronización da conta. É posíbel deixar o(s) ficheiro(s) como está(n) e retirar a ligazón a %3$s, ou mover o(s) ficheiro(s) ao directorio %1$s e manter a ligazón a %4$s.\n\nA seguir enuméranse o(s) ficheiro(s) local(is), e o(s) ficheiro(s) remoto(s) en %5$s co(s) que estaba(n) ligado(s).</string>
<string name="sync_current_folder_was_removed">O cartafol %1$s xa non existe</string>
<string name="foreign_files_move">Mover todo</string>
<string name="foreign_files_success">Foron movidos todos os ficheiros</string>
<string name="foreign_files_local_text">Local: %1$s</string>
<string name="foreign_files_remote_text">Remoto: %1$s</string>
<string name="upload_query_move_foreign_files">Non hai espazo abondo para copiar os ficheiros seleccionados no cartafol %1$s. Quere movelos no canto de copialos?</string>
- <string name="pincode_enter_pin_code">Insira o seu PIN da aplicación</string>
- <string name="pincode_configure_your_pin">Introduza o seu PIN da aplicación</string>
- <string name="pincode_configure_your_pin_explanation">Pediráselle o PIN cada vez que se inicie a aplicación</string>
- <string name="pincode_reenter_your_pincode">Volva a introducir o seu PIN da aplicación</string>
- <string name="pincode_remove_your_pincode">Retirar o seu PIN da aplicación</string>
- <string name="pincode_mismatch">Os PIN da aplicación non son iguais</string>
- <string name="pincode_wrong">O PIN da aplicación é incorrecto</string>
- <string name="pincode_removed">O PIN da aplicación foi retirado</string>
- <string name="pincode_stored">Almacenouse o PIN da aplicación</string>
+ <string name="pass_code_enter_pass_code">Introduza o seu código de acceso</string>
+ <string name="pass_code_configure_your_pass_code">Escriba o seu código de acceso</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Solicitaráselle o código de acceso cada vez que inicie a aplicación</string>
+ <string name="pass_code_reenter_your_pass_code">Volva escribir o seu código de acceso</string>
+ <string name="pass_code_remove_your_pass_code">Retirar o seu código de acceso</string>
+ <string name="pass_code_mismatch">Os códigos de acceso non son iguais</string>
+ <string name="pass_code_wrong">Código de acceso incorrecto</string>
+ <string name="pass_code_removed">Retirouse o código de acceso</string>
+ <string name="pass_code_stored">O código de acceso foi almacenado</string>
<string name="media_notif_ticker">%1$s reprodutor musical</string>
<string name="media_state_playing">%1$s (reproducindo)</string>
<string name="media_state_loading">%1$s (cargando)</string>
<string name="media_err_timeout">Esgotouse o tempo de espera tentando reproducir</string>
<string name="media_err_invalid_progressive_playback">Non é posíbel enviar como fluxo o ficheiro multimedia</string>
<string name="media_err_unknown">Non é posíbel reproducir o ficheiro multimedia co reprodutor «stock»</string>
- <string name="media_err_security_ex">Produciuse un erro de seguranza tentando reproducir %1$s</string>
+ <string name="media_err_security_ex">Produciuse un erro de seguridade tentando reproducir %1$s</string>
<string name="media_err_io_ex">Produciuse un erro de entrada tentando reproducir %1$s</string>
<string name="media_err_unexpected">Produciuse un erro non agardado tentando reproducir %1$s</string>
<string name="media_rewind_description">Botón de retroceso</string>
<string name="auth_no_net_conn_title">Sen conexión de rede</string>
<string name="auth_nossl_plain_ok_title">Non hai conexión seguras dispoñíbeis.</string>
<string name="auth_connection_established">Estabeleceuse a conexión</string>
- <string name="auth_testing_connection">Comprobando a conexión...</string>
+ <string name="auth_testing_connection">Probando a conexión</string>
<string name="auth_not_configured_title">Configuración errada do servidor</string>
<string name="auth_account_not_new">Xa existe unha conta do mesmo usuario e servidor neste dispositivo</string>
<string name="auth_account_not_the_same">O usuario que introduciu non coincide co usuario desta conta</string>
<string name="auth_unknown_error_title">Produciuse un erro descoñecido!</string>
<string name="auth_unknown_host_title">Non foi posíbel atopar a máquina</string>
<string name="auth_incorrect_path_title">Non se atopou unha instancia do servidor</string>
- <string name="auth_timeout_title">O servidor tardou demasiado en responder</string>
+ <string name="auth_timeout_title">O servidor tardou de máis en responder</string>
<string name="auth_incorrect_address_title">URL incorrecto</string>
- <string name="auth_ssl_general_error_title">Produciuse un fallo ao iniciar o SSL</string>
+ <string name="auth_ssl_general_error_title">Produciuse un fallo ao preparar o SSL</string>
<string name="auth_ssl_unverified_server_title">Non foi posíbel verificar a identidade do servidor SSL</string>
<string name="auth_bad_oc_version_title">Versión do servidor non recoñecida</string>
<string name="auth_wrong_connection_title">Non é posíbel estabelecer a conexión</string>
<string name="auth_fail_get_user_name">O seu servidor non devolveu un ID de usuario correcto, contacte cun administrador
</string>
<string name="auth_can_not_auth_against_server">Non pode autenticarse neste servidor</string>
+ <string name="auth_account_does_not_exist">Aínda non existe a conta no dispositivo</string>
<string name="fd_keep_in_sync">Manter actualizado o ficheiro</string>
<string name="common_rename">Renomear</string>
<string name="common_remove">Retirar</string>
<string name="sync_file_nothing_to_do_msg">Os contidos do ficheiro xa están sincronizados</string>
<string name="create_dir_fail_msg">Non foi posíbel crear o cartafol</string>
<string name="filename_forbidden_characters">Caracteres non permitidos: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">O nome de ficheiro contén algún carácter incorrecto</string>
<string name="filename_empty">O nome de ficheiro non pode estar baleiro</string>
<string name="wait_a_moment">Agarde un chisco</string>
<string name="filedisplay_unexpected_bad_get_content">Produciuse un erro non agardado. Seleccione o ficheiro con outra aplicación diferente</string>
<string name="filedisplay_no_file_selected">Non se escolleu ningún ficheiro</string>
<string name="activity_chooser_title">Enviar a ligazón a ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Copiando o ficheiro desde o almacenamento privado</string>
<string name="oauth_check_onoff">Acceder con oAuth2</string>
<string name="oauth_login_connection">Conectando co servidor oAuth2…</string>
<string name="ssl_validator_header">Non foi posíbel verificar a identidade do sitio</string>
<string name="preview_image_description">Vista previa da imaxe</string>
<string name="preview_image_error_unknown_format">Esta imaxe non pode ser amosada</string>
<string name="error__upload__local_file_not_copied">Non foi posíbel copiar %1$s no cartafol local %2$s</string>
+ <string name="prefs_instant_upload_path_title">Enviar a ruta</string>
<string name="share_link_no_support_share_api">O seu servidor non ten activada a opción de compartir. Póñase en contacto co
administrador.</string>
+ <string name="share_link_file_no_exist">Non foi posíbel compartir. Comprobe que existe o ficheiro</string>
<string name="share_link_file_error">Produciuse un erro ao tentar compartir este ficheiro ou cartafol.</string>
+ <string name="unshare_link_file_no_exist">Non foi posíbel deixar de compartir. Comprobe que existe o ficheiro</string>
<string name="unshare_link_file_error">Produciuse un erro ao tentar deixar de compartir este ficheiro ou cartafol</string>
+ <string name="share_link_password_title">Escriba un contrasinal</string>
+ <string name="share_link_empty_password">Ten que escribir un contrasinal</string>
<string name="activity_chooser_send_file_title">Enviar</string>
<string name="copy_link">Copiar a ligazón</string>
<string name="clipboard_text_copied">Copiado no portapapeis.</string>
<string name="downloader_download_file_not_found">O ficheiro xa non está dispoñíbel no servidor</string>
<string name="prefs_category_accounts">Contas</string>
<string name="prefs_add_account">Engadir unha conta</string>
+ <string name="auth_redirect_non_secure_connection_title">A conexión segura está a ser redirixida a unha ruta non segura.</string>
+ <string name="actionbar_logger">Rexistros</string>
+ <string name="log_send_history_button">Enviar o historial</string>
+ <string name="log_send_no_mail_app">Non se atopou unha aplicación para enviar os rexistros. Instale unha aplicación de correo!</string>
+ <string name="log_send_mail_subject">Rexistros da aplicación %1$s Android</string>
+ <string name="log_progress_dialog_text">Cargando os datos...</string>
<string name="saml_authentication_required_text">Requírese autenticación</string>
<string name="saml_authentication_wrong_pass">Contrasinal incorrecto</string>
<string name="actionbar_move">Mover</string>
- <string name="move_choose_button_text">Escoller</string>
- <string name="prefs_category_security">Seguranza</string>
+ <string name="file_list_empty_moving">Aquí non hai nada. Pode engadir un cartafol!</string>
+ <string name="folder_picker_choose_button_text">Escoller</string>
+ <string name="move_file_not_found">Non é posíbel movelo. Comprobe se existe o ficheiro</string>
+ <string name="move_file_invalid_into_descendent">Non é posíbel mover un cartafol cara un descendente</string>
+ <string name="move_file_invalid_overwrite">Este ficheiro xa existe no cartafol de destino</string>
+ <string name="move_file_error">Produciuse un erro ao tentar mover este ficheiro ou cartafol.</string>
+ <string name="forbidden_permissions_move">para mover este ficheiro</string>
+ <string name="prefs_category_instant_uploading">Envío instantáneo</string>
+ <string name="prefs_category_security">Seguridade</string>
+ <string name="prefs_instant_video_upload_path_title">Enviar a ruta do vídeo</string>
+ <string name="download_folder_failed_content">Non foi posíbel completar a descarga do cartafol %1$s</string>
+ <string name="shared_subject_header">compartido</string>
+ <string name="with_you_subject_header">con vostede</string>
+ <string name="subject_token">%1$s compartiu «%2$s» con vostede</string>
+ <string name="auth_refresh_button">Actualizar a conexión</string>
+ <string name="auth_host_address">Enderezo do servidor</string>
+ <string name="common_error_out_memory">Non hai memoria abondo</string>
+ <string name="username">Nome de usuario</string>
+ <string name="file_list__footer__folder">1 cartafol</string>
+ <string name="file_list__footer__folders">%1$d cartafoles</string>
+ <string name="file_list__footer__file">1 ficheiro</string>
+ <string name="file_list__footer__file_and_folder">1 ficheiro, 1 cartafol</string>
+ <string name="file_list__footer__file_and_folders">1 ficheiro, %1$d cartafoles</string>
+ <string name="file_list__footer__files">%1$d ficheiros</string>
+ <string name="file_list__footer__files_and_folder">%1$d ficheiros, 1 cartafol</string>
+ <string name="file_list__footer__files_and_folders">%1$d ficheiros, %2$d cartafoles</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_send_file">שליחה</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">כללי</string>
<string name="prefs_category_more">יותר</string>
<string name="prefs_accounts">חשבונות</string>
<string name="prefs_manage_accounts">ניהול חשבונות</string>
- <string name="prefs_pincode">קוד יישום</string>
- <string name="prefs_pincode_summary">הגנה על הלקוח שלך</string>
<string name="prefs_instant_upload">העלאת תמונות מהירה</string>
<string name="prefs_instant_upload_summary">העלאה מהירה של תמונות שצולמו במצלמה</string>
<string name="prefs_instant_video_upload">העלאת סרטים מהירה</string>
<string name="sync_string_files">קבצים</string>
<string name="setup_btn_connect">התחברות</string>
<string name="uploader_btn_upload_text">העלאה</string>
+ <string name="uploader_btn_new_folder_text">תיקייה חדשה</string>
<string name="uploader_top_message">בחירת תיקיית העלאה:</string>
<string name="uploader_wrn_no_account_title">לא נמצא חשבון</string>
<string name="uploader_wrn_no_account_text">אין חשבונות %1$s בהתקן שלך. נא להגדיר חשבון תחילה.</string>
<string name="uploader_info_uploading">בהעלאה</string>
<string name="file_list_seconds_ago">שניות</string>
<string name="file_list_empty">אין כאן שום דבר. אולי ברצונך להעלות משהו?</string>
- <string name="file_list_loading">בטעינה...</string>
<string name="local_file_list_empty">אין קבצים בתיקייה זו:</string>
<string name="filedetails_select_file">יש לגעת בקובץ כדי להציג פרטים נוספים.</string>
<string name="filedetails_size">גודל:</string>
<string name="foreign_files_local_text">מקומי: %1$s</string>
<string name="foreign_files_remote_text">מרוחק: %1$s</string>
<string name="upload_query_move_foreign_files">אין מספיק מקום להעתקת הקבצים שנבחרו אל תיקיית %1$s . האם להעביר אותם במקום?</string>
- <string name="pincode_enter_pin_code">נא להזין את קוד היישום שלך</string>
- <string name="pincode_configure_your_pin">נא להזין את קוד היישום שלך</string>
- <string name="pincode_configure_your_pin_explanation">תופיע בקשה לקוד בכל פעם שהיישום מופעל</string>
- <string name="pincode_reenter_your_pincode">נא להזין את קוד היישום שלך מחדש</string>
- <string name="pincode_remove_your_pincode">הסרת קוד היישום שלך</string>
- <string name="pincode_mismatch">הקודים של היישום שונים</string>
- <string name="pincode_wrong">קוד היישום שגוי</string>
- <string name="pincode_removed">קוד היישום הוסר</string>
- <string name="pincode_stored">קוד היישום אוחסן</string>
<string name="media_notif_ticker">נגנן המוזיקה %1$s</string>
<string name="media_state_playing">%1$s (מתנגן)</string>
<string name="media_state_loading">%1$s (בטעינה)</string>
<string name="auth_no_net_conn_title">אין חיבור לאינטרנט</string>
<string name="auth_nossl_plain_ok_title">אין חיבור מוצפן זמין.</string>
<string name="auth_connection_established">החיבור נוצר</string>
- <string name="auth_testing_connection">החיבור נבדק…</string>
<string name="auth_not_configured_title">תצורת השרת פגומה</string>
<string name="auth_account_not_new">חשבון לאותו משתמש ושרת כבר קיים במכשיר זה</string>
<string name="auth_account_not_the_same">שם המשתמש שהוכנס לא מתאים לשם המשתמש של חשבון זה</string>
<string name="downloader_download_file_not_found">הקובץ אינו זמין יותר על השרת</string>
<string name="prefs_category_accounts">חשבונות</string>
<string name="prefs_add_account">הוספת חשבון</string>
- <string name="move_choose_button_text">בחירה</string>
+ <string name="folder_picker_choose_button_text">בחירה</string>
<string name="prefs_category_security">אבטחה</string>
+ <string name="auth_host_address">כתובת שרת</string>
</resources>
<string name="actionbar_send_file">भेजें</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">सामान्य </string>
<string name="prefs_category_more">और अधिक</string>
<string name="prefs_accounts">खाते </string>
- <string name="prefs_pincode">एप्प पिन </string>
- <string name="prefs_pincode_summary">अपने उपभोक्ता की सुरक्षा करें </string>
<string name="prefs_help">सहायता </string>
<string name="auth_username">उपभोक्ता का नाम</string>
<string name="auth_password">पासवर्ड</string>
<string name="sync_string_files">फाइलें </string>
<string name="setup_btn_connect">जुड़ें </string>
<string name="uploader_btn_upload_text">अपलोड </string>
+ <string name="uploader_btn_new_folder_text">नया फ़ोल्डर</string>
<string name="common_cancel">रद्द करें </string>
<string name="common_error">त्रुटि</string>
<string name="ssl_validator_btn_details_see">विवरण </string>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="about_android">%1$s Android aplikacija</string>
+ <string name="about_version">verzija %1$s</string>
+ <string name="actionbar_sync">Osvježi račun</string>
<string name="actionbar_upload">Učitaj</string>
+ <string name="actionbar_upload_from_apps">Sadržaj iz drugih aplikacija</string>
<string name="actionbar_upload_files">Datoteke</string>
+ <string name="actionbar_open_with">Otvori sa</string>
<string name="actionbar_mkdir">Nova mapa</string>
<string name="actionbar_settings">Postavke</string>
+ <string name="actionbar_see_details">Detalji</string>
<string name="actionbar_send_file">Pošaljite</string>
+ <string name="actionbar_sort">Sortiraj</string>
+ <string name="actionbar_sort_title">Sortiraj po</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Najnoviji- Stariji</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Općenito</string>
<string name="prefs_category_more">više</string>
<string name="prefs_accounts">Korisnićki računi</string>
+ <string name="prefs_manage_accounts">Upravljaj računima</string>
+ <string name="prefs_instant_upload">Trenutni upload slika</string>
+ <string name="prefs_instant_upload_summary">Trenutni upload slika snimljenih kamerom</string>
+ <string name="prefs_instant_video_upload">Trenutni upload videa</string>
+ <string name="prefs_instant_video_upload_summary">Trenutni upload videa snimljen kamerom</string>
<string name="prefs_help">Pomoć</string>
<string name="auth_username">Korisničko ime</string>
<string name="auth_password">Lozinka</string>
<string name="sync_string_files">Datoteke</string>
<string name="setup_btn_connect">Poveži</string>
<string name="uploader_btn_upload_text">Učitaj</string>
+ <string name="uploader_btn_new_folder_text">Nova mapa</string>
<string name="uploader_wrn_no_account_quit_btn_text">Izlaz</string>
<string name="file_list_seconds_ago">prije par sekundi</string>
<string name="file_list_empty">Nema ničega u ovoj mapi. Pošalji nešto!</string>
<string name="auth_trying_to_login">Trying to login…</string>
<string name="common_rename">Promjeni ime</string>
<string name="common_remove">Makni</string>
+ <string name="ssl_validator_btn_details_see">Detalji</string>
<string name="activity_chooser_send_file_title">Pošaljite</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Korisnićki računi</string>
<string name="saml_authentication_required_text">Potrebna autentikacija</string>
<string name="saml_authentication_wrong_pass">Pogrešna lozinka</string>
- <string name="move_choose_button_text">Izaberi</string>
+ <string name="folder_picker_choose_button_text">Odaberite</string>
<string name="prefs_category_security">Sigurnost</string>
+ <string name="auth_host_address">Adresa poslužitelja</string>
</resources>
<string name="actionbar_send_file">Küldjük el</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Általános</string>
<string name="prefs_category_more">Több</string>
<string name="prefs_accounts">Fiókok</string>
<string name="prefs_manage_accounts">Fiókok kezelése</string>
- <string name="prefs_pincode">Alkalmazás PIN</string>
- <string name="prefs_pincode_summary">Védje meg az alkalmazást</string>
<string name="prefs_instant_upload">Azonnali képfeltöltések</string>
<string name="prefs_instant_upload_summary">Kamera által készítette képek azonnali feltöltése</string>
<string name="prefs_instant_video_upload">Azonnali video feltöltések</string>
<string name="sync_string_files">Fájlok</string>
<string name="setup_btn_connect">Kapcsolódás</string>
<string name="uploader_btn_upload_text">Feltöltés</string>
+ <string name="uploader_btn_new_folder_text">Új mappa</string>
<string name="uploader_top_message">Válassz feltöltési mappát:</string>
<string name="uploader_wrn_no_account_title">Nincs ilyen felhasználói fiók</string>
<string name="uploader_wrn_no_account_text">Nem található %1$s fiók ezen a készüléken. Hozzon létre egy fiókot előbb.</string>
<string name="uploader_info_uploading">Feltöltés</string>
<string name="file_list_seconds_ago">pár másodperce</string>
<string name="file_list_empty">Itt nincs semmi. Töltsön fel valamit!</string>
- <string name="file_list_loading">Betöltés...</string>
<string name="local_file_list_empty">Nincs fájl ebben a mappában.</string>
<string name="filedetails_select_file">Érintsen meg egy fájlt a további információkért.</string>
<string name="filedetails_size">Méret:</string>
<string name="foreign_files_local_text">Helyi: %1$s</string>
<string name="foreign_files_remote_text">Távoli: %1$s</string>
<string name="upload_query_move_foreign_files">Nincs elég hely a kiválasztott fájlok másolására a %1$s könyvtárban. Szeretnéd áthelyezni inkább?</string>
- <string name="pincode_enter_pin_code">Kérem adja meg az alkalmazás PIN-kódját</string>
- <string name="pincode_configure_your_pin">Az alkalmazás PIN-kódja</string>
- <string name="pincode_configure_your_pin_explanation">A PIN-t kötelező lesz megadni az alkalmazás minden indításakor</string>
- <string name="pincode_reenter_your_pincode">Kérem, adja meg újra az alkalmazás PIN-kódját</string>
- <string name="pincode_remove_your_pincode">Az alkalmazás PIN-kódjának eltávolítása</string>
- <string name="pincode_mismatch">A megadott PIN-ek nem egyeznek meg</string>
- <string name="pincode_wrong">Rossz a megadott PIN</string>
- <string name="pincode_removed">Az alkalmazás PIN-ját eltávolítottuk</string>
- <string name="pincode_stored">Az alkalmazás PIN-jét eltároltuk</string>
<string name="media_notif_ticker">%1$s zene lejátszó</string>
<string name="media_state_playing">%1$s (lejátszás)</string>
<string name="media_state_loading">%1$s (betöltés)</string>
<string name="auth_no_net_conn_title">Nincs hálózati kapcsolat</string>
<string name="auth_nossl_plain_ok_title">Nem érhető el biztonságos kapcsolat.</string>
<string name="auth_connection_established">A kapcsolat létrejött</string>
- <string name="auth_testing_connection">Kapcsolat tesztelése...</string>
<string name="auth_not_configured_title">Hibás a kiszolgáló beállítása</string>
<string name="auth_account_not_new">Egy bejelentkezési beállítás már létezik ugyanehhez a kiszolgálóhoz és felhasználóhoz</string>
<string name="auth_account_not_the_same">A megadott felhasználó nem azonos ezzel a belépési jogosultsággal</string>
<string name="clipboard_text_copied">Bemásolva a vágólapra</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Fiókok</string>
+ <string name="prefs_add_account">Fiók hozzáadása</string>
+ <string name="actionbar_logger">Naplók</string>
<string name="saml_authentication_required_text">Felhasználóazonosítás szükséges</string>
<string name="saml_authentication_wrong_pass">Hibás jelszó</string>
- <string name="move_choose_button_text">Válasszon</string>
+ <string name="actionbar_move">Mozgatás</string>
+ <string name="folder_picker_choose_button_text">Válasszon</string>
<string name="prefs_category_security">Biztonság</string>
+ <string name="auth_host_address">A kiszolgáló címe</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="filedetails_download">Բեռնել</string>
<string name="empty"></string>
</resources>
<string name="actionbar_send_file">Invia</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">General</string>
<string name="prefs_category_more">Plus</string>
+ <string name="prefs_accounts">Contos</string>
+ <string name="prefs_log_delete_history_button">Deler historia</string>
<string name="prefs_help">Adjuta</string>
<string name="auth_username">Nomine de usator</string>
<string name="auth_password">Contrasigno</string>
<string name="sync_string_files">Files</string>
<string name="setup_btn_connect">Connecte</string>
<string name="uploader_btn_upload_text">Incargar</string>
+ <string name="uploader_btn_new_folder_text">Nove dossier</string>
+ <string name="uploader_wrn_no_account_title">Nulle contos trovate</string>
<string name="file_list_seconds_ago">secundas passate</string>
<string name="file_list_empty">Nihil hic. Incarga alcun cosa!</string>
+ <string name="filedetails_size">Dimension:</string>
+ <string name="filedetails_type">Typo:</string>
<string name="filedetails_download">Discargar</string>
<string name="action_share_file">Compartir ligamine</string>
<string name="common_yes">Si</string>
<string name="common_no">No</string>
<string name="common_ok">Ok</string>
+ <string name="common_cancel_download">Cancellar discarga</string>
<string name="common_cancel">Cancellar</string>
<string name="common_error">Error</string>
<string name="common_error_unknown">Error Incognite</string>
<string name="change_password">Cambiar contrasigno</string>
+ <string name="delete_account">Deler conto</string>
<string name="uploader_info_dirname">Nomine de dossier</string>
<string name="activity_chooser_send_file_title">Invia</string>
<string name="empty"></string>
- <string name="move_choose_button_text">Seliger</string>
+ <string name="prefs_category_accounts">Contos</string>
+ <string name="saml_authentication_wrong_pass">Contrasigno errate</string>
+ <string name="folder_picker_choose_button_text">Seliger</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Semua berkas</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Pengaturan</string>
+ <string name="drawer_item_logs">Log</string>
+ <string name="drawer_close">Tutup</string>
<string name="prefs_category_general">Umum</string>
<string name="prefs_category_more">Lainnya</string>
<string name="prefs_accounts">Akun</string>
<string name="prefs_manage_accounts">Kelola Akun</string>
- <string name="prefs_pincode">PIN Apl</string>
- <string name="prefs_pincode_summary">Lindungi klien Anda</string>
+ <string name="prefs_passcode">Kunci kode sandi</string>
<string name="prefs_instant_upload">Unggah gambar cepat</string>
<string name="prefs_instant_upload_summary">Unggah gambar yang diambil kamera dengan cepat</string>
<string name="prefs_instant_video_upload">Unggah video cepat</string>
<string name="sync_string_files">Berkas</string>
<string name="setup_btn_connect">Sambungkan</string>
<string name="uploader_btn_upload_text">Unggah</string>
+ <string name="uploader_btn_new_folder_text">Folder baru</string>
<string name="uploader_top_message">Pilih folder unggah:</string>
<string name="uploader_wrn_no_account_title">Tidak ada akun yang ditemukan</string>
<string name="uploader_wrn_no_account_text">Belum ada akun %1$s pada perangkat Anda. Silahkan buat akun terlebih dahulu.</string>
<string name="filedetails_download">Unduh</string>
<string name="filedetails_sync_file">Segarkan berkas</string>
<string name="filedetails_renamed_in_upload_msg">Berkas diubah namanya menjadi %1$s saat pengunggahan</string>
+ <string name="list_layout">Daftar Tata Letak</string>
<string name="action_share_file">Bagikan tautan</string>
<string name="action_unshare_file">Batal bagikan tautan</string>
<string name="common_yes">Ya</string>
<string name="sync_fail_in_favourites_content">Konten berkas %1$d tidak dapat disinkronasikan (%2$d konflik)</string>
<string name="sync_foreign_files_forgotten_ticker">Beberapa berkas lokal terlupakan</string>
<string name="sync_foreign_files_forgotten_content">%1$d berkas diluar folder %2$s tidak dapat disalin kedalamnya</string>
- <string name="sync_foreign_files_forgotten_explanation">Sejak versi 1.3.16, berkas-berkas yang diunggah dari piranti ini akan disalin kedalam folder %1$s lokal untuk mencagah kehilangan data saat berkas tunggal disinkronkan dengan akun lebih dari satu.\n\nAkibat perubahan ini, semua berkas yang diunggah di versi aplikasi sebelumnya disalin kedalam folder %2$s. Namun, sebuah kesalahan mencegah penyelesaian operasi ini saat sinkronisasi akun. Anda boleh meninggalkan berkas seperti ini dan menghapus tautan ke %3$s atau memindahkan berkas kedalam folder %1$s dan membiarkan tautan ke %4$s.\n\nYang tampak dibawah adalah berkas lokal, dan berkas remote didalam %5$s yang dihubungkan dengannya.</string>
+ <string name="sync_foreign_files_forgotten_explanation">Sejak versi 1.3.16, berkas-berkas yang diunggah dari perangkat ini akan disalin kedalam folder %1$s lokal untuk mencagah kehilangan data saat berkas tunggal disinkronkan dengan akun lebih dari satu.\n\nAkibat perubahan ini, semua berkas yang diunggah di versi aplikasi sebelumnya disalin kedalam folder %2$s. Namun, sebuah kesalahan mencegah penyelesaian operasi ini saat sinkronisasi akun. Anda boleh meninggalkan berkas seperti ini dan menghapus tautan ke %3$s atau memindahkan berkas kedalam folder %1$s dan membiarkan tautan ke %4$s.\n\nYang tampak dibawah adalah berkas lokal, dan berkas remote didalam %5$s yang dihubungkan dengannya.</string>
<string name="sync_current_folder_was_removed">Folder %1$s tidak ada lagi</string>
<string name="foreign_files_move">Pindahkan semua</string>
<string name="foreign_files_success">Semua berkas sudah dipindahkan</string>
<string name="foreign_files_local_text">Lokal: %1$s</string>
<string name="foreign_files_remote_text">Jauh: %1$s</string>
<string name="upload_query_move_foreign_files">Ruang tidak cukup untuk menyalin berkas terpilih kedalam folder %1$s. Apakah Anda ingin memindahkannya saja?</string>
- <string name="pincode_enter_pin_code">Silakan masukkan PIN Apl</string>
- <string name="pincode_configure_your_pin">Masukkan PIN Apl</string>
- <string name="pincode_configure_your_pin_explanation">PIN akan selalu diminta setiap kali apl dijalankan</string>
- <string name="pincode_reenter_your_pincode">Silakan masukkan ulang PIN Apl</string>
- <string name="pincode_remove_your_pincode">Hapus PIN Apl</string>
- <string name="pincode_mismatch">PIN Apl tidak sama</string>
- <string name="pincode_wrong">PIN Apl salah</string>
- <string name="pincode_removed">PIN Apl dihapus</string>
- <string name="pincode_stored">PIN Apl disimpan</string>
+ <string name="pass_code_enter_pass_code">Silakan masukkan kode sandi Anda</string>
+ <string name="pass_code_configure_your_pass_code">Masukkan kode sandi Anda</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Kode sandi akan diminta setiap kali apl dijalankan.</string>
+ <string name="pass_code_reenter_your_pass_code">Silakan masukkan ulang kode sandi Anda</string>
+ <string name="pass_code_remove_your_pass_code">Hapus kode sandi Anda</string>
+ <string name="pass_code_mismatch">Kode sandi tidak sama</string>
+ <string name="pass_code_wrong">Kode sandi salah</string>
+ <string name="pass_code_removed">Kode sandi dihapus</string>
+ <string name="pass_code_stored">Kode sandi disimpan</string>
<string name="media_notif_ticker">Pemutar musik %1$s</string>
<string name="media_state_playing">%1$s (dimainkan)</string>
<string name="media_state_loading">%1$s (sedang dimuat)</string>
<string name="auth_no_net_conn_title">Tidak ada koneksi internet</string>
<string name="auth_nossl_plain_ok_title">Sambungan aman tidak tersedia</string>
<string name="auth_connection_established">Sambungan dibuat</string>
- <string name="auth_testing_connection">Pengetesan koneksi ...</string>
+ <string name="auth_testing_connection">Mencoba sambungan</string>
<string name="auth_not_configured_title">Konfigurasi server cacat</string>
<string name="auth_account_not_new">Akun untuk pengguna dan server yang sama sudah ada dalam perangkat</string>
<string name="auth_account_not_the_same">Pengguna yang dimasukkan tidak cocok dengan pengguna akun ini</string>
<string name="auth_fail_get_user_name">Server Anda tidak membalas id pengguna dengan banar, Sialakn hubungi Administrator
</string>
<string name="auth_can_not_auth_against_server">Tidak dapat mengotentikasi pada server ini</string>
+ <string name="auth_account_does_not_exist">Akun tidak ada di perangkat ini</string>
<string name="fd_keep_in_sync">Biarkan berkas tetap terbaru</string>
<string name="common_rename">Ubah nama</string>
<string name="common_remove">Hapus</string>
<string name="sync_file_nothing_to_do_msg">Isi berkas sudah diselaraskan</string>
<string name="create_dir_fail_msg">Folder tidak dapat dibuat</string>
<string name="filename_forbidden_characters">Karakter yang dilarang: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Nama berkas berisi setidaknya satu karakter yang tidak sah</string>
<string name="filename_empty">Nama berkas tidak boleh kosong</string>
<string name="wait_a_moment">Tunggu sebentar</string>
<string name="filedisplay_unexpected_bad_get_content">Masalah tidak terduga, silahkan pilih berkas dari apl yang berbeda</string>
<string name="filedisplay_no_file_selected">Tidak ada berkas yang terpilih</string>
<string name="activity_chooser_title">Kirim taukan ke</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Menyalin berkas dari penyimpanan pribadi</string>
<string name="oauth_check_onoff">Masuk dengan oAuth2</string>
<string name="oauth_login_connection">Menyambungkan ke server oAuth2...</string>
<string name="ssl_validator_header">Identitas situs tidak dapat diverfikasi</string>
<string name="share_link_file_error">Terjadi kesalahan saat mencoba membagikan berkas atau folder ini</string>
<string name="unshare_link_file_no_exist">Tidak dapat menghapus berbagi. Mohon periksa apakah berkas ada</string>
<string name="unshare_link_file_error">Terjadi kesalahan saat mencoba menghapus berbagi berkas dan folder ini</string>
+ <string name="share_link_password_title">Masukkan sandi</string>
+ <string name="share_link_empty_password">Anda harus memasukkan sandi</string>
<string name="activity_chooser_send_file_title">Kirim</string>
<string name="copy_link">Salin tautan</string>
<string name="clipboard_text_copied">Disalin ke papan klip</string>
<string name="auth_redirect_non_secure_connection_title">Sambungan aman dialihkan ke rute yang tidak aman.</string>
<string name="actionbar_logger">Log</string>
<string name="log_send_history_button">Kirim Riwayat</string>
- <string name="log_mail_subject">Log apl ownCloud Android</string>
+ <string name="log_send_no_mail_app">Tidak ada apl untuk mengirim log. Instal apl mail!</string>
+ <string name="log_send_mail_subject">%1$s Android apl log</string>
<string name="log_progress_dialog_text">Memuat data...</string>
<string name="saml_authentication_required_text">Diperlukan otentikasi</string>
<string name="saml_authentication_wrong_pass">Sandi salah</string>
<string name="actionbar_move">Pindah</string>
<string name="file_list_empty_moving">Tdak ada apapun disini. Anda dapat menambahkan sebuah folder!</string>
- <string name="move_choose_button_text">Pilih</string>
+ <string name="folder_picker_choose_button_text">Pilih</string>
<string name="move_file_not_found">Tidak dapat memindahkan. Silakan periksa apakah berkas ada</string>
<string name="move_file_invalid_into_descendent">Tidak mungkin untuk memindahkan folder kedalam turunannya</string>
<string name="move_file_invalid_overwrite">Berkas sudah ada didalam folder tujuan</string>
<string name="forbidden_permissions_move">untuk memindahkan berkas ini</string>
<string name="prefs_category_instant_uploading">Unggah Cepat</string>
<string name="prefs_category_security">Keamanan</string>
+ <string name="prefs_instant_video_upload_path_title">Unggah Lokasi Video</string>
+ <string name="download_folder_failed_content">Mengunduh folder %1$s tidak selesai</string>
+ <string name="shared_subject_header">dibagikan</string>
+ <string name="with_you_subject_header">kepada Anda</string>
+ <string name="subject_token">%1$s dibagikan \"%2$s\" kepada Anda</string>
+ <string name="auth_refresh_button">Menyegarkan sambungan</string>
+ <string name="auth_host_address">Alamat server</string>
+ <string name="common_error_out_memory">Memori tidak cukup</string>
+ <string name="username">Nama pengguna</string>
+ <string name="file_list__footer__folder">1 folder</string>
+ <string name="file_list__footer__folders">%1$d folder</string>
+ <string name="file_list__footer__file">1 berkas</string>
+ <string name="file_list__footer__file_and_folder">1 berkas, 1 folder</string>
+ <string name="file_list__footer__file_and_folders">1 berkas, %1$d folder</string>
+ <string name="file_list__footer__files">%1$d berkas</string>
+ <string name="file_list__footer__files_and_folder">%1$d berkas, 1 folder</string>
+ <string name="file_list__footer__files_and_folders">%1$d berkas, %2$d folder</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_send_file">Senda</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_more">Meira</string>
<string name="prefs_help">Hjálp</string>
<string name="auth_username">Notendanafn</string>
<string name="common_remove">Fjarlægja</string>
<string name="activity_chooser_send_file_title">Senda</string>
<string name="empty"></string>
- <string name="move_choose_button_text">Veldu</string>
+ <string name="folder_picker_choose_button_text">Veldu</string>
+ <string name="auth_host_address">Host nafn netþjóns</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Tutti i file</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Impostazioni</string>
+ <string name="drawer_item_logs">Registri</string>
+ <string name="drawer_close">Chiudi</string>
<string name="prefs_category_general">Generale</string>
<string name="prefs_category_more">Altro</string>
<string name="prefs_accounts">Account</string>
<string name="prefs_manage_accounts">Gestisci account</string>
- <string name="prefs_pincode">PIN App</string>
- <string name="prefs_pincode_summary">Proteggi il tuo client l\'applicazione</string>
+ <string name="prefs_passcode">Blocco con codice di sicurezza</string>
<string name="prefs_instant_upload">Caricamenti istantanei delle foto</string>
<string name="prefs_instant_upload_summary">Carica immediatamente le foto dalla fotocamera</string>
<string name="prefs_instant_video_upload">Caricamenti istantanei dei video</string>
<string name="prefs_log_summary_history">Mostra i log registrati</string>
<string name="prefs_log_delete_history_button">Elimina la cronologia</string>
<string name="prefs_help">Aiuto</string>
- <string name="prefs_recommend">Consiglia ad un amico</string>
+ <string name="prefs_recommend">Consiglia a un amico</string>
<string name="prefs_feedback">Segnalazioni</string>
<string name="prefs_imprint">Imprint</string>
<string name="prefs_remember_last_share_location">Ricorda la posizione della condivisione</string>
<string name="sync_string_files">File</string>
<string name="setup_btn_connect">Connetti</string>
<string name="uploader_btn_upload_text">Carica</string>
+ <string name="uploader_btn_new_folder_text">Nuova cartella</string>
<string name="uploader_top_message">Scegli la cartella da caricare:</string>
<string name="uploader_wrn_no_account_title">Nessun account trovato</string>
<string name="uploader_wrn_no_account_text">Non ci sono account %1$s sul tuo dispositivo. Configura prima un account.</string>
<string name="filedetails_download">Scarica</string>
<string name="filedetails_sync_file">Aggiorna file</string>
<string name="filedetails_renamed_in_upload_msg">Il file è stato rinominato in %1$s durante il caricamento</string>
+ <string name="list_layout">Struttura elenco</string>
<string name="action_share_file">Condividi collegamento</string>
<string name="action_unshare_file">Rimuovi condivisione collegamento</string>
<string name="common_yes">Sì</string>
<string name="foreign_files_local_text">Locale: %1$s</string>
<string name="foreign_files_remote_text">Remoto %1$s</string>
<string name="upload_query_move_foreign_files">Non c\'è spazio sufficiente per copiare i file selezionati nella cartella %1$s. Vuoi invece spostarli?</string>
- <string name="pincode_enter_pin_code">Inserisci il PIN dell\'applicazione</string>
- <string name="pincode_configure_your_pin">Inserisci il PIN di l\'applicazione</string>
- <string name="pincode_configure_your_pin_explanation">Il PIN sarà richiesto ad ogni avvio dell\'applicazione</string>
- <string name="pincode_reenter_your_pincode">Inserisci nuovamente il PIN di l\'applicazione</string>
- <string name="pincode_remove_your_pincode">Rimuovi il PIN di l\'applicazione</string>
- <string name="pincode_mismatch">I PIN di l\'applicazione non corrispondono</string>
- <string name="pincode_wrong">PIN di l\'applicazione non corretto</string>
- <string name="pincode_removed">PIN di l\'applicazione rimosso</string>
- <string name="pincode_stored">PIN di l\'applicazione memorizzato</string>
+ <string name="pass_code_enter_pass_code">Digita il tuo codice segreto</string>
+ <string name="pass_code_configure_your_pass_code">Digita il tuo codice segreto</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Il codice segreto sarà richiesto ogni volta che l\'applicazione è avviata</string>
+ <string name="pass_code_reenter_your_pass_code">Digita nuovamente il tuo codice segreto</string>
+ <string name="pass_code_remove_your_pass_code">Rimuovi il tuo codice segreto</string>
+ <string name="pass_code_mismatch">I codici segreti non corrispondono</string>
+ <string name="pass_code_wrong">Codice segreto non corretto</string>
+ <string name="pass_code_removed">Codice segreto rimosso</string>
+ <string name="pass_code_stored">Codice segreto memorizzato</string>
<string name="media_notif_ticker">Lettore musicale %1$s</string>
<string name="media_state_playing">%1$s (in riproduzione)</string>
<string name="media_state_loading">%1$s (in caricamento)</string>
<string name="auth_no_net_conn_title">Nessuna connessione di rete</string>
<string name="auth_nossl_plain_ok_title">Connessione sicura disponibile.</string>
<string name="auth_connection_established">Connessione stabilita</string>
- <string name="auth_testing_connection">Prova di connessione in corso...</string>
+ <string name="auth_testing_connection">Prova di connessione</string>
<string name="auth_not_configured_title">Configurazione non corretta di il server</string>
<string name="auth_account_not_new">Esiste già un account su questo dispositivo per lo stesso utente e server</string>
<string name="auth_account_not_the_same">L\'utente digitato non corrisponde all\'utente di questo account</string>
<string name="auth_fail_get_user_name">Il tuo server non ha restituito un id utente corretto, contatta un amministratore
</string>
<string name="auth_can_not_auth_against_server">Impossibile eseguire l\'autenticazione su questo server</string>
+ <string name="auth_account_does_not_exist">L\'account non esiste ancora sul dispositivo</string>
<string name="fd_keep_in_sync">Tieni aggiornato il file</string>
<string name="common_rename">Rinomina</string>
<string name="common_remove">Rimuovi</string>
<string name="sync_file_nothing_to_do_msg">Contenuti del file già sincronizzati</string>
<string name="create_dir_fail_msg">La cartella non può essere creata</string>
<string name="filename_forbidden_characters">Caratteri proibiti: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Il nome del file contiene almeno un carattere non valido</string>
<string name="filename_empty">Il nome del file non può essere vuoto</string>
<string name="wait_a_moment">Attendi</string>
<string name="filedisplay_unexpected_bad_get_content">Problema inatteso; prova un\'altra applicazione per selezionare il file</string>
<string name="filedisplay_no_file_selected">Non è stato selezionato alcun file</string>
<string name="activity_chooser_title">Invia collegamento a...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Copia file dall\'archiviazione privata</string>
<string name="oauth_check_onoff">Accesso con oAuth2.</string>
<string name="oauth_login_connection">Connessione al server oAuth2 in corso...</string>
<string name="ssl_validator_header">L\'identità del sito non può essere verificata</string>
<string name="share_link_file_error">Si è verificato un errore durante il tentativo di condivisione del file o della cartella</string>
<string name="unshare_link_file_no_exist">Impossibile rimuovere dalla condivisione. Assicurati che il file esista</string>
<string name="unshare_link_file_error">Si è verificato un errore durante il tentativo di rimuovere la condivisione del file o della cartella</string>
+ <string name="share_link_password_title">Digita una password</string>
+ <string name="share_link_empty_password">Devi digitare una password</string>
<string name="activity_chooser_send_file_title">Invia</string>
<string name="copy_link">Copia collegamento</string>
<string name="clipboard_text_copied">Copiato negli appunti</string>
<string name="auth_redirect_non_secure_connection_title">La connessione sicura è rediretta su un percorso non sicuro.</string>
<string name="actionbar_logger">Registri</string>
<string name="log_send_history_button">Invia cronologia</string>
- <string name="log_mail_subject">Registri applicazione ownCloud Android</string>
- <string name="log_progress_dialog_text">Caricamento dati...</string>
+ <string name="log_send_no_mail_app">Non è stata trovata alcuna applicazione per l\'invio dei registri. Installa l\'applicazione mail!</string>
+ <string name="log_send_mail_subject">Registri applicazione %1$s Android</string>
+ <string name="log_progress_dialog_text">Caricamento dati in corso...</string>
<string name="saml_authentication_required_text">Autenticazione richiesta</string>
<string name="saml_authentication_wrong_pass">Password errata</string>
<string name="actionbar_move">Sposta</string>
<string name="file_list_empty_moving">Qui non c\'è niente. Puoi aggiungere una cartella.</string>
- <string name="move_choose_button_text">Scegli</string>
+ <string name="folder_picker_choose_button_text">Scegli</string>
<string name="move_file_not_found">Impossibile spostare. Assicurati che il file esista</string>
<string name="move_file_invalid_into_descendent">Impossibile spostare una cartella in una cartella inferiore</string>
<string name="move_file_invalid_overwrite">Il file esiste già nella cartella di destinazione</string>
<string name="forbidden_permissions_move">per spostare questo file</string>
<string name="prefs_category_instant_uploading">Caricamenti istantanei</string>
<string name="prefs_category_security">Protezione</string>
+ <string name="prefs_instant_video_upload_path_title">Percorso di caricamento video</string>
+ <string name="download_folder_failed_content">Lo scaricamento della cartella %1$s non può essere completato</string>
+ <string name="shared_subject_header">condiviso</string>
+ <string name="with_you_subject_header">con te</string>
+ <string name="subject_token">%1$s ha condiviso \"%2$s\" con te</string>
+ <string name="auth_refresh_button">Aggiorna la connessione</string>
+ <string name="auth_host_address">Indirizzo del server</string>
+ <string name="common_error_out_memory">Memoria insufficiente</string>
+ <string name="username">Nome utente</string>
+ <string name="file_list__footer__folder">1 cartella</string>
+ <string name="file_list__footer__folders">%1$d cartelle</string>
+ <string name="file_list__footer__file">1 file</string>
+ <string name="file_list__footer__file_and_folder">1 file, 1 cartella</string>
+ <string name="file_list__footer__file_and_folders">1 file, %1$d cartelle</string>
+ <string name="file_list__footer__files">%1$d file</string>
+ <string name="file_list__footer__files_and_folder">%1$d file, 1 cartella</string>
+ <string name="file_list__footer__files_and_folders">%1$d file, %2$d cartelle</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">すべてのファイル</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">設定</string>
+ <string name="drawer_item_logs">ログ</string>
+ <string name="drawer_close">閉じる</string>
<string name="prefs_category_general">一般</string>
<string name="prefs_category_more">もっと見る</string>
<string name="prefs_accounts">アカウント</string>
<string name="prefs_manage_accounts">アカウント管理</string>
- <string name="prefs_pincode">アプリのパスワード</string>
- <string name="prefs_pincode_summary">クライアントを保護する</string>
+ <string name="prefs_passcode">パスコードロック</string>
<string name="prefs_instant_upload">自動画像アップロード</string>
<string name="prefs_instant_upload_summary">カメラで撮影した画像を自動アップロード</string>
<string name="prefs_instant_video_upload">自動動画アップロード</string>
<string name="sync_string_files">ファイル</string>
<string name="setup_btn_connect">接続</string>
<string name="uploader_btn_upload_text">アップロード</string>
+ <string name="uploader_btn_new_folder_text">新しいフォルダー</string>
<string name="uploader_top_message">アップロードするフォルダーを選択:</string>
<string name="uploader_wrn_no_account_title">アカウントが見つかりません</string>
<string name="uploader_wrn_no_account_text">デバイスに%1$sのアカウントがありません。まず最初にアカウントを登録してください。</string>
<string name="uploader_info_uploading">アップロード中</string>
<string name="file_list_seconds_ago">数秒前</string>
<string name="file_list_empty">ここには何もありません。何かアップロードしてください。</string>
- <string name="file_list_loading">読込中 ...</string>
<string name="local_file_list_empty">このフォルダーにはファイルがありません。</string>
<string name="filedetails_select_file">ファイルをタップすると追加情報が表示されます。</string>
<string name="filedetails_size">サイズ:</string>
<string name="foreign_files_local_text">ローカル: %1$s</string>
<string name="foreign_files_remote_text">リモート: %1$s</string>
<string name="upload_query_move_foreign_files">十分なスペースがないため、選択されたファイルを %1$s フォルダーにコピーすることができません。コピーする代わりに、それらを移動させますか?</string>
- <string name="pincode_enter_pin_code">アプリのパスワードを入力してください</string>
- <string name="pincode_configure_your_pin">アプリのパスワードを入力してください</string>
- <string name="pincode_configure_your_pin_explanation">アプリ開始時に毎回PINが要求されます。</string>
- <string name="pincode_reenter_your_pincode">アプリのパスワードを再入力してください</string>
- <string name="pincode_remove_your_pincode">アプリのパスワードを削除</string>
- <string name="pincode_mismatch">アプリのパスワードが一致しません</string>
- <string name="pincode_wrong">無効なアプリのパスワードです</string>
- <string name="pincode_removed">アプリのパスワードを削除しました</string>
- <string name="pincode_stored">アプリのパスワードを保存しました</string>
+ <string name="pass_code_configure_your_pass_code">パスコードを入力</string>
+ <string name="pass_code_reenter_your_pass_code">パスコードを再入力してください</string>
+ <string name="pass_code_remove_your_pass_code">パスコードを削除</string>
+ <string name="pass_code_wrong">パスコードが正しくありません</string>
+ <string name="pass_code_removed">パスコードを削除しました</string>
+ <string name="pass_code_stored">パスコードを保存しました</string>
<string name="media_notif_ticker">%1$s ミュージックプレーヤー</string>
<string name="media_state_playing">%1$s (プレイ中)</string>
<string name="media_state_loading">%1$s (読込中)</string>
<string name="auth_no_net_conn_title">ネットワークに接続されていません</string>
<string name="auth_nossl_plain_ok_title">暗号化通信が利用できません。</string>
<string name="auth_connection_established">接続が確立しました</string>
- <string name="auth_testing_connection">æ\8e¥ç¶\9aã\82\92ã\83\86ã\82¹ã\83\88ä¸...</string>
+ <string name="auth_testing_connection">æ\8e¥ç¶\9aã\81®ã\83\86ã\82¹ã\83\88ä¸</string>
<string name="auth_not_configured_title">サーバー設定が間違っています</string>
<string name="auth_account_not_new">同じユーザーとサーバーのアカウントがデバイス上にすでに存在します</string>
<string name="auth_account_not_the_same">入力されたユーザーはこのアカウントのユーザーと一致しません</string>
<string name="auth_connecting_auth_server">認証サーバーに接続中 ...</string>
<string name="auth_unsupported_auth_method">サーバーはこの認証方式をサポートしていません</string>
<string name="auth_unsupported_multiaccount">%1$s は複数アカウントをサポートしていません</string>
- <string name="auth_fail_get_user_name">サーバーが正しいユーザーIDを返しませんでした。管理者にご連絡ください。
+ <string name="auth_fail_get_user_name">サーバーが正しいユーザーIDを返しませんでした。管理者に問い合わせてください。
</string>
<string name="auth_can_not_auth_against_server">このサーバーに対して認証できません</string>
+ <string name="auth_account_does_not_exist">デバイス上にまだアカウントが存在しません</string>
<string name="fd_keep_in_sync">ファイルを最新に保つ</string>
<string name="common_rename">名前を変更</string>
<string name="common_remove">削除</string>
<string name="placeholder_filesize">389 KB</string>
<string name="placeholder_timestamp">2012/05/18 12:23 PM</string>
<string name="placeholder_media_time">12:23:45</string>
- <string name="instant_upload_on_wifi">WiFi経由でのみ写真をアップロード</string>
+ <string name="instant_upload_on_wifi">WiFi経由でのみ画像をアップロード</string>
<string name="instant_video_upload_on_wifi">WiFi経由でのみ動画をアップロード</string>
<string name="instant_upload_path">/InstantUpload</string>
<string name="conflict_title">更新が競合</string>
<string name="preview_image_error_unknown_format">この画像は表示できません</string>
<string name="error__upload__local_file_not_copied">%1$s は、ローカルフォルダー %2$s にコピーできませんでした。</string>
<string name="prefs_instant_upload_path_title">アップロードパス</string>
- <string name="share_link_no_support_share_api">申し訳ございません。共有がサーバー上で有効になっていません。 管理者に
- ご連絡ください。</string>
+ <string name="share_link_no_support_share_api">すみませんが、サーバーで共有が有効になっていません。
+ 管理者に問い合わせてください。</string>
<string name="share_link_file_no_exist">共有できません。ファイルがあるか確認してください。</string>
<string name="share_link_file_error">このファイルまたはフォルダーを共有する際にエラーが発生しました</string>
<string name="unshare_link_file_no_exist">共有を解除できません。ファイルがあるか確認してください。</string>
<string name="unshare_link_file_error">このファイルまたはフォルダーの共有を解除する際にエラーが発生しました</string>
+ <string name="share_link_password_title">パスワードを入力</string>
+ <string name="share_link_empty_password">パスワードを入力しなければなりません</string>
<string name="activity_chooser_send_file_title">送信</string>
<string name="copy_link">リンクをコピー</string>
<string name="clipboard_text_copied">クリップボードにコピー</string>
<string name="auth_redirect_non_secure_connection_title">暗号化接続は非暗号化接続にリダイレクトされました。</string>
<string name="actionbar_logger">ログ</string>
<string name="log_send_history_button">ログを送信</string>
- <string name="log_mail_subject">ownCloud Android アプリログ</string>
+ <string name="log_send_no_mail_app">ログを送信するアプリが見つかりませんでした。メールアプリをインストールしてください。</string>
+ <string name="log_send_mail_subject">%1$s アンドロイドアプリログ</string>
<string name="log_progress_dialog_text">読込中 ...</string>
<string name="saml_authentication_required_text">認証を必要とする</string>
<string name="saml_authentication_wrong_pass">無効なパスワード</string>
<string name="actionbar_move">移動</string>
- <string name="file_list_empty_moving">ファイルが有りません。フォルダを追加してください。</string>
- <string name="move_choose_button_text">選択</string>
+ <string name="file_list_empty_moving">何もありません。フォルダーを追加してください。</string>
+ <string name="folder_picker_choose_button_text">選択</string>
<string name="move_file_not_found">移動できません。ファイルがあるか確認してください。</string>
- <string name="move_file_invalid_into_descendent">ã\83\95ã\82©ã\83«ã\83\80ã\82\92å\90ã\83\95ã\82©ã\83«ã\83\80へ移動することはできません。</string>
- <string name="move_file_invalid_overwrite">そのファイルは、宛先フォルダに既に存在しています。</string>
+ <string name="move_file_invalid_into_descendent">ã\83\95ã\82©ã\83«ã\83\80ã\83¼ã\82\92å\90ã\83\95ã\82©ã\83«ã\83\80ã\83¼へ移動することはできません。</string>
+ <string name="move_file_invalid_overwrite">そのファイルは宛先フォルダーにすでに存在します。</string>
<string name="move_file_error">このファイルまたはフォルダーを移動する際にエラーが発生しました</string>
<string name="forbidden_permissions_move">このファイルを移動</string>
<string name="prefs_category_instant_uploading">自動アップロード</string>
<string name="prefs_category_security">セキュリティ</string>
+ <string name="prefs_instant_video_upload_path_title">動画のアップロードパス</string>
+ <string name="download_folder_failed_content">%1$s フォルダーのダウンロードが完了しませんでした</string>
+ <string name="auth_refresh_button">再接続中</string>
+ <string name="auth_host_address">サーバーアドレス</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="filedetails_download">Njipuk</string>
<string name="empty"></string>
</resources>
<string name="actionbar_send_file">გაგზავნა</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">ზოგადი</string>
<string name="prefs_category_more">უფრო მეტი</string>
<string name="prefs_accounts">ანგარიში</string>
<string name="prefs_manage_accounts">ანგარიშების მენეჯმენტი</string>
- <string name="prefs_pincode">აპლიკაციის PIN–ი</string>
- <string name="prefs_pincode_summary">თქვენი კლიენტის დაცვა</string>
<string name="prefs_help">დახმარება</string>
<string name="prefs_feedback">უკუკავშირი</string>
<string name="prefs_imprint">ბეჭედი</string>
<string name="sync_string_files">ფაილები</string>
<string name="setup_btn_connect">დაკავშირება</string>
<string name="uploader_btn_upload_text">ატვირთვა</string>
+ <string name="uploader_btn_new_folder_text">ახალი ფოლდერი</string>
<string name="uploader_wrn_no_account_title">ანგარიში ვერ მოიძებნა</string>
<string name="uploader_wrn_no_account_text"> %1$s ანგარიში არ არის თქვენს მოწყობილობაში. გთხოვთ ჯერ დააყენოთ ის.</string>
<string name="uploader_wrn_no_account_setup_btn_text">დაყენება</string>
<string name="foreign_files_fail">რამოდენიმე ფაილის გადატანა ვერ მოხერხდა</string>
<string name="foreign_files_local_text">ლოკალური: %1$s</string>
<string name="foreign_files_remote_text">დაშორებული: %1$s</string>
- <string name="pincode_enter_pin_code">გთხოვთ, ჩასვათ თქვენი აპლიკაციის PIN–ი</string>
- <string name="pincode_configure_your_pin">შეიყვანეთ თქვენი აპლიკაციის PIN–ი</string>
- <string name="pincode_configure_your_pin_explanation">PIN–ი მოთხოვნილი იქნება აპლიკაციის ყოველ ჩართვაზე</string>
- <string name="pincode_reenter_your_pincode">გთხოვთ შეიყვანოთ თქვენი აპლიკაციის PIN–ი ხელთავიდან</string>
- <string name="pincode_remove_your_pincode">წაშალეთ თქვენი აპლიკაციის PIN–ი</string>
- <string name="pincode_mismatch">აპლიკაციის PIN–ი არ არის იგივე</string>
- <string name="pincode_wrong">არასწორი აპლიკაციის PIN–ი</string>
- <string name="pincode_removed">აპლიკაციის PIN–ი წაიშალა</string>
- <string name="pincode_stored">აპლიკაციის PIN–ი დამახსოვრებულ იქნა</string>
<string name="auth_no_net_conn_title">ქსელური კავშირი არ არის</string>
<string name="auth_nossl_plain_ok_title">დაცული კავშირი არ არსებობს.</string>
<string name="auth_connection_established">კავშირი დამყარდა</string>
<string name="clipboard_text_copied">კოპირებულია კლიპბორდში</string>
<string name="empty"></string>
<string name="prefs_category_accounts">ანგარიში</string>
- <string name="move_choose_button_text">არჩევა</string>
+ <string name="folder_picker_choose_button_text">არჩევა</string>
<string name="prefs_category_security">უსაფრთხოება</string>
+ <string name="auth_host_address">სერვერის მისამართი</string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="about_android">%1$s កម្មវិធីអានដ្រយ</string>
+ <string name="about_version">ជំនាន់ %1$s</string>
+ <string name="actionbar_sync">គណនីឱ្យថ្មីឡើងវិញ</string>
<string name="actionbar_upload">ផ្ទុកឡើង</string>
+ <string name="actionbar_upload_from_apps">មាតិការពីកម្មវិធីផ្សេងទៀត</string>
<string name="actionbar_upload_files">ឯកសារ</string>
+ <string name="actionbar_open_with">បើកជាមួយ</string>
<string name="actionbar_mkdir">ថតថ្មី</string>
<string name="actionbar_settings">ការកំណត់</string>
<string name="actionbar_see_details">ព័ត៌មានលម្អិត</string>
<string name="actionbar_send_file">ផ្ញើ</string>
+ <string name="actionbar_sort">តម្រៀប</string>
+ <string name="actionbar_sort_title">តម្រៀបដោយ</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>ថ្មីបំផុត-ចាស់បំផុត</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">ទូទៅ</string>
<string name="prefs_category_more">ច្រើនទៀត</string>
<string name="prefs_accounts">គណនី</string>
<string name="prefs_manage_accounts">គ្រប់គ្រងគណនី</string>
+ <string name="prefs_log_title">ដំណើរការការចូលទៅកាន់</string>
+ <string name="prefs_log_summary">នេះជាបញ្ហាសម្រាប់អ្នកដែលបានចូលទៅកាន់</string>
+ <string name="prefs_log_title_history">ប្រវត្តិនៃការចូលទៅកាន់</string>
+ <string name="prefs_log_summary_history">នៅទីនេះគឺបង្ហាញការដែលបានចូលទៅកាន់</string>
+ <string name="prefs_log_delete_history_button">លុបប្រវត្តិ</string>
<string name="prefs_help">ជំនួយ</string>
+ <string name="prefs_recommend">ផ្ដល់អនុសាសន៍ទៅកាន់មិត្តភក្ដិ</string>
+ <string name="prefs_feedback">មតិត្រឡប់</string>
<string name="auth_username">ឈ្មោះអ្នកប្រើ</string>
<string name="auth_password">ពាក្យសម្ងាត់</string>
<string name="sync_string_files">ឯកសារ</string>
<string name="setup_btn_connect">ភ្ជាប់</string>
<string name="uploader_btn_upload_text">ផ្ទុកឡើង</string>
+ <string name="uploader_btn_new_folder_text">ថតថ្មី</string>
<string name="uploader_wrn_no_account_title">រកមិនឃើញគណនី</string>
<string name="uploader_wrn_no_account_text">គ្មាន %1$s គណនីលើម៉ាស៊ីនរបស់អ្នកទេ។ សូមរៀបចំគណនីមួយជាមុនសិន។</string>
<string name="uploader_wrn_no_account_setup_btn_text">ដំឡើង</string>
<string name="common_error">កំហុស</string>
<string name="common_loading">កំពុងដំណើរការ</string>
<string name="common_error_unknown">មិនស្គាល់កំហុស</string>
+ <string name="about_title">អំពី</string>
<string name="change_password">ប្តូរពាក្យសម្ងាត់</string>
<string name="delete_account">លប់គណនី</string>
<string name="create_account">បង្កើតគណនី</string>
<string name="downloader_download_failed_ticker">ការទាញយកបានបរាជ័យ</string>
<string name="common_choose_account">ជ្រើសគណនី</string>
<string name="foreign_files_move">ផ្លាស់ទីទាំងអស់</string>
- <string name="pincode_enter_pin_code">សូម ដាក់បញ្ចូល App PIN របស់អ្នក</string>
- <string name="pincode_configure_your_pin">បញ្ចូល App PIN របស់អ្នក</string>
- <string name="pincode_reenter_your_pincode">សូម បញ្ចូល App PIN របស់អ្នកម្តងទៀត</string>
- <string name="pincode_remove_your_pincode">លុប App PIN របស់អ្នក</string>
- <string name="pincode_mismatch">App PIN ទាំងនេះមិនដូចគ្នាទេ</string>
- <string name="pincode_wrong">App PIN មិនត្រឹមត្រូវទេ</string>
- <string name="pincode_removed">App PIN បានលុបចេញហើយ</string>
- <string name="pincode_stored">App PIN បានយកមកវិញ</string>
<string name="auth_trying_to_login">កំពុងតែព្យាយាមដើម្បីចូល...</string>
<string name="auth_no_net_conn_title">គ្មានបណ្តាញតភ្ជាប់ទេ</string>
- <string name="auth_testing_connection">ការតភ្ជាប់កំពុងតែធ្វើតេស្ត...</string>
<string name="auth_unknown_error_title">មិនស្គាល់កំហុសបានកើតឡើង!</string>
<string name="fd_keep_in_sync">រក្សាឯកសាររហូតដល់កាលបរិច្ឆេទ</string>
<string name="common_rename">ប្ដូរឈ្មោះ</string>
<string name="common_remove">ដកចេញ</string>
+ <string name="confirmation_remove_local">ទីកន្លែងតែមួយ</string>
+ <string name="confirmation_remove_remote">ដកចេញពីសឺវឺ</string>
+ <string name="confirmation_remove_remote_and_local">បញ្ជារ និងទីតាំង</string>
<string name="remove_success_msg">ការដកយកចេញបានជោគជ័យ</string>
<string name="remove_fail_msg">ការដកយកចេញបានបរាជ័យ</string>
<string name="rename_dialog_title">បញ្ចូលឈ្មោះថ្មី</string>
<string name="empty"></string>
<string name="prefs_category_accounts">គណនី</string>
<string name="saml_authentication_wrong_pass">ខុសពាក្យសម្ងាត់</string>
- <string name="move_choose_button_text">ជ្រើស</string>
+ <string name="folder_picker_choose_button_text">ជ្រើស</string>
<string name="prefs_category_security">សុវត្ថិភាព</string>
+ <string name="auth_host_address">អាសយដ្ឋានម៉ាស៊ីនបម្រើ</string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="actionbar_upload">ಪೇರಿಸು</string>
+ <string name="actionbar_upload_files">ಕಡತಗಳು</string>
+ <string name="actionbar_mkdir">ಹೊಸ ಕಡತಕೋಶ</string>
+ <string name="actionbar_settings">ಆಯ್ಕೆ</string>
+ <string name="actionbar_send_file">ಕಳುಹಿಸಿ</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="prefs_category_more">ಇನ್ನಷ್ಟು</string>
+ <string name="prefs_help">ಸಹಾಯ</string>
+ <string name="prefs_imprint">ಮುದ್ರೆ</string>
+ <string name="auth_username">ಬಳಕೆಯ ಹೆಸರು</string>
+ <string name="auth_password">ಗುಪ್ತ ಪದ</string>
+ <string name="sync_string_files">ಕಡತಗಳು</string>
+ <string name="uploader_btn_upload_text">ಪೇರಿಸು</string>
+ <string name="uploader_btn_new_folder_text">ಹೊಸ ಕಡತಕೋಶ</string>
+ <string name="filedetails_download">ಪ್ರತಿಯನ್ನು ಸ್ಥಳೀಯವಾಗಿ ಉಳಿಸಿಕೊಳ್ಳಿ</string>
+ <string name="action_share_file">ಸಂಪರ್ಕ ಕೊಂಡಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು</string>
+ <string name="common_yes">ಹೌದು</string>
+ <string name="common_no">ಇಲ್ಲ</string>
+ <string name="common_ok">ಸರಿ</string>
+ <string name="common_cancel_upload">ವರ್ಗಾವಣೆ ರದ್ದು ಮಾಡಿ</string>
+ <string name="common_cancel">ರದ್ದು</string>
+ <string name="common_error">ತಪ್ಪಾಗಿದೆ</string>
+ <string name="common_error_unknown">ಗೊತ್ತಿಲ್ಲದ ದೋಷ</string>
+ <string name="change_password">ಗುಪ್ತ ಪದವನ್ನು ಬದಲಾಯಿಸಿ</string>
+ <string name="common_rename">ಮರುಹೆಸರಿಸು</string>
+ <string name="common_remove">ತೆಗೆದುಹಾಕಿ</string>
+ <string name="activity_chooser_send_file_title">ಕಳುಹಿಸಿ</string>
<string name="empty"></string>
+ <string name="saml_authentication_required_text">ದೃಢೀಕರಣ ಅಗತ್ಯವಿದೆ</string>
+ <string name="saml_authentication_wrong_pass">ದುರ್ಬಲ ಗುಪ್ತಪದ</string>
+ <string name="folder_picker_choose_button_text">ಆಯ್ಕೆ</string>
+ <string name="prefs_category_security">ಭದ್ರತೆ</string>
+ <string name="auth_host_address">ಪರಿಚಾರಕ ಗಣಕಯಂತ್ರದ ವಿಳಾಸ</string>
</resources>
<resources>
<string name="about_android">%1$s 안드로이드 앱</string>
<string name="about_version">버전 %1$s</string>
- <string name="actionbar_sync">계정 새로고침</string>
+ <string name="actionbar_sync">계정 새로 고침</string>
<string name="actionbar_upload">업로드</string>
<string name="actionbar_upload_from_apps">다른 앱의 콘텐츠</string>
<string name="actionbar_upload_files">파일</string>
- <string name="actionbar_open_with">로 열기</string>
+ <string name="actionbar_open_with">ë\8b¤ì\9d\8cì\9c¼ë¡\9c ì\97´ê¸°</string>
<string name="actionbar_mkdir">새 폴더</string>
<string name="actionbar_settings">설정</string>
- <string name="actionbar_see_details">ì\84¸ë¶\80ë\82´ì\9a©</string>
+ <string name="actionbar_see_details">ì\9e\90ì\84¸í\95\9c ì \95ë³´</string>
<string name="actionbar_send_file">보내기</string>
+ <string name="actionbar_sort">정렬</string>
+ <string name="actionbar_sort_title">정렬 순서</string>
+ <string-array name="actionbar_sortby">
+ <item>가나다</item>
+ <item>최신 - 이전</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">일반</string>
- <string name="prefs_category_more">더 중요함</string>
+ <string name="prefs_category_more">더 보기</string>
<string name="prefs_accounts">계정</string>
<string name="prefs_manage_accounts">계정 관리</string>
- <string name="prefs_pincode">앱 암호</string>
- <string name="prefs_pincode_summary">내 클라이언트 보호</string>
- <string name="prefs_log_title">로깅 허용</string>
- <string name="prefs_log_summary">이건 로그 문제에 사용됩니다</string>
+ <string name="prefs_passcode">암호 잠금</string>
+ <string name="prefs_instant_upload">사진 즉시 업로드</string>
+ <string name="prefs_instant_upload_summary">카메라로 찍은 사진 즉시 업로드</string>
+ <string name="prefs_instant_video_upload">동영상 즉시 업로드</string>
+ <string name="prefs_instant_video_upload_summary">카메라로 찍은 동영상 즉시 업로드</string>
+ <string name="prefs_log_title">로그 기록 사용</string>
+ <string name="prefs_log_summary">문제점을 기록하는 데 사용됩니다</string>
<string name="prefs_log_title_history">로그 기록</string>
<string name="prefs_log_summary_history">여기서 기록된 로그를 보여줍니다</string>
- <string name="prefs_log_delete_history_button">역사 삭제하기</string>
+ <string name="prefs_log_delete_history_button">과거 기록 삭제</string>
<string name="prefs_help">도움말</string>
- <string name="prefs_recommend">친구들에게 권하기</string>
+ <string name="prefs_recommend">친구에게 추천하기</string>
<string name="prefs_feedback">피드백</string>
- <string name="prefs_imprint">임프린트</string>
- <string name="recommend_subject">%1$s 을 스마트폰에서 사용해보세요!</string>
+ <string name="prefs_imprint">법적 고지</string>
+ <string name="prefs_remember_last_share_location">공유 위치 기억하기</string>
+ <string name="prefs_remember_last_upload_location_summary">마지막 공유 업로드 위치 기억하기</string>
+ <string name="recommend_subject">%1$s을(를) 스마트폰에서 사용해 보세요!</string>
+ <string name="recommend_text">%1$s을(를) 스마트폰에서 사용해 보는 것을 추천합니다!\n다운로드 링크: %2$s</string>
<string name="auth_check_server">서버 확인</string>
<string name="auth_host_url">서버 주소 https://…</string>
<string name="auth_username">사용자 이름</string>
<string name="sync_string_files">파일</string>
<string name="setup_btn_connect">접속</string>
<string name="uploader_btn_upload_text">업로드</string>
+ <string name="uploader_btn_new_folder_text">새 폴더</string>
+ <string name="uploader_top_message">업로드 폴더 선택:</string>
<string name="uploader_wrn_no_account_title">계정 없음</string>
<string name="uploader_wrn_no_account_text">이 장치에 %1$s 계정이 없습니다. 먼저 계정을 설정하십시오.</string>
<string name="uploader_wrn_no_account_setup_btn_text">설정</string>
<string name="uploader_wrn_no_content_text">받은 콘텐츠가 없습니다. 업로드할 항목이 없습니다.</string>
<string name="uploader_error_forbidden_content">%1$s에서 공유된 콘텐츠에 접근할 수 없습니다</string>
<string name="uploader_info_uploading">업로드 중</string>
- <string name="file_list_seconds_ago">ì´\88 ì \84</string>
+ <string name="file_list_seconds_ago">ì´\88 ì§\80ë\82¨</string>
<string name="file_list_empty">내용이 없습니다. 업로드할 수 있습니다!</string>
+ <string name="local_file_list_empty">이 폴더에 파일이 없습니다.</string>
<string name="filedetails_select_file">파일을 누르면 추가 정보가 표시됩니다.</string>
<string name="filedetails_size">크기:</string>
<string name="filedetails_type">종류:</string>
<string name="filedetails_created">만든 날짜:</string>
<string name="filedetails_modified">수정한 날짜:</string>
<string name="filedetails_download">다운로드</string>
- <string name="filedetails_sync_file">파일 새로고침</string>
+ <string name="filedetails_sync_file">파일 새로 고침</string>
<string name="filedetails_renamed_in_upload_msg">업로드 중 파일 이름을 %1$s(으)로 변경하였습니다</string>
<string name="action_share_file">링크 공유</string>
+ <string name="action_unshare_file">링크 공유 해제</string>
<string name="common_yes">예</string>
<string name="common_no">아니요</string>
<string name="common_ok">확인</string>
<string name="common_save_exit">저장하고 끝내기</string>
<string name="common_error">오류</string>
<string name="common_loading">불러오는 중...</string>
- <string name="common_error_unknown">알수없는 오류</string>
+ <string name="common_error_unknown">알 수 없는 오류</string>
<string name="about_title">정보</string>
<string name="change_password">암호 변경</string>
<string name="delete_account">계정 삭제</string>
<string name="uploader_upload_succeeded_ticker">업로드 성공</string>
<string name="uploader_upload_succeeded_content_single">%1$s을(를) 업로드하였습니다</string>
<string name="uploader_upload_failed_ticker">업로드 실패</string>
- <string name="uploader_upload_failed_content_single">%1$s을(를) 업로드할 수 없었습니다</string>
+ <string name="uploader_upload_failed_content_single">%1$s을(를) 업로드할 수 없습니다</string>
+ <string name="uploader_upload_failed_credentials_error">업로드가 실패하였습니다. 다시 로그인하십시오</string>
<string name="downloader_download_in_progress_ticker">다운로드 중...</string>
<string name="downloader_download_in_progress_content">%1$d%% %2$s 다운로드 중</string>
<string name="downloader_download_succeeded_ticker">다운로드 성공</string>
<string name="downloader_download_succeeded_content">%1$s을(를) 다운로드하였습니다</string>
<string name="downloader_download_failed_ticker">다운로드 실패</string>
- <string name="downloader_download_failed_content">%1$sì\9d\84(를) ë\8b¤ì\9a´ë¡\9cë\93\9cí\95 ì\88\98 ì\97\86ì\97\88ì\8aµë\8b\88ë\8b¤</string>
+ <string name="downloader_download_failed_content">%1$s을(를) 다운로드할 수 없습니다</string>
<string name="downloader_not_downloaded_yet">아직 다운로드 되지 않았습니다</string>
+ <string name="downloader_download_failed_credentials_error">다운로드가 실패하였습니다. 다시 로그인하십시오</string>
<string name="common_choose_account">계정 선택</string>
<string name="sync_fail_ticker">동기화 실패</string>
+ <string name="sync_fail_ticker_unauthorized">동기화가 실패하였습니다. 다시 로그인하십시오</string>
<string name="sync_fail_content">%1$s와(과) 동기화할 수 없었습니다</string>
- <string name="sync_fail_content_unauthorized">%1$sì\97\90 ë\8c\80í\95\9c ë¹\84ë°\80ë²\88í\98¸ê°\80 í\8b\80립니다</string>
+ <string name="sync_fail_content_unauthorized">%1$sì\9d\98 ì\95\94í\98¸ê°\80 ì\98¬ë°\94르ì§\80 ì\95\8aì\8aµ니다</string>
<string name="sync_conflicts_in_favourites_ticker">충돌하는 항목 발견됨</string>
- <string name="sync_conflicts_in_favourites_content">ë\8f\99기í\99\94ë\90\9c í\8c\8cì\9d¼ ì¤\91 %1$dê°\9c를 ë\8f\99기í\99\94í\95 ì\88\98 ì\97\86ì\97\88ì\8aµë\8b\88ë\8b¤</string>
+ <string name="sync_conflicts_in_favourites_content">동기화된 파일 중 %1$d개를 동기화할 수 없습니다</string>
<string name="sync_fail_in_favourites_ticker">파일을 동기화할 수 없었습니다</string>
- <string name="sync_fail_in_favourites_content">파일 %1$d개의 내용을 동기화할 수 없었습니다 (충돌 %2$d개)</string>
- <string name="sync_foreign_files_forgotten_ticker">몇몇 로컬 파일이 사라졌습니다.</string>
- <string name="sync_current_folder_was_removed">%1$s 폴더가 존재하지 않습니다.</string>
- <string name="foreign_files_move">모두 옮김</string>
- <string name="foreign_files_success">모든 파일 옮김</string>
- <string name="foreign_files_fail">몇몇 파일을 옮기지 못했습니다.</string>
+ <string name="sync_fail_in_favourites_content">파일 %1$d개의 내용을 동기화할 수 없습니다 (충돌 %2$d개)</string>
+ <string name="sync_foreign_files_forgotten_ticker">일부 로컬 파일이 사라졌습니다.</string>
+ <string name="sync_foreign_files_forgotten_content">폴더 %2$s의 파일 중 %1$d개를 복사할 수 없습니다</string>
+ <string name="sync_foreign_files_forgotten_explanation">버전 1.3.16부터는 하나의 파일이 여러 계정과 동기화될 때 데이터 손실을 막기 위해서 이 장치에서 업로드된 파일은 로컬 폴더 %1$s(으)로 복사됩니다.\n\n이 변경 사항 때문에 이 앱의 이전 버전에서 업로드된 모든 파일은 폴더 %2$s(으)로 복사되었습니다. 계정 동기화 중 오류가 발생하여 이 작업이 중단되었습니다. 파일을 그대로 둔 다음 %3$s(으)로 향한 링크를 삭제하거나, 파일을 직접 폴더 %1$s(으)로 이동한 다음 %4$s(으)로 향한 링크를 그대로 두십시오.\n\n아래 목록은 로컬 파일과 링크가 걸려 있는 %5$s에 있는 원격 파일입니다.</string>
+ <string name="sync_current_folder_was_removed">폴더 %1$s이(가) 더 이상 존재하지 않습니다.</string>
+ <string name="foreign_files_move">모두 이동</string>
+ <string name="foreign_files_success">모든 파일 이동됨</string>
+ <string name="foreign_files_fail">몇몇 파일을 이동할 수 없음</string>
<string name="foreign_files_local_text">로컬: %1$s</string>
<string name="foreign_files_remote_text">원격: %1$s</string>
- <string name="pincode_enter_pin_code">앱 암호를 입력하십시오</string>
- <string name="pincode_configure_your_pin">앱 암호를 입력하십시오</string>
- <string name="pincode_configure_your_pin_explanation">앱을 시작할 때마다 암호를 물어봅니다</string>
- <string name="pincode_reenter_your_pincode">앱 암호를 다시 입력하십시오</string>
- <string name="pincode_remove_your_pincode">앱 암호 삭제</string>
- <string name="pincode_mismatch">앱 암호가 일치하지 않습니다</string>
- <string name="pincode_wrong">앱 암호가 잘못되었습니다</string>
- <string name="pincode_removed">앱 암호가 삭제되었습니다</string>
- <string name="pincode_stored">앱 암호가 저장되었습니다</string>
+ <string name="upload_query_move_foreign_files">선택한 파일을 폴더 %1$s(으)로 복사할 공간이 부족합니다. 파일을 이동하시겠습니까?</string>
+ <string name="pass_code_enter_pass_code">암호를 입력하십시오</string>
+ <string name="pass_code_configure_your_pass_code">암호를 입력하십시오</string>
+ <string name="pass_code_configure_your_pass_code_explanation">앱을 시작할 때마다 암호를 물어봅니다</string>
+ <string name="pass_code_reenter_your_pass_code">암호를 다시 입력하십시오</string>
+ <string name="pass_code_remove_your_pass_code">내 암호 삭제</string>
+ <string name="pass_code_mismatch">암호가 일치하지 않습니다</string>
+ <string name="pass_code_wrong">암호가 잘못됨</string>
+ <string name="pass_code_removed">암호 삭제됨</string>
+ <string name="pass_code_stored">암호 저장됨</string>
<string name="media_notif_ticker">%1$s 음악 재생기</string>
- <string name="media_state_playing">%1$s (재생중)</string>
+ <string name="media_state_playing">%1$s (재생 중)</string>
<string name="media_state_loading">%1$s (불러오는 중)</string>
<string name="media_event_done">%1$s 재생 완료됨</string>
- <string name="media_err_nothing_to_play">미디어 파일을 찾을수 없습니다</string>
+ <string name="media_err_nothing_to_play">미디어 파일을 찾을 수 음</string>
<string name="media_err_no_account">준비된 계정이 없습니다</string>
<string name="media_err_not_in_owncloud">유효한 계정의 파일이 아닙니다</string>
<string name="media_err_unsupported">지원하지 않는 미디어 코덱</string>
- <string name="media_err_io">미디어 파일을 읽을수 </string>
+ <string name="media_err_io">미디어 파일을 읽을 수 없음</string>
<string name="media_err_malformed">미디어 파일이 제대로 인코드 되지 않았습니다</string>
<string name="media_err_timeout">재생 시도 중 시간이 초과됨</string>
- <string name="media_err_invalid_progressive_playback">미디어 파일을 스트리밍 할수 없습니다</string>
- <string name="media_err_unknown">내장된 미디어 플레이어에서는 이 미디어 파일을 재생할수 없습니다</string>
- <string name="media_err_security_ex">%1$s 를 재생하는 중에 보안오류가 발생함</string>
- <string name="media_err_io_ex">%1$s 를 재생하는 중에 입력 에러가 발생함</string>
- <string name="media_err_unexpected">%1$s 를 재생하던 중에 알수 없는 오류가 발생함</string>
- <string name="media_rewind_description">되감기 버튼</string>
- <string name="media_play_pause_description">재생 혹은 일시정지 버튼</string>
- <string name="media_forward_description">빨리감기 버튼</string>
- <string name="auth_trying_to_login">로그인 중...</string>
+ <string name="media_err_invalid_progressive_playback">미디어 파일을 스트리밍 할 수 없습니다</string>
+ <string name="media_err_unknown">내장된 미디어 플레이어에서 이 미디어 파일을 재생할 수 없습니다</string>
+ <string name="media_err_security_ex">%1$s을(를) 재생하는 중 보안 오류가 발생함</string>
+ <string name="media_err_io_ex">%1$s을(를) 재생하는 중 입력 오류가 발생함</string>
+ <string name="media_err_unexpected">%1$s을(를) 재생하는 중 알 수 없는 오류가 발생함</string>
+ <string name="media_rewind_description">되감기 단추</string>
+ <string name="media_play_pause_description">재생 혹은 일시 정지 단추</string>
+ <string name="media_forward_description">빨리감기 단추</string>
+ <string name="auth_getting_authorization">인증 정보 가져오는 중...</string>
+ <string name="auth_trying_to_login">로그인 시도 중...</string>
<string name="auth_no_net_conn_title">네트워크에 연결할 수 없습니다</string>
<string name="auth_nossl_plain_ok_title">암호화된 연결을 사용할 수 없습니다.</string>
<string name="auth_connection_established">연결됨</string>
- <string name="auth_testing_connection">연결 테스트 중...</string>
+ <string name="auth_testing_connection">연결 테스트 중</string>
<string name="auth_not_configured_title">서버 설정이 잘못됨</string>
<string name="auth_account_not_new">같은 사용자와 서버에 대한 계정이 이미 존재합니다</string>
- <string name="auth_account_not_the_same">ì\9e\85ë ¥ë\90\9c ì\82¬ì\9a©ì\9e\90ê°\80 ì\9d´ ê³\84ì \95ì\9d\98 ì\82¬ì\9a©ì\9e\90ì\99\80 ì\9d¼ì¹\98í\95\98ì§\80 ì\95\8aì\9d\8c</string>
+ <string name="auth_account_not_the_same">ì\9e\85ë ¥ë\90\9c ì\82¬ì\9a©ì\9e\90ê°\80 ì\9d´ ê³\84ì \95ì\9d\98 ì\82¬ì\9a©ì\9e\90ì\99\80 ì\9d¼ì¹\98í\95\98ì§\80 ì\95\8aì\8aµë\8b\88ë\8b¤</string>
<string name="auth_unknown_error_title">알 수 없는 오류가 발생하였습니다!</string>
<string name="auth_unknown_host_title">호스트를 찾을 수 없음</string>
<string name="auth_incorrect_path_title">서버 인스턴스를 찾을 수 없음</string>
- <string name="auth_timeout_title">ì\84\9cë²\84 ì\9d\91ë\8bµ ì\8b\9cê°\84ì\9d´ ì´\88ê³¼ë\90\98ì\97\88ì\8aµë\8b\88ë\8b¤</string>
+ <string name="auth_timeout_title">ì\84\9cë²\84 ì\9d\91ë\8bµ ì\8b\9cê°\84ì\9d´ ì´\88ê³¼ë\90¨</string>
<string name="auth_incorrect_address_title">잘못된 URL</string>
<string name="auth_ssl_general_error_title">SSL 초기화 오류</string>
<string name="auth_ssl_unverified_server_title">SSL 서버의 신원을 확인할수 없습니다</string>
<string name="auth_bad_oc_version_title">확인할 수 없는 서버 버전</string>
<string name="auth_wrong_connection_title">연결을 수립할 수 없음</string>
<string name="auth_secure_connection">암호화된 연결 사용 중</string>
- <string name="auth_unauthorized">잘못된 로그인/암호</string>
- <string name="auth_oauth_error">권한부여가 성공적으로 이뤄지지 않았습니다</string>
- <string name="auth_oauth_error_access_denied">권한 서버로 부터 접근이 거부되었습니다</string>
- <string name="auth_wtf_reenter_URL">뜻밖의 상태; 다시 서버 주소를 입력해주십시오</string>
- <string name="auth_expired_oauth_token_toast">인증이 만료되었습니다. 다시 인증해주세요</string>
- <string name="auth_expired_basic_auth_toast">현재 암호를 </string>
- <string name="auth_expired_saml_sso_token_toast">세션이 만료되었습니다. 다시 접속해주세요</string>
- <string name="auth_connecting_auth_server">ì\9d¸ì¦\9d ì\84\9cë²\84ì\97\90 ì \91ì\86\8d하는 중...</string>
+ <string name="auth_unauthorized">잘못된 사용자 이름 및 암호</string>
+ <string name="auth_oauth_error">인증 실패</string>
+ <string name="auth_oauth_error_access_denied">인증 서버 접근 거부됨</string>
+ <string name="auth_wtf_reenter_URL">예상하지 못한 상태입니다. 서버 URL을 다시 입력해 주십시오</string>
+ <string name="auth_expired_oauth_token_toast">인증이 만료되었습니다. 다시 인증해 주십시오</string>
+ <string name="auth_expired_basic_auth_toast">현재 암호를 입력해 주십시오</string>
+ <string name="auth_expired_saml_sso_token_toast">세션이 만료되었습니다. 다시 접속해 주십시오</string>
+ <string name="auth_connecting_auth_server">ì\9d¸ì¦\9d ì\84\9cë²\84ì\97\90 ì\97°ê²°하는 중...</string>
<string name="auth_unsupported_auth_method">서버에서 이 인증 방법을 지원하지 않습니다.</string>
- <string name="auth_unsupported_multiaccount">%1$s 에서는 다중 계정을 지원하지 않습니다</string>
+ <string name="auth_unsupported_multiaccount">%1$s에서 다중 계정을 지원하지 않습니다</string>
+ <string name="auth_fail_get_user_name">서버에서 올바른 사용자 ID를 반환하지 않았습니다. 관리자에게 연락하십시오
+ </string>
+ <string name="auth_can_not_auth_against_server">이 서버에 인증할 수 없음</string>
+ <string name="auth_account_does_not_exist">장치에 아직 계정이 없음</string>
<string name="fd_keep_in_sync">파일을 최신 정보로 유지</string>
<string name="common_rename">이름 바꾸기</string>
<string name="common_remove">삭제</string>
+ <string name="confirmation_remove_alert">%1$s을(를) 삭제하시겠습니까?</string>
+ <string name="confirmation_remove_folder_alert">%1$s 및 포함된 내용을 삭제하시겠습니까?</string>
<string name="confirmation_remove_local">로컬만</string>
<string name="confirmation_remove_folder_local">로컬 콘텐츠만</string>
<string name="confirmation_remove_remote">서버에서 삭제</string>
<string name="confirmation_remove_remote_and_local">서버와 로컬 모두</string>
- <string name="remove_success_msg">ì\84±ê³µì \81ì\9c¼ë¡\9c ì\82ì \9cí\95\98ì\98\80ì\8aµë\8b\88ë\8b¤</string>
- <string name="remove_fail_msg">ì\82ì \9cí\95 ì\88\98 ì\97\86ì\97\88ì\8aµë\8b\88ë\8b¤</string>
+ <string name="remove_success_msg">ì\84±ê³µì \81ì\9c¼ë¡\9c ì\82ì \9cí\95¨</string>
+ <string name="remove_fail_msg">ì\82ì \9cí\95 ì\88\98 ì\97\86ì\9d\8c</string>
<string name="rename_dialog_title">새 이름 입력</string>
<string name="rename_local_fail_msg">로컬 파일의 이름을 변경할 수 없습니다. 다른 이름을 입력하십시오</string>
- <string name="rename_server_fail_msg">이름을 변경할 수 없었습니다</string>
- <string name="sync_file_fail_msg">원격 파일을 확인할 수 없었습니다</string>
- <string name="sync_file_nothing_to_do_msg">파일 내용이 이미 동기화되었습니다</string>
- <string name="filename_forbidden_characters">사용할수 없는 문자들: / \\ < > : \" | ? *</string>
+ <string name="rename_server_fail_msg">이름을 변경할 수 없음</string>
+ <string name="sync_file_fail_msg">원격 파일을 확인할 수 없음</string>
+ <string name="sync_file_nothing_to_do_msg">파일 내용이 이미 동기화됨</string>
+ <string name="create_dir_fail_msg">폴더를 만들 수 없음</string>
+ <string name="filename_forbidden_characters">사용할 수 없는 문자: / \\ < > : \" | ? *</string>
+ <string name="filename_empty">파일 이름이 비어 있을 수 없음</string>
<string name="wait_a_moment">잠시 기다려 주십시오</string>
<string name="filedisplay_unexpected_bad_get_content">예상하지 못한 오류입니다. 다른 앱에서 파일을 선택하십시오</string>
<string name="filedisplay_no_file_selected">선택한 파일 없음</string>
+ <string name="activity_chooser_title">다음으로 링크 보내기...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">개인 저장소에서 파일 복사</string>
<string name="oauth_check_onoff">oAuth2로 로그인하기</string>
- <string name="oauth_login_connection">oAuth2 서버에 연결중...</string>
- <string name="ssl_validator_header">ì\82¬ì\9d´í\8a¸ ì\9d¸ì¦\9dì\84\9c를 í\99\95ì\9d¸í\95 ì\88\98 ì\97\86ì\97\88ì\8aµë\8b\88ë\8b¤</string>
+ <string name="oauth_login_connection">oAuth2 서버에 연결 중...</string>
+ <string name="ssl_validator_header">사이트 인증서를 확인할 수 없습니다</string>
<string name="ssl_validator_reason_cert_not_trusted">- 서버 인증서를 신뢰할 수 없습니다</string>
<string name="ssl_validator_reason_cert_expired">- 서버 인증서가 만료되었습니다</string>
<string name="ssl_validator_reason_cert_not_yet_valid">- 서버 인증서의 유효 기간이 시작되지 않았습니다</string>
<string name="ssl_validator_reason_hostname_not_verified">- 인증서의 URL과 입력한 URL이 일치하지 않습니다</string>
<string name="ssl_validator_question">이 인증서를 신뢰하시겠습니까?</string>
- <string name="ssl_validator_not_saved">ì\9d¸ì¦\9dì\84\9c를 ì \80ì\9e¥í\95 ì\88\98 ì\97\86ì\97\88ì\8aµë\8b\88ë\8b¤</string>
+ <string name="ssl_validator_not_saved">인증서를 저장할 수 없습니다</string>
<string name="ssl_validator_btn_details_see">자세히</string>
<string name="ssl_validator_btn_details_hide">숨기기</string>
<string name="ssl_validator_label_subject">발급 대상:</string>
<string name="ssl_validator_label_validity_to">끝:</string>
<string name="ssl_validator_label_signature">서명:</string>
<string name="ssl_validator_label_signature_algorithm">알고리즘:</string>
- <string name="placeholder_sentence">이것은 플레이스홀더입니다</string>
+ <string name="ssl_validator_null_cert">인증서를 표시할 수 없습니다.</string>
+ <string name="ssl_validator_no_info_about_error">- 오류에 대한 정보가 없습니다</string>
+ <string name="placeholder_sentence">이것은 자리 비움자입니다</string>
<string name="placeholder_filename">placeholder.txt</string>
<string name="placeholder_filetype">PNG 그림</string>
<string name="placeholder_filesize">389 KB</string>
<string name="placeholder_timestamp">2012/05/18 12:23 PM</string>
<string name="placeholder_media_time">12:23:45</string>
- <string name="instant_upload_on_wifi">WiFi 사용 중일때만 사진 업로드</string>
+ <string name="instant_upload_on_wifi">Wi-Fi 사용 중일때만 사진 업로드</string>
+ <string name="instant_video_upload_on_wifi">Wi-Fi 사용 중일때만 동영상 업로드</string>
<string name="instant_upload_path">/InstantUpload</string>
<string name="conflict_title">업데이트 충돌</string>
<string name="conflict_message">원격 파일 %s이(가) 로컬 파일과 동기화되지 않았습니다. 계속 진행하면 서버에 있는 파일을 덮어씁니다.</string>
<string name="conflict_keep_both">모두 저장</string>
<string name="conflict_overwrite">덮어쓰기</string>
<string name="conflict_dont_upload">업로드하지 않음</string>
- <string name="preview_image_description">그림 미리보기</string>
+ <string name="preview_image_description">사진 미리 보기</string>
+ <string name="preview_image_error_unknown_format">이 사진을 미리 볼 수 없습니다</string>
+ <string name="error__upload__local_file_not_copied">%1$s을(를) 로컬 폴더 %2$s(으)로 복사할 수 없습니다</string>
+ <string name="prefs_instant_upload_path_title">업로드 경로</string>
+ <string name="share_link_no_support_share_api">서버에서 공유가 비활성화되어 있습니다. 관리자에게 연락하십시오.</string>
+ <string name="share_link_file_no_exist">공유할 수 없습니다. 파일이 있는지 확인하십시오</string>
+ <string name="share_link_file_error">이 파일이나 폴더를 공유하는 중 오류 발생</string>
+ <string name="unshare_link_file_no_exist">공유를 해제할 수 없습니다. 파일이 있는지 확인하십시오</string>
+ <string name="unshare_link_file_error">이 파일이나 폴더의 공유를 해제하는 중 오류 발생</string>
+ <string name="share_link_password_title">암호 입력</string>
+ <string name="share_link_empty_password">암호를 입력해야 합니다</string>
<string name="activity_chooser_send_file_title">보내기</string>
- <string name="copy_link">링크 복사</string>
+ <string name="copy_link">링크 주소 복사</string>
<string name="clipboard_text_copied">클립보드로 복사됨</string>
+ <string name="error_cant_bind_to_operations_service">치명적 오류: 작업을 진행할 수 없음</string>
+ <string name="network_error_socket_exception">서버에 연결하는 중 오류가 발생하였습니다.</string>
+ <string name="network_error_socket_timeout_exception">서버를 기다리는 중 오류가 발생하였습니다. 작업이 진행되지 않았을 수도 있습니다</string>
+ <string name="network_error_connect_timeout_exception">서버를 기다리는 중 오류가 발생하였습니다. 작업이 진행되지 않았을 수도 있습니다</string>
+ <string name="network_host_not_available">서버를 사용할 수 없어서 작업을 진행할 수 없습니다</string>
<string name="empty"></string>
+ <string name="forbidden_permissions">%s 권한이 없습니다</string>
+ <string name="forbidden_permissions_rename">이 파일의 이름을 바꿀</string>
+ <string name="forbidden_permissions_delete">이 파일을 삭제할</string>
+ <string name="share_link_forbidden_permissions">이 파일을 공유할</string>
+ <string name="unshare_link_forbidden_permissions">이 파일의 공유를 해제할</string>
+ <string name="forbidden_permissions_create">파일을 생성할</string>
+ <string name="uploader_upload_forbidden_permissions">이 폴더에 업로드할</string>
+ <string name="downloader_download_file_not_found">이 파일을 서버에서 더 이상 사용할 수 없습니다</string>
<string name="prefs_category_accounts">계정</string>
+ <string name="prefs_add_account">계정 추가</string>
+ <string name="auth_redirect_non_secure_connection_title">보안 연결이 안전하지 않은 경로로 넘어갑니다.</string>
+ <string name="actionbar_logger">로그</string>
+ <string name="log_send_history_button">과거 기록 보내기</string>
+ <string name="log_send_no_mail_app">로그를 보낼 앱이 없습니다. 메일 앱을 설치하십시오!</string>
+ <string name="log_send_mail_subject">%1$s Android 앱 로그</string>
+ <string name="log_progress_dialog_text">데이터 불러오는 중...</string>
<string name="saml_authentication_required_text">인증 필요함</string>
<string name="saml_authentication_wrong_pass">잘못된 암호</string>
- <string name="move_choose_button_text">선택</string>
+ <string name="actionbar_move">이동</string>
+ <string name="file_list_empty_moving">항목이 없습니다. 폴더를 추가할 수 있습니다!</string>
+ <string name="folder_picker_choose_button_text">선택</string>
+ <string name="move_file_not_found">이동할 수 없습니다. 파일이 존재하는 지 확인하십시오</string>
+ <string name="move_file_invalid_into_descendent">폴더를 하위 폴더 아래로 이동할 수 없습니다</string>
+ <string name="move_file_invalid_overwrite">파일이 이미 대상 폴더에 존재합니다</string>
+ <string name="move_file_error">이 파일이나 폴더를 이동하는 중 오류가 발생하였습니다</string>
+ <string name="forbidden_permissions_move">이 파일을 이동할</string>
+ <string name="prefs_category_instant_uploading">즉시 업로드</string>
<string name="prefs_category_security">보안</string>
+ <string name="prefs_instant_video_upload_path_title">동영상 업로드 경로</string>
+ <string name="download_folder_failed_content">폴더 %1$s을(를) 다운로드할 수 없음</string>
+ <string name="auth_refresh_button">연결 새로 고침</string>
+ <string name="auth_host_address">서버 주소</string>
</resources>
<string name="actionbar_settings">دهستكاری</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">گشتی</string>
<string name="prefs_accounts">هەژمارەکان</string>
<string name="prefs_help">یارمەتی</string>
<string name="uploader_info_dirname">ناوی بوخچه</string>
<string name="empty"></string>
<string name="prefs_category_accounts">هەژمارەکان</string>
+ <string name="auth_host_address">ناونیشانی ڕاژه</string>
</resources>
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="about_android">%1$s Android-App</string>
<string name="about_version">Versioun %1$s</string>
+ <string name="actionbar_sync">Kont opfrëschen</string>
<string name="actionbar_upload">Eroplueden</string>
- <string name="actionbar_upload_files">Dateien</string>
+ <string name="actionbar_upload_from_apps">Contenu aus aneren Appen</string>
+ <string name="actionbar_upload_files">Fichieren</string>
<string name="actionbar_open_with">Opmaachen mat</string>
+ <string name="actionbar_mkdir">Neien Dossier</string>
<string name="actionbar_settings">Astellungen</string>
<string name="actionbar_see_details">Detailer</string>
<string name="actionbar_send_file">Schécken</string>
+ <string name="actionbar_sort">Zortéieren</string>
+ <string name="actionbar_sort_title">Zortéieren no</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Nei - Al</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Allgemeng</string>
<string name="prefs_category_more">Méi</string>
- <string name="prefs_accounts">Accounten</string>
- <string name="prefs_pincode">App PIN</string>
+ <string name="prefs_accounts">Konten</string>
+ <string name="prefs_manage_accounts">Konte geréieren</string>
+ <string name="prefs_instant_upload">Biller direkt eroplueden</string>
+ <string name="prefs_instant_upload_summary">Biller vum Fotoapparat direkt eroplueden</string>
+ <string name="prefs_instant_video_upload">Videoen direkt eroplueden</string>
+ <string name="prefs_instant_video_upload_summary">Biller vun der Kamera direkt eroplueden</string>
+ <string name="prefs_log_title">Protokoller aktivéieren</string>
+ <string name="prefs_log_summary">Heiduerch gi Problemer protokolléiert</string>
+ <string name="prefs_log_title_history">Protokoll-Historique</string>
+ <string name="prefs_log_summary_history">Hei ginn déi enregistréiert Protokoller ugewisen</string>
+ <string name="prefs_log_delete_history_button">Historique läschen</string>
<string name="prefs_help">Hëllef</string>
+ <string name="prefs_recommend">Engem Frënd recommendéieren</string>
<string name="prefs_feedback">Feedback</string>
+ <string name="prefs_imprint">Impressum</string>
+ <string name="auth_check_server">Server kontrolléieren</string>
+ <string name="auth_host_url">Server-Adress https://…</string>
<string name="auth_username">Benotzernumm</string>
<string name="auth_password">Passwuert</string>
- <string name="sync_string_files">Dateien</string>
+ <string name="auth_register">Nei bei %1$s?</string>
+ <string name="sync_string_files">Fichieren</string>
<string name="setup_btn_connect">Verbannen</string>
<string name="uploader_btn_upload_text">Eroplueden</string>
+ <string name="uploader_btn_new_folder_text">Neien Dossier</string>
<string name="uploader_wrn_no_account_title">Keen Account fonnt</string>
<string name="uploader_wrn_no_account_setup_btn_text">Setup</string>
<string name="uploader_wrn_no_account_quit_btn_text">Erausgoen</string>
+ <string name="uploader_wrn_no_content_text">Et gouf kee Contenu emfaangen. Näischt do fir eropzelueden.</string>
<string name="uploader_info_uploading">Eroplueden</string>
- <string name="file_list_seconds_ago">Sekonnen hir</string>
- <string name="file_list_empty">Hei ass näischt. Lued eppes rop!</string>
+ <string name="file_list_seconds_ago">Sekonnen hier</string>
+ <string name="file_list_empty">Hei ass näischt. Lued eppes erop!</string>
<string name="filedetails_size">Gréisst:</string>
<string name="filedetails_type">Typ:</string>
<string name="filedetails_created">Erstallt:</string>
<string name="filedetails_modified">Geännert:</string>
- <string name="filedetails_download">Download</string>
+ <string name="filedetails_download">Eroflueden</string>
+ <string name="filedetails_sync_file">Fichier opfrëschen</string>
<string name="action_share_file">Link deelen</string>
<string name="common_yes">Jo</string>
<string name="common_no">Nee</string>
<string name="common_ok">OK</string>
- <string name="common_cancel_upload">Upload ofbriechen</string>
+ <string name="common_cancel_download">Eroflueden ofbriechen</string>
+ <string name="common_cancel_upload">Eroplueden ofbriechen</string>
<string name="common_cancel">Ofbriechen</string>
- <string name="common_save_exit">Späicher & géi raus</string>
- <string name="common_error">Fehler</string>
- <string name="common_error_unknown">Et ass en onbekannte Fehler opgetrueden</string>
+ <string name="common_save_exit">Späicheren an Zoumaachen</string>
+ <string name="common_error">Feeler</string>
+ <string name="common_error_unknown">Onbekannte Feeler</string>
<string name="about_title">Iwwer</string>
<string name="change_password">Passwuert änneren</string>
- <string name="delete_account">Account läschen</string>
- <string name="create_account">Account erstellen</string>
- <string name="uploader_info_dirname">Dossiers Numm:</string>
- <string name="uploader_upload_in_progress_ticker">Gett eropgelueden ...</string>
- <string name="uploader_upload_succeeded_ticker">Eroplueden färdeg</string>
- <string name="uploader_upload_failed_ticker">Eroplueden huet net geklappt</string>
- <string name="downloader_download_failed_ticker">Eroflueden huet net geklappt</string>
- <string name="common_choose_account">Wiel en Account aus</string>
- <string name="foreign_files_move">Alles bewegen</string>
- <string name="pincode_enter_pin_code">Gëff w.e.g. däin App PIN an</string>
- <string name="pincode_configure_your_pin">Gëff däin App PIN an</string>
- <string name="pincode_reenter_your_pincode">Gëff däin App PIN w.e.g. nei an</string>
- <string name="pincode_remove_your_pincode">Huel däin App PIN raus</string>
- <string name="pincode_wrong">Ongültegen App PIN</string>
- <string name="pincode_removed">App PIN geläscht</string>
- <string name="pincode_stored">App PIN gespaichert</string>
- <string name="auth_no_net_conn_title">Keng Netzwierk Verbindung</string>
- <string name="auth_nossl_plain_ok_title">Keng geséchert Verbindung verfügbar.</string>
- <string name="auth_connection_established">Verbindung hiergestallt</string>
- <string name="auth_not_configured_title">Ongülteg Server Konfiguratioun</string>
- <string name="auth_unknown_error_title">Et ass en onbekannte Fehler opgetrueden!</string>
- <string name="auth_incorrect_path_title">Server Instanz net fonnt</string>
- <string name="common_rename">Ëm-benennen</string>
+ <string name="delete_account">Kont läschen</string>
+ <string name="create_account">Kont uleeën</string>
+ <string name="uploader_info_dirname">Dossiersnumm:</string>
+ <string name="uploader_upload_in_progress_ticker">Lueden erop ...</string>
+ <string name="uploader_upload_succeeded_ticker">Eroplueden ofgeschloss</string>
+ <string name="uploader_upload_succeeded_content_single">%1$s gouf erfollegräich eropgelueden</string>
+ <string name="uploader_upload_failed_ticker">Eropluede feelgeschloen</string>
+ <string name="uploader_upload_failed_content_single">Eropluede vun %1$s konnt net ofgeschloss ginn</string>
+ <string name="uploader_upload_failed_credentials_error">Eropluede feelgeschloen, du muss dech nei aloggen</string>
+ <string name="downloader_download_in_progress_ticker">Lueden erof …</string>
+ <string name="downloader_download_succeeded_ticker">Eroflueden ofgeschloss</string>
+ <string name="downloader_download_succeeded_content">%1$s gouf erfollegräich erofgelueden</string>
+ <string name="downloader_download_failed_ticker">Erofluede feelgeschloen</string>
+ <string name="downloader_download_failed_content">Erofluede vun %1$s konnt net ofgeschloss ginn</string>
+ <string name="downloader_not_downloaded_yet">Nach net erofgelueden</string>
+ <string name="downloader_download_failed_credentials_error">Erofluede feelgeschloen, du muss dech nei aloggen</string>
+ <string name="common_choose_account">Kont auswielen</string>
+ <string name="sync_fail_ticker">Synchroniséierung feelgeschloen</string>
+ <string name="sync_fail_ticker_unauthorized">Synchroniséierung feelgeschloen, du muss dech nei aloggen</string>
+ <string name="sync_fail_content">Synchroniséierung vun %1$s konnt net ofgeschloss ginn</string>
+ <string name="sync_fail_content_unauthorized">Ongëltegt Passwuert fir %1$s</string>
+ <string name="sync_conflicts_in_favourites_ticker">Konflikter fonnt</string>
+ <string name="sync_foreign_files_forgotten_ticker">Verschidde lokal Fichiere goufe vergiess</string>
+ <string name="sync_current_folder_was_removed">Den Dossier %1$s existéiert net méi</string>
+ <string name="foreign_files_move">All réckelen</string>
+ <string name="foreign_files_success">All d\'Fichiere goufe geréckelt</string>
+ <string name="foreign_files_fail">Verschidde Fichiere konnten net geréckelt ginn</string>
+ <string name="foreign_files_local_text">Lokal: %1$s</string>
+ <string name="foreign_files_remote_text">Um Server: %1$s</string>
+ <string name="media_notif_ticker">%1$s Musek-Programm</string>
+ <string name="media_state_playing">%1$s (spillt of)</string>
+ <string name="media_state_loading">%1$s (lued)</string>
+ <string name="media_event_done">%1$s Ofspillen ofgeschloss</string>
+ <string name="media_err_nothing_to_play">Kee Mediefichier fonnt</string>
+ <string name="media_err_no_account">Kee Kont uginn</string>
+ <string name="media_err_not_in_owncloud">Fichier net an engem gëltege Kont</string>
+ <string name="media_err_unsupported">Medie-Codec net ënnerstëtzt</string>
+ <string name="media_err_io">Mediefichier konnt net gelies ginn</string>
+ <string name="media_err_malformed">Mediefichier net korrekt encodéiert</string>
+ <string name="media_err_timeout">Zäit ofgelaf beim Versuch de Fichier ofzespillen</string>
+ <string name="media_err_invalid_progressive_playback">Mediefichier konnt net gestreamt ginn</string>
+ <string name="media_err_unknown">Mediefichier konnt net mam Standard-Medieprogramm ofgespillt ginn</string>
+ <string name="media_err_security_ex">Sécherheetsfeeler beim Ofspille vun %1$s</string>
+ <string name="media_rewind_description">Zréckspull-Knäppchen</string>
+ <string name="media_play_pause_description">Ofspill- oder Paus-Knäppchen</string>
+ <string name="auth_no_net_conn_title">Keng Netzwierkconnectioun</string>
+ <string name="auth_nossl_plain_ok_title">Keng geséchert Connectioun disponibel.</string>
+ <string name="auth_connection_established">Connectioun hiergestallt</string>
+ <string name="auth_testing_connection">Testen d\'Connectioun</string>
+ <string name="auth_not_configured_title">Ongëlteg Server-Konfiguratioun</string>
+ <string name="auth_unknown_error_title">Et ass en onbekannte Feeler opgetrueden!</string>
+ <string name="auth_unknown_host_title">Server konnt net fonnt ginn</string>
+ <string name="auth_incorrect_path_title">Server-Instanz net fonnt</string>
+ <string name="auth_timeout_title">De Server huet ze laang gebraucht fir ze äntweren</string>
+ <string name="auth_incorrect_address_title">Ongëlteg URL</string>
+ <string name="auth_ssl_general_error_title">SSL-Initialiséierung feelgeschloen</string>
+ <string name="auth_ssl_unverified_server_title">Konnt d\'Identitéit vum SSL-Server net verifizéieren</string>
+ <string name="auth_bad_oc_version_title">Onbekannte Server-Versioun</string>
+ <string name="auth_wrong_connection_title">Konnt d\'Connectioun net hierstellen</string>
+ <string name="auth_secure_connection">Sécher Connectioun hiergestallt</string>
+ <string name="auth_unauthorized">Falsche Benotzernumm oder falscht Passwuert</string>
+ <string name="auth_oauth_error">Authoriséierung net erfollegräich</string>
+ <string name="auth_oauth_error_access_denied">Accès duerch den Authoriséierungsserver verweigert</string>
+ <string name="auth_expired_basic_auth_toast">Gëff w.e.g. däin aktuellt Passwuert an</string>
+ <string name="auth_expired_saml_sso_token_toast">Deng Sessioun ass ofgelaf. Connectéier dech nei w.e.g.</string>
+ <string name="auth_unsupported_auth_method">De Server ënnerstëtzt dës Authentifizéierungsmethod net</string>
+ <string name="fd_keep_in_sync">Fichier aktuell halen</string>
+ <string name="common_rename">Ëmbenennen</string>
<string name="common_remove">Läschen</string>
- <string name="confirmation_remove_local">Nemmen Lokal</string>
+ <string name="confirmation_remove_alert">Wëlls du %1$s wierklech läschen?</string>
+ <string name="confirmation_remove_folder_alert">Wëlls du %1$s an de ganzen Inhalt wierklech läschen?</string>
+ <string name="confirmation_remove_local">Nemme lokal</string>
+ <string name="confirmation_remove_folder_local">Nëmme lokal Inhalter</string>
<string name="confirmation_remove_remote">Vum Server läschen</string>
+ <string name="confirmation_remove_remote_and_local">Um Server a lokal</string>
+ <string name="remove_success_msg">Erfollegräich geläscht</string>
+ <string name="remove_fail_msg">Läsche feelgeschloen</string>
+ <string name="rename_dialog_title">Gëff en neien Numm an</string>
+ <string name="sync_file_nothing_to_do_msg">Fichiersinhalter scho synchroniséiert</string>
+ <string name="create_dir_fail_msg">Dossier konnt net ugeluecht ginn</string>
+ <string name="filename_empty">De Fichiersnumm kann net eidel sinn</string>
+ <string name="wait_a_moment">Waart ee Moment</string>
+ <string name="filedisplay_no_file_selected">Kee Fichier selektionéiert</string>
+ <string name="activity_chooser_title">Link schécken un …</string>
+ <string name="oauth_check_onoff">Mat oAuth2 aloggen</string>
+ <string name="ssl_validator_reason_cert_expired">- D\'Server-Zerfitikat ass ofgelaf</string>
+ <string name="ssl_validator_reason_cert_not_yet_valid">- D\'Validitéitsdate vum Server-Zertifikat leien an der Zukunft</string>
+ <string name="ssl_validator_reason_hostname_not_verified">- D\'URL stëmmt net mam Servernumm am Zertifikat iwwereneen</string>
+ <string name="ssl_validator_question">Wëlls du dësem Zertifikat trotzdeem vertrauen?</string>
+ <string name="ssl_validator_not_saved">Den Zertifikat konnt net gespäichert ginn</string>
<string name="ssl_validator_btn_details_see">Detailer</string>
<string name="ssl_validator_btn_details_hide">Verstoppen</string>
+ <string name="ssl_validator_label_subject">Ausgestallt un:</string>
+ <string name="ssl_validator_label_issuer">Ausgestallt vun:</string>
+ <string name="ssl_validator_label_CN">Allgemengen Numm:</string>
+ <string name="ssl_validator_label_O">Organisatioun:</string>
+ <string name="ssl_validator_label_OU">Organisatiounseenheet:</string>
<string name="ssl_validator_label_C">Land:</string>
<string name="ssl_validator_label_ST">Staat:</string>
<string name="ssl_validator_label_L">Uert:</string>
- <string name="ssl_validator_label_validity">Gültegkeet:</string>
+ <string name="ssl_validator_label_validity">Gëltegkeet:</string>
<string name="ssl_validator_label_validity_from">Vun:</string>
- <string name="ssl_validator_label_validity_to">Fir:</string>
+ <string name="ssl_validator_label_validity_to">Un:</string>
<string name="ssl_validator_label_signature">Signatur:</string>
- <string name="placeholder_filetype">PNG Bild</string>
- <string name="placeholder_filesize">389 KB</string>
- <string name="placeholder_timestamp">2012/05/18 12:23</string>
+ <string name="ssl_validator_label_signature_algorithm">Algorithmus:</string>
+ <string name="ssl_validator_null_cert">Den Zertifikat konnt net ugewise ginn.</string>
+ <string name="ssl_validator_no_info_about_error">- Keng Informatioun iwwer de Feeler</string>
+ <string name="placeholder_sentence">Dëst ass e Plazhaler</string>
+ <string name="placeholder_filename">plazhaler.txt</string>
+ <string name="placeholder_filetype">PNG-Bild</string>
+ <string name="placeholder_filesize">389kB</string>
+ <string name="placeholder_timestamp">18.05.2012 12:23</string>
<string name="placeholder_media_time">12:23:45</string>
<string name="conflict_keep_both">Béid halen</string>
<string name="conflict_overwrite">Iwwerschreiwen</string>
<string name="conflict_dont_upload">Net eroplueden</string>
+ <string name="preview_image_description">Biller-Virschau</string>
+ <string name="preview_image_error_unknown_format">Dëst Bild kann net ugewise ginn</string>
+ <string name="error__upload__local_file_not_copied">%1$s konnt net an de lokalen Dossier %2$s kopéiert ginn</string>
+ <string name="prefs_instant_upload_path_title">Pad fir d\'Eroplueden</string>
+ <string name="share_link_password_title">E Passwuert aginn</string>
+ <string name="share_link_empty_password">Du muss e Passwuert aginn</string>
<string name="activity_chooser_send_file_title">Schécken</string>
+ <string name="copy_link">Link kopéieren</string>
+ <string name="clipboard_text_copied">An d\'Tëschenoflag kopéiert</string>
+ <string name="error_cant_bind_to_operations_service">Kritesche Feeler: D\'Operatioune konnten net ausgeféiert ginn</string>
+ <string name="network_error_socket_exception">Bei der Connectioun mam Server ass e Feeler opgetrueden.</string>
+ <string name="network_error_socket_timeout_exception">Beim Waarden op de Server ass e Feeler opgetrueden, d\'Operatioun konnt net duerchgeféiert ginn</string>
+ <string name="network_error_connect_timeout_exception">Beim Waarden op de Server ass e Feeler opgetrueden, d\'Operatioun konnt net duerchgeféiert ginn</string>
+ <string name="network_host_not_available">D\'Operatioun konnt net ofgeschloss ginn, de Server ass net disponibel</string>
<string name="empty"></string>
- <string name="prefs_category_accounts">Accounten</string>
- <string name="move_choose_button_text">Auswielen</string>
+ <string name="forbidden_permissions">Du hues keng Berechtegung %s</string>
+ <string name="forbidden_permissions_rename">fir dëse Fichier ëmzebenennen</string>
+ <string name="forbidden_permissions_delete">fir dëse Fichier ze läschen</string>
+ <string name="share_link_forbidden_permissions">fir dëse Fichier ze deelen</string>
+ <string name="unshare_link_forbidden_permissions">fir dëse Fichier net méi ze deelen</string>
+ <string name="forbidden_permissions_create">fir dëse Fichier unzeleeën</string>
+ <string name="uploader_upload_forbidden_permissions">fir an dësen Dossier eropzelueden</string>
+ <string name="downloader_download_file_not_found">De Fichier ass net méi um Server disponibel</string>
+ <string name="prefs_category_accounts">Konten</string>
+ <string name="prefs_add_account">Kont dobäisetzen</string>
+ <string name="auth_redirect_non_secure_connection_title">Sécher Connectioun gëtt op eng onsécher Route ëmgeleet.</string>
+ <string name="actionbar_logger">Protokoller</string>
+ <string name="log_send_history_button">Historique schécken</string>
+ <string name="log_send_no_mail_app">Keng App fonnt fir d\'Protokoller ze schécken. Installéier eng Mail-App!</string>
+ <string name="log_send_mail_subject">Protokoller vun der %1$s-Android-App</string>
+ <string name="log_progress_dialog_text">Date gi gelueden…</string>
+ <string name="saml_authentication_required_text">Authentifizéierung néideg</string>
+ <string name="saml_authentication_wrong_pass">Falscht Passwuert</string>
+ <string name="actionbar_move">Réckelen</string>
+ <string name="file_list_empty_moving">Hei ass näischt. Setz en Dossier dobäi!</string>
+ <string name="folder_picker_choose_button_text">Auswielen</string>
+ <string name="move_file_not_found">Konnt net réckelen. Kontrolléier w.e.g. ob de Fichier existéiert</string>
+ <string name="move_file_invalid_into_descendent">Et ass net méiglech, en Dossier an en Ënnerdossier vu sech selwer ze réckelen</string>
+ <string name="move_file_invalid_overwrite">De Fichier existéiert schonn am Zildossier</string>
+ <string name="move_file_error">Beim Réckele vun dësem Fichier oder Dossier ass e Feeler opgetrueden</string>
+ <string name="forbidden_permissions_move">fir dëse Fichier ze réckelen</string>
+ <string name="prefs_category_instant_uploading">Direkt eropgeluede Fichieren</string>
+ <string name="prefs_category_security">Sécherheet</string>
+ <string name="prefs_instant_video_upload_path_title">Pad fir d\'Eropluede vun de Videoen</string>
+ <string name="download_folder_failed_content">D\'Erofluede vum %1$s-Dossier konnt net ofgeschloss ginn</string>
+ <string name="auth_refresh_button">Connectioun opfrëschen</string>
+ <string name="auth_host_address">Server-Adress</string>
</resources>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--TODO re-enable when server-side folder size calculation is available
+ <item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="common_error_unknown">ຂໍ້ຜິດພາດທີ່ບໍ່ຮູ້ສາເຫດ</string>
+ <string name="empty"></string>
+</resources>
<string name="actionbar_settings">Nustatymai</string>
<string name="actionbar_see_details">Informacija</string>
<string name="actionbar_send_file">Siųsti</string>
+ <string name="actionbar_sort">Rikiuoti</string>
+ <string name="actionbar_sort_title">Rikiuoti pagal</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Naujausi - Seniausi</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Bendras</string>
<string name="prefs_category_more">Daugiau</string>
<string name="prefs_accounts">Paskyros</string>
<string name="prefs_manage_accounts">Tvarkyti paskyras</string>
- <string name="prefs_pincode">App programos PIN kodas</string>
- <string name="prefs_pincode_summary">Apsaugokite savo klientą</string>
<string name="prefs_instant_upload">Momentiniai nuotraukų įkėlimai</string>
<string name="prefs_instant_upload_summary">Iš karto nusiųsti nufotografuotas nuotraukas</string>
<string name="prefs_instant_video_upload">Momentiniai video įkėlimai</string>
<string name="prefs_recommend">Rekomenduoti draugui</string>
<string name="prefs_feedback">Atsiliepimai</string>
<string name="prefs_imprint">Imprint</string>
+ <string name="prefs_remember_last_share_location">Prisiminti bendrinimo vietą</string>
+ <string name="prefs_remember_last_upload_location_summary">Prisiminti paskutinio bendrinimo įkėlimo vietą</string>
<string name="recommend_subject">Išbandykite %1$s savo išmaniajame telefone!</string>
<string name="auth_check_server">Patikrinti Serverį</string>
<string name="auth_host_url">Serverio adresas </string>
<string name="sync_string_files">Failai</string>
<string name="setup_btn_connect">Prisijungti</string>
<string name="uploader_btn_upload_text">Įkelti</string>
+ <string name="uploader_btn_new_folder_text">Naujas aplankas</string>
<string name="uploader_top_message">Nustatyti įkėlimų aplanką:</string>
<string name="uploader_wrn_no_account_title">Paskyrų nerasta</string>
<string name="uploader_wrn_no_account_text">Jūsų įrenginyje nėra nė vienos %1$s paskyros. Prašome pirmiausia susikurti paskyrą.</string>
<string name="uploader_info_uploading">Išsiunčiama</string>
<string name="file_list_seconds_ago">prieš sekundę</string>
<string name="file_list_empty">Čia tuščia. Įkelkite ką nors!</string>
- <string name="file_list_loading">Įkeliama ...</string>
<string name="local_file_list_empty">Šiame aplanke nėra failų.</string>
<string name="filedetails_select_file">Palieskite failą, kad parodyti papildomą informaciją.</string>
<string name="filedetails_size">Dydis:</string>
<string name="foreign_files_fail">Kai kurių failų negalima perkelti</string>
<string name="foreign_files_local_text">Vietinis: %1$s</string>
<string name="foreign_files_remote_text">Nuotolinis: %1$s</string>
- <string name="pincode_enter_pin_code">Prašome įvesti savo programos PIN kodą</string>
- <string name="pincode_configure_your_pin">Įveskite taikymas programos PIN kodą</string>
- <string name="pincode_configure_your_pin_explanation">PIN bus prašomas kiekvieną kartą paleidus programą</string>
- <string name="pincode_reenter_your_pincode">Prašome pakartoti taikymas PIN kodą</string>
- <string name="pincode_remove_your_pincode">Pašalinti taikymas programos PIN kodą</string>
- <string name="pincode_mismatch">Abu taikymas programos PIN kodai nesutampa</string>
- <string name="pincode_wrong">Neteisingas taikymas programos PIN kodas</string>
- <string name="pincode_removed">Taikymas programos PIN kodas pašalintas</string>
- <string name="pincode_stored">Taikymas programos PIN kodas išsaugotas</string>
<string name="media_notif_ticker">%1$s muzikos grotuvas</string>
<string name="media_state_playing">%1$s (grojama)</string>
<string name="media_state_loading">%1$s (įkeliama)</string>
<string name="auth_no_net_conn_title">Nėra tinklo ryšio</string>
<string name="auth_nossl_plain_ok_title">Saugus prisijungimas negalimas.</string>
<string name="auth_connection_established">Ryšys užmegztas</string>
- <string name="auth_testing_connection">Išbandomas prisijungimas...</string>
<string name="auth_not_configured_title">Sugadinta serverio konfigūracija</string>
<string name="auth_account_not_new">To paties vartotojo ir serverio paskyra jau egzistuoja šiame įrenginyje</string>
<string name="auth_unknown_error_title">Įvyko nežinoma klaida!</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Paskyros</string>
<string name="saml_authentication_wrong_pass">Neteisingas slaptažodis</string>
- <string name="move_choose_button_text">Pasirinkite</string>
+ <string name="folder_picker_choose_button_text">Pasirinkite</string>
<string name="prefs_category_security">Saugumas</string>
+ <string name="auth_host_address">Serverio adresas</string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="about_android">%1$s Android lietotne</string>
+ <string name="about_version">versija %1$s</string>
+ <string name="actionbar_sync">Atsvaidzināt kontu</string>
<string name="actionbar_upload">Augšupielādēt</string>
<string name="actionbar_upload_from_apps">Saturs no citām lietotnēm</string>
<string name="actionbar_upload_files">Datnes</string>
+ <string name="actionbar_open_with">Atvērt ar</string>
<string name="actionbar_mkdir">Jauna mape</string>
<string name="actionbar_settings">Iestatījumi</string>
+ <string name="actionbar_see_details">Detaļas</string>
<string name="actionbar_send_file">Sūtīt</string>
+ <string name="actionbar_sort">Kārtot</string>
+ <string name="actionbar_sort_title">Kārtot pēc</string>
+ <string-array name="actionbar_sortby">
+ <item>Alfabēta: A-Z</item>
+ <item>Jaunākie - vecākie</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Vispārīgi</string>
<string name="prefs_category_more">Vairāk</string>
<string name="prefs_accounts">Konti</string>
<string name="prefs_manage_accounts">Pārvaldīt kontus</string>
- <string name="prefs_pincode">Lietotnes PIN</string>
- <string name="prefs_pincode_summary">Aizsargā savu klientu</string>
+ <string name="prefs_instant_upload">Automātiskā bilžu augšuplāde</string>
+ <string name="prefs_instant_upload_summary">Automātiski augšuplādēt tikko uzņemtās bildes</string>
+ <string name="prefs_instant_video_upload">Automātiskā video augšuplāde</string>
+ <string name="prefs_instant_video_upload_summary">Automātiski augšuplādēt tikko uzņemtos video</string>
+ <string name="prefs_log_title">Ieslēgt ierakstīšanu</string>
+ <string name="prefs_log_summary">Šo lieto lai ierakstītu informāciju par problēmām</string>
+ <string name="prefs_log_title_history">Ierakstu žurnāls</string>
+ <string name="prefs_log_summary_history">Šis parāda ierakstu žurnālu</string>
+ <string name="prefs_log_delete_history_button">Iztīrīt žurnālu</string>
<string name="prefs_help">Palīdzība</string>
+ <string name="prefs_recommend">Ieteikt draugam</string>
+ <string name="prefs_feedback">Atsauksmes</string>
<string name="auth_username">Lietotājvārds</string>
<string name="auth_password">Parole</string>
<string name="sync_string_files">Datnes</string>
<string name="setup_btn_connect">Savienoties</string>
<string name="uploader_btn_upload_text">Augšupielādēt</string>
+ <string name="uploader_btn_new_folder_text">Jauna mape</string>
<string name="uploader_wrn_no_account_title">Nav atrastu kontu</string>
<string name="uploader_wrn_no_account_text">Uz šīs ierīces nav %1$s kontu. Lūdzu, vispirms iestatiet kontu.</string>
<string name="uploader_wrn_no_account_setup_btn_text">Iestatīt</string>
<string name="uploader_info_uploading">Augšupielādē</string>
<string name="file_list_seconds_ago">sekundes atpakaļ</string>
<string name="file_list_empty">Te vēl nekas nav. Rīkojies, sāc augšupielādēt!</string>
+ <string name="local_file_list_empty">Šajā mapē nav failu</string>
<string name="filedetails_select_file">Uzsitiet uz datnes, lai redzētu papildinformāciju.</string>
<string name="filedetails_size">Izmērs:</string>
<string name="filedetails_type">Tips:</string>
<string name="filedetails_created">Izveidota:</string>
<string name="filedetails_modified">Modificēta:</string>
<string name="filedetails_download">Lejupielādēt</string>
+ <string name="filedetails_sync_file">Atsvaidzināt failu</string>
<string name="filedetails_renamed_in_upload_msg">Datne tika pārsaukta uz %1$s augšupielādes laikā</string>
<string name="common_yes">Jā</string>
<string name="common_no">Nē</string>
<string name="sync_conflicts_in_favourites_content">Nevarēja sinhronizēt %1$d kept-in-sync datnes</string>
<string name="sync_fail_in_favourites_ticker">Kept-in-sync datnes cieta neveiksmi</string>
<string name="sync_fail_in_favourites_content">Nevarēja sinhronizēt %1$d datņu saturu (%2$d konflikti)</string>
- <string name="pincode_enter_pin_code">Lūdzu, ierakstiet savu lietotnes PIN</string>
- <string name="pincode_configure_your_pin">Ievadiet savu lietotnes PIN</string>
- <string name="pincode_configure_your_pin_explanation">PIN tiks pieprasīts katrā lietotnes palaišanas reizē</string>
- <string name="pincode_reenter_your_pincode">Lūdzu, vēlreiz ievadiet savu lietotnes PIN</string>
- <string name="pincode_remove_your_pincode">Izņemt savu lietotnes PIN</string>
- <string name="pincode_mismatch">Lietotņu PIN nav vienādi</string>
- <string name="pincode_wrong">Nepareizs lietotnes PIN</string>
- <string name="pincode_removed">Lietotnes PIN ir izņemts</string>
- <string name="pincode_stored">Lietotnes PIN ir noglabāts</string>
<string name="auth_trying_to_login">Mēģina ierakstīties...</string>
<string name="auth_no_net_conn_title">Nav tīkla savienojumu</string>
<string name="auth_nossl_plain_ok_title">Nav pieejams drošs savienojums.</string>
<string name="auth_connection_established">Savienojums ir izveidots</string>
- <string name="auth_testing_connection">Testē savienojumu...</string>
<string name="auth_not_configured_title">Slikti formatēta servera konfigurācija</string>
<string name="auth_unknown_error_title">Gadījās nezināma kļūda!</string>
<string name="auth_unknown_host_title">Nevarēja atrast datoru</string>
<string name="activity_chooser_send_file_title">Sūtīt</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Konti</string>
- <string name="move_choose_button_text">Izvēlieties</string>
+ <string name="saml_authentication_wrong_pass">Nepareiza parole</string>
+ <string name="folder_picker_choose_button_text">Izvēlieties</string>
<string name="prefs_category_security">Drošība</string>
+ <string name="auth_host_address">Servera adrese</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="about_android">%1$s Андроид апликација</string>
+ <string name="about_version">верзија %1$s</string>
+ <string name="actionbar_sync">Освежи сметка</string>
<string name="actionbar_upload">Подигни</string>
+ <string name="actionbar_upload_from_apps">Содржина од други апликации</string>
<string name="actionbar_upload_files">Датотеки</string>
<string name="actionbar_open_with">Отвори со</string>
<string name="actionbar_mkdir">Нова папка</string>
<string name="actionbar_settings">Параметри</string>
<string name="actionbar_see_details">Детали:</string>
<string name="actionbar_send_file">Прати</string>
+ <string name="actionbar_sort">Сортирај</string>
+ <string name="actionbar_sort_title">Сортирај по</string>
+ <string-array name="actionbar_sortby">
+ <item>А-Ш</item>
+ <item>Најнови - Најстари</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Општо</string>
<string name="prefs_category_more">Повеќе</string>
<string name="prefs_accounts">Сметки</string>
<string name="prefs_manage_accounts">Управување со сметки</string>
- <string name="prefs_pincode">Апликативен ПИН</string>
- <string name="prefs_pincode_summary">Заштитете го вашиот клиент</string>
+ <string name="prefs_passcode">Заклучено со код</string>
+ <string name="prefs_instant_upload">Инстантно префрлање на слики</string>
+ <string name="prefs_instant_upload_summary">Инстантно префрли слики направени со камера</string>
+ <string name="prefs_instant_video_upload">Инстантно префрлање на видеа</string>
+ <string name="prefs_instant_video_upload_summary">Инстантно префрла видеа снимени со камерата</string>
<string name="prefs_log_title">Овозможи логирање</string>
+ <string name="prefs_log_summary">Ова е користено за логирање на проблеми</string>
+ <string name="prefs_log_title_history">Историја на логирање</string>
+ <string name="prefs_log_summary_history">Ова ги прикажува снимените логови</string>
+ <string name="prefs_log_delete_history_button">Избриши историја</string>
<string name="prefs_help">Помош</string>
<string name="prefs_recommend">Препорачај на пријател</string>
<string name="prefs_feedback">Повратен одговор</string>
+ <string name="prefs_imprint">Печат</string>
+ <string name="prefs_remember_last_share_location">Запомни ја локацијата на споделувањеот</string>
+ <string name="prefs_remember_last_upload_location_summary">Запомни ја последната локација на споделување на префрлање</string>
+ <string name="recommend_subject">Пробајте %1$s на вашиот паметен телефон!</string>
+ <string name="recommend_text">Сакам да ве поканам да го користите %1$s на вашиот телефон.\nСимнете го овде: %2$s</string>
+ <string name="auth_check_server">Проверка на серверот</string>
<string name="auth_host_url">Адреса на серверот https://…</string>
<string name="auth_username">Корисничко име</string>
<string name="auth_password">Лозинка</string>
+ <string name="auth_register">Нови во %1$s?</string>
<string name="sync_string_files">Датотеки</string>
<string name="setup_btn_connect">Поврзи се</string>
<string name="uploader_btn_upload_text">Подигни</string>
+ <string name="uploader_btn_new_folder_text">Нова папка</string>
+ <string name="uploader_top_message">Избери папка за префрлање:</string>
<string name="uploader_wrn_no_account_title">Не е пронајдена сметка</string>
+ <string name="uploader_wrn_no_account_text">Не постојат %1$s сметки на овој уред. Ве молам подесете прво сметка.</string>
<string name="uploader_wrn_no_account_setup_btn_text">Нагодување</string>
<string name="uploader_wrn_no_account_quit_btn_text">Прекини</string>
+ <string name="uploader_wrn_no_content_title">Нема содржина за префрлање</string>
+ <string name="uploader_wrn_no_content_text">Не е примена содржина. Нема што да се префрла</string>
+ <string name="uploader_error_forbidden_content">на %1$s не му е дозволено да пристапи на споделената содржина</string>
+ <string name="uploader_info_uploading">Префрлам</string>
<string name="file_list_seconds_ago">пред секунди</string>
- <string name="file_list_empty">Тука нема ништо. Снимете нешто!</string>
+ <string name="file_list_empty">Тука нема ништо. Префрлете нешто!</string>
+ <string name="local_file_list_empty">Нема датотеки во оваа папка.</string>
+ <string name="filedetails_select_file">Кликнете на датотеката за дополнителни информации.</string>
<string name="filedetails_size">Големина:</string>
<string name="filedetails_type">Тип:</string>
<string name="filedetails_created">Создадено:</string>
<string name="filedetails_modified">Изменето:</string>
<string name="filedetails_download">Преземање</string>
+ <string name="filedetails_sync_file">Освежи ја датотеката</string>
+ <string name="filedetails_renamed_in_upload_msg">Датотеката беше преименувана во %1$s за време на префрлањето</string>
<string name="action_share_file">Сподели ја врската</string>
+ <string name="action_unshare_file">Тргнете го споделувањето на врската</string>
<string name="common_yes">Да</string>
<string name="common_no">Не</string>
<string name="common_ok">Во ред</string>
+ <string name="common_cancel_download">Откажи превземање</string>
<string name="common_cancel_upload">Откажи прикачување</string>
<string name="common_cancel">Откажи</string>
+ <string name="common_save_exit">Сними & Излез</string>
<string name="common_error">Грешка</string>
<string name="common_loading">Вчитувам ...</string>
<string name="common_error_unknown">Непозната грешка</string>
<string name="upload_chooser_title">подигни од ...</string>
<string name="uploader_info_dirname">Име на папка</string>
<string name="uploader_upload_in_progress_ticker">Подигнувам...</string>
- <string name="uploader_upload_succeeded_ticker">Подигањето беше успешно</string>
+ <string name="uploader_upload_in_progress_content">%1$d%% Прикачување %2$s</string>
+ <string name="uploader_upload_succeeded_ticker">Прикачувањето беше успешно</string>
+ <string name="uploader_upload_succeeded_content_single">%1$s беше успешно прикачено</string>
+ <string name="uploader_upload_failed_ticker">Прикачувањето не успеа</string>
+ <string name="uploader_upload_failed_content_single">Прикачувањето на %1$s не може да се заврши</string>
+ <string name="uploader_upload_failed_credentials_error">Прикачувањето не успеа, морате повторно да се најавите</string>
<string name="downloader_download_in_progress_ticker">Преземање...</string>
+ <string name="downloader_download_in_progress_content">%1$d%% Превземање %2$s</string>
<string name="downloader_download_succeeded_ticker">Преземањето е успешно</string>
+ <string name="downloader_download_succeeded_content">%1$s беше успешно превземен</string>
<string name="downloader_download_failed_ticker">Преземањето не беше успешно</string>
+ <string name="downloader_download_failed_content">Превземањето на %1$s не можеше да се заврши</string>
+ <string name="downloader_not_downloaded_yet">Сеуште не е превземено</string>
+ <string name="downloader_download_failed_credentials_error">Превземањето не успеа, морате повторно да се најавите</string>
<string name="common_choose_account">Одбери сметка</string>
<string name="sync_fail_ticker">Синхронизацијата беше неуспешна</string>
+ <string name="sync_fail_ticker_unauthorized">Синхронизацијата не успеа, морате повторно да се најавите</string>
+ <string name="sync_fail_content">Синхронизацијата на %1$s не може да се заврши</string>
+ <string name="sync_fail_content_unauthorized">Не е точна лозинката за %1$s</string>
<string name="sync_conflicts_in_favourites_ticker">Пронајден е конфликт</string>
+ <string name="sync_conflicts_in_favourites_content">%1$d држи-ги-синхрознизирани датотеките не можеа да се синхронизираат</string>
+ <string name="sync_fail_in_favourites_ticker">држи-ги-синхрознизирани датотеките не успеа</string>
+ <string name="sync_fail_in_favourites_content">Содржината на %1$d датотеки не може да се синхронизираат (%2$d конфликти)</string>
+ <string name="sync_foreign_files_forgotten_ticker">Некои локални датотеки беа заборавени</string>
+ <string name="sync_foreign_files_forgotten_content">%1$d датотеки од %2$s папката не можат да се копираат</string>
+ <string name="sync_foreign_files_forgotten_explanation">Од верзијата 1.3.16, датотеките прикачени од овој уред се копираат во локалниот фолдер %1$s за да се спречи загуба на податоци кога една датотека се синхронизира со повеќе сметки.\n\nПоради оваа промена, сите датотеки прикачени во претходните верзии на оваа апликација беа копирани во %2$s папката. Меѓутоа, грешка спречи го спречи завршувањето на оваа операција за време на синхронизацијата на сметката. Можете или да ја оставите датотеката(ките) како што е/се или да го отстраните линкот до %3$s, или да ја преместите датотеката(ките) во папката %1$s и да го зачувате линкот до %4$s.\n\nПодолу се наведени локалните датотеки и одалечените датотеки во %5$s каде што беа поврзани.</string>
+ <string name="sync_current_folder_was_removed">Папката %1$s веќе не постои</string>
<string name="foreign_files_move">Префрли ги сите</string>
- <string name="pincode_enter_pin_code">Ве молам внесето го вашиот апликативен ПИН</string>
- <string name="pincode_configure_your_pin">Внесето го вашиот апликативен ПИН</string>
- <string name="pincode_reenter_your_pincode">Ве молам повторно внесето го вашиот апликативен ПИН</string>
- <string name="pincode_remove_your_pincode">Одстранете го го вашиот апликативен ПИН</string>
- <string name="pincode_mismatch">Апликативните ПИН-ови не се исти</string>
- <string name="pincode_wrong">Грешен апликативен ПИН</string>
- <string name="pincode_removed">Апликативниот ПИН е одстранет</string>
- <string name="pincode_stored">Апликативниот ПИН е снимен</string>
- <string name="auth_trying_to_login">Обиди се да се најавиш...</string>
+ <string name="foreign_files_success">Сите папки беа преместени</string>
+ <string name="foreign_files_fail">Некои датотеки не можат да се преместат</string>
+ <string name="foreign_files_local_text">Локално: %1$s</string>
+ <string name="foreign_files_remote_text">Одалечено: %1$s</string>
+ <string name="upload_query_move_foreign_files">Нема доволно место за да се копират избраните датотеки во папката %1$s. Сакате ли да ги преместите наместо тоа?</string>
+ <string name="pass_code_enter_pass_code">Ве молам, внесете го вашиот код</string>
+ <string name="pass_code_configure_your_pass_code">Венсете го вашиот код</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Кодот ќе биде баран секогаш кога ќе биде покрената апликацијата</string>
+ <string name="pass_code_reenter_your_pass_code">Ве молам, повторно внесете го вашиот код</string>
+ <string name="pass_code_remove_your_pass_code">Избришете го вашиот код</string>
+ <string name="pass_code_mismatch">Кодовите не се исти</string>
+ <string name="pass_code_wrong">Неточен код</string>
+ <string name="pass_code_removed">Кодот е отстранет</string>
+ <string name="pass_code_stored">Кодот е снимен</string>
+ <string name="media_notif_ticker">%1$s пуштач на музика</string>
+ <string name="media_state_playing">%1$s (свири)</string>
+ <string name="media_state_loading">%1$s (вчитувам)</string>
+ <string name="media_event_done">репродуцирањето на %1$s заврши</string>
+ <string name="media_err_nothing_to_play">Не се најдени медиум датотеки </string>
+ <string name="media_err_no_account">Не е обезбедена сметка</string>
+ <string name="media_err_not_in_owncloud">Датотеката не е во валидна сметка</string>
+ <string name="media_err_unsupported">Неподржан кодек на медиумот</string>
+ <string name="media_err_io">Медиа датотеката не може да се прочита</string>
+ <string name="media_err_malformed">Медиа датотеката не е точно енкодирана</string>
+ <string name="media_err_timeout">Заврши времето за пробување да се пушти </string>
+ <string name="media_err_invalid_progressive_playback">Медиа датотеката не може да се стрима</string>
+ <string name="media_err_unknown">Медиа датотеката не може да се пушти со вградениот пуштач на медиум</string>
+ <string name="media_err_security_ex">Сигурносна грешка при пуштање на %1$s</string>
+ <string name="media_err_io_ex">Влезна грешка при пуштање на %1$s</string>
+ <string name="media_err_unexpected">Неочекувана грешка при пуштање на %1$s</string>
+ <string name="media_rewind_description">Копче за премотување</string>
+ <string name="media_play_pause_description">Копче за пуштање или пауза</string>
+ <string name="media_forward_description">Копче за брзо премотување</string>
+ <string name="auth_getting_authorization">Добивање на авторизација...</string>
+ <string name="auth_trying_to_login">Пробувам се да се најавам...</string>
<string name="auth_no_net_conn_title">Нема мрежна конекција</string>
<string name="auth_nossl_plain_ok_title">Нема безбедна конекција.</string>
<string name="auth_connection_established">Конекцијата е воспоставена</string>
- <string name="auth_testing_connection">Ја тестирам врската...</string>
- <string name="auth_unknown_error_title">Се појави непознаа грешка!</string>
+ <string name="auth_testing_connection">Тестирање на конекцијата</string>
+ <string name="auth_not_configured_title">Погрешна конфигурација на серверот</string>
+ <string name="auth_account_not_new">Сметка за истиот корисник и сервер веќе постои на уредот</string>
+ <string name="auth_account_not_the_same">Внесениот корисник не се совпаѓа со корисникот на оваа сметка</string>
+ <string name="auth_unknown_error_title">Се појави непозната грешка!</string>
<string name="auth_unknown_host_title">Не можев да го најдам хостот</string>
<string name="auth_incorrect_path_title">Серверската инстанца не е пронајдена</string>
<string name="auth_timeout_title">На серверот му треба премногу време за да одговори</string>
+ <string name="auth_incorrect_address_title">Расипано URL</string>
<string name="auth_ssl_general_error_title">Неуспешна SSL иницијализација</string>
<string name="auth_ssl_unverified_server_title">Не можев да го проверам SSL серверскиот идентитет</string>
<string name="auth_bad_oc_version_title">Верзијата на серверот не е препознаена</string>
<string name="auth_secure_connection">Воспоставена е безбедна конекција</string>
<string name="auth_unauthorized">Погрешно корисничко име или лозинка</string>
<string name="auth_oauth_error">Неуспешна авторизација</string>
+ <string name="auth_oauth_error_access_denied">Одбиен пристап од авторизацискиот сервер</string>
+ <string name="auth_wtf_reenter_URL">Неочекувана сосотојба; ве молам, внесете го URL на серверот уште еднаш</string>
+ <string name="auth_expired_oauth_token_toast">Вашата авторизација истече. Ве молам, авторизирајте се повторно</string>
<string name="auth_expired_basic_auth_toast">Внесете ја вашата тековна лозинка:</string>
+ <string name="auth_expired_saml_sso_token_toast">Вашата сесија истече. Ве молам поврзете се повторно</string>
+ <string name="auth_connecting_auth_server">Се поврзувам со серверот за авторизација</string>
+ <string name="auth_unsupported_auth_method">Серверот не го подржува овој метод на авторизација</string>
+ <string name="auth_unsupported_multiaccount">%1$s не подржува повеќе сметки</string>
+ <string name="auth_fail_get_user_name">Вашиот сервер не праќа точен кориснички id, ве молам контактирајте го администраторот
+ </string>
+ <string name="auth_can_not_auth_against_server">Не можам да се авторизирам на овој сервер </string>
+ <string name="auth_account_does_not_exist">Сметката сеуште не постои на овој уред</string>
<string name="fd_keep_in_sync">Чувај ги датотеките ажурно</string>
<string name="common_rename">Преименувај</string>
<string name="common_remove">Отстрани</string>
<string name="confirmation_remove_alert">Дали навистина сакаш да ја отстраниш %1$s?</string>
+ <string name="confirmation_remove_folder_alert">Дали навистина сакаш да го отстранам %1$s и неговата содржина?</string>
<string name="confirmation_remove_local">Само локално</string>
+ <string name="confirmation_remove_folder_local">Само локална содржина</string>
<string name="confirmation_remove_remote">Отстрани од серверот</string>
<string name="confirmation_remove_remote_and_local">Далечинско и локално</string>
<string name="remove_success_msg">Одстранувањето е успешно</string>
<string name="remove_fail_msg">Одстранувањето е неуспешно</string>
<string name="rename_dialog_title">Внеси ново име</string>
+ <string name="rename_local_fail_msg">Локалната копија не може да се преименува; пробајте со друго име</string>
<string name="rename_server_fail_msg">Преименувањето не можеше да се комплетира</string>
+ <string name="sync_file_fail_msg">Одалечената датотека не може да се провери</string>
+ <string name="sync_file_nothing_to_do_msg">Содржината на датотеката веќе е синхронизирана</string>
<string name="create_dir_fail_msg">Папката не можеше да се креира</string>
+ <string name="filename_forbidden_characters">Забранети карактери: / \\ < > : \" | ? *</string>
+ <string name="filename_empty">Името на датотеката не може да биде празно</string>
<string name="wait_a_moment">Почекајте малку</string>
<string name="filedisplay_unexpected_bad_get_content">Неочекуван проблем ; ве молам одберете датотека од друга апликација</string>
<string name="filedisplay_no_file_selected">Нема избрано датотека</string>
+ <string name="activity_chooser_title">Пратете линк на ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Копирам датотека од приватното складиште</string>
<string name="oauth_check_onoff">Најави се со oAuth2</string>
+ <string name="oauth_login_connection">Се поврзувам со серверот на oAuth2</string>
+ <string name="ssl_validator_header">Идентитетот на страната не може да се потврди</string>
+ <string name="ssl_validator_reason_cert_not_trusted">- Сертификатот на серверот не е доверлив</string>
+ <string name="ssl_validator_reason_cert_expired">- Сетификатот на серверот е истечен</string>
+ <string name="ssl_validator_reason_cert_not_yet_valid">- Датумите на сертификатот се од иднината</string>
+ <string name="ssl_validator_reason_hostname_not_verified">- URL не се совпаѓа со hostname во сертификатот</string>
+ <string name="ssl_validator_question">Дали сепак сакате да му верувате на овој сертификат?</string>
+ <string name="ssl_validator_not_saved">Сетификатот не може да се сними</string>
<string name="ssl_validator_btn_details_see">Детали</string>
<string name="ssl_validator_btn_details_hide">Сокриј</string>
<string name="ssl_validator_label_subject">Издаден на:</string>
<string name="ssl_validator_label_issuer">Издаден од:</string>
+ <string name="ssl_validator_label_CN">Заедничко име:</string>
<string name="ssl_validator_label_O">Организација</string>
+ <string name="ssl_validator_label_OU">Огранизациски оддел:</string>
<string name="ssl_validator_label_C">Земја:</string>
<string name="ssl_validator_label_ST">Држава:</string>
<string name="ssl_validator_label_L">Локација:</string>
<string name="ssl_validator_label_validity_to">До:</string>
<string name="ssl_validator_label_signature">Потпис:</string>
<string name="ssl_validator_label_signature_algorithm">Алгоритам:</string>
+ <string name="ssl_validator_null_cert">Сертификатот не може да прикаже.</string>
+ <string name="ssl_validator_no_info_about_error">- Нема информација за грешката</string>
+ <string name="placeholder_sentence">Ова е резервирано место</string>
+ <string name="placeholder_filename">placeholder.txt</string>
+ <string name="placeholder_filetype">PNG слика</string>
<string name="placeholder_filesize">389 KB</string>
<string name="placeholder_timestamp">2012/05/18 12:23 PM</string>
<string name="placeholder_media_time">12:23:45</string>
- <string name="conflict_title">Конфликт при надградбата</string>
+ <string name="instant_upload_on_wifi">Прикачувај слики само преку WiFi</string>
+ <string name="instant_video_upload_on_wifi">Прикачувај видеа само преку WiFi</string>
+ <string name="instant_upload_path">/InstantUpload</string>
+ <string name="conflict_title">Конфликт при ажурирање</string>
+ <string name="conflict_message">Одалечената датотека %s не е синхронизирана со локалната датотека. Ако продолжите ќе се замени содржината на датотеката на серверот.</string>
<string name="conflict_keep_both">Задржи ги и двете</string>
<string name="conflict_overwrite">Препиши</string>
+ <string name="conflict_dont_upload">Не прикачувај</string>
+ <string name="preview_image_description">Преглед на сликата</string>
+ <string name="preview_image_error_unknown_format">Сликата не може да се прикаже</string>
+ <string name="error__upload__local_file_not_copied">%1$s не може да се копира во локалната папка %2$s</string>
+ <string name="prefs_instant_upload_path_title">Патека за прикачување</string>
+ <string name="share_link_no_support_share_api">Жалиме, споделувањето не е овозможено на вашиот сервер. Ве молам контактирајте го вашиот
+ администратор.</string>
+ <string name="share_link_file_no_exist">Не можам да споделам. Ве молам проверете дали постои датотеката</string>
+ <string name="share_link_file_error">Се случи грешка кога пробав да ја споделам оваа папка</string>
+ <string name="unshare_link_file_no_exist">Не можам да го тргнам споделувањето. Ве молам проверете дали постои датотеката</string>
+ <string name="unshare_link_file_error">Се случи грешка кога пробав да го тргнам споделувањето на оваа датотека или папка</string>
+ <string name="share_link_password_title">Внесете лозинка</string>
+ <string name="share_link_empty_password">Морате да внесете лозинка</string>
<string name="activity_chooser_send_file_title">Прати</string>
+ <string name="copy_link">Копирај врска</string>
+ <string name="clipboard_text_copied">Копирано во клипборд</string>
+ <string name="error_cant_bind_to_operations_service">Критична грешка: не можам да ја извршам операцијата</string>
+ <string name="network_error_socket_exception">Се случи грешка при конектирање со серверот.</string>
+ <string name="network_error_socket_timeout_exception">Се случи грешка при чекање на на серверот, операцијата не можеше да се изврши</string>
+ <string name="network_error_connect_timeout_exception">Се случи грешка при чекање на на серверот, операцијата не можеше да се изврши</string>
+ <string name="network_host_not_available">Операцијата не можеше да заврши, серверот не е достапен</string>
<string name="empty"></string>
+ <string name="forbidden_permissions">Немате дозвола %s</string>
+ <string name="forbidden_permissions_rename">да ја преименувате датотеката</string>
+ <string name="forbidden_permissions_delete">да ја избришете оваа датотека</string>
+ <string name="share_link_forbidden_permissions">да ја споделите оваа датотека</string>
+ <string name="unshare_link_forbidden_permissions">да тргнете споделување на оваа датотека</string>
+ <string name="forbidden_permissions_create">да создадете датотека</string>
+ <string name="uploader_upload_forbidden_permissions">да прикачите во оваа папка</string>
+ <string name="downloader_download_file_not_found">Датотеката веќе не е достапна на серверот</string>
<string name="prefs_category_accounts">Сметки</string>
+ <string name="prefs_add_account">Додади сметка</string>
+ <string name="auth_redirect_non_secure_connection_title">Сигурната конекција е преусмерена на несигурна рута.</string>
+ <string name="actionbar_logger">Логови</string>
+ <string name="log_send_history_button">Прати историја</string>
+ <string name="log_send_no_mail_app">Нема апликација за праќање на логови. Инсталирајте апликација за пошта!</string>
+ <string name="log_send_mail_subject">%1$s Апликација на Андроид за логови</string>
+ <string name="log_progress_dialog_text">Вчитувам на податоци...</string>
<string name="saml_authentication_required_text">Потребна е автентификација</string>
<string name="saml_authentication_wrong_pass">Погрешна лозинка</string>
- <string name="move_choose_button_text">Избери</string>
+ <string name="actionbar_move">Премести</string>
+ <string name="file_list_empty_moving">Тука нема ништо. Можете да додадете папка!</string>
+ <string name="folder_picker_choose_button_text">Избери</string>
+ <string name="move_file_not_found">Не можам да преместам. Ве молам проверете дали постои датотеката</string>
+ <string name="move_file_invalid_into_descendent">Не е можно да се премести папката во нејзината подпапка</string>
+ <string name="move_file_invalid_overwrite">Датотеката веќе постои во целната папка</string>
+ <string name="move_file_error">Се случи грешка кога пробував да ја преместам оваа датотека или папка</string>
+ <string name="forbidden_permissions_move">да ја преместам оваа датотека</string>
+ <string name="prefs_category_instant_uploading">Инстант прикачувања</string>
<string name="prefs_category_security">Безбедност</string>
+ <string name="prefs_instant_video_upload_path_title">Прикачи патека на видео</string>
+ <string name="download_folder_failed_content">Превземањето на папката %1$s не може да се заврши</string>
+ <string name="auth_refresh_button">Освежи ја конекцијата</string>
+ <string name="auth_host_address">Адреса на сервер</string>
</resources>
<string name="actionbar_upload_files">ഫയലുകൾ</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="sync_string_files">ഫയലുകൾ</string>
<string name="empty"></string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="actionbar_upload">Байршуулах</string>
+ <string name="actionbar_upload_files">Файлууд</string>
+ <string name="actionbar_settings">Тохиргоо</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="prefs_category_general">Ерөнхий</string>
+ <string name="auth_username">Хэрэглэгчийн нэр</string>
+ <string name="auth_password">Нууц үг</string>
+ <string name="sync_string_files">Файлууд</string>
+ <string name="uploader_btn_upload_text">Байршуулах</string>
+ <string name="create_account">Аккаунт үүсгэх</string>
+ <string name="common_remove">Устгах</string>
<string name="empty"></string>
+ <string name="prefs_category_security">Аюулгүй байдал</string>
</resources>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--TODO re-enable when server-side folder size calculation is available
+ <item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="empty"></string>
+</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="about_version">versi %1$s</string>
<string name="actionbar_upload">Muat naik</string>
<string name="actionbar_upload_files">Fail-fail</string>
+ <string name="actionbar_open_with">Buka dengan</string>
<string name="actionbar_settings">Set</string>
+ <string name="actionbar_send_file">Hantar</string>
+ <string name="actionbar_sort">Susun</string>
+ <string name="actionbar_sort_title">Susun mengikut</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Baharu - Lama</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Umum</string>
<string name="prefs_category_more">Lanjutan</string>
<string name="prefs_accounts">Akaun</string>
- <string name="prefs_pincode">PIN App</string>
<string name="prefs_help">Bantuan</string>
<string name="auth_username">Nama pengguna</string>
<string name="auth_password">Kata laluan</string>
<string name="uploader_upload_failed_ticker">Muatnaik gagal</string>
<string name="downloader_download_in_progress_ticker">Muatturun....</string>
<string name="common_choose_account">Pilih akaun</string>
- <string name="pincode_configure_your_pin">Masukkan PIN App anda</string>
- <string name="pincode_reenter_your_pincode">Sila, memasukkan semula PIN App anda</string>
- <string name="pincode_stored">PIN App disimpan</string>
<string name="auth_no_net_conn_title">Tiada sambungan rangkaian</string>
<string name="common_rename">Namakan</string>
<string name="common_remove">Buang</string>
<string name="confirmation_remove_local">Lokal sahaja</string>
+ <string name="activity_chooser_send_file_title">Hantar</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Akaun</string>
+ <string name="auth_host_address">Alamat pelayan</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_upload_files">ဖိုင်များ</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_help">အကူအညီ</string>
<string name="auth_username">သုံးစွဲသူအမည်</string>
<string name="auth_password">စကားဝှက်</string>
<string name="common_ok">အိုကေ</string>
<string name="common_cancel">ပယ်ဖျက်မည်</string>
<string name="empty"></string>
- <string name="move_choose_button_text">ရွေးချယ်</string>
+ <string name="folder_picker_choose_button_text">ရွေးချယ်</string>
</resources>
<string name="actionbar_settings">Innstillinger</string>
<string name="actionbar_see_details">Detaljer</string>
<string name="actionbar_send_file">Send</string>
+ <string name="actionbar_sort">Sorter</string>
+ <string name="actionbar_sort_title">Sorter etter</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Nyeste - Eldste</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Alle filer</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Innstillinger</string>
+ <string name="drawer_item_logs">Logger</string>
+ <string name="drawer_close">Lukk</string>
<string name="prefs_category_general">Generelt</string>
<string name="prefs_category_more">Mer</string>
<string name="prefs_accounts">Kontoer</string>
<string name="prefs_manage_accounts">Håndter kontoer</string>
- <string name="prefs_pincode">PIN kode</string>
- <string name="prefs_pincode_summary">Beskytt klienten din</string>
+ <string name="prefs_passcode">Passordlås</string>
<string name="prefs_instant_upload">Umiddelbare bildeopplastninger</string>
<string name="prefs_instant_upload_summary">Last opp bilder tatt av kameraet umiddelbart</string>
<string name="prefs_instant_video_upload">Umiddelbare video-opplastninger</string>
<string name="prefs_recommend">Anbefal til en venn</string>
<string name="prefs_feedback">Tilbakemelding</string>
<string name="prefs_imprint">Avtrykk</string>
+ <string name="prefs_remember_last_share_location">Husk delt plassering</string>
+ <string name="prefs_remember_last_upload_location_summary">Husk sist delt plassering for opplasting</string>
<string name="recommend_subject">Prøv %1$s på smarttelefonen din!</string>
<string name="recommend_text">Jeg ønsker å invitere deg til å bruke %1$s på smarttelefonen din!\nLast ned her: %2$s</string>
<string name="auth_check_server">Sjekk server</string>
<string name="sync_string_files">Filer</string>
<string name="setup_btn_connect">Koble til</string>
<string name="uploader_btn_upload_text">Last opp</string>
+ <string name="uploader_btn_new_folder_text">Ny mappe</string>
<string name="uploader_top_message">Velg opplastingsmappe:</string>
<string name="uploader_wrn_no_account_title">Ingen konto funnet</string>
<string name="uploader_wrn_no_account_text">Det finnes ingen %1$s kontoer for din enhet. For å bruker denne appen må du først opprette en.</string>
<string name="filedetails_download">Last ned</string>
<string name="filedetails_sync_file">Oppdater fil</string>
<string name="filedetails_renamed_in_upload_msg">Filnavnet ble endret til %1$s under opplasting</string>
+ <string name="list_layout">Listeoppsett</string>
<string name="action_share_file">Del lenke</string>
<string name="action_unshare_file">Avslutt deling av lenke</string>
<string name="common_yes">Ja</string>
<string name="foreign_files_local_text">Lokal: %1$s</string>
<string name="foreign_files_remote_text">Ekstern: %1$s</string>
<string name="upload_query_move_foreign_files">Det er ikke nok plass til å kopiere de valgte filene inn i mappen %1$s. Vil du flytte dem i stedet? </string>
- <string name="pincode_enter_pin_code">Vennligst tast inn din App-PIN</string>
- <string name="pincode_configure_your_pin">Skriv inn din PIN kode</string>
- <string name="pincode_configure_your_pin_explanation">PIN koden vil bli ettersourt hver gang appen starter</string>
- <string name="pincode_reenter_your_pincode">Vennligst tast inn din PIN kode på nytt</string>
- <string name="pincode_remove_your_pincode">Fjern din PIN kode</string>
- <string name="pincode_mismatch">PIN kodene du tastet er ulike</string>
- <string name="pincode_wrong">Feil PIN kode</string>
- <string name="pincode_removed">PIN kode fjernet</string>
- <string name="pincode_stored">PIN kode lagret</string>
+ <string name="pass_code_enter_pass_code">Legg inn passordet ditt</string>
+ <string name="pass_code_configure_your_pass_code">Skriv inn passordet ditt</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Passordet vil bli krevd hver gang appen startes</string>
+ <string name="pass_code_reenter_your_pass_code">Skriv inn passordet på nytt</string>
+ <string name="pass_code_remove_your_pass_code">Fjern passordet ditt</string>
+ <string name="pass_code_mismatch">Passordene er ikke like</string>
+ <string name="pass_code_wrong">Feil passord</string>
+ <string name="pass_code_removed">Passord fjernet</string>
+ <string name="pass_code_stored">Passord lagret</string>
<string name="media_notif_ticker">%1$s musikkspiller</string>
<string name="media_state_playing">%1$s (spiller)</string>
<string name="media_state_loading">%1$s (laster)</string>
<string name="auth_no_net_conn_title">Ingen nettverkstilkobling</string>
<string name="auth_nossl_plain_ok_title">Sikker tilkobling ikke tilgjengelig.</string>
<string name="auth_connection_established">Tilkobling opprettet</string>
- <string name="auth_testing_connection">Tester tilgang...</string>
+ <string name="auth_testing_connection">Tester forbindelsen</string>
<string name="auth_not_configured_title">Feil i server konfigurasjon</string>
<string name="auth_account_not_new">En konto for samme bruker og server finnes allerede på enheten</string>
<string name="auth_account_not_the_same">Den innskrevne brukeren matcher ikke brukeren av denne kontoen</string>
<string name="auth_fail_get_user_name">Tjeneren din svarer ikke med korrekt bruker-ID, vennligst ta kontakt med en administrator
</string>
<string name="auth_can_not_auth_against_server">Kan ikke autentisere mot denne serveren</string>
+ <string name="auth_account_does_not_exist">Kontoen eksisterer ikke på enheten enda</string>
<string name="fd_keep_in_sync">Hold filen oppdatert</string>
<string name="common_rename">Endre navn</string>
<string name="common_remove">Fjern</string>
<string name="sync_file_nothing_to_do_msg">filinnhold er allerede synkronisert</string>
<string name="create_dir_fail_msg">Mappe kunne ikke opprettes</string>
<string name="filename_forbidden_characters">Forbudte tegn: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Filnavnet inneholder minst ett ulovlig tegn</string>
<string name="filename_empty">Filnavn kan ikke være tomt</string>
<string name="wait_a_moment">Vent et øyeblikk</string>
<string name="filedisplay_unexpected_bad_get_content">Uforventet problem; vennligst velg filen fra en annen applikasjon</string>
<string name="filedisplay_no_file_selected">Ingen fil ble valgt</string>
<string name="activity_chooser_title">Send lenke til ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Kopierer fil fra privat lager</string>
<string name="oauth_check_onoff">Logg inn med oAuth2</string>
<string name="oauth_login_connection">Kobler til oAuth2 server...</string>
<string name="ssl_validator_header">Identiteten til siden kunne ikke verifiseres</string>
<string name="preview_image_description">Bildeforhåndsvisning</string>
<string name="preview_image_error_unknown_format">Dette bildet kan ikke vises</string>
<string name="error__upload__local_file_not_copied">%1$s kunne ikke kopieres til lokal mappe %2$s</string>
+ <string name="prefs_instant_upload_path_title">Sti til opplasting</string>
<string name="share_link_no_support_share_api">Beklager, deling er ikke skrudd på for din tjener. Ta kontakt med
administratoren.</string>
<string name="share_link_file_no_exist">Kan ikke dele. Sjekk om filen eksisterer.</string>
<string name="share_link_file_error">Det skjedde en feil under deling av denne filen eller mappen</string>
<string name="unshare_link_file_no_exist">Kan ikke fjerne deling. Sjekk om filen eksisterer.</string>
<string name="unshare_link_file_error">En feil oppstod ved avslutting av delingen av denne filen eller mappen</string>
+ <string name="share_link_password_title">Skriv inn ett passord</string>
+ <string name="share_link_empty_password">Du må skrive inn ett passord</string>
<string name="activity_chooser_send_file_title">Send</string>
<string name="copy_link">Kopier lenke</string>
<string name="clipboard_text_copied">Kopiert til utklippstavlen</string>
<string name="downloader_download_file_not_found">Filen finnes ikke på serveren lenger</string>
<string name="prefs_category_accounts">Kontoer</string>
<string name="prefs_add_account">Legg til en konto</string>
+ <string name="auth_redirect_non_secure_connection_title">Sikker forbindelse er omdirigert til en usikker rute.</string>
<string name="actionbar_logger">Logger</string>
<string name="log_send_history_button">Send historikk</string>
- <string name="log_mail_subject">logger for ownCloud Android app</string>
+ <string name="log_send_no_mail_app">Ingen app for sending av logger funnet. Installer epost-app!</string>
+ <string name="log_send_mail_subject">%1$s Android app logger</string>
<string name="log_progress_dialog_text">Laster data...</string>
<string name="saml_authentication_required_text">Autentisering kreves</string>
<string name="saml_authentication_wrong_pass">Feil passord</string>
<string name="actionbar_move">Flytt</string>
<string name="file_list_empty_moving">Ingenting her. Du kan legge til en mappe!</string>
- <string name="move_choose_button_text">Velg</string>
+ <string name="folder_picker_choose_button_text">Velg</string>
<string name="move_file_not_found">Kan ikke flytte. Sjekk om filen eksisterer.</string>
<string name="move_file_invalid_into_descendent">Det er ikke mulig å flytte en mappe inn i sin egen undermappe</string>
<string name="move_file_invalid_overwrite">Filen finnes allerede i målmappen</string>
<string name="move_file_error">En feil oppstod ved flytting av denne filen eller mappen</string>
<string name="forbidden_permissions_move">å flytte denne filen</string>
+ <string name="prefs_category_instant_uploading">Umiddelbare opplastinger</string>
<string name="prefs_category_security">Sikkerhet</string>
+ <string name="prefs_instant_video_upload_path_title">Sti til video-opplasting</string>
+ <string name="download_folder_failed_content">Nedlasting av %1$s mappen kunne ikke fullføres</string>
+ <string name="shared_subject_header">delte</string>
+ <string name="with_you_subject_header">med deg</string>
+ <string name="subject_token">%1$s delte \"%2$s\" med deg</string>
+ <string name="auth_refresh_button">Oppfrisk forbindelse</string>
+ <string name="auth_host_address">Server-adresse</string>
+ <string name="common_error_out_memory">Ikke nok minne</string>
+ <string name="username">Brukernavn</string>
+ <string name="file_list__footer__folder">1 mappe</string>
+ <string name="file_list__footer__folders">%1$d mapper</string>
+ <string name="file_list__footer__file">1 fil</string>
+ <string name="file_list__footer__file_and_folder">1 fil, 1 mappe</string>
+ <string name="file_list__footer__file_and_folders">1 fil, %1$d mapper</string>
+ <string name="file_list__footer__files">%1$d filer</string>
+ <string name="file_list__footer__files_and_folder">%1$d filer, 1 mappe</string>
+ <string name="file_list__footer__files_and_folders">%1$d filer, %2$d mapper</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Alle bestanden</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Instellingen</string>
+ <string name="drawer_item_logs">Logs</string>
+ <string name="drawer_close">Sluiten</string>
<string name="prefs_category_general">Algemeen</string>
<string name="prefs_category_more">Meer</string>
<string name="prefs_accounts">Accounts</string>
<string name="prefs_manage_accounts">Beheer accounts</string>
- <string name="prefs_pincode">App PIN</string>
- <string name="prefs_pincode_summary">Beveilig je client</string>
+ <string name="prefs_passcode">Pincode slot</string>
<string name="prefs_instant_upload">Directe uploads van afbeeldingen</string>
<string name="prefs_instant_upload_summary">Direct uploaden van foto\'s genomen met de camera</string>
<string name="prefs_instant_video_upload">Direct uploaden van video\'s</string>
<string name="sync_string_files">Bestanden</string>
<string name="setup_btn_connect">Verbinden</string>
<string name="uploader_btn_upload_text">Uploaden</string>
+ <string name="uploader_btn_new_folder_text">Nieuwe map</string>
<string name="uploader_top_message">Kies upload map:</string>
<string name="uploader_wrn_no_account_title">Geen account gevonden</string>
<string name="uploader_wrn_no_account_text">Er zijn nog geen %1$s accounts op je apparaat. Stel eerst een account in.</string>
<string name="uploader_info_uploading">Uploaden</string>
<string name="file_list_seconds_ago">seconden geleden</string>
<string name="file_list_empty">Er bevindt zich hier niets. Upload een bestand!</string>
- <string name="file_list_loading">Laden ...</string>
+ <string name="file_list_loading">Laden...</string>
<string name="local_file_list_empty">Er staan geen bestanden in deze map.</string>
<string name="filedetails_select_file">Druk op een bestand om extra informatie weer te geven</string>
<string name="filedetails_size">Grootte:</string>
<string name="filedetails_download">Download</string>
<string name="filedetails_sync_file">Bestand verversen</string>
<string name="filedetails_renamed_in_upload_msg">Bestand is tijdens het uploaden hernoemd naar %1$s</string>
+ <string name="list_layout">Lijst layout</string>
<string name="action_share_file">Deel link</string>
<string name="action_unshare_file">Link niet meer delen</string>
<string name="common_yes">Ja</string>
<string name="foreign_files_local_text">Lokaal: %1$s</string>
<string name="foreign_files_remote_text">Extern: %1$s</string>
<string name="upload_query_move_foreign_files">Er is niet genoeg ruimte om de bestanden te gekopieëren in map %1$s. Wilt u ze erheen verplaatsten? </string>
- <string name="pincode_enter_pin_code">Voer App PIN in</string>
- <string name="pincode_configure_your_pin">Voer App PIN in</string>
- <string name="pincode_configure_your_pin_explanation">De PIN wordt steeds opnieuw gevraagd als de app wordt gestart</string>
- <string name="pincode_reenter_your_pincode">Voer App PIN opnieuw in</string>
- <string name="pincode_remove_your_pincode">Verwijder App PIN</string>
- <string name="pincode_mismatch">App PIN\'s komen niet overeen</string>
- <string name="pincode_wrong">Foutieve applicatie PIN</string>
- <string name="pincode_removed">App PIN verwijderd</string>
- <string name="pincode_stored">App PIN opgeslagen</string>
+ <string name="pass_code_enter_pass_code">Geef uw pincode op</string>
+ <string name="pass_code_configure_your_pass_code">Invoeren pincode</string>
+ <string name="pass_code_configure_your_pass_code_explanation">De pincode wordt elke keer gevraagd bij opstarten van de app</string>
+ <string name="pass_code_reenter_your_pass_code">Voer de pincode nogmaals in</string>
+ <string name="pass_code_remove_your_pass_code">Verwijderen pincode</string>
+ <string name="pass_code_mismatch">De pincodes komen niet overeen</string>
+ <string name="pass_code_wrong">Onjuiste pincode</string>
+ <string name="pass_code_removed">Pincode verwijderd</string>
+ <string name="pass_code_stored">Pincode opgeslagen</string>
<string name="media_notif_ticker">%1$s muziekspeler</string>
<string name="media_state_playing">%1$s (speelt)</string>
<string name="media_state_loading">%1$s (laden)</string>
<string name="auth_no_net_conn_title">Geen netwerkverbinding</string>
<string name="auth_nossl_plain_ok_title">Veilige verbinding niet beschikbaar.</string>
<string name="auth_connection_established">Verbinding tot stand gebracht</string>
- <string name="auth_testing_connection">Probeer verbinding...</string>
+ <string name="auth_testing_connection">Testen verbinding</string>
<string name="auth_not_configured_title">Foutieve server configuratie</string>
<string name="auth_account_not_new">Er bestaat al een account voor deze gebruiker en server op dit apparaat.</string>
<string name="auth_account_not_the_same">De opgegeven gebruiker komt niet overeen met de gebruiker van dit account</string>
<string name="auth_fail_get_user_name">Uw server geeft geen goede userid terug, neem contact op met uw beheerder
</string>
<string name="auth_can_not_auth_against_server">Kan niet authenticeren tegen deze server</string>
+ <string name="auth_account_does_not_exist">Het account bestaat nog niet in dit apparaat</string>
<string name="fd_keep_in_sync">Houd bestand actueel</string>
<string name="common_rename">Hernoemen</string>
<string name="common_remove">Verwijderen</string>
<string name="sync_file_nothing_to_do_msg">Bestandsinhoud is al gesynchroniseerd</string>
<string name="create_dir_fail_msg">Map kon niet worden aangemaakt</string>
<string name="filename_forbidden_characters">Verboden tekens: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">De bestandsnaam bevat ten minste één ongeldig teken</string>
<string name="filename_empty">Bestandsnaam mag niet leeg zijn</string>
<string name="wait_a_moment">Even geduld</string>
<string name="filedisplay_unexpected_bad_get_content">Onverwacht probleem; probeer een andere app om het bestand te selecteren</string>
<string name="filedisplay_no_file_selected">Er werd geen bestand geselecteerd</string>
<string name="activity_chooser_title">Verstuur link naar ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Kopiëren bestand vanaf privéopslag</string>
<string name="oauth_check_onoff">Inloggen met oAuth2</string>
<string name="oauth_login_connection">Verbinden met oAuth2-server.</string>
<string name="ssl_validator_header">De identiteit van de site kan niet worden gecontroleerd</string>
<string name="share_link_file_error">Er trad een fout op bij uw poging dit bestand of deze map te delen</string>
<string name="unshare_link_file_no_exist">Kan delen niet beëindigen. Ga na of het bestand bestaat</string>
<string name="unshare_link_file_error">Er trad een fout op bij uw poging het delen van dit bestand of deze map te beëindigen</string>
+ <string name="share_link_password_title">Vul het wachtwoord in</string>
+ <string name="share_link_empty_password">U moet een wachtwoord opgeven</string>
<string name="activity_chooser_send_file_title">Versturen</string>
<string name="copy_link">Link kopiëren</string>
<string name="clipboard_text_copied">Gekopieerd naar het klembord</string>
<string name="auth_redirect_non_secure_connection_title">De beveiligde verbinding is omgeleid naar een onveilige route.</string>
<string name="actionbar_logger">Logs</string>
<string name="log_send_history_button">Verstuur geschiedenis</string>
- <string name="log_mail_subject">ownCloud Android app logs</string>
+ <string name="log_send_no_mail_app">Geen app voor versturen van logs gevonden. Installeer de mail app!</string>
+ <string name="log_send_mail_subject">%1$s Android app logs</string>
<string name="log_progress_dialog_text">Laden data...</string>
<string name="saml_authentication_required_text">Authenticatie vereist</string>
<string name="saml_authentication_wrong_pass">Onjuist wachtwoord</string>
<string name="actionbar_move">verplaatsen</string>
<string name="file_list_empty_moving">Niets hier. U kunt een map toevoegen!</string>
- <string name="move_choose_button_text">Kies</string>
+ <string name="folder_picker_choose_button_text">Kies</string>
<string name="move_file_not_found">Kan niet verplaatsen. Ga na of het bestand wel bestaat</string>
<string name="move_file_invalid_into_descendent">De map kan niet naar een onderliggende map worden verplaatst</string>
<string name="move_file_invalid_overwrite">Het bestand bestaat al in de doelmap</string>
<string name="forbidden_permissions_move">om dit bestand te verplaatsen</string>
<string name="prefs_category_instant_uploading">Directe uploads</string>
<string name="prefs_category_security">Beveiliging</string>
+ <string name="prefs_instant_video_upload_path_title">Upload Video Pad</string>
+ <string name="download_folder_failed_content">Download van %1$s map kon niet worden voltooid</string>
+ <string name="shared_subject_header">gedeeld</string>
+ <string name="with_you_subject_header">met u</string>
+ <string name="subject_token">%1$s deelde \"%2$s\" met u</string>
+ <string name="auth_refresh_button">Verversen verbinding</string>
+ <string name="auth_host_address">Serveradres</string>
+ <string name="common_error_out_memory">Niet voldoende geheugen</string>
+ <string name="username">Gebruikersnaam</string>
+ <string name="file_list__footer__folder">1 map</string>
+ <string name="file_list__footer__folders">%1$d mappen</string>
+ <string name="file_list__footer__file">1 bestand</string>
+ <string name="file_list__footer__file_and_folder">1 bestand, 1 map</string>
+ <string name="file_list__footer__file_and_folders">1 bestand, %1$d mappen</string>
+ <string name="file_list__footer__files">%1$d bestanden</string>
+ <string name="file_list__footer__files_and_folder">%1$d bestanden, 1 map</string>
+ <string name="file_list__footer__files_and_folders">%1$d bestanden, %2$d mappen</string>
</resources>
<string name="actionbar_send_file">Send</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Generelt</string>
<string name="prefs_category_more">Meir</string>
<string name="prefs_accounts">Kontoar</string>
<string name="prefs_manage_accounts">Behandle kontoar</string>
- <string name="prefs_pincode">Programpinkode</string>
- <string name="prefs_pincode_summary">Beskytt klienten din</string>
<string name="prefs_instant_upload">Last opp bilete omgåande</string>
<string name="prefs_instant_upload_summary">Last opp bilete når du tek dei med kameraet</string>
<string name="prefs_instant_video_upload">Last opp film</string>
<string name="sync_string_files">Filer</string>
<string name="setup_btn_connect">Kopla til</string>
<string name="uploader_btn_upload_text">Last opp</string>
+ <string name="uploader_btn_new_folder_text">Ny mappe</string>
<string name="uploader_wrn_no_account_title">Fann ingen konto</string>
<string name="uploader_wrn_no_account_text">Det er ingen %1$s kontoar på eininga di. Gjer vel å konfigurer ein konto først.</string>
<string name="uploader_wrn_no_account_setup_btn_text">Oppsett</string>
<string name="common_choose_account">Vel konto</string>
<string name="sync_fail_ticker">Feil ved synkronisering</string>
<string name="sync_fail_content">Klarte ikkje å synkronisera ferdig %1$s</string>
- <string name="pincode_enter_pin_code">Ver venleg og skriv inn programpinkoden</string>
- <string name="pincode_configure_your_pin">Skriv inn programpinkoden</string>
- <string name="pincode_reenter_your_pincode">Ver venleg å skriv inn programpinkoden på nytt</string>
- <string name="pincode_remove_your_pincode">Fjern programpinkoden</string>
- <string name="pincode_mismatch">Programpinkodane er ikkje like</string>
- <string name="pincode_wrong">Feil programpinkode</string>
- <string name="pincode_removed">Programpinkode er fjerna</string>
- <string name="pincode_stored">Programpinkode er lagra</string>
<string name="auth_trying_to_login">Prøvar å logge på...</string>
<string name="auth_no_net_conn_title">Inga nettilkopling</string>
<string name="auth_nossl_plain_ok_title">Trygg tilkopling ikkje tilgjengeleg.</string>
<string name="auth_connection_established">Tilkopling oppretta</string>
- <string name="auth_testing_connection">Testar tilkopling...</string>
<string name="auth_not_configured_title">Ugyldig tenarkonfigurasjon</string>
<string name="auth_unknown_error_title">Ein ukjend feil oppstod!</string>
<string name="auth_unknown_host_title">Klarte ikkje å finna tenaren</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Kontoar</string>
<string name="saml_authentication_wrong_pass">Feil passord</string>
- <string name="move_choose_button_text">Vel</string>
+ <string name="folder_picker_choose_button_text">Vel</string>
<string name="prefs_category_security">Tryggleik</string>
+ <string name="auth_host_address">Tenaradresse</string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="about_version">version %1$s</string>
<string name="actionbar_upload">Amontcarga</string>
<string name="actionbar_upload_files">Fichièrs</string>
+ <string name="actionbar_mkdir">Novèl dorsièr</string>
<string name="actionbar_settings">Configuracion</string>
+ <string name="actionbar_send_file">Mandar</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Paramètres</string>
<string name="prefs_category_general">General</string>
<string name="prefs_category_more">Mai d\'aquò</string>
<string name="prefs_accounts">Comptes</string>
<string name="prefs_manage_accounts">Maneja comptes</string>
<string name="prefs_help">Ajuda</string>
+ <string name="prefs_imprint">Mencions legalas</string>
<string name="auth_username">Nom d\'usancièr</string>
<string name="auth_password">Senhal</string>
<string name="sync_string_files">Fichièrs</string>
<string name="setup_btn_connect">Connecta</string>
<string name="uploader_btn_upload_text">Amontcarga</string>
+ <string name="uploader_btn_new_folder_text">Novèl dorsièr</string>
<string name="uploader_wrn_no_account_title">Cap de compte trobat</string>
<string name="uploader_wrn_no_account_setup_btn_text">Configuracion</string>
<string name="uploader_wrn_no_account_quit_btn_text">Quita</string>
<string name="filedetails_created">Creat :</string>
<string name="filedetails_modified">Modificat :</string>
<string name="filedetails_download">Avalcarga</string>
+ <string name="action_share_file">Partiment per ligam</string>
<string name="common_yes">Òc</string>
<string name="common_no">Non</string>
<string name="common_ok">D\'accòrdi</string>
<string name="common_cancel_upload"> Anulla l\'amontcargar</string>
<string name="common_cancel">Annula</string>
<string name="common_error">Error</string>
+ <string name="common_error_unknown">Error Desconeguda </string>
<string name="about_title">A prepaus</string>
<string name="change_password">Cambia lo senhal</string>
<string name="delete_account">Escafa lo compte</string>
<string name="create_account">Crea un compte</string>
<string name="upload_chooser_title">Avalcarga dempuèi ...</string>
+ <string name="uploader_info_dirname">Nom del dorsièr</string>
<string name="uploader_upload_in_progress_ticker">Al avalcargar ...</string>
<string name="uploader_upload_succeeded_ticker">Capitada d\'avalcargar</string>
<string name="common_choose_account">Causís lo compte</string>
- <string name="pincode_enter_pin_code">Dintras ton PIN d\'App, se te plai</string>
<string name="common_rename">Torna nomenar</string>
+ <string name="common_remove">Suprimir</string>
+ <string name="ssl_validator_label_C">País :</string>
+ <string name="activity_chooser_send_file_title">Mandar</string>
+ <string name="clipboard_text_copied">Copiat dins lo quichapapièrs</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Comptes</string>
- <string name="move_choose_button_text">Causís</string>
+ <string name="saml_authentication_required_text">Autentificacion requesida</string>
+ <string name="saml_authentication_wrong_pass">Senhal incorrècte</string>
+ <string name="folder_picker_choose_button_text">Causís</string>
+ <string name="auth_host_address">Adreça del servidor</string>
+ <string name="username">Nom d\'utilizaire</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_send_file">ਭੇਜੋ</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">ਆਮ</string>
<string name="prefs_accounts">ਅਕਾਊਂਟ</string>
<string name="prefs_log_title">ਲਾਗ ਰੱਖਣਾ ਚਾਲੂ</string>
<string name="foreign_files_fail">ਕੁਝ ਫਾਇਲਾਂ ਨੂੰ ਭੇਜਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ</string>
<string name="foreign_files_local_text">ਲੋਕਲ: %1$s</string>
<string name="foreign_files_remote_text">ਰਿਮੋਟ: %1$s</string>
- <string name="pincode_enter_pin_code">ਆਪਣਾ ਐਪ ਪਿੰਨ ਦਿਉ ਜੀ</string>
<string name="media_notif_ticker">%1$s ਸੰਗੀਤ ਪਲੇਅਰ</string>
<string name="media_state_playing">%1$s (ਚੱਲਦਾ ਹੈ)</string>
<string name="media_state_loading">%1$s (ਲੋਡ ਹੁੰਦਾ ਹੈ)</string>
<string name="auth_no_net_conn_title">ਕੋਈ ਨੈੱਟਵਰਕ ਕੁਨੈਕਸ਼ਨ ਨਹੀਂ ਹੈ</string>
<string name="auth_nossl_plain_ok_title">ਸੁਰੱਖਿਅਤ ਕੁਨੈਕਸ਼ਨ ਉਪਲੱਬਧ ਨਹੀਂ ਹੈ।</string>
<string name="auth_connection_established">ਕੁਨੈਕਸ਼ਨ ਬਣਾਇਆ ਗਿਆ ਹੈ</string>
- <string name="auth_testing_connection">...ਕੁਨੈਕਸ਼ਨ ਟੈਸਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ</string>
<string name="auth_unknown_error_title">ਅਣਜਾਣ ਗਲਤੀ ਆਈ ਹੈ!</string>
<string name="auth_unknown_host_title">ਹੋਸਟ ਨਹੀਂ ਲੱਭਿਆ ਜਾ ਸਕਿਆ</string>
<string name="auth_ssl_general_error_title">SSL ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਫੇਲ੍ਹ ਹੈ</string>
<string name="activity_chooser_send_file_title">ਭੇਜੋ</string>
<string name="empty"></string>
<string name="prefs_category_accounts">ਅਕਾਊਂਟ</string>
- <string name="move_choose_button_text">ਚੁਣੋ</string>
+ <string name="folder_picker_choose_button_text">ਚੁਣੋ</string>
+ <string name="auth_host_address">ਸਰਵਰ ਐਡਰੈਸ</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Ogólne</string>
<string name="prefs_category_more">Więcej</string>
<string name="prefs_accounts">Konta</string>
<string name="prefs_manage_accounts">Zarządzaj kontami</string>
- <string name="prefs_pincode">PIN aplikacji</string>
- <string name="prefs_pincode_summary">Chroń swojego klienta</string>
+ <string name="prefs_passcode">Blokowanie hasła</string>
<string name="prefs_instant_upload">natychmiastowa wysyłka obrazków</string>
<string name="prefs_instant_upload_summary">Wysyłaj od razu zdjęcia zrobione aparatem</string>
<string name="prefs_instant_video_upload">Natychmiastowa wysyłka wideo</string>
<string name="prefs_recommend">Poleć znajomemu</string>
<string name="prefs_feedback">Wsparcie</string>
<string name="prefs_imprint">Stopka</string>
+ <string name="prefs_remember_last_share_location">Zapamiętaj położenie udostępnienia</string>
+ <string name="prefs_remember_last_upload_location_summary">Zapamiętaj ostatnią lokalizację wgrywania</string>
<string name="recommend_subject">Wypróbuj %1$s na swoim smartphonie!</string>
<string name="recommend_text">Chciałbym zaprosić Cię do używania %1$s na swoim smartfonie!\nŚciągnij tutaj: %2$s</string>
<string name="auth_check_server">Sprawdź serwer</string>
<string name="sync_string_files">Pliki</string>
<string name="setup_btn_connect">Połącz</string>
<string name="uploader_btn_upload_text">Wyślij</string>
+ <string name="uploader_btn_new_folder_text">Nowy folder</string>
<string name="uploader_top_message">Wybierz folder do wysłania:</string>
<string name="uploader_wrn_no_account_title">Nie znaleziono konta</string>
<string name="uploader_wrn_no_account_text">Nie wykryto kont %1$s na twoim urządzeniu. Załóż konto.</string>
<string name="uploader_info_uploading">Wysyłanie</string>
<string name="file_list_seconds_ago">sekund temu</string>
<string name="file_list_empty">Pusto. Wyślij coś!</string>
- <string name="file_list_loading">Ładowanie...</string>
<string name="local_file_list_empty">Nie ma plików w tym folderze.</string>
<string name="filedetails_select_file">Dotknij plik aby wyświetlić dodatkowe informacje</string>
<string name="filedetails_size">Rozmiar:</string>
<string name="filedetails_download">Pobierz</string>
<string name="filedetails_sync_file">Odśwież plik</string>
<string name="filedetails_renamed_in_upload_msg">Podczas wysyłania nazwa pliku została zmieniona na %1$s</string>
+ <string name="list_layout">Lista szablonów wyglądu</string>
<string name="action_share_file">Udostępnij link</string>
<string name="action_unshare_file">Anuluj udostępnianie</string>
<string name="common_yes">Tak</string>
<string name="foreign_files_local_text">Lokalnie: %1$s</string>
<string name="foreign_files_remote_text">Zdalnie: %1$s</string>
<string name="upload_query_move_foreign_files">Nie ma wystarczająco miejśca, aby skopiować zaznaczone pliki do folderu %1$s. Chciałbyś je przenieść?</string>
- <string name="pincode_enter_pin_code">Podaj PIN aplikacji</string>
- <string name="pincode_configure_your_pin">Wpisz PIN aplikacji</string>
- <string name="pincode_configure_your_pin_explanation">Kod PIN będzie wymagany za każdym razem, gdy aplikacja będzie uruchamiana.</string>
- <string name="pincode_reenter_your_pincode">Ponownie wpisz PIN aplikacji</string>
- <string name="pincode_remove_your_pincode">Usuń PIN aplikacji</string>
- <string name="pincode_mismatch">Podane numery PIN są różne</string>
- <string name="pincode_wrong">Niepoprawny PIN aplikacji</string>
- <string name="pincode_removed">Usunięto PIN aplikacji</string>
- <string name="pincode_stored">Zapisano PIN aplikacji</string>
+ <string name="pass_code_enter_pass_code">Proszę podać swoje hasło</string>
+ <string name="pass_code_configure_your_pass_code">Wpisz swoje hasło</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Hasło będzie wymagane przy każdym uruchomieniu aplikacji</string>
+ <string name="pass_code_reenter_your_pass_code">Proszę powtórzyć hasło</string>
+ <string name="pass_code_remove_your_pass_code">Usuń swoje hasło</string>
+ <string name="pass_code_mismatch">Podane hasła nie są takie same</string>
+ <string name="pass_code_wrong">Nieprawidłowe hasło</string>
+ <string name="pass_code_removed">Hasło zostało usunięte</string>
+ <string name="pass_code_stored">Hasło zostało zapisane</string>
<string name="media_notif_ticker">%1$s odtwarzacz muzyki</string>
<string name="media_state_playing">%1$s (odtwarzany)</string>
<string name="media_state_loading">%1$s (wczytywany)</string>
<string name="auth_no_net_conn_title">Brak połączenia sieciowego</string>
<string name="auth_nossl_plain_ok_title">Nie można nawiązać bezpiecznego połączenia.</string>
<string name="auth_connection_established">Połączenie nawiązane</string>
- <string name="auth_testing_connection">Testowanie połączenia…</string>
+ <string name="auth_testing_connection">Sprawdzanie połączenia</string>
<string name="auth_not_configured_title">Uszkodzona konfiguracja serwera</string>
<string name="auth_account_not_new">Konto tego samego użytkownika i serwera już istnieje na tym urządzeniu</string>
<string name="auth_account_not_the_same">Podany login nie pasuje do użytkowników </string>
<string name="auth_fail_get_user_name">Twój serwer nie zwraca prawidłowego id użytkownika, proszę skontaktuj się z administratorem
</string>
<string name="auth_can_not_auth_against_server">Nie można autoryzować przy użyciu tego serwera</string>
+ <string name="auth_account_does_not_exist">Konto nie istnieje jeszcze na tym urządzeniu</string>
<string name="fd_keep_in_sync">Automatyczne aktualizuj plik</string>
<string name="common_rename">Zmień nazwę</string>
<string name="common_remove">Usuń</string>
<string name="filedisplay_unexpected_bad_get_content">Nieoczekiwany problem; spróbuj wybrać plik z innej aplikacji</string>
<string name="filedisplay_no_file_selected">Nie wybrano żadnych plików</string>
<string name="activity_chooser_title">Wyślij link do ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Kopiowanie pliku z prywatnego zasobu</string>
<string name="oauth_check_onoff">Loguj przez oAuth2</string>
<string name="oauth_login_connection">Łączenie z serwerem oAuth2...</string>
<string name="ssl_validator_header">Nie można zweryfikować tożsamości strony</string>
<string name="share_link_file_error">Wystąpił błąd podczas udostępniania tego pliku lub folderu.</string>
<string name="unshare_link_file_no_exist">Nie można wyłączyć udostępniania. Proszę sprawdzić, czy plik istnieje</string>
<string name="unshare_link_file_error">Wystąpił błąd podczas anulowania udostępniania tego pliku lub folderu.</string>
+ <string name="share_link_password_title">Wprowadź hasło</string>
+ <string name="share_link_empty_password">Musisz wprowadzić hasło</string>
<string name="activity_chooser_send_file_title">Wyślij</string>
<string name="copy_link">Skopiuj link</string>
<string name="clipboard_text_copied">Skopiuj do schowka</string>
<string name="auth_redirect_non_secure_connection_title">Bezpieczne połączenie jest przekierowywane przez niezabezpieczone trasy.</string>
<string name="actionbar_logger">Logi</string>
<string name="log_send_history_button">Wyślij historię</string>
- <string name="log_mail_subject">Logi aplikacji ownCloud Android</string>
+ <string name="log_send_no_mail_app">Brak aplikacji do wysyłania logów. Zainstaluj klienta poczty!</string>
+ <string name="log_send_mail_subject">%1$s Logi aplikacji Android</string>
<string name="log_progress_dialog_text">Ładuję dane...</string>
<string name="saml_authentication_required_text">Wymagana autoryzacja</string>
<string name="saml_authentication_wrong_pass">Złe hasło</string>
<string name="actionbar_move">Przenieś</string>
<string name="file_list_empty_moving">Nic tu nie ma. Możesz dodać folder!</string>
- <string name="move_choose_button_text">Wybierz</string>
+ <string name="folder_picker_choose_button_text">Wybierz</string>
<string name="move_file_not_found">Nie można przenieść. Proszę sprawdzić, czy plik istnieje</string>
<string name="move_file_invalid_into_descendent">Nie jest możliwe przeniesienie folderu do potomka</string>
<string name="move_file_invalid_overwrite">Plik istnieje już w folderze docelowym</string>
<string name="forbidden_permissions_move">aby przenieść ten plik</string>
<string name="prefs_category_instant_uploading">Automatyczne wysyłanie</string>
<string name="prefs_category_security">Bezpieczeństwo</string>
+ <string name="prefs_instant_video_upload_path_title">Katalog wysyłania dla wideo</string>
+ <string name="download_folder_failed_content">Pobieranie %1$s katalogu nie może zostać ukończone</string>
+ <string name="auth_refresh_button">Odśwież połączenie</string>
+ <string name="auth_host_address">Adres Serwera</string>
+ <string name="common_error_out_memory">Brak wystarczającej pamięci</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Todos os arquivos</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Configurações</string>
+ <string name="drawer_item_logs">Logs</string>
+ <string name="drawer_close">Fechar</string>
<string name="prefs_category_general">Geral</string>
<string name="prefs_category_more">Mais</string>
<string name="prefs_accounts">Contas</string>
<string name="prefs_manage_accounts">Gerenciar Contas</string>
- <string name="prefs_pincode">PIN App</string>
- <string name="prefs_pincode_summary">Proteja seu cliente</string>
+ <string name="prefs_passcode">Bloqueio de senha</string>
<string name="prefs_instant_upload">Envio instantâneo de imagem</string>
<string name="prefs_instant_upload_summary">Enviar instantaneamente fotos tiradas com a camera</string>
<string name="prefs_instant_video_upload">Envio instantâneo de vídeos</string>
<string name="sync_string_files">Arquivos</string>
<string name="setup_btn_connect">Conectar</string>
<string name="uploader_btn_upload_text">Enviar</string>
+ <string name="uploader_btn_new_folder_text">Nova pasta</string>
<string name="uploader_top_message">Escolher pasta para enviar:</string>
<string name="uploader_wrn_no_account_title">Nenhuma conta encontrada</string>
<string name="uploader_wrn_no_account_text">Não existem contas %1$s no seu dispositivo. Por favor, configure uma conta primeiro.</string>
<string name="filedetails_download">Baixar</string>
<string name="filedetails_sync_file">Atualizar arquivo</string>
<string name="filedetails_renamed_in_upload_msg">Arquivo foi renomeado para %1$s durante o envio</string>
+ <string name="list_layout">Lista de Layout</string>
<string name="action_share_file">Compartilhar link</string>
<string name="action_unshare_file">Descompartilhar o link</string>
<string name="common_yes">Sim</string>
<string name="foreign_files_local_text">Local: %1$s</string>
<string name="foreign_files_remote_text">Remoto: %1$s</string>
<string name="upload_query_move_foreign_files">Não existe espaço suficiente para copiar os arquivos selecionados para a pasta %1$s. Você gostaria de ao invés de copiar movê-los? </string>
- <string name="pincode_enter_pin_code">Por favor, insira o seu PIN de Aplicativo</string>
- <string name="pincode_configure_your_pin">Insira seu PIN de Aplicativo</string>
- <string name="pincode_configure_your_pin_explanation">O PIN (senha) será solicitado toda vez que o aplicativo for iniciado</string>
- <string name="pincode_reenter_your_pincode">Por favor, reinsira seu PIN de Aplicativo</string>
- <string name="pincode_remove_your_pincode">Remova seu PIN de Aplicativo</string>
- <string name="pincode_mismatch">Os PINs de Aplicativo não são iguais</string>
- <string name="pincode_wrong">PIN de Aplicativo incorreto</string>
- <string name="pincode_removed">PIN de Aplicativo removido</string>
- <string name="pincode_stored">PIN de Aplicativo armazenado</string>
+ <string name="pass_code_enter_pass_code">Por favor, insira o código de acesso</string>
+ <string name="pass_code_configure_your_pass_code">Digite o código de acesso</string>
+ <string name="pass_code_configure_your_pass_code_explanation">O código de acesso será solicitado toda vez que o aplicativo é iniciado</string>
+ <string name="pass_code_reenter_your_pass_code">Por favor, insira novamente o seu código de acesso</string>
+ <string name="pass_code_remove_your_pass_code">Remover o seu código de acesso</string>
+ <string name="pass_code_mismatch">Os códigos de acesso não são os mesmos</string>
+ <string name="pass_code_wrong">Código de acesso incorreto</string>
+ <string name="pass_code_removed">Código de acesso removido</string>
+ <string name="pass_code_stored">Código de acesso armazenado</string>
<string name="media_notif_ticker">%1$s reprodutor de música</string>
<string name="media_state_playing">%1$s (reproduzindo)</string>
<string name="media_state_loading">%1$s (carregando)</string>
<string name="auth_fail_get_user_name">Seu servidor não está retornando um ID de usuário correto, por favor, entre em contato com um administrador
⇥</string>
<string name="auth_can_not_auth_against_server">Não foi possível autenticar neste servidor</string>
+ <string name="auth_account_does_not_exist">Conta ainda não existe no dispositivo</string>
<string name="fd_keep_in_sync">Manter arquivo atualizado</string>
<string name="common_rename">Renomear</string>
<string name="common_remove">Remover</string>
<string name="sync_file_nothing_to_do_msg">Conteúdo do arquivo já foi sincronizado</string>
<string name="create_dir_fail_msg">A pasta não pode ser criada</string>
<string name="filename_forbidden_characters">Caracteres proibidos: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">O nome do arquivo contem pelo menos um caractere inválido </string>
<string name="filename_empty">O nome do arquivo não pode estar vazio</string>
<string name="wait_a_moment">Aguarde um momento</string>
<string name="filedisplay_unexpected_bad_get_content">Problema inesperado; por favor, tente selecionar o arquivo com outro app</string>
<string name="filedisplay_no_file_selected">Nenhum arquivo foi selecionado</string>
<string name="activity_chooser_title">Enviar o link para</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Copiando o arquivo de armazenagem privada</string>
<string name="oauth_check_onoff">Login com oAuth2</string>
<string name="oauth_login_connection">Conectando-se a oAuth2 servidor ...</string>
<string name="ssl_validator_header">A identidade do site não pode ser verificada</string>
<string name="share_link_file_error">Ocorreu um erro durante a tentativa de compartilhar esse arquivo ou pasta</string>
<string name="unshare_link_file_no_exist">Não é possível cancelar o compartilhamento. Por favor verifique se o arquivo existe</string>
<string name="unshare_link_file_error">Ocorreu um erro ao tentar descompartilhar este arquivo ou pasta</string>
+ <string name="share_link_password_title">Digite uma senha</string>
+ <string name="share_link_empty_password">Você deve digitar uma senha</string>
<string name="activity_chooser_send_file_title">Enviar</string>
<string name="copy_link">Copiar o link</string>
<string name="clipboard_text_copied">Copiado para área de transferência</string>
<string name="auth_redirect_non_secure_connection_title">Conexão segura esta redirecionada para uma rota não segura.</string>
<string name="actionbar_logger">Logs</string>
<string name="log_send_history_button">Enviar Histórico</string>
- <string name="log_mail_subject">Logs do aplicativo ownCloud Android</string>
- <string name="log_progress_dialog_text">Carregamento de dados...</string>
+ <string name="log_send_no_mail_app">Não foi encontrado nenhum app para envio de logs. Instale o mail app!</string>
+ <string name="log_send_mail_subject">%1$s logs do Android app</string>
+ <string name="log_progress_dialog_text">Carregando dados...</string>
<string name="saml_authentication_required_text">Autenticação é requerida</string>
<string name="saml_authentication_wrong_pass">Senha incorreta</string>
<string name="actionbar_move">Mover</string>
<string name="file_list_empty_moving">Nada aqui. Você pode adicionar uma pasta!</string>
- <string name="move_choose_button_text">Escolher</string>
+ <string name="folder_picker_choose_button_text">Escolher</string>
<string name="move_file_not_found">Não é possível mover. Por favor verifique se o arquivo existe</string>
<string name="move_file_invalid_into_descendent">Não é possível mover a pasta para uma descendente</string>
<string name="move_file_invalid_overwrite">O arquivo já existe na pasta de destino</string>
<string name="forbidden_permissions_move">mover este arquivo</string>
<string name="prefs_category_instant_uploading">Envios Instantâneos</string>
<string name="prefs_category_security">Segurança</string>
+ <string name="prefs_instant_video_upload_path_title">Enviar o Caminho do Vídeo</string>
+ <string name="download_folder_failed_content">Baixar %1$s da pasta não pode ser completado</string>
+ <string name="shared_subject_header">compartilhado</string>
+ <string name="with_you_subject_header">com você</string>
+ <string name="subject_token">%1$s compartilhado \"%2$s\" com você</string>
+ <string name="auth_refresh_button">Reinicializar conexão</string>
+ <string name="auth_host_address">Endereço do servidor</string>
+ <string name="common_error_out_memory">Não há memoria suficiente</string>
+ <string name="username">Nome do Usuário</string>
+ <string name="file_list__footer__folder">1 pasta</string>
+ <string name="file_list__footer__folders">%1$d pastas</string>
+ <string name="file_list__footer__file">1 arquivo</string>
+ <string name="file_list__footer__file_and_folder">1 arquivo, 1 pasta</string>
+ <string name="file_list__footer__file_and_folders">1 arquivo, %1$d pastas</string>
+ <string name="file_list__footer__files">%1$d arquivos</string>
+ <string name="file_list__footer__files_and_folder">%1$d arquivos, 1 pasta</string>
+ <string name="file_list__footer__files_and_folders">%1$d arquivos, %2$d pastas</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Todos os ficheiros</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Definições</string>
+ <string name="drawer_close">Fechar</string>
<string name="prefs_category_general">Geral</string>
<string name="prefs_category_more">Mais</string>
<string name="prefs_accounts">Contas</string>
<string name="prefs_manage_accounts">Gerir Contas</string>
- <string name="prefs_pincode">PIN da App</string>
- <string name="prefs_pincode_summary">Proteja o seu cliente</string>
<string name="prefs_instant_upload">Envios instantâneos de imagens</string>
<string name="prefs_instant_upload_summary">Envio instantâneo de imagens tiradas com a câmara</string>
<string name="prefs_instant_video_upload">Envios instantâneos dos vídeos</string>
<string name="prefs_imprint">Imprint</string>
<string name="prefs_remember_last_share_location">Lembrar localização de partilha</string>
<string name="prefs_remember_last_upload_location_summary">Lembrar da última localização de envio de partilha</string>
- <string name="recommend_subject">Experimente %1$s no seu smartphone!</string>
- <string name="recommend_text">Quero convidar-te a usares %1$s no teu smartphone!\nFaz download aqui: %2$s</string>
+ <string name="recommend_subject">Test %1$s no seu smartphone!</string>
+ <string name="recommend_text">Eu quero convidar-te para usares %1$s no teu smartphone!\nTransfere aqui: %2$s</string>
<string name="auth_check_server">Verificar Servidor</string>
<string name="auth_host_url">Endereço do servidor https://..</string>
<string name="auth_username">Nome de Utilizador</string>
<string name="sync_string_files">Ficheiros</string>
<string name="setup_btn_connect">Ligar</string>
<string name="uploader_btn_upload_text">Enviar</string>
+ <string name="uploader_btn_new_folder_text">Nova Pasta</string>
<string name="uploader_top_message">Escolha a pasta de envio:</string>
<string name="uploader_wrn_no_account_title">A conta não foi encontrada</string>
- <string name="uploader_wrn_no_account_text">Não tem nenhuma conta %1$s no seu dispositivo. Por favor, configure primeiro uma conta.</string>
+ <string name="uploader_wrn_no_account_text">Não existe nenhuma conta %1$s no seu dispositivo. Por favor, configure primeiro uma conta.</string>
<string name="uploader_wrn_no_account_setup_btn_text">Configurar</string>
<string name="uploader_wrn_no_account_quit_btn_text">Sair</string>
<string name="uploader_wrn_no_content_title">Sem conteúdo para enviar</string>
<string name="uploader_error_forbidden_content">O %1$s não está autorizado a aceder aos ficheiro partilhados.</string>
<string name="uploader_info_uploading">A enviar</string>
<string name="file_list_seconds_ago">segundos atrás</string>
- <string name="file_list_empty">Vazio. Envie alguma coisa!</string>
- <string name="file_list_loading">A carregar ...</string>
+ <string name="file_list_empty">Aqui não existe nada. Envie alguma coisa!</string>
<string name="local_file_list_empty">Não existem ficheiros nesta pasta.</string>
- <string name="filedetails_select_file">Clique no ficheiro para visualizar informação adicional.</string>
+ <string name="filedetails_select_file">Toque num ficheiro para visualizar a informação adicional.</string>
<string name="filedetails_size">Tamanho:</string>
<string name="filedetails_type">Tipo:</string>
<string name="filedetails_created">Criado:</string>
<string name="filedetails_modified">Modificado:</string>
<string name="filedetails_download">Transferir</string>
<string name="filedetails_sync_file">Atualizar ficheiro</string>
- <string name="filedetails_renamed_in_upload_msg">O nome do ficheiro foi alterado para %1$s durante o envio.</string>
+ <string name="filedetails_renamed_in_upload_msg">O ficheiro foi renomeado para %1$s durante o envio.</string>
<string name="action_share_file">Partilhar a hiperligação</string>
- <string name="action_unshare_file">Deixar de partilhar a ligação</string>
+ <string name="action_unshare_file">Cancelar partilha da hiperligação</string>
<string name="common_yes">Sim</string>
<string name="common_no">Não</string>
- <string name="common_ok">OK</string>
+ <string name="common_ok">ACEITAR</string>
<string name="common_cancel_download">Cancelar a transferência</string>
<string name="common_cancel_upload">Cancelar o envio</string>
<string name="common_cancel">Cancelar</string>
<string name="upload_chooser_title">Enviar de ...</string>
<string name="uploader_info_dirname">Nome da pasta</string>
<string name="uploader_upload_in_progress_ticker">A enviar ...</string>
- <string name="uploader_upload_in_progress_content">A enviar %1$d%% , %2$s completo.</string>
- <string name="uploader_upload_succeeded_ticker">Carregado com sucesso</string>
- <string name="uploader_upload_succeeded_content_single">%1$s foi carregado com sucesso</string>
- <string name="uploader_upload_failed_ticker">Carregamento falhou</string>
- <string name="uploader_upload_failed_content_single">O envio do ficheiro %1$s não foi concluído.</string>
- <string name="uploader_upload_failed_credentials_error">Falha no carregamento, é necessário fazer novo login</string>
- <string name="downloader_download_in_progress_ticker">A transferir ...</string>
- <string name="downloader_download_in_progress_content">%1$d%% A decarregar %2$s</string>
- <string name="downloader_download_succeeded_ticker">Descarga com sucesso</string>
- <string name="downloader_download_succeeded_content">%1$s foi descarregado com sucesso</string>
- <string name="downloader_download_failed_ticker">Descarga falhou</string>
- <string name="downloader_download_failed_content">O descarregamento %1$s não foi possível descarregar</string>
- <string name="downloader_not_downloaded_yet">Não transferido</string>
- <string name="downloader_download_failed_credentials_error">Falha no download, é necessário fazer login </string>
+ <string name="uploader_upload_in_progress_content">%1$d%% A enviar %2$s</string>
+ <string name="uploader_upload_succeeded_ticker">Envio bem sucedido</string>
+ <string name="uploader_upload_succeeded_content_single">%1$s foi enviado com sucesso</string>
+ <string name="uploader_upload_failed_ticker">Não foi possível enviar</string>
+ <string name="uploader_upload_failed_content_single">Não foi possível concluir o envio de %1$s.</string>
+ <string name="uploader_upload_failed_credentials_error">Falha no envio, precisa de reiniciar a sessão</string>
+ <string name="downloader_download_in_progress_ticker">A transferir...</string>
+ <string name="downloader_download_in_progress_content">%1$d%% A transferir %2$s</string>
+ <string name="downloader_download_succeeded_ticker">Transferência bem sucedida</string>
+ <string name="downloader_download_succeeded_content">%1$s foi transferido com sucesso</string>
+ <string name="downloader_download_failed_ticker">Transferência falhada</string>
+ <string name="downloader_download_failed_content">Não foi possível concluir a transferência de %1$s</string>
+ <string name="downloader_not_downloaded_yet">Ainda não foi transferido</string>
+ <string name="downloader_download_failed_credentials_error">Não foi possível transferir, tem de iniciar a sessão novamente</string>
<string name="common_choose_account">Escolha a conta</string>
<string name="sync_fail_ticker">Falhou a sincronização</string>
- <string name="sync_fail_ticker_unauthorized">Falhou a sincronização, necessita fazer um novo login</string>
- <string name="sync_fail_content">Não foi possível sincronizar %1$s</string>
+ <string name="sync_fail_ticker_unauthorized">Falhou a sincronização, precisa de reiniciar a sessão</string>
+ <string name="sync_fail_content">Não foi possível concluir a sincronização de %1$s</string>
<string name="sync_fail_content_unauthorized">Senha inválida para %1$s</string>
<string name="sync_conflicts_in_favourites_ticker">Foram encontrados conflitos</string>
<string name="sync_conflicts_in_favourites_content">Não foi possível sincronizar o ficheiro %1$d</string>
<string name="sync_fail_in_favourites_ticker">Falhou a operação de manter os ficheiros sincronizados</string>
- <string name="sync_fail_in_favourites_content">Não foi possível sincronizar o conteúdo de %1$d ficheiros (%2$d conflictos)</string>
+ <string name="sync_fail_in_favourites_content">Não foi possível sincronizar o conteúdo de %1$d ficheiros (%2$d conflitos)</string>
<string name="sync_foreign_files_forgotten_ticker">Alguns ficheiros locais ficaram esquecidos</string>
<string name="sync_foreign_files_forgotten_content">Nao foi possivel copiar os ficheiros %1$d da pasta %2$s para</string>
<string name="sync_foreign_files_forgotten_explanation">Tal como na versão 1.3.16, os ficheiros que foram enviados deste dispositivo são copiados para a pasta local %1$s para prevenir perda de dados quando um ficheiro é partilhado com várias contas.\n\nDevido a esta alteração, todos os ficheiros das versões anteriores foram copiados para a pasta %2$s. No entanto, um erro impediu a conclusão deste processo durante a sincronização da conta. Pode deixar o ficheiro(s) como estão e remover o link para %3$s, ou mover o(s) ficheiro(s) para a pasta %1$s e guardar o link para %4$s. \n\nEm baixo estão listados ficheiro(s) locais e remotos em %5$s que foram ligados.</string>
<string name="sync_current_folder_was_removed">A pasta %1$s já não existe</string>
<string name="foreign_files_move">Mover Todos</string>
- <string name="foreign_files_success">Todos os ficheiros foram movidos</string>
+ <string name="foreign_files_success">Foram movidos todos os ficheiros</string>
<string name="foreign_files_fail">Não foi possível mover alguns ficheiros</string>
<string name="foreign_files_local_text">Local: %1$s</string>
<string name="foreign_files_remote_text">Remoto: %1$s</string>
<string name="upload_query_move_foreign_files">Não existe espaço disponível para copiar o ficheiro seleccionado para a pasta %1$s . Em vez disso deseja mover o ficheiro?</string>
- <string name="pincode_enter_pin_code">Por favor escreva o PIN da Aplicação</string>
- <string name="pincode_configure_your_pin">Escreva o PIN da Aplicação</string>
- <string name="pincode_configure_your_pin_explanation">O PIN vai ser pedido todas as vezes que iniciar a aplicação.</string>
- <string name="pincode_reenter_your_pincode">Volte a inserir o App PIN, por favor</string>
- <string name="pincode_remove_your_pincode">Remover o PIN do aplicação.</string>
- <string name="pincode_mismatch">Os códigos PIN introduzidos não são iguais.</string>
- <string name="pincode_wrong">Código PIN Incorrecto.</string>
- <string name="pincode_removed">PIN da aplicação removido</string>
- <string name="pincode_stored">PIN da aplicação guardado</string>
- <string name="media_notif_ticker">%1$s leitor de música</string>
- <string name="media_state_playing">A tocar: %1$s</string>
- <string name="media_state_loading">%1$s (A carregar)</string>
- <string name="media_event_done">%1$s leitura terminada</string>
- <string name="media_err_nothing_to_play">Não foi encontrado nenhum ficheiro de média</string>
- <string name="media_err_no_account">Não foi fornecida conta</string>
+ <string name="media_notif_ticker">%1$s reprodutor de música</string>
+ <string name="media_state_playing">%1$s (a reproduzir)</string>
+ <string name="media_state_loading">%1$s (a carregar)</string>
+ <string name="media_event_done">%1$s reprodução terminada</string>
+ <string name="media_err_nothing_to_play">Não foi encontrado nenhum ficheiro de multimédia</string>
+ <string name="media_err_no_account">Não foi indicada uma conta</string>
<string name="media_err_not_in_owncloud">O ficheiro não está numa conta válida</string>
- <string name="media_err_unsupported">Codec de média não suportado</string>
- <string name="media_err_io">Não foi possível reproduzir o ficheiro</string>
- <string name="media_err_malformed">Ficheiro erradamente codificado (codec)</string>
- <string name="media_err_timeout">O tempo de espera para jogar expirou</string>
- <string name="media_err_invalid_progressive_playback">O ficheiro não pode ser reproduzido (streaming)</string>
+ <string name="media_err_unsupported">Codec de multimédia não suportado</string>
+ <string name="media_err_io">Não foi possível ler o ficheiro de multimédia</string>
+ <string name="media_err_malformed">O ficheiro de multimédia não foi codificado corretamente</string>
+ <string name="media_err_timeout">Tempo expirado enquanto tentava jogar</string>
+ <string name="media_err_invalid_progressive_playback">O ficheiro de multimédia não pôde ser transmitido</string>
<string name="media_err_unknown">O ficheiro não pode ser reproduzido com o leitor de média de origem</string>
<string name="media_err_security_ex">Erro de segurança a tentar reproduzir o ficheiro %1$s</string>
<string name="media_err_io_ex">Erro de input a tentar reproduzir %1$s</string>
<string name="media_err_unexpected">Erro inesperado a tentar reproduzir %1$s</string>
- <string name="media_rewind_description">Botão de rebobinar</string>
- <string name="media_play_pause_description">Botão Tocar/Pausa</string>
+ <string name="media_rewind_description">Botão de Retroceder</string>
+ <string name="media_play_pause_description">Botão de Reproduzir/Pausar</string>
<string name="media_forward_description">Botão de avanço rápido</string>
<string name="auth_getting_authorization">A obter autorização...</string>
- <string name="auth_trying_to_login">A tentar entrar...</string>
+ <string name="auth_trying_to_login">A tentar iniciar a sessão...</string>
<string name="auth_no_net_conn_title">Sem ligação à rede</string>
- <string name="auth_nossl_plain_ok_title">Ligação segura indisponível</string>
+ <string name="auth_nossl_plain_ok_title">Ligação segura indisponível.</string>
<string name="auth_connection_established">Ligação estabelecida</string>
- <string name="auth_testing_connection">A testar a ligação...</string>
+ <string name="auth_testing_connection">A testar a ligação</string>
<string name="auth_not_configured_title">Configuração do servidor incorrecta.</string>
<string name="auth_account_not_new">Uma conta para este utilizador e servidor já existe no dispositivo</string>
<string name="auth_account_not_the_same">O utilizador que escreveu não coincide com o nome de utilizador desta conta</string>
<string name="auth_unknown_error_title">Ocorreu um erro desconhecido!</string>
- <string name="auth_unknown_host_title">Não é possível encontrar o servidor</string>
- <string name="auth_incorrect_path_title">Instância servidor não encontrada</string>
- <string name="auth_timeout_title">O servidor levou demasiado tempo a responder</string>
+ <string name="auth_unknown_host_title">Não foi possível encontrar o anfitrião</string>
+ <string name="auth_incorrect_path_title">Instância do servidor não encontrada</string>
+ <string name="auth_timeout_title">O servidor demorou muito tempo a responder</string>
<string name="auth_incorrect_address_title">URL errado</string>
<string name="auth_ssl_general_error_title">Inicialização de SSL falhou</string>
- <string name="auth_ssl_unverified_server_title">Não foi possível verificar a identidade SSL do servidor</string>
+ <string name="auth_ssl_unverified_server_title">Não foi possível verificar a identidade do servidor SSL</string>
<string name="auth_bad_oc_version_title">Versão do servidor não reconhecida</string>
<string name="auth_wrong_connection_title">Não consegue estabelecer ligação</string>
<string name="auth_secure_connection">Ligação segura estabelecida</string>
<string name="auth_oauth_error_access_denied">Acesso negado pelo servidor</string>
<string name="auth_wtf_reenter_URL">Estado inesperado, por favor, digite a URL do servidor novamente</string>
<string name="auth_expired_oauth_token_toast">O prazo da sua autorização expirou. Por favor renove-a</string>
- <string name="auth_expired_basic_auth_toast">Por favor, introduza a password actual</string>
+ <string name="auth_expired_basic_auth_toast">Por favor, insira a palavra-passe atual</string>
<string name="auth_expired_saml_sso_token_toast">A sua sessão expirou. Por favor autentique-se de novo</string>
<string name="auth_connecting_auth_server">A verificar a sua autenticação no servidor...</string>
<string name="auth_unsupported_auth_method">O servidor não suporta este método de autenticação</string>
<string name="auth_unsupported_multiaccount">%1$s não suporta contas múltiplas</string>
<string name="auth_fail_get_user_name">O seu servidor não transmite o ID correcto. Por favor contacte o administrador.</string>
<string name="auth_can_not_auth_against_server">Não foi possível autenticar no servidor</string>
+ <string name="auth_account_does_not_exist">Conta ainda não existe no dispositivo</string>
<string name="fd_keep_in_sync">manter ficheiro actualizado</string>
<string name="common_rename">Renomear</string>
<string name="common_remove">Remover</string>
<string name="share_link_file_error">Ocorreu um erro enquanto tentava partilhar este ficheiro ou pasta</string>
<string name="unshare_link_file_no_exist">Não é possível retirar a partilha. Verifique se o ficheiro existe</string>
<string name="unshare_link_file_error">Ocorreu um erro enquanto retirava a partilha deste ficheiro ou pasta</string>
+ <string name="share_link_password_title">Introduza uma palavra-passe</string>
+ <string name="share_link_empty_password">Você deve introduzir uma palavra-passe</string>
<string name="activity_chooser_send_file_title">Enviar</string>
<string name="copy_link">Copiar hiperligação</string>
<string name="clipboard_text_copied">Copiado para a área de transferência</string>
<string name="auth_redirect_non_secure_connection_title">Ligação segura é redireccionada para um caminho inseguro.</string>
<string name="actionbar_logger">Registos de Alterações</string>
<string name="log_send_history_button">Enviar Histórico</string>
- <string name="log_mail_subject">Registos das alterações da app ownCloud Android</string>
- <string name="log_progress_dialog_text">A carregar os dados ...</string>
+ <string name="log_send_no_mail_app">Não foi encontrado o aplicativo para envio de registos . Instale app e-mail!</string>
+ <string name="log_send_mail_subject">%1$s Android Aplicação de Registyos</string>
+ <string name="log_progress_dialog_text">A carregar os dados...</string>
<string name="saml_authentication_required_text">Autenticação necessária</string>
<string name="saml_authentication_wrong_pass">Palavra-passe errada</string>
<string name="actionbar_move">Mover</string>
<string name="file_list_empty_moving">Não está aqui nada. Pode adicionar uma pasta!</string>
- <string name="move_choose_button_text">Escolher</string>
+ <string name="folder_picker_choose_button_text">Escolher</string>
<string name="move_file_not_found">Não é possível mover. Por favor, verifique se o ficheiro existe</string>
<string name="move_file_invalid_into_descendent">Não é possível mover esta pasta deste modo</string>
<string name="move_file_invalid_overwrite">O ficheiro já existe na pasta de destino</string>
<string name="forbidden_permissions_move">para mover este ficheiro</string>
<string name="prefs_category_instant_uploading">Envios Instantâneos</string>
<string name="prefs_category_security">Segurança</string>
+ <string name="prefs_instant_video_upload_path_title">Envio do Caminho do Vídeo</string>
+ <string name="download_folder_failed_content">Não foi possível completar o download da pasta %1$s</string>
+ <string name="shared_subject_header">partilhado</string>
+ <string name="with_you_subject_header">consigo</string>
+ <string name="auth_refresh_button">Recarregar ligação</string>
+ <string name="auth_host_address">Endereço do servidor</string>
+ <string name="common_error_out_memory">Falta de memória</string>
+ <string name="username">Nome de utilizador</string>
</resources>
<string name="actionbar_send_file">Expediază</string>
<string name="actionbar_sort">Sortare</string>
<string name="actionbar_sort_title">Sortare după</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Nou - Vechi</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Toate fișierele</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Setări</string>
+ <string name="drawer_item_logs">Înregistrări</string>
+ <string name="drawer_close">Închide</string>
<string name="prefs_category_general">General</string>
<string name="prefs_category_more">Mai mult</string>
<string name="prefs_accounts">Conturi</string>
<string name="prefs_manage_accounts">Administrare conturi</string>
- <string name="prefs_pincode">PIN-ul aplicaţiei</string>
- <string name="prefs_pincode_summary">Protejaţi-vă clientul</string>
- <string name="prefs_instant_upload">Încărcare instanta de imagine</string>
- <string name="prefs_instant_upload_summary">Încărca instantaneu imagini luate de camera</string>
+ <string name="prefs_passcode">Parolă blocare</string>
+ <string name="prefs_instant_upload">Încărcare instantă de imagini</string>
+ <string name="prefs_instant_upload_summary">Încarcă instantant imagini luate cu camera</string>
<string name="prefs_instant_video_upload">Încărcare instantă de videoclipuri.</string>
- <string name="prefs_instant_video_upload_summary">Încarcă videoclipuri instant, filmate cu camera.</string>
+ <string name="prefs_instant_video_upload_summary">Încarcă instant videoclipuri înregistrate cu camera</string>
<string name="prefs_log_title">Permite logarea</string>
<string name="prefs_log_summary">Acesta este folosit pentru a înregistra problemele</string>
<string name="prefs_log_title_history">Istoria logarilor</string>
<string name="prefs_recommend">Recomandati unui prieten</string>
<string name="prefs_feedback">Feedback</string>
<string name="prefs_imprint">Imprint</string>
+ <string name="prefs_remember_last_share_location">Reține contribuie locația</string>
+ <string name="prefs_remember_last_upload_location_summary">Reține locația fișierului încărcat precedent</string>
<string name="recommend_subject">Încearcă %1$s pe smartphone-ul tău!</string>
+ <string name="recommend_text">Te invit sa folosești %1$s pe smartphone-ul tău!\nDescarcă aici: %2$s</string>
<string name="auth_check_server">Verificaţi Serverul</string>
<string name="auth_host_url">Adresa serverului https://...</string>
<string name="auth_username">Nume utilizator</string>
<string name="sync_string_files">Fișiere</string>
<string name="setup_btn_connect">Conectare</string>
<string name="uploader_btn_upload_text">Încărcare</string>
+ <string name="uploader_btn_new_folder_text">Un nou dosar</string>
<string name="uploader_top_message">Alegeţi fişierul pentru încărcare</string>
<string name="uploader_wrn_no_account_title">Nici un cont găsit</string>
<string name="uploader_wrn_no_account_text">Nu există conturi %1$s pe dispozitivul tău. Te rugăm să configurezi un cont mai întâi.</string>
<string name="uploader_info_uploading">Încărcare</string>
<string name="file_list_seconds_ago">secunde în urmă</string>
<string name="file_list_empty">Nimic aici. Încarcă ceva!</string>
- <string name="file_list_loading">Se incarca</string>
+ <string name="file_list_loading">Se încarcă...</string>
<string name="local_file_list_empty">In acest folder nu sunt fisiere.</string>
<string name="filedetails_select_file">Selectati un fisier pentru a afisa informatia aditionala</string>
<string name="filedetails_size">Mărime:</string>
<string name="filedetails_download">Descarcă</string>
<string name="filedetails_sync_file">Împrospătare fişier</string>
<string name="filedetails_renamed_in_upload_msg">Fișierul a fost redenumit %1$s în timpul încărcării</string>
+ <string name="list_layout">Aspect listă</string>
<string name="action_share_file">Share link</string>
<string name="action_unshare_file">Unshare link</string>
<string name="common_yes">Da</string>
<string name="sync_fail_in_favourites_content">Conținutul a%1$d fișiere nu a putut fi sincronizat (conflicte %2$d)</string>
<string name="sync_foreign_files_forgotten_ticker">Unele fisiere locale au fost uitate</string>
<string name="sync_foreign_files_forgotten_content">%1$d fisiere din dosarul %2$s nu a putut fi copiat in</string>
+ <string name="sync_foreign_files_forgotten_explanation">Conform ediției 1.3.16, fișierele încărcate de pe această platformă sunt copiate în dosarul local %1$s pentru a preveni pierderi de date atunci cînd un singur fișier este sincronizat cu mai multe conturi.\n\nDin cauza acestei schimbări, toate fișierele încărcate în edițiile precedente ale acestui app au fost încărcate in dosarul %2$s. Însă acest proces nu fost completat in timpul sincronizării contului din cauza unei erori. Ai opțiunea de a lăsa fișierul intact (fișierele intacte) și de a transfera sursa în dosarul %3$s sau de a schimba locația fișierului(-elor) în dosarul %1$s și de a păstra sursa în %4$s.\n\nMai jos găsești enumerate fișierul local(fișierele locale) și fișierul separat(fișierele separate) în %5$s cu sursa respectivă.</string>
<string name="sync_current_folder_was_removed">Folderul %1$s nu mai există</string>
<string name="foreign_files_move">Muta tot/toate</string>
<string name="foreign_files_success">Toate fişierele au fost mutate</string>
<string name="foreign_files_remote_text">La distanta: %1$s</string>
<string name="upload_query_move_foreign_files">Nu este suficient spațiu pentru a copia fișierele selectate în dosarul %1$s . Dorești să le muți în loc?
</string>
- <string name="pincode_enter_pin_code">Te rugăm să specifici PIN-ul aplicației</string>
- <string name="pincode_configure_your_pin">Introduceti PIN-ul aplicatiei</string>
- <string name="pincode_configure_your_pin_explanation">PIN-ul va fi solicitat ori de cate ori aplicaţia este pornita</string>
- <string name="pincode_reenter_your_pincode">Va rugam , reintroduceti PIN-ul aplicatiei</string>
- <string name="pincode_remove_your_pincode">Elimină PIN-ul aplicației</string>
- <string name="pincode_mismatch">Cele două PIN-uri ale aplicației nu sunt similare</string>
- <string name="pincode_wrong">PIN-ul aplicației este incorect</string>
- <string name="pincode_removed">PIN-ul aplicației a fost eliminat</string>
- <string name="pincode_stored">PIN-ul aplicației a fost memorat</string>
+ <string name="pass_code_enter_pass_code">Te rugăm să introduci parola</string>
+ <string name="pass_code_configure_your_pass_code">Introdu parola</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Parola va fi solicitată de fiecare dată când deschideți aplicația</string>
+ <string name="pass_code_reenter_your_pass_code">Te rugăm să reintroduci parola</string>
+ <string name="pass_code_remove_your_pass_code">Șterge parola</string>
+ <string name="pass_code_mismatch">Parolele nu se potrivesc</string>
+ <string name="pass_code_wrong">Parolă incorectă</string>
+ <string name="pass_code_removed">Parolă ștearsă</string>
+ <string name="pass_code_stored">Parolă stocată</string>
<string name="media_notif_ticker">%1$s player de muzică</string>
<string name="media_state_playing">%1$s (cântă)</string>
<string name="media_state_loading">%1$s (încarcă)</string>
<string name="auth_no_net_conn_title">Nu exista conexiune</string>
<string name="auth_nossl_plain_ok_title">Conexiune securizată indisponibilă</string>
<string name="auth_connection_established">Conexiune stabilită</string>
- <string name="auth_testing_connection">Se testează conexiunea...</string>
+ <string name="auth_testing_connection">Testare conexiune</string>
<string name="auth_not_configured_title">Configurație serverului incorectă</string>
<string name="auth_account_not_new">Un cont pentru același utilizator și server există deja în dispozitiv</string>
<string name="auth_account_not_the_same">Utilizatorul introdus nu se potrivește cu utilizatorul acestui cont</string>
<string name="auth_unsupported_multiaccount">%1$s nu suporta conturi multiple</string>
<string name="auth_fail_get_user_name">Server-ul dvs. nu întoarce un ID de utilizator corect, vă rugăm să contactați un administrator </string>
<string name="auth_can_not_auth_against_server">Nu se poate autentifica cu acest server</string>
+ <string name="auth_account_does_not_exist">Contul nu există încă în dispozitiv</string>
<string name="fd_keep_in_sync">Păstrează fișierul actualizat</string>
<string name="common_rename">Redenumește</string>
<string name="common_remove">Elimină</string>
<string name="sync_file_nothing_to_do_msg">Continutul fisierului este deja sincronizat</string>
<string name="create_dir_fail_msg">Nu a putut fi creat directorul</string>
<string name="filename_forbidden_characters">Caractere interzise: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Numele fișierului conține măcar un caracter invalid</string>
<string name="filename_empty">Numele fișierului nu poate fi gol.</string>
<string name="wait_a_moment">Așteaptă un moment</string>
<string name="filedisplay_unexpected_bad_get_content">Problema neasteptata ; selectati fisierul dintr-o aplicatie diferita </string>
<string name="filedisplay_no_file_selected">Nu a fost selectat nici un fișier</string>
<string name="activity_chooser_title">Trimite link la ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Copiere fișier din stocare privată</string>
<string name="oauth_check_onoff">Întră în cont cu oAuth2</string>
<string name="oauth_login_connection">Se conectează la serverul oAuth2...</string>
<string name="ssl_validator_header">Nu s-a putut verifica identitatea site-ului</string>
<string name="placeholder_media_time">12:23:45</string>
<string name="instant_upload_on_wifi">Incarca poze doar via WiFi</string>
<string name="instant_video_upload_on_wifi">Încarcă videoclipuri doar via WiFi</string>
- <string name="instant_upload_path">/Încărcare instanta</string>
+ <string name="instant_upload_path">/Încărcare instantă</string>
<string name="conflict_title">Actualizați conflictul</string>
<string name="conflict_message">Fișierul de la distanță %s nu este sincronizat cu fișierul local. Continuand, se va înlocui conținutul fișierului de pe server.</string>
<string name="conflict_keep_both">Pastreaza amandoua</string>
<string name="preview_image_description">Previzualizare imagine</string>
<string name="preview_image_error_unknown_format">Aceasta imagine nu poate fi arătată</string>
<string name="error__upload__local_file_not_copied">%1$s nu a putut fi copiat in dosarul local %2$s </string>
+ <string name="prefs_instant_upload_path_title">Calea de încărcare</string>
<string name="share_link_no_support_share_api">Ne pare rău, partajarea nu este activată pe server. Vă rugăm să contactați administratorul dvs.</string>
+ <string name="share_link_file_no_exist">Imposibil de partajat. Te rugăm să verifici dacă există fișierul.</string>
<string name="share_link_file_error">A apărut o eroare în timp ce încerca să partajeze acest fișier sau folder</string>
+ <string name="unshare_link_file_no_exist">Imposibil de șters partajarea. Te rugăm să verifici dacă există fișierul.</string>
<string name="unshare_link_file_error">A apărut o eroare în timp ce încerca să departajeze sau unshare acest fișier sau folder</string>
+ <string name="share_link_password_title">Introduceţi parola</string>
+ <string name="share_link_empty_password">Trebuie să introduci o parolă</string>
<string name="activity_chooser_send_file_title">Expediază</string>
<string name="copy_link">Link copiat</string>
<string name="clipboard_text_copied">Copiat în clipboard</string>
<string name="downloader_download_file_not_found">Fișierul nu mai este disponibil pe server</string>
<string name="prefs_category_accounts">Conturi</string>
<string name="prefs_add_account">Adaugă cont</string>
- <string name="log_progress_dialog_text">Se încarcă datele...</string>
+ <string name="auth_redirect_non_secure_connection_title">Conexiunea securizată este redirecționată către un traseu neasigurat.</string>
+ <string name="actionbar_logger">Înregistrări</string>
+ <string name="log_send_history_button">Trimite Istoria</string>
+ <string name="log_send_no_mail_app">App-ul de trimitere a inregistrărilor nu a fost găsit. Instalează mail app-ul!</string>
+ <string name="log_send_mail_subject">%1$s înregistrările app-ului Android</string>
+ <string name="log_progress_dialog_text">Datele se încarcă...</string>
<string name="saml_authentication_required_text">Autentificare necesară</string>
<string name="saml_authentication_wrong_pass">Parolă greșită</string>
<string name="actionbar_move">Mutare</string>
<string name="file_list_empty_moving">Nu este nimic aici. Poți adăuga un director!</string>
- <string name="move_choose_button_text">Alege</string>
+ <string name="folder_picker_choose_button_text">Alege</string>
+ <string name="move_file_not_found">Incapabil de trasfer. Verifică existența fișierului</string>
+ <string name="move_file_invalid_into_descendent">Nu este posibil să muți un dosar într-un descendent</string>
+ <string name="move_file_invalid_overwrite">Fișierul există deja în dosarul de destinație</string>
+ <string name="move_file_error">O eroare apare la transferarea acestui fișier sau dosar</string>
<string name="forbidden_permissions_move">pentru a muta acest fișier</string>
+ <string name="prefs_category_instant_uploading">Încărcări instante</string>
<string name="prefs_category_security">Securitate</string>
+ <string name="prefs_instant_video_upload_path_title">Calea de încărcare Video</string>
+ <string name="download_folder_failed_content">Descărcarea fișierului %1$s nu s-a finisat</string>
+ <string name="shared_subject_header">partajat</string>
+ <string name="with_you_subject_header">cu tine</string>
+ <string name="subject_token">%1$s a partajat fișierul \"%2$s\" cu tine</string>
+ <string name="auth_refresh_button">Reîmprospătează conexiunea</string>
+ <string name="auth_host_address">Adresa server-ului</string>
+ <string name="common_error_out_memory">Memorie insuficientă </string>
+ <string name="username">Utilizator</string>
+ <string name="file_list__footer__folder">1 folder</string>
+ <string name="file_list__footer__folders">%1$d foldere</string>
+ <string name="file_list__footer__file">1 fișier</string>
+ <string name="file_list__footer__file_and_folder">1 fișier, 1 folder</string>
+ <string name="file_list__footer__file_and_folders">1 fișier, %1$d foldere</string>
+ <string name="file_list__footer__files">%1$d fișiere</string>
+ <string name="file_list__footer__files_and_folder">%1$d fișiere, 1 folder</string>
+ <string name="file_list__footer__files_and_folders">%1$d fișiere, %2$d foldere</string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
- <string name="about_android">%1$s Ð\9fÑ\80иложение длÑ\8f Ð\90ндÑ\80оида</string>
- <string name="about_version">Ð\92ерсия %1$s</string>
+ <string name="about_android">%1$s длÑ\8f Android</string>
+ <string name="about_version">версия %1$s</string>
<string name="actionbar_sync">Обновить учетную запись</string>
<string name="actionbar_upload">Загрузить</string>
<string name="actionbar_upload_from_apps">Содержимое из других приложений</string>
<string name="actionbar_upload_files">Файлы</string>
<string name="actionbar_open_with">Открыть с помощью</string>
- <string name="actionbar_mkdir">Новая папка</string>
+ <string name="actionbar_mkdir">Новый каталог</string>
<string name="actionbar_settings">Настройки</string>
<string name="actionbar_see_details">Подробно</string>
<string name="actionbar_send_file">Отправить</string>
<string name="actionbar_sort_title">Упорядочить по</string>
<string-array name="actionbar_sortby">
<item>А-Я</item>
- <item>Новые - Старые</item>
+ <item>Новое - Старое</item>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Все файлы</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Настройки</string>
+ <string name="drawer_item_logs">Журналы</string>
+ <string name="drawer_close">Закрыть</string>
<string name="prefs_category_general">Основные</string>
<string name="prefs_category_more">Больше</string>
<string name="prefs_accounts">Учётные записи</string>
<string name="prefs_manage_accounts">Управление учётными записями</string>
- <string name="prefs_pincode">App PIN</string>
- <string name="prefs_pincode_summary">Защитить ваш клиент</string>
- <string name="prefs_instant_upload">Быстрая загрузка фотографий</string>
+ <string name="prefs_passcode">Блокировка кодом</string>
+ <string name="prefs_instant_upload">Мгновенная загрузка фотографий</string>
<string name="prefs_instant_upload_summary">Немедленно загружать фотографии сделанные камерой</string>
- <string name="prefs_instant_video_upload">Ð\91Ñ\8bÑ\81Ñ\82Ñ\80ая загрузка видео</string>
- <string name="prefs_instant_video_upload_summary">Ð\91Ñ\8bÑ\81Ñ\82Ñ\80аÑ\8f загÑ\80Ñ\83зка видео Ñ\81 камеÑ\80Ñ\8b</string>
+ <string name="prefs_instant_video_upload">Ð\9cгновенная загрузка видео</string>
+ <string name="prefs_instant_video_upload_summary">Ð\9dемедленно загÑ\80Ñ\83жаÑ\82Ñ\8c видео, Ñ\81деланнÑ\8bе камеÑ\80ой</string>
<string name="prefs_log_title">Включить журналирование</string>
<string name="prefs_log_summary">Используется для регистрации ошибок</string>
<string name="prefs_log_title_history">Журнал</string>
<string name="prefs_recommend">Рекомендовать другу</string>
<string name="prefs_feedback">Обратная связь</string>
<string name="prefs_imprint">Штамп</string>
+ <string name="prefs_remember_last_share_location">Запомнить расположение общего ресурса</string>
+ <string name="prefs_remember_last_upload_location_summary">Запомнить расположение загрузки последней публикации</string>
<string name="recommend_subject">Попробуйте %1$s на вашем смартфоне!</string>
<string name="recommend_text">Хочу предложить вам использовать %1$s на смартфоне!\nЗагрузить можно здесь: %2$s
</string>
<string name="sync_string_files">Файлы</string>
<string name="setup_btn_connect">Подключиться</string>
<string name="uploader_btn_upload_text">Загрузить</string>
- <string name="uploader_top_message">Выберете папку для загрузки</string>
+ <string name="uploader_btn_new_folder_text">Новый каталог</string>
+ <string name="uploader_top_message">Выберите каталог для загрузки</string>
<string name="uploader_wrn_no_account_title">Учётная запись не найдена</string>
- <string name="uploader_wrn_no_account_text">Ð\9dа ваÑ\88ем Ñ\83Ñ\81Ñ\82Ñ\80ойÑ\81Ñ\82ве неÑ\82 Ñ\83Ñ\87Ñ\91Ñ\82нÑ\8bÑ\85 запиÑ\81ей %1$s. СнаÑ\87ала нÑ\83жно наÑ\81Ñ\82Ñ\80оиÑ\82Ñ\8c учётную запись.</string>
- <string name="uploader_wrn_no_account_setup_btn_text">УÑ\81Ñ\82ановка</string>
+ <string name="uploader_wrn_no_account_text">Ð\9dа ваÑ\88ем Ñ\83Ñ\81Ñ\82Ñ\80ойÑ\81Ñ\82ве неÑ\82 Ñ\83Ñ\87Ñ\91Ñ\82нÑ\8bÑ\85 запиÑ\81ей %1$s. Ð\9fожалÑ\83йÑ\81Ñ\82а, наÑ\81Ñ\82Ñ\80ойÑ\82е учётную запись.</string>
+ <string name="uploader_wrn_no_account_setup_btn_text">Ð\9dаÑ\81Ñ\82Ñ\80ойка</string>
<string name="uploader_wrn_no_account_quit_btn_text">Выход</string>
<string name="uploader_wrn_no_content_title">Нет содержимого для загрузки</string>
<string name="uploader_wrn_no_content_text">Содержимое не получено. Нечего загружать.</string>
- <string name="uploader_error_forbidden_content">%1$s не имеет доступа к опубликованным данным</string>
+ <string name="uploader_error_forbidden_content">Доступ к общему ресурсу для %1$s запрещен</string>
<string name="uploader_info_uploading">Загрузка</string>
- <string name="file_list_seconds_ago">только что</string>
+ <string name="file_list_seconds_ago">несколько секунд назад</string>
<string name="file_list_empty">Здесь ничего нет. Загрузите что-нибудь!</string>
<string name="file_list_loading">Загрузка...</string>
- <string name="local_file_list_empty">В данной папке нет файлов.</string>
+ <string name="local_file_list_empty">В этом каталоге нет файлов.</string>
<string name="filedetails_select_file">Нажмите на файл для отображения дополнительной информации.</string>
<string name="filedetails_size">Размер:</string>
<string name="filedetails_type">Тип:</string>
<string name="filedetails_download">Скачать</string>
<string name="filedetails_sync_file">Обновить файл</string>
<string name="filedetails_renamed_in_upload_msg">Файл был переименован в %1$s во время загрузки</string>
+ <string name="list_layout">Макет списка</string>
<string name="action_share_file">Поделиться ссылкой</string>
- <string name="action_unshare_file">Удалить ссылку</string>
+ <string name="action_unshare_file">УбÑ\80ать ссылку</string>
<string name="common_yes">Да</string>
<string name="common_no">Нет</string>
<string name="common_ok">ОК</string>
<string name="common_cancel">Отмена</string>
<string name="common_save_exit">Сохранить и выйти</string>
<string name="common_error">Ошибка</string>
- <string name="common_loading">Ð\98дÑ\91Ñ\82 загÑ\80Ñ\83зка...</string>
+ <string name="common_loading">Ð\97агÑ\80Ñ\83зка ...</string>
<string name="common_error_unknown">Неизвестная ошибка</string>
<string name="about_title">О программе</string>
<string name="change_password">Сменить пароль</string>
<string name="delete_account">Удалить учётную запись</string>
<string name="create_account">Создать учётную запись</string>
- <string name="upload_chooser_title">Загрузить из...</string>
- <string name="uploader_info_dirname">Ð\98мÑ\8f папки</string>
- <string name="uploader_upload_in_progress_ticker">Загрузка...</string>
- <string name="uploader_upload_in_progress_content">%1$d%% загÑ\80Ñ\83зки %2$s</string>
+ <string name="upload_chooser_title">Загрузить из ...</string>
+ <string name="uploader_info_dirname">Ð\98мÑ\8f каÑ\82алога</string>
+ <string name="uploader_upload_in_progress_ticker">Загрузка ...</string>
+ <string name="uploader_upload_in_progress_content">%1$d%% Ð\97агÑ\80Ñ\83жаеÑ\82Ñ\81Ñ\8f %2$s</string>
<string name="uploader_upload_succeeded_ticker">Загрузка завершена</string>
<string name="uploader_upload_succeeded_content_single">%1$s был успешно загружен</string>
<string name="uploader_upload_failed_ticker">Ошибка загрузки</string>
<string name="uploader_upload_failed_content_single">Загрузка %1$s не может быть завершена</string>
- <string name="uploader_upload_failed_credentials_error">Ð\97агÑ\80Ñ\83зка не Ñ\83далаÑ\81Ñ\8c, Ð\92ам необÑ\85одимо пеÑ\80еподклÑ\8eÑ\87иÑ\82Ñ\8cÑ\81Ñ\8f</string>
- <string name="downloader_download_in_progress_ticker">Скачивание...</string>
- <string name="downloader_download_in_progress_content">%1$d%% скачивания %2$s</string>
+ <string name="uploader_upload_failed_credentials_error">Ð\97агÑ\80Ñ\83зка не Ñ\83далаÑ\81Ñ\8c, нÑ\83жно заново войÑ\82и в Ñ\81воÑ\8e Ñ\83Ñ\87еÑ\82нÑ\83Ñ\8e запиÑ\81Ñ\8c</string>
+ <string name="downloader_download_in_progress_ticker">Скачивание ...</string>
+ <string name="downloader_download_in_progress_content">%1$d%% Скачивается %2$s</string>
<string name="downloader_download_succeeded_ticker">Скачивание завершено</string>
<string name="downloader_download_succeeded_content">%1$s успешно скачан</string>
<string name="downloader_download_failed_ticker">Скачивание не удалось</string>
<string name="downloader_download_failed_content">Скачивание %1$s не может быть завершено</string>
<string name="downloader_not_downloaded_yet">Ещё не скачано</string>
- <string name="downloader_download_failed_credentials_error">СкаÑ\87ивание не Ñ\83далоÑ\81Ñ\8c, Ð\92ам необÑ\85одимо пеÑ\80еподклÑ\8eÑ\87иÑ\82Ñ\8cÑ\81Ñ\8f</string>
+ <string name="downloader_download_failed_credentials_error">СкаÑ\87ивание не Ñ\83далоÑ\81Ñ\8c, нÑ\83жно заново войÑ\82и в Ñ\81воÑ\8e Ñ\83Ñ\87еÑ\82нÑ\83Ñ\8e запиÑ\81Ñ\8c</string>
<string name="common_choose_account">Выберите учётную запись</string>
<string name="sync_fail_ticker">Синхронизация прошла неудачно</string>
- <string name="sync_fail_ticker_unauthorized">СинÑ\85Ñ\80онизаÑ\86иÑ\8f не Ñ\83далаÑ\81Ñ\8c, Ð\92ам необÑ\85одимо пеÑ\80еподклÑ\8eÑ\87иÑ\82Ñ\8cÑ\81Ñ\8f</string>
+ <string name="sync_fail_ticker_unauthorized">СинÑ\85Ñ\80онизаÑ\86иÑ\8f не Ñ\83далаÑ\81Ñ\8c, нÑ\83жно заново войÑ\82и в Ñ\81воÑ\8e Ñ\83Ñ\87еÑ\82нÑ\83Ñ\8e запиÑ\81Ñ\8c</string>
<string name="sync_fail_content">Синхронизация %1$s не может быть завершена</string>
<string name="sync_fail_content_unauthorized">Неверный пароль для %1$s</string>
<string name="sync_conflicts_in_favourites_ticker">Обнаружены конфликты</string>
- <string name="sync_conflicts_in_favourites_content">%1$d файлы не могут быть синхронизированы</string>
+ <string name="sync_conflicts_in_favourites_content">%1$d файлов не может быть синхронизировано</string>
<string name="sync_fail_in_favourites_ticker">Не удалось синхронизировать файлы</string>
<string name="sync_fail_in_favourites_content">Содержимое %1$d файлов не может быть синхронизировано (конфликтов: %2$d)</string>
- <string name="sync_foreign_files_forgotten_ticker">Несколько локальных файлов были забыты</string>
- <string name="sync_foreign_files_forgotten_content"> Не возможно скопировать %1$d файлы из %2$s папки</string>
- <string name="sync_foreign_files_forgotten_explanation">Ð\9dаÑ\87инаÑ\8f Ñ\81 веÑ\80Ñ\81ии 1.3.16, Ñ\84айлÑ\8b, загÑ\80Ñ\83жаемÑ\8bе Ñ\81 Ñ\8dÑ\82ого Ñ\83Ñ\81Ñ\82Ñ\80ойÑ\81Ñ\82ва, копиÑ\80Ñ\83Ñ\8eÑ\82Ñ\81Ñ\8f в локалÑ\8cнÑ\83Ñ\8e диÑ\80екÑ\82оÑ\80иÑ\8e %1$s, Ñ\87Ñ\82обÑ\8b пÑ\80едоÑ\82вÑ\80аÑ\82иÑ\82Ñ\8c поÑ\82еÑ\80Ñ\8e даннÑ\8bÑ\85 пÑ\80и Ñ\81инÑ\85Ñ\80онизаÑ\86ии Ñ\84айла Ñ\81 неÑ\81колÑ\8cкими Ñ\83Ñ\87Ñ\91Ñ\82нÑ\8bми запиÑ\81Ñ\8fми.\n\nÐ\9fоÑ\8dÑ\82омÑ\83 вÑ\81е Ñ\84айлÑ\8b, загÑ\80Ñ\83женнÑ\8bе пÑ\80едÑ\8bдÑ\83Ñ\89ими веÑ\80Ñ\81иÑ\8fми данного пÑ\80иложениÑ\8f, бÑ\8bли Ñ\81копиÑ\80ованÑ\8b в диÑ\80екÑ\82оÑ\80иÑ\8e %2$s. Ð\9eднако, во вÑ\80емÑ\8f Ñ\81инÑ\85Ñ\80онизаÑ\86ии Ñ\87Ñ\82о-Ñ\82о помеÑ\88ало завеÑ\80Ñ\88иÑ\82Ñ\8c Ñ\8dÑ\82Ñ\83 опеÑ\80аÑ\86иÑ\8e. ТепеÑ\80Ñ\8c можно либо оставить файлы как есть и удалить ссылку на %3$s, либо переместить их в %1$s и сохранить ссылку на %4$s.\n\nНиже перечислены локальные файлы, и соответствующие им удалённые файлы в %5$s, к которым они привязаны.</string>
+ <string name="sync_foreign_files_forgotten_ticker">Некоторые загруженные файлы не были перенесены в локальную папку </string>
+ <string name="sync_foreign_files_forgotten_content">Не удалось скопировать %1$d файлов из каталога %2$s в</string>
+ <string name="sync_foreign_files_forgotten_explanation">Ð\9dаÑ\87инаÑ\8f Ñ\81 веÑ\80Ñ\81ии 1.3.16, Ñ\84айлÑ\8b, загÑ\80Ñ\83жаемÑ\8bе Ñ\81 Ñ\8dÑ\82ого Ñ\83Ñ\81Ñ\82Ñ\80ойÑ\81Ñ\82ва, копиÑ\80Ñ\83Ñ\8eÑ\82Ñ\81Ñ\8f в локалÑ\8cнÑ\8bй каÑ\82алог %1$s, Ñ\87Ñ\82обÑ\8b пÑ\80едоÑ\82вÑ\80аÑ\82иÑ\82Ñ\8c поÑ\82еÑ\80Ñ\8e даннÑ\8bÑ\85 пÑ\80и Ñ\81инÑ\85Ñ\80онизаÑ\86ии Ñ\84айла Ñ\81 неÑ\81колÑ\8cкими Ñ\83Ñ\87Ñ\91Ñ\82нÑ\8bми запиÑ\81Ñ\8fми.\n\nÐ\9fоÑ\8dÑ\82омÑ\83 вÑ\81е Ñ\84айлÑ\8b, загÑ\80Ñ\83женнÑ\8bе пÑ\80едÑ\8bдÑ\83Ñ\89ими веÑ\80Ñ\81иÑ\8fми данного пÑ\80иложениÑ\8f, бÑ\8bли Ñ\81копиÑ\80ованÑ\8b в каÑ\82алог %2$s. Ð\9eднако, во вÑ\80емÑ\8f Ñ\81инÑ\85Ñ\80онизаÑ\86ии Ñ\87Ñ\82о-Ñ\82о помеÑ\88ало завеÑ\80Ñ\88иÑ\82Ñ\8c Ñ\8dÑ\82Ñ\83 опеÑ\80аÑ\86иÑ\8e. Ð\9cожеÑ\82е оставить файлы как есть и удалить ссылку на %3$s, либо переместить их в %1$s и сохранить ссылку на %4$s.\n\nНиже перечислены локальные файлы, и соответствующие им удалённые файлы в %5$s, к которым они привязаны.</string>
<string name="sync_current_folder_was_removed">Каталог %1$s больше не существует</string>
<string name="foreign_files_move">Переместить всё</string>
<string name="foreign_files_success">Все файлы были перемещены</string>
<string name="foreign_files_fail">Некоторые файлы не могут быть перемещены</string>
- <string name="foreign_files_local_text">Локально: %1$s</string>
- <string name="foreign_files_remote_text">Удаленно: %1$s</string>
- <string name="upload_query_move_foreign_files">Ð\94лÑ\8f копиÑ\80ованиÑ\8f вÑ\8bбÑ\80аннÑ\8bÑ\85 Ñ\84айлов в папкÑ\83 %1$s недоÑ\81Ñ\82аÑ\82оÑ\87но Ñ\81вободного меÑ\81Ñ\82а. СкопиÑ\80оваÑ\82Ñ\8c в дÑ\80Ñ\83гое меÑ\81Ñ\82о?</string>
- <string name="pincode_enter_pin_code">Вставьте App PIN</string>
- <string name="pincode_configure_your_pin">Введите App PIN</string>
- <string name="pincode_configure_your_pin_explanation">PIN-код будет запрашиваться при каждом запуске приложения.</string>
- <string name="pincode_reenter_your_pincode">Повторите ввод App PIN</string>
- <string name="pincode_remove_your_pincode">Удалить App PIN</string>
- <string name="pincode_mismatch">Введённые App PIN не совпадают</string>
- <string name="pincode_wrong">Неверный App PIN</string>
- <string name="pincode_removed">App PIN удалён</string>
- <string name="pincode_stored">App PIN сохранён</string>
+ <string name="foreign_files_local_text">Локальные: %1$s</string>
+ <string name="foreign_files_remote_text">Удаленные: %1$s</string>
+ <string name="upload_query_move_foreign_files">Ð\94лÑ\8f копиÑ\80ованиÑ\8f вÑ\8bбÑ\80аннÑ\8bÑ\85 Ñ\84айлов в каÑ\82алог %1$s недоÑ\81Ñ\82аÑ\82оÑ\87но Ñ\81вободного меÑ\81Ñ\82а. Ð\9fеÑ\80емеÑ\81Ñ\82иÑ\82Ñ\8c иÑ\85 вмеÑ\81Ñ\82о Ñ\8dÑ\82ого?</string>
+ <string name="pass_code_enter_pass_code">Пожалуйста, укажите код</string>
+ <string name="pass_code_configure_your_pass_code">Укажите ваш код</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Код будет запрашиваться каждый раз при запуске приложения</string>
+ <string name="pass_code_reenter_your_pass_code">Пожалуйста, укажите код ещё раз</string>
+ <string name="pass_code_remove_your_pass_code">Убрать код</string>
+ <string name="pass_code_mismatch">Коды не совпадают</string>
+ <string name="pass_code_wrong">Некоррентный код</string>
+ <string name="pass_code_removed">Код удален</string>
+ <string name="pass_code_stored">Код сохранен</string>
<string name="media_notif_ticker">%1$s аудиоплеер</string>
<string name="media_state_playing">%1$s (проигрывается)</string>
<string name="media_state_loading">%1$s (загружается)</string>
<string name="media_event_done">%1$s воспроизведение завершено</string>
- <string name="media_err_nothing_to_play">Медиафайлов не найдено</string>
- <string name="media_err_no_account">Учётная запись не настроена</string>
+ <string name="media_err_nothing_to_play">Медиафайлы не найдены</string>
+ <string name="media_err_no_account">Учётная запись не указана</string>
<string name="media_err_not_in_owncloud">Файл в неверной учётной записи</string>
<string name="media_err_unsupported">Неподдерживаемый кодек</string>
<string name="media_err_io">Медиафайл не может быть прочитан</string>
<string name="media_err_malformed">Медиафайл некорректно закодирован</string>
- <string name="media_err_timeout">Ð\92Ñ\80емÑ\8f попÑ\8bÑ\82ок воÑ\81пÑ\80оизведениÑ\8f вÑ\8bÑ\88ло</string>
+ <string name="media_err_timeout">Ð\98Ñ\81Ñ\82екло вÑ\80емÑ\8f попÑ\8bÑ\82ки воÑ\81пÑ\80оизведениÑ\8f</string>
<string name="media_err_invalid_progressive_playback">Невозможно организовать потоковую передачу медиафайла</string>
<string name="media_err_unknown">Медиафайл не может быть проигран стандартным плеером</string>
<string name="media_err_security_ex">Ошибка безопасности при воспроизведении %1$s</string>
<string name="media_rewind_description">Перемотка назад</string>
<string name="media_play_pause_description">Воспроизведение или пауза</string>
<string name="media_forward_description">Перемотка вперед</string>
- <string name="auth_getting_authorization">Ð\9fÑ\80оиÑ\81Ñ\85одиÑ\82 авÑ\82оÑ\80изаÑ\86иÑ\8f.....</string>
+ <string name="auth_getting_authorization">Ð\92Ñ\8bполнÑ\8fеÑ\82Ñ\81Ñ\8f авÑ\82оÑ\80изаÑ\86иÑ\8f...</string>
<string name="auth_trying_to_login">Попытка входа...</string>
<string name="auth_no_net_conn_title">Нет подключения к сети</string>
<string name="auth_nossl_plain_ok_title">Защищённое соединение недоступно.</string>
<string name="auth_connection_established">Соединение установлено</string>
- <string name="auth_testing_connection">ТеÑ\81Ñ\82иÑ\80ование Ñ\81оединениÑ\8f...</string>
+ <string name="auth_testing_connection">Ð\9fÑ\80овеÑ\80ка Ñ\81оединениÑ\8f</string>
<string name="auth_not_configured_title">Конфигурация сервера задана неверно</string>
<string name="auth_account_not_new">Учётная запись такого пользователя и сервера уже существует на устройстве</string>
<string name="auth_account_not_the_same">Введённый пользователь не соответствует этой учётной записи</string>
<string name="auth_timeout_title">Сервер слишком долго не отвечает</string>
<string name="auth_incorrect_address_title">Неверный URL</string>
<string name="auth_ssl_general_error_title">Ошибка инициализации SSL</string>
- <string name="auth_ssl_unverified_server_title">Невозможно проверить SSL-сертификат сервера</string>
+ <string name="auth_ssl_unverified_server_title">Невозможно проверить SSL подлинность сервера</string>
<string name="auth_bad_oc_version_title">Неизвестная версия сервера</string>
- <string name="auth_wrong_connection_title">Невозможно установить соединение</string>
+ <string name="auth_wrong_connection_title">Не удается установить соединение</string>
<string name="auth_secure_connection">Защищённое соединение установлено</string>
<string name="auth_unauthorized">Неверное имя пользователя или пароль</string>
<string name="auth_oauth_error">Ошибка авторизации</string>
<string name="auth_oauth_error_access_denied">Сервер авторизации отказал в доступе</string>
<string name="auth_wtf_reenter_URL">Неожиданный ответ; введите адрес сервера ещё раз</string>
<string name="auth_expired_oauth_token_toast">Время авторизации истекло. Пожалуйста, авторизуйтесь снова</string>
- <string name="auth_expired_basic_auth_toast">Пожалуйста, введите пароль</string>
+ <string name="auth_expired_basic_auth_toast">Пожалуйста, укажите текущий пароль</string>
<string name="auth_expired_saml_sso_token_toast">Время сессии истекло. Пожалуйста, подключитесь снова</string>
<string name="auth_connecting_auth_server">Подключение к серверу аутентификации...</string>
<string name="auth_unsupported_auth_method">Сервер не поддерживает выбранный метод аутентификации</string>
- <string name="auth_unsupported_multiaccount">%1$s не поддерживает сразу несколько учётных записей</string>
- <string name="auth_fail_get_user_name">Ð\92аÑ\88 Ñ\81еÑ\80веÑ\80 не возвÑ\80аÑ\89аеÑ\82 коÑ\80Ñ\80екÑ\82нÑ\8bй полÑ\8cзоваÑ\82елÑ\8cÑ\81кий иденÑ\82иÑ\84икаÑ\82оÑ\80, пожалÑ\83йÑ\81Ñ\82а Ñ\81вÑ\8fжиÑ\82еÑ\81Ñ\8c Ñ\81 администратором
+ <string name="auth_unsupported_multiaccount">%1$s не поддерживает несколько учётных записей</string>
+ <string name="auth_fail_get_user_name">СеÑ\80веÑ\80 веÑ\80нÑ\83л некоÑ\80Ñ\80екÑ\82нÑ\8bй полÑ\8cзоваÑ\82елÑ\8cÑ\81кий иденÑ\82иÑ\84икаÑ\82оÑ\80. Ð\9fожалÑ\83йÑ\81Ñ\82а, Ñ\81вÑ\8fжиÑ\82еÑ\81Ñ\8c Ñ\81 ваÑ\88им администратором
⇥</string>
- <string name="auth_can_not_auth_against_server">Невозможно аутентифицироваться на этом сервере</string>
+ <string name="auth_can_not_auth_against_server">Невозможно авторизоваться на этом сервере</string>
+ <string name="auth_account_does_not_exist">Аккаунт не существует на устройстве ещё</string>
<string name="fd_keep_in_sync">Обновлять файл</string>
<string name="common_rename">Переименовать</string>
<string name="common_remove">Удалить</string>
<string name="rename_server_fail_msg">Переименование не может быть завершено</string>
<string name="sync_file_fail_msg">Удаленный файл не может быть проверен</string>
<string name="sync_file_nothing_to_do_msg">Содержимое файла уже синхронизировано</string>
- <string name="create_dir_fail_msg">Не возможно создать папку</string>
+ <string name="create_dir_fail_msg">Не удалось создать каталог</string>
<string name="filename_forbidden_characters">Недопустимые символы: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Имя файла содержит по крайней мере один некорректный символ</string>
<string name="filename_empty">Имя файла не может быть пустым</string>
<string name="wait_a_moment">Подождите немного</string>
<string name="filedisplay_unexpected_bad_get_content">Неизвестная ошибка; выберите этот файл из другого приложения</string>
<string name="filedisplay_no_file_selected">Файлы не выбраны</string>
- <string name="activity_chooser_title">Отправить ссылку...</string>
+ <string name="activity_chooser_title">Отправить ссылку ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Копирование файла из частной хранилища</string>
<string name="oauth_check_onoff">Войти через oAuth2</string>
<string name="oauth_login_connection">Подключение к серверу oAuth2...</string>
<string name="ssl_validator_header">Подлинность сайта не может быть проверена</string>
<string name="ssl_validator_reason_cert_expired">- Срок действия сертификата сервера истёк</string>
<string name="ssl_validator_reason_cert_not_yet_valid">- Срок действия сертификата сервера ещё не начался</string>
<string name="ssl_validator_reason_hostname_not_verified">- URL не совпадает с именем сервера в сертификате</string>
- <string name="ssl_validator_question">Ð\92Ñ\8b Ñ\85оÑ\82иÑ\82е довеÑ\80Ñ\8fÑ\82Ñ\8c данному сертификату в любом случае?</string>
+ <string name="ssl_validator_question">Ð\94овеÑ\80Ñ\8fÑ\82Ñ\8c Ñ\8dÑ\82ому сертификату в любом случае?</string>
<string name="ssl_validator_not_saved">Сертификат не может быть сохранён</string>
<string name="ssl_validator_btn_details_see">Подробно</string>
<string name="ssl_validator_btn_details_hide">Скрыть</string>
- <string name="ssl_validator_label_subject">Кому выдано:</string>
- <string name="ssl_validator_label_issuer">Кем выдано:</string>
+ <string name="ssl_validator_label_subject">Кому выдан:</string>
+ <string name="ssl_validator_label_issuer">Кем выдан:</string>
<string name="ssl_validator_label_CN">Имя:</string>
<string name="ssl_validator_label_O">Организация:</string>
- <string name="ssl_validator_label_OU">Ð\9eÑ\80ганизаÑ\86ионное подразделение:</string>
+ <string name="ssl_validator_label_OU">Ð\9fодразделение:</string>
<string name="ssl_validator_label_C">Страна:</string>
<string name="ssl_validator_label_ST">Штат:</string>
<string name="ssl_validator_label_L">Местонахождение:</string>
<string name="ssl_validator_label_validity">Срок действия:</string>
- <string name="ssl_validator_label_validity_from">Ð\98з:</string>
- <string name="ssl_validator_label_validity_to">Ð\92:</string>
+ <string name="ssl_validator_label_validity_from">С:</string>
+ <string name="ssl_validator_label_validity_to">Ð\9fо:</string>
<string name="ssl_validator_label_signature">Подпись:</string>
<string name="ssl_validator_label_signature_algorithm">Алгоритм:</string>
<string name="ssl_validator_null_cert">Сертификат не может быть показан.</string>
- <string name="ssl_validator_no_info_about_error">- Ð\98нÑ\84оÑ\80маÑ\86ии об оÑ\88ибке неÑ\82</string>
+ <string name="ssl_validator_no_info_about_error">- Ð\9dеÑ\82 инÑ\84оÑ\80маÑ\86ии об оÑ\88ибке</string>
<string name="placeholder_sentence">Это заполнитель</string>
<string name="placeholder_filename">placeholder.txt</string>
<string name="placeholder_filetype">Изображение PNG</string>
<string name="placeholder_filesize">389 КБ</string>
<string name="placeholder_timestamp">2012/05/18 12:23 PM</string>
<string name="placeholder_media_time">12:23:45</string>
- <string name="instant_upload_on_wifi">Ð\97агÑ\80Ñ\83жаÑ\82Ñ\8c изобÑ\80ажениÑ\8f только через Wi-Fi</string>
+ <string name="instant_upload_on_wifi">Ð\97агÑ\80Ñ\83зка изобÑ\80ажений только через Wi-Fi</string>
<string name="instant_video_upload_on_wifi">Загрузка видео только через WiFi</string>
<string name="instant_upload_path">/InstantUpload</string>
<string name="conflict_title">Конфликт обновления</string>
<string name="conflict_message">Удаленный файл %s не синхронизирован с локальным. Продолжение приведет к замене содержимого файла на сервере.</string>
<string name="conflict_keep_both">Сохранить оба</string>
- <string name="conflict_overwrite">Ð\97аменить</string>
+ <string name="conflict_overwrite">Ð\9fеÑ\80езапиÑ\81ать</string>
<string name="conflict_dont_upload">Не загружать</string>
<string name="preview_image_description">Предпросмотр</string>
<string name="preview_image_error_unknown_format">Это изображение не может быть отображено</string>
- <string name="error__upload__local_file_not_copied">%1$s не возможно скопировать в локальною папку %2$s </string>
+ <string name="error__upload__local_file_not_copied">%1$s невозможно скопировать в локальный каталог %2$s </string>
<string name="prefs_instant_upload_path_title">Путь для загрузки</string>
- <string name="share_link_no_support_share_api">К сожалению, на вашем сервере отключен совместный доступ. Пожалуйста, свяжитесь с вашим администратором.</string>
- <string name="share_link_file_no_exist">Невозможно добавить в общий доступ. Пожалуйста, проверьте, существует ли файл</string>
- <string name="share_link_file_error">Ошибка предоставления общего доступа к этому файлу или каталогу</string>
- <string name="unshare_link_file_no_exist">Невозможно убрать из общего доступа. Пожалуйста, проверьте, существует ли файл</string>
- <string name="unshare_link_file_error">Ошибка удаления общего доступа к этому файлу или каталогу</string>
+ <string name="share_link_no_support_share_api">Механизм общего доступа не включен на данном сервере. Пожалуйста, свяжитесь с вашим
+⇥⇥администратором.</string>
+ <string name="share_link_file_no_exist">Невозможно поделиться. Убедитесь, что файл существует</string>
+ <string name="share_link_file_error">При попытке поделиться этим файлом или каталогом произошла ошибка</string>
+ <string name="unshare_link_file_no_exist">Невозможно закрыть доступ. Убедитесь что файл существует</string>
+ <string name="unshare_link_file_error">При попытке закрыть доступ к этому файлу или каталогу произошла ошибка</string>
+ <string name="share_link_password_title">Введите пароль</string>
+ <string name="share_link_empty_password">Вы должны ввести пароль</string>
<string name="activity_chooser_send_file_title">Отправить</string>
<string name="copy_link">Копировать ссылку</string>
<string name="clipboard_text_copied">Скопировано в буфер обмена</string>
- <string name="error_cant_bind_to_operations_service">Ð\9aÑ\80иÑ\82иÑ\87еÑ\81каÑ\8f оÑ\88ибка: невозможно вÑ\8bполниÑ\82Ñ\8c опеÑ\80аÑ\86ии</string>
+ <string name="error_cant_bind_to_operations_service">Ð\9aÑ\80иÑ\82иÑ\87еÑ\81каÑ\8f оÑ\88ибка: невозможно вÑ\8bполниÑ\82Ñ\8c дейÑ\81Ñ\82виÑ\8f</string>
<string name="network_error_socket_exception">При подключении к серверу возникла ошибка</string>
- <string name="network_error_socket_timeout_exception">Ð\92о вÑ\80емÑ\8f ожиданиÑ\8f Ñ\81еÑ\80веÑ\80а возникла оÑ\88ибка, опеÑ\80аÑ\86иÑ\8f не можеÑ\82 бÑ\8bÑ\82Ñ\8c завеÑ\80Ñ\88ена</string>
- <string name="network_error_connect_timeout_exception">Ð\92о вÑ\80емÑ\8f ожиданиÑ\8f Ñ\81еÑ\80веÑ\80а возникла оÑ\88ибка, опеÑ\80аÑ\86иÑ\8f не можеÑ\82 бÑ\8bÑ\82Ñ\8c завеÑ\80Ñ\88ена</string>
- <string name="network_host_not_available">Ð\9eпеÑ\80аÑ\86иÑ\8f не можеÑ\82 бÑ\8bÑ\82Ñ\8c завеÑ\80Ñ\88ена, сервер недоступен</string>
+ <string name="network_error_socket_timeout_exception">Ð\92о вÑ\80емÑ\8f ожиданиÑ\8f Ñ\81еÑ\80веÑ\80а пÑ\80оизоÑ\88ла оÑ\88ибка, дейÑ\81Ñ\82вие не можеÑ\82 бÑ\8bÑ\82Ñ\8c вÑ\8bполнено</string>
+ <string name="network_error_connect_timeout_exception">Ð\92о вÑ\80емÑ\8f ожиданиÑ\8f Ñ\81еÑ\80веÑ\80а пÑ\80оизоÑ\88ла оÑ\88ибка, дейÑ\81Ñ\82вие не можеÑ\82 бÑ\8bÑ\82Ñ\8c вÑ\8bполнено</string>
+ <string name="network_host_not_available">Ð\94ейÑ\81Ñ\82вие не можеÑ\82 бÑ\8bÑ\82Ñ\8c вÑ\8bполнено, сервер недоступен</string>
<string name="empty"></string>
- <string name="forbidden_permissions">У ваÑ\81 неÑ\82 доÑ\81Ñ\82Ñ\83па %s</string>
- <string name="forbidden_permissions_rename">пеÑ\80еименоваÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ñ\84айл</string>
- <string name="forbidden_permissions_delete">удалить этот файл</string>
- <string name="share_link_forbidden_permissions">опÑ\83бликоваÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ñ\84айл</string>
- <string name="unshare_link_forbidden_permissions">оÑ\82мениÑ\82Ñ\8c пÑ\83бликаÑ\86иÑ\8e Ñ\8dÑ\82ого Ñ\84айла</string>
- <string name="forbidden_permissions_create">создать файл</string>
- <string name="uploader_upload_forbidden_permissions">загÑ\80Ñ\83зиÑ\82Ñ\8c в Ñ\8dÑ\82Ñ\83 папкÑ\83</string>
+ <string name="forbidden_permissions">У ваÑ\81 неÑ\82 пÑ\80ав %s</string>
+ <string name="forbidden_permissions_rename">длÑ\8f пеÑ\80еименованиÑ\8f Ñ\8dÑ\82ого Ñ\84айла</string>
+ <string name="forbidden_permissions_delete">для удаления этого файла</string>
+ <string name="share_link_forbidden_permissions">длÑ\8f оÑ\82кÑ\80Ñ\8bÑ\82иÑ\8f доÑ\81Ñ\82Ñ\83па к Ñ\8dÑ\82омÑ\83 Ñ\84айлÑ\83</string>
+ <string name="unshare_link_forbidden_permissions">длÑ\8f закÑ\80Ñ\8bÑ\82иÑ\8f доÑ\81Ñ\82Ñ\83па к Ñ\8dÑ\82омÑ\83 Ñ\84айлÑ\83</string>
+ <string name="forbidden_permissions_create">для создания файла</string>
+ <string name="uploader_upload_forbidden_permissions">длÑ\8f загÑ\80Ñ\83зки в Ñ\8dÑ\82оÑ\82 каÑ\82алог</string>
<string name="downloader_download_file_not_found">Этот файл больше недоступен на сервере</string>
<string name="prefs_category_accounts">Учётные записи</string>
<string name="prefs_add_account">Добавить учетную запись</string>
- <string name="auth_redirect_non_secure_connection_title">Ð\97аÑ\89иÑ\89Ñ\91нное Ñ\81оединение пеÑ\80енапÑ\80авлено по незаÑ\89иÑ\89Ñ\91нному маршруту</string>
+ <string name="auth_redirect_non_secure_connection_title">Ð\97аÑ\89иÑ\89Ñ\91нное Ñ\81оединение пеÑ\80енапÑ\80авлено по небезопаÑ\81ному маршруту</string>
<string name="actionbar_logger">Журналы</string>
<string name="log_send_history_button">История Отправлений</string>
- <string name="log_mail_subject">Журналы Андроид-приложения ownCloud</string>
- <string name="log_progress_dialog_text">Загружаются данные...</string>
+ <string name="log_send_no_mail_app">Приложение для отправки журнала не найдено. Установите почтовое приложение!</string>
+ <string name="log_send_mail_subject">Журналы %1$s для Android</string>
+ <string name="log_progress_dialog_text">Загрузка данных…</string>
<string name="saml_authentication_required_text">Требуется аутентификация </string>
<string name="saml_authentication_wrong_pass">Неправильный пароль</string>
<string name="actionbar_move">Переместить</string>
- <string name="file_list_empty_moving">Здесь ничего нет. Вы можете добавить папку!</string>
- <string name="move_choose_button_text">Выбрать</string>
- <string name="move_file_not_found">Ð\9dевозможно пеÑ\80емеÑ\81Ñ\82иÑ\82Ñ\8c. Ð\9fожалÑ\83йÑ\81Ñ\82а, пÑ\80овеÑ\80Ñ\8cÑ\82е, Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 ли Ñ\84айл</string>
- <string name="move_file_invalid_into_descendent">Ð\9dевозможно пеÑ\80емеÑ\81Ñ\82иÑ\82Ñ\8c папкÑ\83 в папкÑ\83-поÑ\82омок</string>
- <string name="move_file_invalid_overwrite">Файл Ñ\83же Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 в папке назначения</string>
- <string name="move_file_error">Ð\9fÑ\80оизоÑ\88ла оÑ\88ибка пÑ\80и попÑ\8bÑ\82ке пеÑ\80емеÑ\89ениÑ\8f Ñ\8dÑ\82ого Ñ\84айла или папки</string>
- <string name="forbidden_permissions_move">пеÑ\80емеÑ\81Ñ\82иÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ñ\84айл</string>
+ <string name="file_list_empty_moving">Здесь ничего нет. Вы можете создать каталог!</string>
+ <string name="folder_picker_choose_button_text">Выбрать</string>
+ <string name="move_file_not_found">Ð\9dевозможно пеÑ\80емеÑ\81Ñ\82иÑ\82Ñ\8c. УбедиÑ\82еÑ\81Ñ\8c, Ñ\87Ñ\82о Ñ\84айл Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82</string>
+ <string name="move_file_invalid_into_descendent">Ð\9dевозможно пеÑ\80емеÑ\81Ñ\82иÑ\82Ñ\8c каÑ\82алог в его подкаÑ\82алог</string>
+ <string name="move_file_invalid_overwrite">Файл Ñ\83же Ñ\81Ñ\83Ñ\89еÑ\81Ñ\82вÑ\83еÑ\82 в каÑ\82алоге назначения</string>
+ <string name="move_file_error">Ð\9fÑ\80оизоÑ\88ла оÑ\88ибка пÑ\80и попÑ\8bÑ\82ке пеÑ\80емеÑ\89ениÑ\8f Ñ\8dÑ\82ого Ñ\84айла или каÑ\82алога</string>
+ <string name="forbidden_permissions_move">длÑ\8f пеÑ\80емеÑ\89ениÑ\8f Ñ\8dÑ\82ого Ñ\84айла</string>
<string name="prefs_category_instant_uploading">Мгновенные загрузки</string>
<string name="prefs_category_security">Безопасность</string>
+ <string name="prefs_instant_video_upload_path_title">Путь для загрузки Видео</string>
+ <string name="download_folder_failed_content">Не удалось завершить скачивание каталога %1$s</string>
+ <string name="shared_subject_header">поделился</string>
+ <string name="with_you_subject_header">с вами</string>
+ <string name="subject_token">%1$s предоставил вам доступ к \"%2$s\"</string>
+ <string name="auth_refresh_button">Обновить соединение</string>
+ <string name="auth_host_address">Адрес сервера</string>
+ <string name="common_error_out_memory">Недостаточно памяти</string>
+ <string name="username">Имя пользователя</string>
+ <string name="file_list__footer__folder">1 каталог</string>
+ <string name="file_list__footer__folders">%1$d каталогов</string>
+ <string name="file_list__footer__file">1 файл</string>
+ <string name="file_list__footer__file_and_folder">1 файл, 1 папка</string>
+ <string name="file_list__footer__file_and_folders">1 файл, %1$d каталогов</string>
+ <string name="file_list__footer__files">%1$d файлов</string>
+ <string name="file_list__footer__files_and_folder">%1$d файлов, 1 каталог</string>
+ <string name="file_list__footer__files_and_folders">%1$d файлов, %2$d каталогов</string>
</resources>
<string name="actionbar_settings">සිටුවම්</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">සාමාන්යයෙන්</string>
<string name="prefs_category_more">වැඩි</string>
<string name="prefs_accounts">ගිණුම්</string>
<string name="prefs_manage_accounts">ගිණුම් කළමනාකරනය</string>
- <string name="prefs_pincode_summary">ඔබේ සේවාලාභියා සුරකින්න</string>
<string name="prefs_help">උදව්</string>
<string name="auth_username">පරිශීලක නම</string>
<string name="auth_password">මුර පදය</string>
<string name="auth_no_net_conn_title">ජාල සම්බන්ධතාවක් නොමැත</string>
<string name="auth_nossl_plain_ok_title">ආරක්ෂිත සම්බන්ධතාවක් නොලැබුණි</string>
<string name="auth_connection_established">සම්බන්ධතාවක් සාදන ලදී</string>
- <string name="auth_testing_connection">සම්බන්ධතාව පරීක්ෂා කෙරේ</string>
<string name="auth_not_configured_title">විකෘතිවු හැඩගැසුමක්</string>
<string name="auth_unknown_error_title">නොදන්නා දෝෂයක් ඇතිවිය</string>
<string name="auth_unknown_host_title">සේවාදායකයා සොයාගත නොහැක</string>
<string name="ssl_validator_btn_details_hide">සඟවන්න</string>
<string name="empty"></string>
<string name="prefs_category_accounts">ගිණුම්</string>
- <string name="move_choose_button_text">තෝරන්න</string>
+ <string name="folder_picker_choose_button_text">තෝරන්න</string>
+ <string name="auth_host_address">සේවාදායකයේ ලිපිනය</string>
</resources>
<string name="actionbar_settings">Nastavenia</string>
<string name="actionbar_see_details">Podrobnosti</string>
<string name="actionbar_send_file">Odoslať</string>
+ <string name="actionbar_sort">Zoradiť</string>
+ <string name="actionbar_sort_title">Zoradiť podľa</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>Najnovšie - Najstaršie</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Všetky súbory</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Nastavenia</string>
+ <string name="drawer_item_logs">Logy</string>
+ <string name="drawer_close">Zavrieť</string>
<string name="prefs_category_general">Všeobecné</string>
<string name="prefs_category_more">Viac</string>
<string name="prefs_accounts">Účty</string>
<string name="prefs_manage_accounts">Správa účtov</string>
- <string name="prefs_pincode">PIN aplikácie</string>
- <string name="prefs_pincode_summary">Chrániť klienta aplikácie</string>
<string name="prefs_instant_upload">Okamžité nahratie obrázka</string>
<string name="prefs_instant_upload_summary">Okamžite nahrať obrázok zaznamenaný fotoaparátom</string>
<string name="prefs_instant_video_upload">Okamžité nahranie videa</string>
<string name="prefs_recommend">Doporučiť známemu</string>
<string name="prefs_feedback">Spätná väzba</string>
<string name="prefs_imprint">Podmienky používania</string>
+ <string name="prefs_remember_last_share_location">Zapamätať umiestnenie zdieľania</string>
+ <string name="prefs_remember_last_upload_location_summary">Zapamätať posledné umiestnenie pre nahranie zdieľaných súborov</string>
<string name="recommend_subject">Skúste %1$s na vašom telefóne!</string>
+ <string name="recommend_text">Chcel by som vám odporučiť %1$s na vašom smartfóne!\nSťahujte tu: %2$s</string>
<string name="auth_check_server">Skontrolovať Server</string>
<string name="auth_host_url">Adresa servera https://...</string>
<string name="auth_username">Používateľské meno</string>
<string name="sync_string_files">Súbory</string>
<string name="setup_btn_connect">Pripojiť</string>
<string name="uploader_btn_upload_text">Nahrať</string>
+ <string name="uploader_btn_new_folder_text">Nový priečinok</string>
<string name="uploader_top_message">Vyberte priečinok pre nahrávanie:</string>
<string name="uploader_wrn_no_account_title">Účet sa nenašiel</string>
<string name="uploader_wrn_no_account_text">Na tomto zariadení nie je zadaný žiadny %1$s účet. Zadajte ho prosím.</string>
<string name="uploader_info_uploading">Nahrávanie</string>
<string name="file_list_seconds_ago">pred sekundami</string>
<string name="file_list_empty">Žiadny súbor. Nahrajte niečo!</string>
- <string name="file_list_loading">Nahráva sa...</string>
<string name="local_file_list_empty">V tomto priečinku nie sú žiadne súbory.</string>
<string name="filedetails_select_file">Viac informácií získate kliknutím na súbor.</string>
<string name="filedetails_size">Veľkosť:</string>
<string name="sync_fail_in_favourites_content">Obsah %1$d súborov nemohol byť synchronizovaný (%2$d konfliktov)</string>
<string name="sync_foreign_files_forgotten_ticker">Niektoré lokálne súbory boli zabudnuté</string>
<string name="sync_foreign_files_forgotten_content">%1$d súborov z %2$s priečinkov sa nepodarilo skopírovať do</string>
+ <string name="sync_foreign_files_forgotten_explanation">Od verzie 1.3.16 sú súbory nahrané z tohoto zariadenia kopírované do lokálneho priečinka %1$s, aby sa zabránilo strate dát pri synchronizácii jedného súboru s viacerými účtami.\n\nVšetky súbory nahraté predchádzajúcimi verziami aplikácie boli z tohoto dôvodu prekopírované do priečinka %2$s. Bohužiaľ sa objavila chyba zabraňujúca dokončeniu tejto operácie v priebehu synchronizácie účtu. Buď môžete súbor(y) ponechať ako sú a odobrať odkaz z priečinka %3$s, alebo presunúť súbor(y) do priečinka %1$s a zachovať odkaz na %4$s.\n\nNižšie je uvedený lokálny súbor(y) a vzdialený súbor(y) v %5$s, s ktorým je prepojený.</string>
<string name="sync_current_folder_was_removed">Priečinok %1$s už existuje</string>
<string name="foreign_files_move">Premiestniť všetko</string>
<string name="foreign_files_success">Všetky súbory boli premiestnené</string>
<string name="foreign_files_local_text">Lokálne: %1$s</string>
<string name="foreign_files_remote_text">Vzdialené: %1$s</string>
<string name="upload_query_move_foreign_files">Nie je dostatok miesta na skopírovanie vybraných súborov do priečinka %1$s. Želáte si ich namiesto toho presunúť?</string>
- <string name="pincode_enter_pin_code">Zadajte PIN aplikácie</string>
- <string name="pincode_configure_your_pin">Zadajte PIN aplikácie</string>
- <string name="pincode_configure_your_pin_explanation">Pri každom spustení aplikácie bude vyžadovaný PIN</string>
- <string name="pincode_reenter_your_pincode">Zadajte znovu PIN aplikácie</string>
- <string name="pincode_remove_your_pincode">Zrušiť PIN pre aplikáciu</string>
- <string name="pincode_mismatch">PINy sa neshodujú</string>
- <string name="pincode_wrong">Nesprávny PIN aplikácie</string>
- <string name="pincode_removed">PIN aplikácie bol odstránený</string>
- <string name="pincode_stored">PIN aplikácie bol uložený</string>
+ <string name="pass_code_enter_pass_code">Prosím, vložte svoje heslo:</string>
+ <string name="pass_code_configure_your_pass_code">Vložte svoje heslo</string>
+ <string name="pass_code_reenter_your_pass_code">Prosím, vložte znovu svoje heslo:</string>
+ <string name="pass_code_remove_your_pass_code">Zmazať svoje heslo</string>
<string name="media_notif_ticker">Prehrávač hudby %1$s</string>
<string name="media_state_playing">%1$s (prehráva)</string>
<string name="media_state_loading">%1$s (načítava)</string>
<string name="auth_no_net_conn_title">Bez sieťového pripojenia</string>
<string name="auth_nossl_plain_ok_title">Nie je k dispozícii bezpečné pripojenie</string>
<string name="auth_connection_established">Pripojenie vytvorené</string>
- <string name="auth_testing_connection">Testovane pripojenia...</string>
+ <string name="auth_testing_connection">Testuje sa pripojenie</string>
<string name="auth_not_configured_title">Nesprávna konfigurácia servera</string>
<string name="auth_account_not_new">Účet pre tohoto používateľa a tento server už v tomto zariadení existuje</string>
<string name="auth_account_not_the_same">Zadané prihlasovacie údaje používateľa sú nesprávne</string>
<string name="auth_fail_get_user_name">Váš server nevracia správne používateľské id, kontaktujte prosím správcu systému
</string>
<string name="auth_can_not_auth_against_server">Nie je možné vykonať autentifikáciu na server</string>
+ <string name="auth_account_does_not_exist">Účet zatiaľ v zariadení neexistuje</string>
<string name="fd_keep_in_sync">Udržiavať súbor aktuálny.</string>
<string name="common_rename">Premenuj</string>
<string name="common_remove">Odober</string>
<string name="preview_image_description">Ukážka obrazu</string>
<string name="preview_image_error_unknown_format">Obrázok nemožno zobraziť</string>
<string name="error__upload__local_file_not_copied">%1$s nemožno skopírovať do lokálneho priečinka %2$s</string>
+ <string name="prefs_instant_upload_path_title">Cesta pre nahrávanie</string>
<string name="share_link_no_support_share_api">Je nám to ľúto, ale zdieľanie nie je na vašom serveri povolené. Prosím kontaktujte vášho
administrátora.</string>
+ <string name="share_link_file_no_exist">Nemožno zdieľať. Skontrolujte, či súbor existuje</string>
<string name="share_link_file_error">Pri pokuse o zdieľanie tohto súboru alebo priečinka došlo k chybe</string>
+ <string name="unshare_link_file_no_exist">Nemožno ukončiť zdieľanie. Skontrolujte, či súbor existuje</string>
<string name="unshare_link_file_error">Pri pokuse zrušiť zdieľanie tohto súboru alebo priečinka došlo k chybe</string>
+ <string name="share_link_password_title">Vložte heslo</string>
+ <string name="share_link_empty_password">Musíte vložiť heslo</string>
<string name="activity_chooser_send_file_title">Odoslať</string>
<string name="copy_link">Kopíruj odkaz</string>
<string name="clipboard_text_copied">Skopírované do schránky</string>
<string name="downloader_download_file_not_found">Súbor už na serveri nie je dostupný</string>
<string name="prefs_category_accounts">Účty</string>
<string name="prefs_add_account">Pridať účet</string>
+ <string name="auth_redirect_non_secure_connection_title">Zabezpečené pripojenie je presmerované na nezabezpečenú trasu.</string>
+ <string name="actionbar_logger">Logy</string>
+ <string name="log_send_history_button">Odoslať históriu</string>
+ <string name="log_send_no_mail_app">Nebola nájdená aplikácia pre odosielanie log protokolov. Nainštalujte si mailovú aplikáciu!</string>
+ <string name="log_send_mail_subject">%1$s Android app logs</string>
+ <string name="log_progress_dialog_text">Načítavam dáta...</string>
<string name="saml_authentication_required_text">Vyžaduje sa overenie</string>
<string name="saml_authentication_wrong_pass">Nesprávne heslo</string>
<string name="actionbar_move">Presunúť</string>
- <string name="move_choose_button_text">Vybrať</string>
+ <string name="file_list_empty_moving">Nič tu nie je. Pridajte priečinok!</string>
+ <string name="folder_picker_choose_button_text">Vybrať</string>
+ <string name="move_file_not_found">Nemožno presunúť. Skontrolujte, či súbor existuje</string>
+ <string name="move_file_invalid_into_descendent">Priečinok nemožno presunúť do vlastného podpriečinka</string>
+ <string name="move_file_invalid_overwrite">Súbor už v cieľovom priečinku existuje</string>
+ <string name="move_file_error">Pri pokuse o presun tohoto súboru alebo priečinka nastala chyba</string>
+ <string name="forbidden_permissions_move">pre presun tohoto súboru</string>
+ <string name="prefs_category_instant_uploading">Okamžité nahratie</string>
<string name="prefs_category_security">Zabezpečenie</string>
+ <string name="prefs_instant_video_upload_path_title">Cesta pre nahrávanie videí</string>
+ <string name="download_folder_failed_content">Sťahovanie %1$s priečinka nebolo dokončené</string>
+ <string name="shared_subject_header">zdieľané</string>
+ <string name="with_you_subject_header">s vami</string>
+ <string name="subject_token">%1$s vám zdieľal \"%2$s\"</string>
+ <string name="auth_refresh_button">Obnoviť pripojenie</string>
+ <string name="auth_host_address">Adresa servera</string>
+ <string name="common_error_out_memory">Nedostatok pamäte</string>
+ <string name="username">Používateľské meno</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Vse datoteke</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Nastavitve</string>
+ <string name="drawer_item_logs">Dnevnik</string>
+ <string name="drawer_close">Zapri</string>
<string name="prefs_category_general">Splošno</string>
<string name="prefs_category_more">Več</string>
<string name="prefs_accounts">Računi</string>
<string name="prefs_manage_accounts">Upravljanje z računi</string>
- <string name="prefs_pincode">Koda PIN programa</string>
- <string name="prefs_pincode_summary">Zaščitite odjemalec</string>
+ <string name="prefs_passcode">Zaklep s kodo PIN</string>
<string name="prefs_instant_upload">Takojšnje pošiljanje slik</string>
<string name="prefs_instant_upload_summary">Takojšnje pošiljanje slik, zajetih s fotoaparatom, na strežnik</string>
<string name="prefs_instant_video_upload">Takojšnje pošiljanje posnetkov</string>
<string name="sync_string_files">Datoteke</string>
<string name="setup_btn_connect">Poveži</string>
<string name="uploader_btn_upload_text">Pošlji</string>
+ <string name="uploader_btn_new_folder_text">Nova mapa</string>
<string name="uploader_top_message">Izbor mape za pošiljanje:</string>
<string name="uploader_wrn_no_account_title">Uporabniškega računa ni mogoče najti</string>
<string name="uploader_wrn_no_account_text">Na napravi ni računov %1$s. Nastaviti je treba vsaj en račun.</string>
<string name="uploader_info_uploading">Pošiljanje</string>
<string name="file_list_seconds_ago">pred nekaj sekundami</string>
<string name="file_list_empty">Tukaj še ni ničesar. Najprej je treba datoteke poslati v oblak!</string>
- <string name="file_list_loading">Poteka nalaganje ...</string>
<string name="local_file_list_empty">V tej mapi ni datotek.</string>
<string name="filedetails_select_file">Pritisnite na datoteko za prikaz dodatnih podrobnosti.</string>
<string name="filedetails_size">Velikost:</string>
<string name="filedetails_download">Prejmi</string>
<string name="filedetails_sync_file">Osveži datoteko</string>
<string name="filedetails_renamed_in_upload_msg">Datoteka je bila med nalaganjem preimenovana v %1$s</string>
+ <string name="list_layout">Postavitev seznama</string>
<string name="action_share_file">Povezava za souporabo</string>
<string name="action_unshare_file">Odstrani možnost souporabe</string>
<string name="common_yes">Da</string>
<string name="foreign_files_local_text">Krajevno: %1$s</string>
<string name="foreign_files_remote_text">Oddaljeno: %1$s</string>
<string name="upload_query_move_foreign_files">Ni dovolj prostora za kopiranje izbranih datotek v mapo %1$s. Ali jih želite premakniti?</string>
- <string name="pincode_enter_pin_code">Vnesite kodo PIN programa</string>
- <string name="pincode_configure_your_pin">Vnesite kodo PIN programa</string>
- <string name="pincode_configure_your_pin_explanation">Koda PIN bo zahtevana vsakič pred zagonom programa.</string>
- <string name="pincode_reenter_your_pincode">Ponovno vnesite kodo PIN programa</string>
- <string name="pincode_remove_your_pincode">Odstrani kodo PIN programa</string>
- <string name="pincode_mismatch">Vrednosti kod PIN programa nista enaki</string>
- <string name="pincode_wrong">Nepravilna koda PIN programa</string>
- <string name="pincode_removed">Koda PIN programa je odstranjena</string>
- <string name="pincode_stored">Koda PIN programa je shranjena</string>
+ <string name="pass_code_enter_pass_code">Vnesite kodo PIN programa</string>
+ <string name="pass_code_configure_your_pass_code">Vnesite kodo PIN programa</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Koda bo zahtevana vsakič pred zagonom programa.</string>
+ <string name="pass_code_reenter_your_pass_code">Ponovno vnesite kodo</string>
+ <string name="pass_code_remove_your_pass_code">Odstrani kodo PIN programa</string>
+ <string name="pass_code_mismatch">Vpisani kodi PIN nista enaki</string>
+ <string name="pass_code_wrong">Napačna koda PIN</string>
+ <string name="pass_code_removed">Koda PIN je odstranjena</string>
+ <string name="pass_code_stored">Koda PIN je shranjena</string>
<string name="media_notif_ticker">Predvajalnik glasbe %1$s</string>
<string name="media_state_playing">%1$s (se predvaja)</string>
<string name="media_state_loading">%1$s (se nalaga)</string>
<string name="auth_no_net_conn_title">Ni omrežne povezave</string>
<string name="auth_nossl_plain_ok_title">Varna povezava ni na voljo.</string>
<string name="auth_connection_established">Povezava je vzpostavljena</string>
- <string name="auth_testing_connection">Preizkušanje povezave ...</string>
+ <string name="auth_testing_connection">Preizkusna povezava</string>
<string name="auth_not_configured_title">Napačno oblikovane nastavitve strežnika</string>
<string name="auth_account_not_new">Na napravi račun za istega uporabnika in strežnik že obstaja</string>
<string name="auth_account_not_the_same">Vpisan uporabnik ni lastnik tega računa</string>
<string name="auth_fail_get_user_name">Strežnik ne vrača ustreznega ID uporabnika. Stopite v stik s skrbnikom sistema.
</string>
<string name="auth_can_not_auth_against_server">Ni mogoče preveriti pristnosti strežnika</string>
+ <string name="auth_account_does_not_exist">Račun na napravi še ne obstaja.</string>
<string name="fd_keep_in_sync">Datoteka naj bo posodobljena</string>
<string name="common_rename">Preimenuj</string>
<string name="common_remove">Odstrani</string>
<string name="sync_file_nothing_to_do_msg">Vsebina datoteke je že usklajena</string>
<string name="create_dir_fail_msg">Mape ni mogoče ustvariti</string>
<string name="filename_forbidden_characters">Nedovoljeni znaki: characters: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Ime datoteke vsebuje vsaj en neveljaven znak.</string>
<string name="filename_empty">Ime datoteke ne sme biti prazno</string>
<string name="wait_a_moment">Počakajte trenutek ...</string>
<string name="filedisplay_unexpected_bad_get_content">Prišlo je do nepričakovane napake. Poskusite datoteko izbrati z drugim programom.</string>
<string name="filedisplay_no_file_selected">Ni izbranih datotek</string>
<string name="activity_chooser_title">Pošlji povezavo ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Kopiranje datoteke iz zasebne shrambe</string>
<string name="oauth_check_onoff">Prijava z oAuth2</string>
<string name="oauth_login_connection">Poteka povezovanje s strežnikom oAuth2 ...</string>
<string name="ssl_validator_header">Istovetnosti strani ni mogoče preveriti</string>
<string name="placeholder_media_time">12:23:45</string>
<string name="instant_upload_on_wifi">Pošiljaj slike le preko povezav Wi-Fi</string>
<string name="instant_video_upload_on_wifi">Pošlji posnetke le preko povezave Wi-Fi</string>
- <string name="instant_upload_path">/TakojšnjePošiljanje</string>
+ <string name="instant_upload_path">/Poslano</string>
<string name="conflict_title">Posodobi podatke spora</string>
<string name="conflict_message">Oddaljena datoteka %s ni usklajena s krajevno. Z nadaljevanem bo datoteka na strežniku zamenjana s krajevno.</string>
<string name="conflict_keep_both">Ohrani obe</string>
<string name="share_link_file_error">Prišlo je do napake med poskusom omogočanja souporabe te datoteke ali mape</string>
<string name="unshare_link_file_no_exist">Ni mogoče prekiniti souporabe. Preverite, ali datoteka obstaja.</string>
<string name="unshare_link_file_error">Prišlo je do napake med poskusom odstranjevanja souporabe te datoteke ali mape</string>
+ <string name="share_link_password_title">Vpis gesla</string>
+ <string name="share_link_empty_password">Vpisati je treba geslo.</string>
<string name="activity_chooser_send_file_title">Pošlji</string>
<string name="copy_link">Kopiraj povezavo</string>
<string name="clipboard_text_copied">Kopirano v odložišče</string>
<string name="auth_redirect_non_secure_connection_title">Varna povezava je preusmerjena preko ne-varne poti.</string>
<string name="actionbar_logger">Dnevnik</string>
<string name="log_send_history_button">Pošlji zgodovino</string>
- <string name="log_mail_subject">Dnevnik programa ownCloud</string>
+ <string name="log_send_no_mail_app">Ni nameščenega poštnega programa za pošiljanje dnevnikov.</string>
+ <string name="log_send_mail_subject">%1$s dnevniki programa</string>
<string name="log_progress_dialog_text">Poteka nalaganje podatkov ...</string>
<string name="saml_authentication_required_text">Zahtevana je overitev</string>
<string name="saml_authentication_wrong_pass">Napačno geslo</string>
<string name="actionbar_move">Premakni</string>
<string name="file_list_empty_moving">Ni vsebine in datotek. Lahko ustvarite na primer mapo.</string>
- <string name="move_choose_button_text">Izbor</string>
+ <string name="folder_picker_choose_button_text">Izbor</string>
<string name="move_file_not_found">Ni mogoče premakniti datoteke. Preverite, ali obstaja.</string>
<string name="move_file_invalid_into_descendent">Ni mogoče premakniti mape v podrejeno mapo.</string>
<string name="move_file_invalid_overwrite">Datoteka v ciljni mapi že obstaja.</string>
<string name="forbidden_permissions_move">med premikanjem datoteke</string>
<string name="prefs_category_instant_uploading">Takojšnje pošiljanje v oblak</string>
<string name="prefs_category_security">Varnost</string>
+ <string name="prefs_instant_video_upload_path_title">Pot videa za pošiljanje</string>
+ <string name="download_folder_failed_content">Imenika %1$s ni mogoče prejeti v celoti</string>
+ <string name="shared_subject_header">v souporabi</string>
+ <string name="with_you_subject_header">z vami</string>
+ <string name="subject_token">Uporabnik %1$s je omogočil souporabo %2$s z vami</string>
+ <string name="auth_refresh_button">Osveži povezavo</string>
+ <string name="auth_host_address">Naslov strežnika</string>
+ <string name="common_error_out_memory">Ni dovolj pomnilnika</string>
+ <string name="username">Uporabniško ime</string>
</resources>
<string name="actionbar_send_file">Dërgo</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Përgjithshme</string>
<string name="prefs_category_more">Më tepër</string>
<string name="prefs_accounts">Llogarit</string>
- <string name="prefs_pincode">PIN-i Aplikacionit</string>
- <string name="prefs_pincode_summary">Ruani klientin tuaj</string>
<string name="prefs_help">Ndihmë</string>
<string name="prefs_imprint">Stampoj</string>
<string name="auth_username">Përdoruesi</string>
<string name="sync_string_files">Skedarët</string>
<string name="setup_btn_connect">Lidhu</string>
<string name="uploader_btn_upload_text">Ngarko</string>
+ <string name="uploader_btn_new_folder_text">Dosje e\'re</string>
<string name="uploader_wrn_no_account_title">Nuk u gjend asnjë llogari</string>
<string name="uploader_wrn_no_account_text">Nuk ka %1$s llogari në pajisjen tuaj. Ju lutemi të krijojnë një llogari të parë.</string>
<string name="uploader_wrn_no_account_setup_btn_text">Ndërto</string>
<string name="filedetails_created">Krijuar:</string>
<string name="filedetails_modified">Modifikuar:</string>
<string name="filedetails_download">Shkarko</string>
+ <string name="action_share_file">Ndaje lidhjen</string>
<string name="common_yes">Po</string>
<string name="common_no">Jo</string>
<string name="common_ok">Ok</string>
<string name="downloader_download_succeeded_content">%1$s u shkarkua me sukses</string>
<string name="downloader_download_failed_ticker">Shkarkimi dështoj</string>
<string name="common_choose_account">Zgjidhni Llogarine</string>
- <string name="pincode_enter_pin_code">Lutemi, vendosni PIN tuaj</string>
- <string name="pincode_reenter_your_pincode">Lutemi, rivendosni PIN tuaj</string>
- <string name="pincode_remove_your_pincode">Hiqni PIN in tuaj</string>
- <string name="pincode_mismatch">PIN-et nuk jane te njejte</string>
- <string name="pincode_wrong">PIN i gabuar</string>
- <string name="pincode_removed">PIN-i u hoq</string>
- <string name="pincode_stored">PIN-i u ruajt</string>
<string name="auth_no_net_conn_title">Nuk ka lidhje ne Rrjet</string>
<string name="auth_connection_established">Lidhja u vendos</string>
- <string name="auth_testing_connection">Duke testuar lidhjen</string>
<string name="auth_secure_connection">Lidhja e Sigurt vendos</string>
<string name="common_rename">Riemërto</string>
<string name="common_remove">Hiq</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Llogarit</string>
<string name="saml_authentication_wrong_pass">Fjalëkalim i gabuar</string>
- <string name="move_choose_button_text">Zgjidh</string>
+ <string name="folder_picker_choose_button_text">Zgjidh</string>
<string name="prefs_category_security">Siguria</string>
+ <string name="auth_host_address">Adresa e serverit</string>
</resources>
<resources>
<string name="actionbar_upload">Pošalji</string>
<string name="actionbar_upload_files">Fajlovi</string>
+ <string name="actionbar_mkdir">Novi direktorijum</string>
<string name="actionbar_settings">Podešavanja</string>
<string name="actionbar_see_details">Detaljnije</string>
<string name="actionbar_send_file">Pošalji</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Opšte</string>
<string name="prefs_accounts">Nalozi</string>
<string name="prefs_manage_accounts">Upravljaj nalozima</string>
<string name="prefs_help">Pomoć</string>
+ <string name="prefs_imprint">Žig</string>
<string name="auth_username">Korisničko ime</string>
<string name="auth_password">Lozinka</string>
<string name="sync_string_files">Fajlovi</string>
<string name="uploader_btn_upload_text">Pošalji</string>
+ <string name="uploader_btn_new_folder_text">Novi direktorijum</string>
<string name="uploader_wrn_no_account_title">Nalog nije nađen</string>
<string name="uploader_info_uploading">Šalje se</string>
<string name="file_list_seconds_ago">Pre par sekundi</string>
<string name="filedetails_size">Veličina:</string>
<string name="filedetails_type">Tip:</string>
<string name="filedetails_download">Preuzmi</string>
+ <string name="action_share_file">Podeli prečicu</string>
<string name="common_yes">Da</string>
<string name="common_no">Ne</string>
<string name="common_ok">Ok</string>
+ <string name="common_cancel_upload">Otkaži otpremanje</string>
<string name="common_cancel">Otkaži</string>
<string name="common_error">Greška</string>
+ <string name="common_error_unknown">Nepoznata greška</string>
+ <string name="about_title">O programu</string>
<string name="change_password">Izmeni lozinku</string>
<string name="delete_account">Ukloni nalog</string>
<string name="create_account">Novi nalog</string>
+ <string name="uploader_info_dirname">Ime fascikle</string>
<string name="uploader_upload_in_progress_ticker">Otpremanje...</string>
<string name="uploader_upload_succeeded_ticker">Uspešno otpremljeno</string>
<string name="uploader_upload_failed_ticker">Otpremanje nije uspelo</string>
<string name="ssl_validator_label_signature">Potpis:</string>
<string name="conflict_keep_both">Zadrži oboje</string>
<string name="activity_chooser_send_file_title">Pošalji</string>
+ <string name="clipboard_text_copied">Kopirano u klipbord</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Nalozi</string>
- <string name="move_choose_button_text">Izaberi</string>
+ <string name="folder_picker_choose_button_text">Izaberi</string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="about_android">%1$s Андроид апликација</string>
+ <string name="about_version">верзија %1$s</string>
+ <string name="actionbar_sync">Освежи налог</string>
<string name="actionbar_upload">Отпреми</string>
- <string name="actionbar_upload_from_apps">Садржај са других апликација</string>
- <string name="actionbar_upload_files">Датотеке</string>
+ <string name="actionbar_upload_from_apps">садржај из других апликација</string>
+ <string name="actionbar_upload_files">фајлове</string>
+ <string name="actionbar_open_with">Отвори помоћу</string>
+ <string name="actionbar_mkdir">Нова фасцикла</string>
<string name="actionbar_settings">Поставке</string>
+ <string name="actionbar_see_details">Детаљи</string>
<string name="actionbar_send_file">Пошаљи</string>
+ <string name="actionbar_sort">Разврставање</string>
+ <string name="actionbar_sort_title">Разврставање</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>новији - старији</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Сви фајлови</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Поставке</string>
+ <string name="drawer_item_logs">Записници</string>
+ <string name="drawer_close">Затвори</string>
<string name="prefs_category_general">Опште</string>
- <string name="prefs_category_more">Ð\92иÑ\88е</string>
+ <string name="prefs_category_more">Ð\9eÑ\81Ñ\82ало</string>
<string name="prefs_accounts">Налози</string>
+ <string name="prefs_manage_accounts">Управљање налозима</string>
+ <string name="prefs_passcode">Закључавање кодом</string>
+ <string name="prefs_instant_upload">Отпремање фотографија</string>
+ <string name="prefs_instant_upload_summary">тренутно отпремај фотографије сликане камером</string>
+ <string name="prefs_instant_video_upload">Отпремање видеа</string>
+ <string name="prefs_instant_video_upload_summary">тренутно отпремај видео снимљен камером</string>
+ <string name="prefs_log_title">Укључи бележење</string>
+ <string name="prefs_log_summary">користи се за бележење проблема</string>
+ <string name="prefs_log_title_history">Историјат бележења</string>
+ <string name="prefs_log_summary_history">приказује сачуване записнике</string>
+ <string name="prefs_log_delete_history_button">Обриши историјат</string>
<string name="prefs_help">Помоћ</string>
+ <string name="prefs_recommend">Препоручи пријатељу</string>
+ <string name="prefs_feedback">Ваше мишљење</string>
+ <string name="prefs_imprint">Жиг</string>
+ <string name="prefs_remember_last_share_location">Упамти локацију дељења</string>
+ <string name="prefs_remember_last_upload_location_summary">памти последњу локацију отпремања дељења</string>
+ <string name="recommend_subject">Пробајте %1$s на вашем телефону!</string>
+ <string name="recommend_text">Предлажем вам да пробате %1$s на вашем телефону!\nПреузмите овде: %2$s</string>
+ <string name="auth_check_server">Провери сервер</string>
+ <string name="auth_host_url">адреса сервера https://…</string>
<string name="auth_username">Корисничко име</string>
<string name="auth_password">Лозинка</string>
+ <string name="auth_register">Нов вам је %1$s?</string>
<string name="sync_string_files">Фајлови</string>
- <string name="setup_btn_connect">Повежи ме</string>
+ <string name="setup_btn_connect">Повежи се</string>
<string name="uploader_btn_upload_text">Отпреми</string>
+ <string name="uploader_btn_new_folder_text">Нова фасцикла</string>
+ <string name="uploader_top_message">Изаберите фасциклу отпремања:</string>
<string name="uploader_wrn_no_account_title">Нема налога</string>
+ <string name="uploader_wrn_no_account_text">Нема %1$s налога на вашем уређају. Прво подесите налог.</string>
<string name="uploader_wrn_no_account_setup_btn_text">Подеси</string>
- <string name="uploader_wrn_no_account_quit_btn_text">Ð\98заÑ\92и</string>
+ <string name="uploader_wrn_no_account_quit_btn_text">Ð\9dапÑ\83Ñ\81Ñ\82и</string>
<string name="uploader_wrn_no_content_title">Нема садржаја за отпремање</string>
- <string name="uploader_wrn_no_content_text">Садржај није примљен. Нема ништа да се отпреми.</string>
+ <string name="uploader_wrn_no_content_text">Садржај није примљен. Нема шта да се отпреми.</string>
+ <string name="uploader_error_forbidden_content">Апликацији %1$s није дозвољен приступ дељеном садржају</string>
<string name="uploader_info_uploading">Отпремање</string>
- <string name="file_list_seconds_ago">пÑ\80е неколико секунди</string>
+ <string name="file_list_seconds_ago">пÑ\80е паÑ\80 секунди</string>
<string name="file_list_empty">Овде нема ничег. Отпремите нешто!</string>
- <string name="filedetails_select_file">Додирните датотеку ради приказа додатних информација.</string>
+ <string name="local_file_list_empty">Нема фајлова у овој фасцикли.</string>
+ <string name="filedetails_select_file">Тапните на фајл ради приказа додатних информација.</string>
<string name="filedetails_size">Величина:</string>
<string name="filedetails_type">Врста:</string>
- <string name="filedetails_created">Направљено:</string>
- <string name="filedetails_modified">Измењено:</string>
+ <string name="filedetails_created">Направљен:</string>
+ <string name="filedetails_modified">Измењен:</string>
<string name="filedetails_download">Преузми</string>
- <string name="filedetails_sync_file">Освежи датотеку</string>
+ <string name="filedetails_sync_file">Освежи фајл</string>
+ <string name="filedetails_renamed_in_upload_msg">Фајл је преименован у %1$s током отпремања</string>
+ <string name="list_layout">Распоред листе</string>
+ <string name="action_share_file">Веза дељења</string>
+ <string name="action_unshare_file">Не дели везом</string>
<string name="common_yes">Да</string>
<string name="common_no">Не</string>
<string name="common_ok">У реду</string>
- <string name="common_cancel_download">Обустави преузимање</string>
- <string name="common_cancel_upload">Ð\9fÑ\80екини Ñ\81лање</string>
+ <string name="common_cancel_download">Откажи преузимање</string>
+ <string name="common_cancel_upload">Ð\9eÑ\82кажи оÑ\82пÑ\80емање</string>
<string name="common_cancel">Откажи</string>
<string name="common_save_exit">Сачувај и изађи</string>
<string name="common_error">Грешка</string>
+ <string name="common_loading">Учитавам...</string>
+ <string name="common_error_unknown">Непозната грешка</string>
<string name="about_title">О програму</string>
<string name="change_password">Измени лозинку</string>
<string name="delete_account">Обриши налог</string>
<string name="create_account">Отвори налог</string>
<string name="upload_chooser_title">Отпреми из…</string>
+ <string name="uploader_info_dirname">Назив фасцикле</string>
<string name="uploader_upload_in_progress_ticker">Отпремам…</string>
- <string name="uploader_upload_in_progress_content">%1$d%% Отпремам %2$s</string>
+ <string name="uploader_upload_in_progress_content">%1$d%% oтпремам %2$s</string>
<string name="uploader_upload_succeeded_ticker">Отпремање је успело</string>
+ <string name="uploader_upload_succeeded_content_single">%1$s је успешно отпремљен</string>
<string name="uploader_upload_failed_ticker">Отпремање није успело</string>
- <string name="uploader_upload_failed_content_single">Не могу да довршим отпремање датотеке %1$s</string>
+ <string name="uploader_upload_failed_content_single">Не могу да довршим отпремање %1$s</string>
+ <string name="uploader_upload_failed_credentials_error">Отпремање неуспешно. Поново се пријавите.</string>
<string name="downloader_download_in_progress_ticker">Преузимам…</string>
- <string name="downloader_download_in_progress_content">%1$d%% Ð\9fреузимам %2$s</string>
+ <string name="downloader_download_in_progress_content">%1$d%% преузимам %2$s</string>
<string name="downloader_download_succeeded_ticker">Преузимање успешно</string>
<string name="downloader_download_succeeded_content">%1$s је успешно преузет</string>
<string name="downloader_download_failed_ticker">Преузимање није успело</string>
- <string name="downloader_download_failed_content">Не могу да довршим преузимање датотеке %1$s</string>
+ <string name="downloader_download_failed_content">Не могу да довршим преузимање %1$s</string>
<string name="downloader_not_downloaded_yet">Још увек није преузето</string>
- <string name="common_choose_account">Изабери налог</string>
+ <string name="downloader_download_failed_credentials_error">Преузимање неуспешно. Пријавите се поново</string>
+ <string name="common_choose_account">Изаберите налог</string>
<string name="sync_fail_ticker">Синхронизовање није успело</string>
- <string name="sync_fail_content">Не могу да довршим синхронизацију датотеке %1$s</string>
- <string name="foreign_files_success">Све датотеке су померене</string>
- <string name="foreign_files_fail">Неке датотеке нису могле бити померене</string>
- <string name="pincode_enter_pin_code">Унесите PIN апликације</string>
- <string name="pincode_configure_your_pin_explanation">Са сваким покретањем апликације мораћете да унесете PIN</string>
+ <string name="sync_fail_ticker_unauthorized">Синхронизовање неуспешно. Пријавите се поново</string>
+ <string name="sync_fail_content">Не могу да довршим синхронизацију %1$s</string>
+ <string name="sync_fail_content_unauthorized">Неисправна лозинка за %1$s</string>
+ <string name="sync_conflicts_in_favourites_ticker">Постоје сукоби</string>
+ <string name="sync_conflicts_in_favourites_content">%1$d фајловa ниje синхронизованo</string>
+ <string name="sync_fail_in_favourites_ticker">Синхронизација није успела</string>
+ <string name="sync_fail_in_favourites_content">Садржај %1$d фајлова не може бити синхронизован (%2$d сукоба)</string>
+ <string name="sync_foreign_files_forgotten_ticker">Неки локални фајлови нису обрађени</string>
+ <string name="sync_foreign_files_forgotten_content">%1$d фајлова из фасцикле %2$s није се могло копирати у</string>
+ <string name="sync_foreign_files_forgotten_explanation">Од верзије 1.3.16, фајлови отпремљени са уређаја се копирају у локалну фасциклу %1$s да би се спречио губитак података када се исти фајл синхронизује са више налога.\n\nЗбог ове измене, сви фајлови отпремљени са претходним верзијама ове апликације се копирају у фасциклу %2$s. Међутим, грешка је онемогућила довршавање ове радње током синхронизације налога. Можете или оставити фајлове како јесу и уклонити линк до %3$s или преместити фајлове у фасциклу %1$s и задржати везу до %4$s.\n\nИспод су наведени локални фајлови и удаљени фајлови у %5$s са којима су повезани.</string>
+ <string name="sync_current_folder_was_removed">Фасцикла %1$s више не постоји</string>
+ <string name="foreign_files_move">Премести све</string>
+ <string name="foreign_files_success">Сви фајлови су премештени</string>
+ <string name="foreign_files_fail">Неки фајлови нису могли бити премештени</string>
+ <string name="foreign_files_local_text">Локално: %1$s</string>
+ <string name="foreign_files_remote_text">Удаљено: %1$s</string>
+ <string name="upload_query_move_foreign_files">Нема довољно простора да би се изабрани фајлови копирали у фасциклу %1$s. Желите ли да их преместите? </string>
+ <string name="pass_code_enter_pass_code">Унесите код за закључавање</string>
+ <string name="pass_code_configure_your_pass_code">Унесите код за закључавање</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Код ће бити затражен сваки пут кад се апликација покрене</string>
+ <string name="pass_code_reenter_your_pass_code">Поново унесите код</string>
+ <string name="pass_code_remove_your_pass_code">Уклоните код за закључавање</string>
+ <string name="pass_code_mismatch">Кодови се не поклапају</string>
+ <string name="pass_code_wrong">Неисправан код</string>
+ <string name="pass_code_removed">Код за закључавање уклоњен</string>
+ <string name="pass_code_stored">Код за закључавање је сачуван</string>
+ <string name="media_notif_ticker">%1$s музички плејер</string>
+ <string name="media_state_playing">%1$s (пуштам)</string>
+ <string name="media_state_loading">%1$s (учитавам)</string>
+ <string name="media_event_done">%1$s пуштање завршено</string>
+ <string name="media_err_nothing_to_play">Нема медијских фајлова</string>
+ <string name="media_err_no_account">Није наведен налог</string>
+ <string name="media_err_not_in_owncloud">Фајл није у исправном налогу</string>
+ <string name="media_err_unsupported">Неподржан кодек</string>
+ <string name="media_err_io">Медијски фајл се не може читати</string>
+ <string name="media_err_malformed">Медијски фајл није исправно кодиран</string>
+ <string name="media_err_timeout">Време истекло у покушавању пуштања</string>
+ <string name="media_err_invalid_progressive_playback">Медијски фајл се не може пустити</string>
+ <string name="media_err_unknown">Медијски фајл се не може пустити са системским плејером</string>
+ <string name="media_err_security_ex">Безбедносна грешка при покушају пуштања %1$s</string>
+ <string name="media_err_io_ex">Улазна грешка при покушају пуштања %1$s</string>
+ <string name="media_err_unexpected">Неочекивана грешка при покушају пуштања %1$s</string>
+ <string name="media_rewind_description">Уназад</string>
+ <string name="media_play_pause_description">Пуштање-пауза</string>
+ <string name="media_forward_description">Унапред</string>
+ <string name="auth_getting_authorization">Тражим ауторизацију...</string>
+ <string name="auth_trying_to_login">Покушавам пријављивање...</string>
<string name="auth_no_net_conn_title">Нема мрежне везе</string>
<string name="auth_nossl_plain_ok_title">Безбедна веза није доступна.</string>
<string name="auth_connection_established">Веза је успостављена</string>
- <string name="auth_unknown_error_title">Дошло је до непознате грешке.</string>
+ <string name="auth_testing_connection">Проверавам везу</string>
+ <string name="auth_not_configured_title">Лоше подешавање сервера</string>
+ <string name="auth_account_not_new">Налог са истим корисником и сервером већ постоји на уређају</string>
+ <string name="auth_account_not_the_same">Унесени корисник се не поклапа са корисником овог налога</string>
+ <string name="auth_unknown_error_title">Дошло је до непознате грешке!</string>
<string name="auth_unknown_host_title">Не могу да пронађем домаћина</string>
<string name="auth_incorrect_path_title">Не могу да пронађем примерак сервера</string>
<string name="auth_timeout_title">Серверу је требало предуго да се одазове</string>
<string name="auth_incorrect_address_title">Погрешно уобличена адреса</string>
- <string name="auth_ssl_general_error_title">Покретање SSL-а није успело</string>
+ <string name="auth_ssl_general_error_title">ССЛ иницијализација није успела</string>
+ <string name="auth_ssl_unverified_server_title">Не могу да проверим ССЛ идентитет сервера</string>
+ <string name="auth_bad_oc_version_title">Непозната верзија сервера</string>
<string name="auth_wrong_connection_title">Не могу да успоставим везу</string>
<string name="auth_secure_connection">Безбедна веза је успостављена</string>
- <string name="fd_keep_in_sync">Редовно ажурирај датотеку</string>
+ <string name="auth_unauthorized">Погрешно име или лозинка</string>
+ <string name="auth_oauth_error">Неуспешна ауторизација</string>
+ <string name="auth_oauth_error_access_denied">Сервер ауторизације је одбио приступ</string>
+ <string name="auth_wtf_reenter_URL">Неочекивано стање. Унесите поново адресу сервера</string>
+ <string name="auth_expired_oauth_token_toast">Ауторизација је истекла. Урадите је поново</string>
+ <string name="auth_expired_basic_auth_toast">Унесите тренутну лозинку</string>
+ <string name="auth_expired_saml_sso_token_toast">Сесија је истекла. Повежите се поново</string>
+ <string name="auth_connecting_auth_server">Повезујем се на сервер аутентификације...</string>
+ <string name="auth_unsupported_auth_method">Сервер не подржава овај начин аутентификације</string>
+ <string name="auth_unsupported_multiaccount">%1$s не подржава вишеструке налоге</string>
+ <string name="auth_fail_get_user_name">Сервер не враћа исправан ИД корисника. Контактирајте администратора
+ </string>
+ <string name="auth_can_not_auth_against_server">Не могу да аутентификујем са овим сервером</string>
+ <string name="auth_account_does_not_exist">Не постоји налог на уређају</string>
+ <string name="fd_keep_in_sync">Редовно ажурирај фајл</string>
<string name="common_rename">Преименуј</string>
<string name="common_remove">Уклони</string>
+ <string name="confirmation_remove_alert">Желите да уклоните %1$s?</string>
+ <string name="confirmation_remove_folder_alert">Желите да уклоните %1$s и њен садржај?</string>
<string name="confirmation_remove_local">Само локално</string>
+ <string name="confirmation_remove_folder_local">Само локални садржај</string>
<string name="confirmation_remove_remote">Уклони са сервера</string>
<string name="confirmation_remove_remote_and_local">Удаљено и локално</string>
- <string name="rename_dialog_title">Унесите ново име</string>
+ <string name="remove_success_msg">Уклањање успешно</string>
+ <string name="remove_fail_msg">Уклањање неуспешно</string>
+ <string name="rename_dialog_title">Унесите нов назив</string>
+ <string name="rename_local_fail_msg">Локална копија се не може преименовати. Покушајте други назив</string>
<string name="rename_server_fail_msg">Не могу да довршим преименовање</string>
- <string name="sync_file_fail_msg">Удаљена датотека се не може проверити</string>
+ <string name="sync_file_fail_msg">Удаљени фајл се не може проверити</string>
+ <string name="sync_file_nothing_to_do_msg">Садржај је већ синхронизован</string>
+ <string name="create_dir_fail_msg">Фасцикла се не може направити</string>
+ <string name="filename_forbidden_characters">Забрањени знакови: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Назив садржи бар један недозвољен карактер</string>
+ <string name="filename_empty">Назив фајла не може бити празан</string>
<string name="wait_a_moment">Сачекајте тренутак</string>
- <string name="filedisplay_no_file_selected">Нисте изабрали датотеку</string>
+ <string name="filedisplay_unexpected_bad_get_content">Неочекивани проблем. Изаберите фајл другом апликацијом</string>
+ <string name="filedisplay_no_file_selected">Нисте изабрали фајл</string>
+ <string name="activity_chooser_title">Пошаљи везу ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Копирам фајл из личног складишта</string>
+ <string name="oauth_check_onoff">Пријави се помоћу „oAuth2“</string>
+ <string name="oauth_login_connection">Повезујем се на „oAuth2“ сервер...</string>
<string name="ssl_validator_header">Не могу да проверим идентитет сајта</string>
- <string name="ssl_validator_reason_cert_not_trusted">â\80\93 СеÑ\80Ñ\82иÑ\84икаÑ\82 Ñ\81еÑ\80веÑ\80а ниÑ\98е повеÑ\80Ñ\99ив</string>
+ <string name="ssl_validator_reason_cert_not_trusted">â\80\93 СеÑ\80Ñ\82иÑ\84икаÑ\82 Ñ\81еÑ\80веÑ\80а ниÑ\98е од повеÑ\80еÑ\9aа</string>
<string name="ssl_validator_reason_cert_expired">– Сертификат сервера је истекао</string>
+ <string name="ssl_validator_reason_cert_not_yet_valid">- Датуми важења сертификата су у будућности</string>
<string name="ssl_validator_reason_hostname_not_verified">– Адреса се не поклапа са именом домаћина у сертификату</string>
- <string name="ssl_validator_question">Ð\96елиÑ\82е ли ипак да ознаÑ\87иÑ\82е Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 као повеÑ\80Ñ\99ив?</string>
+ <string name="ssl_validator_question">Ð\96елиÑ\82е ли ипак да веÑ\80Ñ\83Ñ\98еÑ\82е Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\83?</string>
<string name="ssl_validator_not_saved">Не могу да сачувам сертификат</string>
<string name="ssl_validator_btn_details_see">Подаци</string>
<string name="ssl_validator_btn_details_hide">Сакриј</string>
<string name="ssl_validator_label_subject">Издато за:</string>
- <string name="ssl_validator_label_issuer">Ð\98здао/ла:</string>
+ <string name="ssl_validator_label_issuer">Ð\98здаваÑ\87:</string>
<string name="ssl_validator_label_CN">Уобичајено име:</string>
<string name="ssl_validator_label_O">Организација:</string>
<string name="ssl_validator_label_OU">Организациона јединица:</string>
- <string name="ssl_validator_label_C">Ð\97емÑ\99а:</string>
- <string name="ssl_validator_label_ST">Ð\94Ñ\80жава:</string>
+ <string name="ssl_validator_label_C">Ð\94Ñ\80жава:</string>
+ <string name="ssl_validator_label_ST">Ð\9fокÑ\80аÑ\98ина:</string>
<string name="ssl_validator_label_L">Локација:</string>
<string name="ssl_validator_label_validity">Ваљаност:</string>
<string name="ssl_validator_label_validity_from">Од:</string>
<string name="ssl_validator_label_validity_to">За:</string>
<string name="ssl_validator_label_signature">Потпис:</string>
<string name="ssl_validator_label_signature_algorithm">Алгоритам:</string>
+ <string name="ssl_validator_null_cert">Сертификат се не може приказати.</string>
+ <string name="ssl_validator_no_info_about_error">- Нема података о грешци</string>
+ <string name="placeholder_sentence">Ово је местодржач</string>
+ <string name="placeholder_filename">чувамместо.txt</string>
+ <string name="placeholder_filetype">ПНГ слика</string>
+ <string name="placeholder_filesize">389 KB</string>
+ <string name="placeholder_timestamp">2012/05/18 12:23 ПоП</string>
+ <string name="placeholder_media_time">12:23:45</string>
<string name="instant_upload_on_wifi">Отпремај слике само путем бежичне мреже</string>
+ <string name="instant_video_upload_on_wifi">Отпремај видео само путем бежичне мреже</string>
+ <string name="instant_upload_path">/InstantUpload</string>
<string name="conflict_title">Ажурирај сукоб</string>
+ <string name="conflict_message">Удаљени фајл %s није синхронизован са локалним. Ако наставите, заменићете фајл на серверу.</string>
+ <string name="conflict_keep_both">Задржи оба</string>
+ <string name="conflict_overwrite">Пребриши</string>
+ <string name="conflict_dont_upload">Не отпремај</string>
+ <string name="preview_image_description">Преглед слике</string>
+ <string name="preview_image_error_unknown_format">Слика се не може приказати</string>
+ <string name="error__upload__local_file_not_copied">%1$s се не може копирати у локалну фасциклу %2$s</string>
+ <string name="prefs_instant_upload_path_title">Путања отпремања</string>
+ <string name="share_link_no_support_share_api">Дељење није укључено на вашем серверу. Контактирајте
+ администратора.</string>
+ <string name="share_link_file_no_exist">Не могу да делим. Проверите да ли фајл постоји</string>
+ <string name="share_link_file_error">Дошло је до грешке приликом покушаја дељења овог фајла или фасцикле</string>
+ <string name="unshare_link_file_no_exist">Не могу да прекинем дељење. Проверите да ли фајл постоји</string>
+ <string name="unshare_link_file_error">Дошло је до грешке приликом покушаја укидања дељења овог фајла или фасцикле</string>
+ <string name="share_link_password_title">Унесите лозинку</string>
+ <string name="share_link_empty_password">Морате унети лозинку</string>
<string name="activity_chooser_send_file_title">Пошаљи</string>
+ <string name="copy_link">Копирај везу</string>
+ <string name="clipboard_text_copied">Копирано у клипборд</string>
+ <string name="error_cant_bind_to_operations_service">Критична грешка: не могу да радим</string>
+ <string name="network_error_socket_exception">Дошло је до грешке при повезивању са сервером.</string>
+ <string name="network_error_socket_timeout_exception">Дошло је до грешке при чекању на сервер. Радња није могла бити урађена</string>
+ <string name="network_error_connect_timeout_exception">Дошло је до грешке при чекању на сервер. Радња није могла бити урађена</string>
+ <string name="network_host_not_available">Радња није могла бити довршена. Сервер је недоступан</string>
<string name="empty"></string>
+ <string name="forbidden_permissions">Немате дозволу %s</string>
+ <string name="forbidden_permissions_rename">да преименујете овај фајл</string>
+ <string name="forbidden_permissions_delete">да обришете овај фајл</string>
+ <string name="share_link_forbidden_permissions">да делите овај фајл</string>
+ <string name="unshare_link_forbidden_permissions">да укинете дељење овог фајла</string>
+ <string name="forbidden_permissions_create">да направите фајл</string>
+ <string name="uploader_upload_forbidden_permissions">да отпремате у ову фасциклу</string>
+ <string name="downloader_download_file_not_found">Фајл није више доступан на серверу</string>
<string name="prefs_category_accounts">Налози</string>
- <string name="move_choose_button_text">Одабери</string>
+ <string name="prefs_add_account">Додај налог</string>
+ <string name="auth_redirect_non_secure_connection_title">Безбедна веза је преусмерена на небезбедну руту</string>
+ <string name="actionbar_logger">Записници</string>
+ <string name="log_send_history_button">Историјат слања</string>
+ <string name="log_send_no_mail_app">Нема начина за слање записника. Инсталирајте апликацију е-поште!</string>
+ <string name="log_send_mail_subject">Записници %1$s Андроид апликације</string>
+ <string name="log_progress_dialog_text">Учитавам податке...</string>
+ <string name="saml_authentication_required_text">Неопходна аутентификација</string>
+ <string name="saml_authentication_wrong_pass">Погрешна лозинка</string>
+ <string name="actionbar_move">Премести</string>
+ <string name="file_list_empty_moving">Овде нема ничега. Можете додати фасциклу!</string>
+ <string name="folder_picker_choose_button_text">Одабери</string>
+ <string name="move_file_not_found">Не могу да преместим. Проверите да ли фајл постоји</string>
+ <string name="move_file_invalid_into_descendent">Није могуће преместити фасциклу у њену потфасциклу</string>
+ <string name="move_file_invalid_overwrite">Фајл већ постоји у одредишној фасцикли</string>
+ <string name="move_file_error">Дошло је до грешке при премештању фајла или фасцикле</string>
+ <string name="forbidden_permissions_move">да преместите овај фајл</string>
+ <string name="prefs_category_instant_uploading">Тренутна отпремања</string>
<string name="prefs_category_security">Безбедност</string>
+ <string name="prefs_instant_video_upload_path_title">Путања отпремања видеа</string>
+ <string name="download_folder_failed_content">Преузимање фасцикле %1$s не може бити довршено</string>
+ <string name="shared_subject_header">дељено</string>
+ <string name="with_you_subject_header">са вама</string>
+ <string name="subject_token">%1$s подели „%2$s“ са вама</string>
+ <string name="auth_refresh_button">Освежи везу</string>
+ <string name="auth_host_address">Адреса сервера</string>
+ <string name="common_error_out_memory">Нема довољно меморије</string>
+ <string name="username">Корисничко име</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_settings">Inställningar</string>
<string name="actionbar_see_details">Detaljer</string>
<string name="actionbar_send_file">Skicka</string>
+ <string name="actionbar_sort">Sortera</string>
+ <string name="actionbar_sort_title">Sortera efter</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Ö</item>
+ <item>Nyast - Äldst</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Allmänt</string>
<string name="prefs_category_more">Mer</string>
<string name="prefs_accounts">Konton</string>
<string name="prefs_manage_accounts">Hantera konton</string>
- <string name="prefs_pincode">applikation PIN</string>
- <string name="prefs_pincode_summary">Skydda applikation-klienten</string>
<string name="prefs_instant_upload">Direktuppladdning av kamerabilder</string>
<string name="prefs_instant_upload_summary">Direktuppladning av bilder tagna med kameran</string>
<string name="prefs_instant_video_upload">Direktuppladning av video</string>
<string name="prefs_recommend">Rekommendera till en vän</string>
<string name="prefs_feedback">Feedback</string>
<string name="prefs_imprint">Imprint</string>
+ <string name="prefs_remember_last_share_location">Kom ihåg plats för delat</string>
+ <string name="prefs_remember_last_upload_location_summary">Kom ihåg senaste uppladdningsplats vid dela</string>
<string name="recommend_subject">Prova %1$s på din smartphone!</string>
<string name="recommend_text">Jag skullje vilja bjuda in dig till att prova %1$s på din smartphone!\nLadda ner appen från Google Play här: %2$s</string>
<string name="auth_check_server">Kontrollera Server</string>
<string name="sync_string_files">Filer</string>
<string name="setup_btn_connect">Anslut</string>
<string name="uploader_btn_upload_text">Ladda upp</string>
+ <string name="uploader_btn_new_folder_text">Ny mapp</string>
<string name="uploader_top_message">Välj mapp för uppladdning:</string>
<string name="uploader_wrn_no_account_title">Hittade inget konto</string>
<string name="uploader_wrn_no_account_text">Det finns inga konton för %1$s på denna enhet. Var god skapa ett konto först.</string>
<string name="uploader_info_uploading">Laddar upp</string>
<string name="file_list_seconds_ago">sekunder sedan</string>
<string name="file_list_empty">Ingenting här. Ladda upp något!</string>
- <string name="file_list_loading">Laddar...</string>
<string name="local_file_list_empty">Det finns inga filer i den här mappen.</string>
<string name="filedetails_select_file">Peka på en fil för att visa mer information.</string>
<string name="filedetails_size">Storlek:</string>
<string name="sync_fail_in_favourites_content">Innehållet i %1$d filer kunde inte synkas (%2$d konflikter)</string>
<string name="sync_foreign_files_forgotten_ticker">Vissa lokala filer glömdes</string>
<string name="sync_foreign_files_forgotten_content">%1$d filer från %2$s mappar kunde inte kopieras till</string>
+ <string name="sync_foreign_files_forgotten_explanation">Från och med version 1.3.16 kommer filer uppladdade från denna enhet kopieras in till lokal %1$s mapp för att förhindra dataförlust när en enskild fil synkroniseras med flera konton.\n\nPå grund av denna ändring kommer alla filer uppladdade i tidigare versioner av denna applikation kopieras in till %2$s mapp. Dock förhindrade ett fel slutförandet av denna operation under konto-synkronisering. Du kan antingen lämna filerna som de är och ta bort länken till %3$s, eller flytta filerna in till %1$s mapp och behålla länken till %4$s.\n\nNedan listas de lokala filerna och de fjrran filerna i %5$s som de länkades till.</string>
<string name="sync_current_folder_was_removed">Mappen %1$s existerar inte längre</string>
<string name="foreign_files_move">Flytta allt</string>
<string name="foreign_files_success">Alla filer flyttades</string>
<string name="foreign_files_local_text">Lokal: %1$s</string>
<string name="foreign_files_remote_text">Fjärr: %1$s</string>
<string name="upload_query_move_foreign_files">Det finns inte tillräckligt med ledigt utrymme för att kopiera de valda filerna till %1$s mappen. Skulle du vilja flytta dem istället?</string>
- <string name="pincode_enter_pin_code">Ange din PIN</string>
- <string name="pincode_configure_your_pin">Ange applikation PIN</string>
- <string name="pincode_configure_your_pin_explanation">Din PIN måste anges varje gång du startar programmet.</string>
- <string name="pincode_reenter_your_pincode">Ange applikation PIN igen</string>
- <string name="pincode_remove_your_pincode">Radera applikation PIN</string>
- <string name="pincode_mismatch">Båda applikation PIN är inte lika</string>
- <string name="pincode_wrong">Felaktig applikationd PIN</string>
- <string name="pincode_removed">applikation PIN raderad</string>
- <string name="pincode_stored">applikation PIN sparad</string>
<string name="media_notif_ticker">%1$ musikspelare</string>
<string name="media_state_playing">%1$s (spelar)</string>
<string name="media_state_loading">%1$s (buffrar)</string>
<string name="auth_no_net_conn_title">Ingen nätverksanslutning</string>
<string name="auth_nossl_plain_ok_title">Säker anslutning inte tillgänglig.</string>
<string name="auth_connection_established">Anslutning etablerad</string>
- <string name="auth_testing_connection">Testar anslutning...</string>
<string name="auth_not_configured_title">Felaktig konfiguration</string>
<string name="auth_account_not_new">En användare med samma namn och server finns redan i denna aparat</string>
<string name="auth_account_not_the_same">Den angivna användaren matchar inte användaren för detta konto</string>
<string name="preview_image_description">Förhandsvisa bild</string>
<string name="preview_image_error_unknown_format">Denna bild kan inte visas</string>
<string name="error__upload__local_file_not_copied">%1$s kunde inte kopieras till %2$s lokal mapp</string>
+ <string name="prefs_instant_upload_path_title">Uppladdnings-sökväg</string>
<string name="share_link_no_support_share_api">Ledsen, delning är inte aktiverat på din server. Vänligen kontakta din
administratör.</string>
+ <string name="share_link_file_no_exist">Lyckades ej dela. Vänligen kontrollera om filen eisterar</string>
<string name="share_link_file_error">Ett fel uppstod vid försök att dela denna fil eller mapp</string>
+ <string name="unshare_link_file_no_exist">Lyckades ej sluta dela. Vänligen kontrollera om filen existerar</string>
<string name="unshare_link_file_error">Ett fel uppstod vid försök att sluta dela denna fil eller mapp</string>
+ <string name="share_link_password_title">Ange ett lösenord</string>
+ <string name="share_link_empty_password">Du måste ange ett lösenord</string>
<string name="activity_chooser_send_file_title">Skicka</string>
<string name="copy_link">Kopiera länk</string>
<string name="clipboard_text_copied">Kopierat till urklipp</string>
<string name="downloader_download_file_not_found">Filen är inte längre tillgänglig på servern</string>
<string name="prefs_category_accounts">Konton</string>
<string name="prefs_add_account">Lägg till konto</string>
+ <string name="auth_redirect_non_secure_connection_title">Säker anslutning är omdirigerad till en osäker väg.</string>
+ <string name="actionbar_logger">Loggar</string>
+ <string name="log_send_history_button">Skickat historik</string>
+ <string name="log_send_no_mail_app">Ingen app för att skicka loggar hittades. Installera mail appen!</string>
+ <string name="log_send_mail_subject">%1$s Android app logs</string>
<string name="log_progress_dialog_text">Laddar data...</string>
<string name="saml_authentication_required_text">Autentisering krävs</string>
<string name="saml_authentication_wrong_pass">Fel lösenord</string>
<string name="actionbar_move">Flytta</string>
<string name="file_list_empty_moving">Ingenting här. Du kan skapa en mapp!</string>
- <string name="move_choose_button_text">Välj</string>
+ <string name="folder_picker_choose_button_text">Välj</string>
<string name="move_file_not_found">Gick inte att flytta. Vänligen kontrollera att filen existerar</string>
+ <string name="move_file_invalid_into_descendent">Det är inte möjligt att flytta mappen in i underliggande struktur</string>
+ <string name="move_file_invalid_overwrite">Filen existerar redan i destinationsmappen</string>
+ <string name="move_file_error">Ett fel uppstod vid försök att flytta denna fil eller mapp</string>
<string name="forbidden_permissions_move">att flytta den här filen</string>
+ <string name="prefs_category_instant_uploading">Direktuppladning</string>
<string name="prefs_category_security">Säkerhet</string>
+ <string name="prefs_instant_video_upload_path_title">Uppladdnings-sökväg för video</string>
+ <string name="download_folder_failed_content">Neddladning utav %1$s mappen kunde inte slutföras</string>
+ <string name="auth_host_address">Serveradress</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_send_file">அனுப்பவும்</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">பொது</string>
<string name="prefs_category_more">மேலும்</string>
<string name="prefs_accounts">கணக்குகள்</string>
<string name="prefs_manage_accounts">கணக்குகளை நிர்வகி</string>
- <string name="prefs_pincode">மென்பொருள் பதிவு எண் </string>
- <string name="prefs_pincode_summary">உங்கள் வாடிக்கையாளர் பாதுகாக்கவும்</string>
<string name="prefs_instant_upload">உடனடி புகைப்பட பதிவேற்றம்</string>
<string name="prefs_instant_upload_summary">உடனடியாக கேமரா மூலம் எடுக்கப்பட்ட படங்களை பதிவேற்றம் செய்யவும்</string>
<string name="prefs_instant_video_upload">உடனடி காணொளி பதிவேற்றம்</string>
<string name="prefs_log_summary_history">இது பதிவுசெய்யப்பட்ட பதிகைகள் காட்டுகிறது</string>
<string name="sync_string_files">கோப்புகள்</string>
<string name="uploader_btn_upload_text">பதிவேற்று</string>
+ <string name="uploader_btn_new_folder_text">புதிய கோப்புறை</string>
<string name="ssl_validator_btn_details_see">விவரங்கள்</string>
<string name="activity_chooser_send_file_title">அனுப்பவும்</string>
<string name="empty"></string>
<string name="actionbar_see_details">விவரங்கள்</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">பொதுவான</string>
<string name="prefs_category_more">மேலதிக</string>
<string name="prefs_accounts">கணக்குகள்</string>
<string name="prefs_manage_accounts">கணக்குகளை நிர்வகிக்க</string>
- <string name="prefs_pincode">App PIN</string>
- <string name="prefs_pincode_summary">உங்களுடைய சேவைப் பயனரை பாதுகாக்க</string>
<string name="prefs_help">உதவி</string>
<string name="auth_username">பயனாளர் பெயர்</string>
<string name="auth_password">கடவுச்சொல்</string>
<string name="sync_fail_content">ஒத்திசைவாக்கலின் %1$s ஆனதை முடிக்கமுடியவில்லை</string>
<string name="sync_conflicts_in_favourites_ticker">முரன்பாடுகள் கண்டுப்பிடிக்கப்பட்டன</string>
<string name="sync_fail_in_favourites_content">கோப்புகள் %1$d இலுள்ள உள்ளடக்கங்களை ஒத்திசைவாக்கமுடியாது (%2$d முரன்பாடுகள்) </string>
- <string name="pincode_enter_pin_code">தயவுசெய்து உங்களுடைய App PIN ஐ உள்ளிடுக</string>
- <string name="pincode_configure_your_pin">இன் App PIN ஐ உள்ளிடுக</string>
- <string name="pincode_configure_your_pin_explanation">செயலி தொடங்கும் ஒவ்வொரு நேரமும் PIN கேட்கப்படுகின்றது.</string>
- <string name="pincode_reenter_your_pincode">தயவுசெய்து மீண்டும் App PIN ஐ உள்ளிடுக</string>
- <string name="pincode_remove_your_pincode">உங்களுடைய App PIN ஐ அகற்றுக</string>
- <string name="pincode_mismatch">இரண்டு App PIN களும் ஒன்றே அல்ல</string>
- <string name="pincode_wrong">தவறான App PIN </string>
- <string name="pincode_removed">App PIN அகற்றப்பட்டது</string>
- <string name="pincode_stored">App PIN சேமிக்கப்பட்டது</string>
<string name="auth_trying_to_login">புகுபதிகைக்கு முயற்சிக்கின்றது...</string>
<string name="auth_no_net_conn_title">வலையமைப்பு இணைப்பு இல்லை</string>
<string name="auth_nossl_plain_ok_title">பாதுகாப்பான இணைப்பு காணப்படவில்லை.</string>
<string name="auth_connection_established">இணைப்பு நிறுவப்பட்டது</string>
- <string name="auth_testing_connection">இணைப்பு சோதிக்கப்படுகிறது.....</string>
<string name="auth_not_configured_title">பிறழ்வான தகவமைப்பு</string>
<string name="auth_unknown_error_title">அறியப்படாத வழு ஏற்பட்டுள்ளது!</string>
<string name="auth_unknown_host_title">ஓம்புனரை கண்டுப்பிடிக்கமுடியவில்லை</string>
<string name="conflict_dont_upload">பதிவேற்ற வேண்டாம்</string>
<string name="empty"></string>
<string name="prefs_category_accounts">கணக்குகள்</string>
- <string name="move_choose_button_text">தெரிவுசெய்க </string>
+ <string name="folder_picker_choose_button_text">தெரிவுசெய்க </string>
+ <string name="auth_host_address">சேவையக முகவரி</string>
</resources>
<string name="actionbar_send_file">పంపించు</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_more">మరిన్ని</string>
<string name="prefs_help">సహాయం</string>
<string name="auth_username">వాడుకరి పేరు</string>
<string name="auth_password">సంకేతపదం</string>
+ <string name="uploader_btn_new_folder_text">కొత్త సంచయం</string>
<string name="file_list_seconds_ago">క్షణాల క్రితం</string>
<string name="common_yes">అవును</string>
<string name="common_no">కాదు</string>
<string name="uploader_info_dirname">సంచయం పేరు</string>
<string name="activity_chooser_send_file_title">పంపించు</string>
<string name="empty"></string>
+ <string name="auth_host_address">సేవకి చిరునామా</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<?xml version='1.0' encoding='UTF-8'?>
<resources>
+ <string name="about_android">%1$s แอพฯ แอนดรอยด์</string>
+ <string name="about_version">รุ่น %1$s</string>
+ <string name="actionbar_sync">ฟื้นฟูบัญชี</string>
<string name="actionbar_upload">อัพโหลดไฟล์</string>
- <string name="actionbar_upload_from_apps">à¹\80à¸\99ืà¹\89à¸à¸«à¸²à¸\88าà¸\81à¹\81à¸à¸\9bฯอื่นๆ</string>
+ <string name="actionbar_upload_from_apps">à¹\80à¸\99ืà¹\89à¸à¸«à¸²à¸\88าà¸\81à¹\81à¸à¸\9eฯ อื่นๆ</string>
<string name="actionbar_upload_files">ไฟล์</string>
+ <string name="actionbar_open_with">เปิดด้วย</string>
<string name="actionbar_mkdir">โฟลเดอร์ใหม่</string>
<string name="actionbar_settings">ตั้งค่า</string>
<string name="actionbar_see_details">รายละเอียด</string>
<string name="actionbar_send_file">ส่ง</string>
+ <string name="actionbar_sort">จัดเรียง</string>
+ <string name="actionbar_sort_title">เรียงตาม</string>
+ <string-array name="actionbar_sortby">
+ <item>A-Z</item>
+ <item>ใหม่ที่สุด - เก่าที่สุด</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">ไฟล์ทั้งหมด</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">ตั้งค่า</string>
+ <string name="drawer_item_logs">บันทึก</string>
+ <string name="drawer_close">ปิด</string>
<string name="prefs_category_general">ทั่วไป</string>
- <string name="prefs_category_more">มาà¸\81</string>
+ <string name="prefs_category_more">à¹\80à¸\9eิà¹\88มà¹\80à¸\95ิม</string>
<string name="prefs_accounts">บัญชี</string>
<string name="prefs_manage_accounts">บริหารจัดการบัญชี</string>
- <string name="prefs_pincode">App PIN</string>
- <string name="prefs_pincode_summary">ป้องกันโปรแกรมไคลเอนต์ ของคุณ</string>
+ <string name="prefs_passcode">ล็อค Passcodes</string>
+ <string name="prefs_instant_upload">อัพโหลดรูปภาพทันที</string>
+ <string name="prefs_instant_upload_summary">อัพโหลดรูปภาพที่ถ่ายโดยกล้องทันที</string>
+ <string name="prefs_instant_video_upload">อัพโหลดวิดีโอทันที</string>
+ <string name="prefs_instant_video_upload_summary">อัพโหลดวิดีโอที่บันทึกโดยกล้องทันที</string>
+ <string name="prefs_log_title">เปิดใช้งานการบันทึกข้อมูล</string>
+ <string name="prefs_log_summary">นี้จะใช้เพื่อบันทึกปัญหาที่เกิดขึ้น</string>
+ <string name="prefs_log_title_history">ประวัติการบันทึกข้อมูล</string>
+ <string name="prefs_log_summary_history">สิ่งนี้จะแสดงข้อมูลที่ถูกบันทึกไว้</string>
+ <string name="prefs_log_delete_history_button">ลบประวัติ</string>
<string name="prefs_help">ช่วยเหลือ</string>
+ <string name="prefs_recommend">แนะนำให้เพื่อน</string>
+ <string name="prefs_feedback">ข้อเสนอแนะ</string>
+ <string name="prefs_imprint">ประทับ</string>
+ <string name="prefs_remember_last_share_location">จดจำตำแหน่งที่ใช้ร่วมกัน</string>
+ <string name="prefs_remember_last_upload_location_summary">จดจำตำแหน่งล่าสุดที่ใช้ร่วมกัน</string>
+ <string name="recommend_subject">ลองใช้ %1$s บนสมาร์ทโฟนของคุณ!</string>
+ <string name="recommend_text">ฉันอยากจะขอเชิญให้คุณใช้ %1$s บนสมาร์ทโฟนของคุณ!\nดาวน์โหลดที่นี่: %2$s</string>
+ <string name="auth_check_server">ตรวจสอบเซิร์ฟเวอร์</string>
+ <string name="auth_host_url">ที่อยู่ของเซิร์ฟเวอร์ https://…</string>
<string name="auth_username">ชื่อผู้ใช้</string>
<string name="auth_password">รหัสผ่าน</string>
+ <string name="auth_register">ใหม่จนถึง %1$s?</string>
<string name="sync_string_files">ไฟล์</string>
<string name="setup_btn_connect">เชื่อมต่อ</string>
<string name="uploader_btn_upload_text">อัพโหลด</string>
+ <string name="uploader_btn_new_folder_text">โฟลเดอร์ใหม่</string>
+ <string name="uploader_top_message">เลือกโฟลเดอร์ที่ต้องการอัพโหลด:</string>
<string name="uploader_wrn_no_account_title">ไม่พบบัญชีที่ต้องการ</string>
<string name="uploader_wrn_no_account_text">ไม่มีบัญชี %1$s บนอุปกรณ์ของคุณ กรุณาตั้งค่าบัญชีของคุณก่อน</string>
<string name="uploader_wrn_no_account_setup_btn_text">ตั้งค่า</string>
<string name="uploader_wrn_no_account_quit_btn_text">ออก</string>
- <string name="uploader_wrn_no_content_title">ยัà¸\87à¹\84มà¹\88มีà¹\80à¸\99ืà¹\89à¸à¸«à¸²à¹\83หà¹\89à¸\95à¹\89à¸à¸\87à¸à¸±à¸\9eโหลด</string>
- <string name="uploader_wrn_no_content_text">ยัà¸\87à¹\84มà¹\88à¹\84à¸\94à¹\89รัà¸\9aà¹\80à¸\99ืà¹\89à¸à¸«à¸² à¹\84มà¹\88มีà¸à¸°à¹\84รà¹\83หà¹\89à¸\95à¹\89à¸à¸\87à¸à¸±à¸\9eà¹\82หลà¸\94</string>
- <string name="uploader_error_forbidden_content">%1$s ไม่อนุญาตให้เข้าถึงเนื้อหาที่ถูกแชร์ไว้</string>
+ <string name="uploader_wrn_no_content_title">ยัà¸\87à¹\84มà¹\88มีà¹\80à¸\99ืà¹\89à¸à¸«à¸²à¸\97ีà¹\88à¸\96ูà¸\81à¸à¸±à¸\9bโหลด</string>
+ <string name="uploader_wrn_no_content_text">ยัà¸\87à¹\84มà¹\88à¹\84à¸\94à¹\89รัà¸\9aà¹\80à¸\99ืà¹\89à¸à¸«à¸² ยัà¸\87à¹\84มà¹\88มีà¸\81ารà¸à¸±à¸\9eà¹\82หลà¸\94à¹\83à¸\94à¹\86</string>
+ <string name="uploader_error_forbidden_content">%1$s à¹\84มà¹\88à¹\84à¸\94à¹\89รัà¸\9aà¸à¸\99ุà¸\8dาà¸\95à¹\83หà¹\89à¹\80à¸\82à¹\89าà¸\96ึà¸\87à¹\80à¸\99ืà¹\89à¸à¸«à¸²à¸\97ีà¹\88à¸\96ูà¸\81à¹\81à¸\8aรà¹\8cà¹\84วà¹\89</string>
<string name="uploader_info_uploading">กำลังอัพโหลด</string>
<string name="file_list_seconds_ago">วินาที ก่อนหน้านี้</string>
- <string name="file_list_empty">ยังไม่มีไฟล์ใดๆอยู่ที่นี่ กรุณาอัพโหลดไฟล์!</string>
+ <string name="file_list_empty">ยังไม่มีไฟล์ใดๆเลย ลองอัปโหลดดูสิ!</string>
+ <string name="file_list_loading">กำลังโหลด...</string>
+ <string name="local_file_list_empty">ยังไม่มีไฟล์ในโฟลเดอร์นี้</string>
<string name="filedetails_select_file">แตะที่ไฟล์ เพื่อแสดงข้อมูลเพิ่มเติม</string>
<string name="filedetails_size">ขนาด:</string>
<string name="filedetails_type">ชนิด:</string>
<string name="filedetails_created">สร้างเมื่อ:</string>
<string name="filedetails_modified">แก้ไขเมื่อ:</string>
<string name="filedetails_download">ดาวน์โหลด</string>
+ <string name="filedetails_sync_file">ฟื้นฟูไฟล์</string>
<string name="filedetails_renamed_in_upload_msg">ไฟล์ได้ถูกเปลี่ยนชื่อเป็น %1$s ในระหว่างการอัพโหลด</string>
+ <string name="list_layout">เค้าโครงรายการ</string>
+ <string name="action_share_file">แชร์ลิงค์</string>
+ <string name="action_unshare_file">ยกเลิกการแชร์ลิงค์</string>
<string name="common_yes">ตกลง</string>
<string name="common_no">ไม่ตกลง</string>
<string name="common_ok">ตกลง</string>
<string name="common_cancel">ยกเลิก</string>
<string name="common_save_exit">บันทึก & ออก</string>
<string name="common_error">ข้อผิดพลาด</string>
+ <string name="common_loading">กำลังโหลด ...</string>
<string name="common_error_unknown">ข้อผิดพลาดที่ไม่ทราบสาเหตุ</string>
<string name="about_title">เกี่ยวกับเรา</string>
<string name="change_password">เปลี่ยนรหัสผ่าน</string>
<string name="delete_account">ลบบัญชี</string>
<string name="create_account">สร้างบัญชีใหม่</string>
- <string name="upload_chooser_title">อัพโหลดไฟล์จาก...</string>
+ <string name="upload_chooser_title">อัพโหลดไฟล์จาก ...</string>
<string name="uploader_info_dirname">ชื่อโฟลเดอร์</string>
- <string name="uploader_upload_in_progress_ticker">กำลังอัพโหลด...</string>
+ <string name="uploader_upload_in_progress_ticker">กำลังอัพโหลด ...</string>
<string name="uploader_upload_in_progress_content">%1$d%% กำลังอัพโหลด %2$s</string>
<string name="uploader_upload_succeeded_ticker">อัพโหลดเสร็จสิ้น</string>
<string name="uploader_upload_succeeded_content_single">%1$s ได้ถูกอัพโหลดเรียบร้อยแล้ว</string>
<string name="uploader_upload_failed_ticker">อัพโหลดล้มเหลว</string>
- <string name="uploader_upload_failed_content_single">การอัพโหลด %1$s ไม่สามารถดำเนินการให้เสร็จสมบูรณ์ได้</string>
+ <string name="uploader_upload_failed_content_single">ไม่สามารถดำเนินการอัพโหลด %1$s ให้เสร็จสมบูรณ์ได้</string>
+ <string name="uploader_upload_failed_credentials_error">อัพโหลดล้มเหลวคุณจะต้องเข้าสู่ระบบใหม่</string>
<string name="downloader_download_in_progress_ticker">กำลังดาวน์โหลด ...</string>
<string name="downloader_download_in_progress_content">%1$d%% กำลังดาวน์โหลด %2$s</string>
<string name="downloader_download_succeeded_ticker">ดาวน์โหลดเสร็จสิ้น</string>
<string name="downloader_download_succeeded_content">%1$s ถูกดาวน์โหลดเรียบร้อยแล้ว</string>
<string name="downloader_download_failed_ticker">ดาวน์โหลดล้มเหลว</string>
<string name="downloader_download_failed_content">การดาวน์โหลด %1$s ไม่สามารถดำเนินการให้เสร็จสมบูรณ์ได้</string>
+ <string name="downloader_not_downloaded_yet">ยังดาวน์โหลดไม่ได้</string>
+ <string name="downloader_download_failed_credentials_error">การดาวน์โหลดล้มเหลวคุณจะต้องเข้าสู่ระบบใหม่</string>
<string name="common_choose_account">เลือกบัญชี</string>
<string name="sync_fail_ticker">การเชื่อมผสานข้อมูลล้มเหลว</string>
+ <string name="sync_fail_ticker_unauthorized">การเชื่อมผสานข้อมูลล้มเหลว คุณจะต้องเข้าสู่ระบบใหม่</string>
<string name="sync_fail_content">การเชื่อมผสานข้อมูลของ %1$s ไม่สามารถดำเนินการให้เสร็จสมบูรณ์ได้</string>
+ <string name="sync_fail_content_unauthorized">รหัสผ่านไม่ถูกต้องสำหรับ %1$s</string>
<string name="sync_conflicts_in_favourites_ticker">ตรวจพบความขัดแย้ง</string>
- <string name="sync_conflicts_in_favourites_content">%1$d à¹\84à¸\9fลà¹\8c kept-in-sync à¹\84มà¹\88สามารà¸\96à¸\9cสาà¸\99à¹\80à¸\8aืà¹\88à¸à¸¡ข้อมูลได้</string>
+ <string name="sync_conflicts_in_favourites_content">%1$d à¹\84à¸\9fลà¹\8c kept-in-sync à¹\84มà¹\88สามารà¸\96à¹\80à¸\8aืà¹\88à¸à¸¡à¸\9cสาà¸\99ข้อมูลได้</string>
<string name="sync_fail_in_favourites_ticker">ไฟล์ Kept-in-sync ล้มเหลว</string>
<string name="sync_fail_in_favourites_content">เนื้อหาของไฟล์ %1$d ไม่สามารถผสานเชื่อมข้อมูลได้ (ความขัดแย้ง %2$d รายการ)</string>
- <string name="sync_foreign_files_forgotten_ticker">มีบางแฟ้มข้อมูลในเครื่องถูกลืม</string>
+ <string name="sync_foreign_files_forgotten_ticker">มีแฟ้มข้อมูลต้นทางบางแฟ้มถูกลืม</string>
+ <string name="sync_foreign_files_forgotten_content">ไม่สามารถคัดลอกไฟล์ %1$d ไปยังโฟลเดอร์ %2$s</string>
+ <string name="sync_foreign_files_forgotten_explanation">ขณะที่รุ่น 1.3.16 ไฟล์ที่อัปโหลดจากเครื่องของคุณจะถูกคัดลอกไปสำรองไว้ที่ต้นทาง %1$s เพื่อป้องกันการสูญเสียข้อมูลเมื่อไฟล์เดียวถูกซิงค์กับบัญชีหลายบัญชี \n\n การเปลี่ยนแปลงนี้ไฟล์ทั้งหมดที่อัปโหลดในรุ่นก่อนหน้า ของ app นี้ถูกคัดลอกลงในโฟลเดอร์ %2$s แต่ก็อาจมีข้อผิดพลาดในการดำเนินการนี้ช่วงระหว่างการประสานบัญชี คุณอาจจะสูญเสียข้อมูล เช่นเดียวกับการลบ หรือย้ายไฟล์และเชื่อมโยงไปยัง %3$s ส่วนโฟลเดอร์ %1$s จะถูกเชื่อมโยงไปยัง %4$s \n\n รายชื่อด้านล่าง เป็นแฟ้มต้นทาง และแฟ้มปลายทาง ใน %5$s มันจะถูกนำมาเชื่อมโยงกัน</string>
+ <string name="sync_current_folder_was_removed">โฟลเดอร์ %1$s หายไปแล้ว</string>
<string name="foreign_files_move">ย้ายทั้งหมด</string>
<string name="foreign_files_success">ทุกแฟ้มข้อมูลถูกย้ายเรียบร้อยแล้ว</string>
<string name="foreign_files_fail">มีบางแฟ้มข้อมูลไม่สามารถย้ายได้</string>
<string name="foreign_files_local_text">ต้นทาง: %1$s</string>
<string name="foreign_files_remote_text">ปลายทาง: %1$s</string>
- <string name="pincode_enter_pin_code">กรุณาใส่ PIN แอปของคุณ</string>
- <string name="pincode_configure_your_pin">กรอกรหัส PIN ของ App</string>
- <string name="pincode_configure_your_pin_explanation">หมายเลข PIN ดังกล่าวจะถูกร้องขอทุกครั้งที่เริ่มใช้งานแอปฯ</string>
- <string name="pincode_reenter_your_pincode">กรุณากรอกรหัส PIN ของแอป App ใหม่อีกครั้ง</string>
- <string name="pincode_remove_your_pincode">ลบรหัส PIN แอป ของ App ของคุณ</string>
- <string name="pincode_mismatch">รหัส App API ไม่ตรงกัน</string>
- <string name="pincode_wrong">รหัส PIN App ไม่ถูกต้อง</string>
- <string name="pincode_removed">รหัส PIN แอปสำหรับ ถูกลบออกแล้ว</string>
- <string name="pincode_stored">จัดเก็บรหัส PIN แอป ของ แล้ว</string>
+ <string name="upload_query_move_foreign_files">พื้นที่ใน %1$s ไม่เพียงพอต่อการย้ายไฟล์ คุณต้องการที่จะย้ายไปที่อื่นแทน?</string>
+ <string name="pass_code_enter_pass_code">กรุณาใส่ Passcodes ของคุณ</string>
+ <string name="pass_code_configure_your_pass_code">ใส่ Passcodes ของคุณ</string>
+ <string name="pass_code_configure_your_pass_code_explanation">จะมีการร้องขอ Passcodes ทุกครั้งเมื่อเริ่มต้นใช้แอพฯ</string>
+ <string name="pass_code_reenter_your_pass_code">กรุณาป้อน Passcodes ของคุณอีกครั้ง</string>
+ <string name="pass_code_remove_your_pass_code">ลบ Passcodes ของคุณ</string>
+ <string name="pass_code_mismatch">Passcodes ของคุณไม่ตรงกัน</string>
+ <string name="pass_code_wrong">Passcode ไม่ถูกต้อง</string>
+ <string name="pass_code_removed">ลบ Passcode</string>
+ <string name="pass_code_stored">Passcode ที่เก็บไว้</string>
+ <string name="media_notif_ticker">เล่นเพลง %1$s</string>
+ <string name="media_state_playing">%1$s (กำลังเล่น)</string>
+ <string name="media_state_loading">%1$s (กำลังโหลด)</string>
+ <string name="media_event_done">%1$s เล่นเสร็จแล้ว</string>
+ <string name="media_err_nothing_to_play">ไม่พบไฟล์สื่อ</string>
+ <string name="media_err_no_account">ไม่มีบัญชีที่ระบุ</string>
+ <string name="media_err_not_in_owncloud">ไฟล์ไม่ได้อยู่ในบัญชีที่ถูกต้อง</string>
+ <string name="media_err_unsupported">สื่อไม่สนับสนุนตัวแปลงสัญญาณ</string>
+ <string name="media_err_io">ไม่สามารถอ่านไฟล์สื่อ</string>
+ <string name="media_err_malformed">เข้ารหัสไฟล์สื่อไม่ถูกต้อง</string>
+ <string name="media_err_timeout">หมดเวลาในขณะที่พยายามจะเล่น</string>
+ <string name="media_err_invalid_progressive_playback">ไฟล์สื่อไม่สามารถสตรีม</string>
+ <string name="media_err_unknown">เล่นไฟล์สื่อกับเครื่องเล่นสื่อไม่ได้</string>
+ <string name="media_err_security_ex">เกิดข้อผิดพลาดเรื่องความปลอดภัยขณะพยายามที่จะเล่น %1$s</string>
+ <string name="media_err_io_ex">ป้อนข้อมูลผิดพลาดขณะพยายามที่จะเล่น %1$s</string>
+ <string name="media_err_unexpected">เกิดข้อผิดพลาดขณะพยายามที่จะเล่น %1$s</string>
+ <string name="media_rewind_description">ปุ่มย้อนกลับ</string>
+ <string name="media_play_pause_description">เล่นหรือกดปุ่มหยุดชั่วคราว</string>
+ <string name="media_forward_description">ปุ่มเลื่อนไปข้างหน้า</string>
+ <string name="auth_getting_authorization">ได้รับการอนุมัติ ...</string>
<string name="auth_trying_to_login">กำลังเข้าสู่ระบบ...</string>
<string name="auth_no_net_conn_title">ไม่มีการเชื่อมต่อเครือข่ายใดๆ</string>
- <string name="auth_nossl_plain_ok_title">à¸\81ารà¹\80à¸\8aืà¹\88à¸à¸¡à¸\95à¹\88à¸à¹\81à¸\9aà¸\9aรัà¸\81ษาà¸\84วามà¸\9bลà¸à¸\94ภัยà¹\84มà¹\88สามารà¸\96à¹\83à¸\8aà¹\89à¸\87าà¸\99à¹\84à¸\94à¹\89</string>
+ <string name="auth_nossl_plain_ok_title">การเชื่อมต่อแบบปลอดภัยไม่สามารถใช้งานได้</string>
<string name="auth_connection_established">ติดตั้งการเชื่อมต่อแล้ว</string>
- <string name="auth_testing_connection">à¸\81ำลัà¸\87à¸\97à¸\94สà¸à¸\9aà¸\81ารà¹\80à¸\8aืà¹\88à¸à¸¡à¸\95à¹\88à¸...</string>
+ <string name="auth_testing_connection">à¸\81ารà¸\97à¸\94สà¸à¸\9aà¸\81ารà¹\80à¸\8aืà¹\88à¸à¸¡à¸\95à¹\88à¸</string>
<string name="auth_not_configured_title">การกำหนดค่า Malformed เซิร์ฟเวอร์</string>
- <string name="auth_unknown_error_title">เกิดข้อผิดพลาดที่ไม่ทราบสาเหตุ!</string>
+ <string name="auth_account_not_new">บัญชีผู้ใช้และเซิร์ฟเวอร์เดียวกันมีอยู่แล้วในเครื่อง</string>
+ <string name="auth_account_not_the_same">ป้อนผู้ใช้ไม่ตรงกับบัญชีของผู้ใช้นี้</string>
+ <string name="auth_unknown_error_title">เกิดข้อผิดพลาดโดยไม่ทราบสาเหตุ!</string>
<string name="auth_unknown_host_title">ไม่พบโฮสต์ที่ต้องการ</string>
<string name="auth_incorrect_path_title">ไม่พบค่าตัวอย่างเซิร์ฟเวอร์</string>
<string name="auth_timeout_title">เซิร์ฟเวอร์ดังกล่าวใช้เวลาตอบสนองนานเกินไป</string>
<string name="auth_incorrect_address_title">Malformed URL</string>
<string name="auth_ssl_general_error_title">การเตรียมใช้งาน SSL ล้มเหลว</string>
- <string name="auth_bad_oc_version_title">รุ่นของเซิร์ฟเวอร์เซิร์ฟเวอร์ ไม่เป็นที่รู้จัก</string>
+ <string name="auth_ssl_unverified_server_title">ไม่สามารถตรวจสอบตัวตนของเซิร์ฟเวอร์ SSL</string>
+ <string name="auth_bad_oc_version_title">ไม่รู้จักรุ่นของเซิร์ฟเวอร์</string>
<string name="auth_wrong_connection_title">ไม่สามารถเชื่อมต่อได้</string>
- <string name="auth_secure_connection">ดำเนินการติดตั้งการเชื่อมต่อแบบปลอดภัยเรียบร้อย</string>
+ <string name="auth_secure_connection">เชื่อมต่อแบบปลอดภัยเสร็จสมบูรณ์</string>
+ <string name="auth_unauthorized">ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง</string>
+ <string name="auth_oauth_error">ตรวจสอบสิทธิ์ไม่สำเร็จ</string>
+ <string name="auth_oauth_error_access_denied">การเข้าถึงถูกปฏิเสธโดยเซิร์ฟเวอร์ตรวจสอบสิทธิ์</string>
+ <string name="auth_wtf_reenter_URL">เกิดข้อผิดพลาด โปรดป้อน URL เซิร์ฟเวอร์อีกครั้ง</string>
+ <string name="auth_expired_oauth_token_toast">สิทธิ์การเข้าถึงของคุณหมดอายุแล้ว กรุณาขอสิทธิ์ใหม่</string>
+ <string name="auth_expired_basic_auth_toast">กรุณาใส่รหัสผ่านปัจจุบัน</string>
+ <string name="auth_expired_saml_sso_token_toast">เซสชันของคุณหมดอายุ โปรดเชื่อมต่ออีกครั้ง</string>
+ <string name="auth_connecting_auth_server">กำลังเชื่อมต่อกับเซิร์ฟเวอร์เพื่อยืนยันตัวตน</string>
+ <string name="auth_unsupported_auth_method">เซิร์ฟเวอร์ไม่สนับสนุนการยืนยันตัวตนนี้</string>
+ <string name="auth_unsupported_multiaccount">%1$s ไม่สนับสนุนให้มีหลายบัญชี</string>
+ <string name="auth_fail_get_user_name">เซิร์ฟเวอร์ของคุณไม่ได้ส่งคืนรหัสผู้ใช้ที่ถูกต้อง กรุณาติดต่อผู้ดูแลระบบ!</string>
+ <string name="auth_can_not_auth_against_server">ไม่สามารถยืนยันตัวตนกับเซิร์ฟเวอร์นี้</string>
+ <string name="auth_account_does_not_exist">ยังไม่มีบัญชีในอุปกรณ์นี้</string>
<string name="fd_keep_in_sync">ปรับปรุงไฟล์ให้ทันสมัยอยู่เสมอ</string>
<string name="common_rename">เปลี่ยนชื่อ</string>
<string name="common_remove">ลบออก</string>
- <string name="confirmation_remove_local">เฉพาะเซิร์ฟเวอร์ภายในเท่านั้น</string>
- <string name="confirmation_remove_folder_local">เนื้อหาที่อยู่ในเครื่องเท่านั้น</string>
+ <string name="confirmation_remove_alert">คุณต้องการที่จะลบ %1$s?</string>
+ <string name="confirmation_remove_folder_alert">คุณต้องการที่จะลบ %1$s และเนื้อหาของมัน?</string>
+ <string name="confirmation_remove_local">เฉพาะต้นทางเท่านั้น</string>
+ <string name="confirmation_remove_folder_local">เนื้อหาต้นทางเท่านั้น</string>
<string name="confirmation_remove_remote">ลบออกจากเซิร์ฟเวอร์</string>
- <string name="confirmation_remove_remote_and_local">à¸\97ัà¹\89à¸\87à¹\80à¸\8bิรà¹\8cà¸\9fà¹\80วà¸à¸£à¹\8cระยะà¹\84à¸\81ลà¹\81ละà¹\80à¸\8bิรà¹\8cà¸\9fà¹\80วà¸à¸£à¹\8cภายà¹\83à¸\99</string>
+ <string name="confirmation_remove_remote_and_local">à¸\95à¹\89à¸\99à¸\97าà¸\87à¹\81ละà¸\9bลายà¸\97าà¸\87</string>
<string name="remove_success_msg">ลบเรียบร้อยแล้ว</string>
- <string name="remove_fail_msg">à¸\81ารลà¸\9aà¸à¸à¸\81à¹\84มà¹\88สามารà¸\96à¸\94ำà¹\80à¸\99ิà¸\99à¸\81ารà¹\84à¸\94à¹\89à¸à¸¢à¹\88าà¸\87à¹\80สรà¹\87à¸\88สมà¸\9aูรà¸\93à¹\8c</string>
+ <string name="remove_fail_msg">à¹\84มà¹\88สามารà¸\96ลà¸\9aà¹\84à¸\94à¹\89</string>
<string name="rename_dialog_title">กรอกชื่อใหม่</string>
- <string name="rename_local_fail_msg">à¹\84à¸\9fลà¹\8cà¸\84ัà¸\94ลà¸à¸\81ภายà¹\83à¸\99ไม่สามารถเปลี่ยนชื่อได้, กรุณาเปลี่ยนเป็นชื่อใหม่</string>
+ <string name="rename_local_fail_msg">à¹\84à¸\9fลà¹\8cà¸\95à¹\89à¸\99à¸\97าà¸\87à¸\97ีà¹\88à¸\84ัà¸\94ลà¸à¸\81ไม่สามารถเปลี่ยนชื่อได้, กรุณาเปลี่ยนเป็นชื่อใหม่</string>
<string name="rename_server_fail_msg">ไม่สามารถเปลี่ยนชื่อได้</string>
<string name="sync_file_fail_msg">ไม่สามารถตรวจสอบไฟล์ระยะไกลได้</string>
- <string name="sync_file_nothing_to_do_msg">เนื้อหาของไฟล์ถูกผสานข้อมูลอยู่แล้ว</string>
+ <string name="sync_file_nothing_to_do_msg">เนื้อหาของไฟล์มีข้อมูลอยู่แล้ว</string>
+ <string name="create_dir_fail_msg">ไม่สามารถสร้างโฟลเดอร์</string>
+ <string name="filename_forbidden_characters">ห้ามใช้ตัวอักษรดังนี้: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">มีชื่อแฟ้มอย่างน้อยหนึ่งตัวอักษรที่ไม่ถูกต้อง</string>
+ <string name="filename_empty">ต้องใส่ชื่อไฟล์</string>
<string name="wait_a_moment">กรุณารอสักครู่</string>
- <string name="filedisplay_unexpected_bad_get_content">à¹\80à¸\81ิà¸\94à¸\9bัà¸\8dหาà¸\97ีà¹\88à¹\84มà¹\88à¸\84าà¸\94à¸\84ิà¸\94 ; à¸\81รุà¸\93าลà¸à¸\87à¹\83à¸\8aà¹\89à¸\87าà¸\99à¹\81à¸à¸\9bฯà¸à¸·à¹\88à¸\99à¹\86 à¹\80à¸\9eืà¹\88à¸à¹\80ลืà¸à¸\81à¹\84à¸\9fลà¹\8c</string>
+ <string name="filedisplay_unexpected_bad_get_content">มีà¸\9bัà¸\8dหาà¹\80à¸\81ิà¸\94à¸\82ึà¹\89à¸\99 à¸\81รุà¸\93าà¹\80ลืà¸à¸\81à¹\84à¸\9fลà¹\8cà¸\87าà¸\99à¹\81à¸à¸\9eฯà¸à¸·à¹\88à¸\99à¹\86</string>
<string name="filedisplay_no_file_selected">ไม่มีไฟล์ที่ถูกเลือก</string>
- <string name="ssl_validator_header">ไม่สามารถยืนยันความถูกต้องของตัวตนของเว็บไซต์ได้</string>
+ <string name="activity_chooser_title">ส่งลิงค์ไปยัง ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">คัดลอกไฟล์จากพื้นที่จัดเก็บส่วนตัว</string>
+ <string name="oauth_check_onoff">เข้าสู่ระบบด้วย oAuth2</string>
+ <string name="oauth_login_connection">เชื่อมต่อกับเซิร์ฟเวอร์ oAuth2 ...</string>
+ <string name="ssl_validator_header">ไม่สามารถยืนยันตัวตนของเว็บไซต์ได้</string>
<string name="ssl_validator_reason_cert_not_trusted">- ใบรับรองความปลอดภัยของเซิร์ฟเวอร์ไม่น่าเชื่อถือ</string>
<string name="ssl_validator_reason_cert_expired">- ใบรับรองความปลอดภัยของเซิร์ฟเวอร์หมดอายุแล้ว</string>
<string name="ssl_validator_reason_cert_not_yet_valid">- ใบรับรองความปลอดภัยของเซิร์ฟเวอร์ยังมีอายุน้อยอยู่</string>
<string name="ssl_validator_label_validity_to">ถึง:</string>
<string name="ssl_validator_label_signature">ลายเซ็นต์:</string>
<string name="ssl_validator_label_signature_algorithm">อัลกอริทึ่ม:</string>
- <string name="placeholder_sentence">นี่เป็นตัวยึด</string>
+ <string name="ssl_validator_null_cert">ไม่สามารถแสดงใบรับรอง</string>
+ <string name="ssl_validator_no_info_about_error">- ไม่มีข้อมูลเกี่ยวกับข้อผิดพลาด</string>
+ <string name="placeholder_sentence">นี่คือ placeholder</string>
+ <string name="placeholder_filename">placeholder.txt</string>
+ <string name="placeholder_filetype">รูปภาพ PNG</string>
+ <string name="placeholder_filesize">389 กิโลไบต์</string>
+ <string name="placeholder_timestamp">2012/05/18 12:23 PM</string>
+ <string name="placeholder_media_time">12:23:45</string>
<string name="instant_upload_on_wifi">อัพโหลดรูปภาพผ่านทาง WiFi เท่านั้น</string>
+ <string name="instant_video_upload_on_wifi">อัพโหลดวีดีโอผ่านทาง WiFi เท่านั้น</string>
<string name="instant_upload_path">/อัพโหลดทันที</string>
- <string name="conflict_title">à¸\9bรัà¸\9aà¸\9bรุà¸\87à¸\9bัà¸\8dหาà¸\84วามà¸\82ัà¸\94à¹\81ยà¹\89à¸\87</string>
- <string name="conflict_message">à¹\84à¸\9fลà¹\8cระยะà¹\84à¸\81ล %s ยัà¸\87à¹\84มà¹\88à¹\84à¸\94à¹\89à¸\96ูà¸\81à¸\9cสาà¸\99à¸\82à¹\89à¸à¸¡à¸¹à¸¥à¸\81ัà¸\9aà¹\84à¸\9fลà¹\8cà¹\83à¸\99à¹\80à¸\84รืà¹\88à¸à¸\87 à¸\81ารà¸\94ำà¹\80à¸\99ิà¸\99à¸\81ารà¸\95à¹\88à¸à¹\84à¸\9bà¸\88ะà¹\80à¸\9bà¹\87à¸\99à¸\81ารà¹\81à¸\97à¸\99à¸\97ีà¹\88à¹\80à¸\99ืà¹\89à¸à¸«à¸²à¸\82à¸à¸\87à¹\84à¸\9fลà¹\8cà¸\97ีà¹\88อยู่บนเซิร์ฟเวอร์</string>
+ <string name="conflict_title">à¸\9bรัà¸\9aà¸\9bรุà¸\87à¸\82à¹\89à¸à¸\9cิà¸\94à¸\9eลาà¸\94</string>
+ <string name="conflict_message">à¹\84à¸\9fลà¹\8cระยะà¹\84à¸\81ล %s ยัà¸\87à¹\84มà¹\88à¹\84à¸\94à¹\89à¸\9cสาà¸\99à¸\82à¹\89à¸à¸¡à¸¹à¸¥à¸\81ัà¸\9aà¹\84à¸\9fลà¹\8cà¸\95à¹\89à¸\99à¸\97าà¸\87 à¸\81ารà¸\94ำà¹\80à¸\99ิà¸\99à¸\81ารà¸\95à¹\88à¸à¹\84à¸\9bà¸\88ะà¹\80à¸\9bà¹\87à¸\99à¸\81ารà¹\81à¸\97à¸\99à¸\97ีà¹\88à¹\80à¸\99ืà¹\89à¸à¸«à¸²à¸\82à¸à¸\87à¹\84à¸\9fลà¹\8cà¸\97ีà¹\88มีอยู่บนเซิร์ฟเวอร์</string>
<string name="conflict_keep_both">เก็บไว้ทั้งสองอย่าง</string>
<string name="conflict_overwrite">เขียนทับ</string>
<string name="conflict_dont_upload">ไม่ต้องอัพโหลด</string>
+ <string name="preview_image_description">แสดงรูปภาพตัวอย่าง</string>
+ <string name="preview_image_error_unknown_format">ไม่สามารถแสดงรูปภาพนี้ได้</string>
+ <string name="error__upload__local_file_not_copied">%1$s ไม่สามารถคัดลอกไปยังโฟลเดอร์ %2$s ในเครื่อง</string>
+ <string name="prefs_instant_upload_path_title">เส้นทางอัพโหลด</string>
+ <string name="share_link_no_support_share_api">ขออภัยการแชร์ไม่ได้เปิดใช้งานบนเซิร์ฟเวอร์ของคุณ กรุณาติดต่อผู้ดูแลระบบ</string>
+ <string name="share_link_file_no_exist">ไม่สามารถแชร์ กรุณาตรวจสอบไฟล์ที่มีอยู่</string>
+ <string name="share_link_file_error">เกิดข้อผิดพลาดในขณะที่พยายามจะแชร์ไฟล์หรือโฟลเดอร์นี้</string>
+ <string name="unshare_link_file_no_exist">ไม่สามารถยกเลิกการแชร์ กรุณาตรวจสอบไฟล์ที่มีอยู่</string>
+ <string name="unshare_link_file_error">เกิดข้อผิดพลาดในขณะที่จะยกเลิกการอชร์ไฟล์หรือโฟลเดอร์นี้</string>
+ <string name="share_link_password_title">ป้อนรหัสผ่าน</string>
+ <string name="share_link_empty_password">คุณจะต้องใส่รหัสผ่าน</string>
<string name="activity_chooser_send_file_title">ส่ง</string>
+ <string name="copy_link">คัดลอกลิงค์</string>
+ <string name="clipboard_text_copied">คัดลอกไปยังคลิปบอร์ด</string>
+ <string name="error_cant_bind_to_operations_service">ข้อผิดพลาด: ไม่สามารถดำเนินการได้</string>
+ <string name="network_error_socket_exception">เกิดข้อผิดพลาดขณะกำลังเชื่อมต่อกับเซิร์ฟเวอร์</string>
+ <string name="network_error_socket_timeout_exception">เกิดข้อผิดพลาดขณะที่รอการดำเนินการจากเซิร์ฟเวอร์</string>
+ <string name="network_error_connect_timeout_exception">เกิดข้อผิดพลาดขณะที่รอการดำเนินการจากเซิร์ฟเวอร์</string>
+ <string name="network_host_not_available">การดำเนินการอาจยังไม่เสร็จสมบูรณ์ เซิร์ฟเวอร์ไม่สามารถใช้งานได้</string>
<string name="empty"></string>
+ <string name="forbidden_permissions">คุณไม่ได้รับสิทธิ์ %s</string>
+ <string name="forbidden_permissions_rename">เพื่อเปลี่ยนชื่อไฟล์นี้</string>
+ <string name="forbidden_permissions_delete">เพื่อลบไฟล์นี้</string>
+ <string name="share_link_forbidden_permissions">เพื่อแชร์ไฟล์นี้</string>
+ <string name="unshare_link_forbidden_permissions">เพื่อเลิกแชร์ไฟล์นี้</string>
+ <string name="forbidden_permissions_create">เพื่อสร้างไฟล์</string>
+ <string name="uploader_upload_forbidden_permissions">เพื่ออัพโหลดในโฟลเดอร์นี้</string>
+ <string name="downloader_download_file_not_found">ไฟล์ไม่พร้อมใช้งานบนเซิร์ฟเวอร์</string>
<string name="prefs_category_accounts">บัญชี</string>
- <string name="move_choose_button_text">เลือก</string>
+ <string name="prefs_add_account">เพิ่มบัญชี</string>
+ <string name="auth_redirect_non_secure_connection_title">การเชื่อมต่อที่ปลอดภัยถูกเปลี่ยนเส้นทางไปยังเส้นทางที่ไม่ปลอดภัย</string>
+ <string name="actionbar_logger">บันทึก</string>
+ <string name="log_send_history_button">ส่งประวัติ</string>
+ <string name="log_send_no_mail_app">ไม่พบการส่งบันทึกของแอพฯ ติดตั้งแอพฯเมล!</string>
+ <string name="log_send_mail_subject">%1$s บันทึกแอพแอนดรอยด์</string>
+ <string name="log_progress_dialog_text">กำลังโหลดข้อมูล ...</string>
+ <string name="saml_authentication_required_text">จำเป็นต้องยืนยันตัวตน</string>
+ <string name="saml_authentication_wrong_pass">รหัสผ่านไม่ถูกต้อง</string>
+ <string name="actionbar_move">ย้าย</string>
+ <string name="file_list_empty_moving">ไม่มีสิ่งใดในที่นี่ คุณสามารถสร้างโฟลเดอร์!</string>
+ <string name="folder_picker_choose_button_text">เลือก</string>
+ <string name="move_file_not_found">ไม่สามารถย้ายไฟล์ กรุณาตรวจสอบว่าไฟล์ยังคงอยู่</string>
+ <string name="move_file_invalid_into_descendent">มันเป็นไปไม่ได้ที่จะย้ายโฟลเดอร์ที่มีราก</string>
+ <string name="move_file_invalid_overwrite">มีไฟล์อยู่แล้วในโฟลเดอร์ปลายทาง</string>
+ <string name="move_file_error">เกิดข้อผิดพลาดขณะพยายามที่จะย้ายไฟล์หรือโฟลเดอร์นี้</string>
+ <string name="forbidden_permissions_move">เพื่อย้ายไฟล์นี้</string>
+ <string name="prefs_category_instant_uploading">อัพโหลดทันที</string>
+ <string name="prefs_category_security">ความปลอดภัย</string>
+ <string name="prefs_instant_video_upload_path_title">อัพโหลดเส้นทางวิดีโอ</string>
+ <string name="download_folder_failed_content">การดาวน์โหลดโฟลเดอร์ %1$s อาจไม่สำเร็จ</string>
+ <string name="shared_subject_header">ถูกแชร์</string>
+ <string name="with_you_subject_header">กับคุณ</string>
+ <string name="subject_token">%1$s ได้แชร์ \"%2$s\" กับคุณ</string>
+ <string name="auth_refresh_button">ฟื้นฟูการเชื่อมต่อ</string>
+ <string name="auth_host_address">ที่อยู่เซิร์ฟเวอร์</string>
+ <string name="common_error_out_memory">หน่วยความจำไม่พอ</string>
+ <string name="username">ชื่อผู้ใช้</string>
+ <string name="file_list__footer__folder">1 โฟลเดอร์</string>
+ <string name="file_list__footer__folders">%1$d โฟลเดอร์</string>
+ <string name="file_list__footer__file">1 ไฟล์</string>
+ <string name="file_list__footer__file_and_folder">1 ไฟล์, 1 โฟลเดอร์</string>
+ <string name="file_list__footer__file_and_folders">1 ไฟล์, %1$d โฟลเดอร์</string>
+ <string name="file_list__footer__files">%1$d ไฟล์</string>
+ <string name="file_list__footer__files_and_folder">%1$d ไฟล์, 1 โฟลเดอร์</string>
+ <string name="file_list__footer__files_and_folders">%1$d ไฟล์, %2$d โฟลเดอร์</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Tüm dosyalar</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Ayarlar</string>
+ <string name="drawer_item_logs">Günlükler</string>
+ <string name="drawer_close">Kapat</string>
<string name="prefs_category_general">Genel</string>
<string name="prefs_category_more">Daha fazla</string>
<string name="prefs_accounts">Hesaplar</string>
<string name="prefs_manage_accounts">Hesapları Yönet</string>
- <string name="prefs_pincode">Uygulama PIN\'i</string>
- <string name="prefs_pincode_summary">İstemcinizi koruyun</string>
+ <string name="prefs_passcode">Parola kod kilidi</string>
<string name="prefs_instant_upload">Anında fotoğraf yüklemeleri</string>
<string name="prefs_instant_upload_summary">Kamera ile çekilen fotoğrafları anında yükle</string>
<string name="prefs_instant_video_upload">Anında video yüklemeleri</string>
<string name="sync_string_files">Dosyalar</string>
<string name="setup_btn_connect">Bağlan</string>
<string name="uploader_btn_upload_text">Yükle</string>
+ <string name="uploader_btn_new_folder_text">Yeni klasör</string>
<string name="uploader_top_message">Yükleme klasörünü seçin:</string>
<string name="uploader_wrn_no_account_title">Hesap bulunamadı</string>
<string name="uploader_wrn_no_account_text">Cihazınızda %1$s hesabı bulunmamaktadır. Lütfen öncelikle bir hesap ayarlayın.</string>
<string name="filedetails_download">İndir</string>
<string name="filedetails_sync_file">Dosyayı yenile</string>
<string name="filedetails_renamed_in_upload_msg">Dosya adı, yükleme sırasında %1$s olarak değiştirildi</string>
+ <string name="list_layout">Liste Yerleşimi</string>
<string name="action_share_file">Paylaşma bağlantısı</string>
<string name="action_unshare_file">Bağlantı paylaşımını kaldır</string>
<string name="common_yes">Evet</string>
<string name="foreign_files_local_text">Yerel: %1$s</string>
<string name="foreign_files_remote_text">Uzak: %1$s</string>
<string name="upload_query_move_foreign_files">Seçilen dosyaları %1$s dizinine kopyalamak için yeterli alan yok. Bunun yerine dosyayı içine taşımak ister misiniz?</string>
- <string name="pincode_enter_pin_code">Lütfen uygulama PIN\'inizi girin</string>
- <string name="pincode_configure_your_pin">Uygulama PIN\'inizi girin</string>
- <string name="pincode_configure_your_pin_explanation">PIN uygulama yeniden başladığında tekrar sorulacak</string>
- <string name="pincode_reenter_your_pincode">Lütfen, uygulama PIN\'inizi tekrar girin</string>
- <string name="pincode_remove_your_pincode">Uygulama PIN\'inizi kaldırın</string>
- <string name="pincode_mismatch">Her iki Uygulama PIN\'i aynı değil</string>
- <string name="pincode_wrong">Yanlış Uygulama PIN\'i</string>
- <string name="pincode_removed">Uygulama PIN\'i kaldırıldı</string>
- <string name="pincode_stored">Uygulama PIN\'i saklandı</string>
+ <string name="pass_code_enter_pass_code">Lütfen parola kodu kilidini girin</string>
+ <string name="pass_code_configure_your_pass_code">Parola kodunuzu girin</string>
+ <string name="pass_code_configure_your_pass_code_explanation">Parola kodu uygulama her başlatıldığında sorulacaktır</string>
+ <string name="pass_code_reenter_your_pass_code">Lütfen parola kodunuzu yeniden girin</string>
+ <string name="pass_code_remove_your_pass_code">Parola kodunuzu kaldırın</string>
+ <string name="pass_code_mismatch">Parola kodları aynı değil</string>
+ <string name="pass_code_wrong">Hatalı parola kodu</string>
+ <string name="pass_code_removed">Parola kodu kaldırıldı</string>
+ <string name="pass_code_stored">Parola kodu depolandı</string>
<string name="media_notif_ticker">%1$s müzik çalar</string>
<string name="media_state_playing">%1$s (oynatılıyor)</string>
<string name="media_state_loading">%1$s (yükleniyor)</string>
<string name="auth_no_net_conn_title">Ağ bağlantısı yok</string>
<string name="auth_nossl_plain_ok_title">Güvenli bağlantı mevcut değil.</string>
<string name="auth_connection_established">Bağlantı kuruldu</string>
- <string name="auth_testing_connection">Bağlantı kontrol ediliyor...</string>
+ <string name="auth_testing_connection">Bağlantı sınanıyor</string>
<string name="auth_not_configured_title">Hatalı sunucu yapılandırması</string>
<string name="auth_account_not_new">Cihazda aynı kullanıcı adı ve sunucu için bir hesap zaten mevcut</string>
<string name="auth_account_not_the_same">Girilen kullanıcı bu hesabın kullanıcısı ile eşleşmiyor</string>
<string name="auth_fail_get_user_name">Sunucunuz geçerli bir kullanıcı kimliği döndürmüyor, lütfen yöneticinizle iletişime geçin
</string>
<string name="auth_can_not_auth_against_server">Bu sunucuya karşı kimlik doğrulama yapılamaz</string>
+ <string name="auth_account_does_not_exist">Hesap henüz cihazda mevcut değil</string>
<string name="fd_keep_in_sync">Dosyayı güncel tut</string>
<string name="common_rename">Yeniden adlandır</string>
<string name="common_remove">Kaldır</string>
<string name="sync_file_nothing_to_do_msg">Dosya içerikleri zaten eşitlenmiş</string>
<string name="create_dir_fail_msg">Klasör oluşturulamadı</string>
<string name="filename_forbidden_characters">Yasaklı karakterler: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Dosya adı en az bir geçersiz karakter içeriyor</string>
<string name="filename_empty">Dosya adı boş olamaz</string>
<string name="wait_a_moment">Bir süre bekleyin</string>
<string name="filedisplay_unexpected_bad_get_content">Beklenmedik sorun; lütfen dosya seçmek için farklı bir uygulama kullanın</string>
<string name="filedisplay_no_file_selected">Hiçbir dosya seçilmedi</string>
<string name="activity_chooser_title">Bağlantıyı gönder ...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Dosya özel depolamadan kopyalanıyor</string>
<string name="oauth_check_onoff">oAuth2 ile oturum aç</string>
<string name="oauth_login_connection">oAuth2 sunucusuna bağlanılıyor…</string>
<string name="ssl_validator_header">Bu sitenin sertifikası doğrulanamadı</string>
<string name="share_link_file_error">Bu dosya veya klasörü paylaşmaya çalışılırken bir hata oluştu</string>
<string name="unshare_link_file_no_exist">Paylaşımı kaldırma başarısız. Lütfen dosyanın mevcut olup olmadığını denetleyin</string>
<string name="unshare_link_file_error">Bu dosya veya klasör paylaşımı kaldırılmaya çalışılırken bir hata oluştu</string>
+ <string name="share_link_password_title">Bir parola girin</string>
+ <string name="share_link_empty_password">Bir parola girmelisiniz</string>
<string name="activity_chooser_send_file_title">Gönder</string>
<string name="copy_link">Bağlantıyı kopyala</string>
<string name="clipboard_text_copied">Panoya kopyalandı</string>
<string name="auth_redirect_non_secure_connection_title">Güvenli bağlantı, güvenli olmayan bir rotaya yönlendirildi.</string>
<string name="actionbar_logger">Günlükler</string>
<string name="log_send_history_button">Geçmişi Gönder</string>
- <string name="log_mail_subject">ownCloud Android uygulama kayıtları</string>
+ <string name="log_send_no_mail_app">Kayıtları göndermek için uygulama bulunamadı. E-posta uygulamasını yükleyin!</string>
+ <string name="log_send_mail_subject">%1$s Android uygulama kayıtları</string>
<string name="log_progress_dialog_text">Veri yükleniyor...</string>
<string name="saml_authentication_required_text">Kimlik doğrulama gerekli</string>
<string name="saml_authentication_wrong_pass">Hatalı parola</string>
<string name="actionbar_move">Taşı</string>
<string name="file_list_empty_moving">Burada bir şey yok. Bir klasör ekleyebilirsiniz!</string>
- <string name="move_choose_button_text">Seç</string>
+ <string name="folder_picker_choose_button_text">Seç</string>
<string name="move_file_not_found">Taşıma başarısız. Lütfen dosyanın mevcut olup olmadığını denetleyin</string>
<string name="move_file_invalid_into_descendent">Klasörü, kendi alt klasörüne taşımak mümkün değil</string>
<string name="move_file_invalid_overwrite">Dosya zaten hedef klasörde mevcut</string>
<string name="forbidden_permissions_move">bu dosyayı taşımak için</string>
<string name="prefs_category_instant_uploading">Anında Yüklemeler</string>
<string name="prefs_category_security">Güvenlik</string>
+ <string name="prefs_instant_video_upload_path_title">Video Yükleme Yolu</string>
+ <string name="download_folder_failed_content">%1$s klasörün indirilmesi tamamlanamadı</string>
+ <string name="shared_subject_header">sizinle</string>
+ <string name="with_you_subject_header">paylaştı</string>
+ <string name="subject_token">%1$s, sizinle \"%2$s\" paylaşımını yaptı</string>
+ <string name="auth_refresh_button">Bağlantıyı yenile</string>
+ <string name="auth_host_address">Sunucu adresi</string>
+ <string name="common_error_out_memory">Yeterli hafıza yok</string>
+ <string name="username">Kullanıcı adı</string>
+ <string name="file_list__footer__folder">1 klasör</string>
+ <string name="file_list__footer__folders">%1$d klasör</string>
+ <string name="file_list__footer__file">1 dosya</string>
+ <string name="file_list__footer__file_and_folder">1 dosya, 1 klasör</string>
+ <string name="file_list__footer__file_and_folders">1 dosya, %1$d klasör</string>
+ <string name="file_list__footer__files">%1$d dosya</string>
+ <string name="file_list__footer__files_and_folder">%1$d dosya, 1 klasör</string>
+ <string name="file_list__footer__files_and_folders">%1$d dosya, %2$d klasör</string>
</resources>
<string name="actionbar_send_file">يوللا</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">ئادەتتىكى</string>
<string name="prefs_category_more">تېخىمۇ كۆپ</string>
<string name="prefs_accounts">ھېساباتلار</string>
<string name="sync_string_files">ھۆججەتلەر</string>
<string name="setup_btn_connect">باغلان</string>
<string name="uploader_btn_upload_text">يۈكلە</string>
+ <string name="uploader_btn_new_folder_text">يېڭى قىسقۇچ</string>
<string name="uploader_wrn_no_account_title">ھېسابات تېپىلمىدى</string>
<string name="uploader_wrn_no_account_setup_btn_text">تەڭشەك</string>
<string name="uploader_wrn_no_account_quit_btn_text">چېكىن</string>
<string name="empty"></string>
<string name="prefs_category_accounts">ھېساباتلار</string>
<string name="prefs_category_security">بىخەتەرلىك</string>
+ <string name="auth_host_address">مۇلازىمېتىر ئادرىسى</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">Усі файли</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Налаштування</string>
+ <string name="drawer_item_logs">Журнали</string>
+ <string name="drawer_close">Закрити</string>
<string name="prefs_category_general">Основне</string>
<string name="prefs_category_more">Більше</string>
<string name="prefs_accounts">Облікові записи</string>
<string name="prefs_manage_accounts">Управління обліковими записами</string>
- <string name="prefs_pincode">App програмний PIN</string>
- <string name="prefs_pincode_summary">Захист Вашог App клієнта</string>
<string name="prefs_instant_upload">Миттєві зображення</string>
<string name="prefs_instant_upload_summary">Миттєві зображення з камери</string>
<string name="prefs_instant_video_upload">Миттєві відео</string>
<string name="prefs_recommend">Порадити товаришу</string>
<string name="prefs_feedback">Зворотній зв\'язок</string>
<string name="prefs_imprint">Відбиток</string>
+ <string name="prefs_remember_last_share_location">Запам\'ятати позицію</string>
+ <string name="prefs_remember_last_upload_location_summary">Запам\'ятати останній опублікований шлях завантаження</string>
<string name="recommend_subject">Спробуйте %1$s на своєму смартфоні!</string>
<string name="recommend_text">Пропоную вам користуватися %1$s на вашому смартфоні!\nЗавантажити можна за посиланням: %2$s</string>
<string name="auth_check_server">Перевірити сервер</string>
<string name="sync_string_files">Файли</string>
<string name="setup_btn_connect">З\'єднати</string>
<string name="uploader_btn_upload_text">Відвантажити</string>
+ <string name="uploader_btn_new_folder_text">Нова тека</string>
<string name="uploader_top_message">Оберіть теку для завантаження:</string>
<string name="uploader_wrn_no_account_title">Не знайдено облікового запису</string>
<string name="uploader_wrn_no_account_text">На Вашому пристрої відсутні облікові записи %1$s. Будь ласка, спочатку створіть запис.</string>
<string name="uploader_info_uploading">Завантаження</string>
<string name="file_list_seconds_ago">секунди тому</string>
<string name="file_list_empty">Тут нічого немає. Відвантажте що-небудь!</string>
- <string name="file_list_loading">Завантаження...</string>
+ <string name="file_list_loading">Завантаження…</string>
<string name="local_file_list_empty">В цій теці немає файлів.</string>
<string name="filedetails_select_file">Натисніть на файлі для відображення додаткової інформації</string>
<string name="filedetails_size">Розмір:</string>
<string name="uploader_upload_failed_ticker">Помилка завантаження</string>
<string name="uploader_upload_failed_content_single">Завантаження %1$s не може завершитись</string>
<string name="uploader_upload_failed_credentials_error">Завантажити не вдалося, необхідно повторити вхід</string>
- <string name="downloader_download_in_progress_ticker">Ð\97качування …</string>
+ <string name="downloader_download_in_progress_ticker">Скачування …</string>
<string name="downloader_download_in_progress_content">%1$d%% Зкачування %2$s</string>
<string name="downloader_download_succeeded_ticker">Успішно зкачано</string>
<string name="downloader_download_succeeded_content">%1$s успішно завантажено</string>
<string name="foreign_files_local_text">Локально: %1$s</string>
<string name="foreign_files_remote_text">Віддалено: %1$s</string>
<string name="upload_query_move_foreign_files">Недостатньо місця для копіювання обраних файлів у теку %1$s. Чи бажаєте ви перемістити їх замість копіювання?</string>
- <string name="pincode_enter_pin_code">Будь ласка, введіть свій програмний PIN</string>
- <string name="pincode_configure_your_pin">Введіть програмний PIN</string>
- <string name="pincode_configure_your_pin_explanation">PIN необхідно буде вводити щоразу при запуску цієї програми</string>
- <string name="pincode_reenter_your_pincode">Повторно введіть App програмний PIN, будь ласка</string>
- <string name="pincode_remove_your_pincode">Видалити свій App програмний PIN</string>
- <string name="pincode_mismatch">Обидва App програмних PIN не однакові</string>
- <string name="pincode_wrong">Не вірний App програмний PIN</string>
- <string name="pincode_removed">App програмний PIN видалено</string>
- <string name="pincode_stored">App програмний PIN збережено</string>
<string name="media_notif_ticker">%1$s музичний плеєр</string>
<string name="media_state_playing">%1$s (відтворення)</string>
<string name="media_state_loading">%1$s (завантаження)</string>
<string name="auth_no_net_conn_title">Відсутнє підключення до мережі</string>
<string name="auth_nossl_plain_ok_title">Безпечне з\'єднання не доступне.</string>
<string name="auth_connection_established">З\'єднання встановлено</string>
- <string name="auth_testing_connection">Перевірка з\'єднання…</string>
+ <string name="auth_testing_connection">Перевірка з\'єднання</string>
<string name="auth_not_configured_title">Не вірні налаштування сервер </string>
<string name="auth_account_not_new">Такий обліковий запис вже існує на пристрої</string>
<string name="auth_account_not_the_same">Введений користувач не відповідає обліковому запису</string>
<string name="auth_fail_get_user_name">Ваш сервер не повертає коректний ідентифікатор користувача, будь ласка зверніться до адміністратора
⇥</string>
<string name="auth_can_not_auth_against_server">Аутентифікація на цьому сервері неможлива</string>
+ <string name="auth_account_does_not_exist">Користвача в пристрої не існуе</string>
<string name="fd_keep_in_sync">Оновлювати файл</string>
<string name="common_rename">Перейменувати</string>
<string name="common_remove">Видалити</string>
<string name="sync_file_nothing_to_do_msg">Зміст файлу вже синхронізовано</string>
<string name="create_dir_fail_msg">Не вдалося створити теку</string>
<string name="filename_forbidden_characters">Заборонені символи: / \\ < > : \" | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">Ім’я файлу містить принаймні один некоректний символ</string>
<string name="filename_empty"> Ім\'я файлу не може бути порожнім.</string>
<string name="wait_a_moment">Зачекайте хвилинку</string>
<string name="filedisplay_unexpected_bad_get_content">Несподівані проблеми ; будь ласка, спробуйте використати іншу програму для вибору файлу</string>
<string name="filedisplay_no_file_selected">Не обрано файл</string>
<string name="activity_chooser_title">Надіслати посилання...</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Копіювання файлу з приватного сховища</string>
<string name="oauth_check_onoff">Увійти через oAuth2</string>
<string name="oauth_login_connection">Підключення до серверу oAuth2...</string>
<string name="ssl_validator_header">Не вдалося перевірити ідентифікацію сайта</string>
<string name="share_link_file_error">Виникла помилка при спробі поділитися файлом або текою</string>
<string name="unshare_link_file_no_exist">Неможливо заборонити доступ. Будь ласка, перевірте, чи існує файл</string>
<string name="unshare_link_file_error">Виникла помилка при спробі заборонити доступ до файлу або теки</string>
+ <string name="share_link_password_title">Ввести пароль</string>
+ <string name="share_link_empty_password">Ви повинні ввести пароль</string>
<string name="activity_chooser_send_file_title">Надіслати</string>
<string name="copy_link">Копіювати посилання</string>
<string name="clipboard_text_copied">Скопійовано в буфер обміну</string>
<string name="auth_redirect_non_secure_connection_title">Безпечне підключення перенаправляється через незабезпечений маршрут.</string>
<string name="actionbar_logger">Журнали</string>
<string name="log_send_history_button">Надіслати історію</string>
- <string name="log_mail_subject">Журнали Android-додатка ownCloud</string>
+ <string name="log_send_no_mail_app">Немає додатку для відправки журналів. Встановіть поштовий додаток!</string>
+ <string name="log_send_mail_subject">%1$s Android лог додатку</string>
<string name="log_progress_dialog_text">Завантаження даних...</string>
<string name="saml_authentication_required_text">Потрібна аутентифікація</string>
<string name="saml_authentication_wrong_pass">Невірний пароль</string>
<string name="actionbar_move">Перемістити</string>
<string name="file_list_empty_moving">Тут нічого немає. Ви можете додати теку!</string>
- <string name="move_choose_button_text">Обрати</string>
+ <string name="folder_picker_choose_button_text">Обрати</string>
<string name="move_file_not_found">Неможливо перемістити. Будь ласка, перевірте, чи існує файл</string>
<string name="move_file_invalid_into_descendent">Неможливо перемістити теку до теки-нащадка</string>
<string name="move_file_invalid_overwrite">Файл вже існує в теці призначення</string>
<string name="forbidden_permissions_move">перемістити цей файл</string>
<string name="prefs_category_instant_uploading">Миттєво завантаження</string>
<string name="prefs_category_security">Безпека</string>
+ <string name="prefs_instant_video_upload_path_title">Шлях завантаження відео</string>
+ <string name="download_folder_failed_content">Скачування теки %1$s не може бути завершено</string>
+ <string name="with_you_subject_header">з Вами</string>
+ <string name="subject_token">%1$s поділився \"%2$s\" з вами</string>
+ <string name="auth_refresh_button">Оновити з\'єднання</string>
+ <string name="auth_host_address">Ареса серверу</string>
+ <string name="common_error_out_memory">Недостатньо пам\'яті</string>
+ <string name="username">Ім\'я користувача</string>
+ <string name="file_list__footer__folder">1 тека</string>
+ <string name="file_list__footer__folders">%1$d тек</string>
+ <string name="file_list__footer__file">1 файл</string>
+ <string name="file_list__footer__file_and_folder">1 файл, 1 тека</string>
+ <string name="file_list__footer__file_and_folders">1 файл, %1$d тек</string>
+ <string name="file_list__footer__files">%1$d файлів</string>
+ <string name="file_list__footer__files_and_folder">%1$d файлів, 1 тека</string>
+ <string name="file_list__footer__files_and_folders">%1$d файлів, %2$d тек</string>
</resources>
<string name="actionbar_send_file">بھجیں</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_more">مزید</string>
<string name="prefs_help">مدد</string>
<string name="auth_username">یوزر نیم</string>
<string name="common_error_unknown">غیر معروف خرابی</string>
<string name="activity_chooser_send_file_title">بھجیں</string>
<string name="empty"></string>
- <string name="move_choose_button_text">منتخب کریں</string>
+ <string name="folder_picker_choose_button_text">منتخب کریں</string>
</resources>
<resources>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="empty"></string>
</resources>
<string name="actionbar_send_file">Gởi</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">Tổng hợp</string>
<string name="prefs_category_more">hơn</string>
<string name="prefs_accounts">Tài khoản</string>
<string name="prefs_manage_accounts">Quản lý tài khoản</string>
- <string name="prefs_pincode">Mã PIN ứng dụng App</string>
- <string name="prefs_pincode_summary">Bảo vệ App client của bạn</string>
<string name="prefs_log_title">Bật chế độ nhật trình</string>
<string name="prefs_log_summary">Được sử dụng cho các vấn đề liên quan đến nhật trình</string>
<string name="prefs_log_title_history">Nhật trình dữ kiện</string>
<string name="sync_string_files">Tập tin</string>
<string name="setup_btn_connect">Kết nối</string>
<string name="uploader_btn_upload_text">Tải lên</string>
+ <string name="uploader_btn_new_folder_text">Tạo thư mục</string>
<string name="uploader_wrn_no_account_title">Không tìm thấy tài khoản</string>
<string name="uploader_wrn_no_account_text">Trên thiết bị của bạn không có tài khoản %1$s. Bước đầu tiên hãy thiết lập một tài khoản.</string>
<string name="uploader_wrn_no_account_setup_btn_text">Cài đặt</string>
<string name="foreign_files_fail">Một vài tập tin không thể chuyển đi</string>
<string name="foreign_files_local_text">Cục bộ: %1$s</string>
<string name="foreign_files_remote_text">Từ xa: %1$s</string>
- <string name="pincode_enter_pin_code">Vui lòng, nhập mã PIN ứng dụng của bạn</string>
- <string name="pincode_configure_your_pin">Nhập mã PIN ứng dụng App</string>
- <string name="pincode_configure_your_pin_explanation">Mã PIN sẽ được yêu cầu mỗi khi ứng dụng được bật </string>
- <string name="pincode_reenter_your_pincode">Vui lòng nhập lại mã PIN ứng dụng App</string>
- <string name="pincode_remove_your_pincode">Hủy mã PIN ứng dụng App của bạn</string>
- <string name="pincode_mismatch">Mã PIN ứng dụng App không được trùng</string>
- <string name="pincode_wrong">Mã PIN ứng dụng App không đúng</string>
- <string name="pincode_removed">Mã PIN ứng dụng App đã bị xóa</string>
- <string name="pincode_stored">Mã PIN ứng dụng App đã được lưu trữ</string>
<string name="media_notif_ticker">%1$s trình phát nhạc</string>
<string name="media_state_playing">%1$s (đang phát)</string>
<string name="media_state_loading">%1$s (đang tải)</string>
<string name="auth_no_net_conn_title">Không có kết nối mạng</string>
<string name="auth_nossl_plain_ok_title">Bảo mật kết nối không có giá trị.</string>
<string name="auth_connection_established">Kết nối đã thiết lập</string>
- <string name="auth_testing_connection">Đang kiểm tra kết nối...</string>
<string name="auth_not_configured_title">Thay đổi cấu hình máy chủ </string>
<string name="auth_account_not_new">Một tài khoản với cùng tên người dùng và máy chủ đã tồn tại trong thiết bị</string>
<string name="auth_account_not_the_same">Tên người dùng đã nhập không đúng với tên người dùng của tài khoản này</string>
<string name="activity_chooser_send_file_title">Gởi</string>
<string name="empty"></string>
<string name="prefs_category_accounts">Tài khoản</string>
- <string name="move_choose_button_text">Chọn</string>
+ <string name="folder_picker_choose_button_text">Chọn</string>
+ <string name="auth_host_address">Địa chỉ máy chủ</string>
</resources>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--TODO re-enable when server-side folder size calculation is available
+ <item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="empty"></string>
+</resources>
<string name="about_version">版本:%1$s</string>
<string name="actionbar_sync">刷新帐户</string>
<string name="actionbar_upload">上传</string>
- <string name="actionbar_upload_from_apps">来自其它app的内容</string>
+ <string name="actionbar_upload_from_apps">来自其它应用的内容</string>
<string name="actionbar_upload_files">文件</string>
- <string name="actionbar_open_with">打开</string>
- <string name="actionbar_mkdir">增加文件夹</string>
+ <string name="actionbar_open_with">打开方式</string>
+ <string name="actionbar_mkdir">新建文件夹</string>
<string name="actionbar_settings">设置</string>
<string name="actionbar_see_details">详细信息</string>
<string name="actionbar_send_file">发送</string>
+ <string name="actionbar_sort">排序</string>
+ <string name="actionbar_sort_title">排序方式</string>
+ <string-array name="actionbar_sortby">
+ <item>A - Z</item>
+ <item>新 - 旧</item>
+ </string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">全部文件</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">设置</string>
+ <string name="drawer_item_logs">日志</string>
+ <string name="drawer_close">关闭</string>
<string name="prefs_category_general">常规</string>
<string name="prefs_category_more">更多</string>
<string name="prefs_accounts">账号</string>
<string name="prefs_manage_accounts">管理账号</string>
- <string name="prefs_pincode">App PIN</string>
- <string name="prefs_pincode_summary">保护您的App客户端</string>
+ <string name="prefs_passcode">密码锁</string>
<string name="prefs_instant_upload">即时图片上传</string>
<string name="prefs_instant_upload_summary">即时上传相机拍摄的图片</string>
- <string name="prefs_instant_video_upload">立即上传视频</string>
+ <string name="prefs_instant_video_upload">即时上传视频</string>
<string name="prefs_instant_video_upload_summary">即时上传由相机拍摄的视频</string>
<string name="prefs_log_title">开启日志</string>
- <string name="prefs_log_summary">这过去是日志问题</string>
+ <string name="prefs_log_summary">用于记录问题</string>
<string name="prefs_log_title_history">日志历史</string>
<string name="prefs_log_summary_history">这显示已经保存的日志</string>
<string name="prefs_log_delete_history_button">删除历史</string>
<string name="prefs_recommend">推荐给朋友</string>
<string name="prefs_feedback">反馈</string>
<string name="prefs_imprint">版本说明</string>
- <string name="recommend_subject">在您的智能手机上试用一下 %1$s!</string>
- <string name="recommend_text">“我邀请你使用在你的智能手机上使用 %1$s,在这下载:%2$s”
- </string>
+ <string name="prefs_remember_last_share_location">记住共享位置</string>
+ <string name="prefs_remember_last_upload_location_summary">记住上次共享上传的位置</string>
+ <string name="recommend_subject">在您的智能手机上试用 %1$s!</string>
+ <string name="recommend_text">我邀请你在智能手机上使用 %1$s\n下载路径:%2$s</string>
<string name="auth_check_server">检查服务器</string>
<string name="auth_host_url">服务器地址 https://...</string>
<string name="auth_username">用户名</string>
<string name="auth_password">密码</string>
- <string name="auth_register">新增到 %1$s?</string>
+ <string name="auth_register">初次使用 %1$s?</string>
<string name="sync_string_files">文件</string>
<string name="setup_btn_connect">连接</string>
<string name="uploader_btn_upload_text">上传</string>
+ <string name="uploader_btn_new_folder_text">新建文件夹</string>
<string name="uploader_top_message">选择上传文件夹:</string>
<string name="uploader_wrn_no_account_title">未找到账号</string>
- <string name="uploader_wrn_no_account_text">设备上未找到账号,请先创建账号。</string>
+ <string name="uploader_wrn_no_account_text">设备上未找到 %1$s 账号,请先设置账号。</string>
<string name="uploader_wrn_no_account_setup_btn_text">设置</string>
<string name="uploader_wrn_no_account_quit_btn_text">退出</string>
- <string name="uploader_wrn_no_content_title">没有上传的内容</string>
- <string name="uploader_wrn_no_content_text">没æ\9c\89æ\8e¥æ\94¶å\88°å\86\85容ï¼\8cæ\97 å\8f¯ä¸\8aä¼ 。</string>
+ <string name="uploader_wrn_no_content_title">没有需要上传的内容</string>
+ <string name="uploader_wrn_no_content_text">没æ\9c\89æ\8e¥æ\94¶å\88°å\86\85容ï¼\8c没æ\9c\89é\9c\80è¦\81ä¸\8aä¼ ç\9a\84å\86\85容。</string>
<string name="uploader_error_forbidden_content">%1$s未被允许访问共享内容。</string>
<string name="uploader_info_uploading">上传</string>
- <string name="file_list_seconds_ago">秒前</string>
+ <string name="file_list_seconds_ago">几秒前</string>
<string name="file_list_empty">这里还什么都没有。上传些东西吧!</string>
- <string name="file_list_loading">载入中....</string>
<string name="local_file_list_empty">在该文件夹中不存在文件。</string>
- <string name="filedetails_select_file">点击一个文件æ\9d¥æ\98¾ç¤ºé¢\9då¤\96ç\9a\84ä¿¡æ\81¯ã\80\82</string>
+ <string name="filedetails_select_file">点击一个文件å\8f¯ä»¥æ\98¾ç¤ºé¢\9då¤\96ç\9a\84ä¿¡æ\81¯ã\80\82</string>
<string name="filedetails_size">大小:</string>
<string name="filedetails_type">类型:</string>
<string name="filedetails_created">创建于:</string>
- <string name="filedetails_modified">已修改:</string>
+ <string name="filedetails_modified">修改于:</string>
<string name="filedetails_download">下载</string>
<string name="filedetails_sync_file">刷新文件</string>
<string name="filedetails_renamed_in_upload_msg">上传过程中文件被更名为了 %1$s</string>
+ <string name="list_layout">列表布局</string>
<string name="action_share_file">分享链接</string>
- <string name="action_unshare_file">å\8f\96æ¶\88å\85±享链接</string>
+ <string name="action_unshare_file">å\8f\96æ¶\88å\88\86享链接</string>
<string name="common_yes">是</string>
<string name="common_no">否</string>
- <string name="common_ok">OK</string>
+ <string name="common_ok">确定</string>
<string name="common_cancel_download">取消下载</string>
<string name="common_cancel_upload">取消上传</string>
<string name="common_cancel">取消</string>
<string name="delete_account">删除账号</string>
<string name="create_account">创建账号</string>
<string name="upload_chooser_title">上传自...</string>
- <string name="uploader_info_dirname">目录名称</string>
+ <string name="uploader_info_dirname">文件夹名称</string>
<string name="uploader_upload_in_progress_ticker">上传...</string>
<string name="uploader_upload_in_progress_content">%1$d%% 上传 %2$s</string>
<string name="uploader_upload_succeeded_ticker">上传成功</string>
<string name="uploader_upload_succeeded_content_single">%1$s 成功上传</string>
<string name="uploader_upload_failed_ticker">上传失败</string>
- <string name="uploader_upload_failed_content_single">1$上传未能完成</string>
+ <string name="uploader_upload_failed_content_single">%1$s 未能成功上传</string>
<string name="uploader_upload_failed_credentials_error">上传失败,您需要重新登录</string>
- <string name="downloader_download_in_progress_ticker">下载中……</string>
+ <string name="downloader_download_in_progress_ticker">下载中...</string>
<string name="downloader_download_in_progress_content">%1$d%% 下载中 %2$s</string>
<string name="downloader_download_succeeded_ticker">下载成功</string>
- <string name="downloader_download_succeeded_content">%1$s 成功下载</string>
+ <string name="downloader_download_succeeded_content">成功下载 %1$s </string>
<string name="downloader_download_failed_ticker">下载失败</string>
- <string name="downloader_download_failed_content">下载1$s 未能完成</string>
+ <string name="downloader_download_failed_content">%1$s 下载未能完成</string>
<string name="downloader_not_downloaded_yet">未下载完毕</string>
<string name="downloader_download_failed_credentials_error">下载失败,您需要重新登录</string>
<string name="common_choose_account">选择账户</string>
<string name="sync_fail_ticker">同步失败</string>
<string name="sync_fail_ticker_unauthorized">同步失败,您需要重新登录</string>
<string name="sync_fail_content"> %1$s同步未完成。</string>
- <string name="sync_fail_content_unauthorized">密码错误%1$s</string>
+ <string name="sync_fail_content_unauthorized">%1$s 的密码错误</string>
<string name="sync_conflicts_in_favourites_ticker">发现冲突</string>
<string name="sync_conflicts_in_favourites_content">%1$d 文件无法同步</string>
<string name="sync_fail_in_favourites_ticker">文件同步失败</string>
- <string name="sync_fail_in_favourites_content">无法同步 %1$d 文件内容(与 %2$d 冲突)</string>
+ <string name="sync_fail_in_favourites_content">无法同步 %1$d 文件内容(%2$d 冲突)</string>
<string name="sync_foreign_files_forgotten_ticker">某些本地文件已被遗忘</string>
<string name="sync_foreign_files_forgotten_content">%2$s 目录中的 %1$d 个文件不能被复制到</string>
<string name="sync_foreign_files_forgotten_explanation">从 1.3.16 版起,从此设备上传的文件将被复制到本地的 %1$s 文件夹,以防止某个单一文件在多个账户间同步而造成的数据损失。\n\n 由于此项变化,此应用之前的版本上传的全部文件都已被复制到了 %2$s 文件夹。然而,账户同步期间有一个错误阻止了此操作的完成。您可能想保持文件不动,并移除指向 %3$s 的链接,或将文件移动到 %1$s 文件夹中并保持其到 %4$s 的链接。下面列出的是本地文件,以及它们被链接到的 %5$s 中的远程文件。</string>
- <string name="sync_current_folder_was_removed">文件夹%1$s 不存在</string>
+ <string name="sync_current_folder_was_removed">文件夹%1$s 已经不存在</string>
<string name="foreign_files_move">移动所有</string>
<string name="foreign_files_success">所有文件已被移动</string>
<string name="foreign_files_fail">某些文件无法被移动</string>
<string name="foreign_files_local_text">本地: %1$s</string>
<string name="foreign_files_remote_text">远程:%1$s</string>
<string name="upload_query_move_foreign_files">没有足够的空间以复制选定的文件到 %1$s 文件夹,您想移动文件到此文件夹吗?</string>
- <string name="pincode_enter_pin_code">请输入您的App PIN码</string>
- <string name="pincode_configure_your_pin">输入 App PIN码</string>
- <string name="pincode_configure_your_pin_explanation">每次应用启动时都会请求PIN码</string>
- <string name="pincode_reenter_your_pincode">再次输入 App PIN码</string>
- <string name="pincode_remove_your_pincode">移除 App PIN码</string>
- <string name="pincode_mismatch">两次 App PIN码不同</string>
- <string name="pincode_wrong">App PIN码不正确</string>
- <string name="pincode_removed">App PIN码已移除</string>
- <string name="pincode_stored">App PIN码已保存。</string>
+ <string name="pass_code_enter_pass_code">请输入您的密码</string>
+ <string name="pass_code_configure_your_pass_code">输入您的密码</string>
+ <string name="pass_code_configure_your_pass_code_explanation">每次应用启动将会请求密码</string>
+ <string name="pass_code_reenter_your_pass_code">请重新输入您的密码</string>
+ <string name="pass_code_remove_your_pass_code">移除您的密码</string>
+ <string name="pass_code_mismatch">密码不一致</string>
+ <string name="pass_code_wrong">错误的密码</string>
+ <string name="pass_code_removed">移除的密码</string>
+ <string name="pass_code_stored">存储的密码</string>
<string name="media_notif_ticker">%1$s 音乐播放器</string>
<string name="media_state_playing">%1$s (播放中)</string>
<string name="media_state_loading">%1$s (载入中)</string>
<string name="media_play_pause_description">播放暂停按钮</string>
<string name="media_forward_description">快进按钮</string>
<string name="auth_getting_authorization">正在认证...</string>
- <string name="auth_trying_to_login">尝试登录</string>
+ <string name="auth_trying_to_login">尝试登录...</string>
<string name="auth_no_net_conn_title">没有网络连接</string>
- <string name="auth_nossl_plain_ok_title">安全链接无效。</string>
+ <string name="auth_nossl_plain_ok_title">安全连接不可用。</string>
<string name="auth_connection_established">连接已建立。</string>
- <string name="auth_testing_connection">测试连接……</string>
- <string name="auth_not_configured_title">服务器配置不正确。</string>
+ <string name="auth_testing_connection">测试连接</string>
+ <string name="auth_not_configured_title">服务器配置不正确</string>
<string name="auth_account_not_new">此设备中已经存在同名同服务器的帐号</string>
<string name="auth_account_not_the_same">输入用户与此帐户的用户不符</string>
<string name="auth_unknown_error_title">发生未知错误!</string>
- <string name="auth_unknown_host_title">无法找到服务器</string>
+ <string name="auth_unknown_host_title">无法找到主机</string>
<string name="auth_incorrect_path_title">未发现服务器实例</string>
<string name="auth_timeout_title">看起来服务器不太给力</string>
<string name="auth_incorrect_address_title">网址不正确</string>
<string name="auth_ssl_unverified_server_title">无法验证 SSL 服务器的身份</string>
<string name="auth_bad_oc_version_title">不可辨识的服务器服务器版本</string>
<string name="auth_wrong_connection_title">无法建立连接</string>
- <string name="auth_secure_connection">å\8a å¯\86连接已建立</string>
- <string name="auth_unauthorized">用户名或密码错误!</string>
+ <string name="auth_secure_connection">å®\89å\85¨连接已建立</string>
+ <string name="auth_unauthorized">用户名或密码错误</string>
<string name="auth_oauth_error">认证不成功</string>
<string name="auth_oauth_error_access_denied">访问被认证服务器拒绝</string>
<string name="auth_wtf_reenter_URL">意外状态;请再次输入服务器的地址</string>
<string name="auth_expired_oauth_token_toast">你的授权已经过期。请重新授权。</string>
- <string name="auth_expired_basic_auth_toast">请输入当前密码:</string>
+ <string name="auth_expired_basic_auth_toast">请输入当前密码</string>
<string name="auth_expired_saml_sso_token_toast">您的会话超时了,请重新连接</string>
<string name="auth_connecting_auth_server">正在连接到认证服务器....</string>
<string name="auth_unsupported_auth_method">服务器不支持这种验证方式</string>
<string name="auth_fail_get_user_name">您的服务器没有返回一个正确的用户 id,请联系管理员
</string>
<string name="auth_can_not_auth_against_server">无法通过此服务器认证</string>
+ <string name="auth_account_does_not_exist">设备中还未存在该帐号</string>
<string name="fd_keep_in_sync">保证文件更新</string>
<string name="common_rename">重命名</string>
<string name="common_remove">删除</string>
<string name="filename_empty">文件名不能为空</string>
<string name="wait_a_moment">请稍候</string>
<string name="filedisplay_unexpected_bad_get_content">未知问题;请试试用其他程序选择此文件</string>
- <string name="filedisplay_no_file_selected">未选择文件。</string>
+ <string name="filedisplay_no_file_selected">未选择文件</string>
<string name="activity_chooser_title">发送链接给 …</string>
+ <string name="wait_for_tmp_copy_from_private_storage">从私有存储中拷贝文件</string>
<string name="oauth_check_onoff">使用oAuth2登陆</string>
<string name="oauth_login_connection">连接oAuth2 服务器...</string>
<string name="ssl_validator_header">站点身份无法验证</string>
- <string name="ssl_validator_reason_cert_not_trusted">不受信任的服务器证书</string>
- <string name="ssl_validator_reason_cert_expired">服务器证书过期</string>
- <string name="ssl_validator_reason_cert_not_yet_valid">服务器证书过新</string>
- <string name="ssl_validator_reason_hostname_not_verified">主机名与证书中的记录不匹配</string>
+ <string name="ssl_validator_reason_cert_not_trusted">- 不受信任的服务器证书</string>
+ <string name="ssl_validator_reason_cert_expired">- 服务器证书过期</string>
+ <string name="ssl_validator_reason_cert_not_yet_valid">- 服务器证书时间比当前时间还晚</string>
+ <string name="ssl_validator_reason_hostname_not_verified">- 主机名与证书中的记录不匹配</string>
<string name="ssl_validator_question">是否信任此证书?</string>
<string name="ssl_validator_not_saved">证书无法保存</string>
<string name="ssl_validator_btn_details_see">详细信息</string>
<string name="placeholder_filesize">389字节</string>
<string name="placeholder_timestamp">2012/05/18 下午12:23 </string>
<string name="placeholder_media_time">12:23:45</string>
- <string name="instant_upload_on_wifi">仅通过WIFI上传图片。</string>
- <string name="instant_video_upload_on_wifi">仅在 WIFI 下上传视频</string>
+ <string name="instant_upload_on_wifi">仅通过 WIFI 上传图片。</string>
+ <string name="instant_video_upload_on_wifi">仅通过 WIFI 上传视频</string>
<string name="instant_upload_path">/InstantUpload</string>
<string name="conflict_title">上传冲突</string>
<string name="conflict_message">远程文件 %s 未与本地文件同步。继续将替换服务器上的文件内容。</string>
<string name="conflict_overwrite">覆盖</string>
<string name="conflict_dont_upload">不上传</string>
<string name="preview_image_description">图片预览</string>
- <string name="preview_image_error_unknown_format">不能显示图片</string>
+ <string name="preview_image_error_unknown_format">无法显示图片</string>
<string name="error__upload__local_file_not_copied">无法复制 %1$s 到本地目录 %2$s</string>
+ <string name="prefs_instant_upload_path_title">上传路径</string>
<string name="share_link_no_support_share_api">抱歉,共享功能未启用。请联系管理员。</string>
<string name="share_link_file_no_exist">无法共享。请检查文件是否存在</string>
<string name="share_link_file_error">共享文件或目录出错</string>
<string name="unshare_link_file_no_exist">无法取消共享。请检查文件是否存在</string>
<string name="unshare_link_file_error">解除文件或目录共享时出错</string>
+ <string name="share_link_password_title">输入密码</string>
+ <string name="share_link_empty_password">您必须输入密码</string>
<string name="activity_chooser_send_file_title">发送</string>
<string name="copy_link">复制链接</string>
<string name="clipboard_text_copied">复制到剪贴板</string>
<string name="network_error_connect_timeout_exception">等待服务器响应时发生了一个错误,此操作无法完成</string>
<string name="network_host_not_available">服务器不可用,此操作无法完成</string>
<string name="empty"></string>
- <string name="forbidden_permissions">你没有许可%s</string>
+ <string name="forbidden_permissions">你没有权限%s</string>
<string name="forbidden_permissions_rename">重命名该文件</string>
<string name="forbidden_permissions_delete">删除该文件</string>
- <string name="share_link_forbidden_permissions">å\88\86享该文件</string>
+ <string name="share_link_forbidden_permissions">å\85±享该文件</string>
<string name="unshare_link_forbidden_permissions">取消共享该文件</string>
<string name="forbidden_permissions_create">创建文件</string>
- <string name="uploader_upload_forbidden_permissions">上传此文件夹</string>
+ <string name="uploader_upload_forbidden_permissions">在此文件夹上传</string>
<string name="downloader_download_file_not_found">该文件在服务器上不可用</string>
<string name="prefs_category_accounts">账号</string>
<string name="prefs_add_account">添加账号</string>
+ <string name="auth_redirect_non_secure_connection_title">安全连接被重定向到非安全路径.</string>
<string name="actionbar_logger">日志</string>
<string name="log_send_history_button">发送历史</string>
- <string name="log_mail_subject">ownCloud安卓客户端日志</string>
- <string name="log_progress_dialog_text">加载数据中...</string>
+ <string name="log_send_no_mail_app">未找到可以发送日志的程序。请安装 mail!</string>
+ <string name="log_send_mail_subject">%1$s Android 程序日志</string>
+ <string name="log_progress_dialog_text">载入数据...</string>
<string name="saml_authentication_required_text">需要认证</string>
<string name="saml_authentication_wrong_pass">错误密码</string>
<string name="actionbar_move">移动</string>
<string name="file_list_empty_moving">这里还什么都没有。上传些东西吧!</string>
- <string name="move_choose_button_text">选择(&C)...</string>
+ <string name="folder_picker_choose_button_text">选择</string>
<string name="move_file_not_found">无法移动。请检查文件是否存在</string>
- <string name="move_file_invalid_into_descendent">b不能够把一个目录移动到它的下级</string>
+ <string name="move_file_invalid_into_descendent">无法把一个目录移动到它的下级</string>
<string name="move_file_invalid_overwrite">该文件已经存在在目标文件夹</string>
<string name="move_file_error">尝试移动该文件或文件夹时发生错误</string>
<string name="forbidden_permissions_move">移动该文件</string>
+ <string name="prefs_category_instant_uploading">即时上传</string>
<string name="prefs_category_security">安全</string>
+ <string name="prefs_instant_video_upload_path_title">视频上传路径</string>
+ <string name="download_folder_failed_content">%1$s 文件夹的下载无法完成</string>
+ <string name="shared_subject_header">已共享</string>
+ <string name="with_you_subject_header">与你</string>
+ <string name="auth_refresh_button">刷新连接</string>
+ <string name="auth_host_address">服务器地址</string>
+ <string name="common_error_out_memory">内存不足</string>
+ <string name="username">用户名</string>
</resources>
<string name="actionbar_send_file">傳送</string>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
<string name="prefs_category_general">一般</string>
<string name="prefs_category_more">更多</string>
<string name="prefs_accounts">帳號</string>
<string name="sync_string_files">文件</string>
<string name="setup_btn_connect">連線</string>
<string name="uploader_btn_upload_text">上戴</string>
+ <string name="uploader_btn_new_folder_text">新資料夾</string>
<string name="uploader_wrn_no_account_title">找不到帳戶</string>
<string name="uploader_wrn_no_account_setup_btn_text">設定</string>
<string name="uploader_wrn_no_account_quit_btn_text">退出</string>
<string name="empty"></string>
<string name="prefs_category_accounts">帳號</string>
<string name="saml_authentication_wrong_pass">密碼錯誤</string>
+ <string name="prefs_category_security">安全</string>
+ <string name="auth_host_address">伺服器地址</string>
</resources>
</string-array>
<!--TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item>-->
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">所有檔案</string>
+ <!--TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">設定</string>
+ <string name="drawer_item_logs">紀錄</string>
+ <string name="drawer_close"> 關閉</string>
<string name="prefs_category_general">一般</string>
<string name="prefs_category_more">更多</string>
<string name="prefs_accounts">帳號</string>
<string name="prefs_manage_accounts">管理帳號</string>
- <string name="prefs_pincode">App 密碼</string>
- <string name="prefs_pincode_summary">保護您的 App 用戶端</string>
<string name="prefs_instant_upload">即時圖片上傳</string>
<string name="prefs_instant_upload_summary">即時上傳相機照片</string>
<string name="prefs_instant_video_upload">即時影像上傳</string>
<string name="sync_string_files">檔案</string>
<string name="setup_btn_connect">連線</string>
<string name="uploader_btn_upload_text">上傳</string>
+ <string name="uploader_btn_new_folder_text">新資料夾</string>
<string name="uploader_top_message">選取上傳目錄:</string>
<string name="uploader_wrn_no_account_title">找不到帳號</string>
<string name="uploader_wrn_no_account_text">在您的裝置上找不到 %1$s 的帳號. 請先設定一組帳號.</string>
<string name="uploader_info_uploading">上傳中</string>
<string name="file_list_seconds_ago">幾秒前</string>
<string name="file_list_empty">這裡還沒有東西,上傳一些吧!</string>
- <string name="file_list_loading">載入中…</string>
<string name="local_file_list_empty">這個目錄中沒有任何檔案.</string>
<string name="filedetails_select_file">在檔案上輕觸來顯示更多資訊。</string>
<string name="filedetails_size">容量:</string>
<string name="foreign_files_local_text">本地: %1$s</string>
<string name="foreign_files_remote_text">遠端: %1$s</string>
<string name="upload_query_move_foreign_files">無足夠的空間可以複製檔案到 %1$s 目錄. 是否使用移動的方式來處理? </string>
- <string name="pincode_enter_pin_code">請輸入您的 App 密碼</string>
- <string name="pincode_configure_your_pin">輸入您的 App 密碼</string>
- <string name="pincode_configure_your_pin_explanation">這個密碼在你每次啟動這程式時都會被要求輸入</string>
- <string name="pincode_reenter_your_pincode">請重新輸入您的 App 密碼</string>
- <string name="pincode_remove_your_pincode">移除您的 App 密碼</string>
- <string name="pincode_mismatch">App 密碼不相符</string>
- <string name="pincode_wrong">App 密碼不正確</string>
- <string name="pincode_removed">App 密碼已移除</string>
- <string name="pincode_stored">App 密碼已儲存</string>
<string name="media_notif_ticker">%1$s 音樂播放器</string>
<string name="media_state_playing">%1$s (播放中)</string>
<string name="media_state_loading">%1$s (載入中)</string>
<string name="auth_no_net_conn_title">沒有網際網路連線</string>
<string name="auth_nossl_plain_ok_title">安全連線不可用。</string>
<string name="auth_connection_established">連線已建立</string>
- <string name="auth_testing_connection">測試連線中…</string>
+ <string name="auth_testing_connection">測試連線</string>
<string name="auth_not_configured_title">伺服器設定有問題</string>
<string name="auth_account_not_new">已經有相同使用者與伺服器的帳號存在於這個裝置</string>
<string name="auth_account_not_the_same">輸入的使用者與這個帳戶的使用者不一致</string>
<string name="auth_fail_get_user_name">你的伺服器並沒有傳回正確的使用者 ID, 請聯絡伺服器的管理員
</string>
<string name="auth_can_not_auth_against_server">無法在這個伺服器上取得認證</string>
+ <string name="auth_account_does_not_exist">帳號目前不存在於本裝置</string>
<string name="fd_keep_in_sync">讓檔案保持最新的</string>
<string name="common_rename">重新命名</string>
<string name="common_remove">移除</string>
<string name="placeholder_filesize">389 KB</string>
<string name="placeholder_timestamp">2012/05/18 12:23 PM</string>
<string name="placeholder_media_time">12:23:45</string>
- <string name="instant_upload_on_wifi">å\8fªä½¿ç\94¨ WiFi ä¸\8aå\82³</string>
- <string name="instant_video_upload_on_wifi">只透過無線網路來執行即時影像上傳的功能</string>
+ <string name="instant_upload_on_wifi">å\8fªä½¿ç\94¨ WiFi ä¾\86å\9f·è¡\8cå\8d³æ\99\82å\9c\96ç\89\87ä¸\8aå\82³ç\9a\84å\8a\9fè\83½</string>
+ <string name="instant_video_upload_on_wifi">只使用 WiFi 來執行即時影像上傳的功能</string>
<string name="instant_upload_path">/InstantUpload</string>
<string name="conflict_title">更新衝突</string>
<string name="conflict_message">遠端檔案 %s 未同步到本地. 繼續將取代伺服器上的文件.</string>
<string name="share_link_file_error">在分享檔案或目錄時發生了錯誤</string>
<string name="unshare_link_file_no_exist">無法取消分享這個檔案或目錄. 請檢查它們是否存在</string>
<string name="unshare_link_file_error">在取消分享檔案或目錄時發生了錯誤</string>
+ <string name="share_link_password_title">輸入密碼</string>
+ <string name="share_link_empty_password">您必須輸入密碼</string>
<string name="activity_chooser_send_file_title">寄出</string>
<string name="copy_link">複製連結</string>
<string name="clipboard_text_copied">複製至剪貼簿中</string>
<string name="auth_redirect_non_secure_connection_title">安全連線被轉向到一個非安全的連線</string>
<string name="actionbar_logger">紀錄</string>
<string name="log_send_history_button">傳送歷史記錄</string>
- <string name="log_mail_subject">ownCloud Android 應用程式記錄</string>
+ <string name="log_send_no_mail_app">找不到可以傳送記錄的電子郵件程式. 請安裝電子郵件軟體!</string>
+ <string name="log_send_mail_subject">%1$s Android 應用程式記錄</string>
<string name="log_progress_dialog_text">資料載入中...</string>
<string name="saml_authentication_required_text">必須驗證</string>
<string name="saml_authentication_wrong_pass">密碼錯誤</string>
<string name="actionbar_move">移動</string>
<string name="file_list_empty_moving">找不到任何檔案. 你可以新增一個目錄!</string>
- <string name="move_choose_button_text">選擇</string>
+ <string name="folder_picker_choose_button_text">選擇</string>
<string name="move_file_not_found">無法搬移. 請檢查該檔案是否存在</string>
<string name="move_file_invalid_into_descendent">把一個目錄搬移到其底下的子目錄是不可能的</string>
<string name="move_file_invalid_overwrite">這個檔案已經存在於目的目錄中</string>
<string name="forbidden_permissions_move">移動這個檔案</string>
<string name="prefs_category_instant_uploading">即時上傳</string>
<string name="prefs_category_security">安全性</string>
+ <string name="prefs_instant_video_upload_path_title">影片上傳路徑</string>
+ <string name="download_folder_failed_content">%1$s 目錄的下載未完成</string>
+ <string name="shared_subject_header">以分享的</string>
+ <string name="with_you_subject_header">與你</string>
+ <string name="subject_token">%1$s 分享了 \"%2$s\" 給您</string>
+ <string name="auth_refresh_button">重新連線</string>
+ <string name="auth_host_address">伺服器位址</string>
+ <string name="username">使用者名稱</string>
</resources>
<!--
ownCloud Android client application
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<color name="filelist_icon_backgorund">#DDDDDD</color>
<color name="owncloud_blue_bright">#00ddff</color>
<color name="list_item_lastmod_and_filesize_text">#989898</color>
+ <color name="black">#000000</color>
+ <color name="textColor">#303030</color>
+ <color name="list_divider_background">#fff0f0f0</color>
</resources>
\ No newline at end of file
-->
<resources>
<dimen name="file_icon_size">32dp</dimen>
+ <dimen name="file_icon_size_grid">128dp</dimen>
</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ownCloud Android client application
+
+ Copyright (C) 2015 ownCloud Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2,
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<resources>
+ <!-- Nav Drawer Menu Items -->
+ <string-array name="drawer_items">
+ <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<item>@string/prefs_accounts</item>-->
+ <item>@string/drawer_item_all_files</item>
+ <!--<item>@string/drawer_item_on_device</item>-->
+ <item>@string/actionbar_settings</item>
+ <item>@string/actionbar_logger</item>
+ </string-array>
+
+ <!-- Nav Drawer Content Descriptions -->
+ <string-array name="drawer_content_descriptions">
+ <!-- TODO re-enable when "Accounts" is available in Navigation Drawer-->
+ <!--<item>@string/drawer_item_accounts</item>-->
+ <item>@string/drawer_item_all_files</item>
+ <!--<item>@string/drawer_item_on_device</item>-->
+ <item>@string/drawer_item_settings</item>
+ <item>@string/drawer_item_logs</item>
+ </string-array>
+
+</resources>
\ No newline at end of file
<string name ="data_folder">owncloud</string>
<string name ="log_name">Owncloud_</string>
<string name ="default_display_name_for_root_folder">ownCloud</string>
+ <string name ="user_agent">Mozilla/5.0 (Android) ownCloud-android/%1$s</string>
<!-- URLs and flags related -->
<string name="server_url"></string>
<!-- Flags to enable/disable some features -->
<string name = "send_files_to_other_apps">on</string>
+ <string name = "share_feature">on</string>
<!-- Colors -->
<!-- TODO re-enable when server-side folder size calculation is available
<item>Biggest - Smallest</item> -->
</string-array>
+ <!-- TODO re-enable when "Accounts" is available in Navigation Drawer -->
+ <!--<string name="drawer_item_accounts">Accounts</string>-->
+ <string name="drawer_item_all_files">All files</string>
+ <!-- TODO re-enable when "On Device" is available
+ <string name="drawer_item_on_device">On device</string>-->
+ <string name="drawer_item_settings">Settings</string>
+ <string name="drawer_item_logs">Logs</string>
+ <string name="drawer_close">Close</string>
<string name="prefs_category_general">General</string>
<string name="prefs_category_more">More</string>
<string name="prefs_accounts">Accounts</string>
<string name="prefs_manage_accounts">Manage Accounts</string>
- <string name="prefs_pincode">App PIN</string>
- <string name="prefs_pincode_summary">Protect your client</string>
+ <string name="prefs_passcode">Passcode lock</string>
<string name="prefs_instant_upload">Instant picture uploads</string>
<string name="prefs_instant_upload_summary">Instantly upload pictures taken by camera</string>
<string name="prefs_instant_video_upload">Instant video uploads</string>
<string name="sync_string_files">Files</string>
<string name="setup_btn_connect">Connect</string>
<string name="uploader_btn_upload_text">Upload</string>
+ <string name="uploader_btn_new_folder_text">New folder</string>
<string name="uploader_top_message">Choose upload folder:</string>
<string name="uploader_wrn_no_account_title">No account found</string>
<string name="uploader_wrn_no_account_text">There are no %1$s accounts on your device. Please setup an account first.</string>
<string name="uploader_info_uploading">Uploading</string>
<string name="file_list_seconds_ago">seconds ago</string>
<string name="file_list_empty">Nothing in here. Upload something!</string>
- <string name="file_list_loading">Loading...</string>
+ <string name="file_list_loading">Loading…</string>
<string name="local_file_list_empty">There are no files in this folder.</string>
<string name="filedetails_select_file">Tap on a file to display additional information.</string>
<string name="filedetails_size">Size:</string>
<string name="filedetails_download">Download</string>
<string name="filedetails_sync_file">Refresh file</string>
<string name="filedetails_renamed_in_upload_msg">File was renamed to %1$s during upload</string>
+ <string name="list_layout">List Layout</string>
<string name="action_share_file">Share link</string>
<string name="action_unshare_file">Unshare link</string>
<string name="common_yes">Yes</string>
<string name="foreign_files_local_text">"Local: %1$s"</string>
<string name="foreign_files_remote_text">"Remote: %1$s"</string>
<string name="upload_query_move_foreign_files">There is not space enough to copy the selected files into the %1$s folder. Would you like to move them instead? </string>
- <string name="pincode_enter_pin_code">Please, insert your App PIN</string>
+ <string name="pass_code_enter_pass_code">Please, insert your passcode</string>
- <string name="pincode_configure_your_pin">Enter your App PIN</string>
- <string name="pincode_configure_your_pin_explanation">The PIN will be requested every time the app is started</string>
- <string name="pincode_reenter_your_pincode">Please, reenter your App PIN</string>
- <string name="pincode_remove_your_pincode">Remove your App PIN</string>
- <string name="pincode_mismatch">The App PINs are not the same</string>
- <string name="pincode_wrong">Incorrect App PIN</string>
- <string name="pincode_removed">App PIN removed</string>
- <string name="pincode_stored">App PIN stored</string>
+ <string name="pass_code_configure_your_pass_code">Enter your passcode</string>
+ <string name="pass_code_configure_your_pass_code_explanation">The passcode will be requested every time the app is started</string>
+ <string name="pass_code_reenter_your_pass_code">Please, reenter your passcode</string>
+ <string name="pass_code_remove_your_pass_code">Remove your passcode</string>
+ <string name="pass_code_mismatch">The passcodes are not the same</string>
+ <string name="pass_code_wrong">Incorrect passcode</string>
+ <string name="pass_code_removed">Passcode removed</string>
+ <string name="pass_code_stored">Passcode stored</string>
<string name="media_notif_ticker">"%1$s music player"</string>
<string name="media_state_playing">"%1$s (playing)"</string>
<string name="auth_no_net_conn_title">No network connection</string>
<string name="auth_nossl_plain_ok_title">Secure connection unavailable.</string>
<string name="auth_connection_established">Connection established</string>
- <string name="auth_testing_connection">Testing connection…</string>
+ <string name="auth_testing_connection">Testing connection</string>
<string name="auth_not_configured_title">Malformed server configuration</string>
<string name="auth_account_not_new">An account for the same user and server already exists in the device</string>
<string name="auth_account_not_the_same">The entered user does not match the user of this account</string>
<string name="auth_fail_get_user_name">Your server is not returning a correct user id, please contact an administrator
</string>
<string name="auth_can_not_auth_against_server">Cannot authenticate against this server</string>
+ <string name="auth_account_does_not_exist">Account does not exist in the device yet</string>
<string name="fd_keep_in_sync">Keep file up to date</string>
<string name="common_rename">Rename</string>
<string name="sync_file_nothing_to_do_msg">File contents already synchronized</string>
<string name="create_dir_fail_msg">Folder could not be created</string>
<string name="filename_forbidden_characters">Forbidden characters: / \\ < > : " | ? *</string>
+ <string name="filename_forbidden_charaters_from_server">File name contains at least one invalid character</string>
<string name="filename_empty">File name cannot be empty</string>
<string name="wait_a_moment">Wait a moment</string>
<string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string>
<string name="filedisplay_no_file_selected">No file was selected</string>
<string name="activity_chooser_title">Send link to …</string>
+ <string name="wait_for_tmp_copy_from_private_storage">Copying file from private storage</string>
<string name="oauth_check_onoff">Login with oAuth2</string>
<string name="oauth_login_connection">Connecting to oAuth2 server…</string>
<string name="share_link_file_error">An error occurred while trying to share this file or folder</string>
<string name="unshare_link_file_no_exist">Unable to unshare. Please check whether the file exists</string>
<string name="unshare_link_file_error">An error occurred while trying to unshare this file or folder</string>
+ <string name="share_link_password_title">Enter a password</string>
+ <string name="share_link_empty_password">You must enter a password</string>
<string name="activity_chooser_send_file_title">Send</string>
<string name="network_error_connect_timeout_exception">An error occurred while waiting for the server, the operation couldn\'t have been done</string>
<string name="network_host_not_available">The operation couldn\'t be completed, server is unavailable</string>
- <string name="empty"></string>
+ <string name="empty" />
<string name="forbidden_permissions">You do not have permission %s</string>
<string name="forbidden_permissions_rename">to rename this file</string>
<string name="actionbar_logger">Logs</string>
<string name="log_send_history_button">Send History</string>
- <string name="log_mail_subject">ownCloud Android app logs</string>
- <string name="log_progress_dialog_text">Loading data...</string>
+ <string name="log_send_no_mail_app">No app for sending logs found. Install mail app!</string>
+ <string name="log_send_mail_subject">%1$s Android app logs</string>
+ <string name="log_progress_dialog_text">Loading data…</string>
<string name="saml_authentication_required_text">Authentication required</string>
<string name="saml_authentication_wrong_pass">Wrong password</string>
<string name="actionbar_move">Move</string>
<string name="file_list_empty_moving">Nothing in here. You can add a folder!</string>
- <string name="move_choose_button_text">Choose</string>
+ <string name="folder_picker_choose_button_text">Choose</string>
<string name="move_file_not_found">Unable to move. Please check whether the file exists</string>
<string name="move_file_invalid_into_descendent">It is not possible to move a folder into a descendant</string>
<string name="prefs_category_instant_uploading">Instant Uploads</string>
<string name="prefs_category_security">Security</string>
+
+ <string name="prefs_instant_video_upload_path_title">Upload Video Path</string>
+ <string name="download_folder_failed_content">Download of %1$s folder could not be completed</string>
+
+ <string name="shared_subject_header">shared</string>
+ <string name="with_you_subject_header">with you</string>
+
+ <string name="subject_token">%1$s shared \"%2$s\" with you</string>
+
+ <string name="auth_refresh_button">Refresh connection</string>
+ <string name="auth_host_address">Server address</string>
+ <string name="common_error_out_memory">Not enough memory</string>
+
+ <string name="username">Username</string>
+
+ <string name="file_list__footer__folder">1 folder</string>
+ <string name="file_list__footer__folders">%1$d folders</string>
+ <string name="file_list__footer__file">1 file</string>
+ <string name="file_list__footer__file_and_folder">1 file, 1 folder</string>
+ <string name="file_list__footer__file_and_folders">1 file, %1$d folders</string>
+ <string name="file_list__footer__files">%1$d files</string>
+ <string name="file_list__footer__files_and_folder">%1$d files, 1 folder</string>
+ <string name="file_list__footer__files_and_folders">%1$d files, %2$d folders</string>
+
</resources>
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
<style name="Animations" />
<!-- General ownCloud app style -->
- <style name="Theme.ownCloud" parent="style/Theme.Sherlock.Light.DarkActionBar">
+ <style name="Theme.ownCloud" parent="style/Theme.AppCompat.Light.DarkActionBar">
<item name="android:actionBarStyle">@style/Theme.ownCloud.Widget.ActionBar</item>
<item name="actionBarStyle">@style/Theme.ownCloud.Widget.ActionBar</item>
<item name="android:buttonStyle">@style/Theme.ownCloud.ButtonStyle</item>
- <item name="actionDropDownStyle">@style/Theme.ownCloud.DropDownStyle</item>
- <item name="android:actionDropDownStyle">@style/Theme.ownCloud.DropDownStyle</item>
</style>
- <style name="Theme.ownCloud.noActionBar" parent="style/Theme.Sherlock.Light.NoActionBar">
- <item name="android:actionBarStyle">@style/Theme.ownCloud.Widget.ActionBar</item>
- <item name="actionBarStyle">@style/Theme.ownCloud.Widget.ActionBar</item>
- <item name="android:buttonStyle">@style/Theme.ownCloud.ButtonStyle</item>
- <item name="actionDropDownStyle">@style/Theme.ownCloud.DropDownStyle</item>
- <item name="android:actionDropDownStyle">@style/Theme.ownCloud.DropDownStyle</item>
+ <style name="Theme.ownCloud.noActionBar" parent="style/Theme.AppCompat.Light">
+ <item name="android:buttonStyle">@style/Theme.ownCloud.ButtonStyle</item>
</style>
-
- <style name="Theme.ownCloud.Fullscreen" parent="style/Theme.Sherlock.NoActionBar">
- <item name="android:actionBarStyle">@style/Theme.ownCloud.Widget.ActionBar</item>
- <item name="actionBarStyle">@style/Theme.ownCloud.Widget.ActionBar</item>
- <item name="android:windowFullscreen">true</item>
- <item name="actionDropDownStyle">@style/Theme.ownCloud.DropDownStyle</item>
- <item name="android:actionDropDownStyle">@style/Theme.ownCloud.DropDownStyle</item>
+
+ <style name="Theme.ownCloud.Fullscreen" parent="style/Theme.AppCompat">
+ <item name="android:windowFullscreen">true</item>
</style>
- <style name="Theme.ownCloud.Widget.ActionBar" parent="style/Widget.Sherlock.Light.ActionBar.Solid.Inverse">
+ <style name="Theme.ownCloud.Widget.ActionBar"
+ parent="style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="android:background">@drawable/main_header_bg</item>
<item name="background">@drawable/main_header_bg</item>
<item name="android:textColor">#ffffff</item>
<item name="android:shadowRadius">1</item>
<item name="android:shadowDy">1</item>
<item name="android:backgroundSplit">@drawable/split_action_bg</item>
- <item name="android:indeterminateProgressStyle">@style/Theme.ownCloud.IndeterminateStyle</item>
- <item name="indeterminateProgressStyle">@style/Theme.ownCloud.IndeterminateStyle</item>
</style>
<!-- Dialogs -->
</style>
<!-- DropDown -->
- <style name="Theme.ownCloud.DropDownStyle" parent="style/Widget.Sherlock.Spinner.DropDown.ActionBar">
- <item name="android:background">@drawable/abs__spinner_ab_holo_dark</item>
+ <style name="Theme.ownCloud.DropDownStyle"
+ parent="style/Widget.AppCompat.Spinner.DropDown.ActionBar">
+ <!--<item name="android:background">@drawable/spinner_inner</item>-->
</style>
- <style name="Theme.ownCloud.IndeterminateStyle" parent="style/Widget.Sherlock.ProgressBar">
- <item name="android:indeterminateDrawable">@drawable/abs__progress_medium_holo</item>
+ <style name="Theme.ownCloud.IndeterminateStyle"
+ parent="style/Widget.AppCompat.ProgressBar">
+ <!--<item name="android:indeterminateDrawable">@drawable/abs__progress_medium_holo</item>-->
</style>
<!-- Notifications -->
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
</PreferenceCategory>
<PreferenceCategory android:title="@string/prefs_category_security">
- <!-- ListPreference
- android:key="select_oc_account"
- android:title="@string/prefs_select_oc_account"
- android:summary="@string/prefs_summary_select_oc_account"
- / -->
- <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:title="@string/prefs_pincode" android:key="set_pincode"
- android:summary="@string/prefs_pincode_summary"/>
+ <android.preference.CheckBoxPreference android:title="@string/prefs_passcode" android:key="set_pincode" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/prefs_category_instant_uploading">
<EditTextPreference android:title="@string/prefs_instant_upload_path_title"
android:defaultValue="@string/instant_upload_path"
android:key="instant_upload_path"/>
- <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:dependency="instant_uploading"
- android:disableDependentsState="true"
- android:title="@string/instant_upload_on_charging"
- android:key="instant_upload_on_charging"/>
<com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:key="instant_uploading"
android:title="@string/prefs_instant_upload"
android:summary="@string/prefs_instant_upload_summary"/>
- <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:dependency="instant_uploading"
- android:disableDependentsState="true"
+ <com.owncloud.android.ui.PreferenceWithLongSummary
+ android:title="@string/prefs_instant_upload_path_title"
+ android:key="instant_upload_path" />
+ <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
android:title="@string/instant_upload_on_wifi"
android:key="instant_upload_on_wifi"/>
<com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:key="instant_video_uploading"
android:title="@string/prefs_instant_video_upload"
- android:summary="@string/prefs_instant_video_upload_summary"/>
- <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:dependency="instant_video_uploading"
- android:disableDependentsState="true"
+ android:summary="@string/prefs_instant_video_upload_summary" />
+ <com.owncloud.android.ui.PreferenceWithLongSummary
+ android:title="@string/prefs_instant_video_upload_path_title"
+ android:key="instant_video_upload_path" />
+ <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
android:title="@string/instant_video_upload_on_wifi"
android:key="instant_video_upload_on_wifi"/>
<!-- DISABLED FOR RELEASE UNTIL FIXED
ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski
- Copyright (C) 2012-2013 ownCloud Inc.
+ Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
--- /dev/null
+include ':owncloud-android-library'
+include ':'
+@echo off
+
+:: Use argument to decide which build system should be used
+if "%1" == "gradle" goto initForGradle
+if "%1" == "maven" goto initForMaven
+if "%1" == "ant" goto initForAnt
+goto invalidInput
+
+:initForGradle
+echo "Executing Gradle setup..."
+goto initDefault
+
+:initForMaven
+echo "Executing Maven setup..."
+goto initDefault
+
+:initForAnt
+echo "Executing Ant setup..."
+::If the directory exists the script has already been executed
+
+::Gets the owncloud-android-library
call git submodule init
call git submodule update
-call android.bat update project -p actionbarsherlock\library -n ActionBarSherlock
+
+call android.bat update project -p libs/android-support-appcompat-v7-exploded-aar --target android-16
call android.bat update lib-project -p owncloud-android-library
call android.bat update project -p .
call android.bat update project -p oc_jb_workaround
-copy /Y third_party\android-support-library\android-support-v4.jar actionbarsherlock\library\libs\android-support-v4.jar
call android.bat update test-project -p tests -m ..
+
+goto complete
+
+:initDefault
+call git submodule init
+call git submodule update
+call android.bat update lib-project -p owncloud-android-library
+call android.bat update project -p .
+call android.bat update project -p oc_jb_workaround
+call android.bat update test-project -p tests -m ..
+goto complete
+
+:invalidInput
+echo "Input argument invalid."
+echo "Usage: %0 [ant | maven | gradle]."
+goto exit
+
+:complete
+echo "...setup complete."
+goto exit
+
+:exit
\ No newline at end of file
#!/bin/bash -e
-git submodule init
-git submodule update
-android update project -p actionbarsherlock/library -n ActionBarSherlock
-android update lib-project -p owncloud-android-library
-android update project -p .
-android update project -p oc_jb_workaround
-cp third_party/android-support-library/android-support-v4.jar actionbarsherlock/library/libs/android-support-v4.jar
-android update test-project -p tests -m ..
+
+function initDefault {
+ git submodule init
+ git submodule update
+ android update lib-project -p owncloud-android-library
+ android update project -p .
+ android update project -p oc_jb_workaround
+ android update test-project -p tests -m ..
+}
+
+function initForAnt {
+
+ #Gets the owncloud-android-library
+ git submodule init
+ git submodule update
+
+ #Prepare project android-support-appcompat-v7 ; JAR file is not enough, includes resources
+ android update lib-project -p libs/android-support-appcompat-v7-exploded-aar --target android-16
+
+ #As default it updates the ant scripts
+ android update lib-project -p owncloud-android-library
+ android update project -p .
+ android update project -p oc_jb_workaround
+ android update test-project -p tests -m ..
+}
+
+#No args
+if [ $# -lt 1 ]; then
+ echo "No args found"
+ echo "Usage : $0 [gradle | maven | ant]"
+ exit
+fi
+
+#checking args
+case "$1" in
+
+ "ant")
+ echo "Creating Ant environment"
+ initForAnt
+ ;;
+
+ "gradle") echo "Creating gradle environment"
+ initDefault
+ ;;
+
+ "maven") echo "Creating maven environment"
+ initDefault
+ ;;
+
+ *) echo "Argument not recognized"
+ echo "Usage : $0 [gradle | maven | ant]"
+ ;;
+esac
+
+exit
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
*/
package com.owncloud.android;
+import android.app.Activity;
import android.app.Application;
import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import com.owncloud.android.authentication.PassCodeManager;
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy;
import com.owncloud.android.lib.common.utils.Log_OC;
+
+
/**
* Main Application of the project
*
* Contains methods to build the "static" strings. These strings were before constants in different
* classes
- *
- * @author masensio
- * @author David A. Velasco
*/
public class MainApp extends Application {
-
+
+ private static final String TAG = MainApp.class.getSimpleName();
+
private static final String AUTH_ON = "on";
-
+
@SuppressWarnings("unused")
private static final String POLICY_SINGLE_SESSION_PER_ACCOUNT = "single session per account";
@SuppressWarnings("unused")
private static final String POLICY_ALWAYS_NEW_CLIENT = "always new client";
private static Context mContext;
+
+ // TODO Enable when "On Device" is recovered?
+ // TODO better place
+ // private static boolean mOnlyOnDevice = false;
+
public void onCreate(){
super.onCreate();
MainApp.mContext = getApplicationContext();
boolean isSamlAuth = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));
-
- if (isSamlAuth) {
+
+ OwnCloudClientManagerFactory.setUserAgent(getUserAgent());
+ if (isSamlAuth) {
OwnCloudClientManagerFactory.setDefaultPolicy(Policy.SINGLE_SESSION_PER_ACCOUNT);
-
} else {
OwnCloudClientManagerFactory.setDefaultPolicy(Policy.ALWAYS_NEW_CLIENT);
}
Log_OC.startLogging();
Log_OC.d("Debug", "start logging");
}
+
+ // register global protection with pass code
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ this.registerActivityLifecycleCallbacks( new ActivityLifecycleCallbacks() {
+
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ Log_OC.d(activity.getClass().getSimpleName(), "onCreate(Bundle) starting" );
+ PassCodeManager.getPassCodeManager().onActivityCreated(activity);
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ Log_OC.d(activity.getClass().getSimpleName(), "onStart() starting" );
+ PassCodeManager.getPassCodeManager().onActivityStarted(activity);
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ Log_OC.d(activity.getClass().getSimpleName(), "onResume() starting" );
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ Log_OC.d(activity.getClass().getSimpleName(), "onPause() ending");
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ Log_OC.d(activity.getClass().getSimpleName(), "onStop() ending" );
+ PassCodeManager.getPassCodeManager().onActivityStopped(activity);
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+ Log_OC.d(activity.getClass().getSimpleName(), "onSaveInstanceState(Bundle) starting" );
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ Log_OC.d(activity.getClass().getSimpleName(), "onDestroy() ending" );
+ }
+ });
+ }
}
public static Context getAppContext() {
return getAppContext().getResources().getString(R.string.log_name);
}
+ // TODO Enable when "On Device" is recovered ?
+// public static void showOnlyFilesOnDevice(boolean state){
+// mOnlyOnDevice = state;
+// }
+//
+// public static boolean getOnlyOnDevice(){
+// return mOnlyOnDevice;
+// }
+
+ // user agent
+ public static String getUserAgent() {
+ String appString = getAppContext().getResources().getString(R.string.user_agent);
+ String packageName = getAppContext().getPackageName();
+ String version = "";
+
+ PackageInfo pInfo = null;
+ try {
+ pInfo = getAppContext().getPackageManager().getPackageInfo(packageName, 0);
+ if (pInfo != null) {
+ version = pInfo.versionName;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log_OC.e(TAG, "Trying to get packageName", e.getCause());
+ }
+
+ // Mozilla/5.0 (Android) ownCloud-android/1.7.0
+ String userAgent = String.format(appString, version);
+
+ return userAgent;
+ }
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* Controller class accessed from the system AccountManager, providing integration of ownCloud accounts with the Android system.
*
* TODO - better separation in operations for OAuth-capable and regular ownCloud accounts.
- * TODO - review completeness
- *
- * @author David A. Velasco
+ * TODO - review completeness
*/
public class AccountAuthenticator extends AbstractAccountAuthenticator {
return bundle;
}
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- public Bundle confirmCredentials(AccountAuthenticatorResponse response,\r
- Account account, Bundle options) throws NetworkErrorException {\r
- try {\r
- validateAccountType(account.type);\r
- } catch (AuthenticatorException e) {\r
- Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "\r
- + e.getMessage());\r
- e.printStackTrace();\r
- return e.getFailureBundle();\r
- }\r
- Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
- response);\r
- intent.putExtra(KEY_ACCOUNT, account);\r
- intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-\r
- setIntentFlags(intent);\r
-\r
- Bundle resultBundle = new Bundle();\r
- resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
- return resultBundle;\r
- }\r
-\r
- @Override\r
- public Bundle editProperties(AccountAuthenticatorResponse response,\r
- String accountType) {\r
- return null;\r
- }\r
-\r
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Bundle confirmCredentials(AccountAuthenticatorResponse response,
+ Account account, Bundle options) throws NetworkErrorException {
+ try {
+ validateAccountType(account.type);
+ } catch (AuthenticatorException e) {
+ Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "
+ + e.getMessage());
+ e.printStackTrace();
+ 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) {
+ return null;
+ }
+
/**
* {@inheritDoc}
*/
}
}
- private void validateAuthTokenType(String authTokenType)\r
- throws UnsupportedAuthTokenTypeException {\r
- if (!authTokenType.equals(MainApp.getAuthTokenType()) &&\r
- !authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType())) &&\r
- !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType())) &&\r
+ private void validateAuthTokenType(String authTokenType)
+ throws UnsupportedAuthTokenTypeException {
+ if (!authTokenType.equals(MainApp.getAuthTokenType()) &&
+ !authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType())) &&
+ !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType())) &&
!authTokenType.equals(AccountTypeUtils.getAuthTokenTypeRefreshToken(MainApp.getAccountType())) &&
- !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()))) {\r
- throw new UnsupportedAuthTokenTypeException();\r
- }\r
- }\r
-\r
- public static class AuthenticatorException extends Exception {\r
- private static final long serialVersionUID = 1L;\r
- private Bundle mFailureBundle;\r
-\r
- public AuthenticatorException(int code, String errorMsg) {\r
- mFailureBundle = new Bundle();\r
- mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);\r
- mFailureBundle\r
- .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);\r
- }\r
-\r
- public Bundle getFailureBundle() {\r
- return mFailureBundle;\r
- }\r
- }\r
-\r
- public static class UnsupportedAccountTypeException extends\r
- AuthenticatorException {\r
- private static final long serialVersionUID = 1L;\r
-\r
- public UnsupportedAccountTypeException() {\r
- super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
- "Unsupported account type");\r
- }\r
- }\r
-\r
- public static class UnsupportedAuthTokenTypeException extends\r
- AuthenticatorException {\r
- private static final long serialVersionUID = 1L;\r
-\r
- public UnsupportedAuthTokenTypeException() {\r
- super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
- "Unsupported auth token type");\r
- }\r
- }\r
-\r
- public static class UnsupportedFeaturesException extends\r
- AuthenticatorException {\r
- public static final long serialVersionUID = 1L;\r
-\r
- public UnsupportedFeaturesException() {\r
- super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
- "Unsupported features");\r
- }\r
- }\r
-\r
- public static class AccessDeniedException extends AuthenticatorException {\r
- public AccessDeniedException(int code, String errorMsg) {\r
- super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");\r
- }\r
-\r
- private static final long serialVersionUID = 1L;\r
-\r
- }\r
-}\r
+ !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()))) {
+ throw new UnsupportedAuthTokenTypeException();
+ }
+ }
+
+ 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;
+
+ }
+}
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.os.Bundle;
-
-import com.actionbarsherlock.app.SherlockFragmentActivity;
-
+import android.support.v7.app.ActionBarActivity;
/*
* Base class for implementing an Activity that is used to help implement an AbstractAccountAuthenticator.
* then error AccountManager.ERROR_CODE_CANCELED will be called on the response.
*/
-public class AccountAuthenticatorActivity extends SherlockFragmentActivity {
+public class AccountAuthenticatorActivity extends ActionBarActivity {
private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null;
private Bundle mResultBundle = null;
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
* Copyright (C) 2012 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
\r
import com.owncloud.android.MainApp;\r
import com.owncloud.android.lib.common.accounts.AccountTypeUtils;\r
+import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;\r
+import com.owncloud.android.lib.common.utils.Log_OC;\r
import com.owncloud.android.lib.resources.status.OwnCloudVersion;\r
\r
import android.accounts.Account;\r
import android.accounts.AccountManager;\r
import android.content.Context;\r
import android.content.SharedPreferences;\r
+import android.net.Uri;\r
import android.preference.PreferenceManager;\r
\r
public class AccountUtils {\r
- public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";\r
- public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";\r
- public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav";\r
+\r
+ private static final String TAG = AccountUtils.class.getSimpleName();\r
+\r
+ public static final String WEBDAV_PATH_4_0_AND_LATER = "/remote.php/webdav";\r
private static final String ODAV_PATH = "/remote.php/odav";\r
private static final String SAML_SSO_PATH = "/remote.php/webdav";\r
- public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";\r
- public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php";\r
public static final String STATUS_PATH = "/status.php";\r
\r
+ public static final int ACCOUNT_VERSION = 1;\r
+\r
/**\r
* Can be used to get the currently selected ownCloud {@link Account} in the\r
* application preferences.\r
}\r
\r
\r
- /**\r
- * Checks, whether or not there are any ownCloud accounts setup.\r
- * \r
- * @return true, if there is at least one account.\r
- */\r
- public static boolean accountsAreSetup(Context context) {\r
- AccountManager accMan = AccountManager.get(context);\r
- Account[] accounts = accMan\r
- .getAccountsByType(MainApp.getAccountType());\r
- return accounts.length > 0;\r
- }\r
- \r
- \r
public static boolean setCurrentOwnCloudAccount(Context context, String accountName) {\r
boolean result = false;\r
if (accountName != null) {\r
Account[] ocAccounts = AccountManager.get(context).getAccountsByType(\r
MainApp.getAccountType());\r
- boolean found = false;\r
+ boolean found;\r
for (Account account : ocAccounts) {\r
found = (account.name.equals(accountName));\r
if (found) {\r
* according to its version and the authorization method used.\r
* \r
* @param version Version of ownCloud server.\r
- * @param authTokenType Authorization token type, matching some of the AUTH_TOKEN_TYPE_* constants in {@link AccountAuthenticator}. \r
- * @return WebDAV path for given OC version and authorization method, null if OC version is unknown.\r
+ * @param authTokenType Authorization token type, matching some of the AUTH_TOKEN_TYPE_* constants in\r
+ * {@link AccountAuthenticator}.\r
+ * @return WebDAV path for given OC version and authorization method, null if OC version\r
+ * is unknown; versions prior to ownCloud 4 are not supported anymore\r
*/\r
public static String getWebdavPath(OwnCloudVersion version, String authTokenType) {\r
if (version != null) {\r
if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(authTokenType)) {\r
return SAML_SSO_PATH;\r
}\r
- if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0)\r
- return WEBDAV_PATH_4_0;\r
- if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0\r
- || version.compareTo(OwnCloudVersion.owncloud_v2) >= 0)\r
- return WEBDAV_PATH_2_0;\r
- if (version.compareTo(OwnCloudVersion.owncloud_v1) >= 0)\r
- return WEBDAV_PATH_1_2;\r
+ return WEBDAV_PATH_4_0_AND_LATER;\r
}\r
return null;\r
}\r
- \r
+\r
+\r
+ /**\r
+ * Update the accounts in AccountManager to meet the current version of accounts expected by the app, if needed.\r
+ *\r
+ * Introduced to handle a change in the structure of stored account names needed to allow different OC servers\r
+ * in the same domain, but not in the same path.\r
+ *\r
+ * @param context Used to access the AccountManager.\r
+ */\r
+ public static void updateAccountVersion(Context context) {\r
+ Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(context);\r
+ AccountManager accountMgr = AccountManager.get(context);\r
+\r
+ if ( currentAccount != null ) {\r
+ String currentAccountVersion = accountMgr.getUserData(currentAccount, Constants.KEY_OC_ACCOUNT_VERSION);\r
+\r
+ if (currentAccountVersion == null) {\r
+ Log_OC.i(TAG, "Upgrading accounts to account version #" + ACCOUNT_VERSION);\r
+ Account[] ocAccounts = accountMgr.getAccountsByType(MainApp.getAccountType());\r
+ String serverUrl, username, newAccountName, password;\r
+ Account newAccount;\r
+ for (Account account : ocAccounts) {\r
+ // build new account name\r
+ serverUrl = accountMgr.getUserData(account, Constants.KEY_OC_BASE_URL);\r
+ username = account.name.substring(0, account.name.lastIndexOf('@'));\r
+ newAccountName = com.owncloud.android.lib.common.accounts.AccountUtils.\r
+ buildAccountName(Uri.parse(serverUrl), username);\r
+\r
+ // migrate to a new account, if needed\r
+ if (!newAccountName.equals(account.name)) {\r
+ Log_OC.d(TAG, "Upgrading " + account.name + " to " + newAccountName);\r
+\r
+ // create the new account\r
+ newAccount = new Account(newAccountName, MainApp.getAccountType());\r
+ password = accountMgr.getPassword(account);\r
+ accountMgr.addAccountExplicitly(newAccount, (password != null) ? password : "", null);\r
+\r
+ // copy base URL\r
+ accountMgr.setUserData(newAccount, Constants.KEY_OC_BASE_URL, serverUrl);\r
+\r
+ // copy server version\r
+ accountMgr.setUserData(\r
+ newAccount,\r
+ Constants.KEY_OC_VERSION,\r
+ accountMgr.getUserData(account, Constants.KEY_OC_VERSION)\r
+ );\r
+\r
+ // copy cookies\r
+ accountMgr.setUserData(\r
+ newAccount,\r
+ Constants.KEY_COOKIES,\r
+ accountMgr.getUserData(account, Constants.KEY_COOKIES)\r
+ );\r
+\r
+ // copy type of authentication\r
+ String isSamlStr = accountMgr.getUserData(account, Constants.KEY_SUPPORTS_SAML_WEB_SSO);\r
+ boolean isSaml = "TRUE".equals(isSamlStr);\r
+ if (isSaml) {\r
+ accountMgr.setUserData(newAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE");\r
+ }\r
+\r
+ String isOauthStr = accountMgr.getUserData(account, Constants.KEY_SUPPORTS_OAUTH2);\r
+ boolean isOAuth = "TRUE".equals(isOauthStr);\r
+ if (isOAuth) {\r
+ accountMgr.setUserData(newAccount, Constants.KEY_SUPPORTS_OAUTH2, "TRUE");\r
+ }\r
+ /* TODO - study if it's possible to run this method in a background thread to copy the authToken\r
+ if (isOAuth || isSaml) {\r
+ accountMgr.setAuthToken(newAccount, mAuthTokenType, mAuthToken);\r
+ }\r
+ */\r
+\r
+ // don't forget the account saved in preferences as the current one\r
+ if (currentAccount.name.equals(account.name)) {\r
+ AccountUtils.setCurrentOwnCloudAccount(context, newAccountName);\r
+ }\r
+\r
+ // remove the old account\r
+ accountMgr.removeAccount(account, null, null);\r
+ // will assume it succeeds, not a big deal otherwise\r
+\r
+ } else {\r
+ // servers which base URL is in the root of their domain need no change\r
+ Log_OC.d(TAG, account.name + " needs no upgrade ");\r
+ newAccount = account;\r
+ }\r
+\r
+ // at least, upgrade account version\r
+ Log_OC.d(TAG, "Setting version " + ACCOUNT_VERSION + " to " + newAccountName);\r
+ accountMgr.setUserData(\r
+ newAccount, Constants.KEY_OC_ACCOUNT_VERSION, Integer.toString(ACCOUNT_VERSION)\r
+ );\r
+\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ public static String trimWebdavSuffix(String url) {\r
+ while(url.endsWith("/")) {\r
+ url = url.substring(0, url.length() - 1);\r
+ }\r
+ int pos = url.lastIndexOf(WEBDAV_PATH_4_0_AND_LATER);\r
+ if (pos >= 0) {\r
+ url = url.substring(0, pos);\r
+\r
+ } else {\r
+ pos = url.lastIndexOf(ODAV_PATH);\r
+ if (pos >= 0) {\r
+ url = url.substring(0, pos);\r
+ }\r
+ }\r
+ return url;\r
+ }\r
+\r
+ /**\r
+ * Access the version of the OC server corresponding to an account SAVED IN THE ACCOUNTMANAGER\r
+ *\r
+ * @param account ownCloud account\r
+ * @return Version of the OC server corresponding to account, according to the data saved\r
+ * in the system AccountManager\r
+ */\r
+ public static OwnCloudVersion getServerVersion(Account account) {\r
+ OwnCloudVersion serverVersion = null;\r
+ if (account != null) {\r
+ AccountManager accountMgr = AccountManager.get(MainApp.getAppContext());\r
+ String serverVersionStr = accountMgr.getUserData(account, Constants.KEY_OC_VERSION);\r
+ if (serverVersionStr != null) {\r
+ serverVersion = new OwnCloudVersion(serverVersionStr);\r
+ }\r
+ }\r
+ return serverVersion;\r
+ }\r
+\r
}\r
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
+ * @author Bartek Przybylski\r
+ * @author David A. Velasco\r
+ * @author masensio\r
* Copyright (C) 2012 Bartek Przybylski\r
- * Copyright (C) 2012-2014 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
import android.os.Handler;\r
import android.os.IBinder;\r
import android.preference.PreferenceManager;\r
+import android.support.v4.app.DialogFragment;\r
import android.support.v4.app.Fragment;\r
import android.support.v4.app.FragmentManager;\r
import android.support.v4.app.FragmentTransaction;\r
import android.view.View;\r
import android.view.View.OnFocusChangeListener;\r
import android.view.View.OnTouchListener;\r
-import android.view.Window;\r
import android.view.inputmethod.EditorInfo;\r
import android.webkit.HttpAuthHandler;\r
import android.webkit.SslErrorHandler;\r
import android.widget.TextView.OnEditorActionListener;\r
import android.widget.Toast;\r
\r
-import com.actionbarsherlock.app.SherlockDialogFragment;\r
import com.owncloud.android.MainApp;\r
import com.owncloud.android.R;\r
import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;\r
+import com.owncloud.android.lib.common.OwnCloudCredentials;\r
+import com.owncloud.android.lib.common.OwnCloudCredentialsFactory;\r
import com.owncloud.android.lib.common.accounts.AccountTypeUtils;\r
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;\r
import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;\r
import com.owncloud.android.lib.common.network.CertificateCombinedException;\r
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;\r
import com.owncloud.android.lib.common.operations.RemoteOperationResult;\r
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;\r
import com.owncloud.android.lib.common.utils.Log_OC;\r
-import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;\r
import com.owncloud.android.lib.resources.status.OwnCloudVersion;\r
import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation;\r
import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod;\r
\r
/**\r
* This Activity is used to add an ownCloud account to the App\r
- * \r
- * @author Bartek Przybylski\r
- * @author David A. Velasco\r
- * @author masensio\r
*/\r
public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
-implements OnRemoteOperationListener, OnFocusChangeListener, OnEditorActionListener, \r
-SsoWebViewClientListener, OnSslUntrustedCertListener {\r
+ implements OnRemoteOperationListener, OnFocusChangeListener, OnEditorActionListener,\r
+ SsoWebViewClientListener, OnSslUntrustedCertListener,\r
+ AuthenticatorAsyncTask.OnAuthenticatorTaskListener {\r
\r
private static final String TAG = AuthenticatorActivity.class.getSimpleName();\r
\r
private static final String CREDENTIALS_DIALOG_TAG = "CREDENTIALS_DIALOG";\r
private static final String KEY_AUTH_IS_FIRST_ATTEMPT_TAG = "KEY_AUTH_IS_FIRST_ATTEMPT";\r
\r
+ private static final String KEY_USERNAME = "USERNAME";\r
+ private static final String KEY_PASSWORD = "PASSWORD";\r
+ private static final String KEY_ASYNC_TASK_IN_PROGRESS = "AUTH_IN_PROGRESS";\r
\r
/// parameters from EXTRAs in starter Intent\r
private byte mAction;\r
private int mAuthStatusText = 0, mAuthStatusIcon = 0;\r
\r
private String mAuthToken = "";\r
+ private AuthenticatorAsyncTask mAsyncTask;\r
\r
private boolean mIsFirstAuthAttempt;\r
-\r
\r
/// Identifier of operation in progress which result shouldn't be lost \r
private long mWaitingForOpId = Long.MAX_VALUE;\r
\r
- \r
+ private final String BASIC_TOKEN_TYPE = AccountTypeUtils.getAuthTokenTypePass(\r
+ MainApp.getAccountType());\r
+ private final String OAUTH_TOKEN_TYPE = AccountTypeUtils.getAuthTokenTypeAccessToken(\r
+ MainApp.getAccountType());\r
+ private final String SAML_TOKEN_TYPE =\r
+ AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
+\r
+\r
/**\r
* {@inheritDoc}\r
* \r
protected void onCreate(Bundle savedInstanceState) {\r
//Log_OC.wtf(TAG, "onCreate init");\r
super.onCreate(savedInstanceState);\r
- getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
+\r
+ // Workaround, for fixing a problem with Android Library Suppor v7 19\r
+ //getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
+ if (getSupportActionBar() != null) {\r
+ getSupportActionBar().hide();\r
+\r
+ getSupportActionBar().setDisplayHomeAsUpEnabled(false);\r
+ getSupportActionBar().setDisplayShowHomeEnabled(false);\r
+ getSupportActionBar().setDisplayShowTitleEnabled(false);\r
+ }\r
\r
mIsFirstAuthAttempt = true;\r
\r
setContentView(R.layout.account_setup);\r
\r
/// initialize general UI elements\r
- initOverallUi(savedInstanceState);\r
+ initOverallUi();\r
\r
mOkButton = findViewById(R.id.buttonOK);\r
\r
\r
private String chooseAuthTokenType(boolean oauth, boolean saml) {\r
if (saml) {\r
- return AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
+ return SAML_TOKEN_TYPE;\r
} else if (oauth) {\r
- return AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
+ return OAUTH_TOKEN_TYPE;\r
} else {\r
- return AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
+ return BASIC_TOKEN_TYPE;\r
}\r
}\r
\r
\r
/**\r
* Configures elements in the user interface under direct control of the Activity.\r
- * \r
- * @param savedInstanceState Saved activity state, as in {{@link #onCreate(Bundle)}\r
*/\r
- private void initOverallUi(Bundle savedInstanceState) {\r
+ private void initOverallUi() {\r
\r
/// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)\r
boolean isWelcomeLinkVisible = getResources().getBoolean(R.bool.show_welcome_link);\r
if (mAccount != null) {\r
mServerInfo.mBaseUrl = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_BASE_URL);\r
// TODO do next in a setter for mBaseUrl\r
- mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith("https://"); \r
- String ocVersion = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_VERSION);\r
- if (ocVersion != null) {\r
- mServerInfo.mVersion = new OwnCloudVersion(ocVersion);\r
- }\r
+ mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith("https://");\r
+ mServerInfo.mVersion = AccountUtils.getServerVersion(mAccount);\r
} else {\r
mServerInfo.mBaseUrl = getString(R.string.server_url).trim();\r
mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith("https://");\r
findViewById(R.id.hostUrlFrame).setVisibility(View.GONE);\r
mRefreshButton = findViewById(R.id.centeredRefreshButton);\r
}\r
- showRefreshButton(mServerIsChecked && !mServerIsValid && \r
+ showRefreshButton(mServerIsChecked && !mServerIsValid &&\r
mWaitingForOpId > Integer.MAX_VALUE);\r
mServerStatusView = (TextView) findViewById(R.id.server_status_text);\r
showServerStatus();\r
if (\r
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(\r
MainApp.getAccountType()\r
- ).equals(mAuthTokenType) &&\r
- mHostUrlInput.hasFocus()\r
- ) {\r
+ ).equals(mAuthTokenType) &&\r
+ mHostUrlInput.hasFocus()\r
+ ) {\r
checkOcServer();\r
}\r
}\r
* intended to defer the processing of the redirection caught in \r
* {@link #onNewIntent(Intent)} until {@link #onResume()} \r
* \r
- * See {@link #loadSavedInstanceState(Bundle)}\r
+ * See {@link super#onSaveInstanceState(Bundle)}\r
*/\r
@Override\r
protected void onSaveInstanceState(Bundle outState) {\r
/// authentication\r
outState.putBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG, mIsFirstAuthAttempt);\r
\r
+ /// AsyncTask (User and password)\r
+ outState.putString(KEY_USERNAME, mUsernameInput.getText().toString());\r
+ outState.putString(KEY_PASSWORD, mPasswordInput.getText().toString());\r
+\r
+ if (mAsyncTask != null) {\r
+ mAsyncTask.cancel(true);\r
+ outState.putBoolean(KEY_ASYNC_TASK_IN_PROGRESS, true);\r
+ } else {\r
+ outState.putBoolean(KEY_ASYNC_TASK_IN_PROGRESS, false);\r
+ }\r
+ mAsyncTask = null;\r
+\r
//Log_OC.wtf(TAG, "onSaveInstanceState end" );\r
}\r
\r
+ @Override\r
+ public void onRestoreInstanceState(Bundle savedInstanceState) {\r
+ super.onRestoreInstanceState(savedInstanceState);\r
+\r
+ // AsyncTask\r
+ boolean inProgress = savedInstanceState.getBoolean(KEY_ASYNC_TASK_IN_PROGRESS);\r
+ if (inProgress){\r
+ String username = savedInstanceState.getString(KEY_USERNAME);\r
+ String password = savedInstanceState.getString(KEY_PASSWORD);\r
+\r
+ OwnCloudCredentials credentials = null;\r
+ if (BASIC_TOKEN_TYPE.equals(mAuthTokenType)) {\r
+ credentials = OwnCloudCredentialsFactory.newBasicCredentials(username, password);\r
+\r
+ } else if (OAUTH_TOKEN_TYPE.equals(mAuthTokenType)) {\r
+ credentials = OwnCloudCredentialsFactory.newBearerCredentials(mAuthToken);\r
+\r
+ }\r
+ accessRootFolder(credentials);\r
+ }\r
+ }\r
\r
/**\r
* The redirection triggered by the OAuth authentication server as response to the \r
*/\r
@Override\r
protected void onResume() {\r
- //Log_OC.wtf(TAG, "onResume init" );\r
super.onResume();\r
\r
// bound here to avoid spurious changes triggered by Android on device rotations\r
doOnResumeAndBound();\r
}\r
\r
- //Log_OC.wtf(TAG, "onResume end" );\r
}\r
\r
\r
@Override\r
protected void onPause() {\r
- //Log_OC.wtf(TAG, "onPause init" );\r
if (mOperationsServiceBinder != null) {\r
- //Log_OC.wtf(TAG, "unregistering to listen for operation callbacks" );\r
mOperationsServiceBinder.removeOperationListener(this);\r
}\r
\r
mHostUrlInput.setOnFocusChangeListener(null);\r
\r
super.onPause();\r
- //Log_OC.wtf(TAG, "onPause end" );\r
}\r
\r
@Override\r
\r
if (mOperationsServiceBinder != null) {\r
//Log_OC.wtf(TAG, "getting access token..." );\r
- mWaitingForOpId = mOperationsServiceBinder.newOperation(getServerInfoIntent);\r
+ mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getServerInfoIntent);\r
}\r
}\r
\r
public void onFocusChange(View view, boolean hasFocus) {\r
if (view.getId() == R.id.hostUrlInput) { \r
if (!hasFocus) {\r
- onUrlInputFocusLost((TextView) view);\r
+ onUrlInputFocusLost();\r
}\r
else {\r
showRefreshButton(false);\r
}\r
\r
} else if (view.getId() == R.id.account_password) {\r
- onPasswordFocusChanged((TextView) view, hasFocus);\r
+ onPasswordFocusChanged(hasFocus);\r
}\r
}\r
\r
* started. \r
* \r
* When hasFocus: user 'comes back' to write again the server URL.\r
- * \r
- * @param hostInput TextView with the URL input field receiving the change of focus.\r
*/\r
- private void onUrlInputFocusLost(TextView hostInput) {\r
+ private void onUrlInputFocusLost() {\r
if (!mServerInfo.mBaseUrl.equals(\r
normalizeUrl(mHostUrlInput.getText().toString(), mServerInfo.mIsSslConn))) {\r
// check server again only if the user changed something in the field\r
mOkButton.setEnabled(false);\r
mServerInfo = new GetServerInfoOperation.ServerInfo();\r
showRefreshButton(false);\r
- \r
+\r
if (uri.length() != 0) {\r
// Handle internationalized domain names\r
uri = DisplayUtils.convertIdn(uri, true);\r
+\r
mServerStatusText = R.string.auth_testing_connection;\r
mServerStatusIcon = R.drawable.progress_small;\r
showServerStatus();\r
Intent getServerInfoIntent = new Intent();\r
getServerInfoIntent.setAction(OperationsService.ACTION_GET_SERVER_INFO);\r
getServerInfoIntent.putExtra(\r
- OperationsService.EXTRA_SERVER_URL, \r
+ OperationsService.EXTRA_SERVER_URL,\r
normalizeUrlSuffix(uri)\r
);\r
if (mOperationsServiceBinder != null) {\r
- mWaitingForOpId = mOperationsServiceBinder.newOperation(getServerInfoIntent);\r
+ mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getServerInfoIntent);\r
} else {\r
Log_OC.wtf(TAG, "Server check tried with OperationService unbound!" );\r
}\r
* \r
* When (!hasFocus), the button is made invisible and the password is hidden.\r
* \r
- * @param passwordInput TextView with the password input field receiving the change of focus.\r
* @param hasFocus 'True' if focus is received, 'false' if is lost\r
*/\r
- private void onPasswordFocusChanged(TextView passwordInput, boolean hasFocus) {\r
+ private void onPasswordFocusChanged(boolean hasFocus) {\r
if (hasFocus) {\r
showViewPasswordButton();\r
} else {\r
mServerStatusText = R.string.auth_wtf_reenter_URL;\r
showServerStatus();\r
mOkButton.setEnabled(false);\r
- //Log_OC.wtf(TAG, "The user was allowed to click 'connect' to an unchecked server!!");\r
return;\r
}\r
\r
dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
\r
/// validate credentials accessing the root folder\r
- accessRootFolderRemoteOperation(username, password);\r
- \r
+ OwnCloudCredentials credentials = OwnCloudCredentialsFactory.newBasicCredentials(username,\r
+ password);\r
+ accessRootFolder(credentials);\r
}\r
\r
- private void accessRootFolderRemoteOperation(String username, String password) {\r
- Intent existenceCheckIntent = new Intent();\r
- existenceCheckIntent.setAction(OperationsService.ACTION_EXISTENCE_CHECK);\r
- existenceCheckIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mServerInfo.mBaseUrl);\r
- existenceCheckIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, "/");\r
- existenceCheckIntent.putExtra(OperationsService.EXTRA_USERNAME, username);\r
- existenceCheckIntent.putExtra(OperationsService.EXTRA_PASSWORD, password);\r
- existenceCheckIntent.putExtra(OperationsService.EXTRA_AUTH_TOKEN, mAuthToken);\r
- \r
- if (mOperationsServiceBinder != null) {\r
- //Log_OC.wtf(TAG, "starting existenceCheckRemoteOperation..." );\r
- mWaitingForOpId = mOperationsServiceBinder.newOperation(existenceCheckIntent);\r
- }\r
+ private void accessRootFolder(OwnCloudCredentials credentials) {\r
+ mAsyncTask = new AuthenticatorAsyncTask(this);\r
+ Object[] params = { mServerInfo.mBaseUrl, credentials };\r
+ mAsyncTask.execute(params);\r
}\r
\r
+\r
/**\r
* Starts the OAuth 'grant type' flow to get an access token, with \r
* a GET AUTHORIZATION request to the BUILT-IN authorization server. \r
* in the server.\r
*/\r
private void startSamlBasedFederatedSingleSignOnAuthorization() {\r
- // be gentle with the user\r
+ /// be gentle with the user\r
mAuthStatusIcon = R.drawable.progress_small;\r
mAuthStatusText = R.string.auth_connecting_auth_server;\r
showAuthStatus();\r
- IndeterminateProgressDialog dialog = \r
- IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);\r
- dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
-\r
- /// validate credentials accessing the root folder\r
- accessRootFolderRemoteOperation("", "");\r
\r
+ /// Show SAML-based SSO web dialog\r
+ String targetUrl = mServerInfo.mBaseUrl\r
+ + AccountUtils.getWebdavPath(mServerInfo.mVersion, mAuthTokenType);\r
+ SamlWebViewDialog dialog = SamlWebViewDialog.newInstance(targetUrl, targetUrl);\r
+ dialog.show(getSupportFragmentManager(), SAML_DIALOG_TAG);\r
}\r
\r
/**\r
} else if (operation instanceof OAuth2GetAccessToken) {\r
onGetOAuthAccessTokenFinish(result);\r
\r
- } else if (operation instanceof ExistenceCheckRemoteOperation) {\r
- //Log_OC.wtf(TAG, "received detection response through callback" );\r
- if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
- equals(mAuthTokenType)) {\r
- onSamlBasedFederatedSingleSignOnAuthorizationStart(result);\r
-\r
- } else {\r
- onAuthorizationCheckFinish(result);\r
- }\r
} else if (operation instanceof GetRemoteUserNameOperation) {\r
onGetUserNameFinish(result);\r
}\r
\r
if ( mAction == ACTION_CREATE) {\r
mUsernameInput.setText(username);\r
- success = createAccount();\r
+ success = createAccount(result);\r
} else {\r
\r
if (!mUsernameInput.getText().toString().equals(username)) {\r
// fail - not a new account, but an existing one; disallow\r
result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME);\r
- /*\r
- OwnCloudClientManagerFactory.getDefaultSingleton().removeClientFor(\r
- new OwnCloudAccount(\r
- Uri.parse(mServerInfo.mBaseUrl),\r
- OwnCloudCredentialsFactory.newSamlSsoCredentials(mAuthToken))\r
- );\r
- */\r
mAuthToken = "";\r
updateAuthStatusIconAndText(result);\r
showAuthStatus();\r
Log_OC.d(TAG, result.getLogMessage());\r
} else {\r
- updateToken();\r
- success = true;\r
+ try {\r
+ updateAccountAuthentication();\r
+ success = true;\r
+\r
+ } catch (AccountNotFoundException e) {\r
+ Log_OC.e(TAG, "Account " + mAccount + " was removed!", e);\r
+ Toast.makeText(this, R.string.auth_account_does_not_exist,\r
+ Toast.LENGTH_SHORT).show();\r
+ finish();\r
+ }\r
}\r
}\r
\r
\r
}\r
\r
- private void onSamlBasedFederatedSingleSignOnAuthorizationStart(RemoteOperationResult result) {\r
- mWaitingForOpId = Long.MAX_VALUE;\r
- dismissDialog(WAIT_DIALOG_TAG);\r
-
- if (result.isIdPRedirection()) {
- String url = result.getRedirectedLocation();\r
- String targetUrl = mServerInfo.mBaseUrl \r
- + AccountUtils.getWebdavPath(mServerInfo.mVersion, mAuthTokenType);\r
-\r
- // Show dialog\r
- SamlWebViewDialog dialog = SamlWebViewDialog.newInstance(url, targetUrl); \r
- dialog.show(getSupportFragmentManager(), SAML_DIALOG_TAG);\r
-\r
- mAuthStatusIcon = 0;\r
- mAuthStatusText = 0;\r
-\r
- } else {\r
- mAuthStatusIcon = R.drawable.common_error;\r
- mAuthStatusText = R.string.auth_unsupported_auth_method;\r
-\r
- }\r
- showAuthStatus();\r
- }\r
-\r
-\r
/**\r
* Processes the result of the server check performed when the user finishes the enter of the\r
* server URL.\r
- * \r
- * @param operation Server check performed.\r
+ *\r
* @param result Result of the check.\r
*/\r
private void onGetServerInfoFinish(RemoteOperationResult result) {\r
\r
\r
private boolean authSupported(AuthenticationMethod authMethod) {\r
- String basic = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
- String oAuth = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
- String saml = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
- \r
- return (( mAuthTokenType.equals(basic) && \r
- authMethod.equals(AuthenticationMethod.BASIC_HTTP_AUTH) ) ||\r
- ( mAuthTokenType.equals(oAuth) && \r
- authMethod.equals(AuthenticationMethod.BEARER_TOKEN)) ||\r
- ( mAuthTokenType.equals(saml) && \r
- authMethod.equals(AuthenticationMethod.SAML_WEB_SSO))\r
+ return (( BASIC_TOKEN_TYPE.equals(mAuthTokenType) &&\r
+ AuthenticationMethod.BASIC_HTTP_AUTH.equals(authMethod) ) ||\r
+ ( OAUTH_TOKEN_TYPE.equals(mAuthTokenType) &&\r
+ AuthenticationMethod.BEARER_TOKEN.equals(authMethod)) ||\r
+ ( SAML_TOKEN_TYPE.equals(mAuthTokenType) &&\r
+ AuthenticationMethod.SAML_WEB_SSO.equals(authMethod))\r
);\r
}\r
\r
url = "http://" + url;\r
}\r
}\r
- \r
+\r
url = normalizeUrlSuffix(url);\r
}\r
return (url != null ? url : "");\r
\r
// TODO remove, if possible\r
private String trimUrlWebdav(String url){ \r
- if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_4_0)){\r
- url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_4_0.length()); \r
- } else if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_2_0)){\r
- url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_2_0.length()); \r
- } else if (url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_1_2)){\r
- url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_1_2.length()); \r
- } \r
- return (url != null ? url : "");\r
+ if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_4_0_AND_LATER)){\r
+ url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_4_0_AND_LATER.length());\r
+ }\r
+ return url;\r
}\r
\r
\r
Map<String, String> tokens = (Map<String, String>)(result.getData().get(0));\r
mAuthToken = tokens.get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
Log_OC.d(TAG, "Got ACCESS TOKEN: " + mAuthToken);\r
- \r
- accessRootFolderRemoteOperation("", "");\r
+\r
+ /// validate token accessing to root folder / getting session\r
+ OwnCloudCredentials credentials = OwnCloudCredentialsFactory.newBearerCredentials(\r
+ mAuthToken);\r
+ accessRootFolder(credentials);\r
\r
} else {\r
updateAuthStatusIconAndText(result);\r
* Processes the result of the access check performed to try the user credentials.\r
* \r
* Creates a new account through the AccountManager.\r
- * \r
- * @param operation Access check performed.\r
+ *\r
* @param result Result of the operation.\r
*/\r
- private void onAuthorizationCheckFinish(RemoteOperationResult result) {\r
+ @Override\r
+ public void onAuthenticatorTaskCallback(RemoteOperationResult result) {\r
mWaitingForOpId = Long.MAX_VALUE;\r
dismissDialog(WAIT_DIALOG_TAG);\r
\r
Log_OC.d(TAG, "Successful access - time to save the account");\r
\r
boolean success = false;\r
+\r
if (mAction == ACTION_CREATE) {\r
- success = createAccount();\r
+ success = createAccount(result);\r
\r
} else {\r
- updateToken();\r
- success = true;\r
+ try {\r
+ updateAccountAuthentication();\r
+ success = true;\r
+\r
+ } catch (AccountNotFoundException e) {\r
+ Log_OC.e(TAG, "Account " + mAccount + " was removed!", e);\r
+ Toast.makeText(this, R.string.auth_account_does_not_exist,\r
+ Toast.LENGTH_SHORT).show();\r
+ finish();\r
+ }\r
}\r
\r
if (success) {\r
finish();\r
}\r
\r
- } else if (result.isServerFail() || result.isException()) {
+ } else if (result.isServerFail() || result.isException()) {\r
/// server errors or exceptions in authorization take to requiring a new check of \r
/// the server\r
mServerIsChecked = true;\r
\r
\r
/**\r
- * Sets the proper response to get that the Account Authenticator that started this activity \r
+ * Updates the authentication token.\r
+ *\r
+ * Sets the proper response so that the AccountAuthenticator that started this activity\r
* saves a new authorization token for mAccount.\r
+ *\r
+ * Kills the session kept by OwnCloudClientManager so that a new one will created with\r
+ * the new credentials when needed.\r
*/\r
- private void updateToken() {\r
+ private void updateAccountAuthentication() throws AccountNotFoundException {\r
+ \r
Bundle response = new Bundle();\r
response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);\r
response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);\r
\r
if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).\r
- equals(mAuthTokenType)) { \r
+ equals(mAuthTokenType)) {\r
response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);\r
// the next line is necessary, notifications are calling directly to the \r
// AuthenticatorActivity to update, without AccountManager intervention\r
* \r
* TODO Decide how to name the OAuth accounts\r
*/\r
- private boolean createAccount() {\r
+ private boolean createAccount(RemoteOperationResult authResult) {\r
/// create and save new ownCloud account\r
boolean isOAuth = AccountTypeUtils.\r
getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType);\r
boolean isSaml = AccountTypeUtils.\r
getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType);\r
\r
+ String lastPermanentLocation = authResult.getLastPermanentLocation();\r
+ if (lastPermanentLocation != null) {\r
+ mServerInfo.mBaseUrl = AccountUtils.trimWebdavSuffix(lastPermanentLocation);\r
+ }\r
+\r
Uri uri = Uri.parse(mServerInfo.mBaseUrl);\r
String username = mUsernameInput.getText().toString().trim();\r
if (isOAuth) {\r
);\r
}\r
\r
+ // include account version with the new account\r
+ mAccountMgr.setUserData(\r
+ mAccount,\r
+ Constants.KEY_OC_ACCOUNT_VERSION,\r
+ Integer.toString(AccountUtils.ACCOUNT_VERSION)\r
+ );\r
+\r
/// add the new account as default in preferences, if there is none already\r
Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);\r
if (defaultAccount == null) {\r
final Intent intent = new Intent(); \r
intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, MainApp.getAccountType());\r
intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);\r
- /*if (!isOAuth)\r
- intent.putExtra(AccountManager.KEY_AUTHTOKEN, MainApp.getAccountType()); */\r
intent.putExtra(AccountManager.KEY_USERDATA, username);\r
if (isOAuth || isSaml) {\r
mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);\r
}\r
/// add user data to the new account; TODO probably can be done in the last parameter \r
- // addAccountExplicitly, or in KEY_USERDATA
+ // addAccountExplicitly, or in KEY_USERDATA\r
mAccountMgr.setUserData(\r
- mAccount, Constants.KEY_OC_VERSION, mServerInfo.mVersion.getVersion()\r
+ mAccount, Constants.KEY_OC_VERSION, mServerInfo.mVersion.getVersion()\r
);\r
mAccountMgr.setUserData(\r
mAccount, Constants.KEY_OC_BASE_URL, mServerInfo.mBaseUrl\r
);\r
-
+\r
if (isSaml) {\r
mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE"); \r
} else if (isOAuth) {\r
/**\r
* Updates the content and visibility state of the icon and text associated\r
* to the last check on the ownCloud server.\r
- * \r
- * @param serverStatusText Resource identifier of the text to show.\r
- * @param serverStatusIcon Resource identifier of the icon to show.\r
+ *\r
*/\r
private void showServerStatus() {\r
if (mServerStatusIcon == 0 && mServerStatusText == 0) {\r
public void onCheckClick(View view) {\r
CheckBox oAuth2Check = (CheckBox)view;\r
if (oAuth2Check.isChecked()) {\r
- mAuthTokenType = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
+ mAuthTokenType = OAUTH_TOKEN_TYPE;\r
} else {\r
- mAuthTokenType = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
+ mAuthTokenType = BASIC_TOKEN_TYPE;\r
}\r
updateAuthenticationPreFragmentVisibility();\r
}\r
}\r
\r
\r
- private void getRemoteUserNameOperation(String sessionCookie, boolean followRedirects) {\r
+ private void getRemoteUserNameOperation(String sessionCookie) {\r
\r
Intent getUserNameIntent = new Intent();\r
getUserNameIntent.setAction(OperationsService.ACTION_GET_USER_NAME);\r
getUserNameIntent.putExtra(OperationsService.EXTRA_COOKIE, sessionCookie);\r
\r
if (mOperationsServiceBinder != null) {\r
- //Log_OC.wtf(TAG, "starting getRemoteUserNameOperation..." );\r
- mWaitingForOpId = mOperationsServiceBinder.newOperation(getUserNameIntent);\r
+ mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getUserNameIntent);\r
}\r
}\r
\r
if (sessionCookie != null && sessionCookie.length() > 0) {\r
Log_OC.d(TAG, "Successful SSO - time to save the account");\r
mAuthToken = sessionCookie;\r
- getRemoteUserNameOperation(sessionCookie, true);\r
+ getRemoteUserNameOperation(sessionCookie);\r
Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG);\r
- if (fd != null && fd instanceof SherlockDialogFragment) {\r
- Dialog d = ((SherlockDialogFragment)fd).getDialog();\r
+ if (fd != null && fd instanceof DialogFragment) {\r
+ Dialog d = ((DialogFragment)fd).getDialog();\r
if (d != null && d.isShowing()) {\r
d.dismiss();\r
}\r
X509Certificate x509Certificate, SslError error, SslErrorHandler handler\r
) {\r
// Show a dialog with the certificate info\r
- SslUntrustedCertDialog dialog = null;\r
+ SslUntrustedCertDialog dialog;\r
if (x509Certificate == null) {\r
dialog = SslUntrustedCertDialog.newInstanceForEmptySslError(error, handler);\r
} else {\r
\r
private void dismissDialog(String dialogTag){\r
Fragment frag = getSupportFragmentManager().findFragmentByTag(dialogTag);\r
- if (frag != null && frag instanceof SherlockDialogFragment) {\r
- SherlockDialogFragment dialog = (SherlockDialogFragment) frag;\r
+ if (frag != null && frag instanceof DialogFragment) {\r
+ DialogFragment dialog = (DialogFragment) frag;\r
dialog.dismiss();\r
}\r
}\r
if (component.equals(\r
new ComponentName(AuthenticatorActivity.this, OperationsService.class)\r
)) {\r
- //Log_OC.wtf(TAG, "Operations service connected");\r
mOperationsServiceBinder = (OperationsServiceBinder) service;\r
\r
doOnResumeAndBound();\r
\r
- } else {\r
- return;\r
}\r
\r
}\r
\r
/**\r
* Create and show dialog for request authentication to the user\r
- * @param webView\r
- * @param handler\r
+ * @param webView Web view to emebd into the authentication dialog.\r
+ * @param handler Object responsible for catching and recovering HTTP authentication fails.\r
*/\r
public void createAuthenticationDialog(WebView webView, HttpAuthHandler handler) {\r
\r
public void doNegativeAuthenticatioDialogClick(){\r
mIsFirstAuthAttempt = true;\r
}\r
+\r
}\r
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio on 09/02/2015.
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.authentication;
+
+import android.app.Activity;
+import android.content.Context;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientFactory;
+import com.owncloud.android.lib.common.OwnCloudCredentials;
+import com.owncloud.android.lib.common.network.RedirectionPath;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
+
+import java.lang.ref.WeakReference;
+
+
+/**
+ * Async Task to verify the credentials of a user
+ */
+public class AuthenticatorAsyncTask extends AsyncTask<Object, Void, RemoteOperationResult> {
+
+ private static String REMOTE_PATH = "/";
+ private static boolean SUCCESS_IF_ABSENT = false;
+
+ private Context mContext;
+ private final WeakReference<OnAuthenticatorTaskListener> mListener;
+ protected Activity mActivity;
+
+ public AuthenticatorAsyncTask(Activity activity) {
+ mContext = activity.getApplicationContext();
+ mListener = new WeakReference<OnAuthenticatorTaskListener>((OnAuthenticatorTaskListener)activity);
+ }
+
+ @Override
+ protected RemoteOperationResult doInBackground(Object... params) {
+
+ RemoteOperationResult result;
+ if (params!= null && params.length==2) {
+ String url = (String)params[0];
+ OwnCloudCredentials credentials = (OwnCloudCredentials)params[1];
+
+ // Client
+ Uri uri = Uri.parse(url);
+ OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(uri, mContext, true);
+ client.setCredentials(credentials);
+
+ // Operation
+ ExistenceCheckRemoteOperation operation = new ExistenceCheckRemoteOperation(
+ REMOTE_PATH,
+ mContext,
+ SUCCESS_IF_ABSENT
+ );
+ result = operation.execute(client);
+
+ if (operation.wasRedirected()) {
+ RedirectionPath redirectionPath = operation.getRedirectionPath();
+ String permanentLocation = redirectionPath.getLastPermanentLocation();
+ result.setLastPermanentLocation(permanentLocation);
+ }
+
+ } else {
+ result = new RemoteOperationResult(RemoteOperationResult.ResultCode.UNKNOWN_ERROR);
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(RemoteOperationResult result) {
+
+ if (result!= null)
+ {
+ OnAuthenticatorTaskListener listener = mListener.get();
+ if (listener!= null)
+ {
+ listener.onAuthenticatorTaskCallback(result);
+ }
+ }
+ }
+ /*
+ * Interface to retrieve data from recognition task
+ */
+ public interface OnAuthenticatorTaskListener{
+
+ void onAuthenticatorTaskCallback(RemoteOperationResult result);
+ }
+}
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* Constant values for OAuth 2 protocol.
*
* Includes required and optional parameter NAMES used in the 'authorization code' grant type.
- *
- * @author David A. Velasco
*/
public class OAuth2Constants {
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.authentication;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.PowerManager;
+import android.preference.PreferenceManager;
+import android.view.WindowManager;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.ui.activity.PassCodeActivity;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class PassCodeManager {
+
+ private static final Set<Class> sExemptOfPasscodeActivites;
+
+ static {
+ sExemptOfPasscodeActivites = new HashSet<Class>();
+ sExemptOfPasscodeActivites.add(PassCodeActivity.class);
+ // other activities may be exempted, if needed
+ }
+
+ private static int PASS_CODE_TIMEOUT = 1000;
+ // keeping a "low" positive value is the easiest way to prevent the pass code is requested on rotations
+
+ public static PassCodeManager mPassCodeManagerInstance = null;
+
+ public static PassCodeManager getPassCodeManager() {
+ if (mPassCodeManagerInstance == null) {
+ mPassCodeManagerInstance = new PassCodeManager();
+ }
+ return mPassCodeManagerInstance;
+ }
+
+ private Long mTimestamp = 0l;
+ private int mVisibleActivitiesCounter = 0;
+
+ protected PassCodeManager() {};
+
+ public void onActivityCreated(Activity activity) {
+ if (passCodeIsEnabled()) {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
+ } else {
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
+ }
+ }
+
+ public void onActivityStarted(Activity activity) {
+ if (!sExemptOfPasscodeActivites.contains(activity.getClass()) &&
+ passCodeShouldBeRequested()
+ ){
+
+ Intent i = new Intent(MainApp.getAppContext(), PassCodeActivity.class);
+ i.setAction(PassCodeActivity.ACTION_REQUEST);
+ i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ activity.startActivity(i);
+
+ }
+
+ mVisibleActivitiesCounter++; // keep it AFTER passCodeShouldBeRequested was checked
+ }
+
+ public void onActivityStopped(Activity activity) {
+ if (mVisibleActivitiesCounter > 0) {
+ mVisibleActivitiesCounter--;
+ }
+ setUnlockTimestamp();
+ PowerManager powerMgr = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
+ if (passCodeIsEnabled() && powerMgr != null && !powerMgr.isScreenOn()) {
+ activity.moveTaskToBack(true);
+ }
+ }
+
+ private void setUnlockTimestamp() {
+ mTimestamp = System.currentTimeMillis();
+ }
+
+ private boolean passCodeShouldBeRequested(){
+ if ((System.currentTimeMillis() - mTimestamp) > PASS_CODE_TIMEOUT &&
+ mVisibleActivitiesCounter <= 0
+ ){
+ return passCodeIsEnabled();
+ }
+ return false;
+ }
+
+ private boolean passCodeIsEnabled() {
+ SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(MainApp.getAppContext());
+ return (appPrefs.getBoolean("set_pincode", false));
+ }
+
+}
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
*
* Assumes that the single-sign-on is kept thanks to a cookie set at the end of the
* authentication process.
- *
- * @author David A. Velasco
*/
public class SsoWebViewClient extends WebViewClient {
view.setVisibility(View.GONE);
CookieManager cookieManager = CookieManager.getInstance();
final String cookies = cookieManager.getCookie(url);
- Log_OC.d(TAG, "Cookies: " + cookies);
+ //Log_OC.d(TAG, "Cookies: " + cookies);
if (mListenerHandler != null && mListenerRef != null) {
// this is good idea because onPageFinished is not running in the UI thread
mListenerHandler.post(new Runnable() {
}
}
-
- @Override
- public void doUpdateVisitedHistory (WebView view, String url, boolean isReload) {
- Log_OC.d(TAG, "doUpdateVisitedHistory : " + url);
- }
-
@Override
public void onReceivedSslError (final WebView view, final SslErrorHandler handler, SslError error) {
- Log_OC.d(TAG, "onReceivedSslError : " + error);
+ Log_OC.e(TAG, "onReceivedSslError : " + error);
// Test 1
X509Certificate x509Certificate = getX509CertificateFromError(error);
boolean isKnownServer = false;
if (x509Certificate != null) {
- Log_OC.d(TAG, "------>>>>> x509Certificate " + x509Certificate.toString());
-
try {
isKnownServer = NetworkUtils.isCertInKnownServersStore((Certificate) x509Certificate, mContext);
} catch (Exception e) {
((AuthenticatorActivity)mContext).createAuthenticationDialog(view, handler);
}
- @Override
- public WebResourceResponse shouldInterceptRequest (WebView view, String url) {
- Log_OC.d(TAG, "shouldInterceptRequest : " + url);
- return null;
- }
-
- @Override
- public void onLoadResource (WebView view, String url) {
- Log_OC.d(TAG, "onLoadResource : " + url);
- }
-
- @Override
- public void onReceivedLoginRequest (WebView view, String realm, String account, String args) {
- Log_OC.d(TAG, "onReceivedLoginRequest : " + realm + ", " + account + ", " + args);
- }
-
- @Override
- public void onScaleChanged (WebView view, float oldScale, float newScale) {
- Log_OC.d(TAG, "onScaleChanged : " + oldScale + " -> " + newScale);
- super.onScaleChanged(view, oldScale, newScale);
- }
-
- @Override
- public void onUnhandledKeyEvent (WebView view, KeyEvent event) {
- Log_OC.d(TAG, "onUnhandledKeyEvent : " + event);
- }
-
- @Override
- public boolean shouldOverrideKeyEvent (WebView view, KeyEvent event) {
- Log_OC.d(TAG, "shouldOverrideKeyEvent : " + event);
- return false;
- }
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2014 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Vector;
-import com.owncloud.android.MainApp;
-import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
-import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.lib.resources.shares.OCShare;
-import com.owncloud.android.lib.resources.shares.ShareType;
-import com.owncloud.android.lib.resources.files.FileUtils;
-import com.owncloud.android.utils.FileStorageUtils;
-
-
import android.accounts.Account;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
+import android.content.Intent;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
+import android.provider.MediaStore;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.resources.shares.ShareType;
+import com.owncloud.android.utils.FileStorageUtils;
public class FileDataStorageManager {
}
- public Vector<OCFile> getFolderContent(OCFile f) {
+ public Vector<OCFile> getFolderContent(OCFile f/*, boolean onlyOnDevice*/) {
if (f != null && f.isFolder() && f.getFileId() != -1) {
- return getFolderContent(f.getFileId());
+ // TODO Enable when "On Device" is recovered ?
+ return getFolderContent(f.getFileId()/*, onlyOnDevice*/);
} else {
return new Vector<OCFile>();
}
- public Vector<OCFile> getFolderImages(OCFile folder) {
+ public Vector<OCFile> getFolderImages(OCFile folder/*, boolean onlyOnDevice*/) {
Vector<OCFile> ret = new Vector<OCFile>();
if (folder != null) {
- // TODO better implementation, filtering in the access to database instead of here
- Vector<OCFile> tmp = getFolderContent(folder);
+ // TODO better implementation, filtering in the access to database instead of here
+ // TODO Enable when "On Device" is recovered ?
+ Vector<OCFile> tmp = getFolderContent(folder/*, onlyOnDevice*/);
OCFile current = null;
for (int i=0; i<tmp.size(); i++) {
current = tmp.get(i);
return ret;
}
-
public boolean saveFile(OCFile file) {
boolean overriden = false;
ContentValues cv = new ContentValues();
cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail());
+ cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
boolean sameRemotePath = fileExists(file.getRemotePath());
if (sameRemotePath ||
* HERE ONLY DATA CONSISTENCY SHOULD BE GRANTED
*
* @param folder
- * @param files
- * @param removeNotUpdated
+ * @param updatedFiles
+ * @param filesToRemove
*/
public void saveFolder(
OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove
cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail());
+ cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
boolean existsByPath = fileExists(file.getRemotePath());
if (existsByPath || fileExists(file.getFileId())) {
).withSelection(where, whereArgs).build());
if (file.isDown()) {
- new File(file.getStoragePath()).delete();
+ String path = file.getStoragePath();
+ new File(path).delete();
+ triggerMediaScan(path); // notify MediaScanner about removed file
}
}
}
}
success &= (deleted > 0);
}
- if (removeLocalCopy && file.isDown() && file.getStoragePath() != null && success) {
- success = new File(file.getStoragePath()).delete();
+ String localPath = file.getStoragePath();
+ if (removeLocalCopy && file.isDown() && localPath != null && success) {
+ success = new File(localPath).delete();
+ if (success) {
+ deleteFileInMediaScan(localPath);
+ }
if (!removeDBData && success) {
// maybe unnecessary, but should be checked TODO remove if unnecessary
file.setStoragePath(null);
private boolean removeLocalFolder(OCFile folder) {
boolean success = true;
- File localFolder = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder));
+ String localFolderPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder);
+ File localFolder = new File(localFolderPath);
if (localFolder.exists()) {
// stage 1: remove the local files already registered in the files database
- Vector<OCFile> files = getFolderContent(folder.getFileId());
+ // TODO Enable when "On Device" is recovered ?
+ Vector<OCFile> files = getFolderContent(folder.getFileId()/*, false*/);
if (files != null) {
for (OCFile file : files) {
if (file.isFolder()) {
File localFile = new File(file.getStoragePath());
success &= localFile.delete();
if (success) {
+ // notify MediaScanner about removed file
+ deleteFileInMediaScan(file.getStoragePath());
file.setStoragePath(null);
saveFile(file);
}
if (localFile.isDirectory()) {
success &= removeLocalFolder(localFile);
} else {
+ String path = localFile.getAbsolutePath();
success &= localFile.delete();
}
}
return success;
}
+
/**
- * Updates database for a folder that was moved to a different location.
+ * Updates database and file system for a file or folder that was moved to a different location.
*
* TODO explore better (faster) implementations
* TODO throw exceptions up !
*/
- public void moveFolder(OCFile folder, String newPath) {
- // TODO check newPath
-
- if ( folder != null && folder.isFolder() &&
- folder.fileExists() && !OCFile.ROOT_PATH.equals(folder.getFileName())
- ) {
- /// 1. get all the descendants of 'dir' in a single QUERY (including 'dir')
- Cursor c = null;
- if (getContentProviderClient() != null) {
- try {
- c = getContentProviderClient().query (
- ProviderTableMeta.CONTENT_URI,
- null,
- ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
- ProviderTableMeta.FILE_PATH + " LIKE ? ",
- new String[] { mAccount.name, folder.getRemotePath() + "%" },
- ProviderTableMeta.FILE_PATH + " ASC "
- );
- } catch (RemoteException e) {
- Log_OC.e(TAG, e.getMessage());
- }
- } else {
- c = getContentResolver().query (
- ProviderTableMeta.CONTENT_URI,
- null,
- ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
- ProviderTableMeta.FILE_PATH + " LIKE ? ",
- new String[] { mAccount.name, folder.getRemotePath() + "%" },
- ProviderTableMeta.FILE_PATH + " ASC "
- );
- }
-
- /// 2. prepare a batch of update operations to change all the descendants
- ArrayList<ContentProviderOperation> operations =
- new ArrayList<ContentProviderOperation>(c.getCount());
- int lengthOfOldPath = folder.getRemotePath().length();
- String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
- int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
- if (c.moveToFirst()) {
- do {
- ContentValues cv = new ContentValues(); // keep the constructor in the loop
- OCFile child = createFileInstance(c);
- cv.put(
- ProviderTableMeta.FILE_PATH,
- newPath + child.getRemotePath().substring(lengthOfOldPath)
- );
- if ( child.getStoragePath() != null &&
- child.getStoragePath().startsWith(defaultSavePath) ) {
- cv.put(
- ProviderTableMeta.FILE_STORAGE_PATH,
- defaultSavePath + newPath +
- child.getStoragePath().substring(lengthOfOldStoragePath)
- );
- }
- operations.add(
- ContentProviderOperation.
- newUpdate(ProviderTableMeta.CONTENT_URI).
- withValues(cv).
- withSelection(
- ProviderTableMeta._ID + "=?",
- new String[] { String.valueOf(child.getFileId()) }
- ).
- build()
- );
- } while (c.moveToNext());
- }
- c.close();
-
- /// 3. apply updates in batch
- try {
- if (getContentResolver() != null) {
- getContentResolver().applyBatch(MainApp.getAuthority(), operations);
-
- } else {
- getContentProviderClient().applyBatch(operations);
- }
-
- } catch (OperationApplicationException e) {
- Log_OC.e(TAG, "Fail to update descendants of " +
- folder.getFileId() + " in database", e);
-
- } catch (RemoteException e) {
- Log_OC.e(TAG, "Fail to update desendants of " +
- folder.getFileId() + " in database", e);
- }
-
- }
- }
-
-
public void moveLocalFile(OCFile file, String targetPath, String targetParentPath) {
if (file != null && file.fileExists() && !OCFile.ROOT_PATH.equals(file.getFileName())) {
OCFile targetParent = getFileByPath(targetParentPath);
if (targetParent == null) {
- // TODO panic
+ throw new IllegalStateException("Parent folder of the target path does not exist!!");
}
/// 1. get all the descendants of the moved element in a single QUERY
ArrayList<ContentProviderOperation> operations =
new ArrayList<ContentProviderOperation>(c.getCount());
String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
+ List<String> originalPathsToTriggerMediaScan = new ArrayList<String>();
+ List<String> newPathsToTriggerMediaScan = new ArrayList<String>();
if (c.moveToFirst()) {
int lengthOfOldPath = file.getRemotePath().length();
int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
if (child.getStoragePath() != null &&
child.getStoragePath().startsWith(defaultSavePath)) {
// update link to downloaded content - but local move is not done here!
- cv.put(
- ProviderTableMeta.FILE_STORAGE_PATH,
- defaultSavePath + targetPath +
- child.getStoragePath().substring(lengthOfOldStoragePath)
- );
+ String targetLocalPath = defaultSavePath + targetPath +
+ child.getStoragePath().substring(lengthOfOldStoragePath);
+
+ cv.put(ProviderTableMeta.FILE_STORAGE_PATH, targetLocalPath);
+
+ originalPathsToTriggerMediaScan.add(child.getStoragePath());
+ newPathsToTriggerMediaScan.add(targetLocalPath);
+
}
if (child.getRemotePath().equals(file.getRemotePath())) {
cv.put(
}
} catch (Exception e) {
- Log_OC.e(
- TAG,
- "Fail to update " + file.getFileId() + " and descendants in database",
- e
- );
+ Log_OC.e(TAG, "Fail to update " + file.getFileId() + " and descendants in database", e);
}
/// 4. move in local file system
- String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file);
- File localFile = new File(localPath);
+ String originalLocalPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file);
+ String targetLocalPath = defaultSavePath + targetPath;
+ File localFile = new File(originalLocalPath);
boolean renamed = false;
if (localFile.exists()) {
- File targetFile = new File(defaultSavePath + targetPath);
+ File targetFile = new File(targetLocalPath);
File targetFolder = targetFile.getParentFile();
if (!targetFolder.exists()) {
targetFolder.mkdirs();
}
renamed = localFile.renameTo(targetFile);
}
- Log_OC.d(TAG, "Local file RENAMED : " + renamed);
-
+
+ if (renamed) {
+ Iterator<String> it = originalPathsToTriggerMediaScan.iterator();
+ while (it.hasNext()) {
+ // Notify MediaScanner about removed file
+ deleteFileInMediaScan(it.next());
+ }
+ it = newPathsToTriggerMediaScan.iterator();
+ while (it.hasNext()) {
+ // Notify MediaScanner about new file/folder
+ triggerMediaScan(it.next());
+ }
+ }
}
}
- private Vector<OCFile> getFolderContent(long parentId) {
+ private Vector<OCFile> getFolderContent(long parentId/*, boolean onlyOnDevice*/) {
Vector<OCFile> ret = new Vector<OCFile>();
if (c.moveToFirst()) {
do {
OCFile child = createFileInstance(c);
- ret.add(child);
+ // TODO Enable when "On Device" is recovered ?
+ // if (child.isFolder() || !onlyOnDevice || onlyOnDevice && child.isDown()){
+ ret.add(child);
+ // }
} while (c.moveToNext());
}
file.setRemoteId(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID)));
file.setNeedsUpdateThumbnail(c.getInt(
c.getColumnIndex(ProviderTableMeta.FILE_UPDATE_THUMBNAIL)) == 1 ? true : false);
+ file.setDownloading(c.getInt(
+ c.getColumnIndex(ProviderTableMeta.FILE_IS_DOWNLOADING)) == 1 ? true : false);
}
return file;
ProviderTableMeta.FILE_UPDATE_THUMBNAIL,
file.needsUpdateThumbnail() ? 1 : 0
);
+ cv.put(
+ ProviderTableMeta.FILE_IS_DOWNLOADING,
+ file.isDownloading() ? 1 : 0
+ );
boolean existsByPath = fileExists(file.getRemotePath());
if (existsByPath || fileExists(file.getFileId())) {
path = path + FileUtils.PATH_SEPARATOR;
}
- // Update OCFile with data from share: ShareByLink ¿and publicLink?
+ // Update OCFile with data from share: ShareByLink and publicLink
OCFile file = getFileByPath(path);
if (file != null) {
if (share.getShareType().equals(ShareType.PUBLIC_LINK)) {
}
private ArrayList<ContentProviderOperation> prepareRemoveSharesInFolder(
- OCFile folder, ArrayList<ContentProviderOperation> preparedOperations
- ) {
+ OCFile folder, ArrayList<ContentProviderOperation> preparedOperations) {
if (folder != null) {
String where = ProviderTableMeta.OCSHARES_PATH + "=?" + " AND "
+ ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
String [] whereArgs = new String[]{ "", mAccount.name };
-
- Vector<OCFile> files = getFolderContent(folder);
+
+ // TODO Enable when "On Device" is recovered ?
+ Vector<OCFile> files = getFolderContent(folder /*, false*/);
for (OCFile file : files) {
whereArgs[0] = file.getRemotePath();
//}
}
+ public void triggerMediaScan(String path) {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ intent.setData(Uri.fromFile(new File(path)));
+ MainApp.getAppContext().sendBroadcast(intent);
+ }
+
+ public void deleteFileInMediaScan(String path) {
+
+ String mimetypeString = FileStorageUtils.getMimeTypeFromName(path);
+ ContentResolver contentResolver = getContentResolver();
+
+ if (contentResolver != null) {
+ if (mimetypeString.startsWith("image/")) {
+ // Images
+ contentResolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ MediaStore.Images.Media.DATA + "=?", new String[]{path});
+ } else if (mimetypeString.startsWith("audio/")) {
+ // Audio
+ contentResolver.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ MediaStore.Audio.Media.DATA + "=?", new String[]{path});
+ } else if (mimetypeString.startsWith("video/")) {
+ // Video
+ contentResolver.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ MediaStore.Video.Media.DATA + "=?", new String[]{path});
+ }
+ } else {
+ ContentProviderClient contentProviderClient = getContentProviderClient();
+ try {
+ if (mimetypeString.startsWith("image/")) {
+ // Images
+ contentProviderClient.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ MediaStore.Images.Media.DATA + "=?", new String[]{path});
+ } else if (mimetypeString.startsWith("audio/")) {
+ // Audio
+ contentProviderClient.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ MediaStore.Audio.Media.DATA + "=?", new String[]{path});
+ } else if (mimetypeString.startsWith("video/")) {
+ // Video
+ contentProviderClient.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ MediaStore.Video.Media.DATA + "=?", new String[]{path});
+ }
+ } catch (RemoteException e) {
+ Log_OC.e(TAG, "Exception deleting media file in MediaStore " + e.getMessage());
+ }
+ }
+
+ }
+
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.datamodel;
-import java.io.File;
+import android.os.Parcel;
+import android.os.Parcelable;
import com.owncloud.android.lib.common.utils.Log_OC;
-import third_parties.daveKoeller.AlphanumComparator;
+import com.owncloud.android.utils.FileStorageUtils;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.webkit.MimeTypeMap;
+import java.io.File;
+import third_parties.daveKoeller.AlphanumComparator;
public class OCFile implements Parcelable, Comparable<OCFile> {
public static final Parcelable.Creator<OCFile> CREATOR = new Parcelable.Creator<OCFile>() {
public static final String ROOT_PATH = PATH_SEPARATOR;
private static final String TAG = OCFile.class.getSimpleName();
-
+
private long mId;
private long mParentId;
private long mLength;
private boolean mKeepInSync;
private String mEtag;
-
+
private boolean mShareByLink;
private String mPublicLink;
private boolean mNeedsUpdateThumbnail;
+ private boolean mIsDownloading;
+
/**
* Create new {@link OCFile} with given path.
- *
+ * <p/>
* The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'.
- *
+ *
* @param path The remote path of the file.
*/
public OCFile(String path) {
/**
* Reconstruct from parcel
- *
+ *
* @param source The source parcel
*/
private OCFile(Parcel source) {
mPermissions = source.readString();
mRemoteId = source.readString();
mNeedsUpdateThumbnail = source.readInt() == 0;
+ mIsDownloading = source.readInt() == 0;
}
dest.writeString(mPermissions);
dest.writeString(mRemoteId);
dest.writeInt(mNeedsUpdateThumbnail ? 1 : 0);
+ dest.writeInt(mIsDownloading ? 1 : 0);
}
-
+
/**
* Gets the ID of the file
- *
+ *
* @return the file ID
*/
public long getFileId() {
/**
* Returns the remote path of the file on ownCloud
- *
+ *
* @return The remote path to the file
*/
public String getRemotePath() {
/**
* Can be used to check, whether or not this file exists in the database
* already
- *
+ *
* @return true, if the file exists in the database
*/
public boolean fileExists() {
/**
* Use this to find out if this file is a folder.
- *
+ *
* @return true if it is a folder
*/
public boolean isFolder() {
/**
* Use this to check if this file is available locally
- *
+ *
* @return true if it is
*/
public boolean isDown() {
}
return false;
}
-
+
/**
* The path, where the file is stored locally
- *
+ *
* @return The local path to the file
*/
public String getStoragePath() {
/**
* Can be used to set the path where the file is stored
- *
+ *
* @param storage_path to set
*/
public void setStoragePath(String storage_path) {
/**
* Get a UNIX timestamp of the file creation time
- *
+ *
* @return A UNIX timestamp of the time that file was created
*/
public long getCreationTimestamp() {
/**
* Set a UNIX timestamp of the time the file was created
- *
+ *
* @param creation_timestamp to set
*/
public void setCreationTimestamp(long creation_timestamp) {
/**
* Get a UNIX timestamp of the file modification time.
*
- * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server
- * in the last synchronization of the properties of this file.
+ * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server
+ * in the last synchronization of the properties of this file.
*/
public long getModificationTimestamp() {
return mModifiedTimestamp;
/**
* Set a UNIX timestamp of the time the time the file was modified.
- *
- * To update with the value returned by the server in every synchronization of the properties
+ * <p/>
+ * To update with the value returned by the server in every synchronization of the properties
* of this file.
- *
+ *
* @param modification_timestamp to set
*/
public void setModificationTimestamp(long modification_timestamp) {
mModifiedTimestamp = modification_timestamp;
}
-
+
/**
* Get a UNIX timestamp of the file modification time.
*
- * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server
- * in the last synchronization of THE CONTENTS of this file.
+ * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server
+ * in the last synchronization of THE CONTENTS of this file.
*/
public long getModificationTimestampAtLastSyncForData() {
return mModifiedTimestampAtLastSyncForData;
/**
* Set a UNIX timestamp of the time the time the file was modified.
- *
- * To update with the value returned by the server in every synchronization of THE CONTENTS
+ * <p/>
+ * To update with the value returned by the server in every synchronization of THE CONTENTS
* of this file.
- *
- * @param modification_timestamp to set
+ *
+ * @param modificationTimestamp to set
*/
public void setModificationTimestampAtLastSyncForData(long modificationTimestamp) {
mModifiedTimestampAtLastSyncForData = modificationTimestamp;
}
-
-
+
/**
* Returns the filename and "/" for the root directory
- *
+ *
* @return The name of the file
*/
public String getFileName() {
File f = new File(getRemotePath());
return f.getName().length() == 0 ? ROOT_PATH : f.getName();
}
-
+
/**
* Sets the name of the file
- *
- * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root directory
+ * <p/>
+ * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root directory
*/
public void setFileName(String name) {
Log_OC.d(TAG, "OCFile name changin from " + mRemotePath);
if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) && !mRemotePath.equals(ROOT_PATH)) {
String parent = (new File(getRemotePath())).getParent();
parent = (parent.endsWith(PATH_SEPARATOR)) ? parent : parent + PATH_SEPARATOR;
- mRemotePath = parent + name;
+ mRemotePath = parent + name;
if (isFolder()) {
mRemotePath += PATH_SEPARATOR;
}
/**
* Can be used to get the Mimetype
- *
+ *
* @return the Mimetype as a String
*/
public String getMimetype() {
/**
* Adds a file to this directory. If this file is not a directory, an
* exception gets thrown.
- *
+ *
* @param file to add
* @throws IllegalStateException if you try to add a something and this is
- * not a directory
+ * not a directory
*/
public void addFile(OCFile file) throws IllegalStateException {
if (isFolder()) {
mPermissions = null;
mRemoteId = null;
mNeedsUpdateThumbnail = false;
+ mIsDownloading = false;
}
/**
* Sets the ID of the file
- *
+ *
* @param file_id to set
*/
public void setFileId(long file_id) {
/**
* Sets the Mime-Type of the
- *
+ *
* @param mimetype to set
*/
public void setMimetype(String mimetype) {
/**
* Sets the ID of the parent folder
- *
+ *
* @param parent_id to set
*/
public void setParentId(long parent_id) {
/**
* Sets the file size in bytes
- *
+ *
* @param file_len to set
*/
public void setFileLength(long file_len) {
/**
* Returns the size of the file in bytes
- *
+ *
* @return The filesize in bytes
*/
public long getFileLength() {
/**
* Returns the ID of the parent Folder
- *
+ *
* @return The ID
*/
public long getParentId() {
/**
* Check, if this file needs updating
- *
+ *
* @return
*/
public boolean needsUpdatingWhileSaving() {
return mNeedsUpdating;
}
-
+
public boolean needsUpdateThumbnail() {
return mNeedsUpdateThumbnail;
}
public long getLastSyncDateForProperties() {
return mLastSyncDateForProperties;
}
-
+
public void setLastSyncDateForProperties(long lastSyncDate) {
mLastSyncDateForProperties = lastSyncDate;
}
-
+
public long getLastSyncDateForData() {
return mLastSyncDateForData;
}
public void setKeepInSync(boolean keepInSync) {
mKeepInSync = keepInSync;
}
-
+
public boolean keepInSync() {
return mKeepInSync;
}
-
+
@Override
public int describeContents() {
- return this.hashCode();
+ return ((Object) this).hashCode();
}
@Override
@Override
public boolean equals(Object o) {
- if(o instanceof OCFile){
+ if (o instanceof OCFile) {
OCFile that = (OCFile) o;
- if(that != null){
+ if (that != null) {
return this.mId == that.mId;
}
}
-
+
return false;
}
public void setEtag(String etag) {
this.mEtag = etag;
}
-
-
+
+
public boolean isShareByLink() {
return mShareByLink;
}
return 0;
}
- /** @return 'True' if the file contains audio */
+ /**
+ * @return 'True' if the file contains audio
+ */
public boolean isAudio() {
return (mMimeType != null && mMimeType.startsWith("audio/"));
}
- /** @return 'True' if the file contains video */
+ /**
+ * @return 'True' if the file contains video
+ */
public boolean isVideo() {
return (mMimeType != null && mMimeType.startsWith("video/"));
}
- /** @return 'True' if the file contains an image */
+ /**
+ * @return 'True' if the file contains an image
+ */
public boolean isImage() {
return ((mMimeType != null && mMimeType.startsWith("image/")) ||
- getMimeTypeFromName().startsWith("image/"));
- }
-
- public String getMimeTypeFromName() {
- String extension = "";
- int pos = mRemotePath.lastIndexOf('.');
- if (pos >= 0) {
- extension = mRemotePath.substring(pos + 1);
- }
- String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
- return (result != null) ? result : "";
+ FileStorageUtils.getMimeTypeFromName(mRemotePath).startsWith("image/"));
}
public String getPermissions() {
this.mRemoteId = remoteId;
}
+ public boolean isDownloading() {
+ return mIsDownloading;
+ }
+
+ public void setDownloading(boolean isDownloading) {
+ this.mIsDownloading = isDownloading;
+ }
+
+ public boolean isSynchronizing() {
+ // TODO real implementation
+ return false;
+ }
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.datamodel;
import java.io.File;
+import java.io.InputStream;
import java.lang.ref.WeakReference;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import android.accounts.Account;
-import android.accounts.AccountManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
-import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.ui.adapter.DiskLruImageCache;
import com.owncloud.android.utils.DisplayUtils;
/**
- * Manager for concurrent access to thumbnails cache.
- *
- * @author Tobias Kaminsky
- * @author David A. Velasco
+ * Manager for concurrent access to thumbnails cache.
*/
public class ThumbnailsCacheManager {
private static final String TAG = ThumbnailsCacheManager.class.getSimpleName();
private static final String CACHE_FOLDER = "thumbnailCache";
- private static final String MINOR_SERVER_VERSION_FOR_THUMBS = "7.8.0";
-
+
private static final Object mThumbnailsDiskCacheLock = new Object();
private static DiskLruImageCache mThumbnailCache = null;
private static boolean mThumbnailCacheStarting = true;
private static final CompressFormat mCompressFormat = CompressFormat.JPEG;
private static final int mCompressQuality = 70;
private static OwnCloudClient mClient = null;
- private static String mServerVersion = null;
public static Bitmap mDefaultImg =
BitmapFactory.decodeResource(
MainApp.getAppContext().getResources(),
- DisplayUtils.getResourceId("image/png", "default.png")
+ DisplayUtils.getFileTypeIconId("image/png", "default.png")
);
while (mThumbnailCacheStarting) {
try {
mThumbnailsDiskCacheLock.wait();
- } catch (InterruptedException e) {}
+ } catch (InterruptedException e) {
+ Log_OC.e(TAG, "Wait in mThumbnailsDiskCacheLock was interrupted", e);
+ }
}
if (mThumbnailCache != null) {
- return (Bitmap) mThumbnailCache.getBitmap(key);
+ return mThumbnailCache.getBitmap(key);
}
}
return null;
}
-
- public static boolean cancelPotentialWork(OCFile file, ImageView imageView) {
- final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
-
- if (bitmapWorkerTask != null) {
- final OCFile bitmapData = bitmapWorkerTask.mFile;
- // If bitmapData is not yet set or it differs from the new data
- if (bitmapData == null || bitmapData != file) {
- // Cancel previous task
- bitmapWorkerTask.cancel(true);
- } else {
- // The same work is already in progress
- return false;
- }
- }
- // No task associated with the ImageView, or an existing task was cancelled
- return true;
- }
-
- public static ThumbnailGenerationTask getBitmapWorkerTask(ImageView imageView) {
- if (imageView != null) {
- final Drawable drawable = imageView.getDrawable();
- if (drawable instanceof AsyncDrawable) {
- final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
- return asyncDrawable.getBitmapWorkerTask();
- }
- }
- return null;
- }
-
- public static class ThumbnailGenerationTask extends AsyncTask<OCFile, Void, Bitmap> {
+ public static class ThumbnailGenerationTask extends AsyncTask<Object, Void, Bitmap> {
private final WeakReference<ImageView> mImageViewReference;
private static Account mAccount;
- private OCFile mFile;
+ private Object mFile;
private FileDataStorageManager mStorageManager;
-
- public ThumbnailGenerationTask(ImageView imageView, FileDataStorageManager storageManager, Account account) {
- // Use a WeakReference to ensure the ImageView can be garbage collected
+
+
+ public ThumbnailGenerationTask(ImageView imageView, FileDataStorageManager storageManager,
+ Account account) {
+ // Use a WeakReference to ensure the ImageView can be garbage collected
mImageViewReference = new WeakReference<ImageView>(imageView);
if (storageManager == null)
throw new IllegalArgumentException("storageManager must not be NULL");
mAccount = account;
}
- // Decode image in background.
+ public ThumbnailGenerationTask(ImageView imageView) {
+ // Use a WeakReference to ensure the ImageView can be garbage collected
+ mImageViewReference = new WeakReference<ImageView>(imageView);
+ }
+
@Override
- protected Bitmap doInBackground(OCFile... params) {
+ protected Bitmap doInBackground(Object... params) {
Bitmap thumbnail = null;
-
+
try {
if (mAccount != null) {
- AccountManager accountMgr = AccountManager.get(MainApp.getAppContext());
-
- mServerVersion = accountMgr.getUserData(mAccount, Constants.KEY_OC_VERSION);
- OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, MainApp.getAppContext());
+ OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount,
+ MainApp.getAppContext());
mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
getClientFor(ocAccount, MainApp.getAppContext());
}
-
+
mFile = params[0];
- final String imageKey = String.valueOf(mFile.getRemoteId());
-
- // Check disk cache in background thread
- thumbnail = getBitmapFromDiskCache(imageKey);
-
- // Not found in disk cache
- if (thumbnail == null || mFile.needsUpdateThumbnail()) {
- // Converts dp to pixel
- Resources r = MainApp.getAppContext().getResources();
-
- int px = (int) Math.round(r.getDimension(R.dimen.file_icon_size));
-
- if (mFile.isDown()){
- Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
- mFile.getStoragePath(), px, px);
-
- if (bitmap != null) {
- thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
-
- // Add thumbnail to cache
- addBitmapToCache(imageKey, thumbnail);
+
+ if (mFile instanceof OCFile) {
+ thumbnail = doOCFileInBackground();
+ } else if (mFile instanceof File) {
+ thumbnail = doFileInBackground();
+ //} else { do nothing
+ }
- mFile.setNeedsUpdateThumbnail(false);
- mStorageManager.saveFile(mFile);
- }
-
- } else {
- // Download thumbnail from server
- if (mClient != null && mServerVersion != null) {
- OwnCloudVersion serverOCVersion = new OwnCloudVersion(mServerVersion);
- if (serverOCVersion.compareTo(new OwnCloudVersion(MINOR_SERVER_VERSION_FOR_THUMBS)) >= 0) {
- try {
- int status = -1;
-
- String uri = mClient.getBaseUri() + "/index.php/apps/files/api/v1/thumbnail/" +
- px + "/" + px + Uri.encode(mFile.getRemotePath(), "/");
- Log_OC.d("Thumbnail", "URI: " + uri);
- GetMethod get = new GetMethod(uri);
- status = mClient.executeMethod(get);
- if (status == HttpStatus.SC_OK) {
- byte[] bytes = get.getResponseBody();
- Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
- thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
-
- // Add thumbnail to cache
- if (thumbnail != null) {
- addBitmapToCache(imageKey, thumbnail);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- } else {
- Log_OC.d(TAG, "Server too old");
- }
- }
+ }catch(Throwable t){
+ // the app should never break due to a problem with thumbnails
+ Log_OC.e(TAG, "Generation of thumbnail for " + mFile + " failed", t);
+ if (t instanceof OutOfMemoryError) {
+ System.gc();
}
}
-
- } catch (Throwable t) {
- // the app should never break due to a problem with thumbnails
- Log_OC.e(TAG, "Generation of thumbnail for " + mFile + " failed", t);
- if (t instanceof OutOfMemoryError) {
- System.gc();
- }
- }
-
+
return thumbnail;
}
-
+
protected void onPostExecute(Bitmap bitmap){
if (isCancelled()) {
bitmap = null;
}
- if (mImageViewReference != null && bitmap != null) {
+ if (bitmap != null) {
final ImageView imageView = mImageViewReference.get();
- final ThumbnailGenerationTask bitmapWorkerTask =
- getBitmapWorkerTask(imageView);
- if (this == bitmapWorkerTask && imageView != null) {
- if (imageView.getTag().equals(mFile.getFileId())) {
+ final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
+ if (this == bitmapWorkerTask) {
+ String tagId = "";
+ if (mFile instanceof OCFile){
+ tagId = String.valueOf(((OCFile)mFile).getFileId());
+ } else if (mFile instanceof File){
+ tagId = String.valueOf(mFile.hashCode());
+ }
+ if (String.valueOf(imageView.getTag()).equals(tagId)) {
imageView.setImageBitmap(bitmap);
}
}
}
}
+
+ /**
+ * Add thumbnail to cache
+ * @param imageKey: thumb key
+ * @param bitmap: image for extracting thumbnail
+ * @param path: image path
+ * @param px: thumbnail dp
+ * @return Bitmap
+ */
+ private Bitmap addThumbnailToCache(String imageKey, Bitmap bitmap, String path, int px){
+
+ Bitmap thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
+
+ // Rotate image, obeying exif tag
+ thumbnail = BitmapUtils.rotateImage(thumbnail,path);
+
+ // Add thumbnail to cache
+ addBitmapToCache(imageKey, thumbnail);
+
+ return thumbnail;
+ }
+
+ /**
+ * Converts size of file icon from dp to pixel
+ * @return int
+ */
+ private int getThumbnailDimension(){
+ // Converts dp to pixel
+ Resources r = MainApp.getAppContext().getResources();
+ return Math.round(r.getDimension(R.dimen.file_icon_size_grid));
+ }
+
+ private Bitmap doOCFileInBackground() {
+ OCFile file = (OCFile)mFile;
+
+ final String imageKey = String.valueOf(file.getRemoteId());
+
+ // Check disk cache in background thread
+ Bitmap thumbnail = getBitmapFromDiskCache(imageKey);
+
+ // Not found in disk cache
+ if (thumbnail == null || file.needsUpdateThumbnail()) {
+
+ int px = getThumbnailDimension();
+
+ if (file.isDown()) {
+ Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
+ file.getStoragePath(), px, px);
+
+ if (bitmap != null) {
+ thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), px);
+
+ file.setNeedsUpdateThumbnail(false);
+ mStorageManager.saveFile(file);
+ }
+
+ } else {
+ // Download thumbnail from server
+ OwnCloudVersion serverOCVersion = AccountUtils.getServerVersion(mAccount);
+ if (mClient != null && serverOCVersion != null) {
+ if (serverOCVersion.supportsRemoteThumbnails()) {
+ try {
+ String uri = mClient.getBaseUri() + "" +
+ "/index.php/apps/files/api/v1/thumbnail/" +
+ px + "/" + px + Uri.encode(file.getRemotePath(), "/");
+ Log_OC.d("Thumbnail", "URI: " + uri);
+ GetMethod get = new GetMethod(uri);
+ int status = mClient.executeMethod(get);
+ if (status == HttpStatus.SC_OK) {
+// byte[] bytes = get.getResponseBody();
+// Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0,
+// bytes.length);
+ InputStream inputStream = get.getResponseBodyAsStream();
+ Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
+ thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
+
+ // Add thumbnail to cache
+ if (thumbnail != null) {
+ addBitmapToCache(imageKey, thumbnail);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ Log_OC.d(TAG, "Server too old");
+ }
+ }
+ }
+ }
+
+ return thumbnail;
+
+ }
+
+ private Bitmap doFileInBackground() {
+ File file = (File)mFile;
+
+ final String imageKey = String.valueOf(file.hashCode());
+
+ // Check disk cache in background thread
+ Bitmap thumbnail = getBitmapFromDiskCache(imageKey);
+
+ // Not found in disk cache
+ if (thumbnail == null) {
+
+ int px = getThumbnailDimension();
+
+ Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
+ file.getAbsolutePath(), px, px);
+
+ if (bitmap != null) {
+ thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), px);
+ }
+ }
+ return thumbnail;
+ }
+
}
-
-
+
+ public static boolean cancelPotentialWork(Object file, ImageView imageView) {
+ final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
+
+ if (bitmapWorkerTask != null) {
+ final Object bitmapData = bitmapWorkerTask.mFile;
+ // If bitmapData is not yet set or it differs from the new data
+ if (bitmapData == null || bitmapData != file) {
+ // Cancel previous task
+ bitmapWorkerTask.cancel(true);
+ } else {
+ // The same work is already in progress
+ return false;
+ }
+ }
+ // No task associated with the ImageView, or an existing task was cancelled
+ return true;
+ }
+
+ public static ThumbnailGenerationTask getBitmapWorkerTask(ImageView imageView) {
+ if (imageView != null) {
+ final Drawable drawable = imageView.getDrawable();
+ if (drawable instanceof AsyncDrawable) {
+ final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+ return asyncDrawable.getBitmapWorkerTask();
+ }
+ }
+ return null;
+ }
+
public static class AsyncDrawable extends BitmapDrawable {
private final WeakReference<ThumbnailGenerationTask> bitmapWorkerTaskReference;
public AsyncDrawable(
Resources res, Bitmap bitmap, ThumbnailGenerationTask bitmapWorkerTask
- ) {
-
+ ) {
+
super(res, bitmap);
bitmapWorkerTaskReference =
- new WeakReference<ThumbnailGenerationTask>(bitmapWorkerTask);
+ new WeakReference<ThumbnailGenerationTask>(bitmapWorkerTask);
}
public ThumbnailGenerationTask getBitmapWorkerTask() {
return bitmapWorkerTaskReference.get();
}
}
-
-
- /**
- * Remove from cache the remoteId passed
- * @param fileRemoteId: remote id of mFile passed
- */
- public static void removeFileFromCache(String fileRemoteId){
- synchronized (mThumbnailsDiskCacheLock) {
- if (mThumbnailCache != null) {
- mThumbnailCache.removeKey(fileRemoteId);
- }
- mThumbnailsDiskCacheLock.notifyAll(); // Wake any waiting threads
- }
- }
-
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
* Copyright (C) 2011-2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* Custom database helper for ownCloud
- *
- * @author Bartek Przybylski
- *
*/
public class DbHandler {
private SQLiteDatabase mDB;
db.execSQL("ALTER TABLE " + TABLE_INSTANT_UPLOAD + " ADD COLUMN attempt INTEGER;");
}
db.execSQL("ALTER TABLE " + TABLE_INSTANT_UPLOAD + " ADD COLUMN message TEXT;");
-
+ }
+
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ //downgrading is the exception, so deleting and re-creating is acceptable.
+ //otherwise exception will be thrown (cannot downgrade) and oc app will crash.
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_INSTANT_UPLOAD + ";");
+ onCreate(db);
}
}
}
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
+ * @author Bartek Przybylski\r
* Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
\r
/**\r
* Meta-Class that holds various static field information\r
- * \r
- * @author Bartek Przybylski\r
- * \r
*/\r
public class ProviderMeta {\r
\r
public static final String DB_NAME = "filelist";\r
- public static final int DB_VERSION = 8;\r
+ public static final int DB_VERSION = 10;\r
\r
private ProviderMeta() {\r
}\r
public static final String FILE_PERMISSIONS = "permissions";\r
public static final String FILE_REMOTE_ID = "remote_id";\r
public static final String FILE_UPDATE_THUMBNAIL = "update_thumbnail";\r
+ public static final String FILE_IS_DOWNLOADING= "is_downloading";\r
\r
public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME\r
+ " collate nocase asc";\r
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* App-registered receiver catching the broadcast intent reporting that the system was
* just boot up.
- *
- * @author David A. Velasco
*/
public class BootupBroadcastReceiver extends BroadcastReceiver {
-/* ownCloud Android client application
- * Copyright (C) 2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.services.OperationsService;
+import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
import com.owncloud.android.ui.activity.ComponentsGetter;
/**
* Filters out the file actions available in a given {@link Menu} for a given {@link OCFile}
* according to the current state of the latest.
- *
- * @author David A. Velasco
*/
public class FileMenuFilter {
*
* @param targetFile {@link OCFile} target of the action to filter in the {@link Menu}.
* @param account ownCloud {@link Account} holding targetFile.
- * @param cg Accessor to app components, needed to get access the
- * {@link FileUploader} and {@link FileDownloader} services.
+ * @param cg Accessor to app components, needed to access the
+ * {@link FileUploader} and {@link FileDownloader} services
* @param context Android {@link Context}, needed to access build setup resources.
*/
public FileMenuFilter(OCFile targetFile, Account account, ComponentsGetter cg, Context context) {
}
}
- /**
- * Filters out the file actions available in the passed {@link Menu} taken into account
- * the state of the {@link OCFile} held by the filter.
- *
- * Second method needed thanks to ActionBarSherlock.
- *
- * TODO Get rid of it when ActionBarSherlock is replaced for newer Android Support Library.
- *
- * @param menu Options or context menu to filter.
- */
- public void filter(com.actionbarsherlock.view.Menu menu) {
-
- List<Integer> toShow = new ArrayList<Integer>();
- List<Integer> toHide = new ArrayList<Integer>();
-
- filter(toShow, toHide);
-
- com.actionbarsherlock.view.MenuItem item = null;
- for (int i : toShow) {
- item = menu.findItem(i);
- if (item != null) {
- item.setVisible(true);
- item.setEnabled(true);
- }
- }
- for (int i : toHide) {
- item = menu.findItem(i);
- if (item != null) {
- item.setVisible(false);
- item.setEnabled(false);
- }
- }
- }
/**
* Performs the real filtering, to be applied in the {@link Menu} by the caller methods.
boolean uploading = false;
if (mComponentsGetter != null && mFile != null && mAccount != null) {
FileDownloaderBinder downloaderBinder = mComponentsGetter.getFileDownloaderBinder();
- downloading = downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile);
+ downloading = (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile));
+ OperationsServiceBinder opsBinder = mComponentsGetter.getOperationsServiceBinder();
+ downloading |= (opsBinder != null && opsBinder.isSynchronizing(mAccount, mFile.getRemotePath()));
FileUploaderBinder uploaderBinder = mComponentsGetter.getFileUploaderBinder();
- uploading = uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile);
+ uploading = (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile));
}
/// decision is taken for each possible action on a file in the menu
// DOWNLOAD
- if (mFile == null || mFile.isFolder() || mFile.isDown() || downloading || uploading) {
+ if (mFile == null || mFile.isDown() || downloading || uploading) {
toHide.add(R.id.action_download_file);
} else {
// CANCEL DOWNLOAD
- if (mFile == null || !downloading || mFile.isFolder()) {
+ if (mFile == null || !downloading) {
toHide.add(R.id.action_cancel_download);
} else {
toShow.add(R.id.action_cancel_download);
// SHARE FILE
// TODO add check on SHARE available on server side?
- if (mFile == null) {
+ boolean shareAllowed = (mContext != null &&
+ mContext.getString(R.string.share_feature).equalsIgnoreCase("on"));
+ if (!shareAllowed || mFile == null) {
toHide.add(R.id.action_share_file);
} else {
toShow.add(R.id.action_share_file);
// UNSHARE FILE
// TODO add check on SHARE available on server side?
- if (mFile == null || !mFile.isShareByLink()) {
+ if ( !shareAllowed || (mFile == null || !mFile.isShareByLink())) {
toHide.add(R.id.action_unshare_file);
} else {
toShow.add(R.id.action_unshare_file);
}
-
-
+
// SEE DETAILS
if (mFile == null || mFile.isFolder()) {
toHide.add(R.id.action_see_details);
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import org.apache.http.protocol.HTTP;
import android.accounts.Account;
-import android.accounts.AccountManager;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.DialogFragment;
import android.widget.Toast;
import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.ui.dialog.ShareLinkToDialog;
/**
- *
- * @author masensio
- * @author David A. Velasco
+ *
*/
public class FileOperationsHelper {
Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
- intentForSavedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ intentForSavedMimeType.setFlags(
+ Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ );
Intent intentForGuessedMimeType = null;
if (storagePath.lastIndexOf('.') >= 0) {
- String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
+ String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+ storagePath.substring(storagePath.lastIndexOf('.') + 1)
+ );
if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
- intentForGuessedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ intentForGuessedMimeType.setFlags(
+ Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ );
}
}
- Intent chooserIntent = null;
+ Intent chooserIntent;
if (intentForGuessedMimeType != null) {
chooserIntent = Intent.createChooser(intentForGuessedMimeType, mFileActivity.getString(R.string.actionbar_open_with));
} else {
} else {
// Show a Message
- Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
+ Toast t = Toast.makeText(
+ mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG
+ );
t.show();
}
}
- public void shareFileWithLinkToApp(OCFile file, Intent sendIntent) {
+ public void shareFileWithLinkToApp(OCFile file, String password, Intent sendIntent) {
if (file != null) {
mFileActivity.showLoadingDialog();
service.setAction(OperationsService.ACTION_CREATE_SHARE);
service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+ service.putExtra(OperationsService.EXTRA_PASSWORD_SHARE, password);
service.putExtra(OperationsService.EXTRA_SEND_INTENT, sendIntent);
- mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+ mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
} else {
Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
*/
public boolean isSharedSupported() {
if (mFileActivity.getAccount() != null) {
- AccountManager accountManager = AccountManager.get(mFileActivity);
-
- String version = accountManager.getUserData(mFileActivity.getAccount(), Constants.KEY_OC_VERSION);
- return (new OwnCloudVersion(version)).isSharedSupported();
+ OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
+ return (serverVersion != null && serverVersion.isSharedSupported());
}
return false;
}
service.setAction(OperationsService.ACTION_UNSHARE);
service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
- mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+ mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
mFileActivity.showLoadingDialog();
public void syncFile(OCFile file) {
- // Sync file
- Intent service = new Intent(mFileActivity, OperationsService.class);
- service.setAction(OperationsService.ACTION_SYNC_FILE);
- service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
- service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
- service.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
- mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
- mFileActivity.showLoadingDialog();
+ if (!file.isFolder()){
+ Intent intent = new Intent(mFileActivity, OperationsService.class);
+ intent.setAction(OperationsService.ACTION_SYNC_FILE);
+ intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+ intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+ intent.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
+ mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(intent);
+ mFileActivity.showLoadingDialog();
+
+ } else {
+ Intent intent = new Intent(mFileActivity, OperationsService.class);
+ intent.setAction(OperationsService.ACTION_SYNC_FOLDER);
+ intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+ intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+ mFileActivity.startService(intent);
+ }
}
-
public void renameFile(OCFile file, String newFilename) {
// RenameFile
Intent service = new Intent(mFileActivity, OperationsService.class);
service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
- mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+ mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
mFileActivity.showLoadingDialog();
}
service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
- mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+ mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
mFileActivity.showLoadingDialog();
}
service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
- mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+ mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
mFileActivity.showLoadingDialog();
}
-
+ /**
+ * Cancel the transference in downloads (files/folders) and file uploads
+ * @param file OCFile
+ */
public void cancelTransference(OCFile file) {
Account account = mFileActivity.getAccount();
+ if (file.isFolder()) {
+ OperationsService.OperationsServiceBinder opsBinder = mFileActivity.getOperationsServiceBinder();
+ if (opsBinder != null) {
+ opsBinder.cancel(account, file);
+ }
+ }
+
+ // for both files and folders
FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
- FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
+ FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
+ downloaderBinder.cancel(account, file);
+
+ // TODO - review why is this here, and solve in a better way
// Remove etag for parent, if file is a keep_in_sync
if (file.keepInSync()) {
- OCFile parent = mFileActivity.getStorageManager().getFileById(file.getParentId());
- parent.setEtag("");
- mFileActivity.getStorageManager().saveFile(parent);
+ OCFile parent = mFileActivity.getStorageManager().getFileById(file.getParentId());
+ parent.setEtag("");
+ mFileActivity.getStorageManager().saveFile(parent);
}
-
- downloaderBinder.cancel(account, file);
-
+
} else if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
uploaderBinder.cancel(account, file);
}
service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
- mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+ mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
mFileActivity.showLoadingDialog();
}
mWaitingForOpId = waitingForOpId;
}
-
+ /**
+ * @return 'True' if the server doesn't need to check forbidden characters
+ */
+ public boolean isVersionWithForbiddenCharacters() {
+ if (mFileActivity.getAccount() != null) {
+ OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
+ return (serverVersion != null && serverVersion.isVersionWithForbiddenCharacters());
+ }
+ return false;
+ }
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2014 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
Account account = AccountUtils.getCurrentOwnCloudAccount(context);
if (account == null) {
- Log_OC.w(TAG, "No owncloud account found for instant upload, aborting");
+ Log_OC.w(TAG, "No ownCloud account found for instant upload, aborting");
return;
}
Intent i = new Intent(context, FileUploader.class);
i.putExtra(FileUploader.KEY_ACCOUNT, account);
i.putExtra(FileUploader.KEY_LOCAL_FILE, file_path);
- i.putExtra(FileUploader.KEY_REMOTE_FILE, FileStorageUtils.getInstantUploadFilePath(context, file_name));
+ i.putExtra(FileUploader.KEY_REMOTE_FILE, FileStorageUtils.getInstantVideoUploadFilePath(context, file_name));
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
i.putExtra(FileUploader.KEY_MIME_TYPE, mime_type);
i.putExtra(FileUploader.KEY_INSTANT_UPLOAD, true);
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2012-2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
+import com.owncloud.android.MainApp;
import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.authentication.AuthenticatorActivity;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.utils.ErrorMessageAdapter;
import android.accounts.Account;
+import android.accounts.AccountManager;
import android.accounts.AccountsException;
+import android.accounts.OnAccountsUpdateListener;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.os.Message;
import android.os.Process;
import android.support.v4.app.NotificationCompat;
+import android.util.Pair;
+
+public class FileDownloader extends Service
+ implements OnDatatransferProgressListener, OnAccountsUpdateListener {
-public class FileDownloader extends Service implements OnDatatransferProgressListener {
-
public static final String EXTRA_ACCOUNT = "ACCOUNT";
public static final String EXTRA_FILE = "FILE";
-
+
private static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED";
private static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";
- public static final String EXTRA_DOWNLOAD_RESULT = "RESULT";
+ public static final String EXTRA_DOWNLOAD_RESULT = "RESULT";
public static final String EXTRA_FILE_PATH = "FILE_PATH";
public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
+ public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO";
public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
-
+
private static final String TAG = "FileDownloader";
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private IBinder mBinder;
private OwnCloudClient mDownloadClient = null;
- private Account mLastAccount = null;
+ private Account mCurrentAccount = null;
private FileDataStorageManager mStorageManager;
-
- private ConcurrentMap<String, DownloadFileOperation> mPendingDownloads = new ConcurrentHashMap<String, DownloadFileOperation>();
+
+ private IndexedForest<DownloadFileOperation> mPendingDownloads = new IndexedForest<DownloadFileOperation>();
+
private DownloadFileOperation mCurrentDownload = null;
-
+
private NotificationManager mNotificationManager;
private NotificationCompat.Builder mNotificationBuilder;
private int mLastPercent;
-
-
+
+
public static String getDownloadAddedMessage() {
- return FileDownloader.class.getName().toString() + DOWNLOAD_ADDED_MESSAGE;
+ return FileDownloader.class.getName() + DOWNLOAD_ADDED_MESSAGE;
}
-
+
public static String getDownloadFinishMessage() {
- return FileDownloader.class.getName().toString() + DOWNLOAD_FINISH_MESSAGE;
- }
-
- /**
- * Builds a key for mPendingDownloads from the account and file to download
- *
- * @param account Account where the file to download is stored
- * @param file File to download
- */
- private String buildRemoteName(Account account, OCFile file) {
- return account.name + file.getRemotePath();
+ return FileDownloader.class.getName() + DOWNLOAD_FINISH_MESSAGE;
}
-
/**
* Service initialization
*/
@Override
public void onCreate() {
super.onCreate();
+ Log_OC.d(TAG, "Creating service");
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
HandlerThread thread = new HandlerThread("FileDownloaderThread",
Process.THREAD_PRIORITY_BACKGROUND);
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper, this);
mBinder = new FileDownloaderBinder();
+
+ // add AccountsUpdatedListener
+ AccountManager am = AccountManager.get(getApplicationContext());
+ am.addOnAccountsUpdatedListener(this, null, false);
}
+
+ /**
+ * Service clean up
+ */
+ @Override
+ public void onDestroy() {
+ Log_OC.v(TAG, "Destroying service");
+ mBinder = null;
+ mServiceHandler = null;
+ mServiceLooper.quit();
+ mServiceLooper = null;
+ mNotificationManager = null;
+
+ // remove AccountsUpdatedListener
+ AccountManager am = AccountManager.get(getApplicationContext());
+ am.removeOnAccountsUpdatedListener(this);
+
+ super.onDestroy();
+ }
+
+
/**
* Entry point to add one or several files to the queue of downloads.
- *
- * New downloads are added calling to startService(), resulting in a call to this method. This ensures the service will keep on working
- * although the caller activity goes away.
+ * <p/>
+ * New downloads are added calling to startService(), resulting in a call to this method.
+ * This ensures the service will keep on working although the caller activity goes away.
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- if ( !intent.hasExtra(EXTRA_ACCOUNT) ||
+ Log_OC.d(TAG, "Starting command with id " + startId);
+
+ if (!intent.hasExtra(EXTRA_ACCOUNT) ||
!intent.hasExtra(EXTRA_FILE)
- /*!intent.hasExtra(EXTRA_FILE_PATH) ||
- !intent.hasExtra(EXTRA_REMOTE_PATH)*/
- ) {
+ ) {
Log_OC.e(TAG, "Not enough information provided in intent");
return START_NOT_STICKY;
- }
- Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
- OCFile file = intent.getParcelableExtra(EXTRA_FILE);
-
- AbstractList<String> requestedDownloads = new Vector<String>(); // dvelasco: now this always contains just one element, but that can change in a near future (download of multiple selection)
- String downloadKey = buildRemoteName(account, file);
- try {
- DownloadFileOperation newDownload = new DownloadFileOperation(account, file);
- mPendingDownloads.putIfAbsent(downloadKey, newDownload);
- newDownload.addDatatransferProgressListener(this);
- newDownload.addDatatransferProgressListener((FileDownloaderBinder)mBinder);
- requestedDownloads.add(downloadKey);
- sendBroadcastNewDownload(newDownload);
-
- } catch (IllegalArgumentException e) {
- Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage());
- return START_NOT_STICKY;
- }
-
- if (requestedDownloads.size() > 0) {
- Message msg = mServiceHandler.obtainMessage();
- msg.arg1 = startId;
- msg.obj = requestedDownloads;
- mServiceHandler.sendMessage(msg);
+ } else {
+ final Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
+ final OCFile file = intent.getParcelableExtra(EXTRA_FILE);
+
+ /*Log_OC.v(
+ "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
+ "Received request to download file"
+ );*/
+
+ AbstractList<String> requestedDownloads = new Vector<String>();
+ try {
+ DownloadFileOperation newDownload = new DownloadFileOperation(account, file);
+ newDownload.addDatatransferProgressListener(this);
+ newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder);
+ Pair<String, String> putResult = mPendingDownloads.putIfAbsent(
+ account, file.getRemotePath(), newDownload
+ );
+ String downloadKey = putResult.first;
+ requestedDownloads.add(downloadKey);
+ /*Log_OC.v(
+ "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
+ "Download on " + file.getRemotePath() + " added to queue"
+ );*/
+
+ // Store file on db with state 'downloading'
+ /*
+ TODO - check if helps with UI responsiveness,
+ letting only folders use FileDownloaderBinder to check
+ FileDataStorageManager storageManager =
+ new FileDataStorageManager(account, getContentResolver());
+ file.setDownloading(true);
+ storageManager.saveFile(file);
+ */
+
+ sendBroadcastNewDownload(newDownload, putResult.second);
+
+ } catch (IllegalArgumentException e) {
+ Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage());
+ return START_NOT_STICKY;
+ }
+
+ if (requestedDownloads.size() > 0) {
+ Message msg = mServiceHandler.obtainMessage();
+ msg.arg1 = startId;
+ msg.obj = requestedDownloads;
+ mServiceHandler.sendMessage(msg);
+ }
+ //}
}
return START_NOT_STICKY;
}
-
-
+
+
/**
- * Provides a binder object that clients can use to perform operations on the queue of downloads, excepting the addition of new files.
- *
+ * Provides a binder object that clients can use to perform operations on the queue of downloads,
+ * excepting the addition of new files.
+ * <p/>
* Implemented to perform cancellation, pause and resume of existing downloads.
*/
@Override
*/
@Override
public boolean onUnbind(Intent intent) {
- ((FileDownloaderBinder)mBinder).clearListeners();
+ ((FileDownloaderBinder) mBinder).clearListeners();
return false; // not accepting rebinding (default behaviour)
}
-
+ @Override
+ public void onAccountsUpdated(Account[] accounts) {
+ //review the current download and cancel it if its account doesn't exist
+ if (mCurrentDownload != null &&
+ !AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) {
+ mCurrentDownload.cancel();
+ }
+ // The rest of downloads are cancelled when they try to start
+ }
+
+
/**
- * Binder to let client components to perform operations on the queue of downloads.
- *
- * It provides by itself the available operations.
+ * Binder to let client components to perform operations on the queue of downloads.
+ * <p/>
+ * It provides by itself the available operations.
*/
public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener {
-
- /**
- * Map of listeners that will be reported about progress of downloads from a {@link FileDownloaderBinder} instance
+
+ /**
+ * Map of listeners that will be reported about progress of downloads from a
+ * {@link FileDownloaderBinder}
+ * instance.
*/
- private Map<String, OnDatatransferProgressListener> mBoundListeners = new HashMap<String, OnDatatransferProgressListener>();
-
-
+ private Map<Long, OnDatatransferProgressListener> mBoundListeners =
+ new HashMap<Long, OnDatatransferProgressListener>();
+
+
/**
* Cancels a pending or current download of a remote file.
- *
- * @param account Owncloud account where the remote file is stored.
- * @param file A file in the queue of pending downloads
+ *
+ * @param account ownCloud account where the remote file is stored.
+ * @param file A file in the queue of pending downloads
*/
public void cancel(Account account, OCFile file) {
- DownloadFileOperation download = null;
- synchronized (mPendingDownloads) {
- download = mPendingDownloads.remove(buildRemoteName(account, file));
- }
+ /*Log_OC.v(
+ "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
+ "Received request to cancel download of " + file.getRemotePath()
+ );
+ Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
+ "Removing download of " + file.getRemotePath());*/
+ Pair<DownloadFileOperation, String> removeResult =
+ mPendingDownloads.remove(account, file.getRemotePath());
+ DownloadFileOperation download = removeResult.first;
if (download != null) {
+ /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
+ "Canceling returned download of " + file.getRemotePath());*/
download.cancel();
+ } else {
+ if (mCurrentDownload != null && mCurrentAccount != null &&
+ mCurrentDownload.getRemotePath().startsWith(file.getRemotePath()) &&
+ account.name.equals(mCurrentAccount.name)) {
+ /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
+ "Canceling current sync as descendant: " + mCurrentDownload.getRemotePath());*/
+ mCurrentDownload.cancel();
+ }
}
}
-
-
+
+ /**
+ * Cancels a pending or current upload for an account
+ *
+ * @param account Owncloud accountName where the remote file will be stored.
+ */
+ public void cancel(Account account) {
+ Log_OC.d(TAG, "Account= " + account.name);
+
+ if (mCurrentDownload != null) {
+ Log_OC.d(TAG, "Current Download Account= " + mCurrentDownload.getAccount().name);
+ if (mCurrentDownload.getAccount().name.equals(account.name)) {
+ mCurrentDownload.cancel();
+ }
+ }
+ // Cancel pending downloads
+ cancelDownloadsForAccount(account);
+ }
+
public void clearListeners() {
mBoundListeners.clear();
}
/**
- * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download.
- *
- * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download.
- *
- * @param account Owncloud account where the remote file is stored.
- * @param file A file that could be in the queue of downloads.
+ * Returns True when the file described by 'file' in the ownCloud account 'account'
+ * is downloading or waiting to download.
+ * <p/>
+ * If 'file' is a directory, returns 'true' if any of its descendant files is downloading or
+ * waiting to download.
+ *
+ * @param account ownCloud account where the remote file is stored.
+ * @param file A file that could be in the queue of downloads.
*/
public boolean isDownloading(Account account, OCFile file) {
if (account == null || file == null) return false;
- String targetKey = buildRemoteName(account, file);
- synchronized (mPendingDownloads) {
- if (file.isFolder()) {
- // this can be slow if there are many downloads :(
- Iterator<String> it = mPendingDownloads.keySet().iterator();
- boolean found = false;
- while (it.hasNext() && !found) {
- found = it.next().startsWith(targetKey);
- }
- return found;
- } else {
- return (mPendingDownloads.containsKey(targetKey));
- }
- }
+ return (mPendingDownloads.contains(account, file.getRemotePath()));
}
-
+
/**
* Adds a listener interested in the progress of the download for a concrete file.
- *
- * @param listener Object to notify about progress of transfer.
- * @param account ownCloud account holding the file of interest.
- * @param file {@link OCfile} of interest for listener.
+ *
+ * @param listener Object to notify about progress of transfer.
+ * @param account ownCloud account holding the file of interest.
+ * @param file {@link OCFile} of interest for listener.
*/
- public void addDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {
+ public void addDatatransferProgressListener(
+ OnDatatransferProgressListener listener, Account account, OCFile file
+ ) {
if (account == null || file == null || listener == null) return;
- String targetKey = buildRemoteName(account, file);
- mBoundListeners.put(targetKey, listener);
+ //String targetKey = buildKey(account, file.getRemotePath());
+ mBoundListeners.put(file.getFileId(), listener);
}
-
-
+
+
/**
* Removes a listener interested in the progress of the download for a concrete file.
- *
- * @param listener Object to notify about progress of transfer.
- * @param account ownCloud account holding the file of interest.
- * @param file {@link OCfile} of interest for listener.
+ *
+ * @param listener Object to notify about progress of transfer.
+ * @param account ownCloud account holding the file of interest.
+ * @param file {@link OCFile} of interest for listener.
*/
- public void removeDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {
+ public void removeDatatransferProgressListener(
+ OnDatatransferProgressListener listener, Account account, OCFile file
+ ) {
if (account == null || file == null || listener == null) return;
- String targetKey = buildRemoteName(account, file);
- if (mBoundListeners.get(targetKey) == listener) {
- mBoundListeners.remove(targetKey);
+ //String targetKey = buildKey(account, file.getRemotePath());
+ Long fileId = file.getFileId();
+ if (mBoundListeners.get(fileId) == listener) {
+ mBoundListeners.remove(fileId);
}
}
@Override
- public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,
- String fileName) {
- String key = buildRemoteName(mCurrentDownload.getAccount(), mCurrentDownload.getFile());
- OnDatatransferProgressListener boundListener = mBoundListeners.get(key);
+ public void onTransferProgress(long progressRate, long totalTransferredSoFar,
+ long totalToTransfer, String fileName) {
+ //String key = buildKey(mCurrentDownload.getAccount(),
+ // mCurrentDownload.getFile().getRemotePath());
+ OnDatatransferProgressListener boundListener =
+ mBoundListeners.get(mCurrentDownload.getFile().getFileId());
if (boundListener != null) {
- boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);
+ boundListener.onTransferProgress(progressRate, totalTransferredSoFar,
+ totalToTransfer, fileName);
+ }
+ }
+
+ /**
+ * Review downloads and cancel it if its account doesn't exist
+ */
+ public void checkAccountOfCurrentDownload() {
+ if (mCurrentDownload != null &&
+ !AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) {
+ mCurrentDownload.cancel();
}
+ // The rest of downloads are cancelled when they try to start
}
-
+
}
-
-
- /**
- * Download worker. Performs the pending downloads in the order they were requested.
- *
- * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}.
+
+
+ /**
+ * Download worker. Performs the pending downloads in the order they were requested.
+ * <p/>
+ * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}.
*/
private static class ServiceHandler extends Handler {
- // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak
+ // don't make it a final class, and don't remove the static ; lint will warn about a
+ // possible memory leak
FileDownloader mService;
+
public ServiceHandler(Looper looper, FileDownloader service) {
super(looper);
if (service == null)
if (msg.obj != null) {
Iterator<String> it = requestedDownloads.iterator();
while (it.hasNext()) {
- mService.downloadFile(it.next());
+ String next = it.next();
+ mService.downloadFile(next);
}
}
+ Log_OC.d(TAG, "Stopping after command with id " + msg.arg1);
mService.stopSelf(msg.arg1);
}
}
-
+
/**
* Core download method: requests a file to download and stores it.
- *
- * @param downloadKey Key to access the download to perform, contained in mPendingDownloads
+ *
+ * @param downloadKey Key to access the download to perform, contained in mPendingDownloads
*/
private void downloadFile(String downloadKey) {
-
- synchronized(mPendingDownloads) {
- mCurrentDownload = mPendingDownloads.get(downloadKey);
- }
-
+
+ /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
+ "Getting download of " + downloadKey);*/
+ mCurrentDownload = mPendingDownloads.get(downloadKey);
+
if (mCurrentDownload != null) {
-
- notifyDownloadStart(mCurrentDownload);
+ // Detect if the account exists
+ if (AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) {
+ Log_OC.d(TAG, "Account " + mCurrentDownload.getAccount().name + " exists");
+ notifyDownloadStart(mCurrentDownload);
- RemoteOperationResult downloadResult = null;
- try {
- /// prepare client object to send the request to the ownCloud server
- if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {
- mLastAccount = mCurrentDownload.getAccount();
- mStorageManager =
- new FileDataStorageManager(mLastAccount, getContentResolver());
- OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this);
+ RemoteOperationResult downloadResult = null;
+ try {
+ /// prepare client object to send the request to the ownCloud server
+ if (mCurrentAccount == null ||
+ !mCurrentAccount.equals(mCurrentDownload.getAccount())) {
+ mCurrentAccount = mCurrentDownload.getAccount();
+ mStorageManager = new FileDataStorageManager(
+ mCurrentAccount,
+ getContentResolver()
+ );
+ } // else, reuse storage manager from previous operation
+
+ // always get client from client manager, to get fresh credentials in case
+ // of update
+ OwnCloudAccount ocAccount = new OwnCloudAccount(mCurrentAccount, this);
mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
getClientFor(ocAccount, this);
- }
- /// perform the download
- downloadResult = mCurrentDownload.execute(mDownloadClient);
- if (downloadResult.isSuccess()) {
- saveDownloadedFile();
- }
-
- } catch (AccountsException e) {
- Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
- downloadResult = new RemoteOperationResult(e);
- } catch (IOException e) {
- Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
- downloadResult = new RemoteOperationResult(e);
-
- } finally {
- synchronized(mPendingDownloads) {
- mPendingDownloads.remove(downloadKey);
+
+ /// perform the download
+ /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
+ "Executing download of " + mCurrentDownload.getRemotePath());*/
+ downloadResult = mCurrentDownload.execute(mDownloadClient);
+ if (downloadResult.isSuccess()) {
+ saveDownloadedFile();
+ }
+
+ } catch (AccountsException e) {
+ Log_OC.e(TAG, "Error while trying to get authorization for "
+ + mCurrentAccount.name, e);
+ downloadResult = new RemoteOperationResult(e);
+ } catch (IOException e) {
+ Log_OC.e(TAG, "Error while trying to get authorization for "
+ + mCurrentAccount.name, e);
+ downloadResult = new RemoteOperationResult(e);
+
+ } finally {
+ /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
+ "Removing payload " + mCurrentDownload.getRemotePath());*/
+
+ Pair<DownloadFileOperation, String> removeResult =
+ mPendingDownloads.removePayload(mCurrentAccount,
+ mCurrentDownload.getRemotePath());
+
+ /// notify result
+ notifyDownloadResult(mCurrentDownload, downloadResult);
+
+ sendBroadcastDownloadFinished(mCurrentDownload, downloadResult,
+ removeResult.second);
}
- }
+ } else {
+ // Cancel the transfer
+ Log_OC.d(TAG, "Account " + mCurrentDownload.getAccount().toString() +
+ " doesn't exist");
+ cancelDownloadsForAccount(mCurrentDownload.getAccount());
-
- /// notify result
- notifyDownloadResult(mCurrentDownload, downloadResult);
-
- sendBroadcastDownloadFinished(mCurrentDownload, downloadResult);
+ }
}
}
file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));
file.setRemoteId(mCurrentDownload.getFile().getRemoteId());
mStorageManager.saveFile(file);
+ mStorageManager.triggerMediaScan(file.getStoragePath());
+ }
+
+ /**
+ * Update the OC File after a unsuccessful download
+ */
+ private void updateUnsuccessfulDownloadedFile() {
+ OCFile file = mStorageManager.getFileById(mCurrentDownload.getFile().getFileId());
+ file.setDownloading(false);
+ mStorageManager.saveFile(file);
}
/**
* Creates a status notification to show the download progress
- *
- * @param download Download operation starting.
+ *
+ * @param download Download operation starting.
*/
private void notifyDownloadStart(DownloadFileOperation download) {
/// create status notification with a progress bar
mLastPercent = 0;
- mNotificationBuilder =
+ mNotificationBuilder =
NotificationBuilderWithProgressBar.newNotificationBuilderWithProgressBar(this);
mNotificationBuilder
.setSmallIcon(R.drawable.notification_icon)
String.format(getString(R.string.downloader_download_in_progress_content), 0,
new File(download.getSavePath()).getName())
);
-
+
/// includes a pending intent in the notification showing the details view of the file
Intent showDetailsIntent = null;
if (PreviewImageFragment.canBePreviewed(download.getFile())) {
showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile());
showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, download.getAccount());
showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-
+
mNotificationBuilder.setContentIntent(PendingIntent.getActivity(
- this, (int) System.currentTimeMillis(), showDetailsIntent, 0
+ this, (int) System.currentTimeMillis(), showDetailsIntent, 0
));
mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build());
}
-
+
/**
* Callback method to update the progress bar in the status notification.
*/
@Override
- public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filePath) {
- int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
+ public void onTransferProgress(long progressRate, long totalTransferredSoFar,
+ long totalToTransfer, String filePath) {
+ int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer));
if (percent != mLastPercent) {
mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0);
String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1);
}
mLastPercent = percent;
}
-
-
+
+
/**
* Updates the status notification with the result of a download operation.
- *
- * @param downloadResult Result of the download operation.
- * @param download Finished download operation
+ *
+ * @param downloadResult Result of the download operation.
+ * @param download Finished download operation
*/
- private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) {
+ private void notifyDownloadResult(DownloadFileOperation download,
+ RemoteOperationResult downloadResult) {
mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker);
if (!downloadResult.isCancelled()) {
- int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker :
- R.string.downloader_download_failed_ticker;
-
+ int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker :
+ R.string.downloader_download_failed_ticker;
+
boolean needsToUpdateCredentials = (
downloadResult.getCode() == ResultCode.UNAUTHORIZED ||
- downloadResult.isIdPRedirection()
+ downloadResult.isIdPRedirection()
);
- tickerId = (needsToUpdateCredentials) ?
+ tickerId = (needsToUpdateCredentials) ?
R.string.downloader_download_failed_credentials_error : tickerId;
-
+
mNotificationBuilder
- .setTicker(getString(tickerId))
- .setContentTitle(getString(tickerId))
- .setAutoCancel(true)
- .setOngoing(false)
- .setProgress(0, 0, false);
-
+ .setTicker(getString(tickerId))
+ .setContentTitle(getString(tickerId))
+ .setAutoCancel(true)
+ .setOngoing(false)
+ .setProgress(0, 0, false);
+
if (needsToUpdateCredentials) {
-
+
// let the user update credentials with one click
Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
- updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, download.getAccount());
- updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
+ updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT,
+ download.getAccount());
+ updateAccountCredentials.putExtra(
+ AuthenticatorActivity.EXTRA_ACTION,
+ AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN
+ );
updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
mNotificationBuilder
- .setContentIntent(PendingIntent.getActivity(
- this, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT));
-
- mDownloadClient = null; // grant that future retries on the same account will get the fresh credentials
-
+ .setContentIntent(PendingIntent.getActivity(
+ this, (int) System.currentTimeMillis(), updateAccountCredentials,
+ PendingIntent.FLAG_ONE_SHOT));
+
} else {
// TODO put something smart in showDetailsIntent
- Intent showDetailsIntent = new Intent();
+ Intent showDetailsIntent = new Intent();
mNotificationBuilder
- .setContentIntent(PendingIntent.getActivity(
- this, (int) System.currentTimeMillis(), showDetailsIntent, 0));
+ .setContentIntent(PendingIntent.getActivity(
+ this, (int) System.currentTimeMillis(), showDetailsIntent, 0));
}
-
- mNotificationBuilder.setContentText(ErrorMessageAdapter.getErrorCauseMessage(downloadResult, download, getResources()));
+
+ mNotificationBuilder.setContentText(
+ ErrorMessageAdapter.getErrorCauseMessage(downloadResult, download,
+ getResources())
+ );
mNotificationManager.notify(tickerId, mNotificationBuilder.build());
-
+
// Remove success notification
- if (downloadResult.isSuccess()) {
+ if (downloadResult.isSuccess()) {
// Sleep 2 seconds, so show the notification before remove it
NotificationDelayer.cancelWithDelay(
- mNotificationManager,
- R.string.downloader_download_succeeded_ticker,
+ mNotificationManager,
+ R.string.downloader_download_succeeded_ticker,
2000);
}
-
+
}
}
-
-
+
+
/**
- * Sends a broadcast when a download finishes in order to the interested activities can update their view
- *
- * @param download Finished download operation
- * @param downloadResult Result of the download operation
+ * Sends a broadcast when a download finishes in order to the interested activities can
+ * update their view
+ *
+ * @param download Finished download operation
+ * @param downloadResult Result of the download operation
+ * @param unlinkedFromRemotePath Path in the downloads tree where the download was unlinked from
*/
- private void sendBroadcastDownloadFinished(DownloadFileOperation download, RemoteOperationResult downloadResult) {
+ private void sendBroadcastDownloadFinished(
+ DownloadFileOperation download,
+ RemoteOperationResult downloadResult,
+ String unlinkedFromRemotePath) {
Intent end = new Intent(getDownloadFinishMessage());
end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess());
end.putExtra(ACCOUNT_NAME, download.getAccount().name);
end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());
end.putExtra(EXTRA_FILE_PATH, download.getSavePath());
+ if (unlinkedFromRemotePath != null) {
+ end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath);
+ }
sendStickyBroadcast(end);
}
-
-
+
+
/**
* Sends a broadcast when a new download is added to the queue.
- *
- * @param download Added download operation
+ *
+ * @param download Added download operation
+ * @param linkedToRemotePath Path in the downloads tree where the download was linked to
*/
- private void sendBroadcastNewDownload(DownloadFileOperation download) {
+ private void sendBroadcastNewDownload(DownloadFileOperation download,
+ String linkedToRemotePath) {
Intent added = new Intent(getDownloadAddedMessage());
added.putExtra(ACCOUNT_NAME, download.getAccount().name);
added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());
added.putExtra(EXTRA_FILE_PATH, download.getSavePath());
+ added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath);
sendStickyBroadcast(added);
}
+ /**
+ * Remove downloads of an account
+ *
+ * @param account Downloads account to remove
+ */
+ private void cancelDownloadsForAccount(Account account) {
+ // Cancel pending downloads
+ mPendingDownloads.remove(account);
+ }
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2012-2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountsException;
+import android.accounts.OnAccountsUpdateListener;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
-import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.utils.UriUtils;
-
-public class FileUploader extends Service implements OnDatatransferProgressListener {
+public class FileUploader extends Service
+ implements OnDatatransferProgressListener, OnAccountsUpdateListener {
private static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH";
public static final String EXTRA_UPLOAD_RESULT = "RESULT";
private Account mLastAccount = null;
private FileDataStorageManager mStorageManager;
- private ConcurrentMap<String, UploadFileOperation> mPendingUploads = new ConcurrentHashMap<String, UploadFileOperation>();
+ private ConcurrentMap<String, UploadFileOperation> mPendingUploads =
+ new ConcurrentHashMap<String, UploadFileOperation>();
private UploadFileOperation mCurrentUpload = null;
private NotificationManager mNotificationManager;
private static final String MIME_TYPE_PDF = "application/pdf";
private static final String FILE_EXTENSION_PDF = ".pdf";
-
+
public static String getUploadFinishMessage() {
- return FileUploader.class.getName().toString() + UPLOAD_FINISH_MESSAGE;
+ return FileUploader.class.getName() + UPLOAD_FINISH_MESSAGE;
}
-
+
/**
* Builds a key for mPendingUploads from the account and file to upload
- *
+ *
* @param account Account where the file to upload is stored
* @param file File to upload
*/
/**
* Checks if an ownCloud server version should support chunked uploads.
- *
+ *
* @param version OwnCloud version instance corresponding to an ownCloud
* server.
* @return 'True' if the ownCloud server with version supports chunked
@Override
public void onCreate() {
super.onCreate();
- Log_OC.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
+ Log_OC.d(TAG, "Creating service");
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- HandlerThread thread = new HandlerThread("FileUploaderThread", Process.THREAD_PRIORITY_BACKGROUND);
+ HandlerThread thread = new HandlerThread("FileUploaderThread",
+ Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper, this);
mBinder = new FileUploaderBinder();
+
+ // add AccountsUpdatedListener
+ AccountManager am = AccountManager.get(getApplicationContext());
+ am.addOnAccountsUpdatedListener(this, null, false);
}
/**
+ * Service clean up
+ */
+ @Override
+ public void onDestroy() {
+ Log_OC.v(TAG, "Destroying service" );
+ mBinder = null;
+ mServiceHandler = null;
+ mServiceLooper.quit();
+ mServiceLooper = null;
+ mNotificationManager = null;
+
+ // remove AccountsUpdatedListener
+ AccountManager am = AccountManager.get(getApplicationContext());
+ am.removeOnAccountsUpdatedListener(this);
+
+ super.onDestroy();
+ }
+
+
+ /**
* Entry point to add one or several files to the queue of uploads.
- *
+ *
* New uploads are added calling to startService(), resulting in a call to
* this method. This ensures the service will keep on working although the
* caller activity goes away.
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
+ Log_OC.d(TAG, "Starting command with id " + startId);
+
if (!intent.hasExtra(KEY_ACCOUNT) || !intent.hasExtra(KEY_UPLOAD_TYPE)
|| !(intent.hasExtra(KEY_LOCAL_FILE) || intent.hasExtra(KEY_FILE))) {
Log_OC.e(TAG, "Not enough information provided in intent");
}
}
- FileDataStorageManager storageManager = new FileDataStorageManager(account, getContentResolver());
+ FileDataStorageManager storageManager = new FileDataStorageManager(account,
+ getContentResolver());
boolean forceOverwrite = intent.getBooleanExtra(KEY_FORCE_OVERWRITE, false);
boolean isInstant = intent.getBooleanExtra(KEY_INSTANT_UPLOAD, false);
int localAction = intent.getIntExtra(KEY_LOCAL_BEHAVIOUR, LOCAL_BEHAVIOUR_COPY);
-
+
if (intent.hasExtra(KEY_FILE) && files == null) {
Log_OC.e(TAG, "Incorrect array for OCFiles provided in upload intent");
return Service.START_NOT_STICKY;
files = new OCFile[localPaths.length];
for (int i = 0; i < localPaths.length; i++) {
- files[i] = obtainNewOCFileToUpload(remotePaths[i], localPaths[i], ((mimeTypes != null) ? mimeTypes[i]
- : (String) null), storageManager);
+ files[i] = obtainNewOCFileToUpload(remotePaths[i], localPaths[i],
+ ((mimeTypes != null) ? mimeTypes[i] : null), storageManager);
if (files[i] == null) {
// TODO @andomaex add failure Notification
return Service.START_NOT_STICKY;
}
}
- AccountManager aMgr = AccountManager.get(this);
- String version = aMgr.getUserData(account, Constants.KEY_OC_VERSION);
- OwnCloudVersion ocv = new OwnCloudVersion(version);
-
+ OwnCloudVersion ocv = AccountUtils.getServerVersion(account);
+
boolean chunked = FileUploader.chunkedUploadIsSupported(ocv);
AbstractList<String> requestedUploads = new Vector<String>();
String uploadKey = null;
try {
for (int i = 0; i < files.length; i++) {
uploadKey = buildRemoteName(account, files[i].getRemotePath());
- newUpload = new UploadFileOperation(account, files[i], chunked, isInstant, forceOverwrite, localAction,
+ newUpload = new UploadFileOperation(account, files[i], chunked, isInstant,
+ forceOverwrite, localAction,
getApplicationContext());
if (isInstant) {
newUpload.setRemoteFolderToBeCreated();
}
- mPendingUploads.putIfAbsent(uploadKey, newUpload); // Grants that the file only upload once time
+ // Grants that the file only upload once time
+ mPendingUploads.putIfAbsent(uploadKey, newUpload);
newUpload.addDatatransferProgressListener(this);
newUpload.addDatatransferProgressListener((FileUploaderBinder)mBinder);
/**
* Provides a binder object that clients can use to perform operations on
* the queue of uploads, excepting the addition of new files.
- *
+ *
* Implemented to perform cancellation, pause and resume of existing
* uploads.
*/
public IBinder onBind(Intent arg0) {
return mBinder;
}
-
+
/**
* Called when ALL the bound clients were onbound.
*/
((FileUploaderBinder)mBinder).clearListeners();
return false; // not accepting rebinding (default behaviour)
}
-
+
+ @Override
+ public void onAccountsUpdated(Account[] accounts) {
+ // Review current upload, and cancel it if its account doen't exist
+ if (mCurrentUpload != null &&
+ !AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) {
+ mCurrentUpload.cancel();
+ }
+ // The rest of uploads are cancelled when they try to start
+ }
/**
* Binder to let client components to perform operations on the queue of
* uploads.
- *
+ *
* It provides by itself the available operations.
*/
public class FileUploaderBinder extends Binder implements OnDatatransferProgressListener {
-
- /**
- * Map of listeners that will be reported about progress of uploads from a {@link FileUploaderBinder} instance
+
+ /**
+ * Map of listeners that will be reported about progress of uploads from a
+ * {@link FileUploaderBinder} instance
*/
- private Map<String, OnDatatransferProgressListener> mBoundListeners = new HashMap<String, OnDatatransferProgressListener>();
-
+ private Map<String, OnDatatransferProgressListener> mBoundListeners =
+ new HashMap<String, OnDatatransferProgressListener>();
+
/**
* Cancels a pending or current upload of a remote file.
- *
+ *
* @param account Owncloud account where the remote file will be stored.
* @param file A file in the queue of pending uploads
*/
public void cancel(Account account, OCFile file) {
- UploadFileOperation upload = null;
+ UploadFileOperation upload;
synchronized (mPendingUploads) {
upload = mPendingUploads.remove(buildRemoteName(account, file));
}
upload.cancel();
}
}
-
-
-
+
+ /**
+ * Cancels a pending or current upload for an account
+ *
+ * @param account Owncloud accountName where the remote file will be stored.
+ */
+ public void cancel(Account account) {
+ Log_OC.d(TAG, "Account= " + account.name);
+
+ if (mCurrentUpload != null) {
+ Log_OC.d(TAG, "Current Upload Account= " + mCurrentUpload.getAccount().name);
+ if (mCurrentUpload.getAccount().name.equals(account.name)) {
+ mCurrentUpload.cancel();
+ }
+ }
+ // Cancel pending uploads
+ cancelUploadForAccount(account.name);
+ }
+
public void clearListeners() {
mBoundListeners.clear();
}
-
-
-
/**
* Returns True when the file described by 'file' is being uploaded to
* the ownCloud account 'account' or waiting for it
- *
- * If 'file' is a directory, returns 'true' if some of its descendant files is uploading or waiting to upload.
- *
- * @param account Owncloud account where the remote file will be stored.
- * @param file A file that could be in the queue of pending uploads
+ *
+ * If 'file' is a directory, returns 'true' if some of its descendant files
+ * is uploading or waiting to upload.
+ *
+ * @param account ownCloud account where the remote file will be stored.
+ * @param file A file that could be in the queue of pending uploads
*/
public boolean isUploading(Account account, OCFile file) {
if (account == null || file == null)
/**
* Adds a listener interested in the progress of the upload for a concrete file.
- *
+ *
* @param listener Object to notify about progress of transfer.
* @param account ownCloud account holding the file of interest.
- * @param file {@link OCfile} of interest for listener.
+ * @param file {@link OCFile} of interest for listener.
*/
- public void addDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {
+ public void addDatatransferProgressListener (OnDatatransferProgressListener listener,
+ Account account, OCFile file) {
if (account == null || file == null || listener == null) return;
String targetKey = buildRemoteName(account, file);
mBoundListeners.put(targetKey, listener);
}
-
-
-
+
+
+
/**
* Removes a listener interested in the progress of the upload for a concrete file.
- *
+ *
* @param listener Object to notify about progress of transfer.
* @param account ownCloud account holding the file of interest.
- * @param file {@link OCfile} of interest for listener.
+ * @param file {@link OCFile} of interest for listener.
*/
- public void removeDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {
+ public void removeDatatransferProgressListener (OnDatatransferProgressListener listener,
+ Account account, OCFile file) {
if (account == null || file == null || listener == null) return;
String targetKey = buildRemoteName(account, file);
if (mBoundListeners.get(targetKey) == listener) {
@Override
- public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,
- String fileName) {
+ public void onTransferProgress(long progressRate, long totalTransferredSoFar,
+ long totalToTransfer, String fileName) {
String key = buildRemoteName(mCurrentUpload.getAccount(), mCurrentUpload.getFile());
OnDatatransferProgressListener boundListener = mBoundListeners.get(key);
if (boundListener != null) {
- boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);
+ boundListener.onTransferProgress(progressRate, totalTransferredSoFar,
+ totalToTransfer, fileName);
+ }
+ }
+
+ /**
+ * Review uploads and cancel it if its account doesn't exist
+ */
+ public void checkAccountOfCurrentUpload() {
+ if (mCurrentUpload != null &&
+ !AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) {
+ mCurrentUpload.cancel();
}
+ // The rest of uploads are cancelled when they try to start
}
-
}
/**
* Upload worker. Performs the pending uploads in the order they were
* requested.
- *
+ *
* Created with the Looper of a new thread, started in
* {@link FileUploader#onCreate()}.
*/
mService.uploadFile(it.next());
}
}
+ Log_OC.d(TAG, "Stopping command after id " + msg.arg1);
mService.stopSelf(msg.arg1);
}
}
/**
* Core upload method: sends the file(s) to upload
- *
+ *
* @param uploadKey Key to access the upload to perform, contained in
* mPendingUploads
*/
if (mCurrentUpload != null) {
- notifyUploadStart(mCurrentUpload);
+ // Detect if the account exists
+ if (AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) {
+ Log_OC.d(TAG, "Account " + mCurrentUpload.getAccount().name + " exists");
- RemoteOperationResult uploadResult = null, grantResult = null;
-
- try {
- /// prepare client object to send requests to the ownCloud server
- if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) {
- mLastAccount = mCurrentUpload.getAccount();
- mStorageManager =
- new FileDataStorageManager(mLastAccount, getContentResolver());
- OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this);
- mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
- getClientFor(ocAccount, this);
- }
-
- /// check the existence of the parent folder for the file to upload
- String remoteParentPath = new File(mCurrentUpload.getRemotePath()).getParent();
- remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ? remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR;
- grantResult = grantFolderExistence(remoteParentPath);
-
- /// perform the upload
- if (grantResult.isSuccess()) {
- OCFile parent = mStorageManager.getFileByPath(remoteParentPath);
- mCurrentUpload.getFile().setParentId(parent.getFileId());
- uploadResult = mCurrentUpload.execute(mUploadClient);
- if (uploadResult.isSuccess()) {
- saveUploadedFile();
+ notifyUploadStart(mCurrentUpload);
+
+ RemoteOperationResult uploadResult = null, grantResult;
+
+ try {
+ /// prepare client object to send requests to the ownCloud server
+ if (mUploadClient == null ||
+ !mLastAccount.equals(mCurrentUpload.getAccount())) {
+ mLastAccount = mCurrentUpload.getAccount();
+ mStorageManager =
+ new FileDataStorageManager(mLastAccount, getContentResolver());
+ OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this);
+ mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+ getClientFor(ocAccount, this);
+ }
+
+ /// check the existence of the parent folder for the file to upload
+ String remoteParentPath = new File(mCurrentUpload.getRemotePath()).getParent();
+ remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ?
+ remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR;
+ grantResult = grantFolderExistence(remoteParentPath);
+
+ /// perform the upload
+ if (grantResult.isSuccess()) {
+ OCFile parent = mStorageManager.getFileByPath(remoteParentPath);
+ mCurrentUpload.getFile().setParentId(parent.getFileId());
+ uploadResult = mCurrentUpload.execute(mUploadClient);
+ if (uploadResult.isSuccess()) {
+ saveUploadedFile();
+ }
+ } else {
+ uploadResult = grantResult;
+ }
+
+ } catch (AccountsException e) {
+ Log_OC.e(TAG, "Error while trying to get autorization for " +
+ mLastAccount.name, e);
+ uploadResult = new RemoteOperationResult(e);
+
+ } catch (IOException e) {
+ Log_OC.e(TAG, "Error while trying to get autorization for " +
+ mLastAccount.name, e);
+ uploadResult = new RemoteOperationResult(e);
+
+ } finally {
+ synchronized (mPendingUploads) {
+ mPendingUploads.remove(uploadKey);
+ Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
+ }
+ if (uploadResult != null && uploadResult.isException()) {
+ // enforce the creation of a new client object for next uploads;
+ // this grant that a new socket will be created in the future if
+ // the current exception is due to an abrupt lose of network connection
+ mUploadClient = null;
}
- } else {
- uploadResult = grantResult;
- }
-
- } catch (AccountsException e) {
- Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
- uploadResult = new RemoteOperationResult(e);
-
- } catch (IOException e) {
- Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
- uploadResult = new RemoteOperationResult(e);
-
- } finally {
- synchronized (mPendingUploads) {
- mPendingUploads.remove(uploadKey);
- Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
- }
- if (uploadResult.isException()) {
- // enforce the creation of a new client object for next uploads; this grant that a new socket will
- // be created in the future if the current exception is due to an abrupt lose of network connection
- mUploadClient = null;
}
- }
-
- /// notify result
-
- notifyUploadResult(uploadResult, mCurrentUpload);
- sendFinalBroadcast(mCurrentUpload, uploadResult);
+ /// notify result
+ notifyUploadResult(uploadResult, mCurrentUpload);
+ sendFinalBroadcast(mCurrentUpload, uploadResult);
+
+ } else {
+ // Cancel the transfer
+ Log_OC.d(TAG, "Account " + mCurrentUpload.getAccount().toString() +
+ " doesn't exist");
+ cancelUploadForAccount(mCurrentUpload.getAccount().name);
+
+ }
}
}
/**
- * Checks the existence of the folder where the current file will be uploaded both in the remote server
- * and in the local database.
- *
- * If the upload is set to enforce the creation of the folder, the method tries to create it both remote
- * and locally.
- *
+ * Checks the existence of the folder where the current file will be uploaded both
+ * in the remote server and in the local database.
+ *
+ * If the upload is set to enforce the creation of the folder, the method tries to
+ * create it both remote and locally.
+ *
* @param pathToGrant Full remote path whose existence will be granted.
- * @return An {@link OCFile} instance corresponding to the folder where the file will be uploaded.
+ * @return An {@link OCFile} instance corresponding to the folder where the file
+ * will be uploaded.
*/
private RemoteOperationResult grantFolderExistence(String pathToGrant) {
RemoteOperation operation = new ExistenceCheckRemoteOperation(pathToGrant, this, false);
RemoteOperationResult result = operation.execute(mUploadClient);
- if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND && mCurrentUpload.isRemoteFolderToBeCreated()) {
+ if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND &&
+ mCurrentUpload.isRemoteFolderToBeCreated()) {
SyncOperation syncOp = new CreateFolderOperation( pathToGrant, true);
result = syncOp.execute(mUploadClient, mStorageManager);
}
return result;
}
-
+
private OCFile createLocalFolder(String remotePath) {
String parentPath = new File(remotePath).getParent();
- parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
+ parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ?
+ parentPath : parentPath + OCFile.PATH_SEPARATOR;
OCFile parent = mStorageManager.getFileByPath(parentPath);
if (parent == null) {
parent = createLocalFolder(parentPath);
}
return null;
}
-
+
/**
* Saves a OC File after a successful upload.
- *
+ *
* A PROPFIND is necessary to keep the props in the local database
* synchronized with the server, specially the modification time and Etag
* (where available)
- *
+ *
* TODO refactor this ugly thing
*/
private void saveUploadedFile() {
// new PROPFIND to keep data consistent with server
// in theory, should return the same we already have
- ReadRemoteFileOperation operation = new ReadRemoteFileOperation(mCurrentUpload.getRemotePath());
+ ReadRemoteFileOperation operation =
+ new ReadRemoteFileOperation(mCurrentUpload.getRemotePath());
RemoteOperationResult result = operation.execute(mUploadClient);
if (result.isSuccess()) {
updateOCFile(file, (RemoteFile) result.getData().get(0));
file.setLastSyncDateForProperties(syncDate);
}
-
+
// / maybe this would be better as part of UploadFileOperation... or
// maybe all this method
if (mCurrentUpload.wasRenamed()) {
mStorageManager.saveFile(oldFile);
} // else: it was just an automatic renaming due to a name
- // coincidence; nothing else is needed, the storagePath is right
- // in the instance returned by mCurrentUpload.getFile()
+ // coincidence; nothing else is needed, the storagePath is right
+ // in the instance returned by mCurrentUpload.getFile()
}
file.setNeedsUpdateThumbnail(true);
mStorageManager.saveFile(file);
}
private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType,
- FileDataStorageManager storageManager) {
+ FileDataStorageManager storageManager) {
// MIME type
if (mimeType == null || mimeType.length() <= 0) {
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
remotePath.substring(remotePath.lastIndexOf('.') + 1));
} catch (IndexOutOfBoundsException e) {
- Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + remotePath);
+ Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " +
+ remotePath);
}
}
if (mimeType == null) {
newFile.setFileLength(localFile.length());
newFile.setLastSyncDateForData(localFile.lastModified());
} // don't worry about not assigning size, the problems with localPath
- // are checked when the UploadFileOperation instance is created
+ // are checked when the UploadFileOperation instance is created
newFile.setMimetype(mimeType);
/**
* Creates a status notification to show the upload progress
- *
+ *
* @param upload Upload operation starting.
*/
private void notifyUploadStart(UploadFileOperation upload) {
// / create status notification with a progress bar
mLastPercent = 0;
- mNotificationBuilder =
+ mNotificationBuilder =
NotificationBuilderWithProgressBar.newNotificationBuilderWithProgressBar(this);
mNotificationBuilder
.setOngoing(true)
showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, upload.getAccount());
showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
mNotificationBuilder.setContentIntent(PendingIntent.getActivity(
- this, (int) System.currentTimeMillis(), showDetailsIntent, 0
+ this, (int) System.currentTimeMillis(), showDetailsIntent, 0
));
mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotificationBuilder.build());
* Callback method to update the progress bar in the status notification
*/
@Override
- public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filePath) {
+ public void onTransferProgress(long progressRate, long totalTransferredSoFar,
+ long totalToTransfer, String filePath) {
int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer));
if (percent != mLastPercent) {
mNotificationBuilder.setProgress(100, percent, false);
- String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1);
+ String fileName = filePath.substring(
+ filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1);
String text = String.format(getString(R.string.uploader_upload_in_progress_content), percent, fileName);
mNotificationBuilder.setContentText(text);
mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotificationBuilder.build());
/**
* Updates the status notification with the result of an upload operation.
- *
+ *
* @param uploadResult Result of the upload operation.
* @param upload Finished upload operation
*/
Log_OC.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode());
// / cancelled operation or success -> silent removal of progress notification
mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);
-
+
// Show the result: success or fail notification
if (!uploadResult.isCancelled()) {
- int tickerId = (uploadResult.isSuccess()) ? R.string.uploader_upload_succeeded_ticker :
- R.string.uploader_upload_failed_ticker;
-
- String content = null;
+ int tickerId = (uploadResult.isSuccess()) ? R.string.uploader_upload_succeeded_ticker :
+ R.string.uploader_upload_failed_ticker;
+
+ String content;
// check credentials error
boolean needsToUpdateCredentials = (
- uploadResult.getCode() == ResultCode.UNAUTHORIZED ||
- uploadResult.isIdPRedirection()
+ uploadResult.getCode() == ResultCode.UNAUTHORIZED ||
+ uploadResult.isIdPRedirection()
);
- tickerId = (needsToUpdateCredentials) ?
+ tickerId = (needsToUpdateCredentials) ?
R.string.uploader_upload_failed_credentials_error : tickerId;
mNotificationBuilder
- .setTicker(getString(tickerId))
- .setContentTitle(getString(tickerId))
- .setAutoCancel(true)
- .setOngoing(false)
- .setProgress(0, 0, false);
-
+ .setTicker(getString(tickerId))
+ .setContentTitle(getString(tickerId))
+ .setAutoCancel(true)
+ .setOngoing(false)
+ .setProgress(0, 0, false);
+
content = ErrorMessageAdapter.getErrorCauseMessage(
uploadResult, upload, getResources()
);
-
+
if (needsToUpdateCredentials) {
// let the user update credentials with one click
Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
AuthenticatorActivity.EXTRA_ACCOUNT, upload.getAccount()
);
updateAccountCredentials.putExtra(
- AuthenticatorActivity.EXTRA_ACTION,
+ AuthenticatorActivity.EXTRA_ACTION,
AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN
);
updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
mNotificationBuilder.setContentIntent(PendingIntent.getActivity(
- this,
- (int) System.currentTimeMillis(),
- updateAccountCredentials,
- PendingIntent.FLAG_ONE_SHOT
+ this,
+ (int) System.currentTimeMillis(),
+ updateAccountCredentials,
+ PendingIntent.FLAG_ONE_SHOT
));
-
- mUploadClient = null;
- // grant that future retries on the same account will get the fresh credentials
+
+ mUploadClient = null;
+ // grant that future retries on the same account will get the fresh credentials
} else {
mNotificationBuilder.setContentText(content);
-
+
if (upload.isInstant()) {
DbHandler db = null;
try {
if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) {
//message = getString(R.string.failed_upload_quota_exceeded_text);
if (db.updateFileState(
- upload.getOriginalStoragePath(),
+ upload.getOriginalStoragePath(),
DbHandler.UPLOAD_STATUS_UPLOAD_FAILED,
message) == 0) {
db.putFileForLater(
- upload.getOriginalStoragePath(),
- upload.getAccount().name,
+ upload.getOriginalStoragePath(),
+ upload.getAccount().name,
message
);
}
}
}
}
-
+
mNotificationBuilder.setContentText(content);
mNotificationManager.notify(tickerId, mNotificationBuilder.build());
-
+
if (uploadResult.isSuccess()) {
-
+
DbHandler db = new DbHandler(this.getBaseContext());
db.removeIUPendingFile(mCurrentUpload.getOriginalStoragePath());
db.close();
// remove success notification, with a delay of 2 seconds
NotificationDelayer.cancelWithDelay(
- mNotificationManager,
- R.string.uploader_upload_succeeded_ticker,
+ mNotificationManager,
+ R.string.uploader_upload_succeeded_ticker,
2000);
-
+
}
}
}
/**
* Sends a broadcast in order to the interested activities can update their
* view
- *
+ *
* @param upload Finished upload operation
* @param uploadResult Result of the upload operation
*/
private void sendFinalBroadcast(UploadFileOperation upload, RemoteOperationResult uploadResult) {
Intent end = new Intent(getUploadFinishMessage());
end.putExtra(EXTRA_REMOTE_PATH, upload.getRemotePath()); // real remote
- // path, after
- // possible
- // automatic
- // renaming
+ // path, after
+ // possible
+ // automatic
+ // renaming
if (upload.wasRenamed()) {
end.putExtra(EXTRA_OLD_REMOTE_PATH, upload.getOldFile().getRemotePath());
}
/**
* Checks if content provider, using the content:// scheme, returns a file with mime-type
* 'application/pdf' but file has not extension
- * @param localPath
- * @param mimeType
+ * @param localPath Full path to a file in the local file system.
+ * @param mimeType MIME type of the file.
* @return true if is needed to add the pdf file extension to the file
*/
- private boolean isPdfFileFromContentProviderWithoutExtension(String localPath, String mimeType) {
- return localPath.startsWith(UriUtils.URI_CONTENT_SCHEME) &&
- mimeType.equals(MIME_TYPE_PDF) &&
+ private boolean isPdfFileFromContentProviderWithoutExtension(String localPath,
+ String mimeType) {
+ return localPath.startsWith(UriUtils.URI_CONTENT_SCHEME) &&
+ mimeType.equals(MIME_TYPE_PDF) &&
!localPath.endsWith(FILE_EXTENSION_PDF);
}
+ /**
+ * Remove uploads of an account
+ * @param accountName Name of an OC account
+ */
+ private void cancelUploadForAccount(String accountName){
+ // this can be slow if there are many uploads :(
+ Iterator<String> it = mPendingUploads.keySet().iterator();
+ Log_OC.d(TAG, "Number of pending updloads= " + mPendingUploads.size());
+ while (it.hasNext()) {
+ String key = it.next();
+ Log_OC.d(TAG, "mPendingUploads CANCELLED " + key);
+ if (key.startsWith(accountName)) {
+ synchronized (mPendingUploads) {
+ mPendingUploads.remove(key);
+ }
+ }
+ }
+ }
}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.files.services;
+
+import android.accounts.Account;
+import android.util.Pair;
+
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Helper structure to keep the trees of folders containing any file downloading or synchronizing.
+ *
+ * A map provides the indexation based in hashing.
+ *
+ * A tree is created per account.
+ */
+public class IndexedForest<V> {
+
+ private ConcurrentMap<String, Node<V>> mMap = new ConcurrentHashMap<String, Node<V>>();
+
+ private class Node<V> {
+ String mKey = null;
+ Node<V> mParent = null;
+ Set<Node<V>> mChildren = new HashSet<Node<V>>(); // TODO be careful with hash()
+ V mPayload = null;
+
+ // payload is optional
+ public Node(String key, V payload) {
+ if (key == null) {
+ throw new IllegalArgumentException("Argument key MUST NOT be null");
+ }
+ mKey = key;
+ mPayload = payload;
+ }
+
+ public Node<V> getParent() {
+ return mParent;
+ };
+
+ public Set<Node<V>> getChildren() {
+ return mChildren;
+ }
+
+ public String getKey() {
+ return mKey;
+ }
+
+ public V getPayload() {
+ return mPayload;
+ }
+
+ public void addChild(Node<V> child) {
+ mChildren.add(child);
+ child.setParent(this);
+ }
+
+ private void setParent(Node<V> parent) {
+ mParent = parent;
+ }
+
+ public boolean hasChildren() {
+ return mChildren.size() > 0;
+ }
+
+ public void removeChild(Node<V> removed) {
+ mChildren.remove(removed);
+ }
+
+ public void clearPayload() {
+ mPayload = null;
+ }
+ }
+
+
+ public /* synchronized */ Pair<String, String> putIfAbsent(Account account, String remotePath, V value) {
+ String targetKey = buildKey(account, remotePath);
+ Node<V> valuedNode = new Node(targetKey, value);
+ mMap.putIfAbsent(
+ targetKey,
+ valuedNode
+ );
+
+ String currentPath = remotePath, parentPath = null, parentKey = null;
+ Node<V> currentNode = valuedNode, parentNode = null;
+ boolean linked = false;
+ while (!OCFile.ROOT_PATH.equals(currentPath) && !linked) {
+ parentPath = new File(currentPath).getParent();
+ if (!parentPath.endsWith(OCFile.PATH_SEPARATOR)) {
+ parentPath += OCFile.PATH_SEPARATOR;
+ }
+ parentKey = buildKey(account, parentPath);
+ parentNode = mMap.get(parentKey);
+ if (parentNode == null) {
+ parentNode = new Node(parentKey, null);
+ parentNode.addChild(currentNode);
+ mMap.put(parentKey, parentNode);
+ } else {
+ parentNode.addChild(currentNode);
+ linked = true;
+ }
+ currentPath = parentPath;
+ currentNode = parentNode;
+ }
+
+ String linkedTo = OCFile.ROOT_PATH;
+ if (linked) {
+ linkedTo = parentNode.getKey().substring(account.name.length());
+ }
+ return new Pair<String, String>(targetKey, linkedTo);
+ };
+
+
+ public Pair<V, String> removePayload(Account account, String remotePath) {
+ String targetKey = buildKey(account, remotePath);
+ Node<V> target = mMap.get(targetKey);
+ if (target != null) {
+ target.clearPayload();
+ if (!target.hasChildren()) {
+ return remove(account, remotePath);
+ }
+ }
+ return new Pair<V, String>(null, null);
+ }
+
+
+ public /* synchronized */ Pair<V, String> remove(Account account, String remotePath) {
+ String targetKey = buildKey(account, remotePath);
+ Node<V> firstRemoved = mMap.remove(targetKey);
+ String unlinkedFrom = null;
+
+ if (firstRemoved != null) {
+ /// remove children
+ removeDescendants(firstRemoved);
+
+ /// remove ancestors if only here due to firstRemoved
+ Node<V> removed = firstRemoved;
+ Node<V> parent = removed.getParent();
+ boolean unlinked = false;
+ while (parent != null) {
+ parent.removeChild(removed);
+ if (!parent.hasChildren()) {
+ removed = mMap.remove(parent.getKey());
+ parent = removed.getParent();
+ } else {
+ break;
+ }
+ }
+
+ if (parent != null) {
+ unlinkedFrom = parent.getKey().substring(account.name.length());
+ }
+
+ return new Pair<V, String>(firstRemoved.getPayload(), unlinkedFrom);
+ }
+
+ return new Pair<V, String>(null, null);
+ }
+
+ private void removeDescendants(Node<V> removed) {
+ Iterator<Node<V>> childrenIt = removed.getChildren().iterator();
+ Node<V> child = null;
+ while (childrenIt.hasNext()) {
+ child = childrenIt.next();
+ mMap.remove(child.getKey());
+ removeDescendants(child);
+ }
+ }
+
+ public boolean contains(Account account, String remotePath) {
+ String targetKey = buildKey(account, remotePath);
+ return mMap.containsKey(targetKey);
+ }
+
+ public /* synchronized */ V get(String key) {
+ Node<V> node = mMap.get(key);
+ if (node != null) {
+ return node.getPayload();
+ } else {
+ return null;
+ }
+ }
+
+ public V get(Account account, String remotePath) {
+ String key = buildKey(account, remotePath);
+ return get(key);
+ }
+
+
+ /**
+ * Remove the elements that contains account as a part of its key
+ * @param account
+ */
+ public void remove(Account account){
+ Iterator<String> it = mMap.keySet().iterator();
+ while (it.hasNext()) {
+ String key = it.next();
+ Log_OC.d("IndexedForest", "Number of pending downloads= " + mMap.size());
+ if (key.startsWith(account.name)) {
+ mMap.remove(key);
+ }
+ }
+ }
+
+ /**
+ * Builds a key to index files
+ *
+ * @param account Account where the file to download is stored
+ * @param remotePath Path of the file in the server
+ */
+ private String buildKey(Account account, String remotePath) {
+ return account.name + remotePath;
+ }
+
+}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
-/* ownCloud Android client application
- *
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
*
* It synchronizes itself with the state of the
* {@link MediaPlayer}.
- *
- * @author David A. Velasco
*/
public class MediaControlView extends FrameLayout /* implements OnLayoutChangeListener, OnTouchListener */ implements OnClickListener, OnSeekBarChangeListener {
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
*
* Waits for Intents which signal the service to perform specific operations: Play, Pause,
* Rewind, etc.
- *
- * @author David A. Velasco
*/
public class MediaService extends Service implements OnCompletionListener, OnPreparedListener,
OnErrorListener, AudioManager.OnAudioFocusChangeListener {
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
*
* Provides the operations of {@link MediaController.MediaPlayerControl}, and an extra method to check if
* an {@link OCFile} instance is handled by the MediaService.
- *
- * @author David A. Velasco
*/
public class MediaServiceBinder extends Binder implements MediaController.MediaPlayerControl {
-/* ownCloud Android client application
- * Copyright (C) 2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* a progress bar is available in every Android version, because
* {@link NotificationCompat.Builder#setProgress(int, int, boolean)} has no
* real effect for Android < 4.0
- *
- * @author David A. Velasco
*/
public class NotificationBuilderWithProgressBar extends NotificationCompat.Builder {
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
package com.owncloud.android.notifications;
import java.util.Random;
-/* ownCloud Android client application
- * Copyright (C) 2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.operations;
+import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.resources.files.CreateRemoteFolderOperation;
/**
* Access to remote operation performing the creation of a new folder in the ownCloud server.
* Save the new folder in Database
- *
- * @author David A. Velasco
- * @author masensio
*/
public class CreateFolderOperation extends SyncOperation implements OnRemoteOperationListener{
/**
* Constructor
*
- * @param createFullPath 'True' means that all the ancestor folders should be created if don't exist yet.
+ * @param createFullPath 'True' means that all the ancestor folders should be created
+ * if don't exist yet.
*/
public CreateFolderOperation(String remotePath, boolean createFullPath) {
mRemotePath = remotePath;
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
- CreateRemoteFolderOperation operation = new CreateRemoteFolderOperation(mRemotePath, mCreateFullPath);
+ CreateRemoteFolderOperation operation = new CreateRemoteFolderOperation(mRemotePath,
+ mCreateFullPath);
RemoteOperationResult result = operation.execute(client);
if (result.isSuccess()) {
}
- private void onCreateRemoteFolderOperationFinish(CreateRemoteFolderOperation operation, RemoteOperationResult result) {
+ private void onCreateRemoteFolderOperationFinish(CreateRemoteFolderOperation operation,
+ RemoteOperationResult result) {
if (result.isSuccess()) {
saveFolderInDB();
} else {
-/* ownCloud Android client application
- * Copyright (C) 2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* Creates a new share from a given file
- *
- * @author masensio
- *
*/
+import android.content.Context;
import android.content.Intent;
+import com.owncloud.android.R;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudClient;
public class CreateShareOperation extends SyncOperation {
private static final String TAG = CreateShareOperation.class.getSimpleName();
-
protected FileDataStorageManager mStorageManager;
+ private Context mContext;
private String mPath;
private ShareType mShareType;
private String mShareWith;
/**
* Constructor
+ * @param context The context that the share is coming from.
* @param path Full path of the file/folder being shared. Mandatory argument
- * @param shareType \910\92 = user, \911\92 = group, \913\92 = Public link. Mandatory argument
- * @param shareWith User/group ID with who the file should be shared. This is mandatory for shareType of 0 or 1
- * @param publicUpload If \91false\92 (default) public cannot upload to a public shared folder.
- * If \91true\92 public can upload to a shared folder. Only available for public link shares
- * @param password Password to protect a public link share. Only available for public link shares
- * @param permissions 1 - Read only \96 Default for \93public\94 shares
+ * @param shareType 0 = user, 1 = group, 3 = Public link. Mandatory argument
+ * @param shareWith User/group ID with who the file should be shared.
+ * This is mandatory for shareType of 0 or 1
+ * @param publicUpload If false (default) public cannot upload to a public shared folder.
+ * If true public can upload to a shared folder.
+ * Only available for public link shares
+ * @param password Password to protect a public link share.
+ * Only available for public link shares
+ * @param permissions 1 - Read only - Default for public shares
* 2 - Update
* 4 - Create
* 8 - Delete
* 16- Re-share
- * 31- All above \96 Default for \93private\94 shares
+ * 31- All above - Default for private shares
* For user or group shares.
* To obtain combinations, add the desired values together.
- * For instance, for \93Re-Share\94, \93delete\94, \93read\94, \93update\94, add 16+8+2+1 = 27.
+ * For instance, for Re-Share, delete, read, update, add 16+8+2+1 = 27.
*/
- public CreateShareOperation(String path, ShareType shareType, String shareWith, boolean publicUpload,
- String password, int permissions, Intent sendIntent) {
+ public CreateShareOperation(Context context, String path, ShareType shareType, String shareWith,
+ boolean publicUpload, String password, int permissions,
+ Intent sendIntent) {
+ mContext = context;
mPath = path;
mShareType = shareType;
mShareWith = shareWith;
// Check if the share link already exists
operation = new GetRemoteSharesForFileOperation(mPath, false, false);
- RemoteOperationResult result = ((GetRemoteSharesForFileOperation)operation).execute(client);
+ RemoteOperationResult result =
+ ((GetRemoteSharesForFileOperation)operation).execute(client);
if (!result.isSuccess() || result.getData().size() <= 0) {
- operation = new CreateRemoteShareOperation(mPath, mShareType, mShareWith, mPublicUpload, mPassword, mPermissions);
+ operation = new CreateRemoteShareOperation(mPath, mShareType, mShareWith, mPublicUpload,
+ mPassword, mPermissions);
result = ((CreateRemoteShareOperation)operation).execute(client);
}
return result;
}
-
+ public String getPath() {
+ return mPath;
+ }
+
+ public ShareType getShareType() {
+ return mShareType;
+ }
+
+ public String getShareWith() {
+ return mShareWith;
+ }
+
+ public boolean getPublicUpload() {
+ return mPublicUpload;
+ }
+
+ public String getPassword() {
+ return mPassword;
+ }
+
+ public int getPermissions() {
+ return mPermissions;
+ }
+
public Intent getSendIntent() {
return mSendIntent;
}
OCFile file = getStorageManager().getFileByPath(mPath);
if (file!=null) {
mSendIntent.putExtra(Intent.EXTRA_TEXT, share.getShareLink());
+ mSendIntent.putExtra(Intent.EXTRA_SUBJECT,
+ String.format(mContext.getString(R.string.subject_token),
+ getClient().getCredentials().getUsername(), file.getFileName()));
file.setPublicLink(share.getShareLink());
file.setShareByLink(true);
getStorageManager().saveFile(file);
-/* ownCloud Android Library is available under MIT license
- * Copyright (C) 2014 ownCloud Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import java.util.ArrayList;
+import com.owncloud.android.MainApp;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import android.content.Context;
import android.net.Uri;
-import android.util.Log;
/**
* Operation to find out what authentication method requires
* When successful, the instance of {@link RemoteOperationResult} passed
* through {@link OnRemoteOperationListener#onRemoteOperationFinish(RemoteOperation,
* RemoteOperationResult)} returns in {@link RemoteOperationResult#getData()}
- * a value of {@link AuthenticationMethod}.
- *
- * @author David A. Velasco
+ * a value of {@link AuthenticationMethod}.
*/
public class DetectAuthenticationMethodOperation extends RemoteOperation {
* Constructor
*
* @param context Android context of the caller.
- * @param webdavUrl
*/
public DetectAuthenticationMethodOperation(Context context) {
mContext = context;
ArrayList<Object> data = new ArrayList<Object>();
data.add(authMethod);
result.setData(data);
- return result; // same result instance, so that other errors can be handled by the caller transparently
+ return result; // same result instance, so that other errors
+ // can be handled by the caller transparently
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.OwnCloudClient;
/**
* Remote mDownloadOperation performing the download of a file to an ownCloud server
- *
- * @author David A. Velasco
- * @author masensio
*/
public class DownloadFileOperation extends RemoteOperation {
public DownloadFileOperation(Account account, OCFile file) {
if (account == null)
- throw new IllegalArgumentException("Illegal null account in DownloadFileOperation creation");
+ throw new IllegalArgumentException("Illegal null account in DownloadFileOperation " +
+ "creation");
if (file == null)
- throw new IllegalArgumentException("Illegal null file in DownloadFileOperation creation");
+ throw new IllegalArgumentException("Illegal null file in DownloadFileOperation " +
+ "creation");
mAccount = account;
mFile = file;
}
public String getSavePath() {
- String path = mFile.getStoragePath(); // re-downloads should be done over the original file
+ String path = mFile.getStoragePath(); // re-downloads should be done over the original file
if (path != null && path.length() > 0) {
return path;
}
try {
mimeType = MimeTypeMap.getSingleton()
.getMimeTypeFromExtension(
- mFile.getRemotePath().substring(mFile.getRemotePath().lastIndexOf('.') + 1));
+ mFile.getRemotePath().substring(
+ mFile.getRemotePath().lastIndexOf('.') + 1));
} catch (IndexOutOfBoundsException e) {
- Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + mFile.getRemotePath());
+ Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " +
+ mFile.getRemotePath());
}
}
if (mimeType == null) {
}
public long getModificationTimestamp() {
- return (mModificationTimestamp > 0) ? mModificationTimestamp : mFile.getModificationTimestamp();
+ return (mModificationTimestamp > 0) ? mModificationTimestamp :
+ mFile.getModificationTimestamp();
}
@Override
newFile = new File(getSavePath());
newFile.getParentFile().mkdirs();
moved = tmpFile.renameTo(newFile);
-
if (!moved)
- result = new RemoteOperationResult(RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_MOVED);
+ result = new RemoteOperationResult(
+ RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_MOVED);
}
- Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage());
-
+ Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " +
+ result.getLogMessage());
return result;
}
mDataTransferListeners.remove(listener);
}
}
-
}
-/* ownCloud Android Library is available under MIT license
- * Copyright (C) 2014 ownCloud Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
*
* Checks the existence of a configured ownCloud server in the URL, gets its version
* and finds out what authentication method is needed to access files in it.
- *
- * @author David A. Velasco
- * @author masensio
*/
public class GetServerInfoOperation extends RemoteOperation {
if (url.endsWith("/")) {
url = url.substring(0, url.length() - 1);
}
- if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_4_0)){
- url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_4_0.length());
- } else if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_2_0)){
- url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_2_0.length());
- } else if (url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_1_2)){
- url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_1_2.length());
+ if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_4_0_AND_LATER)){
+ url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_4_0_AND_LATER.length());
}
}
return url;
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import java.util.ArrayList;
+import com.owncloud.android.MainApp;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.operations.common.SyncOperation;
/**
- * Provide a list shares for a specific file.
- *
- * @author masensio
- *
+ * Provide a list shares for a specific file.
*/
public class GetSharesForFileOperation extends SyncOperation {
* Constructor
*
* @param path Path to file or folder
- * @param reshares If set to \91false\92 (default), only shares from the current user are returned
- * If set to \91true\92, all shares from the given file are returned
- * @param subfiles If set to \91false\92 (default), lists only the folder being shared
- * If set to \91true\92, all shared files within the folder are returned.
+ * @param reshares If set to false (default), only shares from the current user are returned
+ * If set to true, all shares from the given file are returned
+ * @param subfiles If set to false (default), lists only the folder being shared
+ * If set to true, all shared files within the folder are returned.
*/
public GetSharesForFileOperation(String path, boolean reshares, boolean subfiles) {
mPath = path;
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
- GetRemoteSharesForFileOperation operation = new GetRemoteSharesForFileOperation(mPath, mReshares, mSubfiles);
+ GetRemoteSharesForFileOperation operation = new GetRemoteSharesForFileOperation(mPath,
+ mReshares, mSubfiles);
RemoteOperationResult result = operation.execute(client);
if (result.isSuccess()) {
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import java.util.ArrayList;
+import com.owncloud.android.MainApp;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
/**
* Access to remote operation to get the share files/folders
* Save the data in Database
- *
- * @author masensio
- * @author David A. Velasco
*/
public class GetSharesOperation extends SyncOperation {
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.operations;
+import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
/**
* Operation mmoving an {@link OCFile} to a different folder.
- *
- * @author David A. Velasco
*/
public class MoveFileOperation extends SyncOperation {
/**
* Constructor
*
- * @param path Remote path of the {@link OCFile} to move.
- * @param newParentPath Path to the folder where the file will be moved into.
+ * @param srcPath Remote path of the {@link OCFile} to move.
+ * @param targetParentPath Path to the folder where the file will be moved into.
* @param account OwnCloud account containing both the file and the target folder
*/
public MoveFileOperation(String srcPath, String targetParentPath, Account account) {
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
package com.owncloud.android.operations;
import java.util.ArrayList;
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.operations;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.http.HttpStatus;
+import android.accounts.Account;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+//import android.support.v4.content.LocalBroadcastManager;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
+import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation;
+import com.owncloud.android.lib.resources.files.RemoteFile;
+
+import com.owncloud.android.syncadapter.FileSyncAdapter;
+import com.owncloud.android.utils.FileStorageUtils;
+
+
+
+/**
+ * Remote operation performing the synchronization of the list of files contained
+ * in a folder identified with its remote path.
+ *
+ * Fetches the list and properties of the files contained in the given folder, including their
+ * properties, and updates the local database with them.
+ *
+ * Does NOT enter in the child folders to synchronize their contents also.
+ */
+public class RefreshFolderOperation extends RemoteOperation {
+
+ private static final String TAG = RefreshFolderOperation.class.getSimpleName();
+
+ public static final String EVENT_SINGLE_FOLDER_CONTENTS_SYNCED =
+ RefreshFolderOperation.class.getName() + ".EVENT_SINGLE_FOLDER_CONTENTS_SYNCED";
+ public static final String EVENT_SINGLE_FOLDER_SHARES_SYNCED =
+ RefreshFolderOperation.class.getName() + ".EVENT_SINGLE_FOLDER_SHARES_SYNCED";
+
+ /** Time stamp for the synchronization process in progress */
+ private long mCurrentSyncTime;
+
+ /** Remote folder to synchronize */
+ private OCFile mLocalFolder;
+
+ /** Access to the local database */
+ private FileDataStorageManager mStorageManager;
+
+ /** Account where the file to synchronize belongs */
+ private Account mAccount;
+
+ /** Android context; necessary to send requests to the download service */
+ private Context mContext;
+
+ /** Files and folders contained in the synchronized folder after a successful operation */
+ private List<OCFile> mChildren;
+
+ /** Counter of conflicts found between local and remote files */
+ private int mConflictsFound;
+
+ /** Counter of failed operations in synchronization of kept-in-sync files */
+ private int mFailsInFavouritesFound;
+
+ /**
+ * Map of remote and local paths to files that where locally stored in a location
+ * out of the ownCloud folder and couldn't be copied automatically into it
+ **/
+ private Map<String, String> mForgottenLocalFiles;
+
+ /** 'True' means that this operation is part of a full account synchronization */
+ private boolean mSyncFullAccount;
+
+ /** 'True' means that Share resources bound to the files into should be refreshed also */
+ private boolean mIsShareSupported;
+
+ /** 'True' means that the remote folder changed and should be fetched */
+ private boolean mRemoteFolderChanged;
+
+ /** 'True' means that Etag will be ignored */
+ private boolean mIgnoreETag;
+
+
+ /**
+ * Creates a new instance of {@link RefreshFolderOperation}.
+ *
+ * @param folder Folder to synchronize.
+ * @param currentSyncTime Time stamp for the synchronization process in progress.
+ * @param syncFullAccount 'True' means that this operation is part of a full account
+ * synchronization.
+ * @param isShareSupported 'True' means that the server supports the sharing API.
+ * @param ignoreETag 'True' means that the content of the remote folder should
+ * be fetched and updated even though the 'eTag' did not
+ * change.
+ * @param dataStorageManager Interface with the local database.
+ * @param account ownCloud account where the folder is located.
+ * @param context Application context.
+ */
+ public RefreshFolderOperation(OCFile folder,
+ long currentSyncTime,
+ boolean syncFullAccount,
+ boolean isShareSupported,
+ boolean ignoreETag,
+ FileDataStorageManager dataStorageManager,
+ Account account,
+ Context context) {
+ mLocalFolder = folder;
+ mCurrentSyncTime = currentSyncTime;
+ mSyncFullAccount = syncFullAccount;
+ mIsShareSupported = isShareSupported;
+ mStorageManager = dataStorageManager;
+ mAccount = account;
+ mContext = context;
+ mForgottenLocalFiles = new HashMap<String, String>();
+ mRemoteFolderChanged = false;
+ mIgnoreETag = ignoreETag;
+ }
+
+
+ public int getConflictsFound() {
+ return mConflictsFound;
+ }
+
+ public int getFailsInFavouritesFound() {
+ return mFailsInFavouritesFound;
+ }
+
+ public Map<String, String> getForgottenLocalFiles() {
+ return mForgottenLocalFiles;
+ }
+
+ /**
+ * Returns the list of files and folders contained in the synchronized folder,
+ * if called after synchronization is complete.
+ *
+ * @return List of files and folders contained in the synchronized folder.
+ */
+ public List<OCFile> getChildren() {
+ return mChildren;
+ }
+
+ /**
+ * Performs the synchronization.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected RemoteOperationResult run(OwnCloudClient client) {
+ RemoteOperationResult result = null;
+ mFailsInFavouritesFound = 0;
+ mConflictsFound = 0;
+ mForgottenLocalFiles.clear();
+
+ if (FileUtils.PATH_SEPARATOR.equals(mLocalFolder.getRemotePath()) && !mSyncFullAccount) {
+ updateOCVersion(client);
+ }
+
+ result = checkForChanges(client);
+
+ if (result.isSuccess()) {
+ if (mRemoteFolderChanged) {
+ result = fetchAndSyncRemoteFolder(client);
+ } else {
+ // TODO Enable when "On Device" is recovered ?
+ mChildren = mStorageManager.getFolderContent(mLocalFolder/*, false*/);
+ }
+ }
+
+ if (!mSyncFullAccount) {
+ sendLocalBroadcast(
+ EVENT_SINGLE_FOLDER_CONTENTS_SYNCED, mLocalFolder.getRemotePath(), result
+ );
+ }
+
+ if (result.isSuccess() && mIsShareSupported && !mSyncFullAccount) {
+ refreshSharesForFolder(client); // share result is ignored
+ }
+
+ if (!mSyncFullAccount) {
+ sendLocalBroadcast(
+ EVENT_SINGLE_FOLDER_SHARES_SYNCED, mLocalFolder.getRemotePath(), result
+ );
+ }
+
+ return result;
+
+ }
+
+
+ private void updateOCVersion(OwnCloudClient client) {
+ UpdateOCVersionOperation update = new UpdateOCVersionOperation(mAccount, mContext);
+ RemoteOperationResult result = update.execute(client);
+ if (result.isSuccess()) {
+ mIsShareSupported = update.getOCVersion().isSharedSupported();
+ }
+ }
+
+
+ private RemoteOperationResult checkForChanges(OwnCloudClient client) {
+ mRemoteFolderChanged = true;
+ RemoteOperationResult result = null;
+ String remotePath = null;
+
+ remotePath = mLocalFolder.getRemotePath();
+ Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath);
+
+ // remote request
+ ReadRemoteFileOperation operation = new ReadRemoteFileOperation(remotePath);
+ result = operation.execute(client);
+ if (result.isSuccess()){
+ OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0));
+
+ if (!mIgnoreETag) {
+ // check if remote and local folder are different
+ mRemoteFolderChanged =
+ !(remoteFolder.getEtag().equalsIgnoreCase(mLocalFolder.getEtag()));
+ }
+
+ result = new RemoteOperationResult(ResultCode.OK);
+
+ Log_OC.i(TAG, "Checked " + mAccount.name + remotePath + " : " +
+ (mRemoteFolderChanged ? "changed" : "not changed"));
+
+ } else {
+ // check failed
+ if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
+ removeLocalFolder();
+ }
+ if (result.isException()) {
+ Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " +
+ result.getLogMessage(), result.getException());
+ } else {
+ Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " +
+ result.getLogMessage());
+ }
+ }
+
+ return result;
+ }
+
+
+ private RemoteOperationResult fetchAndSyncRemoteFolder(OwnCloudClient client) {
+ String remotePath = mLocalFolder.getRemotePath();
+ ReadRemoteFolderOperation operation = new ReadRemoteFolderOperation(remotePath);
+ RemoteOperationResult result = operation.execute(client);
+ Log_OC.d(TAG, "Synchronizing " + mAccount.name + remotePath);
+
+ if (result.isSuccess()) {
+ synchronizeData(result.getData(), client);
+ if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) {
+ result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
+ // should be a different result code, but will do the job
+ }
+ } else {
+ if (result.getCode() == ResultCode.FILE_NOT_FOUND)
+ removeLocalFolder();
+ }
+
+ return result;
+ }
+
+
+ private void removeLocalFolder() {
+ if (mStorageManager.fileExists(mLocalFolder.getFileId())) {
+ String currentSavePath = FileStorageUtils.getSavePath(mAccount.name);
+ mStorageManager.removeFolder(
+ mLocalFolder,
+ true,
+ ( mLocalFolder.isDown() &&
+ mLocalFolder.getStoragePath().startsWith(currentSavePath)
+ )
+ );
+ }
+ }
+
+
+ /**
+ * Synchronizes the data retrieved from the server about the contents of the target folder
+ * with the current data in the local database.
+ *
+ * Grants that mChildren is updated with fresh data after execution.
+ *
+ * @param folderAndFiles Remote folder and children files in Folder
+ *
+ * @param client Client instance to the remote server where the data were
+ * retrieved.
+ * @return 'True' when any change was made in the local data, 'false' otherwise
+ */
+ private void synchronizeData(ArrayList<Object> folderAndFiles, OwnCloudClient client) {
+ // get 'fresh data' from the database
+ mLocalFolder = mStorageManager.getFileByPath(mLocalFolder.getRemotePath());
+
+ // parse data from remote folder
+ OCFile remoteFolder = fillOCFile((RemoteFile)folderAndFiles.get(0));
+ remoteFolder.setParentId(mLocalFolder.getParentId());
+ remoteFolder.setFileId(mLocalFolder.getFileId());
+
+ Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath()
+ + " changed - starting update of local data ");
+
+ List<OCFile> updatedFiles = new Vector<OCFile>(folderAndFiles.size() - 1);
+ List<SynchronizeFileOperation> filesToSyncContents = new Vector<SynchronizeFileOperation>();
+
+ // get current data about local contents of the folder to synchronize
+ // TODO Enable when "On Device" is recovered ?
+ List<OCFile> localFiles = mStorageManager.getFolderContent(mLocalFolder/*, false*/);
+ Map<String, OCFile> localFilesMap = new HashMap<String, OCFile>(localFiles.size());
+ for (OCFile file : localFiles) {
+ localFilesMap.put(file.getRemotePath(), file);
+ }
+
+ // loop to update every child
+ OCFile remoteFile = null, localFile = null;
+ for (int i=1; i<folderAndFiles.size(); i++) {
+ /// new OCFile instance with the data from the server
+ remoteFile = fillOCFile((RemoteFile)folderAndFiles.get(i));
+ remoteFile.setParentId(mLocalFolder.getFileId());
+
+ /// retrieve local data for the read file
+ // localFile = mStorageManager.getFileByPath(remoteFile.getRemotePath());
+ localFile = localFilesMap.remove(remoteFile.getRemotePath());
+
+ /// add to the remoteFile (the new one) data about LOCAL STATE (not existing in server)
+ remoteFile.setLastSyncDateForProperties(mCurrentSyncTime);
+ if (localFile != null) {
+ // some properties of local state are kept unmodified
+ remoteFile.setFileId(localFile.getFileId());
+ remoteFile.setKeepInSync(localFile.keepInSync());
+ remoteFile.setLastSyncDateForData(localFile.getLastSyncDateForData());
+ remoteFile.setModificationTimestampAtLastSyncForData(
+ localFile.getModificationTimestampAtLastSyncForData()
+ );
+ remoteFile.setStoragePath(localFile.getStoragePath());
+ // eTag will not be updated unless contents are synchronized
+ // (Synchronize[File|Folder]Operation with remoteFile as parameter)
+ remoteFile.setEtag(localFile.getEtag());
+ if (remoteFile.isFolder()) {
+ remoteFile.setFileLength(localFile.getFileLength());
+ // TODO move operations about size of folders to FileContentProvider
+ } else if (mRemoteFolderChanged && remoteFile.isImage() &&
+ remoteFile.getModificationTimestamp() !=
+ localFile.getModificationTimestamp()) {
+ remoteFile.setNeedsUpdateThumbnail(true);
+ Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server");
+ }
+ remoteFile.setPublicLink(localFile.getPublicLink());
+ remoteFile.setShareByLink(localFile.isShareByLink());
+ } else {
+ // remote eTag will not be updated unless contents are synchronized
+ // (Synchronize[File|Folder]Operation with remoteFile as parameter)
+ remoteFile.setEtag("");
+ }
+
+ /// check and fix, if needed, local storage path
+ checkAndFixForeignStoragePath(remoteFile); // policy - local files are COPIED
+ // into the ownCloud local folder;
+ searchForLocalFileInDefaultPath(remoteFile); // legacy
+
+ /// prepare content synchronization for kept-in-sync files
+ if (remoteFile.keepInSync()) {
+ SynchronizeFileOperation operation = new SynchronizeFileOperation( localFile,
+ remoteFile,
+ mAccount,
+ true,
+ mContext
+ );
+
+ filesToSyncContents.add(operation);
+ }
+
+ updatedFiles.add(remoteFile);
+ }
+
+ // save updated contents in local database
+ mStorageManager.saveFolder(remoteFolder, updatedFiles, localFilesMap.values());
+
+ // request for the synchronization of file contents AFTER saving current remote properties
+ startContentSynchronizations(filesToSyncContents, client);
+
+ mChildren = updatedFiles;
+ }
+
+ /**
+ * Performs a list of synchronization operations, determining if a download or upload is needed
+ * or if exists conflict due to changes both in local and remote contents of the each file.
+ *
+ * If download or upload is needed, request the operation to the corresponding service and goes
+ * on.
+ *
+ * @param filesToSyncContents Synchronization operations to execute.
+ * @param client Interface to the remote ownCloud server.
+ */
+ private void startContentSynchronizations(
+ List<SynchronizeFileOperation> filesToSyncContents, OwnCloudClient client
+ ) {
+ RemoteOperationResult contentsResult = null;
+ for (SynchronizeFileOperation op: filesToSyncContents) {
+ contentsResult = op.execute(mStorageManager, mContext); // async
+ if (!contentsResult.isSuccess()) {
+ if (contentsResult.getCode() == ResultCode.SYNC_CONFLICT) {
+ mConflictsFound++;
+ } else {
+ mFailsInFavouritesFound++;
+ if (contentsResult.getException() != null) {
+ Log_OC.e(TAG, "Error while synchronizing favourites : "
+ + contentsResult.getLogMessage(), contentsResult.getException());
+ } else {
+ Log_OC.e(TAG, "Error while synchronizing favourites : "
+ + contentsResult.getLogMessage());
+ }
+ }
+ } // won't let these fails break the synchronization process
+ }
+ }
+
+
+ public boolean isMultiStatus(int status) {
+ return (status == HttpStatus.SC_MULTI_STATUS);
+ }
+
+ /**
+ * Creates and populates a new {@link OCFile} object with the data read from the server.
+ *
+ * @param remote remote file read from the server (remote file or folder).
+ * @return New OCFile instance representing the remote resource described by we.
+ */
+ private OCFile fillOCFile(RemoteFile remote) {
+ OCFile file = new OCFile(remote.getRemotePath());
+ file.setCreationTimestamp(remote.getCreationTimestamp());
+ file.setFileLength(remote.getLength());
+ file.setMimetype(remote.getMimeType());
+ file.setModificationTimestamp(remote.getModifiedTimestamp());
+ file.setEtag(remote.getEtag());
+ file.setPermissions(remote.getPermissions());
+ file.setRemoteId(remote.getRemoteId());
+ return file;
+ }
+
+
+ /**
+ * Checks the storage path of the OCFile received as parameter.
+ * If it's out of the local ownCloud folder, tries to copy the file inside it.
+ *
+ * If the copy fails, the link to the local file is nullified. The account of forgotten
+ * files is kept in {@link #mForgottenLocalFiles}
+ *)
+ * @param file File to check and fix.
+ */
+ private void checkAndFixForeignStoragePath(OCFile file) {
+ String storagePath = file.getStoragePath();
+ String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file);
+ if (storagePath != null && !storagePath.equals(expectedPath)) {
+ /// fix storagePaths out of the local ownCloud folder
+ File originalFile = new File(storagePath);
+ if (FileStorageUtils.getUsableSpace(mAccount.name) < originalFile.length()) {
+ mForgottenLocalFiles.put(file.getRemotePath(), storagePath);
+ file.setStoragePath(null);
+
+ } else {
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ File expectedFile = new File(expectedPath);
+ File expectedParent = expectedFile.getParentFile();
+ expectedParent.mkdirs();
+ if (!expectedParent.isDirectory()) {
+ throw new IOException(
+ "Unexpected error: parent directory could not be created"
+ );
+ }
+ expectedFile.createNewFile();
+ if (!expectedFile.isFile()) {
+ throw new IOException("Unexpected error: target file could not be created");
+ }
+ in = new FileInputStream(originalFile);
+ out = new FileOutputStream(expectedFile);
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0){
+ out.write(buf, 0, len);
+ }
+ file.setStoragePath(expectedPath);
+
+ } catch (Exception e) {
+ Log_OC.e(TAG, "Exception while copying foreign file " + expectedPath, e);
+ mForgottenLocalFiles.put(file.getRemotePath(), storagePath);
+ file.setStoragePath(null);
+
+ } finally {
+ try {
+ if (in != null) in.close();
+ } catch (Exception e) {
+ Log_OC.d(TAG, "Weird exception while closing input stream for "
+ + storagePath + " (ignoring)", e);
+ }
+ try {
+ if (out != null) out.close();
+ } catch (Exception e) {
+ Log_OC.d(TAG, "Weird exception while closing output stream for "
+ + expectedPath + " (ignoring)", e);
+ }
+ }
+ }
+ }
+ }
+
+
+ private RemoteOperationResult refreshSharesForFolder(OwnCloudClient client) {
+ RemoteOperationResult result = null;
+
+ // remote request
+ GetRemoteSharesForFileOperation operation =
+ new GetRemoteSharesForFileOperation(mLocalFolder.getRemotePath(), false, true);
+ result = operation.execute(client);
+
+ if (result.isSuccess()) {
+ // update local database
+ ArrayList<OCShare> shares = new ArrayList<OCShare>();
+ for(Object obj: result.getData()) {
+ shares.add((OCShare) obj);
+ }
+ mStorageManager.saveSharesInFolder(shares, mLocalFolder);
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Scans the default location for saving local copies of files searching for
+ * a 'lost' file with the same full name as the {@link OCFile} received as
+ * parameter.
+ *
+ * @param file File to associate a possible 'lost' local file.
+ */
+ private void searchForLocalFileInDefaultPath(OCFile file) {
+ if (file.getStoragePath() == null && !file.isFolder()) {
+ File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
+ if (f.exists()) {
+ file.setStoragePath(f.getAbsolutePath());
+ file.setLastSyncDateForData(f.lastModified());
+ }
+ }
+ }
+
+
+ /**
+ * Sends a message to any application component interested in the progress
+ * of the synchronization.
+ *
+ * @param event
+ * @param dirRemotePath Remote path of a folder that was just synchronized
+ * (with or without success)
+ * @param result
+ */
+ private void sendLocalBroadcast(
+ String event, String dirRemotePath, RemoteOperationResult result
+ ) {
+ Log_OC.d(TAG, "Send broadcast " + event);
+ Intent intent = new Intent(event);
+ intent.putExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME, mAccount.name);
+ if (dirRemotePath != null) {
+ intent.putExtra(FileSyncAdapter.EXTRA_FOLDER_PATH, dirRemotePath);
+ }
+ intent.putExtra(FileSyncAdapter.EXTRA_RESULT, result);
+ mContext.sendStickyBroadcast(intent);
+ //LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
+ }
+
+
+ public boolean getRemoteFolderChanged() {
+ return mRemoteFolderChanged;
+ }
+
+}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.operations;
+import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
/**
* Remote operation performing the removal of a remote file or folder in the ownCloud server.
- *
- * @author David A. Velasco
- * @author masensio
*/
public class RemoveFileOperation extends SyncOperation {
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import java.io.File;
import java.io.IOException;
+import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.operations.common.SyncOperation;
import com.owncloud.android.utils.FileStorageUtils;
-import android.accounts.Account;
-
/**
* Remote operation performing the rename of a remote file (or folder?) in the ownCloud server.
- *
- * @author David A. Velasco
- * @author masensio
*/
public class RenameFileOperation extends SyncOperation {
private OCFile mFile;
private String mRemotePath;
- private Account mAccount;
private String mNewName;
private String mNewRemotePath;
/**
* Constructor
*
- * @param remotePath RemotePath of the OCFile instance describing the remote file or folder to rename
- * @param account OwnCloud account containing the remote file
+ * @param remotePath RemotePath of the OCFile instance describing the remote file or
+ * folder to rename
* @param newName New name to set as the name of file.
*/
- public RenameFileOperation(String remotePath, Account account, String newName) {
+ public RenameFileOperation(String remotePath, String newName) {
mRemotePath = remotePath;
- mAccount = account;
mNewName = newName;
mNewRemotePath = null;
}
return new RemoteOperationResult(ResultCode.INVALID_LOCAL_FILE_NAME);
}
String parent = (new File(mFile.getRemotePath())).getParent();
- parent = (parent.endsWith(OCFile.PATH_SEPARATOR)) ? parent : parent + OCFile.PATH_SEPARATOR;
+ parent = (parent.endsWith(OCFile.PATH_SEPARATOR)) ? parent : parent +
+ OCFile.PATH_SEPARATOR;
mNewRemotePath = parent + mNewName;
if (mFile.isFolder()) {
mNewRemotePath += OCFile.PATH_SEPARATOR;
return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
}
- RenameRemoteFileOperation operation = new RenameRemoteFileOperation(mFile.getFileName(), mFile.getRemotePath(),
+ RenameRemoteFileOperation operation = new RenameRemoteFileOperation(mFile.getFileName(),
+ mFile.getRemotePath(),
mNewName, mFile.isFolder());
result = operation.execute(client);
if (result.isSuccess()) {
if (mFile.isFolder()) {
- saveLocalDirectory();
+ getStorageManager().moveLocalFile(mFile, mNewRemotePath, parent);
+ //saveLocalDirectory();
} else {
saveLocalFile();
}
} catch (IOException e) {
- Log_OC.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " +
+ Log_OC.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ?
+ mNewName : mNewRemotePath) + ": " +
((result!= null) ? result.getLogMessage() : ""), e);
}
return result;
}
-
- private void saveLocalDirectory() {
- getStorageManager().moveFolder(mFile, mNewRemotePath);
- String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
- File localDir = new File(localPath);
- if (localDir.exists()) {
- localDir.renameTo(new File(FileStorageUtils.getSavePath(mAccount.name) + mNewRemotePath));
- // TODO - if renameTo fails, children files that are already down will result unlinked
- }
- }
-
private void saveLocalFile() {
mFile.setFileName(mNewName);
-
+
// try to rename the local copy of the file
if (mFile.isDown()) {
- File f = new File(mFile.getStoragePath());
+ String oldPath = mFile.getStoragePath();
+ File f = new File(oldPath);
String parentStoragePath = f.getParent();
if (!parentStoragePath.endsWith(File.separator))
parentStoragePath += File.separator;
if (f.renameTo(new File(parentStoragePath + mNewName))) {
- mFile.setStoragePath(parentStoragePath + mNewName);
+ String newPath = parentStoragePath + mNewName;
+ mFile.setStoragePath(newPath);
+
+ // notify MediaScanner about removed file
+ getStorageManager().deleteFileInMediaScan(oldPath);
+ // notify to scan about new file
+ getStorageManager().triggerMediaScan(newPath);
}
- // else - NOTHING: the link to the local file is kept although the local name can't be updated
+ // else - NOTHING: the link to the local file is kept although the local name
+ // can't be updated
// TODO - study conditions when this could be a problem
}
/**
* Checks if the new name to set is valid in the file system
*
- * The only way to be sure is trying to create a file with that name. It's made in the temporal directory
- * for downloads, out of any account, and then removed.
+ * The only way to be sure is trying to create a file with that name. It's made in the
+ * temporal directory for downloads, out of any account, and then removed.
*
- * IMPORTANT: The test must be made in the same file system where files are download. The internal storage
- * could be formatted with a different file system.
+ * IMPORTANT: The test must be made in the same file system where files are download.
+ * The internal storage could be formatted with a different file system.
*
- * TODO move this method, and maybe FileDownload.get***Path(), to a class with utilities specific for the interactions with the file system
+ * TODO move this method, and maybe FileDownload.get***Path(), to a class with utilities
+ * specific for the interactions with the file system
*
- * @return 'True' if a temporal file named with the name to set could be created in the file system where
- * local files are stored.
+ * @return 'True' if a temporal file named with the name to set could be
+ * created in the file system where local files are stored.
* @throws IOException When the temporal folder can not be created.
*/
private boolean isValidNewName() throws IOException {
// check tricky names
- if (mNewName == null || mNewName.length() <= 0 || mNewName.contains(File.separator) || mNewName.contains("%")) {
+ if (mNewName == null || mNewName.length() <= 0 || mNewName.contains(File.separator)) {
return false;
}
// create a test file
throw new IOException("Unexpected error: temporal directory could not be created");
}
try {
- testFile.createNewFile(); // return value is ignored; it could be 'false' because the file already existed, that doesn't invalidate the name
+ testFile.createNewFile(); // return value is ignored; it could be 'false' because
+ // the file already existed, that doesn't invalidate the name
} catch (IOException e) {
Log_OC.i(TAG, "Test for validity of name " + mNewName + " in the file system failed");
return false;
}
boolean result = (testFile.exists() && testFile.isFile());
- // cleaning ; result is ignored, since there is not much we could do in case of failure, but repeat and repeat...
+ // cleaning ; result is ignored, since there is not much we could do in case of failure,
+ // but repeat and repeat...
testFile.delete();
return result;
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * @author masensio
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2014 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.operations;
+import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader;
import com.owncloud.android.files.services.FileUploader;
/**
* Remote operation performing the read of remote file in the ownCloud server.
- *
- * @author David A. Velasco
- * @author masensio
*/
public class SynchronizeFileOperation extends SyncOperation {
private boolean mTransferWasRequested = false;
+ /**
+ * When 'false', uploads to the server are not done; only downloads or conflict detection.
+ * This is a temporal field.
+ * TODO Remove when 'folder synchronization' replaces 'folder download'.
+ */
+ private boolean mAllowUploads;
+
/**
- * Constructor.
+ * Constructor for "full synchronization mode".
+ *
+ * Uses remotePath to retrieve all the data both in local cache and in the remote OC server
+ * when the operation is executed, instead of reusing {@link OCFile} instances.
*
- * Uses remotePath to retrieve all the data in local cache and remote server when the operation
- * is executed, instead of reusing {@link OCFile} instances.
+ * Useful for direct synchronization of a single file.
*
* @param
* @param account ownCloud account holding the file.
mAccount = account;
mSyncFileContents = syncFileContents;
mContext = context;
+ mAllowUploads = true;
}
/**
- * Constructor allowing to reuse {@link OCFile} instances just queried from cache or network.
+ * Constructor allowing to reuse {@link OCFile} instances just queried from local cache or
+ * from remote OC server.
*
- * Useful for folder / account synchronizations.
+ * Useful to include this operation as part of the synchronization of a folder
+ * (or a full account), avoiding the repetition of fetch operations (both in local database
+ * or remote server).
*
- * @param localFile Data of file currently hold in device cache. MUSTN't be null.
- * @param serverFile Data of file just retrieved from network. If null, will be
- * retrieved from network by the operation when executed.
+ * At least one of localFile or serverFile MUST NOT BE NULL. If you don't have none of them,
+ * use the other constructor.
+ *
+ * @param localFile Data of file (just) retrieved from local cache/database.
+ * @param serverFile Data of file (just) retrieved from a remote server. If null,
+ * will be retrieved from network by the operation when executed.
* @param account ownCloud account holding the file.
* @param syncFileContents When 'true', transference of data will be started by the
* operation if needed and no conflict is detected.
mLocalFile = localFile;
mServerFile = serverFile;
- mRemotePath = localFile.getRemotePath();
+ if (mLocalFile != null) {
+ mRemotePath = mLocalFile.getRemotePath();
+ if (mServerFile != null && !mServerFile.getRemotePath().equals(mRemotePath)) {
+ throw new IllegalArgumentException("serverFile and localFile do not correspond" +
+ " to the same OC file");
+ }
+ } else if (mServerFile != null) {
+ mRemotePath = mServerFile.getRemotePath();
+ } else {
+ throw new IllegalArgumentException("Both serverFile and localFile are NULL");
+ }
mAccount = account;
mSyncFileContents = syncFileContents;
mContext = context;
+ mAllowUploads = true;
+ }
+
+
+ /**
+ * Temporal constructor.
+ *
+ * Extends the previous one to allow constrained synchronizations where uploads are never
+ * performed - only downloads or conflict detection.
+ *
+ * Do not use unless you are involved in 'folder synchronization' or 'folder download' work
+ * in progress.
+ *
+ * TODO Remove when 'folder synchronization' replaces 'folder download'.
+ *
+ * @param localFile Data of file (just) retrieved from local cache/database.
+ * MUSTN't be null.
+ * @param serverFile Data of file (just) retrieved from a remote server.
+ * If null, will be retrieved from network by the operation
+ * when executed.
+ * @param account ownCloud account holding the file.
+ * @param syncFileContents When 'true', transference of data will be started by the
+ * operation if needed and no conflict is detected.
+ * @param allowUploads When 'false', uploads to the server are not done;
+ * only downloads or conflict detection.
+ * @param context Android context; needed to start transfers.
+ */
+ public SynchronizeFileOperation(
+ OCFile localFile,
+ OCFile serverFile,
+ Account account,
+ boolean syncFileContents,
+ boolean allowUploads,
+ Context context) {
+
+ this(localFile, serverFile, account, syncFileContents, context);
+ mAllowUploads = allowUploads;
}
boolean serverChanged = false;
/* time for eTag is coming, but not yet
if (mServerFile.getEtag() != null) {
- serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag())); // TODO could this be dangerous when the user upgrades the server from non-tagged to tagged?
+ serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag()));
} else { */
- // server without etags
- serverChanged = (mServerFile.getModificationTimestamp() != mLocalFile.getModificationTimestampAtLastSyncForData());
+ serverChanged = (
+ mServerFile.getModificationTimestamp() !=
+ mLocalFile.getModificationTimestampAtLastSyncForData()
+ );
//}
- boolean localChanged = (mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData());
- // TODO this will be always true after the app is upgraded to database version 2; will result in unnecessary uploads
+ boolean localChanged = (
+ mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData()
+ );
/// decide action to perform depending upon changes
//if (!mLocalFile.getEtag().isEmpty() && localChanged && serverChanged) {
result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
} else if (localChanged) {
- if (mSyncFileContents) {
+ if (mSyncFileContents && mAllowUploads) {
requestForUpload(mLocalFile);
- // the local update of file properties will be done by the FileUploader service when the upload finishes
+ // the local update of file properties will be done by the FileUploader
+ // service when the upload finishes
} else {
- // NOTHING TO DO HERE: updating the properties of the file in the server without uploading the contents would be stupid;
- // So, an instance of SynchronizeFileOperation created with syncFileContents == false is completely useless when we suspect
+ // NOTHING TO DO HERE: updating the properties of the file in the server
+ // without uploading the contents would be stupid;
+ // So, an instance of SynchronizeFileOperation created with
+ // syncFileContents == false is completely useless when we suspect
// that an upload is necessary (for instance, in FileObserverService).
}
result = new RemoteOperationResult(ResultCode.OK);
mLocalFile.setRemoteId(mServerFile.getRemoteId());
if (mSyncFileContents) {
- requestForDownload(mLocalFile); // local, not server; we won't to keep the value of keepInSync!
- // the update of local data will be done later by the FileUploader service when the upload finishes
+ requestForDownload(mLocalFile); // local, not server; we won't to keep
+ // the value of keepInSync!
+ // the update of local data will be done later by the FileUploader
+ // service when the upload finishes
} else {
// TODO CHECK: is this really useful in some point in the code?
mServerFile.setKeepInSync(mLocalFile.keepInSync());
}
- Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage());
+ Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() +
+ ": " + result.getLogMessage());
return result;
}
Intent i = new Intent(mContext, FileUploader.class);
i.putExtra(FileUploader.KEY_ACCOUNT, mAccount);
i.putExtra(FileUploader.KEY_FILE, file);
- /*i.putExtra(FileUploader.KEY_REMOTE_FILE, mRemotePath); // doing this we would lose the value of keepInSync in the road, and maybe it's not updated in the database when the FileUploader service gets it!
+ /*i.putExtra(FileUploader.KEY_REMOTE_FILE, mRemotePath);
+ // doing this we would lose the value of keepInSync in the road, and maybe
+ // it's not updated in the database when the FileUploader service gets it!
i.putExtra(FileUploader.KEY_LOCAL_FILE, localFile.getStoragePath());*/
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
i.putExtra(FileUploader.KEY_FORCE_OVERWRITE, true);
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.operations;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
-import org.apache.http.HttpStatus;
import android.accounts.Account;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
-//import android.support.v4.content.LocalBroadcastManager;
+
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
-
+import com.owncloud.android.files.services.FileDownloader;
import com.owncloud.android.lib.common.OwnCloudClient;
-import com.owncloud.android.lib.resources.shares.OCShare;
-import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.OperationCancelledException;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation;
-import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation;
import com.owncloud.android.lib.resources.files.RemoteFile;
-
-import com.owncloud.android.syncadapter.FileSyncAdapter;
+import com.owncloud.android.operations.common.SyncOperation;
+import com.owncloud.android.services.OperationsService;
import com.owncloud.android.utils.FileStorageUtils;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+//import android.support.v4.content.LocalBroadcastManager;
/**
* properties, and updates the local database with them.
*
* Does NOT enter in the child folders to synchronize their contents also.
- *
- * @author David A. Velasco
*/
-public class SynchronizeFolderOperation extends RemoteOperation {
+public class SynchronizeFolderOperation extends SyncOperation {
private static final String TAG = SynchronizeFolderOperation.class.getSimpleName();
- public static final String EVENT_SINGLE_FOLDER_CONTENTS_SYNCED =
- SynchronizeFolderOperation.class.getName() + ".EVENT_SINGLE_FOLDER_CONTENTS_SYNCED";
- public static final String EVENT_SINGLE_FOLDER_SHARES_SYNCED =
- SynchronizeFolderOperation.class.getName() + ".EVENT_SINGLE_FOLDER_SHARES_SYNCED";
-
/** Time stamp for the synchronization process in progress */
private long mCurrentSyncTime;
-
- /** Remote folder to synchronize */
- private OCFile mLocalFolder;
-
- /** Access to the local database */
- private FileDataStorageManager mStorageManager;
+
+ /** Remote path of the folder to synchronize */
+ private String mRemotePath;
/** Account where the file to synchronize belongs */
private Account mAccount;
-
+
/** Android context; necessary to send requests to the download service */
private Context mContext;
-
+
+ /** Locally cached information about folder to synchronize */
+ private OCFile mLocalFolder;
+
/** Files and folders contained in the synchronized folder after a successful operation */
- private List<OCFile> mChildren;
+ //private List<OCFile> mChildren;
/** Counter of conflicts found between local and remote files */
private int mConflictsFound;
/** Counter of failed operations in synchronization of kept-in-sync files */
- private int mFailsInFavouritesFound;
-
- /**
- * Map of remote and local paths to files that where locally stored in a location
- * out of the ownCloud folder and couldn't be copied automatically into it
- **/
- private Map<String, String> mForgottenLocalFiles;
-
- /** 'True' means that this operation is part of a full account synchronization */
- private boolean mSyncFullAccount;
+ private int mFailsInFileSyncsFound;
- /** 'True' means that Share resources bound to the files into should be refreshed also */
- private boolean mIsShareSupported;
-
/** 'True' means that the remote folder changed and should be fetched */
private boolean mRemoteFolderChanged;
- /** 'True' means that Etag will be ignored */
- private boolean mIgnoreETag;
-
+ private List<OCFile> mFilesForDirectDownload;
+ // to avoid extra PROPFINDs when there was no change in the folder
+ private List<SyncOperation> mFilesToSyncContentsWithoutUpload;
+ // this will go out when 'folder synchronization' replaces 'folder download'; step by step
+
+ private List<SyncOperation> mFavouriteFilesToSyncContents;
+ // this will be used for every file when 'folder synchronization' replaces 'folder download'
+
+ private final AtomicBoolean mCancellationRequested;
+
/**
* Creates a new instance of {@link SynchronizeFolderOperation}.
- *
- * @param folder Folder to synchronize.
- * @param currentSyncTime Time stamp for the synchronization process in progress.
- * @param syncFullAccount 'True' means that this operation is part of a full account
- * synchronization.
- * @param isShareSupported 'True' means that the server supports the sharing API.
- * @param ignoreEtag 'True' means that the content of the remote folder should
- * be fetched and updated even though the 'eTag' did not
- * change.
- * @param dataStorageManager Interface with the local database.
- * @param account ownCloud account where the folder is located.
+ *
* @param context Application context.
+ * @param remotePath Path to synchronize.
+ * @param account ownCloud account where the folder is located.
+ * @param currentSyncTime Time stamp for the synchronization process in progress.
*/
- public SynchronizeFolderOperation( OCFile folder,
- long currentSyncTime,
- boolean syncFullAccount,
- boolean isShareSupported,
- boolean ignoreETag,
- FileDataStorageManager dataStorageManager,
- Account account,
- Context context ) {
- mLocalFolder = folder;
+ public SynchronizeFolderOperation(Context context, String remotePath, Account account,
+ long currentSyncTime){
+ mRemotePath = remotePath;
mCurrentSyncTime = currentSyncTime;
- mSyncFullAccount = syncFullAccount;
- mIsShareSupported = isShareSupported;
- mStorageManager = dataStorageManager;
mAccount = account;
mContext = context;
- mForgottenLocalFiles = new HashMap<String, String>();
mRemoteFolderChanged = false;
- mIgnoreETag = ignoreETag;
+ mFilesForDirectDownload = new Vector<OCFile>();
+ mFilesToSyncContentsWithoutUpload = new Vector<SyncOperation>();
+ mFavouriteFilesToSyncContents = new Vector<SyncOperation>();
+ mCancellationRequested = new AtomicBoolean(false);
}
-
-
+
+
public int getConflictsFound() {
return mConflictsFound;
}
-
- public int getFailsInFavouritesFound() {
- return mFailsInFavouritesFound;
- }
-
- public Map<String, String> getForgottenLocalFiles() {
- return mForgottenLocalFiles;
- }
-
- /**
- * Returns the list of files and folders contained in the synchronized folder,
- * if called after synchronization is complete.
- *
- * @return List of files and folders contained in the synchronized folder.
- */
- public List<OCFile> getChildren() {
- return mChildren;
+
+ public int getFailsInFileSyncsFound() {
+ return mFailsInFileSyncsFound;
}
-
+
/**
* Performs the synchronization.
- *
+ *
* {@inheritDoc}
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
- mFailsInFavouritesFound = 0;
+ mFailsInFileSyncsFound = 0;
mConflictsFound = 0;
- mForgottenLocalFiles.clear();
- if (FileUtils.PATH_SEPARATOR.equals(mLocalFolder.getRemotePath()) && !mSyncFullAccount) {
- updateOCVersion(client);
- }
-
- result = checkForChanges(client);
-
- if (result.isSuccess()) {
- if (mRemoteFolderChanged) {
- result = fetchAndSyncRemoteFolder(client);
- } else {
- mChildren = mStorageManager.getFolderContent(mLocalFolder);
+ try {
+ // get locally cached information about folder
+ mLocalFolder = getStorageManager().getFileByPath(mRemotePath);
+
+ result = checkForChanges(client);
+
+ if (result.isSuccess()) {
+ if (mRemoteFolderChanged) {
+ result = fetchAndSyncRemoteFolder(client);
+
+ } else {
+ prepareOpsFromLocalKnowledge();
+ }
+
+ if (result.isSuccess()) {
+ syncContents(client);
+ }
+
}
+
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
+
+ } catch (OperationCancelledException e) {
+ result = new RemoteOperationResult(e);
}
-
- if (!mSyncFullAccount) {
- sendLocalBroadcast(
- EVENT_SINGLE_FOLDER_CONTENTS_SYNCED, mLocalFolder.getRemotePath(), result
- );
- }
-
- if (result.isSuccess() && mIsShareSupported && !mSyncFullAccount) {
- refreshSharesForFolder(client); // share result is ignored
- }
-
- if (!mSyncFullAccount) {
- sendLocalBroadcast(
- EVENT_SINGLE_FOLDER_SHARES_SYNCED, mLocalFolder.getRemotePath(), result
- );
- }
-
- return result;
-
- }
+ return result;
- private void updateOCVersion(OwnCloudClient client) {
- UpdateOCVersionOperation update = new UpdateOCVersionOperation(mAccount, mContext);
- RemoteOperationResult result = update.execute(client);
- if (result.isSuccess()) {
- mIsShareSupported = update.getOCVersion().isSharedSupported();
- }
}
-
- private RemoteOperationResult checkForChanges(OwnCloudClient client) {
+ private RemoteOperationResult checkForChanges(OwnCloudClient client)
+ throws OperationCancelledException {
+ Log_OC.d(TAG, "Checking changes in " + mAccount.name + mRemotePath);
+
mRemoteFolderChanged = true;
RemoteOperationResult result = null;
- String remotePath = null;
-
- remotePath = mLocalFolder.getRemotePath();
- Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath);
- // remote request
- ReadRemoteFileOperation operation = new ReadRemoteFileOperation(remotePath);
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
+
+ // remote request
+ ReadRemoteFileOperation operation = new ReadRemoteFileOperation(mRemotePath);
result = operation.execute(client);
if (result.isSuccess()){
OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0));
- if (!mIgnoreETag) {
- // check if remote and local folder are different
- mRemoteFolderChanged =
+ // check if remote and local folder are different
+ mRemoteFolderChanged =
!(remoteFolder.getEtag().equalsIgnoreCase(mLocalFolder.getEtag()));
- }
result = new RemoteOperationResult(ResultCode.OK);
-
- Log_OC.i(TAG, "Checked " + mAccount.name + remotePath + " : " +
+
+ Log_OC.i(TAG, "Checked " + mAccount.name + mRemotePath + " : " +
(mRemoteFolderChanged ? "changed" : "not changed"));
-
+
} else {
// check failed
if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
removeLocalFolder();
}
if (result.isException()) {
- Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " +
+ Log_OC.e(TAG, "Checked " + mAccount.name + mRemotePath + " : " +
result.getLogMessage(), result.getException());
} else {
- Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " +
+ Log_OC.e(TAG, "Checked " + mAccount.name + mRemotePath + " : " +
result.getLogMessage());
}
+
}
-
+
return result;
}
- private RemoteOperationResult fetchAndSyncRemoteFolder(OwnCloudClient client) {
- String remotePath = mLocalFolder.getRemotePath();
- ReadRemoteFolderOperation operation = new ReadRemoteFolderOperation(remotePath);
- RemoteOperationResult result = operation.execute(client);
- Log_OC.d(TAG, "Synchronizing " + mAccount.name + remotePath);
+ private RemoteOperationResult fetchAndSyncRemoteFolder(OwnCloudClient client)
+ throws OperationCancelledException {
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
+ ReadRemoteFolderOperation operation = new ReadRemoteFolderOperation(mRemotePath);
+ RemoteOperationResult result = operation.execute(client);
+ Log_OC.d(TAG, "Synchronizing " + mAccount.name + mRemotePath);
+
if (result.isSuccess()) {
synchronizeData(result.getData(), client);
- if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) {
- result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
+ if (mConflictsFound > 0 || mFailsInFileSyncsFound > 0) {
+ result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
// should be a different result code, but will do the job
}
} else {
removeLocalFolder();
}
+
return result;
}
-
+
private void removeLocalFolder() {
- if (mStorageManager.fileExists(mLocalFolder.getFileId())) {
+ FileDataStorageManager storageManager = getStorageManager();
+ if (storageManager.fileExists(mLocalFolder.getFileId())) {
String currentSavePath = FileStorageUtils.getSavePath(mAccount.name);
- mStorageManager.removeFolder(
- mLocalFolder,
- true,
- ( mLocalFolder.isDown() &&
+ storageManager.removeFolder(
+ mLocalFolder,
+ true,
+ ( mLocalFolder.isDown() && // TODO: debug, I think this is
+ // always false for folders
mLocalFolder.getStoragePath().startsWith(currentSavePath)
)
);
/**
- * Synchronizes the data retrieved from the server about the contents of the target folder
+ * Synchronizes the data retrieved from the server about the contents of the target folder
* with the current data in the local database.
- *
+ *
* Grants that mChildren is updated with fresh data after execution.
- *
- * @param folderAndFiles Remote folder and children files in Folder
- *
- * @param client Client instance to the remote server where the data were
- * retrieved.
+ *
+ * @param folderAndFiles Remote folder and children files in Folder
+ *
+ * @param client Client instance to the remote server where the data were
+ * retrieved.
* @return 'True' when any change was made in the local data, 'false' otherwise
*/
- private void synchronizeData(ArrayList<Object> folderAndFiles, OwnCloudClient client) {
- // get 'fresh data' from the database
- mLocalFolder = mStorageManager.getFileByPath(mLocalFolder.getRemotePath());
-
- // parse data from remote folder
+ private void synchronizeData(ArrayList<Object> folderAndFiles, OwnCloudClient client)
+ throws OperationCancelledException {
+ FileDataStorageManager storageManager = getStorageManager();
+
+ // parse data from remote folder
OCFile remoteFolder = fillOCFile((RemoteFile)folderAndFiles.get(0));
remoteFolder.setParentId(mLocalFolder.getParentId());
remoteFolder.setFileId(mLocalFolder.getFileId());
-
- Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath()
+
+ Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath()
+ " changed - starting update of local data ");
-
+
List<OCFile> updatedFiles = new Vector<OCFile>(folderAndFiles.size() - 1);
- List<SynchronizeFileOperation> filesToSyncContents = new Vector<SynchronizeFileOperation>();
+ mFilesForDirectDownload.clear();
+ mFilesToSyncContentsWithoutUpload.clear();
+ mFavouriteFilesToSyncContents.clear();
+
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
// get current data about local contents of the folder to synchronize
- List<OCFile> localFiles = mStorageManager.getFolderContent(mLocalFolder);
+ // TODO Enable when "On Device" is recovered ?
+ List<OCFile> localFiles = storageManager.getFolderContent(mLocalFolder/*, false*/);
Map<String, OCFile> localFilesMap = new HashMap<String, OCFile>(localFiles.size());
for (OCFile file : localFiles) {
localFilesMap.put(file.getRemotePath(), file);
}
-
- // loop to update every child
+
+ // loop to synchronize every child
OCFile remoteFile = null, localFile = null;
for (int i=1; i<folderAndFiles.size(); i++) {
/// new OCFile instance with the data from the server
remoteFile = fillOCFile((RemoteFile)folderAndFiles.get(i));
remoteFile.setParentId(mLocalFolder.getFileId());
- /// retrieve local data for the read file
+ /// retrieve local data for the read file
// localFile = mStorageManager.getFileByPath(remoteFile.getRemotePath());
localFile = localFilesMap.remove(remoteFile.getRemotePath());
-
+
/// add to the remoteFile (the new one) data about LOCAL STATE (not existing in server)
remoteFile.setLastSyncDateForProperties(mCurrentSyncTime);
if (localFile != null) {
localFile.getModificationTimestampAtLastSyncForData()
);
remoteFile.setStoragePath(localFile.getStoragePath());
- // eTag will not be updated unless contents are synchronized
+ // eTag will not be updated unless contents are synchronized
// (Synchronize[File|Folder]Operation with remoteFile as parameter)
- remoteFile.setEtag(localFile.getEtag());
+ remoteFile.setEtag(localFile.getEtag());
if (remoteFile.isFolder()) {
- remoteFile.setFileLength(localFile.getFileLength());
+ remoteFile.setFileLength(localFile.getFileLength());
// TODO move operations about size of folders to FileContentProvider
} else if (mRemoteFolderChanged && remoteFile.isImage() &&
- remoteFile.getModificationTimestamp() != localFile.getModificationTimestamp()) {
+ remoteFile.getModificationTimestamp() !=
+ localFile.getModificationTimestamp()) {
remoteFile.setNeedsUpdateThumbnail(true);
Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server");
}
remoteFile.setPublicLink(localFile.getPublicLink());
remoteFile.setShareByLink(localFile.isShareByLink());
} else {
- // remote eTag will not be updated unless contents are synchronized
+ // remote eTag will not be updated unless contents are synchronized
// (Synchronize[File|Folder]Operation with remoteFile as parameter)
- remoteFile.setEtag("");
+ remoteFile.setEtag("");
}
/// check and fix, if needed, local storage path
- checkAndFixForeignStoragePath(remoteFile); // policy - local files are COPIED
- // into the ownCloud local folder;
- searchForLocalFileInDefaultPath(remoteFile); // legacy
-
- /// prepare content synchronization for kept-in-sync files
- if (remoteFile.keepInSync()) {
- SynchronizeFileOperation operation = new SynchronizeFileOperation( localFile,
- remoteFile,
- mAccount,
- true,
- mContext
- );
+ searchForLocalFileInDefaultPath(remoteFile);
+
+ /// classify file to sync/download contents later
+ if (remoteFile.isFolder()) {
+ /// to download children files recursively
+ synchronized(mCancellationRequested) {
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
+ startSyncFolderOperation(remoteFile.getRemotePath());
+ }
+
+ } else if (remoteFile.keepInSync()) {
+ /// prepare content synchronization for kept-in-sync files
+ SynchronizeFileOperation operation = new SynchronizeFileOperation(
+ localFile,
+ remoteFile,
+ mAccount,
+ true,
+ mContext
+ );
+ mFavouriteFilesToSyncContents.add(operation);
- filesToSyncContents.add(operation);
+ } else {
+ /// prepare limited synchronization for regular files
+ SynchronizeFileOperation operation = new SynchronizeFileOperation(
+ localFile,
+ remoteFile,
+ mAccount,
+ true,
+ false,
+ mContext
+ );
+ mFilesToSyncContentsWithoutUpload.add(operation);
}
-
+
updatedFiles.add(remoteFile);
}
// save updated contents in local database
- mStorageManager.saveFolder(remoteFolder, updatedFiles, localFilesMap.values());
+ storageManager.saveFolder(remoteFolder, updatedFiles, localFilesMap.values());
+
+ }
+
+
+ private void prepareOpsFromLocalKnowledge() throws OperationCancelledException {
+ // TODO Enable when "On Device" is recovered ?
+ List<OCFile> children = getStorageManager().getFolderContent(mLocalFolder/*, false*/);
+ for (OCFile child : children) {
+ /// classify file to sync/download contents later
+ if (child.isFolder()) {
+ /// to download children files recursively
+ synchronized(mCancellationRequested) {
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
+ startSyncFolderOperation(child.getRemotePath());
+ }
+
+ } else {
+ /// prepare limited synchronization for regular files
+ if (!child.isDown()) {
+ mFilesForDirectDownload.add(child);
+ }
+ }
+ }
+ }
+
- // request for the synchronization of file contents AFTER saving current remote properties
- startContentSynchronizations(filesToSyncContents, client);
+ private void syncContents(OwnCloudClient client) throws OperationCancelledException {
+ startDirectDownloads();
+ startContentSynchronizations(mFilesToSyncContentsWithoutUpload, client);
+ startContentSynchronizations(mFavouriteFilesToSyncContents, client);
+ }
- mChildren = updatedFiles;
+
+ private void startDirectDownloads() throws OperationCancelledException {
+ for (OCFile file : mFilesForDirectDownload) {
+ synchronized(mCancellationRequested) {
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
+ Intent i = new Intent(mContext, FileDownloader.class);
+ i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
+ i.putExtra(FileDownloader.EXTRA_FILE, file);
+ mContext.startService(i);
+ }
+ }
}
/**
* Performs a list of synchronization operations, determining if a download or upload is needed
* or if exists conflict due to changes both in local and remote contents of the each file.
- *
- * If download or upload is needed, request the operation to the corresponding service and goes
+ *
+ * If download or upload is needed, request the operation to the corresponding service and goes
* on.
- *
+ *
* @param filesToSyncContents Synchronization operations to execute.
* @param client Interface to the remote ownCloud server.
*/
- private void startContentSynchronizations(
- List<SynchronizeFileOperation> filesToSyncContents, OwnCloudClient client
- ) {
+ private void startContentSynchronizations(List<SyncOperation> filesToSyncContents,
+ OwnCloudClient client)
+ throws OperationCancelledException {
+
+ Log_OC.v(TAG, "Starting content synchronization... ");
RemoteOperationResult contentsResult = null;
- for (SynchronizeFileOperation op: filesToSyncContents) {
- contentsResult = op.execute(mStorageManager, mContext); // async
+ for (SyncOperation op: filesToSyncContents) {
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
+ contentsResult = op.execute(getStorageManager(), mContext);
if (!contentsResult.isSuccess()) {
if (contentsResult.getCode() == ResultCode.SYNC_CONFLICT) {
mConflictsFound++;
} else {
- mFailsInFavouritesFound++;
+ mFailsInFileSyncsFound++;
if (contentsResult.getException() != null) {
- Log_OC.e(TAG, "Error while synchronizing favourites : "
+ Log_OC.e(TAG, "Error while synchronizing file : "
+ contentsResult.getLogMessage(), contentsResult.getException());
} else {
- Log_OC.e(TAG, "Error while synchronizing favourites : "
+ Log_OC.e(TAG, "Error while synchronizing file : "
+ contentsResult.getLogMessage());
}
}
+ // TODO - use the errors count in notifications
} // won't let these fails break the synchronization process
}
}
-
- public boolean isMultiStatus(int status) {
- return (status == HttpStatus.SC_MULTI_STATUS);
- }
-
+
/**
- * Creates and populates a new {@link OCFile} object with the data read from the server.
- *
+ * Creates and populates a new {@link com.owncloud.android.datamodel.OCFile}
+ * object with the data read from the server.
+ *
* @param remote remote file read from the server (remote file or folder).
* @return New OCFile instance representing the remote resource described by we.
*/
file.setRemoteId(remote.getRemoteId());
return file;
}
-
- /**
- * Checks the storage path of the OCFile received as parameter.
- * If it's out of the local ownCloud folder, tries to copy the file inside it.
- *
- * If the copy fails, the link to the local file is nullified. The account of forgotten
- * files is kept in {@link #mForgottenLocalFiles}
- *)
- * @param file File to check and fix.
- */
- private void checkAndFixForeignStoragePath(OCFile file) {
- String storagePath = file.getStoragePath();
- String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file);
- if (storagePath != null && !storagePath.equals(expectedPath)) {
- /// fix storagePaths out of the local ownCloud folder
- File originalFile = new File(storagePath);
- if (FileStorageUtils.getUsableSpace(mAccount.name) < originalFile.length()) {
- mForgottenLocalFiles.put(file.getRemotePath(), storagePath);
- file.setStoragePath(null);
-
- } else {
- InputStream in = null;
- OutputStream out = null;
- try {
- File expectedFile = new File(expectedPath);
- File expectedParent = expectedFile.getParentFile();
- expectedParent.mkdirs();
- if (!expectedParent.isDirectory()) {
- throw new IOException(
- "Unexpected error: parent directory could not be created"
- );
- }
- expectedFile.createNewFile();
- if (!expectedFile.isFile()) {
- throw new IOException("Unexpected error: target file could not be created");
- }
- in = new FileInputStream(originalFile);
- out = new FileOutputStream(expectedFile);
- byte[] buf = new byte[1024];
- int len;
- while ((len = in.read(buf)) > 0){
- out.write(buf, 0, len);
- }
- file.setStoragePath(expectedPath);
-
- } catch (Exception e) {
- Log_OC.e(TAG, "Exception while copying foreign file " + expectedPath, e);
- mForgottenLocalFiles.put(file.getRemotePath(), storagePath);
- file.setStoragePath(null);
-
- } finally {
- try {
- if (in != null) in.close();
- } catch (Exception e) {
- Log_OC.d(TAG, "Weird exception while closing input stream for "
- + storagePath + " (ignoring)", e);
- }
- try {
- if (out != null) out.close();
- } catch (Exception e) {
- Log_OC.d(TAG, "Weird exception while closing output stream for "
- + expectedPath + " (ignoring)", e);
- }
- }
- }
- }
- }
-
-
- private RemoteOperationResult refreshSharesForFolder(OwnCloudClient client) {
- RemoteOperationResult result = null;
-
- // remote request
- GetRemoteSharesForFileOperation operation =
- new GetRemoteSharesForFileOperation(mLocalFolder.getRemotePath(), false, true);
- result = operation.execute(client);
-
- if (result.isSuccess()) {
- // update local database
- ArrayList<OCShare> shares = new ArrayList<OCShare>();
- for(Object obj: result.getData()) {
- shares.add((OCShare) obj);
- }
- mStorageManager.saveSharesInFolder(shares, mLocalFolder);
- }
-
- return result;
- }
-
/**
* Scans the default location for saving local copies of files searching for
- * a 'lost' file with the same full name as the {@link OCFile} received as
- * parameter.
+ * a 'lost' file with the same full name as the {@link com.owncloud.android.datamodel.OCFile}
+ * received as parameter.
*
* @param file File to associate a possible 'lost' local file.
*/
/**
- * Sends a message to any application component interested in the progress
- * of the synchronization.
- *
- * @param event
- * @param dirRemotePath Remote path of a folder that was just synchronized
- * (with or without success)
- * @param result
+ * Cancel operation
*/
- private void sendLocalBroadcast(
- String event, String dirRemotePath, RemoteOperationResult result
- ) {
- Log_OC.d(TAG, "Send broadcast " + event);
- Intent intent = new Intent(event);
- intent.putExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME, mAccount.name);
- if (dirRemotePath != null) {
- intent.putExtra(FileSyncAdapter.EXTRA_FOLDER_PATH, dirRemotePath);
- }
- intent.putExtra(FileSyncAdapter.EXTRA_RESULT, result);
- mContext.sendStickyBroadcast(intent);
- //LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
+ public void cancel() {
+ mCancellationRequested.set(true);
}
+ public String getFolderPath() {
+ String path = mLocalFolder.getStoragePath();
+ if (path != null && path.length() > 0) {
+ return path;
+ }
+ return FileStorageUtils.getDefaultSavePathFor(mAccount.name, mLocalFolder);
+ }
- public boolean getRemoteFolderChanged() {
- return mRemoteFolderChanged;
+ private void startSyncFolderOperation(String path){
+ Intent intent = new Intent(mContext, OperationsService.class);
+ intent.setAction(OperationsService.ACTION_SYNC_FOLDER);
+ intent.putExtra(OperationsService.EXTRA_ACCOUNT, mAccount);
+ intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, path);
+ mContext.startService(intent);
}
+ public String getRemotePath() {
+ return mRemotePath;
+ }
}
-/* ownCloud Android client application
- * Copyright (C) 2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.content.Context;
+import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudClient;
/**
* Unshare file/folder
* Save the data in Database
- *
- * @author masensio
*/
public class UnshareLinkOperation extends SyncOperation {
RemoteOperationResult result = null;
// Get Share for a file
- OCShare share = getStorageManager().getFirstShareByPathAndType(mRemotePath, ShareType.PUBLIC_LINK);
+ OCShare share = getStorageManager().getFirstShareByPathAndType(mRemotePath,
+ ShareType.PUBLIC_LINK);
if (share != null) {
- RemoveRemoteShareOperation operation = new RemoveRemoteShareOperation((int) share.getIdRemoteShared());
+ RemoveRemoteShareOperation operation =
+ new RemoveRemoteShareOperation((int) share.getIdRemoteShared());
result = operation.execute(client);
if (result.isSuccess() || result.getCode() == ResultCode.SHARE_NOT_FOUND) {
}
private boolean existsFile(OwnCloudClient client, String remotePath){
- ExistenceCheckRemoteOperation existsOperation = new ExistenceCheckRemoteOperation(remotePath, mContext, false);
+ ExistenceCheckRemoteOperation existsOperation =
+ new ExistenceCheckRemoteOperation(remotePath, mContext, false);
RemoteOperationResult result = existsOperation.execute(client);
return result.isSuccess();
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* Remote operation that checks the version of an ownCloud server and stores it locally
- *
- * @author David A. Velasco
*/
public class UpdateOCVersionOperation extends RemoteOperation {
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* Remote operation performing the upload of a file to an ownCloud server
- *
- * @author David A. Velasco
*/
public class UploadFileOperation extends RemoteOperation {
private String mOriginalStoragePath = null;
PutMethod mPutMethod = null;
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
- private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
+ private AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
private Context mContext;
private UploadRemoteFileOperation mUploadOperation;
int localBehaviour,
Context context) {
if (account == null)
- throw new IllegalArgumentException("Illegal NULL account in UploadFileOperation creation");
+ throw new IllegalArgumentException("Illegal NULL account in UploadFileOperation " +
+ "creation");
if (file == null)
throw new IllegalArgumentException("Illegal NULL file in UploadFileOperation creation");
if (file.getStoragePath() == null || file.getStoragePath().length() <= 0) {
// check location of local file; if not the expected, copy to a
// temporal file before upload (if COPY is the expected behaviour)
- if (!mOriginalStoragePath.equals(expectedPath) && mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY) {
+ if (!mOriginalStoragePath.equals(expectedPath) &&
+ mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY) {
if (FileStorageUtils.getUsableSpace(mAccount.name) < originalFile.length()) {
result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_FULL);
} else {
- String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
+ String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) +
+ mFile.getRemotePath();
mFile.setStoragePath(temporalPath);
temporalFile = new File(temporalPath);
int nRead;
byte[] data = new byte[16384];
- while ((nRead = in.read(data, 0, data.length)) != -1) {
+ while (!mCancellationRequested.get() &&
+ (nRead = in.read(data, 0, data.length)) != -1) {
out.write(data, 0, nRead);
}
-
out.flush();
} else {
out = new FileOutputStream(temporalFile);
byte[] buf = new byte[1024];
int len;
- while ((len = in.read(buf)) > 0) {
+ while (!mCancellationRequested.get() && (len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
}
+ if (mCancellationRequested.get()) {
+ result = new RemoteOperationResult(new OperationCancelledException());
+ }
+
+
} catch (Exception e) {
result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_COPIED);
return result;
if (in != null)
in.close();
} catch (Exception e) {
- Log_OC.d(TAG, "Weird exception while closing input stream for " + mOriginalStoragePath + " (ignoring)", e);
+ Log_OC.d(TAG, "Weird exception while closing input stream for " +
+ mOriginalStoragePath + " (ignoring)", e);
}
try {
if (out != null)
out.close();
} catch (Exception e) {
- Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e);
+ Log_OC.d(TAG, "Weird exception while closing output stream for " +
+ expectedPath + " (ignoring)", e);
}
}
}
}
- localCopyPassed = true;
+ localCopyPassed = (result == null);
/// perform the upload
- if ( mChunked && (new File(mFile.getStoragePath())).length() > ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) {
- mUploadOperation = new ChunkedUploadRemoteFileOperation(mFile.getStoragePath(), mFile.getRemotePath(),
- mFile.getMimetype());
+ if ( mChunked &&
+ (new File(mFile.getStoragePath())).length() >
+ ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) {
+ mUploadOperation = new ChunkedUploadRemoteFileOperation(mFile.getStoragePath(),
+ mFile.getRemotePath(), mFile.getMimetype());
} else {
- mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(), mFile.getRemotePath(),
- mFile.getMimetype());
+ mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(),
+ mFile.getRemotePath(), mFile.getMimetype());
}
Iterator <OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
while (listener.hasNext()) {
mUploadOperation.addDatatransferProgressListener(listener.next());
}
- result = mUploadOperation.execute(client);
-
- /// move local temporal file or original file to its corresponding
- // location in the ownCloud local folder
- if (result.isSuccess()) {
- if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) {
- mFile.setStoragePath(null);
-
- } else {
- mFile.setStoragePath(expectedPath);
- File fileToMove = null;
- if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY
- // ; see where temporalFile was
- // set
- fileToMove = temporalFile;
- } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE
- fileToMove = originalFile;
- }
- if (!expectedFile.equals(fileToMove)) {
- File expectedFolder = expectedFile.getParentFile();
- expectedFolder.mkdirs();
- if (!expectedFolder.isDirectory() || !fileToMove.renameTo(expectedFile)) {
- mFile.setStoragePath(null); // forget the local file
- // by now, treat this as a success; the file was
- // uploaded; the user won't like that the local file
- // is not linked, but this should be a very rare
- // fail;
- // the best option could be show a warning message
- // (but not a fail)
- // result = new
- // RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED);
- // return result;
+ if (!mCancellationRequested.get()) {
+ result = mUploadOperation.execute(client);
+
+ /// move local temporal file or original file to its corresponding
+ // location in the ownCloud local folder
+ if (result.isSuccess()) {
+ if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) {
+ mFile.setStoragePath(null);
+
+ } else {
+ mFile.setStoragePath(expectedPath);
+ File fileToMove = null;
+ if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY
+ // ; see where temporalFile was
+ // set
+ fileToMove = temporalFile;
+ } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE
+ fileToMove = originalFile;
+ }
+ if (!expectedFile.equals(fileToMove)) {
+ File expectedFolder = expectedFile.getParentFile();
+ expectedFolder.mkdirs();
+ if (!expectedFolder.isDirectory() || !fileToMove.renameTo(expectedFile)) {
+ mFile.setStoragePath(null); // forget the local file
+ // by now, treat this as a success; the file was
+ // uploaded; the user won't like that the local file
+ // is not linked, but this should be a very rare
+ // fail;
+ // the best option could be show a warning message
+ // (but not a fail)
+ // result = new
+ // RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED);
+ // return result;
+ }
}
}
}
temporalFile.delete();
}
if (result.isSuccess()) {
- Log_OC.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage());
+ Log_OC.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " +
+ result.getLogMessage());
} else {
if (result.getException() != null) {
String complement = "";
if (!nameCheckPassed) {
complement = " (while checking file existence in server)";
} else if (!localCopyPassed) {
- complement = " (while copying local file to " + FileStorageUtils.getSavePath(mAccount.name)
+ complement = " (while copying local file to " +
+ FileStorageUtils.getSavePath(mAccount.name)
+ ")";
}
- Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage() + complement, result.getException());
+ Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
+ ": " + result.getLogMessage() + complement, result.getException());
} else {
- Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage());
+ Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
+ ": " + result.getLogMessage());
}
}
}
newFile.setFileLength(mFile.getFileLength());
newFile.setMimetype(mFile.getMimetype());
newFile.setModificationTimestamp(mFile.getModificationTimestamp());
- newFile.setModificationTimestampAtLastSyncForData(mFile.getModificationTimestampAtLastSyncForData());
+ newFile.setModificationTimestampAtLastSyncForData(
+ mFile.getModificationTimestampAtLastSyncForData());
// newFile.setEtag(mFile.getEtag())
newFile.setKeepInSync(mFile.keepInSync());
newFile.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties());
* Checks if remotePath does not exist in the server and returns it, or adds
* a suffix to it in order to avoid the server file is overwritten.
*
- * @param string
+ * @param wc
+ * @param remotePath
* @return
*/
private String getAvailableRemotePath(OwnCloudClient wc, String remotePath) throws Exception {
}
private boolean existsFile(OwnCloudClient client, String remotePath){
- ExistenceCheckRemoteOperation existsOperation = new ExistenceCheckRemoteOperation(remotePath, mContext, false);
+ ExistenceCheckRemoteOperation existsOperation =
+ new ExistenceCheckRemoteOperation(remotePath, mContext, false);
RemoteOperationResult result = existsOperation.execute(client);
return result.isSuccess();
}
public void cancel() {
- mUploadOperation.cancel();
+ mCancellationRequested = new AtomicBoolean(true);
+ if (mUploadOperation != null) {
+ mUploadOperation.cancel();
+ }
}
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.operations.common;
+import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
* with local data in the device.
*
* Provides methods to execute the operation both synchronously or asynchronously.
- *
- * @author David A. Velasco
*/
public abstract class SyncOperation extends RemoteOperation {
*
* Do not call this method from the main thread.
*
- * This method should be used whenever an ownCloud account is available, instead of {@link #execute(OwnCloudClient)}.
+ * This method should be used whenever an ownCloud account is available, instead of
+ * {@link #execute(OwnCloudClient, com.owncloud.android.datamodel.FileDataStorageManager)}.
*
- * @param account ownCloud account in remote ownCloud server to reach during the execution of the operation.
+ * @param storageManager
* @param context Android context for the component calling the method.
* @return Result of the operation.
*/
public RemoteOperationResult execute(FileDataStorageManager storageManager, Context context) {
if (storageManager == null) {
- throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+ throw new IllegalArgumentException("Trying to execute a sync operation with a " +
+ "NULL storage manager");
}
if (storageManager.getAccount() == null) {
- throw new IllegalArgumentException("Trying to execute a sync operation with a storage manager for a NULL account");
+ throw new IllegalArgumentException("Trying to execute a sync operation with a " +
+ "storage manager for a NULL account");
}
mStorageManager = storageManager;
return super.execute(mStorageManager.getAccount(), context);
*
* Do not call this method from the main thread.
*
- * @param client Client object to reach an ownCloud server during the execution of the operation.
+ * @param client Client object to reach an ownCloud server during the execution of the o
+ * peration.
+ * @param storageManager
* @return Result of the operation.
*/
- public RemoteOperationResult execute(OwnCloudClient client, FileDataStorageManager storageManager) {
+ public RemoteOperationResult execute(OwnCloudClient client,
+ FileDataStorageManager storageManager) {
if (storageManager == null)
- throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+ throw new IllegalArgumentException("Trying to execute a sync operation with a " +
+ "NULL storage manager");
mStorageManager = storageManager;
return super.execute(client);
}
/**
* Asynchronously executes the remote operation
*
- * This method should be used whenever an ownCloud account is available, instead of {@link #execute(OwnCloudClient)}.
+ * This method should be used whenever an ownCloud account is available, instead of
+ * {@link #execute(OwnCloudClient)}.
*
- * @param account ownCloud account in remote ownCloud server to reach during the execution of the operation.
+ * @param account ownCloud account in remote ownCloud server to reach during the
+ * execution of the operation.
* @param context Android context for the component calling the method.
* @param listener Listener to be notified about the execution of the operation.
- * @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called.
+ * @param listenerHandler Handler associated to the thread where the methods of the listener
+ * objects must be called.
* @return Thread were the remote operation is executed.
*/
/*
- public Thread execute(FileDataStorageManager storageManager, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) {
+ public Thread execute(FileDataStorageManager storageManager,
+ Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) {
if (storageManager == null) {
- throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+ throw new IllegalArgumentException("Trying to execute a sync operation
+ with a NULL storage manager");
}
if (storageManager.getAccount() == null) {
- throw new IllegalArgumentException("Trying to execute a sync operation with a storage manager for a NULL account");
+ throw new IllegalArgumentException("Trying to execute a sync operation with a
+ storage manager for a NULL account");
}
mStorageManager = storageManager;
- return super.execute(storageManager.getAccount(), context, listener, listenerHandler, callerActivity);
+ return super.execute(storageManager.getAccount(), context, listener, listenerHandler,
+ callerActivity);
}
*/
/**
* Asynchronously executes the remote operation
*
- * @param client Client object to reach an ownCloud server during the execution of the operation.
+ * @param client Client object to reach an ownCloud server during the
+ * execution of the operation.
* @param listener Listener to be notified about the execution of the operation.
- * @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called.
+ * @param listenerHandler Handler associated to the thread where the methods of
+ * the listener objects must be called.
* @return Thread were the remote operation is executed.
*/
- public Thread execute(OwnCloudClient client, FileDataStorageManager storageManager, OnRemoteOperationListener listener, Handler listenerHandler) {
+ public Thread execute(OwnCloudClient client, FileDataStorageManager storageManager,
+ OnRemoteOperationListener listener, Handler listenerHandler) {
if (storageManager == null) {
- throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+ throw new IllegalArgumentException("Trying to execute a sync operation " +
+ "with a NULL storage manager");
}
mStorageManager = storageManager;
return super.execute(client, listener, listenerHandler);
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.providers;
+import java.io.File;
+import java.security.Provider;
import java.util.ArrayList;
import java.util.HashMap;
+import com.owncloud.android.MainApp;
import com.owncloud.android.R;
-import com.owncloud.android.datamodel.ThumbnailsCacheManager;
+import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.db.ProviderMeta;
import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
+import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.shares.ShareType;
+import com.owncloud.android.utils.FileStorageUtils;
+import android.accounts.Account;
+import android.accounts.AccountManager;
import android.content.ContentProvider;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
/**
* The ContentProvider for the ownCloud App.
- *
- * @author Bartek Przybylski
- * @author David A. Velasco
- *
*/
public class FileContentProvider extends ContentProvider {
ProviderTableMeta.FILE_KEEP_IN_SYNC);
mFileProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER,
ProviderTableMeta.FILE_ACCOUNT_OWNER);
- mFileProjectionMap.put(ProviderTableMeta.FILE_ETAG,
+ mFileProjectionMap.put(ProviderTableMeta.FILE_ETAG,
ProviderTableMeta.FILE_ETAG);
mFileProjectionMap.put(ProviderTableMeta.FILE_SHARE_BY_LINK,
ProviderTableMeta.FILE_SHARE_BY_LINK);
ProviderTableMeta.FILE_REMOTE_ID);
mFileProjectionMap.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL,
ProviderTableMeta.FILE_UPDATE_THUMBNAIL);
+ mFileProjectionMap.put(ProviderTableMeta.FILE_IS_DOWNLOADING,
+ ProviderTableMeta.FILE_IS_DOWNLOADING);
}
private static final int SINGLE_FILE = 1;
private static final int SHARES = 4;
private static final String TAG = FileContentProvider.class.getSimpleName();
-
+
// Projection for ocshares table
private static HashMap<String, String> mOCSharesProjectionMap;
static {
mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER,
ProviderTableMeta.OCSHARES_ACCOUNT_OWNER);
}
-
+
private UriMatcher mUriMatcher;
-
+
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
//Log_OC.d(TAG, "Deleting " + uri + " at provider " + this);
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
-
+
private int delete(SQLiteDatabase db, Uri uri, String where, String[] whereArgs) {
int count = 0;
switch (mUriMatcher.match(uri)) {
if (children != null && children.moveToFirst()) {
long childId;
boolean isDir;
- //String remotePath;
while (!children.isAfterLast()) {
childId = children.getLong(children.getColumnIndex(ProviderTableMeta._ID));
isDir = "DIR".equals(children.getString(
//remotePath = children.getString(children.getColumnIndex(ProviderTableMeta.FILE_PATH));
if (isDir) {
count += delete(
- db,
- ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId),
- null,
+ db,
+ ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId),
+ null,
null
);
} else {
count += delete(
- db,
+ db,
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId),
- null,
+ null,
null
);
}
getContext().getContentResolver().notifyChange(newUri, null);
return newUri;
}
-
+
private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) {
switch (mUriMatcher.match(uri)){
case ROOT_DIRECTORY:
String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH);
String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER);
String[] projection = new String[] {
- ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH,
- ProviderTableMeta.FILE_ACCOUNT_OWNER
+ ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH,
+ ProviderTableMeta.FILE_ACCOUNT_OWNER
};
- String where = ProviderTableMeta.FILE_PATH + "=? AND " +
+ String where = ProviderTableMeta.FILE_PATH + "=? AND " +
ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
String[] whereArgs = new String[] {remotePath, accountName};
Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null);
- // ugly patch; serious refactorization is needed to reduce work in
+ // ugly patch; serious refactorization is needed to reduce work in
// FileDataStorageManager and bring it to FileContentProvider
- if (doubleCheck == null || !doubleCheck.moveToFirst()) {
+ if (doubleCheck == null || !doubleCheck.moveToFirst()) {
long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, null, values);
if (rowId > 0) {
- Uri insertedFileUri =
+ Uri insertedFileUri =
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
return insertedFileUri;
} else {
} else {
// file is already inserted; race condition, let's avoid a duplicated entry
Uri insertedFileUri = ContentUris.withAppendedId(
- ProviderTableMeta.CONTENT_URI_FILE,
+ ProviderTableMeta.CONTENT_URI_FILE,
doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID))
);
doubleCheck.close();
return insertedFileUri;
}
-
+
case SHARES:
String path = values.getAsString(ProviderTableMeta.OCSHARES_PATH);
String accountNameShare= values.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER);
String[] projectionShare = new String[] {
- ProviderTableMeta._ID, ProviderTableMeta.OCSHARES_PATH,
- ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
+ ProviderTableMeta._ID, ProviderTableMeta.OCSHARES_PATH,
+ ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
};
- String whereShare = ProviderTableMeta.OCSHARES_PATH + "=? AND " +
+ String whereShare = ProviderTableMeta.OCSHARES_PATH + "=? AND " +
ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
String[] whereArgsShare = new String[] {path, accountNameShare};
Uri insertedShareUri = null;
- Cursor doubleCheckShare =
+ Cursor doubleCheckShare =
query(db, uri, projectionShare, whereShare, whereArgsShare, null);
- // ugly patch; serious refactorization is needed to reduce work in
+ // ugly patch; serious refactorization is needed to reduce work in
// FileDataStorageManager and bring it to FileContentProvider
- if (doubleCheckShare == null || !doubleCheckShare.moveToFirst()) {
+ if (doubleCheckShare == null || !doubleCheckShare.moveToFirst()) {
long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values);
if (rowId >0) {
- insertedShareUri =
+ insertedShareUri =
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
} else {
throw new SQLException("ERROR " + uri);
} else {
// file is already inserted; race condition, let's avoid a duplicated entry
insertedShareUri = ContentUris.withAppendedId(
- ProviderTableMeta.CONTENT_URI_SHARE,
+ ProviderTableMeta.CONTENT_URI_SHARE,
doubleCheckShare.getLong(
doubleCheckShare.getColumnIndex(ProviderTableMeta._ID)
)
}
updateFilesTableAccordingToShareInsertion(db, uri, values);
return insertedShareUri;
-
+
default:
throw new IllegalArgumentException("Unknown uri id: " + uri);
}
-
+
}
-
+
private void updateFilesTableAccordingToShareInsertion(
SQLiteDatabase db, Uri uri, ContentValues shareValues
) {
ContentValues fileValues = new ContentValues();
fileValues.put(
- ProviderTableMeta.FILE_SHARE_BY_LINK,
- ShareType.PUBLIC_LINK.getValue() ==
- shareValues.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE)? 1 : 0
+ ProviderTableMeta.FILE_SHARE_BY_LINK,
+ ShareType.PUBLIC_LINK.getValue() ==
+ shareValues.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE) ? 1 : 0
);
- String whereShare = ProviderTableMeta.FILE_PATH + "=? AND " +
+ String whereShare = ProviderTableMeta.FILE_PATH + "=? AND " +
ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
String[] whereArgsShare = new String[] {
- shareValues.getAsString(ProviderTableMeta.OCSHARES_PATH),
+ shareValues.getAsString(ProviderTableMeta.OCSHARES_PATH),
shareValues.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER)
};
db.update(ProviderTableMeta.FILE_TABLE_NAME, fileValues, whereShare, whereArgsShare);
}
-
+
@Override
public boolean onCreate() {
mDbHelper = new DataBaseHelper(getContext());
-
+
String authority = getContext().getResources().getString(R.string.authority);
mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mUriMatcher.addURI(authority, null, ROOT_DIRECTORY);
mUriMatcher.addURI(authority, "dir/#", DIRECTORY);
mUriMatcher.addURI(authority, "shares/", SHARES);
mUriMatcher.addURI(authority, "shares/#", SHARES);
-
+
return true;
}
-
+
@Override
public Cursor query(
- Uri uri,
- String[] projection,
- String selection,
- String[] selectionArgs,
+ Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
String sortOrder
) {
-
+
Cursor result = null;
SQLiteDatabase db = mDbHelper.getReadableDatabase();
db.beginTransaction();
}
return result;
}
-
+
private Cursor query(
- SQLiteDatabase db,
- Uri uri,
- String[] projection,
- String selection,
- String[] selectionArgs,
+ SQLiteDatabase db,
+ Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
String sortOrder
) {
-
+
SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
sqlQuery.setTables(ProviderTableMeta.FILE_TABLE_NAME);
+ uri.getPathSegments().get(1));
}
break;
- case SHARES:
+ case SHARES:
sqlQuery.setTables(ProviderTableMeta.OCSHARES_TABLE_NAME);
sqlQuery.setProjectionMap(mOCSharesProjectionMap);
if (uri.getPathSegments().size() > 1) {
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-
+
int count = 0;
SQLiteDatabase db = mDbHelper.getWritableDatabase();
db.beginTransaction();
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
-
-
+
+
private int update(
- SQLiteDatabase db,
- Uri uri,
- ContentValues values,
- String selection,
+ SQLiteDatabase db,
+ Uri uri,
+ ContentValues values,
+ String selection,
String[] selectionArgs
) {
switch (mUriMatcher.match(uri)) {
ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs
);
}
- }
+ }
- /*
+ /*
private int updateFolderSize(SQLiteDatabase db, String folderId) {
int count = 0;
String [] whereArgs = new String[] { folderId };
-
- // read current size saved for the folder
+
+ // read current size saved for the folder
long folderSize = 0;
long folderParentId = -1;
Uri selectFolderUri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, folderId);
folderParentId = folderCursor.getLong(folderCursor.getColumnIndex(ProviderTableMeta.FILE_PARENT));;
}
folderCursor.close();
-
+
// read and sum sizes of children
long childrenSize = 0;
Uri selectChildrenUri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, folderId);
}
}
childrenCursor.close();
-
+
// update if needed
if (folderSize != childrenSize) {
Log_OC.d("FileContentProvider", "Updating " + folderSize + " to " + childrenSize);
ContentValues cv = new ContentValues();
cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, childrenSize);
count = db.update(ProviderTableMeta.FILE_TABLE_NAME, cv, folderWhere, whereArgs);
-
+
// propagate update until root
if (folderParentId > FileDataStorageManager.ROOT_PARENT_ID) {
Log_OC.d("FileContentProvider", "Propagating update to " + folderParentId);
return count;
}
*/
-
+
@Override
- public ContentProviderResult[] applyBatch (ArrayList<ContentProviderOperation> operations)
+ public ContentProviderResult[] applyBatch (ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
- Log_OC.d("FileContentProvider", "applying batch in provider " + this +
+ Log_OC.d("FileContentProvider", "applying batch in provider " + this +
" (temporary: " + isTemporary() + ")" );
ContentProviderResult[] results = new ContentProviderResult[operations.size()];
int i=0;
-
+
SQLiteDatabase db = mDbHelper.getWritableDatabase();
db.beginTransaction(); // it's supposed that transactions can be nested
try {
+ ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "
+ ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "
+ ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER, "
- + ProviderTableMeta.FILE_ETAG + " TEXT, "
+ + ProviderTableMeta.FILE_ETAG + " TEXT, "
+ ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER, "
+ ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT, "
+ ProviderTableMeta.FILE_PERMISSIONS + " TEXT null,"
+ ProviderTableMeta.FILE_REMOTE_ID + " TEXT null,"
- + ProviderTableMeta.FILE_UPDATE_THUMBNAIL + " INTEGER);" //boolean
+ + ProviderTableMeta.FILE_UPDATE_THUMBNAIL + " INTEGER," //boolean
+ + ProviderTableMeta.FILE_IS_DOWNLOADING + " INTEGER);" //boolean
);
-
+
// Create table ocshares
db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
+ ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
+ ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean
+ ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
- + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
+ + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
+ ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log_OC.i("SQL", "Entering in onUpgrade");
- boolean upgraded = false;
+ boolean upgraded = false;
if (oldVersion == 1 && newVersion >= 2) {
Log_OC.i("SQL", "Entering in the #1 ADD in onUpgrade");
db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
db.beginTransaction();
try {
db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
- " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA +
+ " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA +
" INTEGER " + " DEFAULT 0");
-
+
// assume there are not local changes pending to upload
- db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
- " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = "
- + System.currentTimeMillis() +
+ db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
+ " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = "
+ + System.currentTimeMillis() +
" WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
-
+
upgraded = true;
db.setTransactionSuccessful();
} finally {
Log_OC.i("SQL", "Entering in the #3 ADD in onUpgrade");
db.beginTransaction();
try {
- db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
- " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA +
- " INTEGER " + " DEFAULT 0");
-
- db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
+ db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+ " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA +
+ " INTEGER " + " DEFAULT 0");
+
+ db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
" SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " +
ProviderTableMeta.FILE_MODIFIED +
" WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
-
+
upgraded = true;
db.setTransactionSuccessful();
} finally {
}
}
if (!upgraded)
- Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
+ Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
-
+
if (oldVersion < 5 && newVersion >= 5) {
Log_OC.i("SQL", "Entering in the #4 ADD in onUpgrade");
db.beginTransaction();
try {
- db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+ db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
" ADD COLUMN " + ProviderTableMeta.FILE_ETAG + " TEXT " +
" DEFAULT NULL");
-
+
upgraded = true;
db.setTransactionSuccessful();
} finally {
}
}
if (!upgraded)
- Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
+ Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
if (oldVersion < 6 && newVersion >= 6) {
db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
" ADD COLUMN " + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER " +
" DEFAULT 0");
-
+
db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
" ADD COLUMN " + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT " +
" DEFAULT NULL");
+ ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, "
+ ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, "
+ ProviderTableMeta.OCSHARES_PATH + " TEXT, "
- + ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, "
+ + ProviderTableMeta.OCSHARES_PERMISSIONS + " INTEGER, "
+ ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, "
+ ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, "
+ ProviderTableMeta.OCSHARES_TOKEN + " TEXT, "
+ ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
+ ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean
+ ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
- + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
- + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
+ + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
+ + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );");
upgraded = true;
db.setTransactionSuccessful();
}
}
if (!upgraded)
- Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
+ Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
if (oldVersion < 7 && newVersion >= 7) {
Log_OC.i("SQL", "Entering in the #7 ADD in onUpgrade");
db.beginTransaction();
try {
- db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+ db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
" ADD COLUMN " + ProviderTableMeta.FILE_PERMISSIONS + " TEXT " +
" DEFAULT NULL");
- db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+ db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
" ADD COLUMN " + ProviderTableMeta.FILE_REMOTE_ID + " TEXT " +
" DEFAULT NULL");
-
+
upgraded = true;
db.setTransactionSuccessful();
} finally {
}
}
if (!upgraded)
- Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
+ Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
if (oldVersion < 8 && newVersion >= 8) {
Log_OC.i("SQL", "Entering in the #8 ADD in onUpgrade");
db.beginTransaction();
try {
- db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+ db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
" ADD COLUMN " + ProviderTableMeta.FILE_UPDATE_THUMBNAIL + " INTEGER " +
" DEFAULT 0");
}
}
if (!upgraded)
- Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
+ Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
+
+ if (oldVersion < 9 && newVersion >= 9) {
+ Log_OC.i("SQL", "Entering in the #9 ADD in onUpgrade");
+ db.beginTransaction();
+ try {
+ db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+ " ADD COLUMN " + ProviderTableMeta.FILE_IS_DOWNLOADING + " INTEGER " +
+ " DEFAULT 0");
+
+ upgraded = true;
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+ if (!upgraded)
+ Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
+ ", newVersion == " + newVersion);
+
+ if (oldVersion < 10 && newVersion >= 10) {
+ Log_OC.i("SQL", "Entering in the #10 ADD in onUpgrade");
+ updateAccountName(db);
+ upgraded = true;
+ }
+ if (!upgraded)
+ Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
+ ", newVersion == " + newVersion);
+ }
+ }
+
+
+ /**
+ * Version 10 of database does not modify its scheme. It coincides with the upgrade of the ownCloud account names
+ * structure to include in it the path to the server instance. Updating the account names and path to local files
+ * in the files table is a must to keep the existing account working and the database clean.
+ *
+ * See {@link com.owncloud.android.authentication.AccountUtils#updateAccountVersion(android.content.Context)}
+ *
+ * @param db Database where table of files is included.
+ */
+ private void updateAccountName(SQLiteDatabase db){
+ Log_OC.d("SQL", "THREAD: "+ Thread.currentThread().getName());
+ AccountManager ama = AccountManager.get(getContext());
+ try {
+ // get accounts from AccountManager ; we can't be sure if accounts in it are updated or not although
+ // we know the update was previously done in {link @FileActivity#onCreate} because the changes through
+ // AccountManager are not synchronous
+ Account[] accounts = AccountManager.get(getContext()).getAccountsByType(
+ MainApp.getAccountType());
+ String serverUrl, username, oldAccountName, newAccountName;
+ for (Account account : accounts) {
+ // build both old and new account name
+ serverUrl = ama.getUserData(account, AccountUtils.Constants.KEY_OC_BASE_URL);
+ username = account.name.substring(0, account.name.lastIndexOf('@'));
+ oldAccountName = AccountUtils.buildAccountNameOld(Uri.parse(serverUrl), username);
+ newAccountName = AccountUtils.buildAccountName(Uri.parse(serverUrl), username);
+
+ // update values in database
+ db.beginTransaction();
+ try {
+ ContentValues cv = new ContentValues();
+ cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, newAccountName);
+ int num = db.update(ProviderTableMeta.FILE_TABLE_NAME,
+ cv,
+ ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
+ new String[]{oldAccountName});
+
+ Log_OC.d("SQL", "Updated account in database: old name == " + oldAccountName +
+ ", new name == " + newAccountName + " (" + num + " rows updated )");
+
+ // update path for downloaded files
+ updateDownloadedFiles(db, newAccountName, oldAccountName);
+
+ db.setTransactionSuccessful();
+
+ } catch (SQLException e) {
+ Log_OC.e(TAG, "SQL Exception upgrading account names or paths in database", e);
+ } finally {
+ db.endTransaction();
+ }
+ }
+ } catch (Exception e) {
+ Log_OC.e(TAG, "Exception upgrading account names or paths in database", e);
}
}
+
+ /**
+ * Rename the local ownCloud folder of one account to match the a rename of the account itself. Updates the
+ * table of files in database so that the paths to the local files keep being the same.
+ *
+ * @param db Database where table of files is included.
+ * @param newAccountName New name for the target OC account.
+ * @param oldAccountName Old name of the target OC account.
+ */
+ private void updateDownloadedFiles(SQLiteDatabase db, String newAccountName,
+ String oldAccountName) {
+
+ String whereClause = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
+ ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL";
+
+ Cursor c = db.query(ProviderTableMeta.FILE_TABLE_NAME,
+ null,
+ whereClause,
+ new String[] { newAccountName },
+ null, null, null);
+
+ try {
+ if (c.moveToFirst()) {
+ // create storage path
+ String oldAccountPath = FileStorageUtils.getSavePath(oldAccountName);
+ String newAccountPath = FileStorageUtils.getSavePath(newAccountName);
+
+ // move files
+ File oldAccountFolder = new File(oldAccountPath);
+ File newAccountFolder = new File(newAccountPath);
+ oldAccountFolder.renameTo(newAccountFolder);
+
+ // update database
+ do {
+ // Update database
+ String oldPath = c.getString(
+ c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));
+ OCFile file = new OCFile(
+ c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH)));
+ String newPath = FileStorageUtils.getDefaultSavePathFor(newAccountName, file);
+
+ ContentValues cv = new ContentValues();
+ cv.put(ProviderTableMeta.FILE_STORAGE_PATH, newPath);
+ db.update(ProviderTableMeta.FILE_TABLE_NAME,
+ cv,
+ ProviderTableMeta.FILE_STORAGE_PATH + "=?",
+ new String[]{oldPath});
+
+ Log_OC.v("SQL", "Updated path of downloaded file: old file name == " + oldPath +
+ ", new file name == " + newPath);
+
+ } while (c.moveToNext());
+ }
+ } finally {
+ c.close();
+ }
+
+ }
+
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
import com.owncloud.android.lib.resources.shares.ShareType;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation;
import com.owncloud.android.operations.common.SyncOperation;
import com.owncloud.android.operations.CreateFolderOperation;
import com.owncloud.android.operations.RemoveFileOperation;
import com.owncloud.android.operations.RenameFileOperation;
import com.owncloud.android.operations.SynchronizeFileOperation;
+import com.owncloud.android.operations.SynchronizeFolderOperation;
import com.owncloud.android.operations.UnshareLinkOperation;
import android.accounts.Account;
+import android.accounts.AccountManager;
import android.accounts.AccountsException;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
public static final String EXTRA_SYNC_FILE_CONTENTS = "SYNC_FILE_CONTENTS";
public static final String EXTRA_RESULT = "RESULT";
public static final String EXTRA_NEW_PARENT_PATH = "NEW_PARENT_PATH";
-
- // TODO review if ALL OF THEM are necessary
- public static final String EXTRA_SUCCESS_IF_ABSENT = "SUCCESS_IF_ABSENT";
- public static final String EXTRA_USERNAME = "USERNAME";
- public static final String EXTRA_PASSWORD = "PASSWORD";
- public static final String EXTRA_AUTH_TOKEN = "AUTH_TOKEN";
+ public static final String EXTRA_FILE = "FILE";
+ public static final String EXTRA_PASSWORD_SHARE = "PASSWORD_SHARE";
+
public static final String EXTRA_COOKIE = "COOKIE";
public static final String ACTION_CREATE_SHARE = "CREATE_SHARE";
public static final String ACTION_UNSHARE = "UNSHARE";
public static final String ACTION_GET_SERVER_INFO = "GET_SERVER_INFO";
public static final String ACTION_OAUTH2_GET_ACCESS_TOKEN = "OAUTH2_GET_ACCESS_TOKEN";
- public static final String ACTION_EXISTENCE_CHECK = "EXISTENCE_CHECK";
public static final String ACTION_GET_USER_NAME = "GET_USER_NAME";
public static final String ACTION_RENAME = "RENAME";
public static final String ACTION_REMOVE = "REMOVE";
public static final String ACTION_CREATE_FOLDER = "CREATE_FOLDER";
public static final String ACTION_SYNC_FILE = "SYNC_FILE";
+ public static final String ACTION_SYNC_FOLDER = "SYNC_FOLDER";//for the moment, just to download
public static final String ACTION_MOVE_FILE = "MOVE_FILE";
- public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() + ".OPERATION_ADDED";
- public static final String ACTION_OPERATION_FINISHED = OperationsService.class.getName() + ".OPERATION_FINISHED";
+ public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() +
+ ".OPERATION_ADDED";
+ public static final String ACTION_OPERATION_FINISHED = OperationsService.class.getName() +
+ ".OPERATION_FINISHED";
- private ConcurrentLinkedQueue<Pair<Target, RemoteOperation>> mPendingOperations =
- new ConcurrentLinkedQueue<Pair<Target, RemoteOperation>>();
private ConcurrentMap<Integer, Pair<RemoteOperation, RemoteOperationResult>>
mUndispatchedFinishedOperations =
private static class Target {
public Uri mServerUrl = null;
public Account mAccount = null;
- public String mUsername = null;
- public String mPassword = null;
- public String mAuthToken = null;
public String mCookie = null;
- public Target(Account account, Uri serverUrl, String username, String password, String authToken,
- String cookie) {
+ public Target(Account account, Uri serverUrl, String cookie) {
mAccount = account;
mServerUrl = serverUrl;
- mUsername = username;
- mPassword = password;
- mAuthToken = authToken;
mCookie = cookie;
}
}
- private Looper mServiceLooper;
- private ServiceHandler mServiceHandler;
- private OperationsServiceBinder mBinder;
- private OwnCloudClient mOwnCloudClient = null;
- private Target mLastTarget = null;
- private FileDataStorageManager mStorageManager;
- private RemoteOperation mCurrentOperation = null;
+ private ServiceHandler mOperationsHandler;
+ private OperationsServiceBinder mOperationsBinder;
+ private SyncFolderHandler mSyncFolderHandler;
/**
* Service initialization
@Override
public void onCreate() {
super.onCreate();
- HandlerThread thread = new HandlerThread("Operations service thread", Process.THREAD_PRIORITY_BACKGROUND);
+ Log_OC.d(TAG, "Creating service");
+
+ /// First worker thread for most of operations
+ HandlerThread thread = new HandlerThread("Operations thread",
+ Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
- mServiceLooper = thread.getLooper();
- mServiceHandler = new ServiceHandler(mServiceLooper, this);
- mBinder = new OperationsServiceBinder();
+ mOperationsHandler = new ServiceHandler(thread.getLooper(), this);
+ mOperationsBinder = new OperationsServiceBinder(mOperationsHandler);
+
+ /// Separated worker thread for download of folders (WIP)
+ thread = new HandlerThread("Syncfolder thread", Process.THREAD_PRIORITY_BACKGROUND);
+ thread.start();
+ mSyncFolderHandler = new SyncFolderHandler(thread.getLooper(), this);
}
*
* New operations are added calling to startService(), resulting in a call to this method.
* This ensures the service will keep on working although the caller activity goes away.
- *
- * IMPORTANT: the only operations performed here right now is {@link GetSharedFilesOperation}. The class
- * is taking advantage of it due to time constraints.
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- //Log_OC.wtf(TAG, "onStartCommand init" );
- Message msg = mServiceHandler.obtainMessage();
- msg.arg1 = startId;
- mServiceHandler.sendMessage(msg);
- //Log_OC.wtf(TAG, "onStartCommand end" );
+ Log_OC.d(TAG, "Starting command with id " + startId);
+
+ // WIP: for the moment, only SYNC_FOLDER is expected here;
+ // the rest of the operations are requested through the Binder
+ if (ACTION_SYNC_FOLDER.equals(intent.getAction())) {
+
+ if (!intent.hasExtra(EXTRA_ACCOUNT) || !intent.hasExtra(EXTRA_REMOTE_PATH)) {
+ Log_OC.e(TAG, "Not enough information provided in intent");
+ return START_NOT_STICKY;
+ }
+ Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
+ String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH);
+
+ Pair<Account, String> itemSyncKey = new Pair<Account , String>(account, remotePath);
+
+ Pair<Target, RemoteOperation> itemToQueue = newOperation(intent);
+ if (itemToQueue != null) {
+ mSyncFolderHandler.add(account, remotePath,
+ (SynchronizeFolderOperation)itemToQueue.second);
+ Message msg = mSyncFolderHandler.obtainMessage();
+ msg.arg1 = startId;
+ msg.obj = itemSyncKey;
+ mSyncFolderHandler.sendMessage(msg);
+ }
+
+ } else {
+ Message msg = mOperationsHandler.obtainMessage();
+ msg.arg1 = startId;
+ mOperationsHandler.sendMessage(msg);
+ }
+
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
- //Log_OC.wtf(TAG, "onDestroy init" );
+ Log_OC.v(TAG, "Destroying service" );
// Saving cookies
try {
OwnCloudClientManagerFactory.getDefaultSingleton().
e.printStackTrace();
}
- //Log_OC.wtf(TAG, "Clear mUndispatchedFinisiedOperations" );
mUndispatchedFinishedOperations.clear();
-
- //Log_OC.wtf(TAG, "onDestroy end" );
+
+ mOperationsBinder = null;
+
+ mOperationsHandler.getLooper().quit();
+ mOperationsHandler = null;
+
+ mSyncFolderHandler.getLooper().quit();
+ mSyncFolderHandler = null;
+
super.onDestroy();
}
-
/**
* Provides a binder object that clients can use to perform actions on the queue of operations,
* except the addition of new operations.
@Override
public IBinder onBind(Intent intent) {
//Log_OC.wtf(TAG, "onBind" );
- return mBinder;
+ return mOperationsBinder;
}
*/
@Override
public boolean onUnbind(Intent intent) {
- ((OperationsServiceBinder)mBinder).clearListeners();
+ mOperationsBinder.clearListeners();
return false; // not accepting rebinding (default behaviour)
}
-
+
/**
* Binder to let client components to perform actions on the queue of operations.
*
public class OperationsServiceBinder extends Binder /* implements OnRemoteOperationListener */ {
/**
- * Map of listeners that will be reported about the end of operations from a {@link OperationsServiceBinder} instance
+ * Map of listeners that will be reported about the end of operations from a
+ * {@link OperationsServiceBinder} instance
*/
private ConcurrentMap<OnRemoteOperationListener, Handler> mBoundListeners =
new ConcurrentHashMap<OnRemoteOperationListener, Handler>();
+ private ServiceHandler mServiceHandler = null;
+
+ public OperationsServiceBinder(ServiceHandler serviceHandler) {
+ mServiceHandler = serviceHandler;
+ }
+
+
/**
- * Cancels an operation
+ * Cancels a pending or current synchronization.
*
- * TODO
+ * @param account ownCloud account where the remote folder is stored.
+ * @param file A folder in the queue of pending synchronizations
*/
- public void cancel() {
- // TODO
+ public void cancel(Account account, OCFile file) {
+ mSyncFolderHandler.cancel(account, file);
}
-
-
+
+
public void clearListeners() {
mBoundListeners.clear();
* Adds a listener interested in being reported about the end of operations.
*
* @param listener Object to notify about the end of operations.
- * @param callbackHandler {@link Handler} to access the listener without breaking Android threading protection.
+ * @param callbackHandler {@link Handler} to access the listener without
+ * breaking Android threading protection.
*/
- public void addOperationListener (OnRemoteOperationListener listener, Handler callbackHandler) {
+ public void addOperationListener (OnRemoteOperationListener listener,
+ Handler callbackHandler) {
synchronized (mBoundListeners) {
mBoundListeners.put(listener, callbackHandler);
}
/**
- * Removes a listener from the list of objects interested in the being reported about the end of operations.
+ * Removes a listener from the list of objects interested in the being reported about
+ * the end of operations.
*
* @param listener Object to notify about progress of transfer.
*/
/**
* TODO - IMPORTANT: update implementation when more operations are moved into the service
*
- * @return 'True' when an operation that enforces the user to wait for completion is in process.
+ * @return 'True' when an operation that enforces the user to wait for completion is
+ * in process.
*/
public boolean isPerformingBlockingOperation() {
- return (!mPendingOperations.isEmpty());
+ return (!mServiceHandler.mPendingOperations.isEmpty());
}
/**
- * Creates and adds to the queue a new operation, as described by operationIntent
+ * Creates and adds to the queue a new operation, as described by operationIntent.
+ *
+ * Calls startService to make the operation is processed by the ServiceHandler.
*
* @param operationIntent Intent describing a new operation to queue and execute.
* @return Identifier of the operation created, or null if failed.
*/
- public long newOperation(Intent operationIntent) {
- RemoteOperation operation = null;
- Target target = null;
- try {
- if (!operationIntent.hasExtra(EXTRA_ACCOUNT) &&
- !operationIntent.hasExtra(EXTRA_SERVER_URL)) {
- Log_OC.e(TAG, "Not enough information provided in intent");
-
- } else {
- Account account = operationIntent.getParcelableExtra(EXTRA_ACCOUNT);
- String serverUrl = operationIntent.getStringExtra(EXTRA_SERVER_URL);
- String username = operationIntent.getStringExtra(EXTRA_USERNAME);
- String password = operationIntent.getStringExtra(EXTRA_PASSWORD);
- String authToken = operationIntent.getStringExtra(EXTRA_AUTH_TOKEN);
- String cookie = operationIntent.getStringExtra(EXTRA_COOKIE);
- target = new Target(
- account,
- (serverUrl == null) ? null : Uri.parse(serverUrl),
- username,
- password,
- authToken,
- cookie
- );
-
- String action = operationIntent.getAction();
- if (action.equals(ACTION_CREATE_SHARE)) { // Create Share
- String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- Intent sendIntent = operationIntent.getParcelableExtra(EXTRA_SEND_INTENT);
- if (remotePath.length() > 0) {
- operation = new CreateShareOperation(remotePath, ShareType.PUBLIC_LINK,
- "", false, "", 1, sendIntent);
- }
-
- } else if (action.equals(ACTION_UNSHARE)) { // Unshare file
- String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- if (remotePath.length() > 0) {
- operation = new UnshareLinkOperation(
- remotePath,
- OperationsService.this);
- }
-
- } else if (action.equals(ACTION_GET_SERVER_INFO)) {
- // check OC server and get basic information from it
- operation = new GetServerInfoOperation(serverUrl, OperationsService.this);
-
- } else if (action.equals(ACTION_OAUTH2_GET_ACCESS_TOKEN)) {
- /// GET ACCESS TOKEN to the OAuth server
- String oauth2QueryParameters =
- operationIntent.getStringExtra(EXTRA_OAUTH2_QUERY_PARAMETERS);
- operation = new OAuth2GetAccessToken(
- getString(R.string.oauth2_client_id),
- getString(R.string.oauth2_redirect_uri),
- getString(R.string.oauth2_grant_type),
- oauth2QueryParameters);
-
- } else if (action.equals(ACTION_EXISTENCE_CHECK)) {
- // Existence Check
- String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- boolean successIfAbsent = operationIntent.getBooleanExtra(EXTRA_SUCCESS_IF_ABSENT, false);
- operation = new ExistenceCheckRemoteOperation(remotePath, OperationsService.this, successIfAbsent);
-
- } else if (action.equals(ACTION_GET_USER_NAME)) {
- // Get User Name
- operation = new GetRemoteUserNameOperation();
-
- } else if (action.equals(ACTION_RENAME)) {
- // Rename file or folder
- String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- String newName = operationIntent.getStringExtra(EXTRA_NEWNAME);
- operation = new RenameFileOperation(remotePath, account, newName);
-
- } else if (action.equals(ACTION_REMOVE)) {
- // Remove file or folder
- String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- boolean onlyLocalCopy = operationIntent.getBooleanExtra(EXTRA_REMOVE_ONLY_LOCAL, false);
- operation = new RemoveFileOperation(remotePath, onlyLocalCopy);
-
- } else if (action.equals(ACTION_CREATE_FOLDER)) {
- // Create Folder
- String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- boolean createFullPath = operationIntent.getBooleanExtra(EXTRA_CREATE_FULL_PATH, true);
- operation = new CreateFolderOperation(remotePath, createFullPath);
-
- } else if (action.equals(ACTION_SYNC_FILE)) {
- // Sync file
- String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- boolean syncFileContents = operationIntent.getBooleanExtra(EXTRA_SYNC_FILE_CONTENTS, true);
- operation = new SynchronizeFileOperation(remotePath, account, syncFileContents, getApplicationContext());
- } else if (action.equals(ACTION_MOVE_FILE)) {
- // Move file/folder
- String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
- String newParentPath = operationIntent.getStringExtra(EXTRA_NEW_PARENT_PATH);
- operation = new MoveFileOperation(remotePath,newParentPath,account);
- }
-
- }
-
- } catch (IllegalArgumentException e) {
- Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage());
- operation = null;
- }
-
- if (operation != null) {
- mPendingOperations.add(new Pair<Target , RemoteOperation>(target, operation));
+ public long queueNewOperation(Intent operationIntent) {
+ Pair<Target, RemoteOperation> itemToQueue = newOperation(operationIntent);
+ if (itemToQueue != null) {
+ mServiceHandler.mPendingOperations.add(itemToQueue);
startService(new Intent(OperationsService.this, OperationsService.class));
- //Log_OC.wtf(TAG, "New operation added, opId: " + operation.hashCode());
- // better id than hash? ; should be good enough by the time being
- return operation.hashCode();
+ return itemToQueue.second.hashCode();
} else {
- //Log_OC.wtf(TAG, "New operation failed, returned Long.MAX_VALUE");
return Long.MAX_VALUE;
}
}
-
- public boolean dispatchResultIfFinished(int operationId, OnRemoteOperationListener listener) {
+
+
+ public boolean dispatchResultIfFinished(int operationId,
+ OnRemoteOperationListener listener) {
Pair<RemoteOperation, RemoteOperationResult> undispatched =
mUndispatchedFinishedOperations.remove(operationId);
if (undispatched != null) {
return true;
//Log_OC.wtf(TAG, "Sending callback later");
} else {
- if (!mPendingOperations.isEmpty()) {
- return true;
- } else {
- return false;
- }
- //Log_OC.wtf(TAG, "Not finished yet");
+ return (!mServiceHandler.mPendingOperations.isEmpty());
}
}
+
+
+ /**
+ * Returns True when the file described by 'file' in the ownCloud account 'account' is
+ * downloading or waiting to download.
+ *
+ * If 'file' is a directory, returns 'true' if some of its descendant files is downloading
+ * or waiting to download.
+ *
+ * @param account ownCloud account where the remote file is stored.
+ * @param remotePath Path of the folder to check if something is synchronizing
+ * / downloading / uploading inside.
+ */
+ public boolean isSynchronizing(Account account, String remotePath) {
+ return mSyncFolderHandler.isSynchronizing(account, remotePath);
+ }
}
-
-
- /**
+
+
+ /**
* Operations worker. Performs the pending operations in the order they were requested.
*
* Created with the Looper of a new thread, started in {@link OperationsService#onCreate()}.
*/
private static class ServiceHandler extends Handler {
- // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak
+ // don't make it a final class, and don't remove the static ; lint will warn about a p
+ // ossible memory leak
+
+
OperationsService mService;
+
+
+ private ConcurrentLinkedQueue<Pair<Target, RemoteOperation>> mPendingOperations =
+ new ConcurrentLinkedQueue<Pair<Target, RemoteOperation>>();
+ private RemoteOperation mCurrentOperation = null;
+ private Target mLastTarget = null;
+ private OwnCloudClient mOwnCloudClient = null;
+ private FileDataStorageManager mStorageManager;
+
+
public ServiceHandler(Looper looper, OperationsService service) {
super(looper);
if (service == null) {
@Override
public void handleMessage(Message msg) {
- mService.nextOperation();
+ nextOperation();
+ Log_OC.d(TAG, "Stopping after command with id " + msg.arg1);
mService.stopSelf(msg.arg1);
}
- }
-
-
- /**
- * Performs the next operation in the queue
- */
- private void nextOperation() {
- //Log_OC.wtf(TAG, "nextOperation init" );
- Pair<Target, RemoteOperation> next = null;
- synchronized(mPendingOperations) {
- next = mPendingOperations.peek();
- }
-
- if (next != null) {
+ /**
+ * Performs the next operation in the queue
+ */
+ private void nextOperation() {
- mCurrentOperation = next.second;
- RemoteOperationResult result = null;
- try {
- /// prepare client object to send the request to the ownCloud server
- if (mLastTarget == null || !mLastTarget.equals(next.first)) {
- mLastTarget = next.first;
- if (mLastTarget.mAccount != null) {
- OwnCloudAccount ocAccount = new OwnCloudAccount(mLastTarget.mAccount, this);
- mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
- getClientFor(ocAccount, this);
- mStorageManager =
- new FileDataStorageManager(
- mLastTarget.mAccount,
- getContentResolver());
- } else {
- OwnCloudCredentials credentials = null;
- if (mLastTarget.mUsername != null &&
- mLastTarget.mUsername.length() > 0) {
- credentials = OwnCloudCredentialsFactory.newBasicCredentials(
- mLastTarget.mUsername,
- mLastTarget.mPassword); // basic
-
- } else if (mLastTarget.mAuthToken != null &&
- mLastTarget.mAuthToken.length() > 0) {
- credentials = OwnCloudCredentialsFactory.newBearerCredentials(
- mLastTarget.mAuthToken); // bearer token
-
- } else if (mLastTarget.mCookie != null &&
- mLastTarget.mCookie.length() > 0) {
- credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(
- mLastTarget.mCookie); // SAML SSO
+ //Log_OC.wtf(TAG, "nextOperation init" );
+
+ Pair<Target, RemoteOperation> next = null;
+ synchronized(mPendingOperations) {
+ next = mPendingOperations.peek();
+ }
+
+ if (next != null) {
+
+ mCurrentOperation = next.second;
+ RemoteOperationResult result = null;
+ try {
+ /// prepare client object to send the request to the ownCloud server
+ if (mLastTarget == null || !mLastTarget.equals(next.first)) {
+ mLastTarget = next.first;
+ if (mLastTarget.mAccount != null) {
+ OwnCloudAccount ocAccount = new OwnCloudAccount(mLastTarget.mAccount,
+ mService);
+ mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+ getClientFor(ocAccount, mService);
+
+ OwnCloudVersion version = com.owncloud.android.authentication.AccountUtils.getServerVersion(
+ mLastTarget.mAccount
+ );
+ mOwnCloudClient.setOwnCloudVersion(version);
+
+ mStorageManager = new FileDataStorageManager(
+ mLastTarget.mAccount,
+ mService.getContentResolver()
+ );
+ } else {
+ OwnCloudCredentials credentials = null;
+ if (mLastTarget.mCookie != null &&
+ mLastTarget.mCookie.length() > 0) {
+ // just used for GetUserName
+ // TODO refactor to run GetUserName as AsyncTask in the context of
+ // AuthenticatorActivity
+ credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(
+ mLastTarget.mCookie); // SAML SSO
+ }
+ OwnCloudAccount ocAccount = new OwnCloudAccount(
+ mLastTarget.mServerUrl, credentials);
+ mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+ getClientFor(ocAccount, mService);
+ mStorageManager = null;
}
- OwnCloudAccount ocAccount = new OwnCloudAccount(
- mLastTarget.mServerUrl, credentials);
- mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
- getClientFor(ocAccount, this);
- mStorageManager = null;
}
- }
- /// perform the operation
- if (mCurrentOperation instanceof SyncOperation) {
- result = ((SyncOperation)mCurrentOperation).execute(mOwnCloudClient, mStorageManager);
- } else {
- result = mCurrentOperation.execute(mOwnCloudClient);
- }
+ /// perform the operation
+ if (mCurrentOperation instanceof SyncOperation) {
+ result = ((SyncOperation)mCurrentOperation).execute(mOwnCloudClient,
+ mStorageManager);
+ } else {
+ result = mCurrentOperation.execute(mOwnCloudClient);
+ }
+
+ } catch (AccountsException e) {
+ if (mLastTarget.mAccount == null) {
+ Log_OC.e(TAG, "Error while trying to get authorization for a NULL account",
+ e);
+ } else {
+ Log_OC.e(TAG, "Error while trying to get authorization for " +
+ mLastTarget.mAccount.name, e);
+ }
+ result = new RemoteOperationResult(e);
+
+ } catch (IOException e) {
+ if (mLastTarget.mAccount == null) {
+ Log_OC.e(TAG, "Error while trying to get authorization for a NULL account",
+ e);
+ } else {
+ Log_OC.e(TAG, "Error while trying to get authorization for " +
+ mLastTarget.mAccount.name, e);
+ }
+ result = new RemoteOperationResult(e);
+ } catch (Exception e) {
+ if (mLastTarget.mAccount == null) {
+ Log_OC.e(TAG, "Unexpected error for a NULL account", e);
+ } else {
+ Log_OC.e(TAG, "Unexpected error for " + mLastTarget.mAccount.name, e);
+ }
+ result = new RemoteOperationResult(e);
- } catch (AccountsException e) {
- if (mLastTarget.mAccount == null) {
- Log_OC.e(TAG, "Error while trying to get authorization for a NULL account", e);
- } else {
- Log_OC.e(TAG, "Error while trying to get authorization for " + mLastTarget.mAccount.name, e);
+ } finally {
+ synchronized(mPendingOperations) {
+ mPendingOperations.poll();
+ }
}
- result = new RemoteOperationResult(e);
- } catch (IOException e) {
- if (mLastTarget.mAccount == null) {
- Log_OC.e(TAG, "Error while trying to get authorization for a NULL account", e);
- } else {
- Log_OC.e(TAG, "Error while trying to get authorization for " + mLastTarget.mAccount.name, e);
- }
- result = new RemoteOperationResult(e);
- } catch (Exception e) {
- if (mLastTarget.mAccount == null) {
- Log_OC.e(TAG, "Unexpected error for a NULL account", e);
- } else {
- Log_OC.e(TAG, "Unexpected error for " + mLastTarget.mAccount.name, e);
- }
- result = new RemoteOperationResult(e);
-
- } finally {
- synchronized(mPendingOperations) {
- mPendingOperations.poll();
- }
+ //sendBroadcastOperationFinished(mLastTarget, mCurrentOperation, result);
+ mService.dispatchResultToOperationListeners(mCurrentOperation, result);
}
-
- //sendBroadcastOperationFinished(mLastTarget, mCurrentOperation, result);
- dispatchResultToOperationListeners(mLastTarget, mCurrentOperation, result);
}
+
+
+
}
+
+ /**
+ * Creates a new operation, as described by operationIntent.
+ *
+ * TODO - move to ServiceHandler (probably)
+ *
+ * @param operationIntent Intent describing a new operation to queue and execute.
+ * @return Pair with the new operation object and the information about its
+ * target server.
+ */
+ private Pair<Target , RemoteOperation> newOperation(Intent operationIntent) {
+ RemoteOperation operation = null;
+ Target target = null;
+ try {
+ if (!operationIntent.hasExtra(EXTRA_ACCOUNT) &&
+ !operationIntent.hasExtra(EXTRA_SERVER_URL)) {
+ Log_OC.e(TAG, "Not enough information provided in intent");
+
+ } else {
+ Account account = operationIntent.getParcelableExtra(EXTRA_ACCOUNT);
+ String serverUrl = operationIntent.getStringExtra(EXTRA_SERVER_URL);
+ String cookie = operationIntent.getStringExtra(EXTRA_COOKIE);
+ target = new Target(
+ account,
+ (serverUrl == null) ? null : Uri.parse(serverUrl),
+ cookie
+ );
+
+ String action = operationIntent.getAction();
+ if (action.equals(ACTION_CREATE_SHARE)) { // Create Share
+ String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+ String password = operationIntent.getStringExtra(EXTRA_PASSWORD_SHARE);
+ Intent sendIntent = operationIntent.getParcelableExtra(EXTRA_SEND_INTENT);
+ if (remotePath.length() > 0) {
+ operation = new CreateShareOperation(OperationsService.this, remotePath,
+ ShareType.PUBLIC_LINK,
+ "", false, password, 1, sendIntent);
+ }
+
+ } else if (action.equals(ACTION_UNSHARE)) { // Unshare file
+ String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+ if (remotePath.length() > 0) {
+ operation = new UnshareLinkOperation(
+ remotePath,
+ OperationsService.this);
+ }
+
+ } else if (action.equals(ACTION_GET_SERVER_INFO)) {
+ // check OC server and get basic information from it
+ operation = new GetServerInfoOperation(serverUrl, OperationsService.this);
+
+ } else if (action.equals(ACTION_OAUTH2_GET_ACCESS_TOKEN)) {
+ /// GET ACCESS TOKEN to the OAuth server
+ String oauth2QueryParameters =
+ operationIntent.getStringExtra(EXTRA_OAUTH2_QUERY_PARAMETERS);
+ operation = new OAuth2GetAccessToken(
+ getString(R.string.oauth2_client_id),
+ getString(R.string.oauth2_redirect_uri),
+ getString(R.string.oauth2_grant_type),
+ oauth2QueryParameters);
+
+ } else if (action.equals(ACTION_GET_USER_NAME)) {
+ // Get User Name
+ operation = new GetRemoteUserNameOperation();
+
+ } else if (action.equals(ACTION_RENAME)) {
+ // Rename file or folder
+ String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+ String newName = operationIntent.getStringExtra(EXTRA_NEWNAME);
+ operation = new RenameFileOperation(remotePath, newName);
+
+ } else if (action.equals(ACTION_REMOVE)) {
+ // Remove file or folder
+ String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+ boolean onlyLocalCopy = operationIntent.getBooleanExtra(EXTRA_REMOVE_ONLY_LOCAL,
+ false);
+ operation = new RemoveFileOperation(remotePath, onlyLocalCopy);
+
+ } else if (action.equals(ACTION_CREATE_FOLDER)) {
+ // Create Folder
+ String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+ boolean createFullPath = operationIntent.getBooleanExtra(EXTRA_CREATE_FULL_PATH,
+ true);
+ operation = new CreateFolderOperation(remotePath, createFullPath);
+
+ } else if (action.equals(ACTION_SYNC_FILE)) {
+ // Sync file
+ String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+ boolean syncFileContents =
+ operationIntent.getBooleanExtra(EXTRA_SYNC_FILE_CONTENTS, true);
+ operation = new SynchronizeFileOperation(
+ remotePath, account, syncFileContents, getApplicationContext()
+ );
+
+ } else if (action.equals(ACTION_SYNC_FOLDER)) {
+ // Sync file
+ String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+ operation = new SynchronizeFolderOperation(
+ this, // TODO remove this dependency from construction time
+ remotePath,
+ account,
+ System.currentTimeMillis() // TODO remove this dependency from construction time
+ );
+
+ } else if (action.equals(ACTION_MOVE_FILE)) {
+ // Move file/folder
+ String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+ String newParentPath = operationIntent.getStringExtra(EXTRA_NEW_PARENT_PATH);
+ operation = new MoveFileOperation(remotePath,newParentPath,account);
+ }
+
+ }
+
+ } catch (IllegalArgumentException e) {
+ Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage());
+ operation = null;
+ }
+
+ if (operation != null) {
+ return new Pair<Target , RemoteOperation>(target, operation);
+ } else {
+ return null;
+ }
+ }
+
/**
* Sends a broadcast when a new operation is added to the queue.
*
- * Local broadcasts are only delivered to activities in the same process, but can't be done sticky :\
+ * Local broadcasts are only delivered to activities in the same process, but can't be
+ * done sticky :\
*
* @param target Account or URL pointing to an OC server.
* @param operation Added operation.
// TODO - maybe add a notification for real start of operations
/**
- * Sends a LOCAL broadcast when an operations finishes in order to the interested activities can update their view
+ * Sends a LOCAL broadcast when an operations finishes in order to the interested activities c
+ * an update their view
*
* Local broadcasts are only delivered to activities in the same process.
*
* @param operation Finished operation.
* @param result Result of the operation.
*/
- private void sendBroadcastOperationFinished(Target target, RemoteOperation operation, RemoteOperationResult result) {
+ private void sendBroadcastOperationFinished(Target target, RemoteOperation operation,
+ RemoteOperationResult result) {
Intent intent = new Intent(ACTION_OPERATION_FINISHED);
intent.putExtra(EXTRA_RESULT, result);
if (target.mAccount != null) {
/**
* Notifies the currently subscribed listeners about the end of an operation.
- *
- * @param target Account or URL pointing to an OC server.
+ *
* @param operation Finished operation.
* @param result Result of the operation.
*/
- private void dispatchResultToOperationListeners(
- Target target, final RemoteOperation operation, final RemoteOperationResult result) {
+ protected void dispatchResultToOperationListeners(
+ final RemoteOperation operation, final RemoteOperationResult result
+ ) {
int count = 0;
- Iterator<OnRemoteOperationListener> listeners = mBinder.mBoundListeners.keySet().iterator();
+ Iterator<OnRemoteOperationListener> listeners =
+ mOperationsBinder.mBoundListeners.keySet().iterator();
while (listeners.hasNext()) {
final OnRemoteOperationListener listener = listeners.next();
- final Handler handler = mBinder.mBoundListeners.get(listener);
+ final Handler handler = mOperationsBinder.mBoundListeners.get(listener);
if (handler != null) {
handler.post(new Runnable() {
@Override
}
Log_OC.d(TAG, "Called " + count + " listeners");
}
-
-
}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.services;
+
+import android.accounts.Account;
+import android.accounts.AccountsException;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Pair;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.IndexedForest;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.operations.SynchronizeFolderOperation;
+import com.owncloud.android.utils.FileStorageUtils;
+
+import java.io.IOException;
+
+/**
+ * SyncFolder worker. Performs the pending operations in the order they were requested.
+ *
+ * Created with the Looper of a new thread, started in
+ * {@link com.owncloud.android.services.OperationsService#onCreate()}.
+ */
+class SyncFolderHandler extends Handler {
+
+ private static final String TAG = SyncFolderHandler.class.getSimpleName();
+
+
+ OperationsService mService;
+
+ private IndexedForest<SynchronizeFolderOperation> mPendingOperations =
+ new IndexedForest<SynchronizeFolderOperation>();
+
+ private OwnCloudClient mOwnCloudClient = null;
+ private Account mCurrentAccount = null;
+ private FileDataStorageManager mStorageManager;
+ private SynchronizeFolderOperation mCurrentSyncOperation;
+
+
+ public SyncFolderHandler(Looper looper, OperationsService service) {
+ super(looper);
+ if (service == null) {
+ throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
+ }
+ mService = service;
+ }
+
+
+ /**
+ * Returns True when the folder located in 'remotePath' in the ownCloud account 'account', or any of its
+ * descendants, is being synchronized (or waiting for it).
+ *
+ * @param account ownCloud account where the remote folder is stored.
+ * @param remotePath The path to a folder that could be in the queue of synchronizations.
+ */
+ public boolean isSynchronizing(Account account, String remotePath) {
+ if (account == null || remotePath == null) return false;
+ return (mPendingOperations.contains(account, remotePath));
+ }
+
+
+ @Override
+ public void handleMessage(Message msg) {
+ Pair<Account, String> itemSyncKey = (Pair<Account, String>) msg.obj;
+ doOperation(itemSyncKey.first, itemSyncKey.second);
+ Log_OC.d(TAG, "Stopping after command with id " + msg.arg1);
+ mService.stopSelf(msg.arg1);
+ }
+
+
+ /**
+ * Performs the next operation in the queue
+ */
+ private void doOperation(Account account, String remotePath) {
+
+ mCurrentSyncOperation = mPendingOperations.get(account, remotePath);
+
+ if (mCurrentSyncOperation != null) {
+ RemoteOperationResult result = null;
+
+ try {
+
+ if (mCurrentAccount == null || !mCurrentAccount.equals(account)) {
+ mCurrentAccount = account;
+ mStorageManager = new FileDataStorageManager(
+ account,
+ mService.getContentResolver()
+ );
+ } // else, reuse storage manager from previous operation
+
+ // always get client from client manager, to get fresh credentials in case of update
+ OwnCloudAccount ocAccount = new OwnCloudAccount(account, mService);
+ mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+ getClientFor(ocAccount, mService);
+
+ result = mCurrentSyncOperation.execute(mOwnCloudClient, mStorageManager);
+
+ } catch (AccountsException e) {
+ Log_OC.e(TAG, "Error while trying to get authorization", e);
+ } catch (IOException e) {
+ Log_OC.e(TAG, "Error while trying to get authorization", e);
+ } finally {
+ mPendingOperations.removePayload(account, remotePath);
+
+ mService.dispatchResultToOperationListeners(mCurrentSyncOperation, result);
+
+ sendBroadcastFinishedSyncFolder(account, remotePath, result.isSuccess());
+ }
+ }
+ }
+
+ public void add(Account account, String remotePath,
+ SynchronizeFolderOperation syncFolderOperation){
+ mPendingOperations.putIfAbsent(account, remotePath, syncFolderOperation);
+ sendBroadcastNewSyncFolder(account, remotePath); // TODO upgrade!
+ }
+
+
+ /**
+ * Cancels a pending or current sync' operation.
+ *
+ * @param account ownCloud account where the remote file is stored.
+ * @param file A file in the queue of pending synchronizations
+ */
+ public void cancel(Account account, OCFile file){
+ if (account == null || file == null) {
+ Log_OC.e(TAG, "Cannot cancel with NULL parameters");
+ return;
+ }
+ Pair<SynchronizeFolderOperation, String> removeResult =
+ mPendingOperations.remove(account, file.getRemotePath());
+ SynchronizeFolderOperation synchronization = removeResult.first;
+ if (synchronization != null) {
+ synchronization.cancel();
+ } else {
+ // TODO synchronize?
+ if (mCurrentSyncOperation != null && mCurrentAccount != null &&
+ mCurrentSyncOperation.getRemotePath().startsWith(file.getRemotePath()) &&
+ account.name.equals(mCurrentAccount.name)) {
+ mCurrentSyncOperation.cancel();
+ }
+ }
+
+ //sendBroadcastFinishedSyncFolder(account, file.getRemotePath());
+ }
+
+ /**
+ * TODO review this method when "folder synchronization" replaces "folder download";
+ * this is a fast and ugly patch.
+ */
+ private void sendBroadcastNewSyncFolder(Account account, String remotePath) {
+ Intent added = new Intent(FileDownloader.getDownloadAddedMessage());
+ added.putExtra(FileDownloader.ACCOUNT_NAME, account.name);
+ added.putExtra(FileDownloader.EXTRA_REMOTE_PATH, remotePath);
+ added.putExtra(FileDownloader.EXTRA_FILE_PATH, FileStorageUtils.getSavePath(account.name)
+ + remotePath);
+ mService.sendStickyBroadcast(added);
+ }
+
+ /**
+ * TODO review this method when "folder synchronization" replaces "folder download";
+ * this is a fast and ugly patch.
+ */
+ private void sendBroadcastFinishedSyncFolder(Account account, String remotePath,
+ boolean success) {
+ Intent finished = new Intent(FileDownloader.getDownloadFinishMessage());
+ finished.putExtra(FileDownloader.ACCOUNT_NAME, account.name);
+ finished.putExtra(FileDownloader.EXTRA_REMOTE_PATH, remotePath);
+ finished.putExtra(FileDownloader.EXTRA_FILE_PATH,
+ FileStorageUtils.getSavePath(account.name) + remotePath);
+ finished.putExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, success);
+ mService.sendStickyBroadcast(finished);
+ }
+
+
+}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2014 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* memory. To minimize the impact of this, the service always returns
* Service.START_STICKY, and the later restart of the service is explicitly
* considered in {@link FileObserverService#onStartCommand(Intent, int, int)}.
- *
- * @author David A. Velasco
*/
public class FileObserverService extends Service {
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* The second case requires to monitor the folder parent of the files, since a direct
* {@link FileObserver} on it will not receive more events after the file is deleted to
* be replaced.
- *
- * @author David A. Velasco
*/
public class FolderObserver extends FileObserver {
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
+ * @author sassman\r
+ * @author David A. Velasco\r
* Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
import org.apache.http.HttpResponse;\r
import org.apache.http.client.ClientProtocolException;\r
\r
+import com.owncloud.android.MainApp;\r
import com.owncloud.android.datamodel.FileDataStorageManager;\r
import com.owncloud.android.lib.common.accounts.AccountUtils;\r
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;\r
* resource types, like FileSync, ConcatsSync, CalendarSync, etc..\r
* \r
* Implements the standard {@link AbstractThreadedSyncAdapter}.\r
- * \r
- * @author sassman\r
- * @author David A. Velasco\r
*/\r
public abstract class AbstractOwnCloudSyncAdapter extends\r
AbstractThreadedSyncAdapter {\r
this.setAccountManager(AccountManager.get(context));\r
}\r
\r
- public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {\r
+ public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize,\r
+ boolean allowParallelSyncs) {\r
super(context, autoInitialize, allowParallelSyncs);\r
this.setAccountManager(AccountManager.get(context));\r
}\r
return mStoreManager;\r
}\r
\r
- protected void initClientForCurrentAccount() throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException {\r
+ protected void initClientForCurrentAccount() throws OperationCanceledException,\r
+ AuthenticatorException, IOException, AccountNotFoundException {\r
AccountUtils.constructFullURLForAccount(getContext(), account);\r
OwnCloudAccount ocAccount = new OwnCloudAccount(account, getContext());\r
mClient = OwnCloudClientManagerFactory.getDefaultSingleton().\r
+++ /dev/null
-/* ownCloud Android client application
- * Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.syncadapter;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-
-import org.apache.http.client.methods.HttpPut;
-import org.apache.http.entity.ByteArrayEntity;
-
-import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
-
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.content.ContentProviderClient;
-import android.content.Context;
-import android.content.SyncResult;
-import android.content.res.AssetFileDescriptor;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-
-public class ContactSyncAdapter extends AbstractOwnCloudSyncAdapter {
- private String mAddrBookUri;
-
- public ContactSyncAdapter(Context context, boolean autoInitialize) {
- super(context, autoInitialize);
- mAddrBookUri = null;
- }
-
- @Override
- public void onPerformSync(Account account, Bundle extras, String authority,
- ContentProviderClient provider, SyncResult syncResult) {
- setAccount(account);
- setContentProviderClient(provider);
- Cursor c = getLocalContacts(false);
- if (c.moveToFirst()) {
- do {
- String lookup = c.getString(c
- .getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
- String a = getAddressBookUri();
- String uri = a + lookup + ".vcf";
- FileInputStream f;
- try {
- f = getContactVcard(lookup);
- HttpPut query = new HttpPut(uri);
- byte[] b = new byte[f.available()];
- f.read(b);
- query.setEntity(new ByteArrayEntity(b));
- fireRawRequest(query);
- } catch (IOException e) {
- e.printStackTrace();
- return;
- } catch (OperationCanceledException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (AuthenticatorException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- } while (c.moveToNext());
- // } while (c.moveToNext());
- }
-
- }
-
- private String getAddressBookUri() {
- if (mAddrBookUri != null)
- return mAddrBookUri;
-
- AccountManager am = getAccountManager();
- @SuppressWarnings("deprecation")
- String uri = am.getUserData(getAccount(),
- Constants.KEY_OC_URL).replace(
- AccountUtils.WEBDAV_PATH_2_0, AccountUtils.CARDDAV_PATH_2_0);
- uri += "/addressbooks/"
- + getAccount().name.substring(0,
- getAccount().name.lastIndexOf('@')) + "/default/";
- mAddrBookUri = uri;
- return uri;
- }
-
- private FileInputStream getContactVcard(String lookupKey)
- throws IOException {
- Uri uri = Uri.withAppendedPath(
- ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
- AssetFileDescriptor fd = getContext().getContentResolver()
- .openAssetFileDescriptor(uri, "r");
- return fd.createInputStream();
- }
-
- private Cursor getLocalContacts(boolean include_hidden_contacts) {
- return getContext().getContentResolver().query(
- ContactsContract.Contacts.CONTENT_URI,
- new String[] { ContactsContract.Contacts._ID,
- ContactsContract.Contacts.LOOKUP_KEY },
- ContactsContract.Contacts.IN_VISIBLE_GROUP + " = ?",
- new String[] { (include_hidden_contacts ? "0" : "1") },
- ContactsContract.Contacts._ID + " DESC");
- }
-
-}
+++ /dev/null
-/* ownCloud Android client application
- * Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.syncadapter;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class ContactSyncService extends Service {
- private static final Object syncAdapterLock = new Object();
- private static AbstractOwnCloudSyncAdapter mSyncAdapter = null;
-
- @Override
- public void onCreate() {
- synchronized (syncAdapterLock) {
- if (mSyncAdapter == null) {
- mSyncAdapter = new ContactSyncAdapter(getApplicationContext(),
- true);
- }
- }
- }
-
- @Override
- public IBinder onBind(Intent arg0) {
- return mSyncAdapter.getSyncAdapterBinder();
- }
-
-}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import org.apache.jackrabbit.webdav.DavException;
+import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AuthenticatorActivity;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.operations.SynchronizeFolderOperation;
+import com.owncloud.android.operations.RefreshFolderOperation;
import com.owncloud.android.operations.UpdateOCVersionOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
* Implementation of {@link AbstractThreadedSyncAdapter} responsible for synchronizing
* ownCloud files.
*
- * Performs a full synchronization of the account recieved in {@link #onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult)}.
- *
- * @author Bartek Przybylski
- * @author David A. Velasco
+ * Performs a full synchronization of the account recieved in {@link #onPerformSync(Account, Bundle,
+ * String, ContentProviderClient, SyncResult)}.
*/
public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
private final static String TAG = FileSyncAdapter.class.getSimpleName();
- /** Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation */
+ /** Maximum number of failed folder synchronizations that are supported before finishing
+ * the synchronization operation */
private static final int MAX_FAILED_RESULTS = 3;
- public static final String EVENT_FULL_SYNC_START = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_START";
- public static final String EVENT_FULL_SYNC_END = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_END";
- public static final String EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED";
- //public static final String EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED";
+ public static final String EVENT_FULL_SYNC_START = FileSyncAdapter.class.getName() +
+ ".EVENT_FULL_SYNC_START";
+ public static final String EVENT_FULL_SYNC_END = FileSyncAdapter.class.getName() +
+ ".EVENT_FULL_SYNC_END";
+ public static final String EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED =
+ FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED";
+ //public static final String EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED =
+ // FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED";
- public static final String EXTRA_ACCOUNT_NAME = FileSyncAdapter.class.getName() + ".EXTRA_ACCOUNT_NAME";
- public static final String EXTRA_FOLDER_PATH = FileSyncAdapter.class.getName() + ".EXTRA_FOLDER_PATH";
+ public static final String EXTRA_ACCOUNT_NAME = FileSyncAdapter.class.getName() +
+ ".EXTRA_ACCOUNT_NAME";
+ public static final String EXTRA_FOLDER_PATH = FileSyncAdapter.class.getName() +
+ ".EXTRA_FOLDER_PATH";
public static final String EXTRA_RESULT = FileSyncAdapter.class.getName() + ".EXTRA_RESULT";
/** Flag made 'true' when a request to cancel the synchronization is received */
private boolean mCancellation;
- /** When 'true' the process was requested by the user through the user interface; when 'false', it was requested automatically by the system */
+ /** When 'true' the process was requested by the user through the user interface;
+ * when 'false', it was requested automatically by the system */
private boolean mIsManualSync;
/** Counter for failed operations in the synchronization process */
/** Counter of failed operations in synchronization of kept-in-sync files */
private int mFailsInFavouritesFound;
- /** Map of remote and local paths to files that where locally stored in a location out of the ownCloud folder and couldn't be copied automatically into it */
+ /** Map of remote and local paths to files that where locally stored in a location out
+ * of the ownCloud folder and couldn't be copied automatically into it */
private Map<String, String> mForgottenLocalFiles;
/** {@link SyncResult} instance to return to the system when the synchronization finish */
try {
this.initClientForCurrentAccount();
} catch (IOException e) {
- /// the account is unknown for the Synchronization Manager, unreachable this context, or can not be authenticated; don't try this again
+ /// the account is unknown for the Synchronization Manager, unreachable this context,
+ // or can not be authenticated; don't try this again
mSyncResult.tooManyRetries = true;
notifyFailedSynchronization();
return;
} catch (AccountsException e) {
- /// the account is unknown for the Synchronization Manager, unreachable this context, or can not be authenticated; don't try this again
+ /// the account is unknown for the Synchronization Manager, unreachable this context,
+ // or can not be authenticated; don't try this again
mSyncResult.tooManyRetries = true;
notifyFailedSynchronization();
return;
}
Log_OC.d(TAG, "Synchronization of ownCloud account " + account.name + " starting");
- sendLocalBroadcast(EVENT_FULL_SYNC_START, null, null); // message to signal the start of the synchronization to the UI
+ sendLocalBroadcast(EVENT_FULL_SYNC_START, null, null); // message to signal the start
+ // of the synchronization to the UI
try {
updateOCVersion();
synchronizeFolder(getStorageManager().getFileByPath(OCFile.ROOT_PATH));
} else {
- Log_OC.d(TAG, "Leaving synchronization before synchronizing the root folder because cancelation request");
+ Log_OC.d(TAG, "Leaving synchronization before synchronizing the root folder " +
+ "because cancelation request");
}
} finally {
- // it's important making this although very unexpected errors occur; that's the reason for the finally
+ // it's important making this although very unexpected errors occur;
+ // that's the reason for the finally
if (mFailedResultsCounter > 0 && mIsManualSync) {
/// don't let the system synchronization manager retries MANUAL synchronizations
- // (be careful: "MANUAL" currently includes the synchronization requested when a new account is created and when the user changes the current account)
+ // (be careful: "MANUAL" currently includes the synchronization requested when
+ // a new account is created and when the user changes the current account)
mSyncResult.tooManyRetries = true;
/// notify the user about the failure of MANUAL synchronization
if (mForgottenLocalFiles.size() > 0) {
notifyForgottenLocalFiles();
}
- sendLocalBroadcast(EVENT_FULL_SYNC_END, null, mLastFailedResult); // message to signal the end to the UI
+ sendLocalBroadcast(EVENT_FULL_SYNC_END, null, mLastFailedResult); // message to signal
+ // the end to the UI
}
}
* locally saved.
*
* See {@link #onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult)}
- * and {@link #synchronizeFolder(String, long)}.
+ * and {@link #synchronizeFolder(OCFile)}.
*/
@Override
public void onSyncCanceled() {
}
*/
// folder synchronization
- SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( folder,
- mCurrentSyncTime,
- true,
- mIsShareSupported,
- false,
- getStorageManager(),
- getAccount(),
- getContext()
+ RefreshFolderOperation synchFolderOp = new RefreshFolderOperation( folder,
+ mCurrentSyncTime,
+ true,
+ mIsShareSupported,
+ false,
+ getStorageManager(),
+ getAccount(),
+ getContext()
);
RemoteOperationResult result = synchFolderOp.execute(getClient());
if (result.isSuccess()) {
// synchronize children folders
List<OCFile> children = synchFolderOp.getChildren();
- fetchChildren(folder, children, synchFolderOp.getRemoteFolderChanged()); // beware of the 'hidden' recursion here!
+ // beware of the 'hidden' recursion here!
+ fetchChildren(folder, children, synchFolderOp.getRemoteFolderChanged());
}
} else {
}
/**
- * Checks if a failed result should terminate the synchronization process immediately, according to
- * OUR OWN POLICY
+ * Checks if a failed result should terminate the synchronization process immediately,
+ * according to OUR OWN POLICY
*
* @param failedResult Remote operation result to check.
- * @return 'True' if the result should immediately finish the synchronization
+ * @return 'True' if the result should immediately finish the
+ * synchronization
*/
private boolean isFinisher(RemoteOperationResult failedResult) {
if (failedResult != null) {
syncDown = (parentEtagChanged || etag == null || etag.length() == 0);
if(syncDown) { */
synchronizeFolder(newFile);
- //sendLocalBroadcast(EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED, parent.getRemotePath(), null);
+ //sendLocalBroadcast(EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED, parent.getRemotePath(),
+ // null);
//}
}
}
- if (mCancellation && i <files.size()) Log_OC.d(TAG, "Leaving synchronization before synchronizing " + files.get(i).getRemotePath() + " due to cancelation request");
+ if (mCancellation && i <files.size()) Log_OC.d(TAG,
+ "Leaving synchronization before synchronizing " + files.get(i).getRemotePath() +
+ " due to cancelation request");
}
/**
- * Sends a message to any application component interested in the progress of the synchronization.
+ * Sends a message to any application component interested in the progress of the
+ * synchronization.
*
* @param event Event in the process of synchronization to be notified.
* @param dirRemotePath Remote path of the folder target of the event occurred.
- * @param result Result of an individual {@ SynchronizeFolderOperation}, if completed; may be null.
+ * @param result Result of an individual {@ SynchronizeFolderOperation},
+ * if completed; may be null.
*/
- private void sendLocalBroadcast(String event, String dirRemotePath, RemoteOperationResult result) {
+ private void sendLocalBroadcast(String event, String dirRemotePath,
+ RemoteOperationResult result) {
Log_OC.d(TAG, "Send broadcast " + event);
Intent intent = new Intent(event);
intent.putExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME, getAccount().name);
// let the user update credentials with one click
Intent updateAccountCredentials = new Intent(getContext(), AuthenticatorActivity.class);
updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());
- updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
+ updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION,
+ AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
.setTicker(i18n(R.string.sync_fail_ticker_unauthorized))
.setContentTitle(i18n(R.string.sync_fail_ticker_unauthorized))
.setContentIntent(PendingIntent.getActivity(
- getContext(), (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT
+ getContext(), (int)System.currentTimeMillis(), updateAccountCredentials,
+ PendingIntent.FLAG_ONE_SHOT
))
.setContentText(i18n(R.string.sync_fail_content_unauthorized, getAccount().name));
} else {
/**
- * Notifies the user about conflicts and strange fails when trying to synchronize the contents of kept-in-sync files.
+ * Notifies the user about conflicts and strange fails when trying to synchronize the contents
+ * of kept-in-sync files.
*
* By now, we won't consider a failed synchronization.
*/
getContext(), (int) System.currentTimeMillis(), new Intent(), 0
))
.setContentTitle(i18n(R.string.sync_fail_in_favourites_ticker))
- .setContentText(i18n(R.string.sync_fail_in_favourites_content, mFailedResultsCounter + mConflictsFound, mConflictsFound));
+ .setContentText(i18n(R.string.sync_fail_in_favourites_content,
+ mFailedResultsCounter + mConflictsFound, mConflictsFound));
showNotification(R.string.sync_fail_in_favourites_ticker, notificationBuilder);
} else {
}
/**
- * Notifies the user about local copies of files out of the ownCloud local directory that were 'forgotten' because
- * copying them inside the ownCloud local directory was not possible.
+ * Notifies the user about local copies of files out of the ownCloud local directory that
+ * were 'forgotten' because copying them inside the ownCloud local directory was not possible.
*
- * We don't want links to files out of the ownCloud local directory (foreign files) anymore. It's easy to have
- * synchronization problems if a local file is linked to more than one remote file.
+ * We don't want links to files out of the ownCloud local directory (foreign files) anymore.
+ * It's easy to have synchronization problems if a local file is linked to more than one
+ * remote file.
*
- * We won't consider a synchronization as failed when foreign files can not be copied to the ownCloud local directory.
+ * We won't consider a synchronization as failed when foreign files can not be copied to
+ * the ownCloud local directory.
*/
private void notifyForgottenLocalFiles() {
NotificationCompat.Builder notificationBuilder = createNotificationBuilder();
getContext(), (int) System.currentTimeMillis(), explanationIntent, 0
))
.setContentTitle(i18n(R.string.sync_foreign_files_forgotten_ticker))
- .setContentText(i18n(R.string.sync_foreign_files_forgotten_content, mForgottenLocalFiles.size(), i18n(R.string.app_name)));
+ .setContentText(i18n(R.string.sync_foreign_files_forgotten_content,
+ mForgottenLocalFiles.size(), i18n(R.string.app_name)));
showNotification(R.string.sync_foreign_files_forgotten_ticker, notificationBuilder);
}
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
+ * @author Bartek Przybylski\r
+ * @author David A. Velasco\r
* Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
/**\r
* Background service for synchronizing remote files with their local state.\r
* \r
- * Serves as a connector to an instance of {@link FileSyncAdapter}, as required by standard Android APIs. \r
- * \r
- * @author Bartek Przybylski\r
- * @author David A. Velasco\r
+ * Serves as a connector to an instance of {@link FileSyncAdapter}, as required by standard Android APIs.\r
*/\r
public class FileSyncService extends Service {\r
\r
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
+ * @author Bartek Przybylski\r
* Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
\r
/**\r
* Represents an Item on the ActionBar.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
*/\r
public class ActionItem {\r
private Drawable mIcon;\r
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2014 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
+ * @author Lorensius. W. T\r
* Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
\r
/**\r
* Represents a custom PopupWindows\r
- * \r
- * @author Lorensius. W. T\r
- * \r
*/\r
public class CustomPopup {\r
protected final View mAnchor;\r
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2012-2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.util.AttributeSet;
import android.widget.ListView;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
/**
* ListView allowing to specify the position of an item that should be centered in the visible area, if possible.
- *
- * The cleanest way I found to overcome the problem due to getHeight() returns 0 until the view is really drawn.
- *
- * @author David A. Velasco
+ *
+ * The cleanest way I found to overcome the problem due to getHeight() returns 0 until the view is really drawn.
*/
public class ExtendedListView extends ListView {
- private int mPositionToSetAndCenter;
+ private static final String TAG = ExtendedListView.class.getSimpleName();
+
+ private int mPositionToSetAndCenter = 0;
public ExtendedListView(Context context) {
super(context);
/**
* {@inheritDoc}
- *
- *
+ *
+ *
*/
@Override
protected void onDraw (Canvas canvas) {
super.onDraw(canvas);
if (mPositionToSetAndCenter > 0) {
+ Log_OC.v(TAG, "Centering around position " + mPositionToSetAndCenter);
this.setSelectionFromTop(mPositionToSetAndCenter, getHeight() / 2);
mPositionToSetAndCenter = 0;
}
}
-
+
/**
* Public method to set the position of the item that should be centered in the visible area of the view.
- *
+ *
* The position is saved here and checked in onDraw().
- *
+ *
* @param position Position (in the list of items) of the item to center in the visible area.
*/
public void setAndCenterSelection(int position) {
mPositionToSetAndCenter = position;
}
-}
+
+}
\ No newline at end of file
+++ /dev/null
-package com.owncloud.android.ui;
-
-import android.content.Context;
-import android.preference.CheckBoxPreference;
-import android.view.View;
-
-public class LongClickableCheckBoxPreference extends CheckBoxPreference implements View.OnLongClickListener {
-
- public LongClickableCheckBoxPreference(Context context) {
- super(context);
- }
-
- @Override
- public boolean onLongClick(View v) {
- return true;
- }
-}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui;
+
+public class NavigationDrawerItem {
+
+ private String mTitle;
+ private String mContentDescription;
+
+ // Constructors
+ public NavigationDrawerItem(){}
+
+ public NavigationDrawerItem(String title){
+ mTitle = title;
+ }
+
+ public NavigationDrawerItem(String title, String contentDescription){
+ mTitle = title;
+ mContentDescription = contentDescription;
+ }
+
+ // Getters and Setters
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public void setTitle(String title) {
+ this.mTitle = title;
+ }
+
+ public String getContentDescription() {
+ return mContentDescription;
+ }
+
+ public void setContentDescription(String contentDescription) {
+ this.mContentDescription = contentDescription;
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2014 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+import android.preference.Preference;
+
+public class PreferenceWithLongSummary extends Preference{
+
+ public PreferenceWithLongSummary(Context context) {
+ super(context);
+ }
+
+ public PreferenceWithLongSummary(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ public PreferenceWithLongSummary(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+ TextView titleView = (TextView) view.findViewById(android.R.id.summary);
+ titleView.setSingleLine(true);
+ titleView.setMaxLines(1);
+ titleView.setEllipsize(TextUtils.TruncateAt.MIDDLE);
+ }
+}
\ No newline at end of file
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
+ * @author Lorensius. W. T\r
* Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
/**\r
* Popup window, shows action list as icon and text like the one in Gallery3D\r
* app.\r
- * \r
- * @author Lorensius. W. T\r
*/\r
public class QuickAction extends CustomPopup {\r
private final View root;\r
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui;
+
+import android.content.Context;
+import android.preference.CheckBoxPreference;
+import android.view.View;
+
+import com.owncloud.android.R;
+
+public class RadioButtonPreference extends CheckBoxPreference implements View.OnLongClickListener {
+
+ public RadioButtonPreference(Context context) {
+ super(context, null, android.R.attr.checkBoxPreferenceStyle);
+ setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ return true;
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+public class SquareImageView extends ImageView {
+
+ public SquareImageView(Context context) {
+ super(context);
+ }
+
+ public SquareImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SquareImageView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+ }
+}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+public class SquareLinearLayout extends LinearLayout {
+
+ public SquareLinearLayout(Context context) {
+ super(context);
+ }
+
+ public SquareLinearLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SquareLinearLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+ }
+}
--- /dev/null
+package com.owncloud.android.ui;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Created by tobi on 24.05.15.
+ */
+public class TextDrawable extends Drawable {
+
+ private final String text;
+ private final Paint paint;
+ private final Paint bg;
+
+ public TextDrawable(String text, int r, int g, int b) {
+
+ this.text = text;
+ Integer color = Color.rgb(r, g, b);
+
+ bg = new Paint();
+ bg.setStyle(Paint.Style.FILL);
+ bg.setColor(color);
+
+ paint = new Paint();
+ paint.setColor(Color.WHITE);
+ paint.setTextSize(20);
+ paint.setAntiAlias(true);
+ paint.setFakeBoldText(true);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawRect(0,-20,20,40,bg);
+ canvas.drawText(text, 4, 6, paint);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ paint.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ paint.setColorFilter(cf);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import com.owncloud.android.files.FileOperationsHelper;
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
public interface ComponentsGetter {
/**
- * Callback method invoked when the parent activity is fully created to get a reference to the FileDownloader service API.
- *
- * @return Directory to list firstly. Can be NULL.
+ * To be invoked when the parent activity is fully created to get a reference to the FileDownloader service API.
*/
public FileDownloaderBinder getFileDownloaderBinder();
/**
- * Callback method invoked when the parent activity is fully created to get a reference to the FileUploader service API.
- *
- * @return Directory to list firstly. Can be NULL.
+ * To be invoked when the parent activity is fully created to get a reference to the FileUploader service API.
*/
public FileUploaderBinder getFileUploaderBinder();
+ /**
+ * To be invoked when the parent activity is fully created to get a reference to the OperationsSerivce service API.
+ */
+ public OperationsServiceBinder getOperationsServiceBinder();
+
public FileDataStorageManager getStorageManager();
public FileOperationsHelper getFileOperationsHelper();
+
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author David A. Velasco
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.ui.activity;
-import com.actionbarsherlock.app.ActionBar;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener;
import com.owncloud.android.utils.DisplayUtils;
+import android.app.ActionBar;
import android.content.Intent;
import android.os.Bundle;
/**
* Wrapper activity which will be launched if keep-in-sync file will be modified by external
- * application.
- *
- * @author Bartek Przybylski
- * @author David A. Velasco
+ * application.
*/
public class ConflictsResolveActivity extends FileActivity implements OnConflictDecisionMadeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- ActionBar actionBar = getSupportActionBar();
+ ActionBar actionBar = getActionBar();
actionBar.setIcon(DisplayUtils.getSeasonalIconId());
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* Activity copying the text of the received Intent into the system clibpoard.
- *
- * @author David A. Velasco
*/
@SuppressWarnings("deprecation")
public class CopyToClipboardActivity extends Activity {
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.DialogFragment;
+import android.support.v7.app.ActionBarActivity;
import android.text.method.ScrollingMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
-import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
/**
- * Activity reporting errors occurred when local files uploaded to an ownCloud account with an app in
- * version under 1.3.16 where being copied to the ownCloud local folder.
+ * Activity reporting errors occurred when local files uploaded to an ownCloud account with an app
+ * in version under 1.3.16 where being copied to the ownCloud local folder.
*
* Allows the user move the files to the ownCloud local folder. let them unlinked to the remote
* files.
*
* Shown when the error notification summarizing the list of errors is clicked by the user.
- *
- * @author David A. Velasco
*/
-public class ErrorsWhileCopyingHandlerActivity extends SherlockFragmentActivity implements OnClickListener {
+public class ErrorsWhileCopyingHandlerActivity extends ActionBarActivity
+ implements OnClickListener {
private static final String TAG = ErrorsWhileCopyingHandlerActivity.class.getSimpleName();
- public static final String EXTRA_ACCOUNT = ErrorsWhileCopyingHandlerActivity.class.getCanonicalName() + ".EXTRA_ACCOUNT";
- public static final String EXTRA_LOCAL_PATHS = ErrorsWhileCopyingHandlerActivity.class.getCanonicalName() + ".EXTRA_LOCAL_PATHS";
- public static final String EXTRA_REMOTE_PATHS = ErrorsWhileCopyingHandlerActivity.class.getCanonicalName() + ".EXTRA_REMOTE_PATHS";
+ public static final String EXTRA_ACCOUNT =
+ ErrorsWhileCopyingHandlerActivity.class.getCanonicalName() + ".EXTRA_ACCOUNT";
+ public static final String EXTRA_LOCAL_PATHS =
+ ErrorsWhileCopyingHandlerActivity.class.getCanonicalName() + ".EXTRA_LOCAL_PATHS";
+ public static final String EXTRA_REMOTE_PATHS =
+ ErrorsWhileCopyingHandlerActivity.class.getCanonicalName() + ".EXTRA_REMOTE_PATHS";
private static final String WAIT_DIALOG_TAG = "WAIT_DIALOG";
/// customize text message
TextView textView = (TextView) findViewById(R.id.message);
String appName = getString(R.string.app_name);
- String message = String.format(getString(R.string.sync_foreign_files_forgotten_explanation), appName, appName, appName, appName, mAccount.name);
+ String message = String.format(getString(R.string.sync_foreign_files_forgotten_explanation),
+ appName, appName, appName, appName, mAccount.name);
textView.setText(message);
textView.setMovementMethod(new ScrollingMovementMethod());
/**
- * Customized adapter, showing the local files as main text in two-lines list item and the remote files
- * as the secondary text.
- *
- * @author David A. Velasco
+ * Customized adapter, showing the local files as main text in two-lines list item and the
+ * remote files as the secondary text.
*/
public class ErrorsWhileCopyingListAdapter extends ArrayAdapter<String> {
ErrorsWhileCopyingListAdapter() {
- super(ErrorsWhileCopyingHandlerActivity.this, android.R.layout.two_line_list_item, android.R.id.text1, mLocalPaths);
+ super(ErrorsWhileCopyingHandlerActivity.this, android.R.layout.two_line_list_item,
+ android.R.id.text1, mLocalPaths);
}
@Override
public View getView (int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
- LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater vi = (LayoutInflater) getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(android.R.layout.two_line_list_item, null);
}
if (view != null) {
text1.setText(String.format(getString(R.string.foreign_files_local_text), localPath));
}
}
- if (mRemotePaths != null && mRemotePaths.size() > 0 && position >= 0 && position < mRemotePaths.size()) {
+ if (mRemotePaths != null && mRemotePaths.size() > 0 && position >= 0 &&
+ position < mRemotePaths.size()) {
TextView text2 = (TextView) view.findViewById(android.R.id.text2);
String remotePath = mRemotePaths.get(position);
if (text2 != null && remotePath != null) {
/**
* Asynchronous task performing the move of all the local files to the ownCloud folder.
- *
- * @author David A. Velasco
*/
private class MoveFilesTask extends AsyncTask<Void, Void, Boolean> {
if (result) {
// nothing else to do in this activity
- Toast t = Toast.makeText(ErrorsWhileCopyingHandlerActivity.this, getString(R.string.foreign_files_success), Toast.LENGTH_LONG);
+ Toast t = Toast.makeText(ErrorsWhileCopyingHandlerActivity.this,
+ getString(R.string.foreign_files_success), Toast.LENGTH_LONG);
t.show();
finish();
} else {
- Toast t = Toast.makeText(ErrorsWhileCopyingHandlerActivity.this, getString(R.string.foreign_files_fail), Toast.LENGTH_LONG);
+ Toast t = Toast.makeText(ErrorsWhileCopyingHandlerActivity.this,
+ getString(R.string.foreign_files_fail), Toast.LENGTH_LONG);
t.show();
}
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2014 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
import android.widget.Toast;
-import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.owncloud.android.BuildConfig;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.FileOperationsHelper;
import com.owncloud.android.files.services.FileDownloader;
-import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.SynchronizeFolderOperation;
import com.owncloud.android.operations.UnshareLinkOperation;
-
import com.owncloud.android.services.OperationsService;
import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
+import com.owncloud.android.ui.NavigationDrawerItem;
+import com.owncloud.android.ui.adapter.NavigationDrawerListAdapter;
import com.owncloud.android.ui.dialog.LoadingDialog;
+import com.owncloud.android.ui.dialog.SharePasswordDialogFragment;
import com.owncloud.android.utils.ErrorMessageAdapter;
+import java.util.ArrayList;
+
/**
- * Activity with common behaviour for activities handling {@link OCFile}s in ownCloud {@link Account}s .
- *
- * @author David A. Velasco
+ * Activity with common behaviour for activities handling {@link OCFile}s in ownCloud
+ * {@link Account}s .
*/
-public class FileActivity extends SherlockFragmentActivity
-implements OnRemoteOperationListener, ComponentsGetter {
+public class FileActivity extends ActionBarActivity
+ implements OnRemoteOperationListener, ComponentsGetter {
public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE";
public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT";
- public static final String EXTRA_WAITING_TO_PREVIEW = "com.owncloud.android.ui.activity.WAITING_TO_PREVIEW";
- public static final String EXTRA_FROM_NOTIFICATION= "com.owncloud.android.ui.activity.FROM_NOTIFICATION";
+ public static final String EXTRA_WAITING_TO_PREVIEW =
+ "com.owncloud.android.ui.activity.WAITING_TO_PREVIEW";
+ public static final String EXTRA_FROM_NOTIFICATION =
+ "com.owncloud.android.ui.activity.FROM_NOTIFICATION";
public static final String TAG = FileActivity.class.getSimpleName();
private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
- private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";;
+ private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";
+ private static final String DIALOG_SHARE_PASSWORD = "DIALOG_SHARE_PASSWORD";
+ private static final String KEY_TRY_SHARE_AGAIN = "TRY_SHARE_AGAIN";
+ private static final String KEY_ACTION_BAR_TITLE = "ACTION_BAR_TITLE";
protected static final long DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS = 200;
- /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */
+ /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located.*/
private Account mAccount;
/** Main {@link OCFile} handled by the activity.*/
private OCFile mFile;
- /** Flag to signal that the activity will is finishing to enforce the creation of an ownCloud {@link Account} */
+ /** Flag to signal that the activity will is finishing to enforce the creation of an ownCloud
+ * {@link Account} */
private boolean mRedirectingToSetupAccount = false;
/** Flag to signal when the value of mAccount was set */
- private boolean mAccountWasSet;
+ protected boolean mAccountWasSet;
/** Flag to signal when the value of mAccount was restored from a saved state */
- private boolean mAccountWasRestored;
+ protected boolean mAccountWasRestored;
/** Flag to signal if the activity is launched by a notification */
private boolean mFromNotification;
protected FileDownloaderBinder mDownloaderBinder = null;
protected FileUploaderBinder mUploaderBinder = null;
private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null;
-
+
+ private boolean mTryShareAgain = false;
+
+ // Navigation Drawer
+ protected DrawerLayout mDrawerLayout;
+ protected ActionBarDrawerToggle mDrawerToggle;
+ protected ListView mDrawerList;
+
+ // Slide menu items
+ protected String[] mDrawerTitles;
+ protected String[] mDrawerContentDescriptions;
+
+ protected ArrayList<NavigationDrawerItem> mDrawerItems;
+
+ protected NavigationDrawerListAdapter mNavigationDrawerAdapter = null;
+
+
+ // TODO re-enable when "Accounts" is available in Navigation Drawer
+// protected boolean mShowAccounts = false;
/**
* Loads the ownCloud {@link Account} and main {@link OCFile} to be handled by the instance of
super.onCreate(savedInstanceState);
mHandler = new Handler();
mFileOperationsHelper = new FileOperationsHelper(this);
- Account account;
+ Account account = null;
if(savedInstanceState != null) {
- account = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT);
mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);
mFromNotification = savedInstanceState.getBoolean(FileActivity.EXTRA_FROM_NOTIFICATION);
mFileOperationsHelper.setOpIdWaitingFor(
savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE)
);
+ mTryShareAgain = savedInstanceState.getBoolean(KEY_TRY_SHARE_AGAIN);
+ getSupportActionBar().setTitle(savedInstanceState.getString(KEY_ACTION_BAR_TITLE));
} else {
account = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
- mFromNotification = getIntent().getBooleanExtra(FileActivity.EXTRA_FROM_NOTIFICATION, false);
+ mFromNotification = getIntent().getBooleanExtra(FileActivity.EXTRA_FROM_NOTIFICATION,
+ false);
}
+ AccountUtils.updateAccountVersion(this); // best place, before any access to AccountManager
+ // or database
+
setAccount(account, savedInstanceState != null);
mOperationsServiceConnection = new OperationsServiceConnection();
- bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE);
+ bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection,
+ Context.BIND_AUTO_CREATE);
mDownloadServiceConnection = newTransferenceServiceConnection();
if (mDownloadServiceConnection != null) {
- bindService(new Intent(this, FileDownloader.class), mDownloadServiceConnection, Context.BIND_AUTO_CREATE);
+ bindService(new Intent(this, FileDownloader.class), mDownloadServiceConnection,
+ Context.BIND_AUTO_CREATE);
}
mUploadServiceConnection = newTransferenceServiceConnection();
if (mUploadServiceConnection != null) {
- bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, Context.BIND_AUTO_CREATE);
+ bindService(new Intent(this, FileUploader.class), mUploadServiceConnection,
+ Context.BIND_AUTO_CREATE);
}
-
+
+ }
+
+ @Override
+ protected void onNewIntent (Intent intent) {
+ Log_OC.v(TAG, "onNewIntent() start");
+ Account current = AccountUtils.getCurrentOwnCloudAccount(this);
+ if (current != null && mAccount != null && !mAccount.name.equals(current.name)) {
+ mAccount = current;
+ }
+ Log_OC.v(TAG, "onNewIntent() stop");
}
-
/**
* Since ownCloud {@link Account}s can be managed from the system setting menu,
* the existence of the {@link Account} associated to the instance must be checked
*/
@Override
protected void onRestart() {
+ Log_OC.v(TAG, "onRestart() start");
super.onRestart();
- boolean validAccount = (mAccount != null && AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), mAccount.name));
+ boolean validAccount = (mAccount != null && AccountUtils.exists(mAccount, this));
if (!validAccount) {
swapToDefaultAccount();
}
+ Log_OC.v(TAG, "onRestart() end");
}
if (mOperationsServiceBinder != null) {
doOnResumeAndBound();
}
-
}
@Override
protected void onPause() {
-
if (mOperationsServiceBinder != null) {
mOperationsServiceBinder.removeOperationListener(this);
}
unbindService(mUploadServiceConnection);
mUploadServiceConnection = null;
}
+
super.onDestroy();
}
-
-
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ // Sync the toggle state after onRestoreInstanceState has occurred.
+ if (mDrawerToggle != null) {
+ mDrawerToggle.syncState();
+ if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
+ getSupportActionBar().setTitle(R.string.app_name);
+ mDrawerToggle.setDrawerIndicatorEnabled(true);
+ }
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mDrawerToggle != null) {
+ mDrawerToggle.onConfigurationChanged(newConfig);
+ }
+ }
+
+ protected void initDrawer(){
+ // constant settings for action bar when navigation drawer is inited
+ getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+
+
+ mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+ // Notification Drawer
+ LinearLayout navigationDrawerLayout = (LinearLayout) findViewById(R.id.left_drawer);
+ mDrawerList = (ListView) navigationDrawerLayout.findViewById(R.id.drawer_list);
+
+ // TODO re-enable when "Accounts" is available in Navigation Drawer
+// // load Account in the Drawer Title
+// // User-Icon
+// ImageView userIcon = (ImageView) navigationDrawerLayout.findViewById(R.id.drawer_userIcon);
+// userIcon.setImageResource(DisplayUtils.getSeasonalIconId());
+//
+// // Username
+// TextView username = (TextView) navigationDrawerLayout.findViewById(R.id.drawer_username);
+// Account account = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
+//
+// if (account != null) {
+// int lastAtPos = account.name.lastIndexOf("@");
+// username.setText(account.name.substring(0, lastAtPos));
+// }
+
+ // load slide menu items
+ mDrawerTitles = getResources().getStringArray(R.array.drawer_items);
+
+ // nav drawer content description from resources
+ mDrawerContentDescriptions = getResources().
+ getStringArray(R.array.drawer_content_descriptions);
+
+ // nav drawer items
+ mDrawerItems = new ArrayList<NavigationDrawerItem>();
+ // adding nav drawer items to array
+ // TODO re-enable when "Accounts" is available in Navigation Drawer
+ // Accounts
+ // mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[0],
+ // mDrawerContentDescriptions[0]));
+ // All Files
+ mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[0], mDrawerContentDescriptions[0]));
+
+ // TODO Enable when "On Device" is recovered
+ // On Device
+ //mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[2],
+ // mDrawerContentDescriptions[2]));
+
+ // Settings
+ mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[1], mDrawerContentDescriptions[1]));
+ // Logs
+ if (BuildConfig.DEBUG) {
+ mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[2],
+ mDrawerContentDescriptions[2]));
+ }
+
+ // setting the nav drawer list adapter
+ mNavigationDrawerAdapter = new NavigationDrawerListAdapter(getApplicationContext(), this,
+ mDrawerItems);
+ mDrawerList.setAdapter(mNavigationDrawerAdapter);
+
+ mDrawerToggle = new ActionBarDrawerToggle(
+ this,
+ mDrawerLayout,
+ R.drawable.ic_drawer,
+ R.string.app_name,
+ R.string.drawer_close) {
+
+ /** Called when a drawer has settled in a completely closed state. */
+ public void onDrawerClosed(View view) {
+ super.onDrawerClosed(view);
+ updateActionBarTitleAndHomeButton(null);
+ invalidateOptionsMenu();
+ }
+
+ /** Called when a drawer has settled in a completely open state. */
+ public void onDrawerOpened(View drawerView) {
+ super.onDrawerOpened(drawerView);
+ getSupportActionBar().setTitle(R.string.app_name);
+ mDrawerToggle.setDrawerIndicatorEnabled(true);
+ invalidateOptionsMenu();
+ }
+ };
+
+ //mDrawerToggle.setDrawerIndicatorEnabled(true);
+ // Set the list's click listener
+ mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
+
+ // Set the drawer toggle as the DrawerListener
+ mDrawerLayout.setDrawerListener(mDrawerToggle);
+ }
+
+ /**
+ * Updates title bar and home buttons (state and icon).
+ *
+ * Assumes that navigation drawer is NOT visible.
+ */
+ protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) {
+ String title = getString(R.string.default_display_name_for_root_folder); // default
+ boolean inRoot;
+
+ /// choose the appropiate title
+ if (chosenFile == null) {
+ chosenFile = mFile; // if no file is passed, current file decides
+ }
+ inRoot = (
+ chosenFile == null ||
+ (chosenFile.isFolder() && chosenFile.getParentId() == FileDataStorageManager.ROOT_PARENT_ID)
+ );
+ if (!inRoot) {
+ title = chosenFile.getFileName();
+ }
+
+ /// set the chosen title
+ ActionBar actionBar = getSupportActionBar();
+ actionBar.setTitle(title);
+ /// also as content description
+ View actionBarTitleView = getWindow().getDecorView().findViewById(
+ getResources().getIdentifier("action_bar_title", "id", "android")
+ );
+ if (actionBarTitleView != null) { // it's null in Android 2.x
+ actionBarTitleView.setContentDescription(title);
+ }
+
+ /// set home button properties
+ mDrawerToggle.setDrawerIndicatorEnabled(inRoot);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowTitleEnabled(true);
+
+ }
+
+
/**
* Sets and validates the ownCloud {@link Account} associated to the Activity.
*
* @param account New {@link Account} to set.
* @param savedAccount When 'true', account was retrieved from a saved instance state.
*/
- private void setAccount(Account account, boolean savedAccount) {
+ protected void setAccount(Account account, boolean savedAccount) {
Account oldAccount = mAccount;
- boolean validAccount = (account != null && AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), account.name));
+ boolean validAccount =
+ (account != null && AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(),
+ account.name));
if (validAccount) {
mAccount = account;
mAccountWasSet = true;
* to create a new ownCloud {@link Account}.
*
* POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.
- *
- * @return 'True' if the checked {@link Account} was valid.
*/
private void swapToDefaultAccount() {
// default to the most recently used account
*/
private void createFirstAccount() {
AccountManager am = AccountManager.get(getApplicationContext());
- am.addAccount(MainApp.getAccountType(),
- null,
- null,
- null,
- this,
- new AccountCreationCallback(),
- null);
+ am.addAccount(MainApp.getAccountType(),
+ null,
+ null,
+ null,
+ this,
+ new AccountCreationCallback(),
+ null);
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(FileActivity.EXTRA_FILE, mFile);
- outState.putParcelable(FileActivity.EXTRA_ACCOUNT, mAccount);
outState.putBoolean(FileActivity.EXTRA_FROM_NOTIFICATION, mFromNotification);
outState.putLong(KEY_WAITING_FOR_OP_ID, mFileOperationsHelper.getOpIdWaitingFor());
+ outState.putBoolean(KEY_TRY_SHARE_AGAIN, mTryShareAgain);
+ outState.putString(KEY_ACTION_BAR_TITLE, getSupportActionBar().getTitle().toString());
}
/**
- * Getter for the ownCloud {@link Account} where the main {@link OCFile} handled by the activity is located.
+ * Getter for the ownCloud {@link Account} where the main {@link OCFile} handled by the activity
+ * is located.
*
- * @return OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located.
+ * @return OwnCloud {@link Account} where the main {@link OCFile} handled by the activity
+ * is located.
*/
public Account getAccount() {
return mAccount;
}
+ protected void setAccount(Account account) {
+ mAccount = account;
+ }
+
/**
* @return Value of mFromNotification: True if the Activity is launched by a notification
*/
protected boolean isRedirectingToSetupAccount() {
return mRedirectingToSetupAccount;
}
-
+
+ public boolean isTryShareAgain(){
+ return mTryShareAgain;
+ }
+
+ public void setTryShareAgain(boolean tryShareAgain) {
+ mTryShareAgain = tryShareAgain;
+ }
public OperationsServiceBinder getOperationsServiceBinder() {
return mOperationsServiceBinder;
protected ServiceConnection newTransferenceServiceConnection() {
return null;
}
-
/**
* Helper class handling a callback from the {@link AccountManager} after the creation of
* a new ownCloud {@link Account} finished, successfully or not.
*
* At this moment, only called after the creation of the first account.
- *
- * @author David A. Velasco
*/
public class AccountCreationCallback implements AccountManagerCallback<Bundle> {
*/
@Override
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
- Log_OC.d(TAG, "Received result of operation in FileActivity - common behaviour for all the FileActivities ");
+ Log_OC.d(TAG, "Received result of operation in FileActivity - common behaviour for all the "
+ + "FileActivities ");
mFileOperationsHelper.setOpIdWaitingFor(Long.MAX_VALUE);
if (result.getCode() == ResultCode.UNAUTHORIZED) {
dismissLoadingDialog();
- Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+ Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
+ operation, getResources()),
Toast.LENGTH_LONG);
t.show();
}
+ mTryShareAgain = false;
} else if (operation instanceof CreateShareOperation) {
onCreateShareOperationFinish((CreateShareOperation) operation, result);
} else if (operation instanceof UnshareLinkOperation) {
onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result);
- }
+ } else if (operation instanceof SynchronizeFolderOperation) {
+ onSynchronizeFolderOperationFinish((SynchronizeFolderOperation)operation, result);
+
+ }
}
protected void requestCredentialsUpdate() {
}
- private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
+ private void onCreateShareOperationFinish(CreateShareOperation operation,
+ RemoteOperationResult result) {
dismissLoadingDialog();
if (result.isSuccess()) {
+ mTryShareAgain = false;
updateFileFromDB();
Intent sendIntent = operation.getSendIntent();
startActivity(sendIntent);
-
- } else {
- Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
- Toast.LENGTH_LONG);
- t.show();
+ } else {
+ // Detect Failure (403) --> needs Password
+ if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
+ if (!isTryShareAgain()) {
+ SharePasswordDialogFragment dialog =
+ SharePasswordDialogFragment.newInstance(new OCFile(operation.getPath()),
+ operation.getSendIntent());
+ dialog.show(getSupportFragmentManager(), DIALOG_SHARE_PASSWORD);
+ } else {
+ Toast t = Toast.makeText(this,
+ ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+ Toast.LENGTH_LONG);
+ t.show();
+ mTryShareAgain = false;
+ }
+ } else {
+ Toast t = Toast.makeText(this,
+ ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+ Toast.LENGTH_LONG);
+ t.show();
+ }
}
}
- private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
+ private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
+ RemoteOperationResult result) {
dismissLoadingDialog();
if (result.isSuccess()){
updateFileFromDB();
} else {
- Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
- Toast.LENGTH_LONG);
+ Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
+ operation, getResources()), Toast.LENGTH_LONG);
t.show();
}
}
-
+
+ private void onSynchronizeFolderOperationFinish(
+ SynchronizeFolderOperation operation, RemoteOperationResult result
+ ) {
+ if (!result.isSuccess() && result.getCode() != ResultCode.CANCELLED){
+ Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
+ operation, getResources()), Toast.LENGTH_LONG);
+ t.show();
+ }
+ }
protected void updateFileFromDB(){
OCFile file = getFile();
mOperationsServiceBinder.addOperationListener(FileActivity.this, mHandler);
long waitingForOpId = mFileOperationsHelper.getOpIdWaitingFor();
if (waitingForOpId <= Integer.MAX_VALUE) {
- boolean wait = mOperationsServiceBinder.dispatchResultIfFinished((int)waitingForOpId, this);
+ boolean wait = mOperationsServiceBinder.dispatchResultIfFinished((int)waitingForOpId,
+ this);
if (!wait ) {
dismissLoadingDialog();
}
@Override
public FileUploaderBinder getFileUploaderBinder() {
return mUploaderBinder;
- };
-
-
+ }
+
+
+ public void restart(){
+ Intent i = new Intent(this, FileDisplayActivity.class);
+ i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(i);
+ }
+
+// TODO re-enable when "Accounts" is available in Navigation Drawer
+// public void closeDrawer() {
+// mDrawerLayout.closeDrawers();
+// }
+
+ public void allFilesOption(){
+ restart();
+ }
+
+ private class DrawerItemClickListener implements ListView.OnItemClickListener {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ // TODO re-enable when "Accounts" is available in Navigation Drawer
+// if (mShowAccounts && position > 0){
+// position = position - 1;
+// }
+ switch (position){
+ // TODO re-enable when "Accounts" is available in Navigation Drawer
+// case 0: // Accounts
+// mShowAccounts = !mShowAccounts;
+// mNavigationDrawerAdapter.setShowAccounts(mShowAccounts);
+// mNavigationDrawerAdapter.notifyDataSetChanged();
+// break;
+
+ case 0: // All Files
+ allFilesOption();
+ mDrawerLayout.closeDrawers();
+ break;
+
+ // TODO Enable when "On Device" is recovered ?
+// case 2:
+// MainApp.showOnlyFilesOnDevice(true);
+// mDrawerLayout.closeDrawers();
+// break;
+
+ case 1: // Settings
+ Intent settingsIntent = new Intent(getApplicationContext(),
+ Preferences.class);
+ startActivity(settingsIntent);
+ mDrawerLayout.closeDrawers();
+ break;
+
+ case 2: // Logs
+ Intent loggerIntent = new Intent(getApplicationContext(),
+ LogHistoryActivity.class);
+ startActivity(loggerIntent);
+ mDrawerLayout.closeDrawers();
+ break;
+ }
+ }
+ }
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2014 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.ui.activity;
-import java.io.File;
-import java.io.IOException;
-
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
+import android.annotation.TargetApi;
import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
-import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.Environment;
import android.os.IBinder;
import android.preference.PreferenceManager;
-import android.provider.DocumentsContract;
-import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
+import android.support.v4.view.GravityCompat;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.TextView;
+import android.view.Window;
import android.widget.Toast;
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuInflater;
-import com.actionbarsherlock.view.MenuItem;
-import com.actionbarsherlock.view.Window;
-import com.owncloud.android.BuildConfig;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
+import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader;
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
import com.owncloud.android.operations.CreateFolderOperation;
import com.owncloud.android.operations.CreateShareOperation;
import com.owncloud.android.operations.MoveFileOperation;
+import com.owncloud.android.operations.RefreshFolderOperation;
import com.owncloud.android.operations.RemoveFileOperation;
import com.owncloud.android.operations.RenameFileOperation;
import com.owncloud.android.operations.SynchronizeFileOperation;
-import com.owncloud.android.operations.SynchronizeFolderOperation;
import com.owncloud.android.operations.UnshareLinkOperation;
import com.owncloud.android.services.observer.FileObserverService;
import com.owncloud.android.syncadapter.FileSyncAdapter;
-import com.owncloud.android.ui.adapter.FileListListAdapter;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
+import com.owncloud.android.ui.dialog.UploadSourceDialogFragment;
import com.owncloud.android.ui.fragment.FileDetailFragment;
import com.owncloud.android.ui.fragment.FileFragment;
import com.owncloud.android.ui.fragment.OCFileListFragment;
import com.owncloud.android.ui.preview.PreviewVideoActivity;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.ErrorMessageAdapter;
+import com.owncloud.android.utils.FileStorageUtils;
import com.owncloud.android.utils.UriUtils;
+import java.io.File;
+
/**
* Displays, what files the user has available in his ownCloud.
- *
- * @author Bartek Przybylski
- * @author David A. Velasco
*/
-public class FileDisplayActivity extends HookActivity implements
-FileFragment.ContainerActivity, OnNavigationListener,
-OnSslUntrustedCertListener, OnEnforceableRefreshListener {
-
- private ArrayAdapter<String> mDirectories;
+public class FileDisplayActivity extends HookActivity
+ implements FileFragment.ContainerActivity,
+ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
private SyncBroadcastReceiver mSyncBroadcastReceiver;
private UploadFinishReceiver mUploadFinishReceiver;
private static final String KEY_SYNC_IN_PROGRESS = "SYNC_IN_PROGRESS";
private static final String KEY_WAITING_TO_SEND = "WAITING_TO_SEND";
- public static final int DIALOG_SHORT_WAIT = 0;
- private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 1;
- private static final int DIALOG_CERT_NOT_SAVED = 2;
-
public static final String ACTION_DETAILS = "com.owncloud.android.ui.activity.action.DETAILS";
- private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
- private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
+ public static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
+ public static final int ACTION_SELECT_MULTIPLE_FILES = 2;
public static final int ACTION_MOVE_FILES = 3;
private static final String TAG = FileDisplayActivity.class.getSimpleName();
private boolean mSyncInProgress = false;
- private String DIALOG_UNTRUSTED_CERT;
-
+ private static String DIALOG_UNTRUSTED_CERT = "DIALOG_UNTRUSTED_CERT";
+ private static String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER";
+ private static String DIALOG_UPLOAD_SOURCE = "DIALOG_UPLOAD_SOURCE";
+ private static String DIALOG_CERT_NOT_SAVED = "DIALOG_CERT_NOT_SAVED";
+
private OCFile mWaitingToSend;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
- Log_OC.d(TAG, "onCreate() start");
+ Log_OC.v(TAG, "onCreate() start");
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account is valid
-
- // PIN CODE request ; best location is to decide, let's try this first
- if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {
- requestPinCode();
- } else if (getIntent().getAction() == null && savedInstanceState == null) {
- requestPinCode();
- }
+ super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account
+ // is valid
- /// grant that FileObserverService is watching favourite files
+ /// grant that FileObserverService is watching favorite files
if (savedInstanceState == null) {
Intent initObserversIntent = FileObserverService.makeInitIntent(this);
startService(initObserversIntent);
/// Load of saved instance state
if(savedInstanceState != null) {
- mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW);
+ mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(
+ FileDisplayActivity.KEY_WAITING_TO_PREVIEW);
mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS);
- mWaitingToSend = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND);
+ mWaitingToSend = (OCFile) savedInstanceState.getParcelable(
+ FileDisplayActivity.KEY_WAITING_TO_SEND);
} else {
mWaitingToPreview = null;
/// USER INTERFACE
// Inflate and set the layout view
- setContentView(R.layout.files);
+ setContentView(R.layout.files);
+
+ // Navigation Drawer
+ initDrawer();
+
mDualPane = getResources().getBoolean(R.bool.large_land_layout);
mLeftFragmentContainer = findViewById(R.id.left_fragment_container);
mRightFragmentContainer = findViewById(R.id.right_fragment_container);
}
// Action bar setup
- mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
- getSupportActionBar().setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation
- setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/); // always AFTER setContentView(...) ; to work around bug in its implementation
+ getSupportActionBar().setHomeButtonEnabled(true); // mandatory since Android ICS,
+ // according to the official
+ // documentation
+
+ setSupportProgressBarIndeterminateVisibility(mSyncInProgress
+ /*|| mRefreshSharesInProgress*/);
+ // always AFTER setContentView(...) ; to work around bug in its implementation
setBackgroundText();
- Log_OC.d(TAG, "onCreate() end");
+ Log_OC.v(TAG, "onCreate() end");
}
-
+
@Override
protected void onStart() {
+ Log_OC.v(TAG, "onStart() start");
super.onStart();
getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
+ Log_OC.v(TAG, "onStart() end");
}
@Override
protected void onDestroy() {
+ Log_OC.v(TAG, "onDestroy() start");
super.onDestroy();
+ Log_OC.v(TAG, "onDestroy() end");
}
/**
protected void onAccountSet(boolean stateWasRecovered) {
super.onAccountSet(stateWasRecovered);
if (getAccount() != null) {
- /// Check whether the 'main' OCFile handled by the Activity is contained in the current Account
+ /// Check whether the 'main' OCFile handled by the Activity is contained in the
+ // current Account
OCFile file = getFile();
// get parent from path
String parentPath = "";
if (file != null) {
if (file.isDown() && file.getLastSyncDateForProperties() == 0) {
- // upload in progress - right now, files are not inserted in the local cache until the upload is successful
- // get parent from path
- parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
+ // upload in progress - right now, files are not inserted in the local
+ // cache until the upload is successful get parent from path
+ parentPath = file.getRemotePath().substring(0,
+ file.getRemotePath().lastIndexOf(file.getFileName()));
if (getStorageManager().getFileByPath(parentPath) == null)
file = null; // not able to know the directory where the file is uploading
} else {
- file = getStorageManager().getFileByPath(file.getRemotePath()); // currentDir = null if not in the current Account
+ file = getStorageManager().getFileByPath(file.getRemotePath());
+ // currentDir = null if not in the current Account
}
}
if (file == null) {
file = getStorageManager().getFileByPath(OCFile.ROOT_PATH); // never returns null
}
setFile(file);
- setNavigationListWithFolder(file);
if (!stateWasRecovered) {
- Log_OC.e(TAG, "Initializing Fragments in onAccountChanged..");
+ Log_OC.d(TAG, "Initializing Fragments in onAccountChanged..");
initFragmentsWithFile();
if (file.isFolder()) {
startSyncFolderOperation(file, false);
} else {
updateFragmentsVisibility(!file.isFolder());
- updateNavigationElementsInActionBar(file.isFolder() ? null : file);
- }
- }
- }
-
-
- private void setNavigationListWithFolder(OCFile file) {
- mDirectories.clear();
- OCFile fileIt = file;
- String parentPath;
- while(fileIt != null && fileIt.getFileName() != OCFile.ROOT_PATH) {
- if (fileIt.isFolder()) {
- mDirectories.add(fileIt.getFileName());
+ updateActionBarTitleAndHomeButton(file.isFolder() ? null : file);
}
- // get parent from path
- parentPath = fileIt.getRemotePath().substring(0, fileIt.getRemotePath().lastIndexOf(fileIt.getFileName()));
- fileIt = getStorageManager().getFileByPath(parentPath);
}
- mDirectories.add(OCFile.PATH_SEPARATOR);
}
/// First fragment
OCFileListFragment listOfFiles = getListOfFilesFragment();
if (listOfFiles != null) {
- listOfFiles.listDirectory(getCurrentDir());
+ listOfFiles.listDirectory(getCurrentDir());
+ // TODO Enable when "On Device" is recovered
+ // listOfFiles.listDirectory(getCurrentDir(), MainApp.getOnlyOnDevice());
} else {
Log_OC.e(TAG, "Still have a chance to lose the initializacion of list fragment >(");
}
if (secondFragment != null) {
setSecondFragment(secondFragment);
updateFragmentsVisibility(true);
- updateNavigationElementsInActionBar(file);
+ updateActionBarTitleAndHomeButton(file);
} else {
cleanSecondFragment();
if (file.isDown() && PreviewMediaFragment.canBePreviewed(file)
&& file.getLastSyncDateForProperties() > 0 // temporal fix
) {
- int startPlaybackPosition = getIntent().getIntExtra(PreviewVideoActivity.EXTRA_START_POSITION, 0);
- boolean autoplay = getIntent().getBooleanExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, true);
- secondFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition, autoplay);
+ int startPlaybackPosition =
+ getIntent().getIntExtra(PreviewVideoActivity.EXTRA_START_POSITION, 0);
+ boolean autoplay =
+ getIntent().getBooleanExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, true);
+ secondFragment = new PreviewMediaFragment(file, getAccount(),
+ startPlaybackPosition, autoplay);
} else {
- secondFragment = new FileDetailFragment(file, getAccount());
+ secondFragment = FileDetailFragment.newInstance(file, getAccount());
}
}
return secondFragment;
private OCFileListFragment getListOfFilesFragment() {
- Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_LIST_OF_FILES);
+ Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag(
+ FileDisplayActivity.TAG_LIST_OF_FILES);
if (listOfFiles != null) {
return (OCFileListFragment)listOfFiles;
}
}
public FileFragment getSecondFragment() {
- Fragment second = getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_SECOND_FRAGMENT);
+ Fragment second = getSupportFragmentManager().findFragmentByTag(
+ FileDisplayActivity.TAG_SECOND_FRAGMENT);
if (second != null) {
return (FileFragment)second;
}
tr.commit();
}
updateFragmentsVisibility(false);
- updateNavigationElementsInActionBar(null);
+ updateActionBarTitleAndHomeButton(null);
}
protected void refreshListOfFilesFragment() {
OCFileListFragment fileListFragment = getListOfFilesFragment();
- if (fileListFragment != null) {
+ if (fileListFragment != null) {
fileListFragment.listDirectory();
+ // TODO Enable when "On Device" is recovered ?
+ // fileListFragment.listDirectory(MainApp.getOnlyOnDevice());
}
}
- protected void refreshSecondFragment(String downloadEvent, String downloadedRemotePath, boolean success) {
+ protected void refreshSecondFragment(String downloadEvent, String downloadedRemotePath,
+ boolean success) {
FileFragment secondFragment = getSecondFragment();
- boolean waitedPreview = (mWaitingToPreview != null && mWaitingToPreview.getRemotePath().equals(downloadedRemotePath));
+ boolean waitedPreview = (mWaitingToPreview != null &&
+ mWaitingToPreview.getRemotePath().equals(downloadedRemotePath));
if (secondFragment != null && secondFragment instanceof FileDetailFragment) {
FileDetailFragment detailsFragment = (FileDetailFragment) secondFragment;
OCFile fileInFragment = detailsFragment.getFile();
- if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
+ if (fileInFragment != null &&
+ !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
// the user browsed to other file ; forget the automatic preview
mWaitingToPreview = null;
boolean detailsFragmentChanged = false;
if (waitedPreview) {
if (success) {
- mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); // update the file from database, for the local storage path
+ mWaitingToPreview = getStorageManager().getFileById(
+ mWaitingToPreview.getFileId()); // update the file from database,
+ // for the local storage path
if (PreviewMediaFragment.canBePreviewed(mWaitingToPreview)) {
startMediaPreview(mWaitingToPreview, 0, true);
detailsFragmentChanged = true;
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
- if (BuildConfig.DEBUG) {
- menu.findItem(R.id.action_logger).setVisible(true);
- } else {
- menu.findItem(R.id.action_logger).setVisible(false);
- }
+ boolean drawerOpen = mDrawerLayout.isDrawerOpen(GravityCompat.START);
+ menu.findItem(R.id.action_upload).setVisible(!drawerOpen);
+ menu.findItem(R.id.action_create_dir).setVisible(!drawerOpen);
+ menu.findItem(R.id.action_sort).setVisible(!drawerOpen);
+ menu.findItem(R.id.action_sync_account).setVisible(!drawerOpen);
+
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getSherlock().getMenuInflater();
+ MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean retval = true;
switch (item.getItemId()) {
- case R.id.action_create_dir: {
- CreateFolderDialogFragment dialog =
- CreateFolderDialogFragment.newInstance(getCurrentDir());
- dialog.show(getSupportFragmentManager(), "createdirdialog");
- break;
- }
- case R.id.action_sync_account: {
- startSynchronization();
- break;
- }
- case R.id.action_upload: {
- showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE);
- break;
- }
- case R.id.action_settings: {
- Intent settingsIntent = new Intent(this, Preferences.class);
- startActivity(settingsIntent);
- break;
- }
- case R.id.action_logger: {
- Intent loggerIntent = new Intent(getApplicationContext(),LogHistoryActivity.class);
- startActivity(loggerIntent);
- break;
- }
- case android.R.id.home: {
- FileFragment second = getSecondFragment();
- OCFile currentDir = getCurrentDir();
- if((currentDir != null && currentDir.getParentId() != 0) ||
- (second != null && second.getFile() != null)) {
- onBackPressed();
-
+ case R.id.action_create_dir: {
+ CreateFolderDialogFragment dialog =
+ CreateFolderDialogFragment.newInstance(getCurrentDir());
+ dialog.show(getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
+ break;
}
- break;
- }
- case R.id.action_sort: {
- SharedPreferences appPreferences = PreferenceManager
- .getDefaultSharedPreferences(this);
-
- // Read sorting order, default to sort by name ascending
- Integer sortOrder = appPreferences
- .getInt("sortOrder", FileListListAdapter.SORT_NAME);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.actionbar_sort_title)
- .setSingleChoiceItems(R.array.actionbar_sortby, sortOrder , new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
-
- switch (which){
- case 0:
- sortByName(true);
- break;
- case 1:
- sortByDate(false);
- break;
-
-// TODO re-enable when server-side folder size calculation is available
-// case 2:
-// sortBySize(false);
-// break;
- }
-
- dialog.dismiss();
-
+ case R.id.action_sync_account: {
+ startSynchronization();
+ break;
+ }
+ case R.id.action_upload: {
+ UploadSourceDialogFragment dialog =
+ UploadSourceDialogFragment.newInstance(getAccount());
+ dialog.show(getSupportFragmentManager(), DIALOG_UPLOAD_SOURCE);
+
+ break;
+ }
+ case android.R.id.home: {
+ FileFragment second = getSecondFragment();
+ OCFile currentDir = getCurrentDir();
+ if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
+ mDrawerLayout.closeDrawer(GravityCompat.START);
+ } else if((currentDir != null && currentDir.getParentId() != 0) ||
+ (second != null && second.getFile() != null)) {
+ onBackPressed();
+
+ } else {
+ mDrawerLayout.openDrawer(GravityCompat.START);
}
- });
- builder.create().show();
- break;
- }
+ break;
+ }
+ case R.id.action_sort: {
+ SharedPreferences appPreferences = PreferenceManager
+ .getDefaultSharedPreferences(this);
+
+ // Read sorting order, default to sort by name ascending
+ Integer sortOrder = appPreferences
+ .getInt("sortOrder", FileStorageUtils.SORT_NAME);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.actionbar_sort_title)
+ .setSingleChoiceItems(R.array.actionbar_sortby, sortOrder ,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which){
+ case 0:
+ sortByName(true);
+ break;
+ case 1:
+ sortByDate(false);
+ break;
+ }
+
+ dialog.dismiss();
+ }
+ });
+ builder.create().show();
+ break;
+ }
default:
retval = super.onOptionsItemSelected(item);
}
}
private void startSynchronization() {
- Log_OC.e(TAG, "Got to start sync");
+ Log_OC.d(TAG, "Got to start sync");
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
- Log_OC.e(TAG, "Canceling all syncs for " + MainApp.getAuthority());
- ContentResolver.cancelSync(null, MainApp.getAuthority()); // cancel the current synchronizations of any ownCloud account
+ Log_OC.d(TAG, "Canceling all syncs for " + MainApp.getAuthority());
+ ContentResolver.cancelSync(null, MainApp.getAuthority());
+ // cancel the current synchronizations of any ownCloud account
Bundle bundle = new Bundle();
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
- Log_OC.e(TAG, "Requesting sync for " + getAccount().name + " at " + MainApp.getAuthority());
+ Log_OC.d(TAG, "Requesting sync for " + getAccount().name + " at " +
+ MainApp.getAuthority());
ContentResolver.requestSync(
getAccount(),
MainApp.getAuthority(), bundle);
} else {
- Log_OC.e(TAG, "Requesting sync for " + getAccount().name + " at " + MainApp.getAuthority() + " with new API");
+ Log_OC.d(TAG, "Requesting sync for " + getAccount().name + " at " +
+ MainApp.getAuthority() + " with new API");
SyncRequest.Builder builder = new SyncRequest.Builder();
builder.setSyncAdapter(getAccount(), MainApp.getAuthority());
builder.setExpedited(true);
}
}
-
- @Override
- public boolean onNavigationItemSelected(int itemPosition, long itemId) {
- if (itemPosition != 0) {
- String targetPath = "";
- for (int i=itemPosition; i < mDirectories.getCount() - 1; i++) {
- targetPath = mDirectories.getItem(i) + OCFile.PATH_SEPARATOR + targetPath;
- }
- targetPath = OCFile.PATH_SEPARATOR + targetPath;
- OCFile targetFolder = getStorageManager().getFileByPath(targetPath);
- if (targetFolder != null) {
- browseTo(targetFolder);
- }
-
- // the next operation triggers a new call to this method, but it's necessary to
- // ensure that the name exposed in the action bar is the current directory when the
- // user selected it in the navigation list
- if (getSupportActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST && itemPosition != 0)
- getSupportActionBar().setSelectedNavigationItem(0);
- }
- return true;
- }
-
/**
* Called, when the user selected something for uploading
+ *
*/
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
- requestSimpleUpload(data, resultCode);
-
- } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
+ if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK ||
+ resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
+ //getClipData is only supported on api level 16+, Jelly Bean
+ if (data.getData() == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN){
+ for( int i = 0; i < data.getClipData().getItemCount(); i++){
+ Intent intent = new Intent();
+ intent.setData(data.getClipData().getItemAt(i).getUri());
+ requestSimpleUpload(intent, resultCode);
+ }
+ }else {
+ requestSimpleUpload(data, resultCode);
+ }
+ } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK ||
+ resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
requestMultipleUpload(data, resultCode);
- } else if (requestCode == ACTION_MOVE_FILES && (resultCode == RESULT_OK ||
- resultCode == MoveActivity.RESULT_OK_AND_MOVE)){
+ } else if (requestCode == ACTION_MOVE_FILES && resultCode == RESULT_OK){
final Intent fData = data;
final int fResultCode = resultCode;
},
DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
);
+
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
}
+
}
private void requestMultipleUpload(Intent data, int resultCode) {
String[] filePaths = data.getStringArrayExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES);
if (filePaths != null) {
String[] remotePaths = new String[filePaths.length];
- String remotePathBase = "";
- for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
- remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
- }
- if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR))
- remotePathBase += OCFile.PATH_SEPARATOR;
+ String remotePathBase = getCurrentDir().getRemotePath();
for (int j = 0; j< remotePaths.length; j++) {
remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName();
}
} else {
Log_OC.d(TAG, "User clicked on 'Update' with no selection");
- Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG);
+ Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected),
+ Toast.LENGTH_LONG);
t.show();
return;
}
private void requestSimpleUpload(Intent data, int resultCode) {
- String filepath = null;
+ String filePath = null;
String mimeType = null;
Uri selectedImageUri = data.getData();
try {
mimeType = getContentResolver().getType(selectedImageUri);
- String filemanagerstring = selectedImageUri.getPath();
- String selectedImagePath = getPath(selectedImageUri);
+ String fileManagerString = selectedImageUri.getPath();
+ String selectedImagePath = UriUtils.getLocalPath(selectedImageUri, this);
if (selectedImagePath != null)
- filepath = selectedImagePath;
+ filePath = selectedImagePath;
else
- filepath = filemanagerstring;
+ filePath = fileManagerString;
} catch (Exception e) {
- Log_OC.e(TAG, "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);
- e.printStackTrace();
+ Log_OC.e(TAG, "Unexpected exception when trying to read the result of " +
+ "Intent.ACTION_GET_CONTENT", e);
} finally {
- if (filepath == null) {
- Log_OC.e(TAG, "Couldnt resolve path to file");
- Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);
+ if (filePath == null) {
+ Log_OC.e(TAG, "Couldn't resolve path to file");
+ Toast t = Toast.makeText(
+ this, getString(R.string.filedisplay_unexpected_bad_get_content),
+ Toast.LENGTH_LONG
+ );
t.show();
return;
}
}
Intent i = new Intent(this, FileUploader.class);
- i.putExtra(FileUploader.KEY_ACCOUNT,
- getAccount());
- String remotepath = new String();
- for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
- remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
- }
- if (!remotepath.endsWith(OCFile.PATH_SEPARATOR))
- remotepath += OCFile.PATH_SEPARATOR;
-
- if (filepath.startsWith(UriUtils.URI_CONTENT_SCHEME)) {
-
- Cursor cursor = MainApp.getAppContext().getContentResolver()
- .query(Uri.parse(filepath), null, null, null, null, null);
+ i.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
+ OCFile currentDir = getCurrentDir();
+ String remotePath = (currentDir != null) ? currentDir.getRemotePath() : OCFile.ROOT_PATH;
+ if (filePath.startsWith(UriUtils.URI_CONTENT_SCHEME)) {
+ Cursor cursor = getContentResolver().query(Uri.parse(filePath), null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
- String displayName = cursor.getString(
- cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
- Log.i(TAG, "Display Name: " + displayName + "; mimeType: " + mimeType);
+ String displayName = cursor.getString(cursor.getColumnIndex(
+ OpenableColumns.DISPLAY_NAME));
+ Log_OC.v(TAG, "Display Name: " + displayName );
displayName.replace(File.separatorChar, '_');
displayName.replace(File.pathSeparatorChar, '_');
- remotepath += displayName + DisplayUtils.getComposedFileExtension(filepath);
+ remotePath += displayName + DisplayUtils.getComposedFileExtension(filePath);
}
+ // and what happens in case of error?; wrong target name for the upload
} finally {
cursor.close();
}
} else {
- remotepath += new File(filepath).getName();
+ remotePath += new File(filePath).getName();
}
- i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath);
- i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath);
+ i.putExtra(FileUploader.KEY_LOCAL_FILE, filePath);
+ i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePath);
i.putExtra(FileUploader.KEY_MIME_TYPE, mimeType);
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)
- i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
+ i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
startService(i);
}
* @param resultCode Result code received
*/
private void requestMoveOperation(Intent data, int resultCode) {
- OCFile folderToMoveAt = (OCFile) data.getParcelableExtra(MoveActivity.EXTRA_CURRENT_FOLDER);
- OCFile targetFile = (OCFile) data.getParcelableExtra(MoveActivity.EXTRA_TARGET_FILE);
+ OCFile folderToMoveAt = (OCFile) data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER);
+ OCFile targetFile = (OCFile) data.getParcelableExtra(FolderPickerActivity.EXTRA_FILE);
getFileOperationsHelper().moveFile(folderToMoveAt, targetFile);
}
public void onBackPressed() {
OCFileListFragment listOfFiles = getListOfFilesFragment();
if (mDualPane || getSecondFragment() == null) {
+ OCFile currentDir = getCurrentDir();
+ if (currentDir == null || currentDir.getParentId() == FileDataStorageManager.ROOT_PARENT_ID) {
+ finish();
+ return;
+ }
if (listOfFiles != null) { // should never be null, indeed
- if (mDirectories.getCount() <= 1) {
- finish();
- return;
- }
- int levelsUp = listOfFiles.onBrowseUp();
- for (int i=0; i < levelsUp && mDirectories.getCount() > 1 ; i++) {
- popDirname();
- }
+ listOfFiles.onBrowseUp();
}
}
if (listOfFiles != null) { // should never be null, indeed
@Override
protected void onSaveInstanceState(Bundle outState) {
- // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
- Log_OC.e(TAG, "onSaveInstanceState() start");
+ // responsibility of restore is preferred in onCreate() before than in
+ // onRestoreInstanceState when there are Fragments involved
+ Log_OC.v(TAG, "onSaveInstanceState() start");
super.onSaveInstanceState(outState);
outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress);
- //outState.putBoolean(FileDisplayActivity.KEY_REFRESH_SHARES_IN_PROGRESS, mRefreshSharesInProgress);
+ //outState.putBoolean(FileDisplayActivity.KEY_REFRESH_SHARES_IN_PROGRESS,
+ // mRefreshSharesInProgress);
outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND, mWaitingToSend);
- Log_OC.d(TAG, "onSaveInstanceState() end");
+ Log_OC.v(TAG, "onSaveInstanceState() end");
}
@Override
protected void onResume() {
+ Log_OC.v(TAG, "onResume() start");
super.onResume();
- Log_OC.e(TAG, "onResume() start");
-
+
+ // refresh Navigation Drawer account list
+ mNavigationDrawerAdapter.updateAccountList();
+
+
// refresh list of files
refreshListOfFilesFragment();
IntentFilter syncIntentFilter = new IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START);
syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_END);
syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED);
- syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED);
- syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
+ syncIntentFilter.addAction(RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED);
+ syncIntentFilter.addAction(RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
mSyncBroadcastReceiver = new SyncBroadcastReceiver();
registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
- //LocalBroadcastManager.getInstance(this).registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
+ //LocalBroadcastManager.getInstance(this).registerReceiver(mSyncBroadcastReceiver,
+ // syncIntentFilter);
// Listen for upload messages
IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.getUploadFinishMessage());
registerReceiver(mUploadFinishReceiver, uploadIntentFilter);
// Listen for download messages
- IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.getDownloadAddedMessage());
+ IntentFilter downloadIntentFilter = new IntentFilter(
+ FileDownloader.getDownloadAddedMessage());
downloadIntentFilter.addAction(FileDownloader.getDownloadFinishMessage());
mDownloadFinishReceiver = new DownloadFinishReceiver();
registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
- Log_OC.d(TAG, "onResume() end");
+ Log_OC.v(TAG, "onResume() end");
}
@Override
protected void onPause() {
- Log_OC.e(TAG, "onPause() start");
+ Log_OC.v(TAG, "onPause() start");
if (mSyncBroadcastReceiver != null) {
unregisterReceiver(mSyncBroadcastReceiver);
//LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
mDownloadFinishReceiver = null;
}
-
- Log_OC.d(TAG, "onPause() end");
super.onPause();
+ Log_OC.v(TAG, "onPause() end");
}
- @Override
- protected Dialog onCreateDialog(int id) {
- Dialog dialog = null;
- AlertDialog.Builder builder;
- switch (id) {
- case DIALOG_SHORT_WAIT: {
- ProgressDialog working_dialog = new ProgressDialog(this);
- working_dialog.setMessage(getResources().getString(
- R.string.wait_a_moment));
- working_dialog.setIndeterminate(true);
- working_dialog.setCancelable(false);
- dialog = working_dialog;
- break;
- }
- case DIALOG_CHOOSE_UPLOAD_SOURCE: {
-
-
- String[] allTheItems = { getString(R.string.actionbar_upload_files),
- getString(R.string.actionbar_upload_from_apps) };
-
- builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.actionbar_upload);
- builder.setItems(allTheItems, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int item) {
- if (item == 0) {
- // if (!mDualPane) {
- Intent action = new Intent(FileDisplayActivity.this, UploadFilesActivity.class);
- action.putExtra(UploadFilesActivity.EXTRA_ACCOUNT, FileDisplayActivity.this.getAccount());
- startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);
- // } else {
- // TODO create and handle new fragment
- // LocalFileListFragment
- // }
- } else if (item == 1) {
- Intent action = new Intent(Intent.ACTION_GET_CONTENT);
- action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
- startActivityForResult(Intent.createChooser(action, getString(R.string.upload_chooser_title)),
- ACTION_SELECT_CONTENT_FROM_APPS);
- }
- }
- });
- dialog = builder.create();
- break;
- }
- case DIALOG_CERT_NOT_SAVED: {
- builder = new AlertDialog.Builder(this);
- builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));
- builder.setCancelable(false);
- builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- };
- });
- dialog = builder.create();
- break;
- }
- default:
- dialog = null;
- }
-
- return dialog;
- }
-
- /**
- * Translates a content URI of an content to a physical path on the disk
- *
- * @param uri The URI to resolve
- * @return The path to the content or null if it could not be found
- */
- public String getPath(Uri uri) {
- final boolean isKitKatOrLater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
-
- // DocumentProvider
- if (isKitKatOrLater && DocumentsContract.isDocumentUri(getApplicationContext(), uri)) {
- // ExternalStorageProvider
- if (UriUtils.isExternalStorageDocument(uri)) {
- final String docId = DocumentsContract.getDocumentId(uri);
- final String[] split = docId.split(":");
- final String type = split[0];
-
- if ("primary".equalsIgnoreCase(type)) {
- return Environment.getExternalStorageDirectory() + "/" + split[1];
- }
- }
- // DownloadsProvider
- else if (UriUtils.isDownloadsDocument(uri)) {
-
- final String id = DocumentsContract.getDocumentId(uri);
- final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
- Long.valueOf(id));
-
- return UriUtils.getDataColumn(getApplicationContext(), contentUri, null, null);
- }
- // MediaProvider
- else if (UriUtils.isMediaDocument(uri)) {
- final String docId = DocumentsContract.getDocumentId(uri);
- final String[] split = docId.split(":");
- final String type = split[0];
-
- Uri contentUri = null;
- if ("image".equals(type)) {
- contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
- } else if ("video".equals(type)) {
- contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- } else if ("audio".equals(type)) {
- contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- }
-
- final String selection = "_id=?";
- final String[] selectionArgs = new String[] { split[1] };
-
- return UriUtils.getDataColumn(getApplicationContext(), contentUri, selection, selectionArgs);
- }
- // Documents providers returned as content://...
- else if (UriUtils.isContentDocument(uri)) {
- return uri.toString();
- }
- }
- // MediaStore (and general)
- else if ("content".equalsIgnoreCase(uri.getScheme())) {
-
- // Return the remote address
- if (UriUtils.isGooglePhotosUri(uri))
- return uri.getLastPathSegment();
-
- return UriUtils.getDataColumn(getApplicationContext(), uri, null, null);
- }
- // File
- else if ("file".equalsIgnoreCase(uri.getScheme())) {
- return uri.getPath();
- }
- return null;
- }
-
- /**
- * Pushes a directory to the drop down list
- * @param directory to push
- * @throws IllegalArgumentException If the {@link OCFile#isFolder()} returns false.
- */
- public void pushDirname(OCFile directory) {
- if(!directory.isFolder()){
- throw new IllegalArgumentException("Only directories may be pushed!");
- }
- mDirectories.insert(directory.getFileName(), 0);
- setFile(directory);
- }
-
- /**
- * Pops a directory name from the drop down list
- * @return True, unless the stack is empty
- */
- public boolean popDirname() {
- mDirectories.remove(mDirectories.getItem(0));
- return !mDirectories.isEmpty();
- }
-
- // Custom array adapter to override text colors
- private class CustomArrayAdapter<T> extends ArrayAdapter<T> {
-
- public CustomArrayAdapter(FileDisplayActivity ctx, int view) {
- super(ctx, view);
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = super.getView(position, convertView, parent);
-
- ((TextView) v).setTextColor(getResources().getColorStateList(
- android.R.color.white));
-
- fixRoot((TextView) v );
- return v;
- }
-
- public View getDropDownView(int position, View convertView,
- ViewGroup parent) {
- View v = super.getDropDownView(position, convertView, parent);
-
- ((TextView) v).setTextColor(getResources().getColorStateList(
- android.R.color.white));
-
- fixRoot((TextView) v );
- return v;
- }
-
- private void fixRoot(TextView v) {
- if (v.getText().equals(OCFile.PATH_SEPARATOR)) {
- v.setText(R.string.default_display_name_for_root_folder);
- }
- }
-
- }
-
private class SyncBroadcastReceiver extends BroadcastReceiver {
/**
String event = intent.getAction();
Log_OC.d(TAG, "Received broadcast " + event);
String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME);
- String synchFolderRemotePath = intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH);
- RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncAdapter.EXTRA_RESULT);
- boolean sameAccount = (getAccount() != null && accountName.equals(getAccount().name) && getStorageManager() != null);
+ String synchFolderRemotePath =
+ intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH);
+ RemoteOperationResult synchResult =
+ (RemoteOperationResult)intent.getSerializableExtra(
+ FileSyncAdapter.EXTRA_RESULT);
+ boolean sameAccount = (getAccount() != null &&
+ accountName.equals(getAccount().name) && getStorageManager() != null);
if (sameAccount) {
mSyncInProgress = true;
} else {
- OCFile currentFile = (getFile() == null) ? null : getStorageManager().getFileByPath(getFile().getRemotePath());
- OCFile currentDir = (getCurrentDir() == null) ? null : getStorageManager().getFileByPath(getCurrentDir().getRemotePath());
+ OCFile currentFile = (getFile() == null) ? null :
+ getStorageManager().getFileByPath(getFile().getRemotePath());
+ OCFile currentDir = (getCurrentDir() == null) ? null :
+ getStorageManager().getFileByPath(getCurrentDir().getRemotePath());
if (currentDir == null) {
// current folder was removed from the server
Toast.makeText( FileDisplayActivity.this,
- String.format(getString(R.string.sync_current_folder_was_removed), mDirectories.getItem(0)),
+ String.format(
+ getString(R.string.
+ sync_current_folder_was_removed),
+ synchFolderRemotePath),
Toast.LENGTH_LONG)
.show();
browseToRoot();
} else {
if (currentFile == null && !getFile().isFolder()) {
- // currently selected file was removed in the server, and now we know it
+ // currently selected file was removed in the server, and now we
+ // know it
cleanSecondFragment();
currentFile = currentDir;
}
- if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) {
+ if (synchFolderRemotePath != null &&
+ currentDir.getRemotePath().equals(synchFolderRemotePath)) {
OCFileListFragment fileListFragment = getListOfFilesFragment();
if (fileListFragment != null) {
- fileListFragment.listDirectory(currentDir);
+ fileListFragment.listDirectory();
+ // TODO Enable when "On Device" is recovered ?
+ // fileListFragment.listDirectory(currentDir,
+ // MainApp.getOnlyOnDevice());
}
}
setFile(currentFile);
}
- mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event));
+ mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) &&
+ !RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED
+ .equals(event));
- if (SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
+ if (RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
equals(event) &&
/// TODO refactor and make common
synchResult != null && !synchResult.isSuccess() &&
(synchResult.isException() && synchResult.getException()
instanceof AuthenticatorException))) {
- OwnCloudClient client = null;
+
try {
- OwnCloudAccount ocAccount =
+ OwnCloudClient client;
+ OwnCloudAccount ocAccount =
new OwnCloudAccount(getAccount(), context);
client = (OwnCloudClientManagerFactory.getDefaultSingleton().
removeClientFor(ocAccount));
- // TODO get rid of these exceptions
- } catch (AccountNotFoundException e) {
- e.printStackTrace();
- } catch (AuthenticatorException e) {
- e.printStackTrace();
- } catch (OperationCanceledException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- if (client != null) {
- OwnCloudCredentials cred = client.getCredentials();
- if (cred != null) {
- AccountManager am = AccountManager.get(context);
- if (cred.authTokenExpires()) {
- am.invalidateAuthToken(
- getAccount().type,
- cred.getAuthToken()
- );
- } else {
- am.clearPassword(getAccount());
+
+ if (client != null) {
+ OwnCloudCredentials cred = client.getCredentials();
+ if (cred != null) {
+ AccountManager am = AccountManager.get(context);
+ if (cred.authTokenExpires()) {
+ am.invalidateAuthToken(
+ getAccount().type,
+ cred.getAuthToken()
+ );
+ } else {
+ am.clearPassword(getAccount());
+ }
}
}
+ requestCredentialsUpdate();
+
+ } catch (AccountNotFoundException e) {
+ Log_OC.e(TAG, "Account " + getAccount() + " was removed!", e);
}
-
- requestCredentialsUpdate();
-
+
}
}
removeStickyBroadcast(intent);
Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
- setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/);
+ setSupportProgressBarIndeterminateVisibility(mSyncInProgress
+ /*|| mRefreshSharesInProgress*/);
setBackgroundText();
}
if (synchResult != null) {
- if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
+ if (synchResult.getCode().equals(
+ RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
mLastSslUntrustedServerResult = synchResult;
}
}
refreshListOfFilesFragment();
}
- boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);
+ boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT,
+ false);
boolean renamedInUpload = getFile().getRemotePath().
equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));
boolean sameFile = getFile().getRemotePath().equals(uploadedRemotePath) ||
/**
- * Class waiting for broadcast events from the {@link FielDownloader} service.
+ * Class waiting for broadcast events from the {@link FileDownloader} service.
*
* Updates the UI when a download is started or finished, provided that it is relevant for the
* current folder.
*/
private class DownloadFinishReceiver extends BroadcastReceiver {
+
+ //int refreshCounter = 0;
@Override
public void onReceive(Context context, Intent intent) {
try {
boolean sameAccount = isSameAccount(context, intent);
- String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
+ String downloadedRemotePath =
+ intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
boolean isDescendant = isDescendant(downloadedRemotePath);
-
+
if (sameAccount && isDescendant) {
- refreshListOfFilesFragment();
- refreshSecondFragment(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
+ String linkedToRemotePath =
+ intent.getStringExtra(FileDownloader.EXTRA_LINKED_TO_PATH);
+ if (linkedToRemotePath == null || isAscendant(linkedToRemotePath)) {
+ //Log_OC.v(TAG, "refresh #" + ++refreshCounter);
+ refreshListOfFilesFragment();
+ }
+ refreshSecondFragment(
+ intent.getAction(),
+ downloadedRemotePath,
+ intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false)
+ );
}
if (mWaitingToSend != null) {
- mWaitingToSend = getStorageManager().getFileByPath(mWaitingToSend.getRemotePath()); // Update the file to send
+ mWaitingToSend =
+ getStorageManager().getFileByPath(mWaitingToSend.getRemotePath());
if (mWaitingToSend.isDown()) {
sendDownloadedFile();
}
private boolean isDescendant(String downloadedRemotePath) {
OCFile currentDir = getCurrentDir();
- return (currentDir != null && downloadedRemotePath != null && downloadedRemotePath.startsWith(currentDir.getRemotePath()));
+ return (
+ currentDir != null &&
+ downloadedRemotePath != null &&
+ downloadedRemotePath.startsWith(currentDir.getRemotePath())
+ );
+ }
+
+ private boolean isAscendant(String linkedToRemotePath) {
+ OCFile currentDir = getCurrentDir();
+ return (
+ currentDir != null &&
+ currentDir.getRemotePath().startsWith(linkedToRemotePath)
+ );
}
private boolean isSameAccount(Context context, Intent intent) {
String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
- return (accountName != null && getAccount() != null && accountName.equals(getAccount().name));
+ return (accountName != null && getAccount() != null &&
+ accountName.equals(getAccount().name));
}
}
public void browseToRoot() {
OCFileListFragment listOfFiles = getListOfFilesFragment();
if (listOfFiles != null) { // should never be null, indeed
- while (mDirectories.getCount() > 1) {
- popDirname();
- }
OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
listOfFiles.listDirectory(root);
+ // TODO Enable when "On Device" is recovered ?
+ // listOfFiles.listDirectory(root, MainApp.getOnlyOnDevice());
setFile(listOfFiles.getCurrentFile());
startSyncFolderOperation(root, false);
}
cleanSecondFragment();
- }
-
-
- public void browseTo(OCFile folder) {
- if (folder == null || !folder.isFolder()) {
- throw new IllegalArgumentException("Trying to browse to invalid folder " + folder);
- }
- OCFileListFragment listOfFiles = getListOfFilesFragment();
- if (listOfFiles != null) {
- setNavigationListWithFolder(folder);
- listOfFiles.listDirectory(folder);
- setFile(listOfFiles.getCurrentFile());
- startSyncFolderOperation(folder, false);
- } else {
- Log_OC.e(TAG, "Unexpected null when accessing list fragment");
- }
- cleanSecondFragment();
+
}
*/
@Override
public void onBrowsedDownTo(OCFile directory) {
- pushDirname(directory);
+ setFile(directory);
cleanSecondFragment();
-
// Sync Folder
startSyncFolderOperation(directory, false);
-
}
/**
*/
@Override
public void showDetails(OCFile file) {
- Fragment detailFragment = new FileDetailFragment(file, getAccount());
+ Fragment detailFragment = FileDetailFragment.newInstance(file, getAccount());
setSecondFragment(detailFragment);
updateFragmentsVisibility(true);
- updateNavigationElementsInActionBar(file);
+ updateActionBarTitleAndHomeButton(file);
setFile(file);
}
-
- /**
- * TODO
- */
- private void updateNavigationElementsInActionBar(OCFile chosenFile) {
- ActionBar actionBar = getSupportActionBar();
- if (chosenFile == null || mDualPane) {
- // only list of files - set for browsing through folders
- OCFile currentDir = getCurrentDir();
- boolean noRoot = (currentDir != null && currentDir.getParentId() != 0);
- actionBar.setDisplayHomeAsUpEnabled(noRoot);
- actionBar.setDisplayShowTitleEnabled(!noRoot);
- if (!noRoot) {
- actionBar.setTitle(getString(R.string.default_display_name_for_root_folder));
- }
- actionBar.setNavigationMode(!noRoot ? ActionBar.NAVIGATION_MODE_STANDARD : ActionBar.NAVIGATION_MODE_LIST);
- actionBar.setListNavigationCallbacks(mDirectories, this); // assuming mDirectories is updated
+ @Override
+ protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) {
+ if (mDualPane) {
+ // in dual pane mode, keep the focus of title an action bar in the current folder
+ super.updateActionBarTitleAndHomeButton(getCurrentDir());
} else {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowTitleEnabled(true);
- actionBar.setTitle(chosenFile.getFileName());
- actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ super.updateActionBarTitleAndHomeButton(chosenFile);
}
+
}
@Override
public void onServiceConnected(ComponentName component, IBinder service) {
- if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
+ if (component.equals(new ComponentName(
+ FileDisplayActivity.this, FileDownloader.class))) {
Log_OC.d(TAG, "Download service connected");
mDownloaderBinder = (FileDownloaderBinder) service;
if (mWaitingToPreview != null)
if (getStorageManager() != null) {
- mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); // update the file
+ // update the file
+ mWaitingToPreview =
+ getStorageManager().getFileById(mWaitingToPreview.getFileId());
if (!mWaitingToPreview.isDown()) {
requestForDownload();
}
}
- } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
+ } else if (component.equals(new ComponentName(FileDisplayActivity.this,
+ FileUploader.class))) {
Log_OC.d(TAG, "Upload service connected");
mUploaderBinder = (FileUploaderBinder) service;
} else {
return;
}
- // a new chance to get the mDownloadBinder through getFileDownloadBinder() - THIS IS A MESS
+ // a new chance to get the mDownloadBinder through
+ // getFileDownloadBinder() - THIS IS A MESS
OCFileListFragment listOfFiles = getListOfFilesFragment();
if (listOfFiles != null) {
listOfFiles.listDirectory();
+ // TODO Enable when "On Device" is recovered ?
+ // listOfFiles.listDirectory(MainApp.getOnlyOnDevice());
}
FileFragment secondFragment = getSecondFragment();
if (secondFragment != null && secondFragment instanceof FileDetailFragment) {
@Override
public void onServiceDisconnected(ComponentName component) {
- if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
+ if (component.equals(new ComponentName(FileDisplayActivity.this,
+ FileDownloader.class))) {
Log_OC.d(TAG, "Download service disconnected");
mDownloaderBinder = null;
- } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
+ } else if (component.equals(new ComponentName(FileDisplayActivity.this,
+ FileUploader.class))) {
Log_OC.d(TAG, "Upload service disconnected");
mUploaderBinder = null;
}
}
};
-
-
- /**
- * Launch an intent to request the PIN code to the user before letting him use the app
- */
- private void requestPinCode() {
- boolean pinStart = false;
- SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
- pinStart = appPrefs.getBoolean("set_pincode", false);
- if (pinStart) {
- Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
- i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity");
- startActivity(i);
- }
- }
-
-
@Override
public void onSavedCertificate() {
startSyncFolderOperation(getCurrentDir(), false);
@Override
public void onFailedSavingCertificate() {
- showDialog(DIALOG_CERT_NOT_SAVED);
+ ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(
+ R.string.ssl_validator_not_saved, new String[]{}, R.string.common_ok, -1, -1
+ );
+ dialog.show(getSupportFragmentManager(), DIALOG_CERT_NOT_SAVED);
}
@Override
}
- private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
+ private void onCreateShareOperationFinish(CreateShareOperation operation,
+ RemoteOperationResult result) {
if (result.isSuccess()) {
refreshShowDetails();
refreshListOfFilesFragment();
}
- private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
+ private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
+ RemoteOperationResult result) {
if (result.isSuccess()) {
refreshShowDetails();
refreshListOfFilesFragment();
}
/**
- * Updates the view associated to the activity after the finish of an operation trying to remove a
- * file.
+ * Updates the view associated to the activity after the finish of an operation trying to
+ * remove a file.
*
* @param operation Removal operation performed.
* @param result Result of the removal.
*/
- private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
+ private void onRemoveFileOperationFinish(RemoveFileOperation operation,
+ RemoteOperationResult result) {
dismissLoadingDialog();
- Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+ Toast msg = Toast.makeText(this,
+ ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
Toast.LENGTH_LONG);
msg.show();
* @param operation Move operation performed.
* @param result Result of the move operation.
*/
- private void onMoveFileOperationFinish(MoveFileOperation operation, RemoteOperationResult result) {
+ private void onMoveFileOperationFinish(MoveFileOperation operation,
+ RemoteOperationResult result) {
if (result.isSuccess()) {
dismissLoadingDialog();
refreshListOfFilesFragment();
/**
- * Updates the view associated to the activity after the finish of an operation trying to rename a
- * file.
+ * Updates the view associated to the activity after the finish of an operation trying to rename
+ * a file.
*
* @param operation Renaming operation performed.
* @param result Result of the renaming.
*/
- private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {
+ private void onRenameFileOperationFinish(RenameFileOperation operation,
+ RemoteOperationResult result) {
dismissLoadingDialog();
OCFile renamedFile = operation.getFile();
if (result.isSuccess()) {
FileFragment details = getSecondFragment();
if (details != null) {
- if (details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) {
+ if (details instanceof FileDetailFragment &&
+ renamedFile.equals(details.getFile()) ) {
((FileDetailFragment) details).updateFileDetails(renamedFile, getAccount());
showDetails(renamedFile);
- } else if (details instanceof PreviewMediaFragment && renamedFile.equals(details.getFile())) {
+ } else if (details instanceof PreviewMediaFragment &&
+ renamedFile.equals(details.getFile())) {
((PreviewMediaFragment) details).updateFile(renamedFile);
if (PreviewMediaFragment.canBePreviewed(renamedFile)) {
int position = ((PreviewMediaFragment)details).getPosition();
}
}
- if (getStorageManager().getFileById(renamedFile.getParentId()).equals(getCurrentDir())) {
+ if (getStorageManager().getFileById(renamedFile.getParentId()).equals(getCurrentDir())){
refreshListOfFilesFragment();
}
} else {
- Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+ Toast msg = Toast.makeText(this,
+ ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
Toast.LENGTH_LONG);
msg.show();
}
}
- private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
+ private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation,
+ RemoteOperationResult result) {
dismissLoadingDialog();
OCFile syncedFile = operation.getLocalFile();
if (!result.isSuccess()) {
onTransferStateChanged(syncedFile, true, true);
} else {
- Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
- Toast.LENGTH_LONG);
+ Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
+ operation, getResources()), Toast.LENGTH_LONG);
msg.show();
}
}
}
/**
- * Updates the view associated to the activity after the finish of an operation trying create a new folder
+ * Updates the view associated to the activity after the finish of an operation trying create a
+ * new folder
*
* @param operation Creation operation performed.
* @param result Result of the creation.
*/
- private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {
+ private void onCreateFolderOperationFinish(CreateFolderOperation operation,
+ RemoteOperationResult result) {
if (result.isSuccess()) {
dismissLoadingDialog();
refreshListOfFilesFragment();
public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
refreshListOfFilesFragment();
FileFragment details = getSecondFragment();
- if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) {
+ if (details != null && details instanceof FileDetailFragment &&
+ file.equals(details.getFile()) ) {
if (downloading || uploading) {
((FileDetailFragment)details).updateFileDetails(file, getAccount());
} else {
private void requestForDownload() {
Account account = getAccount();
+ //if (!mWaitingToPreview.isDownloading()) {
if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) {
Intent i = new Intent(this, FileDownloader.class);
i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
if (file.isFolder()) {
return file;
} else if (getStorageManager() != null) {
- String parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
+ String parentPath = file.getRemotePath().substring(0,
+ file.getRemotePath().lastIndexOf(file.getFileName()));
return getStorageManager().getFileByPath(parentPath);
}
}
mSyncInProgress = true;
// perform folder synchronization
- RemoteOperation synchFolderOp = new SynchronizeFolderOperation( folder,
- currentSyncTime,
- false,
- getFileOperationsHelper().isSharedSupported(),
- ignoreETag,
- getStorageManager(),
- getAccount(),
- getApplicationContext()
- );
- synchFolderOp.execute(getAccount(), this, null, null);
+ RemoteOperation synchFolderOp = new RefreshFolderOperation( folder,
+ currentSyncTime,
+ false,
+ getFileOperationsHelper().isSharedSupported(),
+ ignoreETag,
+ getStorageManager(),
+ getAccount(),
+ getApplicationContext()
+ );
+ synchFolderOp.execute(getAccount(), MainApp.getAppContext(), this, null, null);
setSupportProgressBarIndeterminateVisibility(true);
*/
public void showUntrustedCertDialog(RemoteOperationResult result) {
// Show a dialog with the certificate info
- SslUntrustedCertDialog dialog = SslUntrustedCertDialog.newInstanceForFullSslError((CertificateCombinedException)result.getException());
+ SslUntrustedCertDialog dialog = SslUntrustedCertDialog.newInstanceForFullSslError(
+ (CertificateCombinedException) result.getException());
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
dialog.show(ft, DIALOG_UNTRUSTED_CERT);
private void requestForDownload(OCFile file) {
Account account = getAccount();
- if (!mDownloaderBinder.isDownloading(account, file)) {
+ if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) {
Intent i = new Intent(this, FileDownloader.class);
i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
i.putExtra(FileDownloader.EXTRA_FILE, file);
* Stars the preview of an already down media {@link OCFile}.
*
* @param file Media {@link OCFile} to preview.
- * @param startPlaybackPosition Media position where the playback will be started, in milliseconds.
- * @param autoplay When 'true', the playback will start without user interactions.
+ * @param startPlaybackPosition Media position where the playback will be started,
+ * in milliseconds.
+ * @param autoplay When 'true', the playback will start without user
+ * interactions.
*/
public void startMediaPreview(OCFile file, int startPlaybackPosition, boolean autoplay) {
- Fragment mediaFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition, autoplay);
+ Fragment mediaFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition,
+ autoplay);
setSecondFragment(mediaFragment);
updateFragmentsVisibility(true);
- updateNavigationElementsInActionBar(file);
+ updateActionBarTitleAndHomeButton(file);
setFile(file);
}
* @param file {@link OCFile} to download and preview.
*/
public void startDownloadForPreview(OCFile file) {
- Fragment detailFragment = new FileDetailFragment(file, getAccount());
+ Fragment detailFragment = FileDetailFragment.newInstance(file, getAccount());
setSecondFragment(detailFragment);
mWaitingToPreview = file;
requestForDownload();
updateFragmentsVisibility(true);
- updateNavigationElementsInActionBar(file);
+ updateActionBarTitleAndHomeButton(file);
setFile(file);
}
private void sortByName(boolean ascending){
getListOfFilesFragment().sortByName(ascending);
}
+
+ public void allFilesOption() {
+ browseToRoot();
+ }
}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.activity;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorException;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources.NotFoundException;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v7.app.ActionBar;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.OwnCloudCredentials;
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.operations.CreateFolderOperation;
+import com.owncloud.android.operations.RefreshFolderOperation;
+import com.owncloud.android.syncadapter.FileSyncAdapter;
+import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
+import com.owncloud.android.ui.fragment.FileFragment;
+import com.owncloud.android.ui.fragment.OCFileListFragment;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.ErrorMessageAdapter;
+
+public class FolderPickerActivity extends FileActivity implements FileFragment.ContainerActivity,
+ OnClickListener, OnEnforceableRefreshListener {
+
+ public static final String EXTRA_FOLDER = UploadFilesActivity.class.getCanonicalName()
+ + ".EXTRA_FOLDER";
+ public static final String EXTRA_FILE = UploadFilesActivity.class.getCanonicalName()
+ + ".EXTRA_FILE";
+ //TODO: Think something better
+
+ private SyncBroadcastReceiver mSyncBroadcastReceiver;
+
+ private static final String TAG = FolderPickerActivity.class.getSimpleName();
+
+ private static final String TAG_LIST_OF_FOLDERS = "LIST_OF_FOLDERS";
+
+ private boolean mSyncInProgress = false;
+
+ protected Button mCancelBtn;
+ protected Button mChooseBtn;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ Log_OC.d(TAG, "onCreate() start");
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.files_folder_picker);
+
+ if (savedInstanceState == null) {
+ createFragments();
+ }
+
+ // sets callback listeners for UI elements
+ initControls();
+
+ // Action bar setup
+ ActionBar actionBar = getSupportActionBar();
+ actionBar.setDisplayShowTitleEnabled(true);
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ setSupportProgressBarIndeterminateVisibility(mSyncInProgress);
+ // always AFTER setContentView(...) ; to work around bug in its implementation
+
+ // sets message for empty list of folders
+ setBackgroundText();
+
+ Log_OC.d(TAG, "onCreate() end");
+
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
+ }
+
+ /**
+ * Called when the ownCloud {@link Account} associated to the Activity was just updated.
+ */
+ @Override
+ protected void onAccountSet(boolean stateWasRecovered) {
+ super.onAccountSet(stateWasRecovered);
+ if (getAccount() != null) {
+
+ updateFileFromDB();
+
+ OCFile folder = getFile();
+ if (folder == null || !folder.isFolder()) {
+ // fall back to root folder
+ setFile(getStorageManager().getFileByPath(OCFile.ROOT_PATH));
+ folder = getFile();
+ }
+
+ if (!stateWasRecovered) {
+ OCFileListFragment listOfFolders = getListOfFilesFragment();
+ listOfFolders.listDirectory(folder/*, false*/);
+
+ startSyncFolderOperation(folder, false);
+ }
+
+ updateNavigationElementsInActionBar();
+ }
+ }
+
+ private void createFragments() {
+ OCFileListFragment listOfFiles = new OCFileListFragment();
+ Bundle args = new Bundle();
+ args.putBoolean(OCFileListFragment.ARG_JUST_FOLDERS, true);
+ args.putBoolean(OCFileListFragment.ARG_ALLOW_CONTEXTUAL_ACTIONS, false);
+ listOfFiles.setArguments(args);
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.add(R.id.fragment_container, listOfFiles, TAG_LIST_OF_FOLDERS);
+ transaction.commit();
+ }
+
+ /**
+ * Show a text message on screen view for notifying user if content is
+ * loading or folder is empty
+ */
+ private void setBackgroundText() {
+ OCFileListFragment listFragment = getListOfFilesFragment();
+ if (listFragment != null) {
+ int message = R.string.file_list_loading;
+ if (!mSyncInProgress) {
+ // In case folder list is empty
+ message = R.string.file_list_empty_moving;
+ }
+ listFragment.setMessageForEmptyList(getString(message));
+ } else {
+ Log.e(TAG, "OCFileListFragment is null");
+ }
+ }
+
+ protected OCFileListFragment getListOfFilesFragment() {
+ Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag(FolderPickerActivity.TAG_LIST_OF_FOLDERS);
+ if (listOfFiles != null) {
+ return (OCFileListFragment)listOfFiles;
+ }
+ Log_OC.wtf(TAG, "Access to unexisting list of files fragment!!");
+ return null;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * Updates action bar and second fragment, if in dual pane mode.
+ */
+ @Override
+ public void onBrowsedDownTo(OCFile directory) {
+ setFile(directory);
+ updateNavigationElementsInActionBar();
+ // Sync Folder
+ startSyncFolderOperation(directory, false);
+
+ }
+
+
+ public void startSyncFolderOperation(OCFile folder, boolean ignoreETag) {
+ long currentSyncTime = System.currentTimeMillis();
+
+ mSyncInProgress = true;
+
+ // perform folder synchronization
+ RemoteOperation synchFolderOp = new RefreshFolderOperation( folder,
+ currentSyncTime,
+ false,
+ getFileOperationsHelper().isSharedSupported(),
+ ignoreETag,
+ getStorageManager(),
+ getAccount(),
+ getApplicationContext()
+ );
+ synchFolderOp.execute(getAccount(), this, null, null);
+
+ setSupportProgressBarIndeterminateVisibility(true);
+
+ setBackgroundText();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ Log_OC.e(TAG, "onResume() start");
+
+ // refresh list of files
+ refreshListOfFilesFragment();
+
+ // Listen for sync messages
+ IntentFilter syncIntentFilter = new IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START);
+ syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_END);
+ syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED);
+ syncIntentFilter.addAction(RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED);
+ syncIntentFilter.addAction(RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
+ mSyncBroadcastReceiver = new SyncBroadcastReceiver();
+ registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
+
+ Log_OC.d(TAG, "onResume() end");
+ }
+
+ @Override
+ protected void onPause() {
+ Log_OC.e(TAG, "onPause() start");
+ if (mSyncBroadcastReceiver != null) {
+ unregisterReceiver(mSyncBroadcastReceiver);
+ //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
+ mSyncBroadcastReceiver = null;
+ }
+
+ Log_OC.d(TAG, "onPause() end");
+ super.onPause();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.main_menu, menu);
+ menu.findItem(R.id.action_upload).setVisible(false);
+ menu.findItem(R.id.action_sort).setVisible(false);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ boolean retval = true;
+ switch (item.getItemId()) {
+ case R.id.action_create_dir: {
+ CreateFolderDialogFragment dialog =
+ CreateFolderDialogFragment.newInstance(getCurrentFolder());
+ dialog.show(
+ getSupportFragmentManager(),
+ CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT
+ );
+ break;
+ }
+ case android.R.id.home: {
+ OCFile currentDir = getCurrentFolder();
+ if(currentDir != null && currentDir.getParentId() != 0) {
+ onBackPressed();
+ }
+ break;
+ }
+ default:
+ retval = super.onOptionsItemSelected(item);
+ }
+ return retval;
+ }
+
+ protected OCFile getCurrentFolder() {
+ OCFile file = getFile();
+ if (file != null) {
+ if (file.isFolder()) {
+ return file;
+ } else if (getStorageManager() != null) {
+ String parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
+ return getStorageManager().getFileByPath(parentPath);
+ }
+ }
+ return null;
+ }
+
+ protected void refreshListOfFilesFragment() {
+ OCFileListFragment fileListFragment = getListOfFilesFragment();
+ if (fileListFragment != null) {
+ fileListFragment.listDirectory();
+ // TODO Enable when "On Device" is recovered ?
+ // fileListFragment.listDirectory(false);
+ }
+ }
+
+ public void browseToRoot() {
+ OCFileListFragment listOfFiles = getListOfFilesFragment();
+ if (listOfFiles != null) { // should never be null, indeed
+ OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
+ listOfFiles.listDirectory(root);
+ // TODO Enable when "On Device" is recovered ?
+ // listOfFiles.listDirectory(root, false);
+ setFile(listOfFiles.getCurrentFile());
+ updateNavigationElementsInActionBar();
+ startSyncFolderOperation(root, false);
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ OCFileListFragment listOfFiles = getListOfFilesFragment();
+ if (listOfFiles != null) { // should never be null, indeed
+ int levelsUp = listOfFiles.onBrowseUp();
+ if (levelsUp == 0) {
+ finish();
+ return;
+ }
+ setFile(listOfFiles.getCurrentFile());
+ updateNavigationElementsInActionBar();
+ }
+ }
+
+ protected void updateNavigationElementsInActionBar() {
+ ActionBar actionBar = getSupportActionBar();
+ OCFile currentDir = getCurrentFolder();
+ boolean atRoot = (currentDir == null || currentDir.getParentId() == 0);
+ actionBar.setDisplayHomeAsUpEnabled(!atRoot);
+ actionBar.setHomeButtonEnabled(!atRoot);
+ actionBar.setTitle(
+ atRoot
+ ? getString(R.string.default_display_name_for_root_folder)
+ : currentDir.getFileName()
+ );
+ }
+
+ /**
+ * Set per-view controllers
+ */
+ private void initControls(){
+ mCancelBtn = (Button) findViewById(R.id.folder_picker_btn_cancel);
+ mCancelBtn.setOnClickListener(this);
+ mChooseBtn = (Button) findViewById(R.id.folder_picker_btn_choose);
+ mChooseBtn.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mCancelBtn) {
+ finish();
+ } else if (v == mChooseBtn) {
+ Intent i = getIntent();
+ Parcelable targetFile = i.getParcelableExtra(FolderPickerActivity.EXTRA_FILE);
+
+ Intent data = new Intent();
+ data.putExtra(EXTRA_FOLDER, getCurrentFolder());
+ if (targetFile != null) {
+ data.putExtra(EXTRA_FILE, targetFile);
+ }
+ setResult(RESULT_OK, data);
+ finish();
+ }
+ }
+
+
+ @Override
+ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+ super.onRemoteOperationFinish(operation, result);
+
+ if (operation instanceof CreateFolderOperation) {
+ onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
+
+ }
+ }
+
+
+ /**
+ * Updates the view associated to the activity after the finish of an operation trying
+ * to create a new folder.
+ *
+ * @param operation Creation operation performed.
+ * @param result Result of the creation.
+ */
+ private void onCreateFolderOperationFinish(
+ CreateFolderOperation operation, RemoteOperationResult result
+ ) {
+
+ if (result.isSuccess()) {
+ dismissLoadingDialog();
+ refreshListOfFilesFragment();
+ } else {
+ dismissLoadingDialog();
+ try {
+ Toast msg = Toast.makeText(FolderPickerActivity.this,
+ ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+ Toast.LENGTH_LONG);
+ msg.show();
+
+ } catch (NotFoundException e) {
+ Log_OC.e(TAG, "Error while trying to show fail message " , e);
+ }
+ }
+ }
+
+
+
+ private class SyncBroadcastReceiver extends BroadcastReceiver {
+
+ /**
+ * {@link BroadcastReceiver} to enable syncing feedback in UI
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ String event = intent.getAction();
+ Log_OC.d(TAG, "Received broadcast " + event);
+ String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME);
+ String synchFolderRemotePath = intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH);
+ RemoteOperationResult synchResult = (RemoteOperationResult)intent.
+ getSerializableExtra(FileSyncAdapter.EXTRA_RESULT);
+ boolean sameAccount = (getAccount() != null &&
+ accountName.equals(getAccount().name) && getStorageManager() != null);
+
+ if (sameAccount) {
+
+ if (FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) {
+ mSyncInProgress = true;
+
+ } else {
+ OCFile currentFile = (getFile() == null) ? null :
+ getStorageManager().getFileByPath(getFile().getRemotePath());
+ OCFile currentDir = (getCurrentFolder() == null) ? null :
+ getStorageManager().getFileByPath(getCurrentFolder().getRemotePath());
+
+ if (currentDir == null) {
+ // current folder was removed from the server
+ Toast.makeText( FolderPickerActivity.this,
+ String.format(
+ getString(R.string.sync_current_folder_was_removed),
+ getCurrentFolder().getFileName()),
+ Toast.LENGTH_LONG)
+ .show();
+ browseToRoot();
+
+ } else {
+ if (currentFile == null && !getFile().isFolder()) {
+ // currently selected file was removed in the server, and now we know it
+ currentFile = currentDir;
+ }
+
+ if (synchFolderRemotePath != null && currentDir.getRemotePath().
+ equals(synchFolderRemotePath)) {
+ OCFileListFragment fileListFragment = getListOfFilesFragment();
+ if (fileListFragment != null) {
+ fileListFragment.listDirectory(currentDir);
+ // TODO Enable when "On Device" is recovered ?
+ // fileListFragment.listDirectory(currentDir, false);
+ }
+ }
+ setFile(currentFile);
+ }
+
+ mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) &&
+ !RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event));
+
+ if (RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
+ equals(event) &&
+ /// TODO refactor and make common
+ synchResult != null && !synchResult.isSuccess() &&
+ (synchResult.getCode() == ResultCode.UNAUTHORIZED ||
+ synchResult.isIdPRedirection() ||
+ (synchResult.isException() && synchResult.getException()
+ instanceof AuthenticatorException))) {
+
+ try {
+ OwnCloudClient client;
+ OwnCloudAccount ocAccount =
+ new OwnCloudAccount(getAccount(), context);
+ client = (OwnCloudClientManagerFactory.getDefaultSingleton().
+ removeClientFor(ocAccount));
+
+ if (client != null) {
+ OwnCloudCredentials cred = client.getCredentials();
+ if (cred != null) {
+ AccountManager am = AccountManager.get(context);
+ if (cred.authTokenExpires()) {
+ am.invalidateAuthToken(
+ getAccount().type,
+ cred.getAuthToken()
+ );
+ } else {
+ am.clearPassword(getAccount());
+ }
+ }
+ }
+ requestCredentialsUpdate();
+
+ } catch (AccountNotFoundException e) {
+ Log_OC.e(TAG, "Account " + getAccount() + " was removed!", e);
+ }
+
+ }
+ }
+ removeStickyBroadcast(intent);
+ Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
+ setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/);
+
+ setBackgroundText();
+
+ }
+
+ } catch (RuntimeException e) {
+ // avoid app crashes after changing the serial id of RemoteOperationResult
+ // in owncloud library with broadcast notifications pending to process
+ removeStickyBroadcast(intent);
+ }
+ }
+ }
+
+
+
+ /**
+ * Shows the information of the {@link OCFile} received as a
+ * parameter in the second fragment.
+ *
+ * @param file {@link OCFile} whose details will be shown
+ */
+ @Override
+ public void showDetails(OCFile file) {
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
+
+ }
+
+ @Override
+ public void onRefresh() {
+ refreshList(true);
+ }
+
+ @Override
+ public void onRefresh(boolean enforced) {
+ refreshList(enforced);
+ }
+
+ private void refreshList(boolean ignoreETag) {
+ OCFileListFragment listOfFiles = getListOfFilesFragment();
+ if (listOfFiles != null) {
+ OCFile folder = listOfFiles.getCurrentFile();
+ if (folder != null) {
+ startSyncFolderOperation(folder, ignoreETag);
+ }
+ }
+ }
+}
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.owncloud.android.R;
import com.owncloud.android.utils.DisplayUtils;
*
* Added to show explanations for notifications when the user clicks on them, and there no place
* better to show them.
- *
- * @author David A. Velasco
*/
-public class GenericExplanationActivity extends SherlockFragmentActivity {
+public class GenericExplanationActivity extends ActionBarActivity {
- public static final String EXTRA_LIST = GenericExplanationActivity.class.getCanonicalName() + ".EXTRA_LIST";
- public static final String EXTRA_LIST_2 = GenericExplanationActivity.class.getCanonicalName() + ".EXTRA_LIST_2";
- public static final String MESSAGE = GenericExplanationActivity.class.getCanonicalName() + ".MESSAGE";
+ public static final String EXTRA_LIST = GenericExplanationActivity.class.getCanonicalName() +
+ ".EXTRA_LIST";
+ public static final String EXTRA_LIST_2 = GenericExplanationActivity.class.getCanonicalName() +
+ ".EXTRA_LIST_2";
+ public static final String MESSAGE = GenericExplanationActivity.class.getCanonicalName() +
+ ".MESSAGE";
@Override
ListView listView = (ListView) findViewById(R.id.list);
if (list != null && list.size() > 0) {
- //ListAdapter adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
+ //ListAdapter adapter = new ArrayAdapter<String>(this,
+ // android.R.layout.simple_list_item_1, list);
ListAdapter adapter = new ExplanationListAdapterView(this, list, list2);
listView.setAdapter(adapter);
} else {
ArrayList<String> mList;
ArrayList<String> mList2;
- ExplanationListAdapterView(Context context, ArrayList<String> list, ArrayList<String> list2) {
+ ExplanationListAdapterView(Context context, ArrayList<String> list,
+ ArrayList<String> list2) {
super(context, android.R.layout.two_line_list_item, android.R.id.text1, list);
mList = list;
mList2 = list2;
public View getView (int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
if (view != null) {
- if (mList2 != null && mList2.size() > 0 && position >= 0 && position < mList2.size()) {
+ if (mList2 != null && mList2.size() > 0 && position >= 0 &&
+ position < mList2.size()) {
TextView text2 = (TextView) view.findViewById(android.R.id.text2);
if (text2 != null) {
text2.setText(mList2.get(position));
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import java.lang.reflect.Field;
import java.util.ArrayList;
+import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
+import android.widget.Toast;
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.SherlockFragmentActivity;
-import com.actionbarsherlock.view.MenuItem;
import com.owncloud.android.R;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.ui.dialog.LoadingDialog;
import com.owncloud.android.utils.FileStorageUtils;
-public class LogHistoryActivity extends SherlockFragmentActivity {
+public class LogHistoryActivity extends ActionBarActivity {
private static final String MAIL_ATTACHMENT_TYPE = "text/plain";
+ private static final String KEY_LOG_TEXT = "LOG_TEXT";
+
private static final String TAG = LogHistoryActivity.class.getSimpleName();
private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
private String mLogPath = FileStorageUtils.getLogPath();
private File logDIR = null;
+ private String mLogText;
@Override
setContentView(R.layout.log_send_file);
setTitle(getText(R.string.actionbar_logger));
- ActionBar actionBar = getSherlock().getActionBar();
+ ActionBar actionBar = getSupportActionBar();
actionBar.setIcon(DisplayUtils.getSeasonalIconId());
actionBar.setDisplayHomeAsUpEnabled(true);
Button deleteHistoryButton = (Button) findViewById(R.id.deleteLogHistoryButton);
Button sendHistoryButton = (Button) findViewById(R.id.sendLogHistoryButton);
+ TextView logTV = (TextView) findViewById(R.id.logTV);
deleteHistoryButton.setOnClickListener(new OnClickListener() {
}
});
- if (mLogPath != null) {
- logDIR = new File(mLogPath);
- }
-
- if (logDIR != null && logDIR.isDirectory()) {
- // Show a dialog while log data is being loaded
- showLoadingDialog();
-
- TextView logTV = (TextView) findViewById(R.id.logTV);
+ if (savedInstanceState == null) {
+ if (mLogPath != null) {
+ logDIR = new File(mLogPath);
+ }
- // Start a new thread that will load all the log data
- LoadingLogTask task = new LoadingLogTask(logTV);
- task.execute();
+ if (logDIR != null && logDIR.isDirectory()) {
+ // Show a dialog while log data is being loaded
+ showLoadingDialog();
+ // Start a new thread that will load all the log data
+ LoadingLogTask task = new LoadingLogTask(logTV);
+ task.execute();
+ }
+ } else {
+ mLogText = savedInstanceState.getString(KEY_LOG_TEXT);
+ logTV.setText(mLogText);
}
}
@Override
- public boolean onMenuItemSelected(int featureId, MenuItem item) {
- super.onMenuItemSelected(featureId, item);
+ public boolean onOptionsItemSelected(MenuItem item) {
+ super.onOptionsItemSelected(item);
switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- break;
- default:
- return false;
+ case android.R.id.home:
+ finish();
+ break;
+ default:
+ return false;
}
return true;
}
*/
private void sendMail() {
+ // For the moment we need to consider the possibility that setup.xml
+ // does not include the "mail_logger" entry. This block prevents that
+ // compilation fails in this case.
String emailAddress;
try {
Class<?> stringClass = R.string.class;
Field mailLoggerField = stringClass.getField("mail_logger");
- int emailAddressId = (Integer)mailLoggerField.get(null);
+ int emailAddressId = (Integer) mailLoggerField.get(null);
emailAddress = getString(emailAddressId);
-
} catch (Exception e) {
emailAddress = "";
}
-
+
ArrayList<Uri> uris = new ArrayList<Uri>();
// Convert from paths to Android friendly Parcelable Uri's
for (String file : Log_OC.getLogFileNames())
{
- if (new File(mLogPath + File.separator, file).exists()) {
- Uri u = Uri.parse("file://" + mLogPath + File.separator + file);
- uris.add(u);
+ File logFile = new File(mLogPath, file);
+ if (logFile.exists()) {
+ uris.add(Uri.fromFile(logFile));
}
}
Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
- // Explicitly only use Gmail to send
- intent.setClassName("com.google.android.gm","com.google.android.gm.ComposeActivityGmail");
- intent.putExtra(Intent.EXTRA_EMAIL, new String[]{ emailAddress });
- intent.putExtra(Intent.EXTRA_SUBJECT, getText(R.string.log_mail_subject));
+ intent.putExtra(Intent.EXTRA_EMAIL, emailAddress);
+ String subject = String.format(getString(R.string.log_send_mail_subject), getString(R.string.app_name));
+ intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setType(MAIL_ATTACHMENT_TYPE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
-
- if (intent.resolveActivity(getPackageManager()) != null) {
+ try {
startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(this, getString(R.string.log_send_no_mail_app), Toast.LENGTH_LONG).show();
+ Log_OC.i(TAG, "Could not find app for sending log history.");
}
+
}
/**
if (textViewReference != null && result != null) {
final TextView logTV = textViewReference.get();
if (logTV != null) {
- logTV.setText(result);
+ mLogText = result;
+ logTV.setText(mLogText);
dismissLoadingDialog();
}
}
loading.dismiss();
}
}
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ /// global state
+ outState.putString(KEY_LOG_TEXT, mLogText);
+ }
}
\ No newline at end of file
+++ /dev/null
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.ui.activity;
-
-import java.io.IOException;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources.NotFoundException;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.Toast;
-
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuInflater;
-import com.actionbarsherlock.view.MenuItem;
-import com.actionbarsherlock.view.Window;
-import com.owncloud.android.R;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.lib.common.OwnCloudAccount;
-import com.owncloud.android.lib.common.OwnCloudClient;
-import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
-import com.owncloud.android.lib.common.OwnCloudCredentials;
-import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
-import com.owncloud.android.lib.common.operations.RemoteOperation;
-import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
-import com.owncloud.android.operations.CreateFolderOperation;
-import com.owncloud.android.operations.SynchronizeFolderOperation;
-import com.owncloud.android.syncadapter.FileSyncAdapter;
-import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
-import com.owncloud.android.ui.fragment.FileFragment;
-import com.owncloud.android.ui.fragment.OCFileListFragment;
-import com.owncloud.android.utils.DisplayUtils;
-import com.owncloud.android.utils.ErrorMessageAdapter;
-import com.owncloud.android.lib.common.utils.Log_OC;
-
-public class MoveActivity extends HookActivity implements FileFragment.ContainerActivity,
- OnClickListener, OnEnforceableRefreshListener {
-
- public static final String EXTRA_CURRENT_FOLDER = UploadFilesActivity.class.getCanonicalName() + ".EXTRA_CURRENT_FOLDER";
- public static final String EXTRA_TARGET_FILE = UploadFilesActivity.class.getCanonicalName() + "EXTRA_TARGET_FILE";
-
- public static final int RESULT_OK_AND_MOVE = 1;
-
- private SyncBroadcastReceiver mSyncBroadcastReceiver;
-
- private static final String TAG = MoveActivity.class.getSimpleName();
-
- private static final String TAG_LIST_OF_FOLDERS = "LIST_OF_FOLDERS";
-
- private boolean mSyncInProgress = false;
-
- private Button mCancelBtn;
- private Button mChooseBtn;
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- Log_OC.d(TAG, "onCreate() start");
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
-
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.files_move);
-
- if (savedInstanceState == null) {
- createFragments();
- }
-
- // sets callback listeners for UI elements
- initControls();
-
- // Action bar setup
- ActionBar actionBar = getSupportActionBar();
- actionBar.setDisplayShowTitleEnabled(true);
- actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
- setSupportProgressBarIndeterminateVisibility(mSyncInProgress);
- // always AFTER setContentView(...) ; to work around bug in its implementation
-
- // sets message for empty list of folders
- setBackgroundText();
-
- Log_OC.d(TAG, "onCreate() end");
-
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- }
-
- /**
- * Called when the ownCloud {@link Account} associated to the Activity was just updated.
- */
- @Override
- protected void onAccountSet(boolean stateWasRecovered) {
- super.onAccountSet(stateWasRecovered);
- if (getAccount() != null) {
-
- updateFileFromDB();
-
- OCFile folder = getFile();
- if (folder == null || !folder.isFolder()) {
- // fall back to root folder
- setFile(getStorageManager().getFileByPath(OCFile.ROOT_PATH));
- folder = getFile();
- }
-
- if (!stateWasRecovered) {
- OCFileListFragment listOfFolders = getListOfFilesFragment();
- listOfFolders.listDirectory(folder);
-
- startSyncFolderOperation(folder, false);
- }
-
- updateNavigationElementsInActionBar();
- }
- }
-
- private void createFragments() {
- OCFileListFragment listOfFiles = new OCFileListFragment();
- Bundle args = new Bundle();
- args.putBoolean(OCFileListFragment.ARG_JUST_FOLDERS, true);
- args.putBoolean(OCFileListFragment.ARG_ALLOW_CONTEXTUAL_ACTIONS, false);
- listOfFiles.setArguments(args);
- FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
- transaction.add(R.id.fragment_container, listOfFiles, TAG_LIST_OF_FOLDERS);
- transaction.commit();
- }
-
- /**
- * Show a text message on screen view for notifying user if content is
- * loading or folder is empty
- */
- private void setBackgroundText() {
- OCFileListFragment listFragment = getListOfFilesFragment();
- if (listFragment != null) {
- int message = R.string.file_list_loading;
- if (!mSyncInProgress) {
- // In case folder list is empty
- message = R.string.file_list_empty_moving;
- }
- listFragment.setMessageForEmptyList(getString(message));
- } else {
- Log.e(TAG, "OCFileListFragment is null");
- }
- }
-
- private OCFileListFragment getListOfFilesFragment() {
- Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag(MoveActivity.TAG_LIST_OF_FOLDERS);
- if (listOfFiles != null) {
- return (OCFileListFragment)listOfFiles;
- }
- Log_OC.wtf(TAG, "Access to unexisting list of files fragment!!");
- return null;
- }
-
-
- /**
- * {@inheritDoc}
- *
- * Updates action bar and second fragment, if in dual pane mode.
- */
- @Override
- public void onBrowsedDownTo(OCFile directory) {
- setFile(directory);
- updateNavigationElementsInActionBar();
- // Sync Folder
- startSyncFolderOperation(directory, false);
-
- }
-
-
- public void startSyncFolderOperation(OCFile folder, boolean ignoreETag) {
- long currentSyncTime = System.currentTimeMillis();
-
- mSyncInProgress = true;
-
- // perform folder synchronization
- RemoteOperation synchFolderOp = new SynchronizeFolderOperation( folder,
- currentSyncTime,
- false,
- getFileOperationsHelper().isSharedSupported(),
- ignoreETag,
- getStorageManager(),
- getAccount(),
- getApplicationContext()
- );
- synchFolderOp.execute(getAccount(), this, null, null);
-
- setSupportProgressBarIndeterminateVisibility(true);
-
- setBackgroundText();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- Log_OC.e(TAG, "onResume() start");
-
- // refresh list of files
- refreshListOfFilesFragment();
-
- // Listen for sync messages
- IntentFilter syncIntentFilter = new IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START);
- syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_END);
- syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED);
- syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED);
- syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
- mSyncBroadcastReceiver = new SyncBroadcastReceiver();
- registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
-
- Log_OC.d(TAG, "onResume() end");
- }
-
- @Override
- protected void onPause() {
- Log_OC.e(TAG, "onPause() start");
- if (mSyncBroadcastReceiver != null) {
- unregisterReceiver(mSyncBroadcastReceiver);
- //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
- mSyncBroadcastReceiver = null;
- }
-
- Log_OC.d(TAG, "onPause() end");
- super.onPause();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getSherlock().getMenuInflater();
- inflater.inflate(R.menu.main_menu, menu);
- menu.findItem(R.id.action_upload).setVisible(false);
- menu.findItem(R.id.action_settings).setVisible(false);
- menu.findItem(R.id.action_sync_account).setVisible(false);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- boolean retval = true;
- switch (item.getItemId()) {
- case R.id.action_create_dir: {
- CreateFolderDialogFragment dialog =
- CreateFolderDialogFragment.newInstance(getCurrentFolder());
- dialog.show(
- getSupportFragmentManager(),
- CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT
- );
- break;
- }
- case android.R.id.home: {
- OCFile currentDir = getCurrentFolder();
- if(currentDir != null && currentDir.getParentId() != 0) {
- onBackPressed();
- }
- break;
- }
- default:
- retval = super.onOptionsItemSelected(item);
- }
- return retval;
- }
-
- private OCFile getCurrentFolder() {
- OCFile file = getFile();
- if (file != null) {
- if (file.isFolder()) {
- return file;
- } else if (getStorageManager() != null) {
- String parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
- return getStorageManager().getFileByPath(parentPath);
- }
- }
- return null;
- }
-
- protected void refreshListOfFilesFragment() {
- OCFileListFragment fileListFragment = getListOfFilesFragment();
- if (fileListFragment != null) {
- fileListFragment.listDirectory();
- }
- }
-
- public void browseToRoot() {
- OCFileListFragment listOfFiles = getListOfFilesFragment();
- if (listOfFiles != null) { // should never be null, indeed
- OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
- listOfFiles.listDirectory(root);
- setFile(listOfFiles.getCurrentFile());
- updateNavigationElementsInActionBar();
- startSyncFolderOperation(root, false);
- }
- }
-
- @Override
- public void onBackPressed() {
- OCFileListFragment listOfFiles = getListOfFilesFragment();
- if (listOfFiles != null) { // should never be null, indeed
- int levelsUp = listOfFiles.onBrowseUp();
- if (levelsUp == 0) {
- finish();
- return;
- }
- setFile(listOfFiles.getCurrentFile());
- updateNavigationElementsInActionBar();
- }
- }
-
- private void updateNavigationElementsInActionBar() {
- ActionBar actionBar = getSupportActionBar();
- OCFile currentDir = getCurrentFolder();
- boolean atRoot = (currentDir == null || currentDir.getParentId() == 0);
- actionBar.setDisplayHomeAsUpEnabled(!atRoot);
- actionBar.setHomeButtonEnabled(!atRoot);
- actionBar.setTitle(
- atRoot
- ? getString(R.string.default_display_name_for_root_folder)
- : currentDir.getFileName()
- );
- }
-
- /**
- * Set per-view controllers
- */
- private void initControls(){
- mCancelBtn = (Button) findViewById(R.id.move_files_btn_cancel);
- mCancelBtn.setOnClickListener(this);
- mChooseBtn = (Button) findViewById(R.id.move_files_btn_choose);
- mChooseBtn.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- if (v == mCancelBtn) {
- finish();
- } else if (v == mChooseBtn) {
- Intent i = getIntent();
- OCFile targetFile = (OCFile) i.getParcelableExtra(MoveActivity.EXTRA_TARGET_FILE);
-
- Intent data = new Intent();
- data.putExtra(EXTRA_CURRENT_FOLDER, getCurrentFolder());
- data.putExtra(EXTRA_TARGET_FILE, targetFile);
- setResult(RESULT_OK_AND_MOVE, data);
- finish();
- }
- }
-
-
- @Override
- public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
- super.onRemoteOperationFinish(operation, result);
-
- if (operation instanceof CreateFolderOperation) {
- onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
-
- }
- }
-
-
- /**
- * Updates the view associated to the activity after the finish of an operation trying
- * to create a new folder.
- *
- * @param operation Creation operation performed.
- * @param result Result of the creation.
- */
- private void onCreateFolderOperationFinish(
- CreateFolderOperation operation, RemoteOperationResult result
- ) {
-
- if (result.isSuccess()) {
- dismissLoadingDialog();
- refreshListOfFilesFragment();
- } else {
- dismissLoadingDialog();
- try {
- Toast msg = Toast.makeText(MoveActivity.this,
- ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
- Toast.LENGTH_LONG);
- msg.show();
-
- } catch (NotFoundException e) {
- Log_OC.e(TAG, "Error while trying to show fail message " , e);
- }
- }
- }
-
-
-
- private class SyncBroadcastReceiver extends BroadcastReceiver {
-
- /**
- * {@link BroadcastReceiver} to enable syncing feedback in UI
- */
- @Override
- public void onReceive(Context context, Intent intent) {
- try {
- String event = intent.getAction();
- Log_OC.d(TAG, "Received broadcast " + event);
- String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME);
- String synchFolderRemotePath = intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH);
- RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncAdapter.EXTRA_RESULT);
- boolean sameAccount = (getAccount() != null && accountName.equals(getAccount().name) && getStorageManager() != null);
-
- if (sameAccount) {
-
- if (FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) {
- mSyncInProgress = true;
-
- } else {
- OCFile currentFile = (getFile() == null) ? null : getStorageManager().getFileByPath(getFile().getRemotePath());
- OCFile currentDir = (getCurrentFolder() == null) ? null : getStorageManager().getFileByPath(getCurrentFolder().getRemotePath());
-
- if (currentDir == null) {
- // current folder was removed from the server
- Toast.makeText( MoveActivity.this,
- String.format(getString(R.string.sync_current_folder_was_removed), getCurrentFolder().getFileName()),
- Toast.LENGTH_LONG)
- .show();
- browseToRoot();
-
- } else {
- if (currentFile == null && !getFile().isFolder()) {
- // currently selected file was removed in the server, and now we know it
- currentFile = currentDir;
- }
-
- if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) {
- OCFileListFragment fileListFragment = getListOfFilesFragment();
- if (fileListFragment != null) {
- fileListFragment.listDirectory(currentDir);
- }
- }
- setFile(currentFile);
- }
-
- mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event));
-
- if (SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
- equals(event) &&
- /// TODO refactor and make common
- synchResult != null && !synchResult.isSuccess() &&
- (synchResult.getCode() == ResultCode.UNAUTHORIZED ||
- synchResult.isIdPRedirection() ||
- (synchResult.isException() && synchResult.getException()
- instanceof AuthenticatorException))) {
-
- OwnCloudClient client = null;
- try {
- OwnCloudAccount ocAccount =
- new OwnCloudAccount(getAccount(), context);
- client = (OwnCloudClientManagerFactory.getDefaultSingleton().
- removeClientFor(ocAccount));
- // TODO get rid of these exceptions
- } catch (AccountNotFoundException e) {
- e.printStackTrace();
- } catch (AuthenticatorException e) {
- e.printStackTrace();
- } catch (OperationCanceledException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- if (client != null) {
- OwnCloudCredentials cred = client.getCredentials();
- if (cred != null) {
- AccountManager am = AccountManager.get(context);
- if (cred.authTokenExpires()) {
- am.invalidateAuthToken(
- getAccount().type,
- cred.getAuthToken()
- );
- } else {
- am.clearPassword(getAccount());
- }
- }
- }
-
- requestCredentialsUpdate();
-
- }
- }
- removeStickyBroadcast(intent);
- Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
- setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/);
-
- setBackgroundText();
-
- }
-
- } catch (RuntimeException e) {
- // avoid app crashes after changing the serial id of RemoteOperationResult
- // in owncloud library with broadcast notifications pending to process
- removeStickyBroadcast(intent);
- }
- }
- }
-
-
-
- /**
- * Shows the information of the {@link OCFile} received as a
- * parameter in the second fragment.
- *
- * @param file {@link OCFile} whose details will be shown
- */
- @Override
- public void showDetails(OCFile file) {
-
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
-
- }
-
- @Override
- public void onRefresh() {
- refreshList(true);
- }
-
- @Override
- public void onRefresh(boolean enforced) {
- refreshList(enforced);
- }
-
- private void refreshList(boolean ignoreETag) {
- OCFileListFragment listOfFiles = getListOfFilesFragment();
- if (listOfFiles != null) {
- OCFile folder = listOfFiles.getCurrentFile();
- if (folder != null) {
- startSyncFolderOperation(folder, ignoreETag);
- }
- }
- }
-}
+
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
package com.owncloud.android.ui.activity;
import android.support.v4.widget.SwipeRefreshLayout;
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author masensio
+ * @author David A. Velasco
+ * Copyright (C) 2011 Bartek Przybylski
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.activity;
+
+import java.util.Arrays;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.owncloud.android.R;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.utils.DisplayUtils;
+
+public class PassCodeActivity extends ActionBarActivity {
+
+
+ private static final String TAG = PassCodeActivity.class.getSimpleName();
+
+ public final static String ACTION_ENABLE = PassCodeActivity.class.getCanonicalName() +
+ ".ENABLE";
+ public final static String ACTION_DISABLE = PassCodeActivity.class.getCanonicalName() +
+ ".DISABLE";
+ public final static String ACTION_REQUEST = PassCodeActivity.class.getCanonicalName() +
+ ".REQUEST";
+
+ private Button mBCancel;
+ private TextView mPassCodeHdr;
+ private TextView mPassCodeHdrExplanation;
+ private EditText[] mPassCodeEditTexts = new EditText[4];
+
+ private String [] mPassCodeDigits = {"","","",""};
+ private static String KEY_PASSCODE_DIGITS = "PASSCODE_DIGITS";
+ private boolean mConfirmingPassCode = false;
+ private static String KEY_CONFIRMING_PASSCODE = "CONFIRMING_PASSCODE";
+
+ private boolean mBChange = true; // to control that only one blocks jump
+
+
+ /**
+ * Initializes the activity.
+ *
+ * An intent with a valid ACTION is expected; if none is found, an
+ * {@link IllegalArgumentException} will be thrown.
+ *
+ * @param savedInstanceState Previously saved state - irrelevant in this case
+ */
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.passcodelock);
+
+ mBCancel = (Button) findViewById(R.id.cancel);
+ mPassCodeHdr = (TextView) findViewById(R.id.header);
+ mPassCodeHdrExplanation = (TextView) findViewById(R.id.explanation);
+ mPassCodeEditTexts[0] = (EditText) findViewById(R.id.txt0);
+ mPassCodeEditTexts[0].requestFocus();
+ getWindow().setSoftInputMode(
+ android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ mPassCodeEditTexts[1] = (EditText) findViewById(R.id.txt1);
+ mPassCodeEditTexts[2] = (EditText) findViewById(R.id.txt2);
+ mPassCodeEditTexts[3] = (EditText) findViewById(R.id.txt3);
+
+ if (ACTION_REQUEST.equals(getIntent().getAction())) {
+ /// this is a pass code request; the user has to input the right value
+ mPassCodeHdr.setText(R.string.pass_code_enter_pass_code);
+ mPassCodeHdrExplanation.setVisibility(View.INVISIBLE);
+ setCancelButtonEnabled(false); // no option to cancel
+
+ } else if (ACTION_ENABLE.equals(getIntent().getAction())) {
+ if (savedInstanceState != null) {
+ mConfirmingPassCode = savedInstanceState.getBoolean(PassCodeActivity.KEY_CONFIRMING_PASSCODE);
+ mPassCodeDigits = savedInstanceState.getStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS);
+ }
+ if(mConfirmingPassCode){
+ //the app was in the passcodeconfirmation
+ requestPassCodeConfirmation();
+ }else{
+ /// pass code preference has just been activated in Preferences;
+ // will receive and confirm pass code value
+ mPassCodeHdr.setText(R.string.pass_code_configure_your_pass_code);
+ //mPassCodeHdr.setText(R.string.pass_code_enter_pass_code);
+ // TODO choose a header, check iOS
+ mPassCodeHdrExplanation.setVisibility(View.VISIBLE);
+ setCancelButtonEnabled(true);
+ }
+
+ } else if (ACTION_DISABLE.equals(getIntent().getAction())) {
+ /// pass code preference has just been disabled in Preferences;
+ // will confirm user knows pass code, then remove it
+ mPassCodeHdr.setText(R.string.pass_code_remove_your_pass_code);
+ mPassCodeHdrExplanation.setVisibility(View.INVISIBLE);
+ setCancelButtonEnabled(true);
+
+ } else {
+ throw new IllegalArgumentException("A valid ACTION is needed in the Intent passed to "
+ + TAG);
+ }
+
+ setTextListeners();
+
+ ActionBar actionBar = getSupportActionBar();
+ actionBar.setIcon(DisplayUtils.getSeasonalIconId());
+ }
+
+
+ /**
+ * Enables or disables the cancel button to allow the user interrupt the ACTION
+ * requested to the activity.
+ *
+ * @param enabled 'True' makes the cancel button available, 'false' hides it.
+ */
+ protected void setCancelButtonEnabled(boolean enabled){
+ if(enabled){
+ mBCancel.setVisibility(View.VISIBLE);
+ mBCancel.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ revertActionAndExit();
+ }
+ });
+ } else {
+ mBCancel.setVisibility(View.GONE);
+ mBCancel.setVisibility(View.INVISIBLE);
+ mBCancel.setOnClickListener(null);
+ }
+ }
+
+
+ /**
+ * Binds the appropiate listeners to the input boxes receiving each digit of the pass code.
+ */
+ protected void setTextListeners() {
+
+ /// First input field
+ mPassCodeEditTexts[0].addTextChangedListener(new PassCodeDigitTextWatcher(0, false));
+
+
+ /*------------------------------------------------
+ * SECOND BOX
+ -------------------------------------------------*/
+ mPassCodeEditTexts[1].addTextChangedListener(new PassCodeDigitTextWatcher(1, false));
+
+ mPassCodeEditTexts[1].setOnKeyListener(new View.OnKeyListener() {
+
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) { // TODO WIP: event should be
+ // used to control what's exactly happening with DEL, not any custom field...
+ mPassCodeEditTexts[0].setText("");
+ mPassCodeEditTexts[0].requestFocus();
+ if (!mConfirmingPassCode)
+ mPassCodeDigits[0] = "";
+ mBChange = false;
+
+ } else if (!mBChange) {
+ mBChange = true;
+ }
+ return false;
+ }
+ });
+
+ mPassCodeEditTexts[1].setOnFocusChangeListener(new View.OnFocusChangeListener() {
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ /// TODO WIP: should take advantage of hasFocus to reduce processing
+ if (mPassCodeEditTexts[0].getText().toString().equals("")) { // TODO WIP validation
+ // could be done in a global way, with a single OnFocusChangeListener for all the
+ // input fields
+ mPassCodeEditTexts[0].requestFocus();
+ }
+ }
+ });
+
+
+ /*------------------------------------------------
+ * THIRD BOX
+ -------------------------------------------------*/
+ mPassCodeEditTexts[2].addTextChangedListener(new PassCodeDigitTextWatcher(2, false));
+
+ mPassCodeEditTexts[2].setOnKeyListener(new View.OnKeyListener() {
+
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
+ mPassCodeEditTexts[1].requestFocus();
+ if (!mConfirmingPassCode)
+ mPassCodeDigits[1] = "";
+ mPassCodeEditTexts[1].setText("");
+ mBChange = false;
+
+ } else if (!mBChange) {
+ mBChange = true;
+
+ }
+ return false;
+ }
+ });
+
+ mPassCodeEditTexts[2].setOnFocusChangeListener(new View.OnFocusChangeListener() {
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (mPassCodeEditTexts[0].getText().toString().equals("")) {
+ mPassCodeEditTexts[0].requestFocus();
+ } else if (mPassCodeEditTexts[1].getText().toString().equals("")) {
+ mPassCodeEditTexts[1].requestFocus();
+ }
+ }
+ });
+
+
+ /*------------------------------------------------
+ * FOURTH BOX
+ -------------------------------------------------*/
+ mPassCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true));
+
+ mPassCodeEditTexts[3].setOnKeyListener(new View.OnKeyListener() {
+
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
+ mPassCodeEditTexts[2].requestFocus();
+ if (!mConfirmingPassCode)
+ mPassCodeDigits[2] = "";
+ mPassCodeEditTexts[2].setText("");
+ mBChange = false;
+
+ } else if (!mBChange) {
+ mBChange = true;
+ }
+ return false;
+ }
+ });
+
+ mPassCodeEditTexts[3].setOnFocusChangeListener(new View.OnFocusChangeListener() {
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+
+ if (mPassCodeEditTexts[0].getText().toString().equals("")) {
+ mPassCodeEditTexts[0].requestFocus();
+ } else if (mPassCodeEditTexts[1].getText().toString().equals("")) {
+ mPassCodeEditTexts[1].requestFocus();
+ } else if (mPassCodeEditTexts[2].getText().toString().equals("")) {
+ mPassCodeEditTexts[2].requestFocus();
+ }
+
+ }
+ });
+
+ } // end setTextListener
+
+
+ /**
+ * Processes the pass code entered by the user just after the last digit was in.
+ *
+ * Takes into account the action requested to the activity, the currently saved pass code and
+ * the previously typed pass code, if any.
+ */
+ private void processFullPassCode() {
+ if (ACTION_REQUEST.equals(getIntent().getAction())) {
+ if (checkPassCode()) {
+ /// pass code accepted in request, user is allowed to access the app
+ finish();
+
+ } else {
+ showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code,
+ View.INVISIBLE);
+ }
+
+ } else if (ACTION_DISABLE.equals(getIntent().getAction())) {
+ if (checkPassCode()) {
+ /// pass code accepted when disabling, pass code is removed
+ SharedPreferences.Editor appPrefs = PreferenceManager
+ .getDefaultSharedPreferences(getApplicationContext()).edit();
+ appPrefs.putBoolean("set_pincode", false); // TODO remove; this should be
+ // unnecessary, was done before entering in the activity
+ appPrefs.commit();
+
+ Toast.makeText(PassCodeActivity.this, R.string.pass_code_removed, Toast.LENGTH_LONG).show();
+ finish();
+
+ } else {
+ showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code,
+ View.INVISIBLE);
+ }
+
+ } else if (ACTION_ENABLE.equals(getIntent().getAction())) {
+ /// enabling pass code
+ if (!mConfirmingPassCode) {
+ requestPassCodeConfirmation();
+
+ } else if (confirmPassCode()) {
+ /// confirmed: user typed the same pass code twice
+ savePassCodeAndExit();
+
+ } else {
+ showErrorAndRestart(
+ R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE
+ );
+ }
+ }
+ }
+
+
+ private void showErrorAndRestart(int errorMessage, int headerMessage,
+ int explanationVisibility) {
+ Arrays.fill(mPassCodeDigits, null);
+ CharSequence errorSeq = getString(errorMessage);
+ Toast.makeText(this, errorSeq, Toast.LENGTH_LONG).show();
+ mPassCodeHdr.setText(headerMessage); // TODO check if really needed
+ mPassCodeHdrExplanation.setVisibility(explanationVisibility); // TODO check if really needed
+ clearBoxes();
+ }
+
+
+ /**
+ * Ask to the user for retyping the pass code just entered before saving it as the current pass
+ * code.
+ */
+ protected void requestPassCodeConfirmation(){
+ clearBoxes();
+ mPassCodeHdr.setText(R.string.pass_code_reenter_your_pass_code);
+ mPassCodeHdrExplanation.setVisibility(View.INVISIBLE);
+ mConfirmingPassCode = true;
+ }
+
+ /**
+ * Compares pass code entered by the user with the value currently saved in the app.
+ *
+ * @return 'True' if entered pass code equals to the saved one.
+ */
+ protected boolean checkPassCode(){
+ SharedPreferences appPrefs = PreferenceManager
+ .getDefaultSharedPreferences(getApplicationContext());
+
+ String savedPassCodeDigits[] = new String[4];
+ savedPassCodeDigits[0] = appPrefs.getString("PrefPinCode1", null);
+ savedPassCodeDigits[1] = appPrefs.getString("PrefPinCode2", null);
+ savedPassCodeDigits[2] = appPrefs.getString("PrefPinCode3", null);
+ savedPassCodeDigits[3] = appPrefs.getString("PrefPinCode4", null);
+
+ boolean result = true;
+ for (int i = 0; i < mPassCodeDigits.length && result; i++) {
+ result = result && (mPassCodeDigits[i] != null) &&
+ mPassCodeDigits[i].equals(savedPassCodeDigits[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Compares pass code retyped by the user in the input fields with the value entered just
+ * before.
+ *
+ * @return 'True' if retyped pass code equals to the entered before.
+ */
+ protected boolean confirmPassCode(){
+ mConfirmingPassCode = false;
+
+ boolean result = true;
+ for (int i = 0; i < mPassCodeEditTexts.length && result; i++) {
+ result = result &&
+ ((mPassCodeEditTexts[i].getText().toString()).equals(mPassCodeDigits[i]));
+ }
+ return result;
+ }
+
+ /**
+ * Sets the input fields to empty strings and puts the focus on the first one.
+ */
+ protected void clearBoxes(){
+ for (int i=0; i < mPassCodeEditTexts.length; i++) {
+ mPassCodeEditTexts[i].setText("");
+ }
+ mPassCodeEditTexts[0].requestFocus();
+ }
+
+ /**
+ * Overrides click on the BACK arrow to correctly cancel ACTION_ENABLE or ACTION_DISABLE, while
+ * preventing than ACTION_REQUEST may be worked around.
+ *
+ * @param keyCode Key code of the key that triggered the down event.
+ * @param event Event triggered.
+ * @return 'True' when the key event was processed by this method.
+ */
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event){
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount()== 0){
+ if (ACTION_ENABLE.equals(getIntent().getAction()) ||
+ ACTION_DISABLE.equals(getIntent().getAction())) {
+ revertActionAndExit();
+ }
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ /**
+ * Saves the pass code input by the user as the current pass code.
+ */
+ protected void savePassCodeAndExit() {
+ SharedPreferences.Editor appPrefs = PreferenceManager
+ .getDefaultSharedPreferences(getApplicationContext()).edit();
+
+ appPrefs.putString("PrefPinCode1", mPassCodeDigits[0]);
+ appPrefs.putString("PrefPinCode2", mPassCodeDigits[1]);
+ appPrefs.putString("PrefPinCode3", mPassCodeDigits[2]);
+ appPrefs.putString("PrefPinCode4", mPassCodeDigits[3]);
+ appPrefs.putBoolean("set_pincode", true); /// TODO remove; unnecessary,
+ // Preferences did it before entering here
+ appPrefs.commit();
+
+ Toast.makeText(this, R.string.pass_code_stored, Toast.LENGTH_LONG).show();
+ finish();
+ }
+
+ /**
+ * Cancellation of ACTION_ENABLE or ACTION_DISABLE; reverts the enable or disable action done by
+ * {@link Preferences}, then finishes.
+ */
+ protected void revertActionAndExit() {
+ SharedPreferences.Editor appPrefsE = PreferenceManager
+ .getDefaultSharedPreferences(getApplicationContext()).edit();
+
+ SharedPreferences appPrefs = PreferenceManager
+ .getDefaultSharedPreferences(getApplicationContext());
+
+ boolean state = appPrefs.getBoolean("set_pincode", false);
+ appPrefsE.putBoolean("set_pincode", !state);
+ // TODO WIP: this is reverting the value of the preference because it was changed BEFORE
+ // entering
+ // TODO in this activity; was the PreferenceCheckBox in the caller who did it
+ appPrefsE.commit();
+ finish();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(PassCodeActivity.KEY_CONFIRMING_PASSCODE, mConfirmingPassCode);
+ outState.putStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS, mPassCodeDigits);
+ }
+
+
+ private class PassCodeDigitTextWatcher implements TextWatcher {
+
+ private int mIndex = -1;
+ private boolean mLastOne = false;
+
+ /**
+ * Constructor
+ *
+ * @param index Position in the pass code of the input field that will be bound to
+ * this watcher.
+ * @param lastOne 'True' means that watcher corresponds to the last position of the
+ * pass code.
+ */
+ public PassCodeDigitTextWatcher(int index, boolean lastOne) {
+ mIndex = index;
+ mLastOne = lastOne;
+ if (mIndex < 0) {
+ throw new IllegalArgumentException(
+ "Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() +
+ " constructor"
+ );
+ }
+ }
+
+ private int next() {
+ return mLastOne ? 0 : mIndex + 1;
+ }
+
+ /**
+ * Performs several actions when the user types a digit in an input field:
+ * - saves the input digit to the state of the activity; this will allow retyping the
+ * pass code to confirm it.
+ * - moves the focus automatically to the next field
+ * - for the last field, triggers the processing of the full pass code
+ *
+ * @param s
+ */
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (s.length() > 0) {
+ if (!mConfirmingPassCode) {
+ mPassCodeDigits[mIndex] = mPassCodeEditTexts[mIndex].getText().toString();
+ }
+ mPassCodeEditTexts[next()].requestFocus();
+
+ if (mLastOne) {
+ processFullPassCode();
+ }
+
+ } else {
+ Log_OC.d(TAG, "Text box " + mIndex + " was cleaned");
+ }
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // nothing to do
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ // nothing to do
+ }
+
+ }
+
+
+}
+++ /dev/null
-/* 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 version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package com.owncloud.android.ui.activity;
-
-import java.util.Arrays;
-
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.SherlockFragmentActivity;
-import com.owncloud.android.R;
-import com.owncloud.android.utils.DisplayUtils;
-
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnKeyListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
-
-public class PinCodeActivity extends SherlockFragmentActivity {
-
-
- public final static String EXTRA_ACTIVITY = "com.owncloud.android.ui.activity.PinCodeActivity.ACTIVITY";
- public final static String EXTRA_NEW_STATE = "com.owncloud.android.ui.activity.PinCodeActivity.NEW_STATE";
-
- private Button mBCancel;
- private TextView mPinHdr;
- private TextView mPinHdrExplanation;
- private EditText mText1;
- private EditText mText2;
- private EditText mText3;
- private EditText mText4;
-
- private String [] mTempText ={"","","",""};
-
- private String mActivity;
-
- private boolean mConfirmingPinCode = false;
- private boolean mPinCodeChecked = false;
- private boolean mNewPasswordEntered = false;
- private boolean mBChange = true; // to control that only one blocks jump
- //private int mTCounter ; // Count the number of attempts an user could introduce the PIN code
-
-
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.pincodelock);
-
- Intent intent = getIntent();
- mActivity = intent.getStringExtra(EXTRA_ACTIVITY);
-
- mBCancel = (Button) findViewById(R.id.cancel);
- mPinHdr = (TextView) findViewById(R.id.pinHdr);
- mPinHdrExplanation = (TextView) findViewById(R.id.pinHdrExpl);
- mText1 = (EditText) findViewById(R.id.txt1);
- mText1.requestFocus();
- getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
- mText2 = (EditText) findViewById(R.id.txt2);
- mText3 = (EditText) findViewById(R.id.txt3);
- mText4 = (EditText) findViewById(R.id.txt4);
-
- SharedPreferences appPrefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
-
- // Not PIN Code defined yet.
- // In a previous version settings is allow from start
- if ( (appPrefs.getString("PrefPinCode1", null) == null ) ){
- setChangePincodeView(true);
- mPinCodeChecked = true;
- mNewPasswordEntered = true;
-
- }else{
-
- if (appPrefs.getBoolean("set_pincode", false)){
- // pincode activated
- if (mActivity.equals("preferences")){
- // PIN has been activated yet
- mPinHdr.setText(R.string.pincode_configure_your_pin);
- mPinHdrExplanation.setVisibility(View.VISIBLE);
- mPinCodeChecked = true ; // No need to check it
- setChangePincodeView(true);
- }else{
- // PIN active
- mBCancel.setVisibility(View.INVISIBLE);
- mBCancel.setVisibility(View.GONE);
- mPinHdr.setText(R.string.pincode_enter_pin_code);
- mPinHdrExplanation.setVisibility(View.INVISIBLE);
- setChangePincodeView(false);
- }
-
- }else {
- // pincode removal
- mPinHdr.setText(R.string.pincode_remove_your_pincode);
- mPinHdrExplanation.setVisibility(View.INVISIBLE);
- mPinCodeChecked = false;
- setChangePincodeView(true);
- }
-
- }
- setTextListeners();
-
- ActionBar actionBar = getSupportActionBar();
- actionBar.setIcon(DisplayUtils.getSeasonalIconId());
- }
-
-
-
- protected void setInitVars(){
- mConfirmingPinCode = false;
- mPinCodeChecked = false;
- mNewPasswordEntered = false;
-
- }
-
- protected void setInitView(){
- mBCancel.setVisibility(View.INVISIBLE);
- mBCancel.setVisibility(View.GONE);
- mPinHdr.setText(R.string.pincode_enter_pin_code);
- mPinHdrExplanation.setVisibility(View.INVISIBLE);
- }
-
-
- protected void setChangePincodeView(boolean state){
-
- if(state){
- mBCancel.setVisibility(View.VISIBLE);
- mBCancel.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
-
- SharedPreferences.Editor appPrefsE = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()).edit();
-
- SharedPreferences appPrefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- boolean state = appPrefs.getBoolean("set_pincode", false);
- appPrefsE.putBoolean("set_pincode",!state);
- appPrefsE.commit();
- setInitVars();
- finish();
- }
- });
- }
-
- }
-
-
-
- /*
- *
- */
- protected void setTextListeners(){
-
- /*------------------------------------------------
- * FIRST BOX
- -------------------------------------------------*/
-
- mText1.addTextChangedListener(new TextWatcher() {
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before,
- int count) {
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- if (s.length() > 0) {
- if (!mConfirmingPinCode){
- mTempText[0] = mText1.getText().toString();
-
- }
- mText2.requestFocus();
- }
- }
- });
-
-
-
- /*------------------------------------------------
- * SECOND BOX
- -------------------------------------------------*/
- mText2.addTextChangedListener(new TextWatcher() {
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before,
- int count) {
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- if (s.length() > 0) {
- if (!mConfirmingPinCode){
- mTempText[1] = mText2.getText().toString();
- }
-
- mText3.requestFocus();
- }
- }
- });
-
- mText2.setOnKeyListener(new OnKeyListener() {
-
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
-
- mText1.setText("");
- mText1.requestFocus();
- if (!mConfirmingPinCode)
- mTempText[0] = "";
- mBChange= false;
-
- }else if(!mBChange){
- mBChange=true;
-
- }
- return false;
- }
- });
-
- mText2.setOnFocusChangeListener(new OnFocusChangeListener() {
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mText2.setCursorVisible(true);
- if (mText1.getText().toString().equals("")){
- mText2.setSelected(false);
- mText2.setCursorVisible(false);
- mText1.requestFocus();
- mText1.setSelected(true);
- mText1.setSelection(0);
- }
-
- }
- });
-
-
- /*------------------------------------------------
- * THIRD BOX
- -------------------------------------------------*/
- mText3.addTextChangedListener(new TextWatcher() {
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before,
- int count) {
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- if (s.length() > 0) {
- if (!mConfirmingPinCode){
- mTempText[2] = mText3.getText().toString();
- }
- mText4.requestFocus();
- }
- }
- });
-
- mText3.setOnKeyListener(new OnKeyListener() {
-
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
- mText2.requestFocus();
- if (!mConfirmingPinCode)
- mTempText[1] = "";
- mText2.setText("");
- mBChange= false;
-
- }else if(!mBChange){
- mBChange=true;
-
- }
- return false;
- }
- });
-
- mText3.setOnFocusChangeListener(new OnFocusChangeListener() {
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mText3.setCursorVisible(true);
- if (mText1.getText().toString().equals("")){
- mText3.setSelected(false);
- mText3.setCursorVisible(false);
- mText1.requestFocus();
- mText1.setSelected(true);
- mText1.setSelection(0);
- }else if (mText2.getText().toString().equals("")){
- mText3.setSelected(false);
- mText3.setCursorVisible(false);
- mText2.requestFocus();
- mText2.setSelected(true);
- mText2.setSelection(0);
- }
-
- }
- });
-
- /*------------------------------------------------
- * FOURTH BOX
- -------------------------------------------------*/
- mText4.addTextChangedListener(new TextWatcher() {
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before,
- int count) {
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- if (s.length() > 0) {
-
- if (!mConfirmingPinCode){
- mTempText[3] = mText4.getText().toString();
- }
- mText1.requestFocus();
-
- if (!mPinCodeChecked){
- mPinCodeChecked = checkPincode();
- }
-
- if (mPinCodeChecked &&
- ( mActivity.equals("FileDisplayActivity") || mActivity.equals("PreviewImageActivity") ) ){
- finish();
- } else if (mPinCodeChecked){
-
- Intent intent = getIntent();
- String newState = intent.getStringExtra(EXTRA_NEW_STATE);
-
- if (newState.equals("false")){
- SharedPreferences.Editor appPrefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()).edit();
- appPrefs.putBoolean("set_pincode",false);
- appPrefs.commit();
-
- setInitVars();
- pinCodeEnd(false);
-
- }else{
-
- if (!mConfirmingPinCode){
- pinCodeChangeRequest();
-
- } else {
- confirmPincode();
- }
- }
-
-
- }
- }
- }
- });
-
-
-
- mText4.setOnKeyListener(new OnKeyListener() {
-
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
- mText3.requestFocus();
- if (!mConfirmingPinCode)
- mTempText[2]="";
- mText3.setText("");
- mBChange= false;
-
- }else if(!mBChange){
- mBChange=true;
- }
- return false;
- }
- });
-
- mText4.setOnFocusChangeListener(new OnFocusChangeListener() {
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mText4.setCursorVisible(true);
-
- if (mText1.getText().toString().equals("")){
- mText4.setSelected(false);
- mText4.setCursorVisible(false);
- mText1.requestFocus();
- mText1.setSelected(true);
- mText1.setSelection(0);
- }else if (mText2.getText().toString().equals("")){
- mText4.setSelected(false);
- mText4.setCursorVisible(false);
- mText2.requestFocus();
- mText2.setSelected(true);
- mText2.setSelection(0);
- }else if (mText3.getText().toString().equals("")){
- mText4.setSelected(false);
- mText4.setCursorVisible(false);
- mText3.requestFocus();
- mText3.setSelected(true);
- mText3.setSelection(0);
- }
-
- }
- });
-
-
-
- } // end setTextListener
-
-
- protected void pinCodeChangeRequest(){
-
- clearBoxes();
- mPinHdr.setText(R.string.pincode_reenter_your_pincode);
- mPinHdrExplanation.setVisibility(View.INVISIBLE);
- mConfirmingPinCode =true;
-
- }
-
-
- protected boolean checkPincode(){
-
-
- SharedPreferences appPrefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- String pText1 = appPrefs.getString("PrefPinCode1", null);
- String pText2 = appPrefs.getString("PrefPinCode2", null);
- String pText3 = appPrefs.getString("PrefPinCode3", null);
- String pText4 = appPrefs.getString("PrefPinCode4", null);
-
- if ( mTempText[0].equals(pText1) &&
- mTempText[1].equals(pText2) &&
- mTempText[2].equals(pText3) &&
- mTempText[3].equals(pText4) ) {
-
- return true;
-
-
- }else {
- Arrays.fill(mTempText, null);
- AlertDialog aDialog = new AlertDialog.Builder(this).create();
- CharSequence errorSeq = getString(R.string.common_error);
- aDialog.setTitle(errorSeq);
- CharSequence cseq = getString(R.string.pincode_wrong);
- aDialog.setMessage(cseq);
- CharSequence okSeq = getString(R.string.common_ok);
- aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- return;
- }
-
- });
- aDialog.show();
- clearBoxes();
- mPinHdr.setText(R.string.pincode_enter_pin_code);
- mPinHdrExplanation.setVisibility(View.INVISIBLE);
- mNewPasswordEntered = true;
- mConfirmingPinCode = false;
-
- }
-
-
- return false;
- }
-
- protected void confirmPincode(){
-
- mConfirmingPinCode = false;
-
- String rText1 = mText1.getText().toString();
- String rText2 = mText2.getText().toString();
- String rText3 = mText3.getText().toString();
- String rText4 = mText4.getText().toString();
-
- if ( mTempText[0].equals(rText1) &&
- mTempText[1].equals(rText2) &&
- mTempText[2].equals(rText3) &&
- mTempText[3].equals(rText4) ) {
-
- savePincodeAndExit();
-
- } else {
-
- Arrays.fill(mTempText, null);
- AlertDialog aDialog = new AlertDialog.Builder(this).create();
- CharSequence errorSeq = getString(R.string.common_error);
- aDialog.setTitle(errorSeq);
- CharSequence cseq = getString(R.string.pincode_mismatch);
- aDialog.setMessage(cseq);
- CharSequence okSeq = getString(R.string.common_ok);
- aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- return;
- }
-
- });
- aDialog.show();
- mPinHdr.setText(R.string.pincode_configure_your_pin);
- mPinHdrExplanation.setVisibility(View.VISIBLE);
- clearBoxes();
- }
-
- }
-
-
- protected void pinCodeEnd(boolean state){
- AlertDialog aDialog = new AlertDialog.Builder(this).create();
-
- if (state){
- CharSequence saveSeq = getString(R.string.common_save_exit);
- aDialog.setTitle(saveSeq);
- CharSequence cseq = getString(R.string.pincode_stored);
- aDialog.setMessage(cseq);
-
- }else{
- CharSequence saveSeq = getString(R.string.common_save_exit);
- aDialog.setTitle(saveSeq);
- CharSequence cseq = getString(R.string.pincode_removed);
- aDialog.setMessage(cseq);
-
- }
- CharSequence okSeq = getString(R.string.common_ok);
- aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- return;
- }
-
- });
- aDialog.show();
- }
-
- protected void savePincodeAndExit(){
- SharedPreferences.Editor appPrefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()).edit();
-
- appPrefs.putString("PrefPinCode1", mTempText[0]);
- appPrefs.putString("PrefPinCode2",mTempText[1]);
- appPrefs.putString("PrefPinCode3", mTempText[2]);
- appPrefs.putString("PrefPinCode4", mTempText[3]);
- appPrefs.putBoolean("set_pincode",true);
- appPrefs.commit();
-
- pinCodeEnd(true);
-
-
-
- }
-
-
- protected void clearBoxes(){
-
- mText1.setText("");
- mText2.setText("");
- mText3.setText("");
- mText4.setText("");
- mText1.requestFocus();
- }
-
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event){
- if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount()== 0){
-
- if (mActivity.equals("preferences")){
- SharedPreferences.Editor appPrefsE = PreferenceManager
-
- .getDefaultSharedPreferences(getApplicationContext()).edit();
-
- SharedPreferences appPrefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- boolean state = appPrefs.getBoolean("set_pincode", false);
- appPrefsE.putBoolean("set_pincode",!state);
- appPrefsE.commit();
- setInitVars();
- finish();
- }
- return true;
-
- }
-
- return super.onKeyDown(keyCode, event);
- }
-
-
-
-
-
-}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
+//import android.support.v7.app.ActionBar;
+import android.app.ActionBar;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListAdapter;
import android.widget.ListView;
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.SherlockPreferenceActivity;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuItem;
+import com.owncloud.android.BuildConfig;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.authentication.AuthenticatorActivity;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.db.DbHandler;
+import com.owncloud.android.files.FileOperationsHelper;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.ui.LongClickableCheckBoxPreference;
+import com.owncloud.android.services.OperationsService;
+import com.owncloud.android.ui.RadioButtonPreference;
import com.owncloud.android.utils.DisplayUtils;
/**
* An Activity that allows the user to change the application's settings.
- *
- * @author Bartek Przybylski
- * @author David A. Velasco
*/
-public class Preferences extends SherlockPreferenceActivity implements AccountManagerCallback<Boolean> {
+public class Preferences extends PreferenceActivity
+ implements AccountManagerCallback<Boolean>, ComponentsGetter {
private static final String TAG = "OwnCloudPreferences";
+ private static final int ACTION_SELECT_UPLOAD_PATH = 1;
+ private static final int ACTION_SELECT_UPLOAD_VIDEO_PATH = 2;
+
private DbHandler mDbHandler;
private CheckBoxPreference pCode;
private Preference pAboutApp;
private String mAccountName;
private boolean mShowContextMenu = false;
private String mUploadPath;
-
+ private PreferenceCategory mPrefInstantUploadCategory;
+ private Preference mPrefInstantUpload;
+ private Preference mPrefInstantUploadPath;
+ private Preference mPrefInstantUploadPathWiFi;
+ private Preference mPrefInstantVideoUpload;
+ private Preference mPrefInstantVideoUploadPath;
+ private Preference mPrefInstantVideoUploadPathWiFi;
+ private String mUploadVideoPath;
+
+ protected FileDownloader.FileDownloaderBinder mDownloaderBinder = null;
+ protected FileUploader.FileUploaderBinder mUploaderBinder = null;
+ private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null;
@SuppressWarnings("deprecation")
@Override
mDbHandler = new DbHandler(getBaseContext());
addPreferencesFromResource(R.xml.preferences);
- ActionBar actionBar = getSherlock().getActionBar();
- actionBar.setIcon(DisplayUtils.getSeasonalIconId());
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setTitle(R.string.actionbar_settings);
+ // Set properties of Action Bar in an ugly workaround to build correctly without
+ // upgrading minSdk
+ // TODO : increase minSdk; scheduled for next realease, don't wont to mix with this US
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ ActionBar actionBar = getActionBar();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ actionBar.setIcon(DisplayUtils.getSeasonalIconId());
+ }
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setTitle(R.string.actionbar_settings);
+ } else {
+ setTitle(R.string.actionbar_settings);
+ }
- loadInstantUploadPath();
+ // For adding content description tag to a title field in the action bar
+ int actionBarTitleId = getResources().getIdentifier("action_bar_title", "id", "android");
+ View actionBarTitleView = getWindow().getDecorView().findViewById(actionBarTitleId);
+ if (actionBarTitleView != null) { // it's null in Android 2.x
+ getWindow().getDecorView().findViewById(actionBarTitleId).
+ setContentDescription(getString(R.string.actionbar_settings));
+ }
// Load the accounts category for adding the list of accounts
mAccountsPrefCategory = (PreferenceCategory) findPreference("accounts_category");
ListAdapter listAdapter = listView.getAdapter();
Object obj = listAdapter.getItem(position);
- if (obj != null && obj instanceof LongClickableCheckBoxPreference) {
+ if (obj != null && obj instanceof RadioButtonPreference) {
mShowContextMenu = true;
- mAccountName = ((LongClickableCheckBoxPreference) obj).getKey();
+ mAccountName = ((RadioButtonPreference) obj).getKey();
Preferences.this.openContextMenu(listView);
return false;
}
});
-
+
+ // Load package info
+ String temp;
+ try {
+ PackageInfo pkg = getPackageManager().getPackageInfo(getPackageName(), 0);
+ temp = pkg.versionName;
+ } catch (NameNotFoundException e) {
+ temp = "";
+ Log_OC.e(TAG, "Error while showing about dialog", e);
+ }
+ final String appVersion = temp;
+
// Register context menu for list of preferences.
registerForContextMenu(getListView());
pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
- i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences");
- i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString());
+ Intent i = new Intent(getApplicationContext(), PassCodeActivity.class);
+ Boolean enable = (Boolean) newValue;
+ i.setAction(
+ enable.booleanValue() ? PassCodeActivity.ACTION_ENABLE :
+ PassCodeActivity.ACTION_DISABLE
+ );
startActivity(i);
return true;
}
}
+
+ if (BuildConfig.DEBUG) {
+ Preference pLog = findPreference("log");
+ if (pLog != null ){
+ pLog.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ Intent loggerIntent = new Intent(getApplicationContext(),
+ LogHistoryActivity.class);
+ startActivity(loggerIntent);
+ return true;
+ }
+ });
+ }
+ }
-
boolean recommendEnabled = getResources().getBoolean(R.bool.recommend_enabled);
Preference pRecommend = findPreference("recommend");
if (pRecommend != null){
String appName = getString(R.string.app_name);
String downloadUrl = getString(R.string.url_app_download);
- Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(Preferences.this);
- String username = currentAccount.name.substring(0, currentAccount.name.lastIndexOf('@'));
+ Account currentAccount = AccountUtils.
+ getCurrentOwnCloudAccount(Preferences.this);
+ String username = currentAccount.name.substring(0,
+ currentAccount.name.lastIndexOf('@'));
- String recommendSubject = String.format(getString(R.string.recommend_subject), appName);
- String recommendText = String.format(getString(R.string.recommend_text), appName, downloadUrl, username);
+ String recommendSubject = String.format(getString(R.string.recommend_subject),
+ appName);
+ String recommendText = String.format(getString(R.string.recommend_text),
+ appName, downloadUrl);
intent.putExtra(Intent.EXTRA_SUBJECT, recommendSubject);
intent.putExtra(Intent.EXTRA_TEXT, recommendText);
startActivity(intent);
-
return(true);
}
@Override
public boolean onPreferenceClick(Preference preference) {
String feedbackMail =(String) getText(R.string.mail_feedback);
- String feedback =(String) getText(R.string.prefs_feedback);
+ String feedback =(String) getText(R.string.prefs_feedback) + " - android v" + appVersion;
Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, feedback);
}
}
- Preference pInstantUploadPathApp = (Preference) findPreference("instant_upload_path");
+ mPrefInstantUploadPath = findPreference("instant_upload_path");
+ if (mPrefInstantUploadPath != null){
+
+ mPrefInstantUploadPath.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ if (!mUploadPath.endsWith(OCFile.PATH_SEPARATOR)) {
+ mUploadPath += OCFile.PATH_SEPARATOR;
+ }
+ Intent intent = new Intent(Preferences.this, UploadPathActivity.class);
+ intent.putExtra(UploadPathActivity.KEY_INSTANT_UPLOAD_PATH, mUploadPath);
+ startActivityForResult(intent, ACTION_SELECT_UPLOAD_PATH);
+ return true;
+ }
+ });
+ }
+
+ mPrefInstantUploadCategory =
+ (PreferenceCategory) findPreference("instant_uploading_category");
+
+ mPrefInstantUploadPathWiFi = findPreference("instant_upload_on_wifi");
+ mPrefInstantUpload = findPreference("instant_uploading");
+
+ toggleInstantPictureOptions(((CheckBoxPreference) mPrefInstantUpload).isChecked());
+
+ mPrefInstantUpload.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ toggleInstantPictureOptions((Boolean) newValue);
+ return true;
+ }
+ });
+
+ mPrefInstantVideoUploadPath = findPreference("instant_video_upload_path");
+ if (mPrefInstantVideoUploadPath != null){
- pInstantUploadPathApp.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+ mPrefInstantVideoUploadPath.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ if (!mUploadVideoPath.endsWith(OCFile.PATH_SEPARATOR)) {
+ mUploadVideoPath += OCFile.PATH_SEPARATOR;
+ }
+ Intent intent = new Intent(Preferences.this, UploadPathActivity.class);
+ intent.putExtra(UploadPathActivity.KEY_INSTANT_UPLOAD_PATH,
+ mUploadVideoPath);
+ startActivityForResult(intent, ACTION_SELECT_UPLOAD_VIDEO_PATH);
+ return true;
+ }
+ });
+ }
+
+ mPrefInstantVideoUploadPathWiFi = findPreference("instant_video_upload_on_wifi");
+ mPrefInstantVideoUpload = findPreference("instant_video_uploading");
+ toggleInstantVideoOptions(((CheckBoxPreference) mPrefInstantVideoUpload).isChecked());
+
+ mPrefInstantVideoUpload.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- mUploadPath = updateInstantUploadPath(newValue.toString());
+ toggleInstantVideoOptions((Boolean) newValue);
return true;
}
});
pAboutApp = (Preference) findPreference("about_app");
if (pAboutApp != null) {
pAboutApp.setTitle(String.format(getString(R.string.about_android), getString(R.string.app_name)));
- PackageInfo pkg;
- try {
- pkg = getPackageManager().getPackageInfo(getPackageName(), 0);
- pAboutApp.setSummary(String.format(getString(R.string.about_version), pkg.versionName));
- } catch (NameNotFoundException e) {
- Log_OC.e(TAG, "Error while showing about dialog", e);
- }
+ pAboutApp.setSummary(String.format(getString(R.string.about_version), appVersion));
}
- }
- @Override
- protected void onPause() {
- saveInstantUploadPathOnPreferences();
- super.onPause();
+ loadInstantUploadPath();
+ loadInstantUploadVideoPath();
+
+ /* ComponentsGetter */
+ mDownloadServiceConnection = newTransferenceServiceConnection();
+ if (mDownloadServiceConnection != null) {
+ bindService(new Intent(this, FileDownloader.class), mDownloadServiceConnection,
+ Context.BIND_AUTO_CREATE);
+ }
+ mUploadServiceConnection = newTransferenceServiceConnection();
+ if (mUploadServiceConnection != null) {
+ bindService(new Intent(this, FileUploader.class), mUploadServiceConnection,
+ Context.BIND_AUTO_CREATE);
+ }
+
+ }
+
+ private void toggleInstantPictureOptions(Boolean value){
+ if (value){
+ mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPathWiFi);
+ mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPath);
+ } else {
+ mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPathWiFi);
+ mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPath);
+ }
+ }
+
+ private void toggleInstantVideoOptions(Boolean value){
+ if (value){
+ mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPathWiFi);
+ mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPath);
+ } else {
+ mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPathWiFi);
+ mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPath);
+ }
}
@Override
// Remove account
am.removeAccount(a, this, mHandler);
+ Log_OC.d(TAG, "Remove an account " + a.name);
}
}
}
@Override
public void run(AccountManagerFuture<Boolean> future) {
if (future.isDone()) {
+ // after remove account
+ Account account = new Account(mAccountName, MainApp.getAccountType());
+ if (!AccountUtils.exists(account, MainApp.getAppContext())) {
+ // Cancel tranfers
+ if (mUploaderBinder != null) {
+ mUploaderBinder.cancel(account);
+ }
+ if (mDownloaderBinder != null) {
+ mDownloaderBinder.cancel(account);
+ }
+ }
+
Account a = AccountUtils.getCurrentOwnCloudAccount(this);
String accountName = "";
if (a == null) {
- Account[] accounts = AccountManager.get(this).getAccountsByType(MainApp.getAccountType());
+ Account[] accounts = AccountManager.get(this)
+ .getAccountsByType(MainApp.getAccountType());
if (accounts.length != 0)
accountName = accounts[0].name;
AccountUtils.setCurrentOwnCloudAccount(this, accountName);
@Override
protected void onResume() {
super.onResume();
- SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ SharedPreferences appPrefs =
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
boolean state = appPrefs.getBoolean("set_pincode", false);
pCode.setChecked(state);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
+
+ if (requestCode == ACTION_SELECT_UPLOAD_PATH && resultCode == RESULT_OK){
+
+ OCFile folderToUpload =
+ (OCFile) data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER);
+
+ mUploadPath = folderToUpload.getRemotePath();
+
+ mUploadPath = DisplayUtils.getPathWithoutLastSlash(mUploadPath);
+
+ // Show the path on summary preference
+ mPrefInstantUploadPath.setSummary(mUploadPath);
+
+ saveInstantUploadPathOnPreferences();
+
+ } else if (requestCode == ACTION_SELECT_UPLOAD_VIDEO_PATH && resultCode == RESULT_OK){
+
+ OCFile folderToUploadVideo =
+ (OCFile) data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER);
+
+ mUploadVideoPath = folderToUploadVideo.getRemotePath();
+
+ mUploadVideoPath = DisplayUtils.getPathWithoutLastSlash(mUploadVideoPath);
+
+ // Show the video path on summary preference
+ mPrefInstantVideoUploadPath.setSummary(mUploadVideoPath);
+
+ saveInstantUploadVideoPathOnPreferences();
+ }
}
@Override
protected void onDestroy() {
mDbHandler.close();
+
+ if (mDownloadServiceConnection != null) {
+ unbindService(mDownloadServiceConnection);
+ mDownloadServiceConnection = null;
+ }
+ if (mUploadServiceConnection != null) {
+ unbindService(mUploadServiceConnection);
+ mUploadServiceConnection = null;
+ }
+
super.onDestroy();
}
else {
for (Account a : accounts) {
- LongClickableCheckBoxPreference accountPreference = new LongClickableCheckBoxPreference(this);
+ RadioButtonPreference accountPreference = new RadioButtonPreference(this);
accountPreference.setKey(a.name);
// Handle internationalized domain names
accountPreference.setTitle(DisplayUtils.convertIdn(a.name, false));
AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE);
Account accounts[] = am.getAccountsByType(MainApp.getAccountType());
for (Account a : accounts) {
- CheckBoxPreference p = (CheckBoxPreference) findPreference(a.name);
+ RadioButtonPreference p =
+ (RadioButtonPreference) findPreference(a.name);
if (key.equals(a.name)) {
boolean accountChanged = !p.isChecked();
p.setChecked(true);
FileDisplayActivity.class
);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
} else {
finish();
@Override
public boolean onPreferenceClick(Preference preference) {
AccountManager am = AccountManager.get(getApplicationContext());
- am.addAccount(MainApp.getAccountType(), null, null, null, Preferences.this, null, null);
+ am.addAccount(MainApp.getAccountType(), null, null, null, Preferences.this,
+ null, null);
return true;
}
});
}
/**
- * Update the upload path checking that it is a correct path
- * @param uploadPath: path write by user
- * @return String: uploadPath
- */
- private String updateInstantUploadPath(String uploadPath) {
- String slashString = "/";
-
- // If slashes are duplicated, replace them for only one slash
- uploadPath = uploadPath.replaceAll("/+", slashString);
-
- // Remove last slash from path
- if (uploadPath.length() > 0 && uploadPath.charAt(uploadPath.length()-1) == slashString.charAt(0)) {
- uploadPath = uploadPath.substring(0, uploadPath.length()-1);
- }
-
- if (uploadPath.isEmpty()) { // Set default instant upload path
- uploadPath = getString(R.string.instant_upload_path);
- }else {
- if (!uploadPath.startsWith(slashString)) { // Add initial slash on path if necessary
- uploadPath = slashString.concat(uploadPath);
- }
- }
- return uploadPath;
- }
-
- /**
* Load upload path set on preferences
*/
private void loadInstantUploadPath() {
- SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ SharedPreferences appPrefs =
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mUploadPath = appPrefs.getString("instant_upload_path", getString(R.string.instant_upload_path));
+ mPrefInstantUploadPath.setSummary(mUploadPath);
}
/**
* Save the "Instant Upload Path" on preferences
*/
private void saveInstantUploadPathOnPreferences() {
- SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ SharedPreferences appPrefs =
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = appPrefs.edit();
editor.putString("instant_upload_path", mUploadPath);
editor.commit();
}
+
+ /**
+ * Load upload video path set on preferences
+ */
+ private void loadInstantUploadVideoPath() {
+ SharedPreferences appPrefs =
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ mUploadVideoPath = appPrefs.getString("instant_video_upload_path", getString(R.string.instant_upload_path));
+ mPrefInstantVideoUploadPath.setSummary(mUploadVideoPath);
+ }
+
+ /**
+ * Save the "Instant Video Upload Path" on preferences
+ */
+ private void saveInstantUploadVideoPathOnPreferences() {
+ SharedPreferences appPrefs =
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ SharedPreferences.Editor editor = appPrefs.edit();
+ editor.putString("instant_video_upload_path", mUploadVideoPath);
+ editor.commit();
+ }
+
+ // Methods for ComponetsGetter
+ @Override
+ public FileDownloader.FileDownloaderBinder getFileDownloaderBinder() {
+ return mDownloaderBinder;
+ }
+
+
+ @Override
+ public FileUploader.FileUploaderBinder getFileUploaderBinder() {
+ return mUploaderBinder;
+ }
+
+ @Override
+ public OperationsService.OperationsServiceBinder getOperationsServiceBinder() {
+ return null;
+ }
+
+ @Override
+ public FileDataStorageManager getStorageManager() {
+ return null;
+ }
+
+ @Override
+ public FileOperationsHelper getFileOperationsHelper() {
+ return null;
+ }
+
+ protected ServiceConnection newTransferenceServiceConnection() {
+ return new PreferencesServiceConnection();
+ }
+
+ /** Defines callbacks for service binding, passed to bindService() */
+ private class PreferencesServiceConnection implements ServiceConnection {
+
+ @Override
+ public void onServiceConnected(ComponentName component, IBinder service) {
+
+ if (component.equals(new ComponentName(Preferences.this, FileDownloader.class))) {
+ mDownloaderBinder = (FileDownloader.FileDownloaderBinder) service;
+
+ } else if (component.equals(new ComponentName(Preferences.this, FileUploader.class))) {
+ Log_OC.d(TAG, "Upload service connected");
+ mUploaderBinder = (FileUploader.FileUploaderBinder) service;
+ } else {
+ return;
+ }
+
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName component) {
+ if (component.equals(new ComponentName(Preferences.this, FileDownloader.class))) {
+ Log_OC.d(TAG, "Download service suddenly disconnected");
+ mDownloaderBinder = null;
+ } else if (component.equals(new ComponentName(Preferences.this, FileUploader.class))) {
+ Log_OC.d(TAG, "Upload service suddenly disconnected");
+ mUploaderBinder = null;
+ }
+ }
+ };
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.DialogFragment;
+import android.support.v7.app.ActionBar;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
-import com.actionbarsherlock.view.MenuItem;
import com.owncloud.android.R;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
/**
* Displays local files and let the user choose what of them wants to upload
* to the current ownCloud account
- *
- * @author David A. Velasco
- *
*/
public class UploadFilesActivity extends FileActivity implements
- LocalFileListFragment.ContainerActivity, OnNavigationListener, OnClickListener, ConfirmationDialogFragmentListener {
+ LocalFileListFragment.ContainerActivity, ActionBar.OnNavigationListener,
+ OnClickListener, ConfirmationDialogFragmentListener {
private ArrayAdapter<String> mDirectories;
private File mCurrentDir = null;
private Account mAccountOnCreation;
private DialogFragment mCurrentDialog;
- public static final String EXTRA_CHOSEN_FILES = UploadFilesActivity.class.getCanonicalName() + ".EXTRA_CHOSEN_FILES";
+ public static final String EXTRA_CHOSEN_FILES =
+ UploadFilesActivity.class.getCanonicalName() + ".EXTRA_CHOSEN_FILES";
public static final int RESULT_OK_AND_MOVE = RESULT_FIRST_USER;
- private static final String KEY_DIRECTORY_PATH = UploadFilesActivity.class.getCanonicalName() + ".KEY_DIRECTORY_PATH";
+ private static final String KEY_DIRECTORY_PATH =
+ UploadFilesActivity.class.getCanonicalName() + ".KEY_DIRECTORY_PATH";
private static final String TAG = "UploadFilesActivity";
private static final String WAIT_DIALOG_TAG = "WAIT";
private static final String QUERY_TO_MOVE_DIALOG_TAG = "QUERY_TO_MOVE";
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
- mCurrentDir = new File(savedInstanceState.getString(UploadFilesActivity.KEY_DIRECTORY_PATH));
+ mCurrentDir = new File(savedInstanceState.getString(
+ UploadFilesActivity.KEY_DIRECTORY_PATH));
} else {
mCurrentDir = Environment.getExternalStorageDirectory();
}
/// USER INTERFACE
// Drop-down navigation
- mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
+ mDirectories = new CustomArrayAdapter<String>(this,
+ R.layout.support_simple_spinner_dropdown_item);
File currDir = mCurrentDir;
while(currDir != null && currDir.getParentFile() != null) {
mDirectories.add(currDir.getName());
// Inflate and set the layout view
setContentView(R.layout.upload_files_layout);
- mFileListFragment = (LocalFileListFragment) getSupportFragmentManager().findFragmentById(R.id.local_files_list);
+ mFileListFragment = (LocalFileListFragment)
+ getSupportFragmentManager().findFragmentById(R.id.local_files_list);
// Set input controllers
// Action bar setup
ActionBar actionBar = getSupportActionBar();
actionBar.setIcon(DisplayUtils.getSeasonalIconId());
- actionBar.setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation
+ actionBar.setHomeButtonEnabled(true); // mandatory since Android ICS, according to the
+ // official documentation
actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null && mCurrentDir.getName() != null);
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
@Override
protected void onSaveInstanceState(Bundle outState) {
- // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
+ // responsibility of restore is preferred in onCreate() before than in
+ // onRestoreInstanceState when there are Fragments involved
Log_OC.d(TAG, "onSaveInstanceState() start");
super.onSaveInstanceState(outState);
outState.putString(UploadFilesActivity.KEY_DIRECTORY_PATH, mCurrentDir.getAbsolutePath());
* to upload into the ownCloud local folder.
*
* Maybe an AsyncTask is not strictly necessary, but who really knows.
- *
- * @author David A. Velasco
*/
private class CheckAvailableSpaceTask extends AsyncTask<Void, Void, Boolean> {
File localFile = new File(localPath);
total += localFile.length();
}
- return (FileStorageUtils.getUsableSpace(mAccountOnCreation.name) >= total);
+ return (new Boolean(FileStorageUtils.getUsableSpace(mAccountOnCreation.name) >= total));
}
/**
finish();
} else {
- // show a dialog to query the user if wants to move the selected files to the ownCloud folder instead of copying
+ // show a dialog to query the user if wants to move the selected files
+ // to the ownCloud folder instead of copying
String[] args = {getString(R.string.app_name)};
- ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(R.string.upload_query_move_foreign_files, args, R.string.common_yes, -1, R.string.common_no);
+ ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(
+ R.string.upload_query_move_foreign_files, args, R.string.common_yes, -1, R.string.common_no
+ );
dialog.setOnConfirmationListener(UploadFilesActivity.this);
dialog.show(getSupportFragmentManager(), QUERY_TO_MOVE_DIALOG_TAG);
}
public void onConfirmation(String callerTag) {
Log_OC.d(TAG, "Positive button in dialog was clicked; dialog tag is " + callerTag);
if (callerTag.equals(QUERY_TO_MOVE_DIALOG_TAG)) {
- // return the list of selected files to the caller activity (success), signaling that they should be moved to the ownCloud folder, instead of copied
+ // return the list of selected files to the caller activity (success),
+ // signaling that they should be moved to the ownCloud folder, instead of copied
Intent data = new Intent();
data.putExtra(EXTRA_CHOSEN_FILES, mFileListFragment.getCheckedFilePaths());
setResult(RESULT_OK_AND_MOVE, data);
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.activity;
+
+import android.accounts.Account;
+import android.os.Bundle;
+import android.view.View.OnClickListener;
+
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.fragment.FileFragment;
+import com.owncloud.android.ui.fragment.OCFileListFragment;
+
+public class UploadPathActivity extends FolderPickerActivity implements FileFragment.ContainerActivity,
+ OnClickListener, OnEnforceableRefreshListener {
+
+ public static final String KEY_INSTANT_UPLOAD_PATH = "INSTANT_UPLOAD_PATH";
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ String instantUploadPath = getIntent().getStringExtra(KEY_INSTANT_UPLOAD_PATH);
+
+ // The caller activity (Preferences) is not a FileActivity, so it has no OCFile, only a path.
+ OCFile folder = new OCFile(instantUploadPath);
+
+ setFile(folder);
+ }
+
+ /**
+ * Called when the ownCloud {@link Account} associated to the Activity was
+ * just updated.
+ */
+ @Override
+ protected void onAccountSet(boolean stateWasRecovered) {
+ super.onAccountSet(stateWasRecovered);
+ if (getAccount() != null) {
+
+ updateFileFromDB();
+
+ OCFile folder = getFile();
+ if (folder == null || !folder.isFolder()) {
+ // fall back to root folder
+ setFile(getStorageManager().getFileByPath(OCFile.ROOT_PATH));
+ folder = getFile();
+ }
+
+ onBrowsedDownTo(folder);
+
+ if (!stateWasRecovered) {
+ OCFileListFragment listOfFolders = getListOfFilesFragment();
+ // TODO Enable when "On Device" is recovered ?
+ listOfFolders.listDirectory(folder/*, false*/);
+
+ startSyncFolderOperation(folder, false);
+ }
+
+ updateNavigationElementsInActionBar();
+ }
+ }
+}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author masensio
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import java.util.Stack;
import java.util.Vector;
-import com.owncloud.android.MainApp;
-import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountAuthenticator;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.lib.common.utils.Log_OC;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.Resources.NotFoundException;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.preference.PreferenceManager;
+import android.provider.MediaStore;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v7.app.ActionBar;
+import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.SherlockListActivity;
-import com.actionbarsherlock.view.MenuItem;
+import com.owncloud.android.MainApp;
+import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountAuthenticator;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.operations.CreateFolderOperation;
+import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
+import com.owncloud.android.ui.dialog.LoadingDialog;
+import com.owncloud.android.utils.CopyTmpFileAsyncTask;
import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.ErrorMessageAdapter;
+
/**
* This can be used to upload things to an ownCloud instance.
- *
- * @author Bartek Przybylski
- *
*/
-public class Uploader extends SherlockListActivity implements OnItemClickListener, android.view.View.OnClickListener {
- private static final String TAG = "ownCloudUploader";
+public class Uploader extends FileActivity
+ implements OnItemClickListener, android.view.View.OnClickListener,
+ CopyTmpFileAsyncTask.OnCopyTmpFileTaskListener {
+
+ private static final String TAG = Uploader.class.getSimpleName();
- private Account mAccount;
private AccountManager mAccountManager;
private Stack<String> mParents;
private ArrayList<Parcelable> mStreamsToUpload;
private boolean mCreateDir;
private String mUploadPath;
- private FileDataStorageManager mStorageManager;
private OCFile mFile;
+ private boolean mAccountSelected;
+ private boolean mAccountSelectionShowing;
+ private ArrayList<String> mRemoteCacheData;
+ private int mNumCacheFile;
+
private final static int DIALOG_NO_ACCOUNT = 0;
private final static int DIALOG_WAITING = 1;
private final static int DIALOG_NO_STREAM = 2;
private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
+ private final static String KEY_PARENTS = "PARENTS";
+ private final static String KEY_FILE = "FILE";
+ private final static String KEY_ACCOUNT_SELECTED = "ACCOUNT_SELECTED";
+ private final static String KEY_ACCOUNT_SELECTION_SHOWING = "ACCOUNT_SELECTION_SHOWING";
+ private final static String KEY_NUM_CACHE_FILE = "NUM_CACHE_FILE";
+ private final static String KEY_REMOTE_CACHE_DATA = "REMOTE_CACHE_DATA";
+
+ private static final String DIALOG_WAIT_COPY_FILE = "DIALOG_WAIT_COPY_FILE";
+
@Override
protected void onCreate(Bundle savedInstanceState) {
+ prepareStreamsToUpload();
+
+ if (savedInstanceState == null) {
+ mParents = new Stack<String>();
+ mAccountSelected = false;
+ mAccountSelectionShowing = false;
+ mNumCacheFile = 0;
+
+ // ArrayList for files with path in private storage
+ mRemoteCacheData = new ArrayList<String>();
+ } else {
+ mParents = (Stack<String>) savedInstanceState.getSerializable(KEY_PARENTS);
+ mFile = savedInstanceState.getParcelable(KEY_FILE);
+ mAccountSelected = savedInstanceState.getBoolean(KEY_ACCOUNT_SELECTED);
+ mAccountSelectionShowing = savedInstanceState.getBoolean(KEY_ACCOUNT_SELECTION_SHOWING);
+ mNumCacheFile = savedInstanceState.getInt(KEY_NUM_CACHE_FILE);
+ mRemoteCacheData = savedInstanceState.getStringArrayList(KEY_REMOTE_CACHE_DATA);
+ }
+
super.onCreate(savedInstanceState);
- mParents = new Stack<String>();
+
+ if (mAccountSelected) {
+ setAccount((Account) savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT));
+ }
+
ActionBar actionBar = getSupportActionBar();
actionBar.setIcon(DisplayUtils.getSeasonalIconId());
- if (prepareStreamsToUpload()) {
+ }
+
+ @Override
+ protected void setAccount(Account account, boolean savedAccount) {
+ if (somethingToUpload()) {
mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAccountType());
if (accounts.length == 0) {
Log_OC.i(TAG, "No ownCloud account is available");
showDialog(DIALOG_NO_ACCOUNT);
- } else if (accounts.length > 1) {
- Log_OC.i(TAG, "More then one ownCloud is available");
+ } else if (accounts.length > 1 && !mAccountSelected && !mAccountSelectionShowing) {
+ Log_OC.i(TAG, "More than one ownCloud is available");
showDialog(DIALOG_MULTIPLE_ACCOUNT);
+ mAccountSelectionShowing = true;
} else {
- mAccount = accounts[0];
- mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
- initTargetFolder();
- populateDirectoryList();
-
+ if (!savedAccount) {
+ setAccount(accounts[0]);
+ }
}
-
+
} else {
showDialog(DIALOG_NO_STREAM);
}
+
+ super.setAccount(account, savedAccount);
}
-
+
+ @Override
+ protected void onAccountSet(boolean stateWasRecovered) {
+ super.onAccountSet(mAccountWasRestored);
+ initTargetFolder();
+ populateDirectoryList();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ Log_OC.d(TAG, "onSaveInstanceState() start");
+ super.onSaveInstanceState(outState);
+ outState.putSerializable(KEY_PARENTS, mParents);
+ //outState.putParcelable(KEY_ACCOUNT, mAccount);
+ outState.putParcelable(KEY_FILE, mFile);
+ outState.putBoolean(KEY_ACCOUNT_SELECTED, mAccountSelected);
+ outState.putBoolean(KEY_ACCOUNT_SELECTION_SHOWING, mAccountSelectionShowing);
+ outState.putInt(KEY_NUM_CACHE_FILE, mNumCacheFile);
+ outState.putStringArrayList(KEY_REMOTE_CACHE_DATA, mRemoteCacheData);
+ outState.putParcelable(FileActivity.EXTRA_ACCOUNT, getAccount());
+
+ Log_OC.d(TAG, "onSaveInstanceState() end");
+ }
+
@Override
protected Dialog onCreateDialog(final int id) {
final AlertDialog.Builder builder = new Builder(this);
case DIALOG_NO_ACCOUNT:
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setTitle(R.string.uploader_wrn_no_account_title);
- builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));
+ builder.setMessage(String.format(
+ getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));
builder.setCancelable(false);
builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
+ 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
});
return builder.create();
case DIALOG_MULTIPLE_ACCOUNT:
- CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(MainApp.getAccountType()).length];
+ CharSequence ac[] = new CharSequence[
+ mAccountManager.getAccountsByType(MainApp.getAccountType()).length];
for (int i = 0; i < ac.length; ++i) {
- ac[i] = DisplayUtils.convertIdn(mAccountManager.getAccountsByType(MainApp.getAccountType())[i].name, false);
+ ac[i] = DisplayUtils.convertIdn(
+ mAccountManager.getAccountsByType(MainApp.getAccountType())[i].name, false);
}
builder.setTitle(R.string.common_choose_account);
builder.setItems(ac, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- mAccount = mAccountManager.getAccountsByType(MainApp.getAccountType())[which];
- mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
- initTargetFolder();
- populateDirectoryList();
+ setAccount(mAccountManager.getAccountsByType(MainApp.getAccountType())[which]);
+ onAccountSet(mAccountWasRestored);
+ dialog.dismiss();
+ mAccountSelected = true;
+ mAccountSelectionShowing = false;
}
});
builder.setCancelable(true);
builder.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
+ mAccountSelectionShowing = false;
dialog.cancel();
finish();
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// click on folder in the list
Log_OC.d(TAG, "on item click");
- Vector<OCFile> tmpfiles = mStorageManager.getFolderContent(mFile);
+ // TODO Enable when "On Device" is recovered ?
+ Vector<OCFile> tmpfiles = getStorageManager().getFolderContent(mFile /*, false*/);
if (tmpfiles.size() <= 0) return;
// filter on dirtype
Vector<OCFile> files = new Vector<OCFile>();
// click on button
switch (v.getId()) {
case R.id.uploader_choose_folder:
- mUploadPath = ""; // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix
+ mUploadPath = ""; // first element in mParents is root dir, represented by "";
+ // init mUploadPath with "/" results in a "//" prefix
for (String p : mParents)
mUploadPath += p + OCFile.PATH_SEPARATOR;
Log_OC.d(TAG, "Uploading file to dir " + mUploadPath);
uploadFiles();
break;
+
+ case R.id.uploader_new_folder:
+ CreateFolderDialogFragment dialog = CreateFolderDialogFragment.newInstance(mFile);
+ dialog.show(getSupportFragmentManager(), "createdirdialog");
+ break;
+
+
default:
throw new IllegalArgumentException("Wrong element clicked");
}
// 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];
+ setAccount(accounts[0]);
populateDirectoryList();
}
}
private void populateDirectoryList() {
setContentView(R.layout.uploader_layout);
+
+ ListView mListView = (ListView) findViewById(android.R.id.list);
String current_dir = mParents.peek();
if(current_dir.equals("")){
actionBar.setHomeButtonEnabled(notRoot);
String full_path = generatePath(mParents);
-
+
Log_OC.d(TAG, "Populating view with content of : " + full_path);
- mFile = mStorageManager.getFileByPath(full_path);
+ mFile = getStorageManager().getFileByPath(full_path);
if (mFile != null) {
- Vector<OCFile> files = mStorageManager.getFolderContent(mFile);
+ // TODO Enable when "On Device" is recovered ?
+ Vector<OCFile> files = getStorageManager().getFolderContent(mFile/*, false*/);
List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();
for (OCFile f : files) {
HashMap<String, Object> h = new HashMap<String, Object>();
data,
R.layout.uploader_list_item_layout,
new String[] {"dirname"},
- new int[] {R.id.textView1});
- setListAdapter(sa);
- Button btn = (Button) findViewById(R.id.uploader_choose_folder);
- btn.setOnClickListener(this);
- getListView().setOnItemClickListener(this);
+ new int[] {R.id.filename});
+
+ mListView.setAdapter(sa);
+ Button btnChooseFolder = (Button) findViewById(R.id.uploader_choose_folder);
+ btnChooseFolder.setOnClickListener(this);
+
+ Button btnNewFolder = (Button) findViewById(R.id.uploader_new_folder);
+ btnNewFolder.setOnClickListener(this);
+
+ mListView.setOnItemClickListener(this);
}
}
return full_path;
}
- private boolean prepareStreamsToUpload() {
+ 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);
}
+ }
+
+ private boolean somethingToUpload() {
return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);
}
public void uploadFiles() {
try {
+ // ArrayList for files with path in external storage
ArrayList<String> local = new ArrayList<String>();
ArrayList<String> remote = new ArrayList<String>();
for (Parcelable mStream : mStreamsToUpload) {
Uri uri = (Uri) mStream;
- if (uri !=null) {
+ String data = null;
+ String filePath = "";
+
+ if (uri != null) {
if (uri.getScheme().equals("content")) {
-
- String mimeType = getContentResolver().getType(uri);
-
- if (mimeType.contains("image")) {
- String[] CONTENT_PROJECTION = { Images.Media.DATA, Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE, Images.Media.SIZE};
- Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
- c.moveToFirst();
- int index = c.getColumnIndex(Images.Media.DATA);
- String data = c.getString(index);
- local.add(data);
- remote.add(mUploadPath + c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME)));
-
- }
- else if (mimeType.contains("video")) {
- String[] CONTENT_PROJECTION = { Video.Media.DATA, Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE, Video.Media.SIZE, Video.Media.DATE_MODIFIED };
- Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
- c.moveToFirst();
- int index = c.getColumnIndex(Video.Media.DATA);
- String data = c.getString(index);
- local.add(data);
- remote.add(mUploadPath + c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME)));
+ String mimeType = getContentResolver().getType(uri);
+
+ if (mimeType.contains("image")) {
+ String[] CONTENT_PROJECTION = { Images.Media.DATA,
+ Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE,
+ Images.Media.SIZE };
+ Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
+ null, null);
+ c.moveToFirst();
+ int index = c.getColumnIndex(Images.Media.DATA);
+ data = c.getString(index);
+ filePath = mUploadPath +
+ c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME));
+
+ } else if (mimeType.contains("video")) {
+ String[] CONTENT_PROJECTION = { Video.Media.DATA,
+ Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE,
+ Video.Media.SIZE, Video.Media.DATE_MODIFIED };
+ Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
+ null, null);
+ c.moveToFirst();
+ int index = c.getColumnIndex(Video.Media.DATA);
+ data = c.getString(index);
+ filePath = mUploadPath +
+ c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME));
- }
- else if (mimeType.contains("audio")) {
- String[] CONTENT_PROJECTION = { Audio.Media.DATA, Audio.Media.DISPLAY_NAME, Audio.Media.MIME_TYPE, Audio.Media.SIZE };
- Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
- c.moveToFirst();
- int index = c.getColumnIndex(Audio.Media.DATA);
- String data = c.getString(index);
- local.add(data);
- remote.add(mUploadPath + c.getString(c.getColumnIndex(Audio.Media.DISPLAY_NAME)));
-
- }
- else {
- String filePath = Uri.decode(uri.toString()).replace(uri.getScheme() + "://", "");
- // cut everything whats before mnt. It occured to me that sometimes apps send their name into the URI
- if (filePath.contains("mnt")) {
- String splitedFilePath[] = filePath.split("/mnt");
- filePath = splitedFilePath[1];
- }
- final File file = new File(filePath);
- local.add(file.getAbsolutePath());
- remote.add(mUploadPath + file.getName());
- }
-
+ } else if (mimeType.contains("audio")) {
+ String[] CONTENT_PROJECTION = { Audio.Media.DATA,
+ Audio.Media.DISPLAY_NAME, Audio.Media.MIME_TYPE,
+ Audio.Media.SIZE };
+ Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
+ null, null);
+ c.moveToFirst();
+ int index = c.getColumnIndex(Audio.Media.DATA);
+ data = c.getString(index);
+ filePath = mUploadPath +
+ c.getString(c.getColumnIndex(Audio.Media.DISPLAY_NAME));
+
+ } else {
+ Cursor cursor = getContentResolver().query(uri,
+ new String[]{MediaStore.MediaColumns.DISPLAY_NAME},
+ null, null, null);
+ cursor.moveToFirst();
+ int nameIndex = cursor.getColumnIndex(cursor.getColumnNames()[0]);
+ if (nameIndex >= 0) {
+ filePath = mUploadPath + cursor.getString(nameIndex);
+ }
+ }
+
} else if (uri.getScheme().equals("file")) {
- String filePath = Uri.decode(uri.toString()).replace(uri.getScheme() + "://", "");
+ filePath = Uri.decode(uri.toString()).replace(uri.getScheme() +
+ "://", "");
if (filePath.contains("mnt")) {
String splitedFilePath[] = filePath.split("/mnt");
filePath = splitedFilePath[1];
}
final File file = new File(filePath);
- local.add(file.getAbsolutePath());
- remote.add(mUploadPath + file.getName());
+ data = file.getAbsolutePath();
+ filePath = mUploadPath + file.getName();
}
else {
throw new SecurityException();
}
+ if (data == null) {
+ mRemoteCacheData.add(filePath);
+ CopyTmpFileAsyncTask copyTask = new CopyTmpFileAsyncTask(this);
+ Object[] params = { uri, filePath, mRemoteCacheData.size()-1,
+ getAccount().name, getContentResolver()};
+ mNumCacheFile++;
+ showWaitingCopyDialog();
+ copyTask.execute(params);
+ } else {
+ remote.add(filePath);
+ local.add(data);
+ }
}
else {
throw new SecurityException();
}
-
- Intent intent = new Intent(getApplicationContext(), FileUploader.class);
- intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
- intent.putExtra(FileUploader.KEY_LOCAL_FILE, local.toArray(new String[local.size()]));
- intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote.toArray(new String[remote.size()]));
- intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);
- startService(intent);
- //Save the path to shared preferences
- SharedPreferences.Editor appPrefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()).edit();
- appPrefs.putString("last_upload_path", mUploadPath);
- appPrefs.apply();
+ Intent intent = new Intent(getApplicationContext(), FileUploader.class);
+ intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
+ intent.putExtra(FileUploader.KEY_LOCAL_FILE, local.toArray(new String[local.size()]));
+ intent.putExtra(FileUploader.KEY_REMOTE_FILE,
+ remote.toArray(new String[remote.size()]));
+ intent.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
+ startService(intent);
- finish();
+ //Save the path to shared preferences
+ SharedPreferences.Editor appPrefs = PreferenceManager
+ .getDefaultSharedPreferences(getApplicationContext()).edit();
+ appPrefs.putString("last_upload_path", mUploadPath);
+ appPrefs.apply();
+
+ finish();
}
} catch (SecurityException e) {
- String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name));
+ String message = String.format(getString(R.string.uploader_error_forbidden_content),
+ getString(R.string.app_name));
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}
+ @Override
+ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+ super.onRemoteOperationFinish(operation, result);
+
+
+ if (operation instanceof CreateFolderOperation) {
+ onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
+ }
+
+ }
+
+ /**
+ * Updates the view associated to the activity after the finish of an operation
+ * trying create a new folder
+ *
+ * @param operation Creation operation performed.
+ * @param result Result of the creation.
+ */
+ private void onCreateFolderOperationFinish(CreateFolderOperation operation,
+ RemoteOperationResult result) {
+ if (result.isSuccess()) {
+ dismissLoadingDialog();
+ populateDirectoryList();
+ } else {
+ dismissLoadingDialog();
+ try {
+ Toast msg = Toast.makeText(this,
+ ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+ Toast.LENGTH_LONG);
+ msg.show();
+
+ } catch (NotFoundException e) {
+ Log_OC.e(TAG, "Error while trying to show fail message " , e);
+ }
+ }
+ }
+
+
/**
* Loads the target folder initialize shown to the user.
*
* The target account has to be chosen before this method is called.
*/
private void initTargetFolder() {
- if (mStorageManager == null) {
- throw new IllegalStateException("Do not call this method before initializing mStorageManager");
+ if (getStorageManager() == null) {
+ throw new IllegalStateException("Do not call this method before " +
+ "initializing mStorageManager");
}
SharedPreferences appPreferences = PreferenceManager
// "/" equals root-directory
if(last_path.equals("/")) {
mParents.add("");
- }
- else{
+ } else{
String[] dir_names = last_path.split("/");
+ mParents.clear();
for (String dir : dir_names)
mParents.add(dir);
}
//Make sure that path still exists, if it doesn't pop the stack and try the previous path
- while(!mStorageManager.fileExists(generatePath(mParents)) && mParents.size() > 1){
- mParents.pop();
- }
+ while(!getStorageManager().fileExists(generatePath(mParents)) && mParents.size() > 1){
+ mParents.pop();
+ }
}
public boolean onOptionsItemSelected(MenuItem item) {
boolean retval = true;
switch (item.getItemId()) {
- case android.R.id.home: {
- if((mParents.size() > 1)) {
- onBackPressed();
- }
- break;
- }
- default:
- retval = super.onOptionsItemSelected(item);
+ case android.R.id.home:
+ if((mParents.size() > 1)) {
+ onBackPressed();
+ }
+ break;
+
+ default:
+ retval = super.onOptionsItemSelected(item);
}
return retval;
}
-
+
+ /**
+ * Process the result of CopyTmpFileAsyncTask
+ * @param result
+ * @param index
+ */
+ @Override
+ public void onTmpFileCopied(String result, int index) {
+ if (mNumCacheFile -- == 0) {
+ dismissWaitingCopyDialog();
+ }
+ if (result != null) {
+ Intent intent = new Intent(getApplicationContext(), FileUploader.class);
+ intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
+ intent.putExtra(FileUploader.KEY_LOCAL_FILE, result);
+ intent.putExtra(FileUploader.KEY_REMOTE_FILE, mRemoteCacheData.get(index));
+ intent.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
+ startService(intent);
+
+ } else {
+ String message = String.format(getString(R.string.uploader_error_forbidden_content),
+ getString(R.string.app_name));
+ Toast.makeText(this, message, Toast.LENGTH_LONG).show();
+ Log_OC.d(TAG, message);
+ }
+
+ }
+/**
+ * Show waiting for copy dialog
+ */
+ public void showWaitingCopyDialog() {
+ // Construct dialog
+ LoadingDialog loading = new LoadingDialog(
+ getResources().getString(R.string.wait_for_tmp_copy_from_private_storage));
+ FragmentManager fm = getSupportFragmentManager();
+ FragmentTransaction ft = fm.beginTransaction();
+ loading.show(ft, DIALOG_WAIT_COPY_FILE);
+
+ }
+
+
+ /**
+ * Dismiss waiting for copy dialog
+ */
+ public void dismissWaitingCopyDialog(){
+ Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_COPY_FILE);
+ if (frag != null) {
+ LoadingDialog loading = (LoadingDialog) frag;
+ loading.dismiss();
+ }
+ }
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* TODO
- *
- * @author masensio
- * @author David A. Velasco
*
*/
public class CertificateCombinedExceptionViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter {
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
+ * @author Bartek Przybylski\r
+ * @author Tobias Kaminsky\r
+ * @author David A. Velasco\r
* Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2014 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
*/\r
package com.owncloud.android.ui.adapter;\r
\r
-
+\r
import java.io.File;\r
-import java.util.Collections;\r
-import java.util.Comparator;\r
import java.util.Vector;\r
\r
-import third_parties.daveKoeller.AlphanumComparator;\r
import android.accounts.Account;\r
import android.content.Context;\r
import android.content.SharedPreferences;\r
import android.graphics.Bitmap;\r
+import android.os.Build;\r
import android.preference.PreferenceManager;\r
import android.text.format.DateUtils;\r
import android.view.LayoutInflater;\r
import android.view.View;\r
import android.view.ViewGroup;\r
+import android.widget.AbsListView;\r
import android.widget.BaseAdapter;\r
import android.widget.ImageView;\r
+import android.widget.LinearLayout;\r
import android.widget.ListAdapter;\r
-import android.widget.ListView;\r
import android.widget.TextView;\r
\r
import com.owncloud.android.R;\r
import com.owncloud.android.datamodel.FileDataStorageManager;\r
import com.owncloud.android.datamodel.OCFile;\r
import com.owncloud.android.datamodel.ThumbnailsCacheManager;\r
-import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncDrawable;\r
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
-import com.owncloud.android.lib.common.utils.Log_OC;\r
+import com.owncloud.android.services.OperationsService.OperationsServiceBinder;\r
import com.owncloud.android.ui.activity.ComponentsGetter;\r
import com.owncloud.android.utils.DisplayUtils;\r
import com.owncloud.android.utils.FileStorageUtils;\r
-
+\r
\r
/**\r
* This Adapter populates a ListView with all files and folders in an ownCloud\r
* instance.\r
- * \r
- * @author Bartek Przybylski\r
- * @author Tobias Kaminsky\r
- * @author David A. Velasco\r
*/\r
-public class FileListListAdapter extends BaseAdapter implements ListAdapter {
+public class FileListListAdapter extends BaseAdapter implements ListAdapter {\r
private final static String PERMISSION_SHARED_WITH_ME = "S";\r
- \r
+\r
private Context mContext;\r
private OCFile mFile = null;\r
private Vector<OCFile> mFiles = null;\r
+ private Vector<OCFile> mFilesOrig = new Vector<OCFile>();\r
private boolean mJustFolders;\r
\r
- private FileDataStorageManager mStorageManager;
- private Account mAccount;
+ private FileDataStorageManager mStorageManager;\r
+ private Account mAccount;\r
private ComponentsGetter mTransferServiceGetter;\r
- private Integer mSortOrder;\r
- public static final Integer SORT_NAME = 0;\r
- public static final Integer SORT_DATE = 1;\r
- public static final Integer SORT_SIZE = 2;\r
- private Boolean mSortAscending;\r
+ private boolean mGridMode;\r
+\r
+ private enum ViewType {LIST_ITEM, GRID_IMAGE, GRID_ITEM };\r
+\r
private SharedPreferences mAppPreferences;\r
\r
public FileListListAdapter(\r
boolean justFolders, \r
- Context context, \r
+ Context context,\r
ComponentsGetter transferServiceGetter\r
) {\r
-\r
+ \r
mJustFolders = justFolders;\r
mContext = context;\r
mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);\r
-
- mTransferServiceGetter = transferServiceGetter;
- \r
+ mTransferServiceGetter = transferServiceGetter;\r
+\r
mAppPreferences = PreferenceManager\r
.getDefaultSharedPreferences(mContext);\r
\r
// Read sorting order, default to sort by name ascending\r
- mSortOrder = mAppPreferences\r
- .getInt("sortOrder", 0);\r
- mSortAscending = mAppPreferences.getBoolean("sortAscending", true);
+ FileStorageUtils.mSortOrder = mAppPreferences.getInt("sortOrder", 0);\r
+ FileStorageUtils.mSortAscending = mAppPreferences.getBoolean("sortAscending", true);\r
\r
// initialise thumbnails cache on background thread\r
new ThumbnailsCacheManager.InitDiskCacheTask().execute();\r
\r
+ mGridMode = false;\r
}\r
-
+ \r
@Override\r
public boolean areAllItemsEnabled() {\r
return true;\r
\r
@Override\r
public View getView(int position, View convertView, ViewGroup parent) {\r
+\r
View view = convertView;\r
- if (view == null) {\r
- LayoutInflater inflator = (LayoutInflater) mContext\r
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
- view = inflator.inflate(R.layout.list_item, null);\r
- }\r
- \r
+ OCFile file = null;\r
+ LayoutInflater inflator = (LayoutInflater) mContext\r
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
+\r
if (mFiles != null && mFiles.size() > position) {\r
- OCFile file = mFiles.get(position);\r
- TextView fileName = (TextView) view.findViewById(R.id.Filename); \r
- String name = file.getFileName();\r
+ file = mFiles.get(position);\r
+ }\r
+\r
+ // Find out which layout should be displayed\r
+ ViewType viewType;\r
+ if (!mGridMode){\r
+ viewType = ViewType.LIST_ITEM;\r
+ } else if (file.isImage()){\r
+ viewType = ViewType.GRID_IMAGE;\r
+ } else {\r
+ viewType = ViewType.GRID_ITEM;\r
+ }\r
+\r
+ // create view only if differs, otherwise reuse\r
+ if (convertView == null || (convertView != null && convertView.getTag() != viewType)) {\r
+ switch (viewType) {\r
+ case GRID_IMAGE:\r
+ view = inflator.inflate(R.layout.grid_image, null);\r
+ view.setTag(ViewType.GRID_IMAGE);\r
+ break;\r
+ case GRID_ITEM:\r
+ view = inflator.inflate(R.layout.grid_item, null);\r
+ view.setTag(ViewType.GRID_ITEM);\r
+ break;\r
+ case LIST_ITEM:\r
+ view = inflator.inflate(R.layout.list_item, null);\r
+ view.setTag(ViewType.LIST_ITEM);\r
+ break;\r
+ }\r
+ }\r
+\r
+ view.invalidate();\r
+\r
+ if (file != null){\r
+\r
+ ImageView fileIcon = (ImageView) view.findViewById(R.id.thumbnail);\r
\r
- fileName.setText(name);\r
- ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1);\r
fileIcon.setTag(file.getFileId());\r
- ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);\r
- ImageView sharedWithMeIconV = (ImageView) view.findViewById(R.id.sharedWithMeIcon);\r
- sharedWithMeIconV.setVisibility(View.GONE);\r
-\r
- ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2);\r
- localStateView.bringToFront();\r
- FileDownloaderBinder downloaderBinder = \r
- mTransferServiceGetter.getFileDownloaderBinder();\r
- FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder();\r
- if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) {\r
- localStateView.setImageResource(R.drawable.downloading_file_indicator);\r
- localStateView.setVisibility(View.VISIBLE);\r
- } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file)) {\r
- localStateView.setImageResource(R.drawable.uploading_file_indicator);\r
- localStateView.setVisibility(View.VISIBLE);\r
- } else if (file.isDown()) {\r
- localStateView.setImageResource(R.drawable.local_file_indicator);\r
- localStateView.setVisibility(View.VISIBLE);\r
- } else {\r
- localStateView.setVisibility(View.INVISIBLE);\r
+ TextView fileName;\r
+ String name = file.getFileName();\r
+\r
+ LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.ListItemLayout);\r
+ linearLayout.setContentDescription("LinearLayout-" + name);\r
+\r
+ switch (viewType){\r
+ case LIST_ITEM:\r
+ TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);\r
+ TextView lastModV = (TextView) view.findViewById(R.id.last_mod);\r
+ ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);\r
+\r
+ lastModV.setVisibility(View.VISIBLE);\r
+ lastModV.setText(showRelativeTimestamp(file));\r
+\r
+ checkBoxV.setVisibility(View.GONE);\r
+\r
+ fileSizeV.setVisibility(View.VISIBLE);\r
+ fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
+\r
+ if (!file.isFolder()) {\r
+ AbsListView parentList = (AbsListView)parent;\r
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {\r
+ if (parentList.getChoiceMode() == AbsListView.CHOICE_MODE_NONE) {\r
+ checkBoxV.setVisibility(View.GONE);\r
+ } else {\r
+ if (parentList.isItemChecked(position)) {\r
+ checkBoxV.setImageResource(\r
+ android.R.drawable.checkbox_on_background);\r
+ } else {\r
+ checkBoxV.setImageResource(\r
+ android.R.drawable.checkbox_off_background);\r
+ }\r
+ checkBoxV.setVisibility(View.VISIBLE);\r
+ }\r
+ }\r
+\r
+ } else { //Folder\r
+ fileSizeV.setVisibility(View.INVISIBLE);\r
+ }\r
+\r
+ case GRID_ITEM:\r
+ // filename\r
+ fileName = (TextView) view.findViewById(R.id.Filename);\r
+ name = file.getFileName();\r
+ fileName.setText(name);\r
+\r
+ case GRID_IMAGE:\r
+ // sharedIcon\r
+ ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);\r
+ if (file.isShareByLink()) {\r
+ sharedIconV.setVisibility(View.VISIBLE);\r
+ sharedIconV.bringToFront();\r
+ } else {\r
+ sharedIconV.setVisibility(View.GONE);\r
+ }\r
+\r
+ // local state\r
+ ImageView localStateView = (ImageView) view.findViewById(R.id.localFileIndicator);\r
+ localStateView.bringToFront();\r
+ FileDownloaderBinder downloaderBinder =\r
+ mTransferServiceGetter.getFileDownloaderBinder();\r
+ FileUploaderBinder uploaderBinder =\r
+ mTransferServiceGetter.getFileUploaderBinder();\r
+ boolean downloading = (downloaderBinder != null &&\r
+ downloaderBinder.isDownloading(mAccount, file));\r
+ OperationsServiceBinder opsBinder =\r
+ mTransferServiceGetter.getOperationsServiceBinder();\r
+ downloading |= (opsBinder != null &&\r
+ opsBinder.isSynchronizing(mAccount, file.getRemotePath()));\r
+ if (downloading) {\r
+ localStateView.setImageResource(R.drawable.downloading_file_indicator);\r
+ localStateView.setVisibility(View.VISIBLE);\r
+ } else if (uploaderBinder != null &&\r
+ uploaderBinder.isUploading(mAccount, file)) {\r
+ localStateView.setImageResource(R.drawable.uploading_file_indicator);\r
+ localStateView.setVisibility(View.VISIBLE);\r
+ } else if (file.isDown()) {\r
+ localStateView.setImageResource(R.drawable.local_file_indicator);\r
+ localStateView.setVisibility(View.VISIBLE);\r
+ } else {\r
+ localStateView.setVisibility(View.INVISIBLE);\r
+ }\r
+\r
+ // share with me icon\r
+ ImageView sharedWithMeIconV = (ImageView)\r
+ view.findViewById(R.id.sharedWithMeIcon);\r
+ sharedWithMeIconV.bringToFront();\r
+ if (checkIfFileIsSharedWithMe(file) &&\r
+ (!file.isFolder() || !mGridMode)) {\r
+ sharedWithMeIconV.setVisibility(View.VISIBLE);\r
+ } else {\r
+ sharedWithMeIconV.setVisibility(View.GONE);\r
+ }\r
+\r
+ break;\r
}\r
\r
- TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);\r
- TextView lastModV = (TextView) view.findViewById(R.id.last_mod);\r
- ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);\r
+ // For all Views\r
+ \r
+ // this if-else is needed even though favorite icon is visible by default\r
+ // because android reuses views in listview\r
+ if (!file.keepInSync()) {\r
+ view.findViewById(R.id.favoriteIcon).setVisibility(View.GONE);\r
+ } else {\r
+ view.findViewById(R.id.favoriteIcon).setVisibility(View.VISIBLE);\r
+ }\r
\r
+ // No Folder\r
if (!file.isFolder()) {\r
- fileSizeV.setVisibility(View.VISIBLE);\r
- fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
- lastModV.setVisibility(View.VISIBLE);\r
- lastModV.setText(showRelativeTimestamp(file));\r
- // this if-else is needed even thoe fav icon is visible by default\r
- // because android reuses views in listview\r
- if (!file.keepInSync()) {\r
- view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
- } else {\r
- view.findViewById(R.id.imageView3).setVisibility(View.VISIBLE);\r
- }\r
- \r
- ListView parentList = (ListView)parent;\r
- if (parentList.getChoiceMode() == ListView.CHOICE_MODE_NONE) { \r
- checkBoxV.setVisibility(View.GONE);\r
- } else {\r
- if (parentList.isItemChecked(position)) {\r
- checkBoxV.setImageResource(android.R.drawable.checkbox_on_background);\r
- } else {\r
- checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);\r
- }\r
- checkBoxV.setVisibility(View.VISIBLE);\r
- } \r
- \r
- // get Thumbnail if file is image\r
if (file.isImage() && file.getRemoteId() != null){\r
- // Thumbnail in Cache?\r
+ // Thumbnail in Cache?\r
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(\r
String.valueOf(file.getRemoteId())\r
- );\r
+ );\r
if (thumbnail != null && !file.needsUpdateThumbnail()){\r
fileIcon.setImageBitmap(thumbnail);\r
} else {\r
// generate new Thumbnail\r
if (ThumbnailsCacheManager.cancelPotentialWork(file, fileIcon)) {\r
- final ThumbnailsCacheManager.ThumbnailGenerationTask task = \r
+ final ThumbnailsCacheManager.ThumbnailGenerationTask task =\r
new ThumbnailsCacheManager.ThumbnailGenerationTask(\r
fileIcon, mStorageManager, mAccount\r
- );\r
+ );\r
if (thumbnail == null) {\r
thumbnail = ThumbnailsCacheManager.mDefaultImg;\r
}\r
- final AsyncDrawable asyncDrawable = new AsyncDrawable(\r
+ final ThumbnailsCacheManager.AsyncDrawable asyncDrawable =\r
+ new ThumbnailsCacheManager.AsyncDrawable(\r
mContext.getResources(), \r
thumbnail, \r
task\r
- );\r
+ );\r
fileIcon.setImageDrawable(asyncDrawable);\r
task.execute(file);\r
}\r
}\r
} else {\r
- fileIcon.setImageResource(\r
- DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())\r
- );\r
- }\r
-
- if (checkIfFileIsSharedWithMe(file)) {\r
- sharedWithMeIconV.setVisibility(View.VISIBLE);\r
+ fileIcon.setImageResource(DisplayUtils.getFileTypeIconId(file.getMimetype(),\r
+ file.getFileName()));\r
}\r
- } \r
- else {\r
- // TODO Re-enable when server supports folder-size calculation\r
-// if (FileStorageUtils.getDefaultSavePathFor(mAccount.name, file) != null){\r
-// fileSizeV.setVisibility(View.VISIBLE);\r
-// fileSizeV.setText(getFolderSizeHuman(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file)));\r
-// } else {\r
- fileSizeV.setVisibility(View.INVISIBLE);\r
-// }\r
-
- lastModV.setVisibility(View.VISIBLE);\r
- lastModV.setText(showRelativeTimestamp(file));\r
- checkBoxV.setVisibility(View.GONE);\r
- view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
\r
+ } else {\r
+ // Folder\r
if (checkIfFileIsSharedWithMe(file)) {\r
fileIcon.setImageResource(R.drawable.shared_with_me_folder);\r
- sharedWithMeIconV.setVisibility(View.VISIBLE);\r
+ } else if (file.isShareByLink()) {\r
+ // If folder is sharedByLink, icon folder must be changed to\r
+ // folder-public one\r
+ fileIcon.setImageResource(R.drawable.folder_public);\r
} else {\r
fileIcon.setImageResource(\r
- DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())\r
+ DisplayUtils.getFileTypeIconId(file.getMimetype(), file.getFileName())\r
);\r
}\r
-\r
- // If folder is sharedByLink, icon folder must be changed to\r
- // folder-public one\r
- if (file.isShareByLink()) {\r
- fileIcon.setImageResource(R.drawable.folder_public);\r
- }\r
- }\r
-\r
- if (file.isShareByLink()) {\r
- sharedIconV.setVisibility(View.VISIBLE);\r
- } else {\r
- sharedIconV.setVisibility(View.GONE);\r
}\r
}\r
\r
return view;\r
}\r
-
+\r
/**\r
* Local Folder size in human readable format\r
* \r
File dir = new File(path);\r
\r
if (dir.exists()) {\r
- long bytes = getFolderSize(dir);\r
+ long bytes = FileStorageUtils.getFolderSize(dir);\r
return DisplayUtils.bytesToHumanReadable(bytes);\r
}\r
\r
return result;\r
}\r
return 0;\r
- }
-
+ } \r
+\r
@Override\r
public int getViewTypeCount() {\r
return 1;\r
* @param updatedStorageManager Optional updated storage manager; used to replace \r
* mStorageManager if is different (and not NULL)\r
*/\r
- public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager) {\r
+ public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager\r
+ /*, boolean onlyOnDevice*/) {\r
mFile = directory;\r
if (updatedStorageManager != null && updatedStorageManager != mStorageManager) {\r
mStorageManager = updatedStorageManager;\r
mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);\r
}\r
if (mStorageManager != null) {\r
- mFiles = mStorageManager.getFolderContent(mFile);\r
+ // TODO Enable when "On Device" is recovered ?\r
+ mFiles = mStorageManager.getFolderContent(mFile/*, onlyOnDevice*/);\r
+ mFilesOrig.clear();\r
+ mFilesOrig.addAll(mFiles);\r
+ \r
if (mJustFolders) {\r
mFiles = getFolders(mFiles);\r
}\r
mFiles = null;\r
}\r
\r
- sortDirectory();\r
- }\r
- \r
- /**\r
- * Sorts all filenames, regarding last user decision \r
- */\r
- private void sortDirectory(){\r
- switch (mSortOrder){\r
- case 0:\r
- sortByName(mSortAscending);\r
- break;\r
- case 1:\r
- sortByDate(mSortAscending);\r
- break;\r
- case 2: \r
- sortBySize(mSortAscending);\r
- break;\r
- }\r
- \r
+ mFiles = FileStorageUtils.sortFolder(mFiles);\r
notifyDataSetChanged();\r
}\r
\r
- \r
+\r
/**\r
* Filter for getting only the folders\r
* @param files\r
&& file.getPermissions().contains(PERMISSION_SHARED_WITH_ME));\r
}\r
\r
- /**\r
- * Sorts list by Date\r
- * @param sortAscending true: ascending, false: descending\r
- */\r
- private void sortByDate(boolean sortAscending){\r
- final Integer val;\r
- if (sortAscending){\r
- val = 1;\r
- } else {\r
- val = -1;\r
- }\r
- \r
- Collections.sort(mFiles, new Comparator<OCFile>() {\r
- public int compare(OCFile o1, OCFile o2) {\r
- if (o1.isFolder() && o2.isFolder()) {\r
- Long obj1 = o1.getModificationTimestamp();\r
- return val * obj1.compareTo(o2.getModificationTimestamp());\r
- }\r
- else if (o1.isFolder()) {\r
- return -1;\r
- } else if (o2.isFolder()) {\r
- return 1;\r
- } else if (o1.getModificationTimestamp() == 0 || o2.getModificationTimestamp() == 0){\r
- return 0;\r
- } else {\r
- Long obj1 = o1.getModificationTimestamp();\r
- return val * obj1.compareTo(o2.getModificationTimestamp());\r
- }\r
- }\r
- });\r
- }\r
-\r
- /**\r
- * Sorts list by Size\r
- * @param sortAscending true: ascending, false: descending\r
- */\r
- private void sortBySize(boolean sortAscending){\r
- final Integer val;\r
- if (sortAscending){\r
- val = 1;\r
- } else {\r
- val = -1;\r
- }\r
- \r
- Collections.sort(mFiles, new Comparator<OCFile>() {\r
- public int compare(OCFile o1, OCFile o2) {\r
- if (o1.isFolder() && o2.isFolder()) {\r
- Long obj1 = getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o1)));\r
- return val * obj1.compareTo(getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o2))));\r
- }\r
- else if (o1.isFolder()) {\r
- return -1;\r
- } else if (o2.isFolder()) {\r
- return 1;\r
- } else if (o1.getFileLength() == 0 || o2.getFileLength() == 0){\r
- return 0;\r
- } else {\r
- Long obj1 = o1.getFileLength();\r
- return val * obj1.compareTo(o2.getFileLength());\r
- }\r
- }\r
- });\r
- }\r
-\r
- /**\r
- * Sorts list by Name\r
- * @param sortAscending true: ascending, false: descending\r
- */\r
- private void sortByName(boolean sortAscending){\r
- final Integer val;\r
- if (sortAscending){\r
- val = 1;\r
- } else {\r
- val = -1;\r
- }\r
-\r
- Collections.sort(mFiles, new Comparator<OCFile>() {\r
- public int compare(OCFile o1, OCFile o2) {\r
- if (o1.isFolder() && o2.isFolder()) {\r
- return val * o1.getRemotePath().toLowerCase().compareTo(o2.getRemotePath().toLowerCase());\r
- } else if (o1.isFolder()) {\r
- return -1;\r
- } else if (o2.isFolder()) {\r
- return 1;\r
- }\r
- return val * new AlphanumComparator().compare(o1, o2);\r
- }\r
- });\r
- }\r
-\r
public void setSortOrder(Integer order, boolean ascending) {\r
SharedPreferences.Editor editor = mAppPreferences.edit();\r
editor.putInt("sortOrder", order);\r
editor.putBoolean("sortAscending", ascending);\r
editor.commit();\r
\r
- mSortOrder = order;\r
- mSortAscending = ascending;\r
+ FileStorageUtils.mSortOrder = order;\r
+ FileStorageUtils.mSortAscending = ascending;\r
\r
- sortDirectory();\r
- } \r
+\r
+ mFiles = FileStorageUtils.sortFolder(mFiles);\r
+ notifyDataSetChanged();\r
+\r
+ }\r
\r
private CharSequence showRelativeTimestamp(OCFile file){\r
return DisplayUtils.getRelativeDateTimeString(mContext, file.getModificationTimestamp(),\r
DateUtils.SECOND_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, 0);\r
- }
+ }\r
+\r
+ public void setGridMode(boolean gridMode) {\r
+ mGridMode = gridMode;\r
+ }\r
}\r
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.adapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GroupAdapter {
+
+ public String string;
+ public final List<String> children = new ArrayList<String>();
+
+ public GroupAdapter(String string) {
+ this.string = string;
+ }
+
+}
\ No newline at end of file
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2014 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import java.util.Comparator;
import android.content.Context;
+import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.owncloud.android.R;
+import com.owncloud.android.datamodel.ThumbnailsCacheManager;
+import com.owncloud.android.utils.BitmapUtils;
import com.owncloud.android.utils.DisplayUtils;
/**
* This Adapter populates a ListView with all files and directories contained
* in a local directory
- *
- * @author David A. Velasco
- *
*/
public class LocalFileListAdapter extends BaseAdapter implements ListAdapter {
private Context mContext;
private File mDirectory;
private File[] mFiles = null;
-
+
public LocalFileListAdapter(File directory, Context context) {
mContext = context;
swapDirectory(directory);
String name = file.getName();
fileName.setText(name);
- ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1);
+ ImageView fileIcon = (ImageView) view.findViewById(R.id.thumbnail);
if (!file.isDirectory()) {
fileIcon.setImageResource(R.drawable.file);
} else {
fileIcon.setImageResource(R.drawable.ic_menu_archive);
}
+ fileIcon.setTag(file.hashCode());
TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);
TextView lastModV = (TextView) view.findViewById(R.id.last_mod);
if (!file.isDirectory()) {
fileSizeV.setVisibility(View.VISIBLE);
fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.length()));
+
lastModV.setVisibility(View.VISIBLE);
lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.lastModified()));
- ListView parentList = (ListView)parent;
+ ListView parentList = (ListView) parent;
if (parentList.getChoiceMode() == ListView.CHOICE_MODE_NONE) {
checkBoxV.setVisibility(View.GONE);
} else {
}
checkBoxV.setVisibility(View.VISIBLE);
}
+
+ // get Thumbnail if file is image
+ if (BitmapUtils.isImage(file)){
+ // Thumbnail in Cache?
+ Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
+ String.valueOf(file.hashCode())
+ );
+ if (thumbnail != null){
+ fileIcon.setImageBitmap(thumbnail);
+ } else {
+
+ // generate new Thumbnail
+ if (ThumbnailsCacheManager.cancelPotentialWork(file, fileIcon)) {
+ final ThumbnailsCacheManager.ThumbnailGenerationTask task =
+ new ThumbnailsCacheManager.ThumbnailGenerationTask(fileIcon);
+ if (thumbnail == null) {
+ thumbnail = ThumbnailsCacheManager.mDefaultImg;
+ }
+ final ThumbnailsCacheManager.AsyncDrawable asyncDrawable =
+ new ThumbnailsCacheManager.AsyncDrawable(
+ mContext.getResources(),
+ thumbnail,
+ task
+ );
+ fileIcon.setImageDrawable(asyncDrawable);
+ task.execute(file);
+ }
+ }
+ } else {
+ fileIcon.setImageResource(DisplayUtils.getFileTypeIconId(null, file.getName()));
+ }
} else {
fileSizeV.setVisibility(View.GONE);
lastModV.setVisibility(View.GONE);
checkBoxV.setVisibility(View.GONE);
}
-
- view.findViewById(R.id.imageView2).setVisibility(View.INVISIBLE); // not GONE; the alignment changes; ugly way to keep it
- view.findViewById(R.id.imageView3).setVisibility(View.GONE);
+
+ // not GONE; the alignment changes; ugly way to keep it
+ view.findViewById(R.id.localFileIndicator).setVisibility(View.INVISIBLE);
+ view.findViewById(R.id.favoriteIcon).setVisibility(View.GONE);
view.findViewById(R.id.sharedIcon).setVisibility(View.GONE);
view.findViewById(R.id.sharedWithMeIcon).setVisibility(View.GONE);
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
package com.owncloud.android.ui.adapter;
import java.io.File;
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.adapter;
+
+import android.app.Activity;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.owncloud.android.R;
+
+public class MyExpandableListAdapter extends BaseExpandableListAdapter {
+
+ private final SparseArray<GroupAdapter> groups;
+ public LayoutInflater inflater;
+ public Activity activity;
+
+ public MyExpandableListAdapter(Activity act, SparseArray<GroupAdapter> groups) {
+ activity = act;
+ this.groups = groups;
+ inflater = act.getLayoutInflater();
+
+ }
+
+
+ @Override
+ public Object getChild(int groupPosition, int childPosition) {
+ return groups.get(groupPosition).children.get(childPosition);
+ }
+
+ @Override
+ public long getChildId(int groupPosition, int childPosition) {
+ return 0;
+ }
+
+ @Override
+ public View getChildView(int groupPosition, final int childPosition,
+ boolean isLastChild, View convertView, ViewGroup parent) {
+ final String children = (String) getChild(groupPosition, childPosition);
+ TextView text = null;
+ if (convertView == null) {
+ convertView = inflater.inflate(R.layout.listrow_details, null);
+ }
+
+
+ text = (TextView) convertView.findViewById(R.id.textView1);
+ text.setText(children);
+ convertView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Toast.makeText(activity, children, Toast.LENGTH_SHORT).show();
+ }
+ });
+ return convertView;
+ }
+
+ @Override
+ public View getGroupView(int groupPosition, boolean isExpanded,
+ View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = inflater.inflate(R.layout.listrow_group, null);
+ }
+
+ final GroupAdapter groupAdapter = (GroupAdapter) getGroup(groupPosition);
+ if (groupAdapter.children.size() == 0){
+ convertView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Toast.makeText(activity, groupAdapter.string, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ ((TextView) convertView).setText(groupAdapter.string);
+
+ return convertView;
+ }
+
+ @Override
+ public int getChildrenCount(int groupPosition) {
+ return groups.get(groupPosition).children.size();
+ }
+
+ @Override
+ public Object getGroup(int groupPosition) {
+ return groups.get(groupPosition);
+ }
+
+ @Override
+ public int getGroupCount() {
+ return groups.size();
+ }
+
+ @Override
+ public void onGroupCollapsed(int groupPosition) {
+ super.onGroupCollapsed(groupPosition);
+ }
+
+ @Override
+ public void onGroupExpanded(int groupPosition) {
+ super.onGroupExpanded(groupPosition);
+ }
+
+ @Override
+ public long getGroupId(int groupPosition) {
+ return 0;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return false;
+ }
+
+ @Override
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return false;
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author tobiasKaminsky
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.adapter;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.ui.NavigationDrawerItem;
+import com.owncloud.android.ui.activity.FileActivity;
+
+import java.util.ArrayList;
+
+public class NavigationDrawerListAdapter extends BaseAdapter {
+
+ private final static String TAG = NavigationDrawerListAdapter.class.getSimpleName();
+
+ private Context mContext;
+
+ private ArrayList<NavigationDrawerItem> mNavigationDrawerItems;
+ private ArrayList<Object> mAll = new ArrayList<Object>();
+ private Account[] mAccounts;
+ private boolean mShowAccounts;
+ private Account mCurrentAccount;
+ private FileActivity mFileActivity;
+
+
+ public NavigationDrawerListAdapter(Context context, FileActivity fileActivity,
+ ArrayList<NavigationDrawerItem> navigationDrawerItems){
+ mFileActivity = fileActivity;
+ mContext = context;
+ mNavigationDrawerItems = navigationDrawerItems;
+
+ updateAccountList();
+
+ mAll.addAll(mNavigationDrawerItems);
+ }
+
+ public void updateAccountList(){
+ AccountManager am = (AccountManager) mContext.getSystemService(mContext.ACCOUNT_SERVICE);
+ mAccounts = am.getAccountsByType(MainApp.getAccountType());
+ mCurrentAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
+ }
+
+ @Override
+ public int getCount() {
+ if (mShowAccounts){
+ return mNavigationDrawerItems.size() + 1;
+ } else {
+ return mNavigationDrawerItems.size();
+ }
+ }
+
+ @Override
+ public Object getItem(int position) {
+ //return all.get(position);
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+
+ LayoutInflater inflator = (LayoutInflater) mContext
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ if (mAll.size() > position) {
+ // Normal entry
+ if (mAll.get(position) instanceof NavigationDrawerItem){
+ NavigationDrawerItem navItem = (NavigationDrawerItem) mAll.get(position);
+
+ View view = inflator.inflate(R.layout.drawer_list_item, null);
+ view.setMinimumHeight(40);
+ LinearLayout itemLayout = (LinearLayout) view.findViewById(R.id.itemLayout);
+ itemLayout.setContentDescription(navItem.getContentDescription());
+ TextView itemText = (TextView) view.findViewById(R.id.itemTitle);
+ itemText.setText(navItem.getTitle());
+
+ return view;
+ }
+ // TODO re-enable when "Accounts" is available in Navigation Drawer
+ // Account
+// if (mAll.get(position) instanceof Account[]){
+// final View view = inflator.inflate(R.layout.drawer_account_group, null);
+//
+// final RadioGroup group = (RadioGroup) view.findViewById(R.id.drawer_radio_group);
+//
+// for (Account account : mAccounts) {
+// RadioButton rb = new RadioButton(mContext);
+//
+// rb.setText(account.name);
+// rb.setContentDescription(account.name);
+// rb.setTextColor(Color.BLACK);
+// rb.setEllipsize(TextUtils.TruncateAt.MIDDLE);
+// rb.setSingleLine();
+// rb.setCompoundDrawablePadding(30);
+//
+//
+// try {
+// // using adapted algorithm from /core/js/placeholder.js:50
+// int lastAtPos = account.name.lastIndexOf("@");
+// String username = account.name.substring(0, lastAtPos);
+// byte[] seed = username.getBytes("UTF-8");
+// MessageDigest md = MessageDigest.getInstance("MD5");
+//// Integer seedMd5Int = Math.abs(new String(Hex.encodeHex(seedMd5))
+//// .hashCode());
+// Integer seedMd5Int = String.format(Locale.ROOT, "%032x",
+// new BigInteger(1, md.digest(seed))).hashCode();
+//
+// double maxRange = java.lang.Integer.MAX_VALUE;
+// float hue = (float) (seedMd5Int / maxRange * 360);
+//
+// int[] rgb = BitmapUtils.HSLtoRGB(hue, 90.0f, 65.0f, 1.0f);
+//
+// TextDrawable text = new TextDrawable(username.substring(0, 1).toUpperCase(),
+// rgb[0], rgb[1], rgb[2]);
+// rb.setCompoundDrawablesWithIntrinsicBounds(text, null, null, null);
+//
+//
+// } catch (Exception e){
+// Log_OC.d(TAG, e.toString());
+// rb.setTextColor(mContext.getResources().getColor(R.color.black));
+// }
+// RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(
+// LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+// params.weight=1.0f;
+// params.setMargins(15, 5, 5, 5);
+//
+// // Check the current account that is being used
+// if (account.name.equals(mCurrentAccount.name)) {
+// rb.setChecked(true);
+// } else {
+// rb.setChecked(false);
+// }
+//
+// group.addView(rb, params);
+// }
+//
+// group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){
+// public void onCheckedChanged(RadioGroup group, int checkedId) {
+// // checkedId is the RadioButton selected
+// RadioButton rb = (RadioButton) view.findViewById(checkedId);
+//
+// AccountUtils.setCurrentOwnCloudAccount(mContext,rb.getText().toString());
+// notifyDataSetChanged();
+// mFileActivity.closeDrawer();
+//
+// // restart the main activity
+// mFileActivity.restart();
+// }
+// });
+//
+// return view;
+// }
+ }
+ return convertView;
+ }
+
+ //TODO re-enable when "Accounts" is available in Navigation Drawer
+ // TODO update Account List after creating a new account and on fresh installation
+// public void setShowAccounts(boolean value){
+// mAll.clear();
+// mAll.addAll(mNavigationDrawerItems);
+//
+// if (value){
+// mAll.add(1, mAccounts);
+// }
+// mShowAccounts = value;
+// }
+}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* TODO
- *
- * @author masensio
- * @author David A. Velasco
*/
public class SslCertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter {
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* Dialog to show an Untrusted Certificate
- *
- * @author masensio
- * @author David A. Velasco
- *
*/
public class SslErrorViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter {
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.widget.TextView;
/**
- *
- * @author masensio
- * @author David A. Velasco
*
*/
public class X509CertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter {
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.webkit.WebView;
-import com.actionbarsherlock.app.SherlockDialogFragment;
import com.owncloud.android.R;
import com.owncloud.android.utils.DisplayUtils;
/**
* Dialog to show the contents of res/raw/CHANGELOG.txt
*/
-public class ChangelogDialog extends SherlockDialogFragment {
+public class ChangelogDialog extends DialogFragment {
- private static final String ARG_CANCELABLE = ChangelogDialog.class.getCanonicalName() + ".ARG_CANCELABLE";
+ private static final String ARG_CANCELABLE = ChangelogDialog.class.getCanonicalName() +
+ ".ARG_CANCELABLE";
/**
* Public factory method to get dialog instances.
*
- * @param cancelable If 'true', the dialog can be cancelled by the user input (BACK button, touch outside...)
+ * @param cancelable If 'true', the dialog can be cancelled by the user input
+ * (BACK button, touch outside...)
* @return New dialog instance, ready to show.
*/
public static ChangelogDialog newInstance(boolean cancelable) {
public Dialog onCreateDialog(Bundle savedInstanceState) {
/// load the custom view to insert in the dialog, between title and
WebView webview = new WebView(getActivity());
- webview.loadUrl("file:///android_res/raw/" + getResources().getResourceEntryName(R.raw.changelog) + ".html");
+ webview.loadUrl("file:///android_res/raw/" +
+ getResources().getResourceEntryName(R.raw.changelog) + ".html");
/// build the dialog
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
* {@inheritDoc}
*-/
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
/// load the custom layout
View view = inflater.inflate(R.layout.fragment_changelog, container);
mEditText = (EditText) view.findViewById(R.id.txt_your_name);
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
-import com.actionbarsherlock.app.SherlockDialogFragment;
import com.owncloud.android.lib.common.utils.Log_OC;
-public class ConfirmationDialogFragment extends SherlockDialogFragment {
+public class ConfirmationDialogFragment extends DialogFragment {
public final static String ARG_CONF_RESOURCE_ID = "resource_id";
public final static String ARG_CONF_ARGUMENTS = "string_array";
builder.setPositiveButton(posBtn,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
- mListener.onConfirmation(getTag());
+ if (mListener != null) {
+ mListener.onConfirmation(getTag());
+ }
dialog.dismiss();
}
});
builder.setNeutralButton(neuBtn,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
- mListener.onNeutral(getTag());
+ if (mListener != null) {
+ mListener.onNeutral(getTag());
+ }
dialog.dismiss();
}
});
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- mListener.onCancel(getTag());
+ if (mListener != null) {
+ mListener.onCancel(getTag());
+ }
dialog.dismiss();
}
});
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
+import android.support.v7.app.ActionBarActivity;
-import com.actionbarsherlock.app.SherlockDialogFragment;
-import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.owncloud.android.R;
import com.owncloud.android.utils.DisplayUtils;
/**
* Dialog which will be displayed to user upon keep-in-sync file conflict.
- *
- * @author Bartek Przybylski
- *
*/
-public class ConflictsResolveDialog extends SherlockDialogFragment {
+public class ConflictsResolveDialog extends DialogFragment {
public static enum Decision {
CANCEL,
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
String remotepath = getArguments().getString("remotepath");
- return new AlertDialog.Builder(getSherlockActivity())
+ return new AlertDialog.Builder(getActivity())
.setIcon(DisplayUtils.getSeasonalIconId())
.setTitle(R.string.conflict_title)
.setMessage(String.format(getString(R.string.conflict_message), remotepath))
.create();
}
- public void showDialog(SherlockFragmentActivity activity) {
+ public void showDialog(ActionBarActivity activity) {
Fragment prev = activity.getSupportFragmentManager().findFragmentByTag("dialog");
FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
if (prev != null) {
this.show(ft, "dialog");
}
- public void dismissDialog(SherlockFragmentActivity activity) {
+ public void dismissDialog(ActionBarActivity activity) {
Fragment prev = activity.getSupportFragmentManager().findFragmentByTag(getTag());
if (prev != null) {
FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
-/* ownCloud Android client application
- * Copyright (C) 2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.ui.dialog;
-import com.actionbarsherlock.app.SherlockDialogFragment;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.resources.files.FileUtils;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager.LayoutParams;
/**
* Dialog to input the name for a new folder to create.
*
- * Triggers the folder creation when name is confirmed.
- *
- * @author David A. Velasco
+ * Triggers the folder creation when name is confirmed.
*/
-public class CreateFolderDialogFragment
-extends SherlockDialogFragment implements DialogInterface.OnClickListener {
+public class CreateFolderDialogFragment
+ extends DialogFragment implements DialogInterface.OnClickListener {
private static final String ARG_PARENT_FOLDER = "PARENT_FOLDER";
/**
* Public factory method to create new CreateFolderDialogFragment instances.
- *
- * @param file File to remove.
- * @return Dialog ready to show.
+ *
+ * @param parentFolder Folder to create
+ * @return Dialog ready to show.
*/
public static CreateFolderDialogFragment newInstance(OCFile parentFolder) {
CreateFolderDialogFragment frag = new CreateFolderDialogFragment();
mParentFolder = getArguments().getParcelable(ARG_PARENT_FOLDER);
// Inflate the layout for the dialog
- LayoutInflater inflater = getSherlockActivity().getLayoutInflater();
+ LayoutInflater inflater = getActivity().getLayoutInflater();
View v = inflater.inflate(R.layout.edit_box_dialog, null);
// Setup layout
inputText.requestFocus();
// Build the dialog
- AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(v)
.setPositiveButton(R.string.common_ok, this)
.setNegativeButton(R.string.common_cancel, this)
if (newFolderName.length() <= 0) {
Toast.makeText(
- getSherlockActivity(),
+ getActivity(),
R.string.filename_empty,
Toast.LENGTH_LONG).show();
return;
}
-
- if (!FileUtils.isValidName(newFolderName)) {
- Toast.makeText(
- getSherlockActivity(),
- R.string.filename_forbidden_characters,
- Toast.LENGTH_LONG).show();
+ boolean serverWithForbiddenChars = ((ComponentsGetter)getActivity()).
+ getFileOperationsHelper().isVersionWithForbiddenCharacters();
+
+ if (!FileUtils.isValidName(newFolderName, serverWithForbiddenChars)) {
+ int messageId = 0;
+ if (serverWithForbiddenChars) {
+ messageId = R.string.filename_forbidden_charaters_from_server;
+ } else {
+ messageId = R.string.filename_forbidden_characters;
+ }
+ Toast.makeText(getActivity(), messageId, Toast.LENGTH_LONG).show();
+
return;
}
String path = mParentFolder.getRemotePath();
path += newFolderName + OCFile.PATH_SEPARATOR;
- ((ComponentsGetter)getSherlockActivity()).
+ ((ComponentsGetter)getActivity()).
getFileOperationsHelper().createFolder(path, false);
}
}
-/* ownCloud Android client application
- * Copyright (C) 2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.ui.dialog;
-import com.actionbarsherlock.app.SherlockDialogFragment;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AuthenticatorActivity;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.text.InputType;
import android.view.WindowManager.LayoutParams;
import android.webkit.HttpAuthHandler;
* Dialog to input authentication credentials
*
*/
-public class CredentialsDialogFragment extends SherlockDialogFragment
+public class CredentialsDialogFragment extends DialogFragment
implements DialogInterface.OnClickListener {
private WebView mWebView = null;
* @param handler HttpAuthHandler
* @return Dialog ready to show
*/
- public static CredentialsDialogFragment newInstanceForCredentials(WebView webView, HttpAuthHandler handler) {
+ public static CredentialsDialogFragment newInstanceForCredentials(WebView webView,
+ HttpAuthHandler handler) {
if (handler == null) {
- throw new IllegalArgumentException("Trying to create instance with parameter handler == null");
+ throw new IllegalArgumentException("Trying to create instance with parameter handler" +
+ " == null");
}
CredentialsDialogFragment frag = new CredentialsDialogFragment();
frag.mHandler = handler;
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Create field for username
- mUsernameET = new EditText(getSherlockActivity());
- mUsernameET.setHint(getSherlockActivity().getText(R.string.auth_username));
+ mUsernameET = new EditText(getActivity());
+ mUsernameET.setHint(getActivity().getText(R.string.auth_username));
// Create field for password
- mPasswordET = new EditText(getSherlockActivity());
- mPasswordET.setHint(getSherlockActivity().getText(R.string.auth_password));
+ mPasswordET = new EditText(getActivity());
+ mPasswordET.setHint(getActivity().getText(R.string.auth_password));
mPasswordET.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
// Prepare LinearLayout for dialog
- LinearLayout ll = new LinearLayout(getSherlockActivity());
+ LinearLayout ll = new LinearLayout(getActivity());
ll.setOrientation(LinearLayout.VERTICAL);
ll.addView(mUsernameET);
ll.addView(mPasswordET);
setRetainInstance(true);
Builder authDialog = new AlertDialog
- .Builder(getSherlockActivity())
- .setTitle(getSherlockActivity().getText(R.string.saml_authentication_required_text))
+ .Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.saml_authentication_required_text))
.setView(ll)
.setCancelable(false)
.setPositiveButton(R.string.common_ok, this)
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.content.DialogInterface;
import android.content.DialogInterface.OnKeyListener;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.view.KeyEvent;
-import com.actionbarsherlock.app.SherlockDialogFragment;
import com.owncloud.android.R;
-public class IndeterminateProgressDialog extends SherlockDialogFragment {
+public class IndeterminateProgressDialog extends DialogFragment {
private static final String ARG_MESSAGE_ID = IndeterminateProgressDialog.class.getCanonicalName() + ".ARG_MESSAGE_ID";
private static final String ARG_CANCELABLE = IndeterminateProgressDialog.class.getCanonicalName() + ".ARG_CANCELABLE";
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
-/* ownCloud Android client application
- * Copyright (C) 2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* Dialog requiring confirmation before removing a given OCFile.
*
- * Triggers the removal according to the user response.
- *
- * @author David A. Velasco
+ * Triggers the removal according to the user response.
*/
import java.util.Vector;
+import android.app.Dialog;
+import android.os.Bundle;
+
import com.owncloud.android.R;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.ui.activity.ComponentsGetter;
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
-import android.app.Dialog;
-import android.os.Bundle;
-
public class RemoveFileDialogFragment extends ConfirmationDialogFragment
implements ConfirmationDialogFragmentListener {
*/
@Override
public void onConfirmation(String callerTag) {
- ComponentsGetter cg = (ComponentsGetter)getSherlockActivity();
+ ComponentsGetter cg = (ComponentsGetter)getActivity();
FileDataStorageManager storageManager = cg.getStorageManager();
if (storageManager.getFileById(mTargetFile.getFileId()) != null) {
cg.getFileOperationsHelper().removeFile(mTargetFile, false);
*/
@Override
public void onNeutral(String callerTag) {
- ComponentsGetter cg = (ComponentsGetter)getSherlockActivity();
- cg.getFileOperationsHelper()
- .removeFile(mTargetFile, true);
+ ComponentsGetter cg = (ComponentsGetter)getActivity();
+ cg.getFileOperationsHelper().removeFile(mTargetFile, true);
FileDataStorageManager storageManager = cg.getStorageManager();
boolean containsKeepInSync = false;
if (mTargetFile.isFolder()) {
- Vector<OCFile> files = storageManager.getFolderContent(mTargetFile);
+ // TODO Enable when "On Device" is recovered ?
+ Vector<OCFile> files = storageManager.getFolderContent(mTargetFile/*, false*/);
for(OCFile file: files) {
containsKeepInSync = file.keepInSync() || containsKeepInSync;
// nothing to do here
}
-}
+}
\ No newline at end of file
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
* Copyright (C) 2014 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
*
* Triggers the rename operation.
*/
-import com.actionbarsherlock.app.SherlockDialogFragment;
-import com.owncloud.android.R;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.lib.resources.files.FileUtils;
-import com.owncloud.android.ui.activity.ComponentsGetter;
-
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.widget.TextView;
import android.widget.Toast;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+
/**
* Dialog to input a new name for a file or folder to rename.
*
- * Triggers the rename operation when name is confirmed.
- *
- * @author David A. Velasco
+ * Triggers the rename operation when name is confirmed.
*/
public class RenameFileDialogFragment
-extends SherlockDialogFragment implements DialogInterface.OnClickListener {
+ extends DialogFragment implements DialogInterface.OnClickListener {
private static final String ARG_TARGET_FILE = "TARGET_FILE";
mTargetFile = getArguments().getParcelable(ARG_TARGET_FILE);
// Inflate the layout for the dialog
- LayoutInflater inflater = getSherlockActivity().getLayoutInflater();
+ LayoutInflater inflater = getActivity().getLayoutInflater();
View v = inflater.inflate(R.layout.edit_box_dialog, null);
// Setup layout
inputText.requestFocus();
// Build the dialog
- AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(v)
.setPositiveButton(R.string.common_ok, this)
.setNegativeButton(R.string.common_cancel, this)
if (newFileName.length() <= 0) {
Toast.makeText(
- getSherlockActivity(),
+ getActivity(),
R.string.filename_empty,
Toast.LENGTH_LONG).show();
return;
}
-
- if (!FileUtils.isValidName(newFileName)) {
- Toast.makeText(
- getSherlockActivity(),
- R.string.filename_forbidden_characters,
- Toast.LENGTH_LONG).show();
+
+ boolean serverWithForbiddenChars = ((ComponentsGetter)getActivity()).
+ getFileOperationsHelper().isVersionWithForbiddenCharacters();
+
+ if (!FileUtils.isValidName(newFileName, serverWithForbiddenChars)) {
+ int messageId = 0;
+ if (serverWithForbiddenChars) {
+ messageId = R.string.filename_forbidden_charaters_from_server;
+ } else {
+ messageId = R.string.filename_forbidden_characters;
+ }
+ Toast.makeText(getActivity(), messageId, Toast.LENGTH_LONG).show();
return;
}
-
- ((ComponentsGetter)getSherlockActivity()).
- getFileOperationsHelper().renameFile(mTargetFile, newFileName);
-
-
+
+ ((ComponentsGetter)getActivity()).getFileOperationsHelper().
+ renameFile(mTargetFile, newFileName);
+
}
}
-
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author Maria Asensio
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
+import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater;
import android.webkit.WebView;
import android.widget.RelativeLayout;
-import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.SsoWebViewClient;
import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;
-import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.utils.Log_OC;
/**
* Dialog to show the WebView for SAML Authentication
- *
- * @author Maria Asensio
- * @author David A. Velasco
*/
-public class SamlWebViewDialog extends SherlockDialogFragment {
+public class SamlWebViewDialog extends DialogFragment {
public final String SAML_DIALOG_TAG = "SamlWebViewDialog";
/**
* Public factory method to get dialog instances.
- *
- * @param handler
- * @param Url Url to open at WebView
- * @param targetURL mBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType)
+ *
+ * @param url Url to open at WebView
+ * @param targetUrl mBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, m
+ * CurrentAuthTokenType)
* @return New dialog instance, ready to show.
*/
public static SamlWebViewDialog newInstance(String url, String targetUrl) {
- Log_OC.d(TAG, "New instance");
SamlWebViewDialog fragment = new SamlWebViewDialog();
Bundle args = new Bundle();
args.putString(ARG_INITIAL_URL, url);
public SamlWebViewDialog() {
super();
- Log_OC.d(TAG, "constructor");
}
@Override
public void onAttach(Activity activity) {
- Log_OC.d(TAG, "onAttach");
+ Log_OC.v(TAG, "onAttach");
super.onAttach(activity);
try {
mSsoWebViewClientListener = (SsoWebViewClientListener) activity;
mWebViewClient = new SsoWebViewClient(activity, mHandler, mSsoWebViewClientListener);
} catch (ClassCastException e) {
- throw new ClassCastException(activity.toString() + " must implement " + SsoWebViewClientListener.class.getSimpleName());
+ throw new ClassCastException(activity.toString() + " must implement " +
+ SsoWebViewClientListener.class.getSimpleName());
}
}
@SuppressLint("SetJavaScriptEnabled")
@Override
public void onCreate(Bundle savedInstanceState) {
- Log_OC.d(TAG, "onCreate, savedInstanceState is " + savedInstanceState);
+ Log_OC.v(TAG, "onCreate, savedInstanceState is " + savedInstanceState);
super.onCreate(savedInstanceState);
setRetainInstance(true);
- CookieSyncManager.createInstance(getSherlockActivity().getApplicationContext());
+ CookieSyncManager.createInstance(getActivity().getApplicationContext());
if (savedInstanceState == null) {
mInitialUrl = getArguments().getString(ARG_INITIAL_URL);
mTargetUrl = savedInstanceState.getString(ARG_TARGET_URL);
}
- setStyle(SherlockDialogFragment.STYLE_NO_TITLE, R.style.Theme_ownCloud_Dialog);
+ setStyle(DialogFragment.STYLE_NO_TITLE, R.style.Theme_ownCloud_Dialog);
}
@SuppressWarnings("deprecation")
@SuppressLint("SetJavaScriptEnabled")
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- Log_OC.d(TAG, "onCreateView, savedInsanceState is " + savedInstanceState);
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ Log_OC.v(TAG, "onCreateView, savedInsanceState is " + savedInstanceState);
// Inflate layout of the dialog
- RelativeLayout ssoRootView = (RelativeLayout) inflater.inflate(R.layout.sso_dialog, container, false); // null parent view because it will go in the dialog layout
+ RelativeLayout ssoRootView = (RelativeLayout) inflater.inflate(R.layout.sso_dialog,
+ container, false); // null parent view because it will go in the dialog layout
if (mSsoWebView == null) {
// initialize the WebView
- mSsoWebView = new SsoWebView(getSherlockActivity().getApplicationContext());
+ mSsoWebView = new SsoWebView(getActivity().getApplicationContext());
mSsoWebView.setFocusable(true);
mSsoWebView.setFocusableInTouchMode(true);
mSsoWebView.setClickable(true);
- CookieManager cookieManager = CookieManager.getInstance();
- cookieManager.setAcceptCookie(true);
- cookieManager.removeAllCookie();
- mSsoWebView.loadUrl(mInitialUrl);
-
WebSettings webSettings = mSsoWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setBuiltInZoomControls(false);
webSettings.setLoadWithOverviewMode(false);
webSettings.setSavePassword(false);
- webSettings.setUserAgentString(OwnCloudClient.USER_AGENT);
+ webSettings.setUserAgentString(MainApp.getUserAgent());
webSettings.setSaveFormData(false);
+
+ CookieManager cookieManager = CookieManager.getInstance();
+ cookieManager.setAcceptCookie(true);
+ cookieManager.removeAllCookie();
+
+ mSsoWebView.loadUrl(mInitialUrl);
}
mWebViewClient.setTargetUrl(mTargetUrl);
@Override
public void onSaveInstanceState(Bundle outState) {
- Log_OC.d(TAG, "onSaveInstanceState being CALLED");
+ Log_OC.v(TAG, "onSaveInstanceState being CALLED");
super.onSaveInstanceState(outState);
// save URLs
@Override
public void onDestroyView() {
- Log_OC.d(TAG, "onDestroyView");
+ Log_OC.v(TAG, "onDestroyView");
if ((ViewGroup)mSsoWebView.getParent() != null) {
((ViewGroup)mSsoWebView.getParent()).removeView(mSsoWebView);
Dialog dialog = getDialog();
if ((dialog != null)) {
dialog.setOnDismissListener(null);
- //dialog.dismiss();
- //dialog.setDismissMessage(null);
}
super.onDestroyView();
@Override
public void onDestroy() {
- Log_OC.d(TAG, "onDestroy");
+ Log_OC.v(TAG, "onDestroy");
super.onDestroy();
}
@Override
public void onDetach() {
- Log_OC.d(TAG, "onDetach");
+ Log_OC.v(TAG, "onDetach");
mSsoWebViewClientListener = null;
mWebViewClient = null;
super.onDetach();
@Override
public void onStart() {
- Log_OC.d(TAG, "onStart");
+ Log_OC.v(TAG, "onStart");
super.onStart();
}
@Override
public void onStop() {
- Log_OC.d(TAG, "onStop");
+ Log_OC.v(TAG, "onStop");
super.onStop();
}
@Override
public void onResume() {
- Log_OC.d(TAG, "onResume");
+ Log_OC.v(TAG, "onResume");
super.onResume();
mSsoWebView.onResume();
}
@Override
public void onPause() {
- Log_OC.d(TAG, "onPause");
+ Log_OC.v(TAG, "onPause");
mSsoWebView.onPause();
super.onPause();
}
@Override
public int show (FragmentTransaction transaction, String tag) {
- Log_OC.d(TAG, "show (transaction)");
+ Log_OC.v(TAG, "show (transaction)");
return super.show(transaction, tag);
}
@Override
public void show (FragmentManager manager, String tag) {
- Log_OC.d(TAG, "show (manager)");
+ Log_OC.v(TAG, "show (manager)");
super.show(manager, tag);
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-import com.actionbarsherlock.app.SherlockDialogFragment;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.utils.Log_OC;
/**
* Dialog showing a list activities able to resolve a given Intent,
* filtering out the activities matching give package names.
- *
- * @author David A. Velasco
*/
-public class ShareLinkToDialog extends SherlockDialogFragment {
+public class ShareLinkToDialog extends DialogFragment {
private final static String TAG = ShareLinkToDialog.class.getSimpleName();
- private final static String ARG_INTENT = ShareLinkToDialog.class.getSimpleName() + ".ARG_INTENT";
- private final static String ARG_PACKAGES_TO_EXCLUDE = ShareLinkToDialog.class.getSimpleName() + ".ARG_PACKAGES_TO_EXCLUDE";
- private final static String ARG_FILE_TO_SHARE = ShareLinkToDialog.class.getSimpleName() + ".FILE_TO_SHARE";
+ private final static String ARG_INTENT = ShareLinkToDialog.class.getSimpleName() +
+ ".ARG_INTENT";
+ private final static String ARG_PACKAGES_TO_EXCLUDE = ShareLinkToDialog.class.getSimpleName() +
+ ".ARG_PACKAGES_TO_EXCLUDE";
+ private final static String ARG_FILE_TO_SHARE = ShareLinkToDialog.class.getSimpleName() +
+ ".FILE_TO_SHARE";
private ActivityAdapter mAdapter;
private OCFile mFile;
private Intent mIntent;
- public static ShareLinkToDialog newInstance(Intent intent, String[] packagesToExclude, OCFile fileToShare) {
+ public static ShareLinkToDialog newInstance(Intent intent, String[] packagesToExclude,
+ OCFile fileToShare) {
ShareLinkToDialog f = new ShareLinkToDialog();
Bundle args = new Bundle();
args.putParcelable(ARG_INTENT, intent);
public Dialog onCreateDialog(Bundle savedInstanceState) {
mIntent = getArguments().getParcelable(ARG_INTENT);
String[] packagesToExclude = getArguments().getStringArray(ARG_PACKAGES_TO_EXCLUDE);
- List<String> packagesToExcludeList = Arrays.asList(packagesToExclude != null ? packagesToExclude : new String[0]);
+ List<String> packagesToExcludeList = Arrays.asList(packagesToExclude != null ?
+ packagesToExclude : new String[0]);
mFile = getArguments().getParcelable(ARG_FILE_TO_SHARE);
- PackageManager pm= getSherlockActivity().getPackageManager();
- List<ResolveInfo> activities = pm.queryIntentActivities(mIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ PackageManager pm= getActivity().getPackageManager();
+ List<ResolveInfo> activities = pm.queryIntentActivities(mIntent,
+ PackageManager.MATCH_DEFAULT_ONLY);
Iterator<ResolveInfo> it = activities.iterator();
ResolveInfo resolveInfo;
while (it.hasNext()) {
resolveInfo = it.next();
- if (packagesToExcludeList.contains(resolveInfo.activityInfo.packageName.toLowerCase())) {
+ if (packagesToExcludeList.contains(resolveInfo.activityInfo.packageName.toLowerCase())){
it.remove();
}
}
if (!sendAction) {
// add activity for copy to clipboard
- Intent copyToClipboardIntent = new Intent(getSherlockActivity(), CopyToClipboardActivity.class);
+ Intent copyToClipboardIntent = new Intent(getActivity(), CopyToClipboardActivity.class);
List<ResolveInfo> copyToClipboard = pm.queryIntentActivities(copyToClipboardIntent, 0);
if (!copyToClipboard.isEmpty()) {
activities.add(copyToClipboard.get(0));
}
Collections.sort(activities, new ResolveInfo.DisplayNameComparator(pm));
- mAdapter = new ActivityAdapter(getSherlockActivity(), pm, activities);
+ mAdapter = new ActivityAdapter(getActivity(), pm, activities);
return createSelector(sendAction);
titleId = R.string.activity_chooser_title;
}
- return new AlertDialog.Builder(getSherlockActivity())
+ return new AlertDialog.Builder(getActivity())
.setTitle(titleId)
.setAdapter(mAdapter, new DialogInterface.OnClickListener() {
@Override
dialog.dismiss(); // explicitly added for Android 2.x devices
// Send the file
- ((FileActivity)getSherlockActivity()).startActivity(mIntent);
+ ((FileActivity)getActivity()).startActivity(mIntent);
} else {
// Create a new share resource
- ((ComponentsGetter)getSherlockActivity()).getFileOperationsHelper()
- .shareFileWithLinkToApp(mFile, mIntent);
+ ((ComponentsGetter)getActivity()).getFileOperationsHelper()
+ .shareFileWithLinkToApp(mFile, "", mIntent);
}
}
})
}
private View newView(ViewGroup parent) {
- return(((LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.activity_row, parent, false));
+ return(((LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).
+ inflate(R.layout.activity_row, parent, false));
}
private void bindView(int position, View row) {
--- /dev/null
+/**
+ * ownCloud Android client application
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.dialog;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.activity.FileActivity;
+
+/**
+ * Dialog to input the password for sharing a file/folder.
+ *
+ * Triggers the share when the password is introduced.
+ */
+
+public class SharePasswordDialogFragment extends DialogFragment
+ implements DialogInterface.OnClickListener {
+
+ private static final String ARG_FILE = "FILE";
+ private static final String ARG_SEND_INTENT = "SEND_INTENT";
+
+ public static final String PASSWORD_FRAGMENT = "PASSWORD_FRAGMENT";
+
+ private OCFile mFile;
+ private Intent mSendIntent;
+
+ /**
+ * Public factory method to create new SharePasswordDialogFragment instances.
+ *
+ * @param file
+ * @param sendIntent
+ * @return Dialog ready to show.
+ */
+ public static SharePasswordDialogFragment newInstance(OCFile file, Intent sendIntent) {
+ SharePasswordDialogFragment frag = new SharePasswordDialogFragment();
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_FILE, file);
+ args.putParcelable(ARG_SEND_INTENT, sendIntent);
+ frag.setArguments(args);
+ return frag;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ mFile = getArguments().getParcelable(ARG_FILE);
+ mSendIntent = getArguments().getParcelable(ARG_SEND_INTENT);
+
+ // Inflate the layout for the dialog
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ View v = inflater.inflate(R.layout.password_dialog, null);
+
+ // Setup layout
+ EditText inputText = ((EditText)v.findViewById(R.id.share_password));
+ inputText.setText("");
+ inputText.requestFocus();
+
+ // Build the dialog
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setView(v)
+ .setPositiveButton(R.string.common_ok, this)
+ .setNegativeButton(R.string.common_cancel, this)
+ .setTitle(R.string.share_link_password_title);
+ Dialog d = builder.create();
+ d.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ return d;
+ }
+
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ // Enable the flag "Share again"
+ ((FileActivity) getActivity()).setTryShareAgain(true);
+
+ String password =
+ ((TextView)(getDialog().findViewById(R.id.share_password)))
+ .getText().toString();
+
+ if (password.length() <= 0) {
+ Toast.makeText(
+ getActivity(),
+ R.string.share_link_empty_password,
+ Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ // Share the file
+ ((FileActivity)getActivity()).getFileOperationsHelper()
+ .shareFileWithLinkToApp(mFile, password, mSendIntent);
+
+ } else {
+ // Disable the flag "Share again"
+ ((FileActivity) getActivity()).setTryShareAgain(false);
+ }
+ }
+}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.app.Dialog;
import android.net.http.SslError;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.SslErrorHandler;
import android.widget.Button;
-import com.actionbarsherlock.app.SherlockDialogFragment;
import com.owncloud.android.R;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
import com.owncloud.android.lib.common.network.NetworkUtils;
* to decide trust on it or not.
*
* Abstract implementation of common functionality for different dialogs that
- * get the information about the error and the certificate from different classes.
- *
- * @author masensio
- * @author David A. Velasco
+ * get the information about the error and the certificate from different classes.
*/
-public class SslUntrustedCertDialog extends SherlockDialogFragment {
+public class SslUntrustedCertDialog extends DialogFragment {
private final static String TAG = SslUntrustedCertDialog.class.getSimpleName();
if (mHandler != null) {
mHandler.cancel();
}
- ((OnSslUntrustedCertListener)getSherlockActivity()).onCancelCertificate();
+ ((OnSslUntrustedCertListener)getActivity()).onCancelCertificate();
}
}
mHandler.proceed();
}
if (m509Certificate != null) {
- Activity activity = getSherlockActivity();
+ Activity activity = getActivity();
try {
NetworkUtils.addCertToKnownServersStore(m509Certificate, activity); // TODO make this asynchronously, it can take some time
((OnSslUntrustedCertListener)activity).onSavedCertificate();
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* Dialog to request the user about a certificate that could not be validated with the certificates store in the system.
- *
- * @author David A. Velasco
*/
public class SslValidatorDialog extends Dialog {
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.dialog;
+
+import android.accounts.Account;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+import com.owncloud.android.R;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.activity.FileActivity;
+import com.owncloud.android.ui.activity.UploadFilesActivity;
+
+
+/**
+ * Dialog showing two options to allow the user upload files from the filesystem or from other apps.
+ *
+ * Assumes that its parent activity extends {@link FileActivity}
+ */
+public class UploadSourceDialogFragment extends DialogFragment {
+
+ private final static String TAG = UploadSourceDialogFragment.class.getSimpleName();
+ private final static String ARG_ACCOUNT = UploadSourceDialogFragment.class.getSimpleName() +
+ ".ARG_ACCOUNT";
+
+ public static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
+ public static final int ACTION_SELECT_MULTIPLE_FILES = 2;
+
+ public static UploadSourceDialogFragment newInstance(Account account) {
+ UploadSourceDialogFragment f = new UploadSourceDialogFragment();
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_ACCOUNT, account);
+ f.setArguments(args);
+ return f;
+ }
+
+ public UploadSourceDialogFragment() {
+ super();
+ Log_OC.v(TAG, "constructor");
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+
+ String[] allTheItems = {
+ getString(R.string.actionbar_upload_files),
+ getString(R.string.actionbar_upload_from_apps)
+ };
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.actionbar_upload);
+ builder.setItems(allTheItems, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ if (item == 0) {
+ Intent action = new Intent(getActivity(), UploadFilesActivity.class);
+ action.putExtra(
+ UploadFilesActivity.EXTRA_ACCOUNT,
+ ((FileActivity)getActivity()).getAccount()
+ );
+ //startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);
+ // this flow seems broken;
+ // Actionbarsherlock, maybe?
+ getActivity().startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);
+
+ } else if (item == 1) {
+ Intent action = new Intent(Intent.ACTION_GET_CONTENT);
+ action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
+ //Intent.EXTRA_ALLOW_MULTIPLE is only supported on api level 18+, Jelly Bean
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ action.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ }
+ //startActivityForResult( // this flow seems broken;
+ // Actionbarsherlock, maybe?
+ getActivity().startActivityForResult(
+ Intent.createChooser(action, getString(R.string.upload_chooser_title)),
+ ACTION_SELECT_CONTENT_FROM_APPS
+ );
+ }
+ }
+ });
+ return builder.create();
+ }
+
+}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.ui.fragment;
-import com.actionbarsherlock.app.SherlockFragment;
+import android.support.v4.app.Fragment;
-public class AuthenticatorAccountDetailsFragment extends SherlockFragment {
+public class AuthenticatorAccountDetailsFragment extends Fragment {
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.ui.fragment;
-import com.actionbarsherlock.app.SherlockFragment;
+import android.support.v4.app.Fragment;
-public class AuthenticatorGetStartedFragment extends SherlockFragment {
+public class AuthenticatorGetStartedFragment extends Fragment {
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2012-2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import java.util.ArrayList;
+import android.os.Build;
import android.os.Bundle;
+import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
+import android.widget.GridView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
-import com.actionbarsherlock.app.SherlockFragment;
import com.owncloud.android.R;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.ui.ExtendedListView;
import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
+import com.owncloud.android.ui.adapter.FileListListAdapter;
+
+import third_parties.in.srain.cube.GridViewWithHeaderAndFooter;
/**
- * TODO extending SherlockListFragment instead of SherlockFragment
+ * TODO extending SherlockListFragment instead of SherlockFragment
*/
-public class ExtendedListFragment extends SherlockFragment
-implements OnItemClickListener, OnEnforceableRefreshListener {
-
+public class ExtendedListFragment extends Fragment
+ implements OnItemClickListener, OnEnforceableRefreshListener {
+
private static final String TAG = ExtendedListFragment.class.getSimpleName();
- private static final String KEY_SAVED_LIST_POSITION = "SAVED_LIST_POSITION";
+ private static final String KEY_SAVED_LIST_POSITION = "SAVED_LIST_POSITION";
private static final String KEY_INDEXES = "INDEXES";
private static final String KEY_FIRST_POSITIONS= "FIRST_POSITIONS";
private static final String KEY_TOPS = "TOPS";
private static final String KEY_HEIGHT_CELL = "HEIGHT_CELL";
private static final String KEY_EMPTY_LIST_MESSAGE = "EMPTY_LIST_MESSAGE";
- protected ExtendedListView mList;
-
- private SwipeRefreshLayout mRefreshLayout;
+ private SwipeRefreshLayout mRefreshListLayout;
+ private SwipeRefreshLayout mRefreshGridLayout;
private SwipeRefreshLayout mRefreshEmptyLayout;
private TextView mEmptyListMessage;
private OnEnforceableRefreshListener mOnRefreshListener = null;
-
- public void setListAdapter(ListAdapter listAdapter) {
- mList.setAdapter(listAdapter);
- mList.invalidate();
+ protected AbsListView mCurrentListView;
+ private ExtendedListView mListView;
+ private View mListFooterView;
+ private GridViewWithHeaderAndFooter mGridView;
+ private View mGridFooterView;
+
+ private ListAdapter mAdapter;
+
+ protected void setListAdapter(ListAdapter listAdapter) {
+ mAdapter = listAdapter;
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ mCurrentListView.setAdapter(listAdapter);
+ } else {
+ ((ListView)mCurrentListView).setAdapter(listAdapter);
+ }
+
+ mCurrentListView.invalidate();
}
- public ListView getListView() {
- return mList;
+ protected AbsListView getListView() {
+ return mCurrentListView;
+ }
+
+
+ protected void switchToGridView() {
+ if ((mCurrentListView == mListView)) {
+
+ mListView.setAdapter(null);
+ mRefreshListLayout.setVisibility(View.GONE);
+
+ if (mAdapter instanceof FileListListAdapter) {
+ ((FileListListAdapter) mAdapter).setGridMode(true);
+ }
+ mGridView.setAdapter(mAdapter);
+ mRefreshGridLayout.setVisibility(View.VISIBLE);
+
+ mCurrentListView = mGridView;
+ }
+ }
+
+ protected void switchToListView() {
+ if (mCurrentListView == mGridView) {
+ mGridView.setAdapter(null);
+ mRefreshGridLayout.setVisibility(View.GONE);
+
+ if (mAdapter instanceof FileListListAdapter) {
+ ((FileListListAdapter) mAdapter).setGridMode(false);
+ }
+ mListView.setAdapter(mAdapter);
+ mRefreshListLayout.setVisibility(View.VISIBLE);
+
+ mCurrentListView = mListView;
+ }
}
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- Log_OC.e(TAG, "onCreateView");
-
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ Log_OC.d(TAG, "onCreateView");
+
View v = inflater.inflate(R.layout.list_fragment, null);
- mEmptyListMessage = (TextView) v.findViewById(R.id.empty_list_view);
- mList = (ExtendedListView)(v.findViewById(R.id.list_root));
- mList.setOnItemClickListener(this);
- mList.setDivider(getResources().getDrawable(R.drawable.uploader_list_separator));
- mList.setDividerHeight(1);
+ mListView = (ExtendedListView)(v.findViewById(R.id.list_root));
+ mListView.setOnItemClickListener(this);
+ mListFooterView = inflater.inflate(R.layout.list_footer, null, false);
+
+ mGridView = (GridViewWithHeaderAndFooter) (v.findViewById(R.id.grid_root));
+ mGridView.setNumColumns(GridView.AUTO_FIT);
+ mGridView.setOnItemClickListener(this);
+ mGridFooterView = inflater.inflate(R.layout.list_footer, null, false);
if (savedInstanceState != null) {
int referencePosition = savedInstanceState.getInt(KEY_SAVED_LIST_POSITION);
- setReferencePosition(referencePosition);
+ if (mCurrentListView == mListView) {
+ Log_OC.v(TAG, "Setting and centering around list position " + referencePosition);
+ mListView.setAndCenterSelection(referencePosition);
+ } else {
+ Log_OC.v(TAG, "Setting grid position " + referencePosition);
+ mGridView.setSelection(referencePosition);
+ }
}
+
+ // Pull-down to refresh layout
+ mRefreshListLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_containing_list);
+ mRefreshGridLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_containing_grid);
+ mRefreshEmptyLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_containing_empty);
+ mEmptyListMessage = (TextView) v.findViewById(R.id.empty_list_view);
- // Pull down refresh
- mRefreshLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_refresh_files);
- mRefreshEmptyLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_refresh_files_emptyView);
-
- onCreateSwipeToRefresh(mRefreshLayout);
+ onCreateSwipeToRefresh(mRefreshListLayout);
+ onCreateSwipeToRefresh(mRefreshGridLayout);
onCreateSwipeToRefresh(mRefreshEmptyLayout);
-
- mList.setEmptyView(mRefreshEmptyLayout);
+
+ mListView.setEmptyView(mRefreshEmptyLayout);
+ mGridView.setEmptyView(mRefreshEmptyLayout);
+
+ mCurrentListView = mListView; // list as default
return v;
}
-
/**
* {@inheritDoc}
*/
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
- Log_OC.e(TAG, "onSaveInstanceState()");
+ Log_OC.d(TAG, "onSaveInstanceState()");
savedInstanceState.putInt(KEY_SAVED_LIST_POSITION, getReferencePosition());
savedInstanceState.putIntegerArrayList(KEY_INDEXES, mIndexes);
savedInstanceState.putIntegerArrayList(KEY_FIRST_POSITIONS, mFirstPositions);
savedInstanceState.putString(KEY_EMPTY_LIST_MESSAGE, getEmptyViewText());
}
-
/**
- * Calculates the position of the item that will be used as a reference to reposition the visible items in the list when
- * the device is turned to other position.
+ * Calculates the position of the item that will be used as a reference to
+ * reposition the visible items in the list when the device is turned to
+ * other position.
*
- * THe current policy is take as a reference the visible item in the center of the screen.
+ * The current policy is take as a reference the visible item in the center
+ * of the screen.
*
- * @return The position in the list of the visible item in the center of the screen.
+ * @return The position in the list of the visible item in the center of the
+ * screen.
*/
protected int getReferencePosition() {
- if (mList != null) {
- return (mList.getFirstVisiblePosition() + mList.getLastVisiblePosition()) / 2;
+ if (mCurrentListView != null) {
+ return (mCurrentListView.getFirstVisiblePosition() +
+ mCurrentListView.getLastVisiblePosition()) / 2;
} else {
return 0;
}
}
-
- /**
- * Sets the visible part of the list from the reference position.
- *
- * @param position Reference position previously returned by {@link LocalFileListFragment#getReferencePosition()}
- */
- protected void setReferencePosition(int position) {
- if (mList != null) {
- mList.setAndCenterSelection(position);
- }
- }
-
/*
* Restore index and position
// needs to be checked; not every browse-up had a browse-down before
int index = mIndexes.remove(mIndexes.size() - 1);
-
- int firstPosition = mFirstPositions.remove(mFirstPositions.size() -1);
-
+ final int firstPosition = mFirstPositions.remove(mFirstPositions.size() -1);
int top = mTops.remove(mTops.size() - 1);
-
- mList.setSelectionFromTop(firstPosition, top);
-
- // Move the scroll if the selection is not visible
- int indexPosition = mHeightCell*index;
- int height = mList.getHeight();
-
- if (indexPosition > height) {
- if (android.os.Build.VERSION.SDK_INT >= 11)
- {
- mList.smoothScrollToPosition(index);
+
+ Log_OC.v(TAG, "Setting selection to position: " + firstPosition + "; top: "
+ + top + "; index: " + index);
+
+ if (mCurrentListView == mListView) {
+ if (mHeightCell*index <= mListView.getHeight()) {
+ mListView.setSelectionFromTop(firstPosition, top);
+ } else {
+ mListView.setSelectionFromTop(index, 0);
}
- else if (android.os.Build.VERSION.SDK_INT >= 8)
- {
- mList.setSelectionFromTop(index, 0);
+
+ } else {
+ if (mHeightCell*index <= mGridView.getHeight()) {
+ mGridView.setSelection(firstPosition);
+ //mGridView.smoothScrollToPosition(firstPosition);
+ } else {
+ mGridView.setSelection(index);
+ //mGridView.smoothScrollToPosition(index);
}
-
}
+
}
}
mIndexes.add(index);
- int firstPosition = mList.getFirstVisiblePosition();
+ int firstPosition = mCurrentListView.getFirstVisiblePosition();
mFirstPositions.add(firstPosition);
- View view = mList.getChildAt(0);
+ View view = mCurrentListView.getChildAt(0);
int top = (view == null) ? 0 : view.getTop() ;
mTops.add(top);
@Override
public void onItemClick (AdapterView<?> parent, View view, int position, long id) {
- // to be @overriden
+ // to be @overriden
}
@Override
public void onRefresh() {
- // to be @overriden
- mRefreshLayout.setRefreshing(false);
+ mRefreshListLayout.setRefreshing(false);
+ mRefreshGridLayout.setRefreshing(false);
mRefreshEmptyLayout.setRefreshing(false);
-
+
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefresh();
}
}
-
public void setOnRefreshListener(OnEnforceableRefreshListener listener) {
mOnRefreshListener = listener;
}
/**
- * Enables swipe gesture
+ * Disables swipe gesture.
+ *
+ * Sets the 'enabled' state of the refresh layouts contained in the fragment.
+ *
+ * When 'false' is set, prevents user gestures but keeps the option to refresh programatically,
+ *
+ * @param enabled Desired state for capturing swipe gesture.
*/
- public void enableSwipe() {
- mRefreshLayout.setEnabled(true);
- }
-
- /**
- * Disables swipe gesture. It prevents manual gestures but keeps the option you show
- * refreshing programmatically.
- */
- public void disableSwipe() {
- mRefreshLayout.setEnabled(false);
- }
-
- /**
- * It shows the SwipeRefreshLayout progress
- */
- public void showSwipeProgress() {
- mRefreshLayout.setRefreshing(true);
- }
-
- /**
- * It shows the SwipeRefreshLayout progress
- */
- public void hideSwipeProgress() {
- mRefreshLayout.setRefreshing(false);
+ public void setSwipeEnabled(boolean enabled) {
+ mRefreshListLayout.setEnabled(enabled);
+ mRefreshGridLayout.setEnabled(enabled);
+ mRefreshEmptyLayout.setEnabled(enabled);
}
/**
private void onCreateSwipeToRefresh(SwipeRefreshLayout refreshLayout) {
// Colors in animations: background
- refreshLayout.setColorScheme(R.color.background_color, R.color.background_color, R.color.background_color,
- R.color.background_color);
+ refreshLayout.setColorScheme(R.color.background_color, R.color.background_color,
+ R.color.background_color, R.color.background_color);
refreshLayout.setOnRefreshListener(this);
}
@Override
public void onRefresh(boolean ignoreETag) {
- mRefreshLayout.setRefreshing(false);
+ mRefreshListLayout.setRefreshing(false);
+ mRefreshGridLayout.setRefreshing(false);
mRefreshEmptyLayout.setRefreshing(false);
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefresh(ignoreETag);
}
}
+
+ protected void setChoiceMode(int choiceMode) {
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ mListView.setChoiceMode(choiceMode);
+ mGridView.setChoiceMode(choiceMode);
+ } else {
+ ((ListView)mListView).setChoiceMode(choiceMode);
+ }
+ }
+
+ protected void registerForContextMenu() {
+ registerForContextMenu(mListView);
+ registerForContextMenu(mGridView);
+ mListView.setOnCreateContextMenuListener(this);
+ mGridView.setOnCreateContextMenuListener(this);
+ }
+
+ /**
+ * TODO doc
+ * To be called before setAdapter, or GridViewWithHeaderAndFooter will throw an exception
+ *
+ * @param enabled
+ */
+ protected void setFooterEnabled(boolean enabled) {
+ if (enabled) {
+ if (mGridView.getFooterViewCount() == 0) {
+ if (mGridFooterView.getParent() != null ) {
+ ((ViewGroup) mGridFooterView.getParent()).removeView(mGridFooterView);
+ }
+ mGridView.addFooterView(mGridFooterView, null, false);
+ }
+ mGridFooterView.invalidate();
+
+ if (mListView.getFooterViewsCount() == 0) {
+ if (mListFooterView.getParent() != null ) {
+ ((ViewGroup) mListFooterView.getParent()).removeView(mListFooterView);
+ }
+ mListView.addFooterView(mListFooterView, null, false);
+ }
+ mListFooterView.invalidate();
+
+ } else {
+ mGridView.removeFooterView(mGridFooterView);
+ mListView.removeFooterView(mListFooterView);
+ }
+ }
+
+ /**
+ * TODO doc
+ * @param text
+ */
+ protected void setFooterText(String text) {
+ if (text != null && text.length() > 0) {
+ ((TextView)mListFooterView.findViewById(R.id.footerText)).setText(text);
+ ((TextView)mGridFooterView.findViewById(R.id.footerText)).setText(text);
+ setFooterEnabled(true);
+
+ } else {
+ setFooterEnabled(false);
+ }
+ }
+
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuInflater;
-import com.actionbarsherlock.view.MenuItem;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
/**
* This Fragment is used to display the details about a file.
- *
- * @author Bartek Przybylski
- * @author David A. Velasco
*/
public class FileDetailFragment extends FileFragment implements OnClickListener {
private static final String TAG = FileDetailFragment.class.getSimpleName();
public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";
public static final String FTAG_RENAME_FILE = "RENAME_FILE_FRAGMENT";
-
+
+ private static final String ARG_FILE = "FILE";
+ private static final String ARG_ACCOUNT = "ACCOUNT";
+
+
+ /**
+ * Public factory method to create new FileDetailFragment instances.
+ *
+ * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).
+ *
+ * @param fileToDetail An {@link OCFile} to show in the fragment
+ * @param account An ownCloud account; needed to start downloads
+ * @return New fragment with arguments set
+ */
+ public static FileDetailFragment newInstance(OCFile fileToDetail, Account account) {
+ FileDetailFragment frag = new FileDetailFragment();
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_FILE, fileToDetail);
+ args.putParcelable(ARG_ACCOUNT, account);
+ frag.setArguments(args);
+ return frag;
+ }
/**
* Creates an empty details fragment.
*
- * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically.
+ * It's necessary to keep a public constructor without parameters; the system uses it when tries
+ * to reinstantiate a fragment automatically.
*/
public FileDetailFragment() {
super();
mProgressListener = null;
}
- /**
- * Creates a details fragment.
- *
- * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).
- *
- * @param fileToDetail An {@link OCFile} to show in the fragment
- * @param ocAccount An ownCloud account; needed to start downloads
- */
- public FileDetailFragment(OCFile fileToDetail, Account ocAccount) {
- super(fileToDetail);
- mAccount = ocAccount;
- mLayout = R.layout.file_details_empty;
- mProgressListener = null;
- }
-
-
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
-
+
+ setFile((OCFile) getArguments().getParcelable(ARG_FILE));
+ mAccount = getArguments().getParcelable(ARG_ACCOUNT);
+
if (savedInstanceState != null) {
setFile((OCFile)savedInstanceState.getParcelable(FileActivity.EXTRA_FILE));
mAccount = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT);
mLayout = R.layout.file_details_fragment;
}
- View view = null;
- view = inflater.inflate(mLayout, null);
- mView = view;
+ mView = inflater.inflate(mLayout, null);
if (mLayout == R.layout.file_details_fragment) {
mView.findViewById(R.id.fdKeepInSync).setOnClickListener(this);
mProgressListener = new ProgressListener(progressBar);
mView.findViewById(R.id.fdCancelBtn).setOnClickListener(this);
}
-
+
updateFileDetails(false, false);
- return view;
+ return mView;
}
@Override
getFile(),
mContainerActivity.getStorageManager().getAccount(),
mContainerActivity,
- getSherlockActivity()
+ getActivity()
);
mf.filter(menu);
}
setFilename(file.getFileName());
setFiletype(file.getMimetype(), file.getFileName());
setFilesize(file.getFileLength());
- if(ocVersionSupportsTimeCreated()){
- setTimeCreated(file.getCreationTimestamp());
- }
-
+
setTimeModified(file.getModificationTimestamp());
CheckBox cb = (CheckBox)getView().findViewById(R.id.fdKeepInSync);
// configure UI for depending upon local state of the file
FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
- if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file))) {
+ if (transferring ||
+ (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) ||
+ (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file))
+ ) {
setButtonsForTransferring();
} else if (file.isDown()) {
setButtonsForDown();
} else {
- // TODO load default preview image; when the local file is removed, the preview remains there
+ // TODO load default preview image; when the local file is removed, the preview
+ // remains there
setButtonsForRemote();
}
}
/**
* Updates the MIME type in view
- * @param mimetype to set
- * @param filename
+ * @param mimetype MIME type to set
+ * @param filename Name of the file, to deduce the icon to use in case the MIME type is not precise enough
*/
private void setFiletype(String mimetype, String filename) {
TextView tv = (TextView) getView().findViewById(R.id.fdType);
if (tv != null) {
- String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);;
+ String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);
tv.setText(printableMimetype);
}
ImageView iv = (ImageView) getView().findViewById(R.id.fdIcon);
if (iv != null) {
- iv.setImageResource(DisplayUtils.getResourceId(mimetype, filename));
+ iv.setImageResource(DisplayUtils.getFileTypeIconId(mimetype, filename));
}
}
}
/**
- * Updates the time that the file was created in view
- * @param milliseconds Unix time to set
- */
- private void setTimeCreated(long milliseconds){
- TextView tv = (TextView) getView().findViewById(R.id.fdCreated);
- TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel);
- if(tv != null){
- tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));
- tv.setVisibility(View.VISIBLE);
- tvLabel.setVisibility(View.VISIBLE);
- }
- }
-
- /**
* Updates the time that the file was last modified
* @param milliseconds Unix time to set
*/
progressText.setVisibility(View.VISIBLE);
FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
+ //if (getFile().isDownloading()) {
if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, getFile())) {
progressText.setText(R.string.downloader_download_in_progress_ticker);
} else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, getFile())) {
}
- /**
- * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return
- * the time that the file was created. There is a chance that this will
- * be fixed in future versions. Use this method to check if this version of
- * ownCloud has this fix.
- * @return True, if ownCloud the ownCloud version is supporting creation time
- */
- private boolean ocVersionSupportsTimeCreated(){
- /*if(mAccount != null){
- AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE);
- OwnCloudVersion ocVersion = new OwnCloudVersion(accManager
- .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));
- if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) {
- return true;
- }
- }*/
- return false;
- }
-
-
public void listenForTransferProgress() {
if (mProgressListener != null) {
if (mContainerActivity.getFileDownloaderBinder() != null) {
- mContainerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, getFile());
+ mContainerActivity.getFileDownloaderBinder().
+ addDatatransferProgressListener(mProgressListener, mAccount, getFile());
}
if (mContainerActivity.getFileUploaderBinder() != null) {
- mContainerActivity.getFileUploaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, getFile());
+ mContainerActivity.getFileUploaderBinder().
+ addDatatransferProgressListener(mProgressListener, mAccount, getFile());
}
}
}
public void leaveTransferProgress() {
if (mProgressListener != null) {
if (mContainerActivity.getFileDownloaderBinder() != null) {
- mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, getFile());
+ mContainerActivity.getFileDownloaderBinder().
+ removeDatatransferProgressListener(mProgressListener, mAccount, getFile());
}
if (mContainerActivity.getFileUploaderBinder() != null) {
- mContainerActivity.getFileUploaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, getFile());
+ mContainerActivity.getFileUploaderBinder().
+ removeDatatransferProgressListener(mProgressListener, mAccount, getFile());
}
}
}
/**
- * Helper class responsible for updating the progress bar shown for file uploading or downloading
- *
- * @author David A. Velasco
+ * Helper class responsible for updating the progress bar shown for file uploading or
+ * downloading
*/
private class ProgressListener implements OnDatatransferProgressListener {
int mLastPercent = 0;
}
@Override
- public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filename) {
+ public void onTransferProgress(long progressRate, long totalTransferredSoFar,
+ long totalToTransfer, String filename) {
int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
if (percent != mLastPercent) {
ProgressBar pb = mProgressBar.get();
mLastPercent = percent;
}
- };
+ }
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.app.Activity;
import android.support.v4.app.Fragment;
-import com.actionbarsherlock.app.SherlockFragment;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
/**
* Common methods for {@link Fragment}s containing {@link OCFile}s
- *
- * @author David A. Velasco
- *
*/
-public class FileFragment extends SherlockFragment {
+public class FileFragment extends Fragment {
private OCFile mFile;
/**
* Creates an empty fragment.
*
- * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically.
+ * It's necessary to keep a public constructor without parameters; the system uses it when
+ * tries to reinstantiate a fragment automatically.
*/
public FileFragment() {
mFile = null;
mContainerActivity = (ContainerActivity) activity;
} catch (ClassCastException e) {
- throw new ClassCastException(activity.toString() + " must implement " + ContainerActivity.class.getSimpleName());
+ throw new ClassCastException(activity.toString() + " must implement " +
+ ContainerActivity.class.getSimpleName());
}
}
/**
* Interface to implement by any Activity that includes some instance of FileListFragment
* Interface to implement by any Activity that includes some instance of FileFragment
- *
- * @author David A. Velasco
*/
public interface ContainerActivity extends ComponentsGetter {
public void showDetails(OCFile file);
- ///// TO UNIFY IN A SINGLE CALLBACK METHOD - EVENT NOTIFICATIONs -> something happened inside the fragment, MAYBE activity is interested --> unify in notification method
+ ///// TO UNIFY IN A SINGLE CALLBACK METHOD - EVENT NOTIFICATIONs -> something happened
+ // inside the fragment, MAYBE activity is interested --> unify in notification method
/**
- * Callback method invoked when a the user browsed into a different folder through the list of files
+ * Callback method invoked when a the user browsed into a different folder through the
+ * list of files
*
- * @param file
+ * @param folder
*/
public void onBrowsedDownTo(OCFile folder);
*
* This happens when a download or upload is started or ended for a file.
*
- * This method is necessary by now to update the user interface of the double-pane layout in tablets
- * because methods {@link FileDownloaderBinder#isDownloading(Account, OCFile)} and {@link FileUploaderBinder#isUploading(Account, OCFile)}
+ * This method is necessary by now to update the user interface of the double-pane layout
+ * in tablets because methods {@link FileDownloaderBinder#isDownloading(Account, OCFile)}
+ * and {@link FileUploaderBinder#isUploading(Account, OCFile)}
* won't provide the needed response before the method where this is called finishes.
*
- * TODO Remove this when the transfer state of a file is kept in the database (other thing TODO)
+ * TODO Remove this when the transfer state of a file is kept in the database
+ * (other thing TODO)
*
* @param file OCFile which state changed.
* @param downloading Flag signaling if the file is now downloading.
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
/**
* A Fragment that lists all files and folders in a given LOCAL path.
- *
- * @author David A. Velasco
- *
*/
public class LocalFileListFragment extends ExtendedListFragment {
private static final String TAG = "LocalFileListFragment";
try {
mContainerActivity = (ContainerActivity) activity;
} catch (ClassCastException e) {
- throw new ClassCastException(activity.toString() + " must implement " + LocalFileListFragment.ContainerActivity.class.getSimpleName());
+ throw new ClassCastException(activity.toString() + " must implement " +
+ LocalFileListFragment.ContainerActivity.class.getSimpleName());
}
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log_OC.i(TAG, "onCreateView() start");
View v = super.onCreateView(inflater, container, savedInstanceState);
- getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- disableSwipe(); // Disable pull refresh
+ setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+ setSwipeEnabled(false); // Disable pull-to-refresh
setMessageForEmptyList(getString(R.string.local_file_list_empty));
Log_OC.i(TAG, "onCreateView() end");
return v;
- }
+ }
/**
Log_OC.i(TAG, "onActivityCreated() stop");
}
-
/**
- * Checks the file clicked over. Browses inside if it is a directory. Notifies the container activity in any case.
+ * Checks the file clicked over. Browses inside if it is a directory.
+ * Notifies the container activity in any case.
*/
@Override
public void onItemClick(AdapterView<?> l, View v, int position, long id) {
} else { /// Click on a file
ImageView checkBoxV = (ImageView) v.findViewById(R.id.custom_checkbox);
if (checkBoxV != null) {
- if (getListView().isItemChecked(position)) {
+ if (((ListView)getListView()).isItemChecked(position)) {
checkBoxV.setImageResource(android.R.drawable.checkbox_on_background);
} else {
checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);
if(mDirectory != null){
directory = mDirectory;
} else {
- directory = Environment.getExternalStorageDirectory(); // TODO be careful with the state of the storage; could not be available
+ directory = Environment.getExternalStorageDirectory();
+ // TODO be careful with the state of the storage; could not be available
if (directory == null) return; // no files to show
}
}
directory = directory.getParentFile();
}
- mList.clearChoices(); // by now, only files in the same directory will be kept as selected
+ // by now, only files in the same directory will be kept as selected
+ ((ListView)mCurrentListView).clearChoices();
mAdapter.swapDirectory(directory);
if (mDirectory == null || !mDirectory.equals(directory)) {
- mList.setSelectionFromTop(0, 0);
+ mCurrentListView.setSelection(0);
}
mDirectory = directory;
}
*/
public String[] getCheckedFilePaths() {
ArrayList<String> result = new ArrayList<String>();
- SparseBooleanArray positions = mList.getCheckedItemPositions();
+ SparseBooleanArray positions = ((ListView)mCurrentListView).getCheckedItemPositions();
if (positions.size() > 0) {
for (int i = 0; i < positions.size(); i++) {
if (positions.get(positions.keyAt(i)) == true) {
- result.add(((File) mList.getItemAtPosition(positions.keyAt(i))).getAbsolutePath());
+ result.add(((File) mCurrentListView.getItemAtPosition(
+ positions.keyAt(i))).getAbsolutePath());
}
}
/**
* Interface to implement by any Activity that includes some instance of LocalFileListFragment
- *
- * @author David A. Velasco
*/
public interface ContainerActivity {
/**
* Callback method invoked when a directory is clicked by the user on the files list
*
- * @param file
+ * @param directory
*/
public void onDirectoryClick(File directory);
/**
- * Callback method invoked when a file (non directory) is clicked by the user on the files list
+ * Callback method invoked when a file (non directory)
+ * is clicked by the user on the files list
*
* @param file
*/
/**
- * Callback method invoked when the parent activity is fully created to get the directory to list firstly.
+ * Callback method invoked when the parent activity
+ * is fully created to get the directory to list firstly.
*
* @return Directory to list firstly. Can be NULL.
*/
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author masensio
+ * @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2014 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.widget.AdapterView.AdapterContextMenuInfo;
import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.FileMenuFilter;
import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.activity.MoveActivity;
+import com.owncloud.android.ui.activity.FolderPickerActivity;
import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
import com.owncloud.android.ui.adapter.FileListListAdapter;
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
import com.owncloud.android.ui.preview.PreviewImageFragment;
import com.owncloud.android.ui.preview.PreviewMediaFragment;
+import com.owncloud.android.utils.FileStorageUtils;
/**
* A Fragment that lists all files and folders in a given path.
*
- * TODO refactorize to get rid of direct dependency on FileDisplayActivity
- *
- * @author Bartek Przybylski
- * @author masensio
- * @author David A. Velasco
+ * TODO refactor to get rid of direct dependency on FileDisplayActivity
*/
public class OCFileListFragment extends ExtendedListFragment {
private OCFile mFile = null;
private FileListListAdapter mAdapter;
+ private boolean mJustFolders;
private OCFile mTargetFile;
-
+
+
/**
* {@inheritDoc}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log_OC.e(TAG, "onActivityCreated() start");
-
+
if (savedInstanceState != null) {
mFile = savedInstanceState.getParcelable(KEY_FILE);
}
-
+
+ if (mJustFolders) {
+ setFooterEnabled(false);
+ } else {
+ setFooterEnabled(true);
+ }
+
Bundle args = getArguments();
- boolean justFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false);
+ mJustFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false);
mAdapter = new FileListListAdapter(
- justFolders,
- getSherlockActivity(),
+ mJustFolders,
+ getActivity(),
mContainerActivity
- );
+ );
setListAdapter(mAdapter);
-
- registerForContextMenu(getListView());
- getListView().setOnCreateContextMenuListener(this);
+
+ registerForContextMenu();
}
-
+
/**
* Saves the current listed folder.
*/
moveCount++;
} // exit is granted because storageManager.getFileByPath("/") never returns null
mFile = parentDir;
-
- listDirectory(mFile);
+
+ // TODO Enable when "On Device" is recovered ?
+ listDirectory(mFile /*, MainApp.getOnlyOnDevice()*/);
onRefresh(false);
if (file != null) {
if (file.isFolder()) {
// update state and view of this fragment
- listDirectory(file);
+ // TODO Enable when "On Device" is recovered ?
+ listDirectory(file/*, MainApp.getOnlyOnDevice()*/);
// then, notify parent activity to let it update its state and view
mContainerActivity.onBrowsedDownTo(file);
// save index and top position
boolean allowContextualActions =
(args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
if (allowContextualActions) {
- MenuInflater inflater = getSherlockActivity().getMenuInflater();
+ MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.file_actions_menu, menu);
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
targetFile,
mContainerActivity.getStorageManager().getAccount(),
mContainerActivity,
- getSherlockActivity()
+ getActivity()
);
mf.filter(menu);
}
-
- /// additional restrictions for this fragment
- // TODO allow in the future 'open with' for previewable files
- MenuItem item = menu.findItem(R.id.action_open_file_with);
- if (item != null) {
- item.setVisible(false);
- item.setEnabled(false);
- }
+
/// TODO break this direct dependency on FileDisplayActivity... if possible
- FileFragment frag = ((FileDisplayActivity)getSherlockActivity()).getSecondFragment();
+ MenuItem item = menu.findItem(R.id.action_open_file_with);
+ FileFragment frag = ((FileDisplayActivity)getActivity()).getSecondFragment();
if (frag != null && frag instanceof FileDetailFragment &&
frag.getFile().getFileId() == targetFile.getFileId()) {
item = menu.findItem(R.id.action_see_details);
mContainerActivity.getFileOperationsHelper().shareFileWithLink(mTargetFile);
return true;
}
+ case R.id.action_open_file_with: {
+ mContainerActivity.getFileOperationsHelper().openFile(mTargetFile);
+ return true;
+ }
case R.id.action_unshare_file: {
mContainerActivity.getFileOperationsHelper().unshareFileWithLink(mTargetFile);
return true;
return true;
}
case R.id.action_move: {
- Intent action = new Intent(getActivity(), MoveActivity.class);
+ Intent action = new Intent(getActivity(), FolderPickerActivity.class);
// Pass mTargetFile that contains info of selected file/folder
- action.putExtra(MoveActivity.EXTRA_TARGET_FILE, mTargetFile);
+ action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
return true;
}
/**
* Calls {@link OCFileListFragment#listDirectory(OCFile)} with a null parameter
*/
- public void listDirectory(){
+ public void listDirectory(/*boolean onlyOnDevice*/){
listDirectory(null);
+ // TODO Enable when "On Device" is recovered ?
+ // listDirectory(null, onlyOnDevice);
+ }
+
+ public void refreshDirectory(){
+ // TODO Enable when "On Device" is recovered ?
+ listDirectory(getCurrentFile()/*, MainApp.getOnlyOnDevice()*/);
}
/**
*
* @param directory File to be listed
*/
- public void listDirectory(OCFile directory) {
+ public void listDirectory(OCFile directory/*, boolean onlyOnDevice*/) {
FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
if (storageManager != null) {
directory = storageManager.getFileById(directory.getParentId());
}
- mAdapter.swapDirectory(directory, storageManager);
+ // TODO Enable when "On Device" is recovered ?
+ mAdapter.swapDirectory(directory, storageManager/*, onlyOnDevice*/);
if (mFile == null || !mFile.equals(directory)) {
- mList.setSelectionFromTop(0, 0);
+ mCurrentListView.setSelection(0);
}
mFile = directory;
+
+ updateLayout();
+
}
}
-
+
+ private void updateLayout() {
+ if (!mJustFolders) {
+ int filesCount = 0, foldersCount = 0, imagesCount = 0;
+ int count = mAdapter.getCount();
+ OCFile file;
+ for (int i=0; i < count ; i++) {
+ file = (OCFile) mAdapter.getItem(i);
+ if (file.isFolder()) {
+ foldersCount++;
+ } else {
+ filesCount++;
+ if (file.isImage()){
+ imagesCount++;
+ }
+ }
+ }
+ // set footer text
+ setFooterText(generateFooterText(filesCount, foldersCount));
+
+ // decide grid vs list view
+ OwnCloudVersion version = AccountUtils.getServerVersion(
+ ((FileActivity)mContainerActivity).getAccount());
+ if (version != null && version.supportsRemoteThumbnails() &&
+ imagesCount > 0 && imagesCount == filesCount) {
+ switchToGridView();
+ } else {
+ switchToListView();
+ }
+ }
+ }
+
+ private String generateFooterText(int filesCount, int foldersCount) {
+ String output;
+ if (filesCount <= 0) {
+ if (foldersCount <= 0) {
+ output = "";
+
+ } else if (foldersCount == 1) {
+ output = getResources().getString(R.string.file_list__footer__folder);
+
+ } else { // foldersCount > 1
+ output = getResources().getString(R.string.file_list__footer__folders, foldersCount);
+ }
+
+ } else if (filesCount == 1) {
+ if (foldersCount <= 0) {
+ output = getResources().getString(R.string.file_list__footer__file);
+
+ } else if (foldersCount == 1) {
+ output = getResources().getString(R.string.file_list__footer__file_and_folder);
+
+ } else { // foldersCount > 1
+ output = getResources().getString(R.string.file_list__footer__file_and_folders, foldersCount);
+ }
+ } else { // filesCount > 1
+ if (foldersCount <= 0) {
+ output = getResources().getString(R.string.file_list__footer__files, filesCount);
+
+ } else if (foldersCount == 1) {
+ output = getResources().getString(R.string.file_list__footer__files_and_folder, filesCount);
+
+ } else { // foldersCount > 1
+ output = getResources().getString(
+ R.string.file_list__footer__files_and_folders, filesCount, foldersCount
+ );
+
+ }
+ }
+ return output;
+ }
+
+
public void sortByName(boolean descending) {
- mAdapter.setSortOrder(FileListListAdapter.SORT_NAME, descending);
+ mAdapter.setSortOrder(FileStorageUtils.SORT_NAME, descending);
}
public void sortByDate(boolean descending) {
- mAdapter.setSortOrder(FileListListAdapter.SORT_DATE, descending);
+ mAdapter.setSortOrder(FileStorageUtils.SORT_DATE, descending);
}
public void sortBySize(boolean descending) {
- mAdapter.setSortOrder(FileListListAdapter.SORT_SIZE, descending);
+ mAdapter.setSortOrder(FileStorageUtils.SORT_SIZE, descending);
}
-
+
+
+
}
-/* ownCloud Android client application
- *
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
import com.owncloud.android.ui.fragment.FileFragment;
import android.accounts.Account;
import android.os.Bundle;
+import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* This Fragment is used to monitor the progress of a file downloading.
- *
- * @author David A. Velasco
*/
public class FileDownloadFragment extends FileFragment implements OnClickListener {
public static final String EXTRA_FILE = "FILE";
public static final String EXTRA_ACCOUNT = "ACCOUNT";
private static final String EXTRA_ERROR = "ERROR";
+
+ private static final String ARG_FILE = "FILE";
+ private static final String ARG_IGNORE_FIRST = "IGNORE_FIRST";
+ private static final String ARG_ACCOUNT = "ACCOUNT" ;
private View mView;
private Account mAccount;
-
+
public ProgressListener mProgressListener;
private boolean mListening;
private boolean mIgnoreFirstSavedState;
private boolean mError;
-
+
+
+ /**
+ * Public factory method to create a new fragment that shows the progress of a file download.
+ *
+ * Android strongly recommends keep the empty constructor of fragments as the only public constructor, and
+ * use {@link #setArguments(Bundle)} to set the needed arguments.
+ *
+ * This method hides to client objects the need of doing the construction in two steps.
+ *
+ * When 'file' is null creates a dummy layout (useful when a file wasn't tapped before).
+ *
+ * @param file An {@link OCFile} to show in the fragment
+ * @param account An OC account; needed to start downloads
+ * @param ignoreFirstSavedState Flag to work around an unexpected behaviour of {@link FragmentStatePagerAdapter}
+ * TODO better solution
+ */
+ public static Fragment newInstance(OCFile file, Account account, boolean ignoreFirstSavedState) {
+ FileDownloadFragment frag = new FileDownloadFragment();
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_FILE, file);
+ args.putParcelable(ARG_ACCOUNT, account);
+ args.putBoolean(ARG_IGNORE_FIRST, ignoreFirstSavedState);
+ frag.setArguments(args);
+ return frag;
+ }
+
/**
* Creates an empty details fragment.
*
- * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically.
+ * It's necessary to keep a public constructor without parameters; the system uses it when tries to
+ * reinstantiate a fragment automatically.
*/
public FileDownloadFragment() {
super();
mIgnoreFirstSavedState = false;
mError = false;
}
-
-
- /**
- * Creates a details fragment.
- *
- * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).
- *
- * @param fileToDetail An {@link OCFile} to show in the fragment
- * @param ocAccount An ownCloud account; needed to start downloads
- * @param ignoreFirstSavedState Flag to work around an unexpected behaviour of {@link FragmentStatePagerAdapter}; TODO better solution
- */
- public FileDownloadFragment(OCFile fileToDetail, Account ocAccount, boolean ignoreFirstSavedState) {
- super(fileToDetail);
- mAccount = ocAccount;
- mProgressListener = null;
- mListening = false;
- mIgnoreFirstSavedState = ignoreFirstSavedState;
- mError = false;
- }
-
-
+
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ Bundle args = getArguments();
+ setFile((OCFile)args.getParcelable(ARG_FILE));
+ // TODO better in super, but needs to check ALL the class extending FileFragment; not right now
+
+ mIgnoreFirstSavedState = args.getBoolean(ARG_IGNORE_FIRST);
+ mAccount = args.getParcelable(ARG_ACCOUNT);
}
ProgressBar progressBar = (ProgressBar)mView.findViewById(R.id.progressBar);
mProgressListener = new ProgressListener(progressBar);
- ((ImageButton)mView.findViewById(R.id.cancelBtn)).setOnClickListener(this);
+ (mView.findViewById(R.id.cancelBtn)).setOnClickListener(this);
- ((LinearLayout)mView.findViewById(R.id.fileDownloadLL)).setOnClickListener(new OnClickListener() {
+ (mView.findViewById(R.id.fileDownloadLL)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
((PreviewImageActivity) getActivity()).toggleFullScreen();
/**
- * Updates the view depending upon the state of the downloading file.
- *
- * @param transferring When true, the view must be updated assuming that the holded file is
- * downloading, no matter what the downloaderBinder says.
- */
- public void updateView(boolean transferring) {
- // configure UI for depending upon local state of the file
- FileDownloaderBinder downloaderBinder = (mContainerActivity == null) ? null : mContainerActivity.getFileDownloaderBinder();
- if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, getFile()))) {
- setButtonsForTransferring();
-
- } else if (getFile().isDown()) {
-
- setButtonsForDown();
-
- } else {
- setButtonsForRemote();
- }
- getView().invalidate();
-
- }
-
-
- /**
* Enables or disables buttons for a file being downloaded
*/
private void setButtonsForTransferring() {
public void listenForTransferProgress() {
if (mProgressListener != null && !mListening) {
if (mContainerActivity.getFileDownloaderBinder() != null) {
- mContainerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, getFile());
+ mContainerActivity.getFileDownloaderBinder().addDatatransferProgressListener(
+ mProgressListener, mAccount, getFile()
+ );
mListening = true;
setButtonsForTransferring();
}
public void leaveTransferProgress() {
if (mProgressListener != null) {
if (mContainerActivity.getFileDownloaderBinder() != null) {
- mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, getFile());
+ mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(
+ mProgressListener, mAccount, getFile()
+ );
mListening = false;
}
}
}
-
+
/**
- * Helper class responsible for updating the progress bar shown for file uploading or downloading
- *
- * @author David A. Velasco
+ * Helper class responsible for updating the progress bar shown for file uploading or downloading
*/
private class ProgressListener implements OnDatatransferProgressListener {
int mLastPercent = 0;
}
@Override
- public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filename) {
+ public void onTransferProgress(
+ long progressRate, long totalTransferredSoFar, long totalToTransfer, String filename
+ ) {
int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
if (percent != mLastPercent) {
ProgressBar pb = mProgressBar.get();
import com.owncloud.android.lib.common.utils.Log_OC;
public class ImageViewCustom extends ImageView {
-
+
+ private static final String TAG = ImageViewCustom.class.getSimpleName();
+
private static final boolean IS_ICS_OR_HIGHER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
-
- private Bitmap mBitmap;
+ private static final boolean IS_VERSION_BUGGY_ON_RECYCLES =
+ Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1 ||
+ Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR2;
+
+ private int mBitmapHeight;
+ private int mBitmapWidth;
public ImageViewCustom(Context context) {
@Override
protected void onDraw(Canvas canvas) {
- if(IS_ICS_OR_HIGHER && checkIfMaximumBitmapExceed(canvas)) {
- // Set layer type to software one for avoiding exceed
- // and problems in visualization
+ if(IS_ICS_OR_HIGHER && checkIfMaximumBitmapExceed(canvas) || IS_VERSION_BUGGY_ON_RECYCLES ) {
+ // Software type is set with two targets:
+ // 1. prevent that bitmaps larger than maximum textures allowed are shown as black views in devices
+ // with LAYER_TYPE_HARDWARE enabled by default;
+ // 2. grant that bitmaps are correctly dellocated from memory in versions suffering the bug fixed in
+ // https://android.googlesource.com/platform/frameworks/base/+/034de6b1ec561797a2422314e6ef03e3cd3e08e0;
+ //
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
/**
* Checks if current bitmaps exceed the maximum OpenGL texture size limit
- * @param bitmap
- * @return boolean
+ * @param canvas Canvas where the view will be drawn into.
+ * @return boolean True means that the bitmap is too big for the canvas.
*/
@SuppressLint("NewApi")
private boolean checkIfMaximumBitmapExceed(Canvas canvas) {
- Log_OC.d("OC", "Canvas maximum: " + canvas.getMaximumBitmapWidth() + " - " + canvas.getMaximumBitmapHeight());
- if (mBitmap!= null && (mBitmap.getWidth() > canvas.getMaximumBitmapWidth()
- || mBitmap.getHeight() > canvas.getMaximumBitmapHeight())) {
+ Log_OC.v(TAG, "Canvas maximum: " + canvas.getMaximumBitmapWidth() + " - " + canvas.getMaximumBitmapHeight());
+ if (mBitmapWidth > canvas.getMaximumBitmapWidth()
+ || mBitmapHeight > canvas.getMaximumBitmapHeight()) {
return true;
}
return false;
}
+ @Override
/**
- * Set current bitmap
- * @param bitmap
+ * Keeps the size of the bitmap cached in member variables for faster access in {@link #onDraw(Canvas)} ,
+ * but without keeping another reference to the {@link Bitmap}
*/
- public void setBitmap (Bitmap bitmap) {
- mBitmap = bitmap;
+ public void setImageBitmap (Bitmap bm) {
+ mBitmapWidth = bm.getWidth();
+ mBitmapHeight = bm.getHeight();
+ super.setImageBitmap(bm);
}
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
- * This program is distributed in the hope that it will be useful,
+ * This program is distributed in the hd 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.
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
-import android.preference.PreferenceManager;
+import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewPager;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.ActionBar;
+import android.view.MenuItem;
import android.view.View;
+import android.view.Window;
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.view.MenuItem;
-import com.actionbarsherlock.view.Window;
import com.ortiz.touch.ExtendedViewPager;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.operations.UnshareLinkOperation;
import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.activity.PinCodeActivity;
import com.owncloud.android.ui.fragment.FileFragment;
import com.owncloud.android.utils.DisplayUtils;
/**
* Holds a swiping galley where image files contained in an ownCloud directory are shown
- *
- * @author David A. Velasco
*/
-public class PreviewImageActivity extends FileActivity implements
- FileFragment.ContainerActivity,
-ViewPager.OnPageChangeListener, OnRemoteOperationListener {
+public class PreviewImageActivity extends FileActivity implements
+ FileFragment.ContainerActivity,
+ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
public static final int DIALOG_SHORT_WAIT = 0;
private static final int INITIAL_HIDE_DELAY = 0; // immediate hide
private ExtendedViewPager mViewPager;
- private PreviewImagePagerAdapter mPreviewImagePagerAdapter;
+ private PreviewImagePagerAdapter mPreviewImagePagerAdapter;
+ private int mSavedPosition = 0;
+ private boolean mHasSavedPosition = false;
private boolean mRequestWaitingForBinder;
private View mFullScreenAnchorView;
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
+ requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
+
super.onCreate(savedInstanceState);
- requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
setContentView(R.layout.preview_image_activity);
-
+
+ // Navigation Drawer
+ initDrawer();
+
+ // ActionBar
ActionBar actionBar = getSupportActionBar();
actionBar.setIcon(DisplayUtils.getSeasonalIconId());
- actionBar.setDisplayHomeAsUpEnabled(true);
+ updateActionBarTitleAndHomeButton(null);
actionBar.hide();
-
- // PIN CODE request
- if (getIntent().getExtras() != null && savedInstanceState == null && fromNotification()) {
- requestPinCode();
- }
+
// Make sure we're running on Honeycomb or higher to use FullScreen and
// Immersive Mode
mFullScreenAnchorView = getWindow().getDecorView();
// to keep our UI controls visibility in line with system bars
// visibility
- mFullScreenAnchorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
+ mFullScreenAnchorView.setOnSystemUiVisibilityChangeListener
+ (new View.OnSystemUiVisibilityChangeListener() {
@SuppressLint("InlinedApi")
@Override
public void onSystemUiVisibilityChange(int flags) {
ActionBar actionBar = getSupportActionBar();
if (visible) {
actionBar.show();
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
} else {
actionBar.hide();
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
}
});
private void initViewPager() {
// get parent from path
- String parentPath = getFile().getRemotePath().substring(0, getFile().getRemotePath().lastIndexOf(getFile().getFileName()));
+ String parentPath = getFile().getRemotePath().substring(0,
+ getFile().getRemotePath().lastIndexOf(getFile().getFileName()));
OCFile parentFolder = getStorageManager().getFileByPath(parentPath);
if (parentFolder == null) {
// should not be necessary
parentFolder = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
}
- mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), parentFolder, getAccount(), getStorageManager());
+
+ // TODO Enable when "On Device" is recovered ?
+ mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(),
+ parentFolder, getAccount(), getStorageManager()/*, MainApp.getOnlyOnDevice()*/);
+
mViewPager = (ExtendedViewPager) findViewById(R.id.fragmentPager);
- int position = mPreviewImagePagerAdapter.getFilePosition(getFile());
+ int position = mHasSavedPosition ? mSavedPosition :
+ mPreviewImagePagerAdapter.getFilePosition(getFile());
position = (position >= 0) ? position : 0;
mViewPager.setAdapter(mPreviewImagePagerAdapter);
mViewPager.setOnPageChangeListener(this);
mViewPager.setCurrentItem(position);
if (position == 0 && !getFile().isDown()) {
- // this is necessary because mViewPager.setCurrentItem(0) just after setting the adapter does not result in a call to #onPageSelected(0)
+ // this is necessary because mViewPager.setCurrentItem(0) just after setting the
+ // adapter does not result in a call to #onPageSelected(0)
mRequestWaitingForBinder = true;
}
}
}
- private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
+ private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
+ RemoteOperationResult result) {
if (result.isSuccess()) {
OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
if (file != null) {
}
- private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
+ private void onCreateShareOperationFinish(CreateShareOperation operation,
+ RemoteOperationResult result) {
if (result.isSuccess()) {
OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
if (file != null) {
@Override
public void onServiceConnected(ComponentName component, IBinder service) {
- if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
+ if (component.equals(new ComponentName(PreviewImageActivity.this,
+ FileDownloader.class))) {
mDownloaderBinder = (FileDownloaderBinder) service;
if (mRequestWaitingForBinder) {
mRequestWaitingForBinder = false;
- Log_OC.d(TAG, "Simulating reselection of current page after connection of download binder");
+ Log_OC.d(TAG, "Simulating reselection of current page after connection " +
+ "of download binder");
onPageSelected(mViewPager.getCurrentItem());
}
- } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
+ } else if (component.equals(new ComponentName(PreviewImageActivity.this,
+ FileUploader.class))) {
Log_OC.d(TAG, "Upload service connected");
mUploaderBinder = (FileUploaderBinder) service;
} else {
@Override
public void onServiceDisconnected(ComponentName component) {
- if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
+ if (component.equals(new ComponentName(PreviewImageActivity.this,
+ FileDownloader.class))) {
Log_OC.d(TAG, "Download service suddenly disconnected");
mDownloaderBinder = null;
- } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
+ } else if (component.equals(new ComponentName(PreviewImageActivity.this,
+ FileUploader.class))) {
Log_OC.d(TAG, "Upload service suddenly disconnected");
mUploaderBinder = null;
}
switch(item.getItemId()){
case android.R.id.home:
- backToDisplayActivity();
+ if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
+ mDrawerLayout.closeDrawer(GravityCompat.START);
+ } else {
+ backToDisplayActivity();
+ }
returnValue = true;
break;
default:
@Override
protected void onResume() {
super.onResume();
- //Log_OC.e(TAG, "ACTIVITY, ONRESUME");
+
mDownloadFinishReceiver = new DownloadFinishReceiver();
IntentFilter filter = new IntentFilter(FileDownloader.getDownloadFinishMessage());
@Override
protected void onPostResume() {
- //Log_OC.e(TAG, "ACTIVITY, ONPOSTRESUME");
super.onPostResume();
}
@Override
public void onPause() {
- unregisterReceiver(mDownloadFinishReceiver);
- mDownloadFinishReceiver = null;
+ if (mDownloadFinishReceiver != null){
+ unregisterReceiver(mDownloadFinishReceiver);
+ mDownloadFinishReceiver = null;
+ }
+
super.onPause();
}
Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class);
showDetailsIntent.setAction(FileDisplayActivity.ACTION_DETAILS);
showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, file);
- showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+ showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT,
+ AccountUtils.getCurrentOwnCloudAccount(this));
startActivity(showDetailsIntent);
int pos = mPreviewImagePagerAdapter.getFilePosition(file);
file = mPreviewImagePagerAdapter.getFileAt(pos);
}
/**
- * This method will be invoked when a new page becomes selected. Animation is not necessarily complete.
+ * This method will be invoked when a new page becomes selected. Animation is not necessarily
+ * complete.
*
- * @param Position Position index of the new selected page
+ * @param position Position index of the new selected page
*/
@Override
public void onPageSelected(int position) {
+ mSavedPosition = position;
+ mHasSavedPosition = true;
if (mDownloaderBinder == null) {
mRequestWaitingForBinder = true;
} else {
OCFile currentFile = mPreviewImagePagerAdapter.getFileAt(position);
getSupportActionBar().setTitle(currentFile.getFileName());
+ mDrawerToggle.setDrawerIndicatorEnabled(false);
if (!currentFile.isDown()) {
if (!mPreviewImagePagerAdapter.pendingErrorAt(position)) {
requestForDownload(currentFile);
* Called when the scroll state changes. Useful for discovering when the user begins dragging,
* when the pager is automatically settling to the current page. when it is fully stopped/idle.
*
- * @param State The new scroll state (SCROLL_STATE_IDLE, _DRAGGING, _SETTLING
+ * @param state The new scroll state (SCROLL_STATE_IDLE, _DRAGGING, _SETTLING
*/
@Override
public void onPageScrollStateChanged(int state) {
}
/**
- * This method will be invoked when the current page is scrolled, either as part of a programmatically
- * initiated smooth scroll or a user initiated touch scroll.
+ * This method will be invoked when the current page is scrolled, either as part of a
+ * programmatically initiated smooth scroll or a user initiated touch scroll.
*
* @param position Position index of the first page currently being displayed.
- * Page position+1 will be visible if positionOffset is nonzero.
+ * Page position+1 will be visible if positionOffset is
+ * nonzero.
*
- * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
+ * @param positionOffset Value from [0, 1) indicating the offset from the page
+ * at position.
* @param positionOffsetPixels Value in pixels indicating the offset from position.
*/
@Override
/**
- * Class waiting for broadcast events from the {@link FielDownloader} service.
+ * Class waiting for broadcast events from the {@link FileDownloader} service.
*
* Updates the UI when a download is started or finished, provided that it is relevant for the
* folder displayed in the gallery.
OCFile file = getStorageManager().getFileByPath(downloadedRemotePath);
int position = mPreviewImagePagerAdapter.getFilePosition(file);
- boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false);
- //boolean isOffscreen = Math.abs((mViewPager.getCurrentItem() - position)) <= mViewPager.getOffscreenPageLimit();
+ boolean downloadWasFine = intent.getBooleanExtra(
+ FileDownloader.EXTRA_DOWNLOAD_RESULT, false);
+ //boolean isOffscreen = Math.abs((mViewPager.getCurrentItem() - position))
+ // <= mViewPager.getOffscreenPageLimit();
- if (position >= 0 && intent.getAction().equals(FileDownloader.getDownloadFinishMessage())) {
+ if (position >= 0 &&
+ intent.getAction().equals(FileDownloader.getDownloadFinishMessage())) {
if (downloadWasFine) {
mPreviewImagePagerAdapter.updateFile(position, file);
} else {
mPreviewImagePagerAdapter.updateWithDownloadError(position);
}
- mPreviewImagePagerAdapter.notifyDataSetChanged(); // will trigger the creation of new fragments
+ mPreviewImagePagerAdapter.notifyDataSetChanged(); // will trigger the creation
+ // of new fragments
} else {
Log_OC.d(TAG, "Download finished, but the fragment is offscreen");
ActionBar actionBar = getSupportActionBar();
if (!actionBar.isShowing()) {
actionBar.show();
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
} else {
actionBar.hide();
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
}
}
}
-
-
- /**
- * Launch an intent to request the PIN code to the user before letting him use the app
- */
- private void requestPinCode() {
- boolean pinStart = false;
- SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
- pinStart = appPrefs.getBoolean("set_pincode", false);
- if (pinStart) {
- Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
- i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "PreviewImageActivity");
- startActivity(i);
- }
- }
@Override
public void onBrowsedDownTo(OCFile folder) {
return false;
}
+ @Override
+ public void allFilesOption(){
+ backToDisplayActivity();
+ super.allFilesOption();
+ }
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
*/
package com.owncloud.android.ui.preview;
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.lang.ref.WeakReference;
import android.accounts.Account;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapFactory.Options;
import android.graphics.Point;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentStatePagerAdapter;
-import android.view.Display;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuInflater;
-import com.actionbarsherlock.view.MenuItem;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.FileMenuFilter;
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
import com.owncloud.android.ui.fragment.FileFragment;
-import com.owncloud.android.utils.TouchImageViewCustom;
+import com.owncloud.android.utils.BitmapUtils;
+import com.owncloud.android.utils.DisplayUtils;
+import third_parties.michaelOrtiz.TouchImageViewCustom;
/**
* This fragment shows a preview of a downloaded image.
+ *
+ * Trying to get an instance with a NULL {@link OCFile} will produce an
+ * {@link IllegalStateException}.
*
- * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
- *
- * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
- *
- * @author David A. Velasco
+ * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on
+ * instantiation too.
*/
public class PreviewImageFragment extends FileFragment {
public static final String EXTRA_FILE = "FILE";
- public static final String EXTRA_ACCOUNT = "ACCOUNT";
- private View mView;
- private Account mAccount;
+ private static final String ARG_FILE = "FILE";
+ private static final String ARG_IGNORE_FIRST = "IGNORE_FIRST";
+
private TouchImageViewCustom mImageView;
private TextView mMessageView;
private ProgressBar mProgressWheel;
private static final String TAG = PreviewImageFragment.class.getSimpleName();
private boolean mIgnoreFirstSavedState;
-
+ private LoadBitmapTask mLoadBitmapTask = null;
+
+
/**
- * Creates a fragment to preview an image.
- *
- * When 'imageFile' or 'ocAccount' are null
- *
+ * Public factory method to create a new fragment that previews an image.
+ *
+ * Android strongly recommends keep the empty constructor of fragments as the only public
+ * constructor, and
+ * use {@link #setArguments(Bundle)} to set the needed arguments.
+ *
+ * This method hides to client objects the need of doing the construction in two steps.
+ *
* @param imageFile An {@link OCFile} to preview as an image in the fragment
- * @param ocAccount An ownCloud account; needed to start downloads
- * @param ignoreFirstSavedState Flag to work around an unexpected behaviour of {@link FragmentStatePagerAdapter}; TODO better solution
+ * @param ignoreFirstSavedState Flag to work around an unexpected behaviour of
+ * {@link FragmentStatePagerAdapter}
+ * ; TODO better solution
*/
- public PreviewImageFragment(OCFile fileToDetail, Account ocAccount, boolean ignoreFirstSavedState) {
- super(fileToDetail);
- mAccount = ocAccount;
- mIgnoreFirstSavedState = ignoreFirstSavedState;
+ public static PreviewImageFragment newInstance(OCFile imageFile, boolean ignoreFirstSavedState){
+ PreviewImageFragment frag = new PreviewImageFragment();
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_FILE, imageFile);
+ args.putBoolean(ARG_IGNORE_FIRST, ignoreFirstSavedState);
+ frag.setArguments(args);
+ return frag;
}
+
/**
* Creates an empty fragment for image previews.
*
- * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside).
+ * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically
+ * (for instance, when the device is turned a aside).
*
- * DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction
+ * DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful
+ * construction
*/
public PreviewImageFragment() {
- super();
- mAccount = null;
mIgnoreFirstSavedState = false;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ Bundle args = getArguments();
+ setFile((OCFile)args.getParcelable(ARG_FILE));
+ // TODO better in super, but needs to check ALL the class extending FileFragment;
+ // not right now
+
+ mIgnoreFirstSavedState = args.getBoolean(ARG_IGNORE_FIRST);
setHasOptionsMenu(true);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
- mView = inflater.inflate(R.layout.preview_image_fragment, container, false);
- mImageView = (TouchImageViewCustom) mView.findViewById(R.id.image);
+ View view = inflater.inflate(R.layout.preview_image_fragment, container, false);
+ mImageView = (TouchImageViewCustom) view.findViewById(R.id.image);
mImageView.setVisibility(View.GONE);
mImageView.setOnClickListener(new OnClickListener() {
@Override
}
});
- mMessageView = (TextView)mView.findViewById(R.id.message);
+ mMessageView = (TextView)view.findViewById(R.id.message);
mMessageView.setVisibility(View.GONE);
- mProgressWheel = (ProgressBar)mView.findViewById(R.id.progressWheel);
+ mProgressWheel = (ProgressBar)view.findViewById(R.id.progressWheel);
mProgressWheel.setVisibility(View.VISIBLE);
- return mView;
+ return view;
}
/**
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
if (!mIgnoreFirstSavedState) {
- OCFile file = (OCFile)savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE);
+ OCFile file = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE);
setFile(file);
- mAccount = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_ACCOUNT);
} else {
mIgnoreFirstSavedState = false;
}
if (getFile() == null) {
throw new IllegalStateException("Instanced with a NULL OCFile");
}
- if (mAccount == null) {
- throw new IllegalStateException("Instanced with a NULL ownCloud Account");
- }
if (!getFile().isDown()) {
throw new IllegalStateException("There is no local file to preview");
}
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(PreviewImageFragment.EXTRA_FILE, getFile());
- outState.putParcelable(PreviewImageFragment.EXTRA_ACCOUNT, mAccount);
}
public void onStart() {
super.onStart();
if (getFile() != null) {
- BitmapLoader bl = new BitmapLoader(mImageView, mMessageView, mProgressWheel);
- bl.execute(new String[]{getFile().getStoragePath()});
+ mLoadBitmapTask = new LoadBitmapTask(mImageView, mMessageView, mProgressWheel);
+ //mLoadBitmapTask.execute(new String[]{getFile().getStoragePath()});
+ mLoadBitmapTask.execute(getFile().getStoragePath());
}
}
+ @Override
+ public void onStop() {
+ Log_OC.d(TAG, "onStop starts");
+ if (mLoadBitmapTask != null) {
+ mLoadBitmapTask.cancel(true);
+ mLoadBitmapTask = null;
+ }
+ super.onStop();
+ }
+
/**
* {@inheritDoc}
*/
getFile(),
mContainerActivity.getStorageManager().getAccount(),
mContainerActivity,
- getSherlockActivity()
+ getActivity()
);
mf.filter(menu);
}
if (mBitmap != null) {
mBitmap.recycle();
System.gc();
+ // putting this in onStop() is just the same; the fragment is always destroyed by
+ // {@link FragmentStatePagerAdapter} when the fragment in swiped further than the
+ // valid offscreen distance, and onStop() is never called before than that
}
super.onDestroy();
}
}
- private class BitmapLoader extends AsyncTask<String, Void, Bitmap> {
+ private class LoadBitmapTask extends AsyncTask<String, Void, Bitmap> {
/**
* Weak reference to the target {@link ImageView} where the bitmap will be loaded into.
- *
- * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+ *
+ * Using a weak reference will avoid memory leaks if the target ImageView is retired from
+ * memory before the load finishes.
*/
private final WeakReference<ImageViewCustom> mImageViewRef;
/**
* Weak reference to the target {@link TextView} where error messages will be written.
- *
- * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+ *
+ * Using a weak reference will avoid memory leaks if the target ImageView is retired from
+ * memory before the load finishes.
*/
private final WeakReference<TextView> mMessageViewRef;
/**
- * Weak reference to the target {@link Progressbar} shown while the load is in progress.
+ * Weak reference to the target {@link ProgressBar} shown while the load is in progress.
*
- * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+ * Using a weak reference will avoid memory leaks if the target ImageView is retired from
+ * memory before the load finishes.
*/
private final WeakReference<ProgressBar> mProgressWheelRef;
*
* @param imageView Target {@link ImageView} where the bitmap will be loaded into.
*/
- public BitmapLoader(ImageViewCustom imageView, TextView messageView, ProgressBar progressWheel) {
+ public LoadBitmapTask(ImageViewCustom imageView, TextView messageView,
+ ProgressBar progressWheel) {
mImageViewRef = new WeakReference<ImageViewCustom>(imageView);
mMessageViewRef = new WeakReference<TextView>(messageView);
mProgressWheelRef = new WeakReference<ProgressBar>(progressWheel);
@Override
protected Bitmap doInBackground(String... params) {
Bitmap result = null;
- if (params.length != 1) return result;
+ if (params.length != 1) return null;
String storagePath = params[0];
try {
- File picture = new File(storagePath);
-
- if (picture != null) {
- //Decode file into a bitmap in real size for being able to make zoom on the image
- result = BitmapFactory.decodeStream(new FlushedInputStream
- (new BufferedInputStream(new FileInputStream(picture))));
- }
-
- if (result == null) {
- mErrorMessageId = R.string.preview_image_error_unknown_format;
- Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
+ int maxDownScale = 3; // could be a parameter passed to doInBackground(...)
+ Point screenSize = DisplayUtils.getScreenSize(getActivity());
+ int minWidth = screenSize.x;
+ int minHeight = screenSize.y;
+ for (int i = 0; i < maxDownScale && result == null; i++) {
+ if (isCancelled()) return null;
+ try {
+ result = BitmapUtils.decodeSampledBitmapFromFile(storagePath, minWidth,
+ minHeight);
+
+ if (isCancelled()) return result;
+
+ if (result == null) {
+ mErrorMessageId = R.string.preview_image_error_unknown_format;
+ Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
+ break;
+ } else {
+ // Rotate image, obeying exif tag.
+ result = BitmapUtils.rotateImage(result, storagePath);
+ }
+
+ } catch (OutOfMemoryError e) {
+ mErrorMessageId = R.string.common_error_out_memory;
+ if (i < maxDownScale - 1) {
+ Log_OC.w(TAG, "Out of memory rendering file " + storagePath +
+ " ; scaling down");
+ minWidth = minWidth / 2;
+ minHeight = minHeight / 2;
+
+ } else {
+ Log_OC.w(TAG, "Out of memory rendering file " + storagePath +
+ " ; failing");
+ }
+ if (result != null) {
+ result.recycle();
+ }
+ result = null;
+ }
}
-
- } catch (OutOfMemoryError e) {
- Log_OC.e(TAG, "Out of memory occured for file " + storagePath, e);
- // If out of memory error when loading image, try to load it scaled
- result = loadScaledImage(storagePath);
-
- if (result == null) {
- mErrorMessageId = R.string.preview_image_error_unknown_format;
- Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
- }
-
} catch (NoSuchFieldError e) {
mErrorMessageId = R.string.common_error_unknown;
- Log_OC.e(TAG, "Error from access to unexisting field despite protection; file " + storagePath, e);
+ Log_OC.e(TAG, "Error from access to unexisting field despite protection; file "
+ + storagePath, e);
} catch (Throwable t) {
mErrorMessageId = R.string.common_error_unknown;
Log_OC.e(TAG, "Unexpected error loading " + getFile().getStoragePath(), t);
}
+
return result;
}
@Override
+ protected void onCancelled(Bitmap result) {
+ if (result != null) {
+ result.recycle();
+ }
+ }
+
+ @Override
protected void onPostExecute(Bitmap result) {
hideProgressWheel();
if (result != null) {
} else {
showErrorMessage();
}
+ if (result != null && mBitmap != result) {
+ // unused bitmap, release it! (just in case)
+ result.recycle();
+ }
}
-
+
@SuppressLint("InlinedApi")
private void showLoadedImage(Bitmap result) {
- if (mImageViewRef != null) {
- final ImageViewCustom imageView = mImageViewRef.get();
- if (imageView != null) {
- imageView.setBitmap(result);
- imageView.setImageBitmap(result);
- imageView.setVisibility(View.VISIBLE);
- mBitmap = result;
- } // else , silently finish, the fragment was destroyed
- }
- if (mMessageViewRef != null) {
- final TextView messageView = mMessageViewRef.get();
- if (messageView != null) {
- messageView.setVisibility(View.GONE);
- } // else , silently finish, the fragment was destroyed
+ final ImageViewCustom imageView = mImageViewRef.get();
+ if (imageView != null) {
+ Log_OC.d(TAG, "Showing image with resolution " + result.getWidth() + "x" +
+ result.getHeight());
+ imageView.setImageBitmap(result);
+ imageView.setVisibility(View.VISIBLE);
+ mBitmap = result; // needs to be kept for recycling when not useful
}
+
+ final TextView messageView = mMessageViewRef.get();
+ if (messageView != null) {
+ messageView.setVisibility(View.GONE);
+ } // else , silently finish, the fragment was destroyed
}
private void showErrorMessage() {
- if (mImageViewRef != null) {
- final ImageView imageView = mImageViewRef.get();
- if (imageView != null) {
- // shows the default error icon
- imageView.setVisibility(View.VISIBLE);
- } // else , silently finish, the fragment was destroyed
- }
- if (mMessageViewRef != null) {
- final TextView messageView = mMessageViewRef.get();
- if (messageView != null) {
- messageView.setText(mErrorMessageId);
- messageView.setVisibility(View.VISIBLE);
- } // else , silently finish, the fragment was destroyed
- }
+ final ImageView imageView = mImageViewRef.get();
+ if (imageView != null) {
+ // shows the default error icon
+ imageView.setVisibility(View.VISIBLE);
+ } // else , silently finish, the fragment was destroyed
+
+ final TextView messageView = mMessageViewRef.get();
+ if (messageView != null) {
+ messageView.setText(mErrorMessageId);
+ messageView.setVisibility(View.VISIBLE);
+ } // else , silently finish, the fragment was destroyed
}
private void hideProgressWheel() {
- if (mProgressWheelRef != null) {
- final ProgressBar progressWheel = mProgressWheelRef.get();
- if (progressWheel != null) {
- progressWheel.setVisibility(View.GONE);
- }
+ final ProgressBar progressWheel = mProgressWheelRef.get();
+ if (progressWheel != null) {
+ progressWheel.setVisibility(View.GONE);
}
}
}
/**
- * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment} to be previewed.
+ * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment}
+ * to be previewed.
*
* @param file File to test if can be previewed.
* @return 'True' if the file can be handled by the fragment.
return mImageView;
}
- static class FlushedInputStream extends FilterInputStream {
- public FlushedInputStream(InputStream inputStream) {
- super(inputStream);
- }
-
- @Override
- public long skip(long n) throws IOException {
- long totalBytesSkipped = 0L;
- while (totalBytesSkipped < n) {
- long bytesSkipped = in.skip(n - totalBytesSkipped);
- if (bytesSkipped == 0L) {
- int byteValue = read();
- if (byteValue < 0) {
- break; // we reached EOF
- } else {
- bytesSkipped = 1; // we read one byte
- }
- }
- totalBytesSkipped += bytesSkipped;
- }
- return totalBytesSkipped;
- }
- }
-
- /**
- * Load image scaled
- * @param storagePath: path of the image
- * @return Bitmap
- */
- @SuppressWarnings("deprecation")
- private Bitmap loadScaledImage(String storagePath) {
-
- Log_OC.d(TAG, "Loading image scaled");
-
- // set desired options that will affect the size of the bitmap
- BitmapFactory.Options options = new Options();
- options.inScaled = true;
- options.inPurgeable = true;
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- options.inPreferQualityOverSpeed = false;
- }
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
- options.inMutable = false;
- }
- // make a false load of the bitmap - just to be able to read outWidth, outHeight and outMimeType
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(storagePath, options);
-
- int width = options.outWidth;
- int height = options.outHeight;
- int scale = 1;
-
- Display display = getActivity().getWindowManager().getDefaultDisplay();
- Point size = new Point();
- int screenWidth;
- int screenHeight;
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
- display.getSize(size);
- screenWidth = size.x;
- screenHeight = size.y;
- } else {
- screenWidth = display.getWidth();
- screenHeight = display.getHeight();
- }
-
- if (width > screenWidth) {
- // second try to scale down the image , this time depending upon the screen size
- scale = (int) Math.floor((float)width / screenWidth);
- }
- if (height > screenHeight) {
- scale = Math.max(scale, (int) Math.floor((float)height / screenHeight));
- }
- options.inSampleSize = scale;
-
- // really load the bitmap
- options.inJustDecodeBounds = false; // the next decodeFile call will be real
- return BitmapFactory.decodeFile(storagePath, options);
-
- }
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.ui.fragment.FileFragment;
+import com.owncloud.android.utils.FileStorageUtils;
/**
- * Adapter class that provides Fragment instances
- *
- * @author David A. Velasco
+ * Adapter class that provides Fragment instances
*/
//public class PreviewImagePagerAdapter extends PagerAdapter {
public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
/**
* Constructor.
*
- * @param fragmentManager {@link FragmentManager} instance that will handle the {@link Fragment}s provided by the adapter.
+ * @param fragmentManager {@link FragmentManager} instance that will handle
+ * the {@link Fragment}s provided by the adapter.
* @param parentFolder Folder where images will be searched for.
* @param storageManager Bridge to database.
*/
- public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder, Account account, FileDataStorageManager storageManager) {
+ public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder,
+ Account account, FileDataStorageManager storageManager /*,
+ boolean onlyOnDevice*/) {
super(fragmentManager);
if (fragmentManager == null) {
mAccount = account;
mStorageManager = storageManager;
- mImageFiles = mStorageManager.getFolderImages(parentFolder);
+ // TODO Enable when "On Device" is recovered ?
+ mImageFiles = mStorageManager.getFolderImages(parentFolder/*, false*/);
+
+ mImageFiles = FileStorageUtils.sortFolder(mImageFiles);
+
mObsoleteFragments = new HashSet<Object>();
mObsoletePositions = new HashSet<Integer>();
mDownloadErrors = new HashSet<Integer>();
//mFragmentManager = fragmentManager;
mCachedFragments = new HashMap<Integer, FileFragment>();
}
-
/**
* Returns the image files handled by the adapter.
OCFile file = mImageFiles.get(i);
Fragment fragment = null;
if (file.isDown()) {
- fragment = new PreviewImageFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)));
+ fragment = PreviewImageFragment.newInstance(file,
+ mObsoletePositions.contains(Integer.valueOf(i)));
} else if (mDownloadErrors.contains(Integer.valueOf(i))) {
- fragment = new FileDownloadFragment(file, mAccount, true);
+ fragment = FileDownloadFragment.newInstance(file, mAccount, true);
((FileDownloadFragment)fragment).setError(true);
mDownloadErrors.remove(Integer.valueOf(i));
} else {
- fragment = new FileDownloadFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)));
+ fragment = FileDownloadFragment.newInstance(
+ file, mAccount, mObsoletePositions.contains(Integer.valueOf(i))
+ );
}
mObsoletePositions.remove(Integer.valueOf(i));
return fragment;
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.os.Bundle;
import android.os.IBinder;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Toast;
import android.widget.VideoView;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuInflater;
-import com.actionbarsherlock.view.MenuItem;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.FileMenuFilter;
/**
* This fragment shows a preview of a downloaded media file (audio or video).
*
- * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
- *
- * By now, if the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
+ * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will
+ * produce an {@link IllegalStateException}.
*
- * @author David A. Velasco
+ * By now, if the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is
+ * generated on instantiation too.
*/
public class PreviewMediaFragment extends FileFragment implements
OnTouchListener {
private void stopAudio() {
- Intent i = new Intent(getSherlockActivity(), MediaService.class);
+ Intent i = new Intent(getActivity(), MediaService.class);
i.setAction(MediaService.ACTION_STOP_ALL);
- getSherlockActivity().startService(i);
+ getActivity().startService(i);
}
getFile(),
mContainerActivity.getStorageManager().getAccount(),
mContainerActivity,
- getSherlockActivity()
+ getActivity()
);
mf.filter(menu);
}
*
* Just starts the playback.
*
- * @param mp {@link MediaPlayer} instance performing the playback.
+ * @param vp {@link MediaPlayer} instance performing the playback.
*/
@Override
public void onPrepared(MediaPlayer vp) {
public boolean onError(MediaPlayer mp, int what, int extra) {
if (mVideoPreview.getWindowToken() != null) {
String message = MediaService.getMessageForMediaError(
- getSherlockActivity(), what, extra);
- new AlertDialog.Builder(getSherlockActivity())
+ getActivity(), what, extra);
+ new AlertDialog.Builder(getActivity())
.setMessage(message)
.setPositiveButton(android.R.string.VideoView_error_button,
new DialogInterface.OnClickListener() {
if (mMediaServiceBinder != null && mMediaController != null) {
mMediaServiceBinder.unregisterMediaController(mMediaController);
}
- getSherlockActivity().unbindService(mMediaServiceConnection);
+ getActivity().unbindService(mMediaServiceConnection);
mMediaServiceConnection = null;
mMediaServiceBinder = null;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && v == mVideoPreview) {
- startFullScreenVideo();
+ // added a margin on the left to avoid interfering with gesture to open navigation drawer
+ if (event.getX() / Resources.getSystem().getDisplayMetrics().density > 24.0) {
+ startFullScreenVideo();
+ }
return true;
}
return false;
private void startFullScreenVideo() {
- Intent i = new Intent(getSherlockActivity(), PreviewVideoActivity.class);
+ Intent i = new Intent(getActivity(), PreviewVideoActivity.class);
i.putExtra(FileActivity.EXTRA_ACCOUNT, mAccount);
i.putExtra(FileActivity.EXTRA_FILE, getFile());
i.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, mVideoPreview.isPlaying());
if (mMediaServiceConnection == null) {
mMediaServiceConnection = new MediaServiceConnection();
}
- getSherlockActivity().bindService( new Intent(getSherlockActivity(),
+ getActivity().bindService( new Intent(getActivity(),
MediaService.class),
mMediaServiceConnection,
Context.BIND_AUTO_CREATE);
@Override
public void onServiceConnected(ComponentName component, IBinder service) {
- if (getSherlockActivity() != null) {
+ if (getActivity() != null) {
if (component.equals(
- new ComponentName(getSherlockActivity(), MediaService.class))) {
+ new ComponentName(getActivity(), MediaService.class))) {
Log_OC.d(TAG, "Media service connected");
mMediaServiceBinder = (MediaServiceBinder) service;
if (mMediaServiceBinder != null) {
@Override
public void onServiceDisconnected(ComponentName component) {
- if (component.equals(new ComponentName(getSherlockActivity(), MediaService.class))) {
+ if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
Log_OC.e(TAG, "Media service suddenly disconnected");
if (mMediaController != null) {
mMediaController.setMediaPlayer(null);
} else {
Toast.makeText(
- getSherlockActivity(),
+ getActivity(),
"No media controller to release when disconnected from media service",
Toast.LENGTH_SHORT).show();
}
* Finishes the preview
*/
private void finish() {
- getSherlockActivity().onBackPressed();
+ getActivity().onBackPressed();
}
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* Used as an utility to preview video files contained in an ownCloud account.
*
* Currently, it always plays in landscape mode, full screen. When the playback ends,
- * the activity is finished.
- *
- * @author David A. Velasco
+ * the activity is finished.
*/
public class PreviewVideoActivity extends FileActivity implements OnCompletionListener, OnPreparedListener, OnErrorListener {
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
*/
package com.owncloud.android.utils;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
import android.graphics.BitmapFactory.Options;
+import android.media.ExifInterface;
+import android.net.Uri;
+import android.webkit.MimeTypeMap;
+
+import java.io.File;
/**
* Utility class with methods for decoding Bitmaps.
- *
- * @author David A. Velasco
*/
public class BitmapUtils {
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
-
+
+ // calculates the largest inSampleSize value (for smallest sample) that is a power of 2 and keeps both
+ // height and width **larger** than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
return inSampleSize;
}
+ /**
+ * Rotate bitmap according to EXIF orientation.
+ * Cf. http://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/
+ * @param bitmap Bitmap to be rotated
+ * @param storagePath Path to source file of bitmap. Needed for EXIF information.
+ * @return correctly EXIF-rotated bitmap
+ */
+ public static Bitmap rotateImage(Bitmap bitmap, String storagePath){
+ Bitmap resultBitmap = bitmap;
+
+ try
+ {
+ ExifInterface exifInterface = new ExifInterface(storagePath);
+ int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
+
+ Matrix matrix = new Matrix();
+
+ // 1: nothing to do
+
+ // 2
+ if (orientation == ExifInterface.ORIENTATION_FLIP_HORIZONTAL)
+ {
+ matrix.postScale(-1.0f, 1.0f);
+ }
+ // 3
+ else if (orientation == ExifInterface.ORIENTATION_ROTATE_180)
+ {
+ matrix.postRotate(180);
+ }
+ // 4
+ else if (orientation == ExifInterface.ORIENTATION_FLIP_VERTICAL)
+ {
+ matrix.postScale(1.0f, -1.0f);
+ }
+ // 5
+ else if (orientation == ExifInterface.ORIENTATION_TRANSPOSE)
+ {
+ matrix.postRotate(-90);
+ matrix.postScale(1.0f, -1.0f);
+ }
+ // 6
+ else if (orientation == ExifInterface.ORIENTATION_ROTATE_90)
+ {
+ matrix.postRotate(90);
+ }
+ // 7
+ else if (orientation == ExifInterface.ORIENTATION_TRANSVERSE)
+ {
+ matrix.postRotate(90);
+ matrix.postScale(1.0f, -1.0f);
+ }
+ // 8
+ else if (orientation == ExifInterface.ORIENTATION_ROTATE_270)
+ {
+ matrix.postRotate(270);
+ }
+
+ // Rotate the bitmap
+ resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
+ if (resultBitmap != bitmap) {
+ bitmap.recycle();
+ }
+ }
+ catch (Exception exception)
+ {
+ Log_OC.e("BitmapUtil", "Could not rotate the image: " + storagePath);
+ }
+ return resultBitmap;
+ }
+
+ /**
+ * Convert HSL values to a RGB Color.
+ *
+ * @param h Hue is specified as degrees in the range 0 - 360.
+ * @param s Saturation is specified as a percentage in the range 1 - 100.
+ * @param l Lumanance is specified as a percentage in the range 1 - 100.
+ * @paran alpha the alpha value between 0 - 1
+ * adapted from https://svn.codehaus.org/griffon/builders/gfxbuilder/tags/GFXBUILDER_0.2/
+ * gfxbuilder-core/src/main/com/camick/awt/HSLColor.java
+ */
+ public static int[] HSLtoRGB(float h, float s, float l, float alpha)
+ {
+ if (s <0.0f || s > 100.0f)
+ {
+ String message = "Color parameter outside of expected range - Saturation";
+ throw new IllegalArgumentException( message );
+ }
+
+ if (l <0.0f || l > 100.0f)
+ {
+ String message = "Color parameter outside of expected range - Luminance";
+ throw new IllegalArgumentException( message );
+ }
+
+ if (alpha <0.0f || alpha > 1.0f)
+ {
+ String message = "Color parameter outside of expected range - Alpha";
+ throw new IllegalArgumentException( message );
+ }
+
+ // Formula needs all values between 0 - 1.
+
+ h = h % 360.0f;
+ h /= 360f;
+ s /= 100f;
+ l /= 100f;
+
+ float q = 0;
+
+ if (l < 0.5)
+ q = l * (1 + s);
+ else
+ q = (l + s) - (s * l);
+
+ float p = 2 * l - q;
+
+ int r = Math.round(Math.max(0, HueToRGB(p, q, h + (1.0f / 3.0f)) * 256));
+ int g = Math.round(Math.max(0, HueToRGB(p, q, h) * 256));
+ int b = Math.round(Math.max(0, HueToRGB(p, q, h - (1.0f / 3.0f)) * 256));
+
+ int[] array = {r, g, b};
+ return array;
+ }
+
+ private static float HueToRGB(float p, float q, float h){
+ if (h < 0) h += 1;
+
+ if (h > 1 ) h -= 1;
+
+ if (6 * h < 1)
+ {
+ return p + ((q - p) * 6 * h);
+ }
+
+ if (2 * h < 1 )
+ {
+ return q;
+ }
+
+ if (3 * h < 2)
+ {
+ return p + ( (q - p) * 6 * ((2.0f / 3.0f) - h) );
+ }
+
+ return p;
+ }
+
+ /**
+ * Checks if file passed is an image
+ * @param file
+ * @return true/false
+ */
+ public static boolean isImage(File file) {
+ Uri selectedUri = Uri.fromFile(file);
+ String fileExtension = MimeTypeMap.getFileExtensionFromUrl(selectedUri.toString().toLowerCase());
+ String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);
+
+ return (mimeType != null && mimeType.startsWith("image/"));
+ }
+
}
--- /dev/null
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.utils;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+
+/**
+ * AsyncTask to copy a file from a uri in a temporal file
+ */
+public class CopyTmpFileAsyncTask extends AsyncTask<Object, Void, String> {
+
+ private final String TAG = CopyTmpFileAsyncTask.class.getSimpleName();
+ private final WeakReference<OnCopyTmpFileTaskListener> mListener;
+ private int mIndex;
+
+ public int getIndex(){
+ return mIndex;
+ }
+
+ public CopyTmpFileAsyncTask(OnCopyTmpFileTaskListener listener) {
+ mListener = new WeakReference<OnCopyTmpFileTaskListener>(listener);
+ }
+
+ /**
+ * Params for execute:
+ * - Uri: uri of file
+ * - String: path for saving the file into the app
+ * - int: index of upload
+ * - String: accountName
+ * - ContentResolver: content resolver
+ */
+ @Override
+ protected String doInBackground(Object[] params) {
+ String result = null;
+
+ if (params != null && params.length == 5) {
+ Uri uri = (Uri) params[0];
+ String filePath = (String) params[1];
+ mIndex = ((Integer) params[2]).intValue();
+ String accountName = (String) params[3];
+ ContentResolver contentResolver = (ContentResolver) params[4];
+
+ String fullTempPath = FileStorageUtils.getTemporalPath(accountName) + filePath;
+ InputStream inputStream = null;
+ FileOutputStream outputStream = null;
+
+ try {
+ inputStream = contentResolver.openInputStream(uri);
+ File cacheFile = new File(fullTempPath);
+ File tempDir = cacheFile.getParentFile();
+ if (!tempDir.exists()) {
+ tempDir.mkdirs();
+ }
+ cacheFile.createNewFile();
+ outputStream = new FileOutputStream(fullTempPath);
+ byte[] buffer = new byte[4096];
+
+ int count = 0;
+
+ while ((count = inputStream.read(buffer)) > 0) {
+ outputStream.write(buffer, 0, count);
+ }
+
+ outputStream.close();
+ inputStream.close();
+
+ result = fullTempPath;
+ } catch (Exception e) {
+ Log_OC.e(TAG, "Exception ", e);
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (Exception e1) {
+ Log_OC.e(TAG, "Input Stream Exception ", e1);
+ }
+ }
+
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (Exception e1) {
+ Log_OC.e(TAG, "Output Stream Exception ", e1);
+ }
+ }
+
+ if (fullTempPath != null) {
+ File f = new File(fullTempPath);
+ f.delete();
+ }
+ result = null;
+ }
+ } else {
+ throw new IllegalArgumentException("Error in parameters number");
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(String result) {
+
+ OnCopyTmpFileTaskListener listener = mListener.get();
+ if (listener!= null)
+ {
+ listener.onTmpFileCopied(result, mIndex);
+ }
+ }
+
+ /*
+ * Interface to retrieve data from recognition task
+ */
+ public interface OnCopyTmpFileTaskListener{
+
+ void onTmpFileCopied(String result, int index);
+ }
+}
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
+ * @author Bartek Przybylski\r
+ * @author David A. Velasco\r
* Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
package com.owncloud.android.utils;\r
\r
import java.net.IDN;\r
+import java.text.DateFormat;\r
import java.util.Arrays;\r
import java.util.Calendar;\r
import java.util.Date;\r
import java.util.HashMap;\r
import java.util.HashSet;\r
import java.util.Set;\r
+import java.util.Vector;\r
\r
import android.annotation.TargetApi;\r
+import android.app.Activity;\r
import android.content.Context;\r
+import android.graphics.Point;\r
import android.os.Build;\r
-import android.text.format.DateFormat;\r
import android.text.format.DateUtils;\r
+import android.view.Display;\r
+import android.webkit.MimeTypeMap;\r
\r
import com.owncloud.android.MainApp;\r
import com.owncloud.android.R;\r
+import com.owncloud.android.datamodel.OCFile;\r
\r
/**\r
* A helper class for some string operations.\r
- * \r
- * @author Bartek Przybylski\r
- * @author David A. Velasco\r
*/\r
public class DisplayUtils {\r
\r
private static final String TYPE_VIDEO = "video";\r
\r
private static final String SUBTYPE_PDF = "pdf";\r
- private static final String[] SUBTYPES_DOCUMENT = { "msword",\r
- "vnd.openxmlformats-officedocument.wordprocessingml.document",\r
- "vnd.oasis.opendocument.text",\r
- "rtf"\r
- };\r
+ private static final String SUBTYPE_XML = "xml";\r
+ private static final String[] SUBTYPES_DOCUMENT = { \r
+ "msword",\r
+ "vnd.openxmlformats-officedocument.wordprocessingml.document",\r
+ "vnd.oasis.opendocument.text",\r
+ "rtf",\r
+ "javascript"\r
+ };\r
private static Set<String> SUBTYPES_DOCUMENT_SET = new HashSet<String>(Arrays.asList(SUBTYPES_DOCUMENT));\r
- private static final String[] SUBTYPES_SPREADSHEET = { "msexcel",\r
- "vnd.openxmlformats-officedocument.spreadsheetml.sheet",\r
- "vnd.oasis.opendocument.spreadsheet"\r
- };\r
+ private static final String[] SUBTYPES_SPREADSHEET = {\r
+ "msexcel",\r
+ "vnd.ms-excel",\r
+ "vnd.openxmlformats-officedocument.spreadsheetml.sheet",\r
+ "vnd.oasis.opendocument.spreadsheet"\r
+ };\r
private static Set<String> SUBTYPES_SPREADSHEET_SET = new HashSet<String>(Arrays.asList(SUBTYPES_SPREADSHEET));\r
- private static final String[] SUBTYPES_PRESENTATION = { "mspowerpoint",\r
- "vnd.openxmlformats-officedocument.presentationml.presentation",\r
- "vnd.oasis.opendocument.presentation"\r
- };\r
+ private static final String[] SUBTYPES_PRESENTATION = { \r
+ "mspowerpoint",\r
+ "vnd.ms-powerpoint",\r
+ "vnd.openxmlformats-officedocument.presentationml.presentation",\r
+ "vnd.oasis.opendocument.presentation"\r
+ };\r
private static Set<String> SUBTYPES_PRESENTATION_SET = new HashSet<String>(Arrays.asList(SUBTYPES_PRESENTATION));\r
private static final String[] SUBTYPES_COMPRESSED = {"x-tar", "x-gzip", "zip"};\r
private static final Set<String> SUBTYPES_COMPRESSED_SET = new HashSet<String>(Arrays.asList(SUBTYPES_COMPRESSED));\r
private static final String EXTENSION_RAR = "rar";\r
private static final String EXTENSION_RTF = "rtf";\r
private static final String EXTENSION_3GP = "3gp";\r
+ private static final String EXTENSION_PY = "py";\r
+ private static final String EXTENSION_JS = "js";\r
\r
/**\r
* Converts the file size in bytes to human readable output.\r
}\r
\r
/**\r
- * Removes special HTML entities from a string\r
- * \r
- * @param s Input string\r
- * @return A cleaned version of the string\r
- */\r
- public static String HtmlDecode(String s) {\r
- /*\r
- * TODO: Perhaps we should use something more proven like:\r
- * http://commons.apache.org/lang/api-2.6/org/apache/commons/lang/StringEscapeUtils.html#unescapeHtml%28java.lang.String%29\r
- */\r
-\r
- String ret = "";\r
- for (int i = 0; i < s.length(); ++i) {\r
- if (s.charAt(i) == '%') {\r
- ret += (char) Integer.parseInt(s.substring(i + 1, i + 3), 16);\r
- i += 2;\r
- } else {\r
- ret += s.charAt(i);\r
- }\r
- }\r
- return ret;\r
- }\r
-\r
- /**\r
* Converts MIME types like "image/jpg" to more end user friendly output\r
* like "JPG image".\r
* \r
\r
\r
/**\r
- * Returns the resource identifier of an image resource to use as icon associated to a \r
- * known MIME type.\r
+ * Returns the resource identifier of an image to use as icon associated to a known MIME type.\r
* \r
- * @param mimetype MIME type string.\r
- * @param filename name, with extension\r
- * @return Resource identifier of an image resource.\r
+ * @param mimetype MIME type string; if NULL, the method tries to guess it from the extension in filename\r
+ * @param filename Name, with extension.\r
+ * @return Identifier of an image resource.\r
*/\r
- public static int getResourceId(String mimetype, String filename) {\r
+ public static int getFileTypeIconId(String mimetype, String filename) {\r
\r
- if (mimetype == null || "DIR".equals(mimetype)) {\r
- return R.drawable.ic_menu_archive;\r
+ if (mimetype == null) {\r
+ String fileExtension = getExtension(filename);\r
+ mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);\r
+ if (mimetype == null) {\r
+ mimetype = TYPE_APPLICATION + "/" + SUBTYPE_OCTET_STREAM;\r
+ }\r
+ } \r
\r
+ if ("DIR".equals(mimetype)) {\r
+ return R.drawable.ic_menu_archive;\r
+\r
} else {\r
String [] parts = mimetype.split("/");\r
String type = parts[0];\r
if (SUBTYPE_PDF.equals(subtype)) {\r
return R.drawable.file_pdf;\r
\r
+ } else if (SUBTYPE_XML.equals(subtype)) {\r
+ return R.drawable.file_doc;\r
+\r
} else if (SUBTYPES_DOCUMENT_SET.contains(subtype)) {\r
return R.drawable.file_doc;\r
\r
\r
} else if (SUBTYPES_COMPRESSED_SET.contains(subtype)) {\r
return R.drawable.file_zip;\r
- \r
+\r
} else if (SUBTYPE_OCTET_STREAM.equals(subtype) ) {\r
if (getExtension(filename).equalsIgnoreCase(EXTENSION_RAR)) {\r
return R.drawable.file_zip;\r
\r
} else if (getExtension(filename).equalsIgnoreCase(EXTENSION_3GP)) {\r
return R.drawable.file_movie;\r
- \r
+ \r
+ } else if ( getExtension(filename).equalsIgnoreCase(EXTENSION_PY) ||\r
+ getExtension(filename).equalsIgnoreCase(EXTENSION_JS)) {\r
+ return R.drawable.file_doc;\r
} \r
} \r
}\r
\r
\r
private static String getExtension(String filename) {\r
- String extension = filename.substring(filename.lastIndexOf(".") + 1);\r
- \r
+ String extension = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();\r
return extension;\r
}\r
\r
/**\r
* Converts Unix time to human readable format\r
- * @param miliseconds that have passed since 01/01/1970\r
+ * @param milliseconds that have passed since 01/01/1970\r
* @return The human readable time for the users locale\r
*/\r
public static String unixTimeToHumanReadable(long milliseconds) {\r
Date date = new Date(milliseconds);\r
- return date.toLocaleString();\r
+ DateFormat df = DateFormat.getDateTimeInstance();\r
+ return df.format(date);\r
}\r
\r
\r
*/\r
@TargetApi(Build.VERSION_CODES.GINGERBREAD)\r
public static String convertIdn(String url, boolean toASCII) {\r
- \r
+\r
+ String urlNoDots = url;\r
+ String dots="";\r
+ while (urlNoDots.startsWith(".")) {\r
+ urlNoDots = url.substring(1);\r
+ dots = dots + ".";\r
+ }\r
+\r
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {\r
// Find host name after '//' or '@'\r
int hostStart = 0;\r
- if (url.indexOf("//") != -1) {\r
+ if (urlNoDots.indexOf("//") != -1) {\r
hostStart = url.indexOf("//") + "//".length();\r
} else if (url.indexOf("@") != -1) {\r
hostStart = url.indexOf("@") + "@".length();\r
}\r
- \r
+\r
int hostEnd = url.substring(hostStart).indexOf("/");\r
// Handle URL which doesn't have a path (path is implicitly '/')\r
- hostEnd = (hostEnd == -1 ? url.length() : hostStart + hostEnd);\r
- \r
- String host = url.substring(hostStart, hostEnd);\r
+ hostEnd = (hostEnd == -1 ? urlNoDots.length() : hostStart + hostEnd);\r
+\r
+ String host = urlNoDots.substring(hostStart, hostEnd);\r
host = (toASCII ? IDN.toASCII(host) : IDN.toUnicode(host));\r
- \r
- return url.substring(0, hostStart) + host + url.substring(hostEnd);\r
+\r
+ return dots + urlNoDots.substring(0, hostStart) + host + urlNoDots.substring(hostEnd);\r
} else {\r
- return url;\r
+ return dots + url;\r
}\r
}\r
\r
return fileExtension;\r
}\r
\r
- public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution, long transitionResolution, int flags){\r
+ @SuppressWarnings("deprecation")\r
+ public static CharSequence getRelativeDateTimeString (\r
+ Context c, long time, long minResolution, long transitionResolution, int flags\r
+ ){\r
+ \r
CharSequence dateString = "";\r
\r
// in Future\r
return c.getString(R.string.file_list_seconds_ago);\r
} else {\r
// Workaround 2.x bug (see https://github.com/owncloud/android/issues/716)\r
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB && (System.currentTimeMillis() - time) > 24 * 60 * 60 * 1000){\r
+ if ( Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB && \r
+ (System.currentTimeMillis() - time) > 24 * 60 * 60 * 1000 ) {\r
Date date = new Date(time);\r
date.setHours(0);\r
date.setMinutes(0);\r
date.setSeconds(0);\r
- dateString = DateUtils.getRelativeDateTimeString(c, date.getTime(), minResolution, transitionResolution, flags);\r
+ dateString = DateUtils.getRelativeDateTimeString(\r
+ c, date.getTime(), minResolution, transitionResolution, flags\r
+ );\r
} else {\r
dateString = DateUtils.getRelativeDateTimeString(c, time, minResolution, transitionResolution, flags);\r
}\r
}\r
\r
- return dateString.toString().split(",")[0];
+ return dateString.toString().split(",")[0];\r
+ }\r
+\r
+ /**\r
+ * Update the passed path removing the last "/" if it is not the root folder\r
+ * @param path\r
+ */\r
+ public static String getPathWithoutLastSlash(String path) {\r
+\r
+ // Remove last slash from path\r
+ if (path.length() > 1 && path.charAt(path.length()-1) == OCFile.PATH_SEPARATOR.charAt(0)) {\r
+ path = path.substring(0, path.length()-1);\r
+ }\r
+ return path;\r
+ }\r
+\r
+\r
+ /**\r
+ * Gets the screen size in pixels in a backwards compatible way\r
+ *\r
+ * @param caller Activity calling; needed to get access to the {@link android.view.WindowManager}\r
+ * @return Size in pixels of the screen, or default {@link Point} if caller is null\r
+ */\r
+ public static Point getScreenSize(Activity caller) {\r
+ Point size = new Point();\r
+ if (caller != null) {\r
+ Display display = caller.getWindowManager().getDefaultDisplay();\r
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {\r
+ display.getSize(size);\r
+ } else {\r
+ size.set(display.getWidth(), display.getHeight());\r
+ }\r
+ }\r
+ return size;\r
}\r
+\r
}\r
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author masensio
* Copyright (C) 2014 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
import com.owncloud.android.operations.RemoveFileOperation;
import com.owncloud.android.operations.RenameFileOperation;
import com.owncloud.android.operations.SynchronizeFileOperation;
+import com.owncloud.android.operations.SynchronizeFolderOperation;
import com.owncloud.android.operations.UnshareLinkOperation;
import com.owncloud.android.operations.UploadFileOperation;
/**
- * Class to choose proper error messages to show to the user depending on the results of operations, always following the same policy
- *
- * @author masensio
- *
+ * Class to choose proper error messages to show to the user depending on the results of operations,
+ * always following the same policy
*/
public class ErrorMessageAdapter {
}
- public static String getErrorCauseMessage(RemoteOperationResult result, RemoteOperation operation, Resources res) {
+ public static String getErrorCauseMessage(RemoteOperationResult result,
+ RemoteOperation operation, Resources res) {
String message = null;
if (operation instanceof UploadFileOperation) {
if (result.isSuccess()) {
- message = String.format(res.getString(R.string.uploader_upload_succeeded_content_single),
+ message = String.format(
+ res.getString(R.string.uploader_upload_succeeded_content_single),
((UploadFileOperation) operation).getFileName());
} else {
if (result.getCode() == ResultCode.LOCAL_STORAGE_FULL
|| result.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) {
- message = String.format(res.getString(R.string.error__upload__local_file_not_copied),
+ message = String.format(
+ res.getString(R.string.error__upload__local_file_not_copied),
((UploadFileOperation) operation).getFileName(),
res.getString(R.string.app_name));
/*
message = String.format(res.getString(R.string.forbidden_permissions),
res.getString(R.string.uploader_upload_forbidden_permissions));
+ } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
+ message = res.getString(R.string.filename_forbidden_charaters_from_server);
+
} else {
- message = String.format(res.getString(R.string.uploader_upload_failed_content_single),
+ message = String.format(
+ res.getString(R.string.uploader_upload_failed_content_single),
((UploadFileOperation) operation).getFileName());
}
}
} else if (operation instanceof DownloadFileOperation) {
if (result.isSuccess()) {
- message = String.format(res.getString(R.string.downloader_download_succeeded_content),
+ message = String.format(
+ res.getString(R.string.downloader_download_succeeded_content),
new File(((DownloadFileOperation) operation).getSavePath()).getName());
} else {
message = res.getString(R.string.downloader_download_file_not_found);
} else {
- message = String.format(res.getString(R.string.downloader_download_failed_content), new File(
+ message = String.format(
+ res.getString(R.string.downloader_download_failed_content), new File(
((DownloadFileOperation) operation).getSavePath()).getName());
}
}
} else if (isNetworkError(result.getCode())) {
message = getErrorMessage(result, res);
+ } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
+ message = res.getString(R.string.filename_forbidden_charaters_from_server);
+
} else {
message = res.getString(R.string.rename_server_fail_msg);
}
} else if (isNetworkError(result.getCode())) {
message = getErrorMessage(result, res);
+ } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
+ message = res.getString(R.string.filename_forbidden_charaters_from_server);
} else {
message = res.getString(R.string.create_dir_fail_msg);
}
} else if (operation instanceof CreateShareOperation) {
- if (result.getCode() == ResultCode.SHARE_NOT_FOUND) { // Error --> SHARE_NOT_FOUND
+ if (result.getCode() == ResultCode.SHARE_NOT_FOUND) { // Error --> SHARE_NOT_FOUND
message = res.getString(R.string.share_link_file_no_exist);
} else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
} else if (operation instanceof UnshareLinkOperation) {
- if (result.getCode() == ResultCode.SHARE_NOT_FOUND) { // Error --> SHARE_NOT_FOUND
+ if (result.getCode() == ResultCode.SHARE_NOT_FOUND) { // Error --> SHARE_NOT_FOUND
message = res.getString(R.string.unshare_link_file_no_exist);
} else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
message = String.format(res.getString(R.string.forbidden_permissions),
res.getString(R.string.forbidden_permissions_move));
- }else { // Generic error
+ } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
+ message = res.getString(R.string.filename_forbidden_charaters_from_server);
+
+ } else { // Generic error
// Show a Message, operation finished without success
message = res.getString(R.string.move_file_error);
}
+ } else if (operation instanceof SynchronizeFolderOperation) {
+
+ if (!result.isSuccess()) {
+ String folderPathName = new File(
+ ((SynchronizeFolderOperation) operation).getFolderPath()).getName();
+ if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
+ message = String.format(res.getString(R.string.sync_current_folder_was_removed),
+ folderPathName);
+
+ } else { // Generic error
+ // Show a Message, operation finished without success
+ message = String.format(res.getString(R.string.download_folder_failed_content),
+ folderPathName);
+ }
+ }
}
return message;
-/* ownCloud Android client application
- * Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * @author David A. Velasco
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.utils;
import java.io.File;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Vector;
+
+import third_parties.daveKoeller.AlphanumComparator;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import android.net.Uri;
import android.os.Environment;
import android.os.StatFs;
+import android.webkit.MimeTypeMap;
/**
* Static methods to help in access to local file system.
- *
- * @author David A. Velasco
*/
public class FileStorageUtils {
+ public static Integer mSortOrder;
+ public static Boolean mSortAscending;
+ public static final Integer SORT_NAME = 0;
+ public static final Integer SORT_DATE = 1;
+ public static final Integer SORT_SIZE = 2;
+
+
//private static final String LOG_TAG = "FileStorageUtils";
public static final String getSavePath(String accountName) {
String value = uploadPath + OCFile.PATH_SEPARATOR + (fileName == null ? "" : fileName);
return value;
}
+
+ /**
+ * Gets the composed path when video is or must be stored
+ * @param context
+ * @param fileName: video file name
+ * @return String: video file path composed
+ */
+ public static String getInstantVideoUploadFilePath(Context context, String fileName) {
+ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
+ String uploadVideoPathdef = context.getString(R.string.instant_upload_path);
+ String uploadVideoPath = pref.getString("instant_video_upload_path", uploadVideoPathdef);
+ String value = uploadVideoPath + OCFile.PATH_SEPARATOR + (fileName == null ? "" : fileName);
+ return value;
+ }
public static String getParentPath(String remotePath) {
String parentPath = new File(remotePath).getParent();
/**
* Creates and populates a new {@link RemoteFile} object with the data read from an {@link OCFile}.
*
- * @param oCFile OCFile
+ * @param ocFile OCFile
* @return New RemoteFile instance representing the resource described by ocFile.
*/
public static RemoteFile fillRemoteFile(OCFile ocFile){
file.setRemoteId(ocFile.getRemoteId());
return file;
}
+
+ /**
+ * Sorts all filenames, regarding last user decision
+ */
+ public static Vector<OCFile> sortFolder(Vector<OCFile> files){
+ switch (mSortOrder){
+ case 0:
+ files = FileStorageUtils.sortByName(files);
+ break;
+ case 1:
+ files = FileStorageUtils.sortByDate(files);
+ break;
+ case 2:
+ // mFiles = FileStorageUtils.sortBySize(mSortAscending);
+ break;
+ }
+
+ return files;
+ }
+
+ /**
+ * Sorts list by Date
+ * @param files
+ */
+ public static Vector<OCFile> sortByDate(Vector<OCFile> files){
+ final Integer val;
+ if (mSortAscending){
+ val = 1;
+ } else {
+ val = -1;
+ }
+
+ Collections.sort(files, new Comparator<OCFile>() {
+ public int compare(OCFile o1, OCFile o2) {
+ if (o1.isFolder() && o2.isFolder()) {
+ Long obj1 = o1.getModificationTimestamp();
+ return val * obj1.compareTo(o2.getModificationTimestamp());
+ }
+ else if (o1.isFolder()) {
+ return -1;
+ } else if (o2.isFolder()) {
+ return 1;
+ } else if (o1.getModificationTimestamp() == 0 || o2.getModificationTimestamp() == 0){
+ return 0;
+ } else {
+ Long obj1 = o1.getModificationTimestamp();
+ return val * obj1.compareTo(o2.getModificationTimestamp());
+ }
+ }
+ });
+
+ return files;
+ }
+
+// /**
+// * Sorts list by Size
+// * @param sortAscending true: ascending, false: descending
+// */
+// public static Vector<OCFile> sortBySize(Vector<OCFile> files){
+// final Integer val;
+// if (mSortAscending){
+// val = 1;
+// } else {
+// val = -1;
+// }
+//
+// Collections.sort(files, new Comparator<OCFile>() {
+// public int compare(OCFile o1, OCFile o2) {
+// if (o1.isFolder() && o2.isFolder()) {
+// Long obj1 = getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o1)));
+// return val * obj1.compareTo(getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o2))));
+// }
+// else if (o1.isFolder()) {
+// return -1;
+// } else if (o2.isFolder()) {
+// return 1;
+// } else if (o1.getFileLength() == 0 || o2.getFileLength() == 0){
+// return 0;
+// } else {
+// Long obj1 = o1.getFileLength();
+// return val * obj1.compareTo(o2.getFileLength());
+// }
+// }
+// });
+//
+// return files;
+// }
+
+ /**
+ * Sorts list by Name
+ * @param files files to sort
+ */
+ public static Vector<OCFile> sortByName(Vector<OCFile> files){
+ final Integer val;
+ if (mSortAscending){
+ val = 1;
+ } else {
+ val = -1;
+ }
+
+ Collections.sort(files, new Comparator<OCFile>() {
+ public int compare(OCFile o1, OCFile o2) {
+ if (o1.isFolder() && o2.isFolder()) {
+ return val * o1.getRemotePath().toLowerCase().compareTo(o2.getRemotePath().toLowerCase());
+ } else if (o1.isFolder()) {
+ return -1;
+ } else if (o2.isFolder()) {
+ return 1;
+ }
+ return val * new AlphanumComparator().compare(o1, o2);
+ }
+ });
+
+ return files;
+ }
+
+ /**
+ * Local Folder size
+ * @param dir File
+ * @return Size in bytes
+ */
+ public static long getFolderSize(File dir) {
+ if (dir.exists()) {
+ long result = 0;
+ File[] fileList = dir.listFiles();
+ for(int i = 0; i < fileList.length; i++) {
+ if(fileList[i].isDirectory()) {
+ result += getFolderSize(fileList[i]);
+ } else {
+ result += fileList[i].length();
+ }
+ }
+ return result;
+ }
+ return 0;
+ }
+
+ /**
+ * Mimetype String of a file
+ * @param path
+ * @return
+ */
+ public static String getMimeTypeFromName(String path) {
+ String extension = "";
+ int pos = path.lastIndexOf('.');
+ if (pos >= 0) {
+ extension = path.substring(pos + 1);
+ }
+ String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
+ return (result != null) ? result : "";
+ }
}
-/* ownCloud Android client application\r
+/**\r
+ * ownCloud Android client application\r
+ *\r
+ * @author Bartek Przybylski\r
* Copyright (C) 2011 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
+ * Copyright (C) 2015 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
\r
/**\r
* Represents a session to an ownCloud instance\r
- * \r
- * @author Bartek Przybylski\r
- * \r
*/\r
public class OwnCloudSession {\r
private String mSessionName;\r
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
+++ /dev/null
-/*
- * TouchImageView.java
- * By: Michael Ortiz
- * Updated By: Patrick Lackemacher
- * Updated By: Babay88
- * Updated By: @ipsilondev
- * Updated By: hank-cp
- * Updated By: singpolyma
- * -------------------
- * Extends Android ImageView to include pinch zooming, panning, fling and double tap zoom.
- */
-
-package com.owncloud.android.utils;
-
-import com.owncloud.android.ui.preview.ImageViewCustom;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.View;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.widget.OverScroller;
-import android.widget.Scroller;
-
-public class TouchImageViewCustom extends ImageViewCustom {
- private static final String DEBUG = "DEBUG";
-
- //
- // SuperMin and SuperMax multipliers. Determine how much the image can be
- // zoomed below or above the zoom boundaries, before animating back to the
- // min/max zoom boundary.
- //
- private static final float SUPER_MIN_MULTIPLIER = .75f;
- private static final float SUPER_MAX_MULTIPLIER = 1.25f;
-
- //
- // Scale of image ranges from minScale to maxScale, where minScale == 1
- // when the image is stretched to fit view.
- //
- private float normalizedScale;
-
- //
- // Matrix applied to image. MSCALE_X and MSCALE_Y should always be equal.
- // MTRANS_X and MTRANS_Y are the other values used. prevMatrix is the matrix
- // saved prior to the screen rotating.
- //
- private Matrix matrix, prevMatrix;
-
- private static enum State { NONE, DRAG, ZOOM, FLING, ANIMATE_ZOOM };
- private State state;
-
- private float minScale;
- private float maxScale;
- private float superMinScale;
- private float superMaxScale;
- private float[] m;
-
- private Context context;
- private Fling fling;
-
- private ScaleType mScaleType;
-
- private boolean imageRenderedAtLeastOnce;
- private boolean onDrawReady;
-
- private ZoomVariables delayedZoomVariables;
-
- //
- // Size of view and previous view size (ie before rotation)
- //
- private int viewWidth, viewHeight, prevViewWidth, prevViewHeight;
-
- //
- // Size of image when it is stretched to fit view. Before and After rotation.
- //
- private float matchViewWidth, matchViewHeight, prevMatchViewWidth, prevMatchViewHeight;
-
- private ScaleGestureDetector mScaleDetector;
- private GestureDetector mGestureDetector;
- private GestureDetector.OnDoubleTapListener doubleTapListener = null;
- private OnTouchListener userTouchListener = null;
- private OnTouchImageViewListener touchImageViewListener = null;
-
- public TouchImageViewCustom(Context context) {
- super(context);
- sharedConstructing(context);
- }
-
- public TouchImageViewCustom(Context context, AttributeSet attrs) {
- super(context, attrs);
- sharedConstructing(context);
- }
-
- public TouchImageViewCustom(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- sharedConstructing(context);
- }
-
- private void sharedConstructing(Context context) {
- super.setClickable(true);
- this.context = context;
- mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
- mGestureDetector = new GestureDetector(context, new GestureListener());
- matrix = new Matrix();
- prevMatrix = new Matrix();
- m = new float[9];
- normalizedScale = 1;
- if (mScaleType == null) {
- mScaleType = ScaleType.FIT_CENTER;
- }
- minScale = 1;
- maxScale = 3;
- superMinScale = SUPER_MIN_MULTIPLIER * minScale;
- superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
- setImageMatrix(matrix);
- setScaleType(ScaleType.MATRIX);
- setState(State.NONE);
- onDrawReady = false;
- super.setOnTouchListener(new PrivateOnTouchListener());
- }
-
- @Override
- public void setOnTouchListener(View.OnTouchListener l) {
- userTouchListener = l;
- }
-
- public void setOnTouchImageViewListener(OnTouchImageViewListener l) {
- touchImageViewListener = l;
- }
-
- public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener l) {
- doubleTapListener = l;
- }
-
- @Override
- public void setImageResource(int resId) {
- super.setImageResource(resId);
- savePreviousImageValues();
- fitImageToView();
- }
-
- @Override
- public void setImageBitmap(Bitmap bm) {
- super.setImageBitmap(bm);
- savePreviousImageValues();
- fitImageToView();
- }
-
- @Override
- public void setImageDrawable(Drawable drawable) {
- super.setImageDrawable(drawable);
- savePreviousImageValues();
- fitImageToView();
- }
-
- @Override
- public void setImageURI(Uri uri) {
- super.setImageURI(uri);
- savePreviousImageValues();
- fitImageToView();
- }
-
- @Override
- public void setScaleType(ScaleType type) {
- if (type == ScaleType.FIT_START || type == ScaleType.FIT_END) {
- throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END");
- }
- if (type == ScaleType.MATRIX) {
- super.setScaleType(ScaleType.MATRIX);
-
- } else {
- mScaleType = type;
- if (onDrawReady) {
- //
- // If the image is already rendered, scaleType has been called programmatically
- // and the TouchImageView should be updated with the new scaleType.
- //
- setZoom(this);
- }
- }
- }
-
- @Override
- public ScaleType getScaleType() {
- return mScaleType;
- }
-
- /**
- * Returns false if image is in initial, unzoomed state. False, otherwise.
- * @return true if image is zoomed
- */
- public boolean isZoomed() {
- return normalizedScale != 1;
- }
-
- /**
- * Return a Rect representing the zoomed image.
- * @return rect representing zoomed image
- */
- public RectF getZoomedRect() {
- if (mScaleType == ScaleType.FIT_XY) {
- throw new UnsupportedOperationException("getZoomedRect() not supported with FIT_XY");
- }
- PointF topLeft = transformCoordTouchToBitmap(0, 0, true);
- PointF bottomRight = transformCoordTouchToBitmap(viewWidth, viewHeight, true);
-
- float w = getDrawable().getIntrinsicWidth();
- float h = getDrawable().getIntrinsicHeight();
- return new RectF(topLeft.x / w, topLeft.y / h, bottomRight.x / w, bottomRight.y / h);
- }
-
- /**
- * Save the current matrix and view dimensions
- * in the prevMatrix and prevView variables.
- */
- private void savePreviousImageValues() {
- if (matrix != null && viewHeight != 0 && viewWidth != 0) {
- matrix.getValues(m);
- prevMatrix.setValues(m);
- prevMatchViewHeight = matchViewHeight;
- prevMatchViewWidth = matchViewWidth;
- prevViewHeight = viewHeight;
- prevViewWidth = viewWidth;
- }
- }
-
- @Override
- public Parcelable onSaveInstanceState() {
- Bundle bundle = new Bundle();
- bundle.putParcelable("instanceState", super.onSaveInstanceState());
- bundle.putFloat("saveScale", normalizedScale);
- bundle.putFloat("matchViewHeight", matchViewHeight);
- bundle.putFloat("matchViewWidth", matchViewWidth);
- bundle.putInt("viewWidth", viewWidth);
- bundle.putInt("viewHeight", viewHeight);
- matrix.getValues(m);
- bundle.putFloatArray("matrix", m);
- bundle.putBoolean("imageRendered", imageRenderedAtLeastOnce);
- return bundle;
- }
-
- @Override
- public void onRestoreInstanceState(Parcelable state) {
- if (state instanceof Bundle) {
- Bundle bundle = (Bundle) state;
- normalizedScale = bundle.getFloat("saveScale");
- m = bundle.getFloatArray("matrix");
- prevMatrix.setValues(m);
- prevMatchViewHeight = bundle.getFloat("matchViewHeight");
- prevMatchViewWidth = bundle.getFloat("matchViewWidth");
- prevViewHeight = bundle.getInt("viewHeight");
- prevViewWidth = bundle.getInt("viewWidth");
- imageRenderedAtLeastOnce = bundle.getBoolean("imageRendered");
- super.onRestoreInstanceState(bundle.getParcelable("instanceState"));
- return;
- }
-
- super.onRestoreInstanceState(state);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- onDrawReady = true;
- imageRenderedAtLeastOnce = true;
- if (delayedZoomVariables != null) {
- setZoom(delayedZoomVariables.scale, delayedZoomVariables.focusX, delayedZoomVariables.focusY, delayedZoomVariables.scaleType);
- delayedZoomVariables = null;
- }
- super.onDraw(canvas);
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- savePreviousImageValues();
- }
-
- /**
- * Get the max zoom multiplier.
- * @return max zoom multiplier.
- */
- public float getMaxZoom() {
- return maxScale;
- }
-
- /**
- * Set the max zoom multiplier. Default value: 3.
- * @param max max zoom multiplier.
- */
- public void setMaxZoom(float max) {
- maxScale = max;
- superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
- }
-
- /**
- * Get the min zoom multiplier.
- * @return min zoom multiplier.
- */
- public float getMinZoom() {
- return minScale;
- }
-
- /**
- * Get the current zoom. This is the zoom relative to the initial
- * scale, not the original resource.
- * @return current zoom multiplier.
- */
- public float getCurrentZoom() {
- return normalizedScale;
- }
-
- /**
- * Set the min zoom multiplier. Default value: 1.
- * @param min min zoom multiplier.
- */
- public void setMinZoom(float min) {
- minScale = min;
- superMinScale = SUPER_MIN_MULTIPLIER * minScale;
- }
-
- /**
- * Reset zoom and translation to initial state.
- */
- public void resetZoom() {
- normalizedScale = 1;
- fitImageToView();
- }
-
- /**
- * Set zoom to the specified scale. Image will be centered by default.
- * @param scale
- */
- public void setZoom(float scale) {
- setZoom(scale, 0.5f, 0.5f);
- }
-
- /**
- * Set zoom to the specified scale. Image will be centered around the point
- * (focusX, focusY). These floats range from 0 to 1 and denote the focus point
- * as a fraction from the left and top of the view. For example, the top left
- * corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
- * @param scale
- * @param focusX
- * @param focusY
- */
- public void setZoom(float scale, float focusX, float focusY) {
- setZoom(scale, focusX, focusY, mScaleType);
- }
-
- /**
- * Set zoom to the specified scale. Image will be centered around the point
- * (focusX, focusY). These floats range from 0 to 1 and denote the focus point
- * as a fraction from the left and top of the view. For example, the top left
- * corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
- * @param scale
- * @param focusX
- * @param focusY
- * @param scaleType
- */
- public void setZoom(float scale, float focusX, float focusY, ScaleType scaleType) {
- //
- // setZoom can be called before the image is on the screen, but at this point,
- // image and view sizes have not yet been calculated in onMeasure. Thus, we should
- // delay calling setZoom until the view has been measured.
- //
- if (!onDrawReady) {
- delayedZoomVariables = new ZoomVariables(scale, focusX, focusY, scaleType);
- return;
- }
-
- if (scaleType != mScaleType) {
- setScaleType(scaleType);
- }
- resetZoom();
- scaleImage(scale, viewWidth / 2, viewHeight / 2, true);
- matrix.getValues(m);
- m[Matrix.MTRANS_X] = -((focusX * getImageWidth()) - (viewWidth * 0.5f));
- m[Matrix.MTRANS_Y] = -((focusY * getImageHeight()) - (viewHeight * 0.5f));
- matrix.setValues(m);
- fixTrans();
- setImageMatrix(matrix);
- }
-
- /**
- * Set zoom parameters equal to another TouchImageView. Including scale, position,
- * and ScaleType.
- * @param TouchImageView
- */
- public void setZoom(TouchImageViewCustom img) {
- PointF center = img.getScrollPosition();
- setZoom(img.getCurrentZoom(), center.x, center.y, img.getScaleType());
- }
-
- /**
- * Return the point at the center of the zoomed image. The PointF coordinates range
- * in value between 0 and 1 and the focus point is denoted as a fraction from the left
- * and top of the view. For example, the top left corner of the image would be (0, 0).
- * And the bottom right corner would be (1, 1).
- * @return PointF representing the scroll position of the zoomed image.
- */
- public PointF getScrollPosition() {
- Drawable drawable = getDrawable();
- if (drawable == null) {
- return null;
- }
- int drawableWidth = drawable.getIntrinsicWidth();
- int drawableHeight = drawable.getIntrinsicHeight();
-
- PointF point = transformCoordTouchToBitmap(viewWidth / 2, viewHeight / 2, true);
- point.x /= drawableWidth;
- point.y /= drawableHeight;
- return point;
- }
-
- /**
- * Set the focus point of the zoomed image. The focus points are denoted as a fraction from the
- * left and top of the view. The focus points can range in value between 0 and 1.
- * @param focusX
- * @param focusY
- */
- public void setScrollPosition(float focusX, float focusY) {
- setZoom(normalizedScale, focusX, focusY);
- }
-
- /**
- * Performs boundary checking and fixes the image matrix if it
- * is out of bounds.
- */
- private void fixTrans() {
- matrix.getValues(m);
- float transX = m[Matrix.MTRANS_X];
- float transY = m[Matrix.MTRANS_Y];
-
- float fixTransX = getFixTrans(transX, viewWidth, getImageWidth());
- float fixTransY = getFixTrans(transY, viewHeight, getImageHeight());
-
- if (fixTransX != 0 || fixTransY != 0) {
- matrix.postTranslate(fixTransX, fixTransY);
- }
- }
-
- /**
- * When transitioning from zooming from focus to zoom from center (or vice versa)
- * the image can become unaligned within the view. This is apparent when zooming
- * quickly. When the content size is less than the view size, the content will often
- * be centered incorrectly within the view. fixScaleTrans first calls fixTrans() and
- * then makes sure the image is centered correctly within the view.
- */
- private void fixScaleTrans() {
- fixTrans();
- matrix.getValues(m);
- if (getImageWidth() < viewWidth) {
- m[Matrix.MTRANS_X] = (viewWidth - getImageWidth()) / 2;
- }
-
- if (getImageHeight() < viewHeight) {
- m[Matrix.MTRANS_Y] = (viewHeight - getImageHeight()) / 2;
- }
- matrix.setValues(m);
- }
-
- private float getFixTrans(float trans, float viewSize, float contentSize) {
- float minTrans, maxTrans;
-
- if (contentSize <= viewSize) {
- minTrans = 0;
- maxTrans = viewSize - contentSize;
-
- } else {
- minTrans = viewSize - contentSize;
- maxTrans = 0;
- }
-
- if (trans < minTrans)
- return -trans + minTrans;
- if (trans > maxTrans)
- return -trans + maxTrans;
- return 0;
- }
-
- private float getFixDragTrans(float delta, float viewSize, float contentSize) {
- if (contentSize <= viewSize) {
- return 0;
- }
- return delta;
- }
-
- private float getImageWidth() {
- return matchViewWidth * normalizedScale;
- }
-
- private float getImageHeight() {
- return matchViewHeight * normalizedScale;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- Drawable drawable = getDrawable();
- if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) {
- setMeasuredDimension(0, 0);
- return;
- }
-
- int drawableWidth = drawable.getIntrinsicWidth();
- int drawableHeight = drawable.getIntrinsicHeight();
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- viewWidth = setViewSize(widthMode, widthSize, drawableWidth);
- viewHeight = setViewSize(heightMode, heightSize, drawableHeight);
-
- //
- // Set view dimensions
- //
- setMeasuredDimension(viewWidth, viewHeight);
-
- //
- // Fit content within view
- //
- fitImageToView();
- }
-
- /**
- * If the normalizedScale is equal to 1, then the image is made to fit the screen. Otherwise,
- * it is made to fit the screen according to the dimensions of the previous image matrix. This
- * allows the image to maintain its zoom after rotation.
- */
- private void fitImageToView() {
- Drawable drawable = getDrawable();
- if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) {
- return;
- }
- if (matrix == null || prevMatrix == null) {
- return;
- }
-
- int drawableWidth = drawable.getIntrinsicWidth();
- int drawableHeight = drawable.getIntrinsicHeight();
-
- //
- // Scale image for view
- //
- float scaleX = (float) viewWidth / drawableWidth;
- float scaleY = (float) viewHeight / drawableHeight;
-
- switch (mScaleType) {
- case CENTER:
- scaleX = scaleY = 1;
- break;
-
- case CENTER_CROP:
- scaleX = scaleY = Math.max(scaleX, scaleY);
- break;
-
- case CENTER_INSIDE:
- scaleX = scaleY = Math.min(1, Math.min(scaleX, scaleY));
-
- case FIT_CENTER:
- scaleX = scaleY = Math.min(scaleX, scaleY);
- break;
-
- case FIT_XY:
- break;
-
- default:
- //
- // FIT_START and FIT_END not supported
- //
- throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END");
-
- }
-
- //
- // Center the image
- //
- float redundantXSpace = viewWidth - (scaleX * drawableWidth);
- float redundantYSpace = viewHeight - (scaleY * drawableHeight);
- matchViewWidth = viewWidth - redundantXSpace;
- matchViewHeight = viewHeight - redundantYSpace;
- if (!isZoomed() && !imageRenderedAtLeastOnce) {
- //
- // Stretch and center image to fit view
- //
- matrix.setScale(scaleX, scaleY);
- matrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2);
- normalizedScale = 1;
-
- } else {
- //
- // These values should never be 0 or we will set viewWidth and viewHeight
- // to NaN in translateMatrixAfterRotate. To avoid this, call savePreviousImageValues
- // to set them equal to the current values.
- //
- if (prevMatchViewWidth == 0 || prevMatchViewHeight == 0) {
- savePreviousImageValues();
- }
-
- prevMatrix.getValues(m);
-
- //
- // Rescale Matrix after rotation
- //
- m[Matrix.MSCALE_X] = matchViewWidth / drawableWidth * normalizedScale;
- m[Matrix.MSCALE_Y] = matchViewHeight / drawableHeight * normalizedScale;
-
- //
- // TransX and TransY from previous matrix
- //
- float transX = m[Matrix.MTRANS_X];
- float transY = m[Matrix.MTRANS_Y];
-
- //
- // Width
- //
- float prevActualWidth = prevMatchViewWidth * normalizedScale;
- float actualWidth = getImageWidth();
- translateMatrixAfterRotate(Matrix.MTRANS_X, transX, prevActualWidth, actualWidth, prevViewWidth, viewWidth, drawableWidth);
-
- //
- // Height
- //
- float prevActualHeight = prevMatchViewHeight * normalizedScale;
- float actualHeight = getImageHeight();
- translateMatrixAfterRotate(Matrix.MTRANS_Y, transY, prevActualHeight, actualHeight, prevViewHeight, viewHeight, drawableHeight);
-
- //
- // Set the matrix to the adjusted scale and translate values.
- //
- matrix.setValues(m);
- }
- fixTrans();
- setImageMatrix(matrix);
- }
-
- /**
- * Set view dimensions based on layout params
- *
- * @param mode
- * @param size
- * @param drawableWidth
- * @return
- */
- private int setViewSize(int mode, int size, int drawableWidth) {
- int viewSize;
- switch (mode) {
- case MeasureSpec.EXACTLY:
- viewSize = size;
- break;
-
- case MeasureSpec.AT_MOST:
- viewSize = Math.min(drawableWidth, size);
- break;
-
- case MeasureSpec.UNSPECIFIED:
- viewSize = drawableWidth;
- break;
-
- default:
- viewSize = size;
- break;
- }
- return viewSize;
- }
-
- /**
- * After rotating, the matrix needs to be translated. This function finds the area of image
- * which was previously centered and adjusts translations so that is again the center, post-rotation.
- *
- * @param axis Matrix.MTRANS_X or Matrix.MTRANS_Y
- * @param trans the value of trans in that axis before the rotation
- * @param prevImageSize the width/height of the image before the rotation
- * @param imageSize width/height of the image after rotation
- * @param prevViewSize width/height of view before rotation
- * @param viewSize width/height of view after rotation
- * @param drawableSize width/height of drawable
- */
- private void translateMatrixAfterRotate(int axis, float trans, float prevImageSize, float imageSize, int prevViewSize, int viewSize, int drawableSize) {
- if (imageSize < viewSize) {
- //
- // The width/height of image is less than the view's width/height. Center it.
- //
- m[axis] = (viewSize - (drawableSize * m[Matrix.MSCALE_X])) * 0.5f;
-
- } else if (trans > 0) {
- //
- // The image is larger than the view, but was not before rotation. Center it.
- //
- m[axis] = -((imageSize - viewSize) * 0.5f);
-
- } else {
- //
- // Find the area of the image which was previously centered in the view. Determine its distance
- // from the left/top side of the view as a fraction of the entire image's width/height. Use that percentage
- // to calculate the trans in the new view width/height.
- //
- float percentage = (Math.abs(trans) + (0.5f * prevViewSize)) / prevImageSize;
- m[axis] = -((percentage * imageSize) - (viewSize * 0.5f));
- }
- }
-
- private void setState(State state) {
- this.state = state;
- }
-
- public boolean canScrollHorizontallyFroyo(int direction) {
- return canScrollHorizontally(direction);
- }
-
- @Override
- public boolean canScrollHorizontally(int direction) {
- matrix.getValues(m);
- float x = m[Matrix.MTRANS_X];
-
- if (getImageWidth() < viewWidth) {
- return false;
-
- } else if (x >= -1 && direction < 0) {
- return false;
-
- } else if (Math.abs(x) + viewWidth + 1 >= getImageWidth() && direction > 0) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Gesture Listener detects a single click or long click and passes that on
- * to the view's listener.
- * @author Ortiz
- *
- */
- private class GestureListener extends GestureDetector.SimpleOnGestureListener {
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e)
- {
- if(doubleTapListener != null) {
- return doubleTapListener.onSingleTapConfirmed(e);
- }
- return performClick();
- }
-
- @Override
- public void onLongPress(MotionEvent e)
- {
- performLongClick();
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
- {
- if (fling != null) {
- //
- // If a previous fling is still active, it should be cancelled so that two flings
- // are not run simultaenously.
- //
- fling.cancelFling();
- }
- fling = new Fling((int) velocityX, (int) velocityY);
- compatPostOnAnimation(fling);
- return super.onFling(e1, e2, velocityX, velocityY);
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- boolean consumed = false;
- if(doubleTapListener != null) {
- consumed = doubleTapListener.onDoubleTap(e);
- }
- if (state == State.NONE) {
- float targetZoom = (normalizedScale == minScale) ? maxScale : minScale;
- DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, e.getX(), e.getY(), false);
- compatPostOnAnimation(doubleTap);
- consumed = true;
- }
- return consumed;
- }
-
- @Override
- public boolean onDoubleTapEvent(MotionEvent e) {
- if(doubleTapListener != null) {
- return doubleTapListener.onDoubleTapEvent(e);
- }
- return false;
- }
- }
-
- public interface OnTouchImageViewListener {
- public void onMove();
- }
-
- /**
- * Responsible for all touch events. Handles the heavy lifting of drag and also sends
- * touch events to Scale Detector and Gesture Detector.
- * @author Ortiz
- *
- */
- private class PrivateOnTouchListener implements OnTouchListener {
-
- //
- // Remember last point position for dragging
- //
- private PointF last = new PointF();
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- mScaleDetector.onTouchEvent(event);
- mGestureDetector.onTouchEvent(event);
- PointF curr = new PointF(event.getX(), event.getY());
-
- if (state == State.NONE || state == State.DRAG || state == State.FLING) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- last.set(curr);
- if (fling != null)
- fling.cancelFling();
- setState(State.DRAG);
- break;
-
- case MotionEvent.ACTION_MOVE:
- if (state == State.DRAG) {
- float deltaX = curr.x - last.x;
- float deltaY = curr.y - last.y;
- float fixTransX = getFixDragTrans(deltaX, viewWidth, getImageWidth());
- float fixTransY = getFixDragTrans(deltaY, viewHeight, getImageHeight());
- matrix.postTranslate(fixTransX, fixTransY);
- fixTrans();
- last.set(curr.x, curr.y);
- }
- break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP:
- setState(State.NONE);
- break;
- }
- }
-
- setImageMatrix(matrix);
-
- //
- // User-defined OnTouchListener
- //
- if(userTouchListener != null) {
- userTouchListener.onTouch(v, event);
- }
-
- //
- // OnTouchImageViewListener is set: TouchImageView dragged by user.
- //
- if (touchImageViewListener != null) {
- touchImageViewListener.onMove();
- }
-
- //
- // indicate event was handled
- //
- return true;
- }
- }
-
- /**
- * ScaleListener detects user two finger scaling and scales image.
- * @author Ortiz
- *
- */
- private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
- @Override
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- setState(State.ZOOM);
- return true;
- }
-
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
- scaleImage(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY(), true);
-
- //
- // OnTouchImageViewListener is set: TouchImageView pinch zoomed by user.
- //
- if (touchImageViewListener != null) {
- touchImageViewListener.onMove();
- }
- return true;
- }
-
- @Override
- public void onScaleEnd(ScaleGestureDetector detector) {
- super.onScaleEnd(detector);
- setState(State.NONE);
- boolean animateToZoomBoundary = false;
- float targetZoom = normalizedScale;
- if (normalizedScale > maxScale) {
- targetZoom = maxScale;
- animateToZoomBoundary = true;
-
- } else if (normalizedScale < minScale) {
- targetZoom = minScale;
- animateToZoomBoundary = true;
- }
-
- if (animateToZoomBoundary) {
- DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, viewWidth / 2, viewHeight / 2, true);
- compatPostOnAnimation(doubleTap);
- }
- }
- }
-
- private void scaleImage(double deltaScale, float focusX, float focusY, boolean stretchImageToSuper) {
-
- float lowerScale, upperScale;
- if (stretchImageToSuper) {
- lowerScale = superMinScale;
- upperScale = superMaxScale;
-
- } else {
- lowerScale = minScale;
- upperScale = maxScale;
- }
-
- float origScale = normalizedScale;
- normalizedScale *= deltaScale;
- if (normalizedScale > upperScale) {
- normalizedScale = upperScale;
- deltaScale = upperScale / origScale;
- } else if (normalizedScale < lowerScale) {
- normalizedScale = lowerScale;
- deltaScale = lowerScale / origScale;
- }
-
- matrix.postScale((float) deltaScale, (float) deltaScale, focusX, focusY);
- fixScaleTrans();
- }
-
- /**
- * DoubleTapZoom calls a series of runnables which apply
- * an animated zoom in/out graphic to the image.
- * @author Ortiz
- *
- */
- private class DoubleTapZoom implements Runnable {
-
- private long startTime;
- private static final float ZOOM_TIME = 500;
- private float startZoom, targetZoom;
- private float bitmapX, bitmapY;
- private boolean stretchImageToSuper;
- private AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
- private PointF startTouch;
- private PointF endTouch;
-
- DoubleTapZoom(float targetZoom, float focusX, float focusY, boolean stretchImageToSuper) {
- setState(State.ANIMATE_ZOOM);
- startTime = System.currentTimeMillis();
- this.startZoom = normalizedScale;
- this.targetZoom = targetZoom;
- this.stretchImageToSuper = stretchImageToSuper;
- PointF bitmapPoint = transformCoordTouchToBitmap(focusX, focusY, false);
- this.bitmapX = bitmapPoint.x;
- this.bitmapY = bitmapPoint.y;
-
- //
- // Used for translating image during scaling
- //
- startTouch = transformCoordBitmapToTouch(bitmapX, bitmapY);
- endTouch = new PointF(viewWidth / 2, viewHeight / 2);
- }
-
- @Override
- public void run() {
- float t = interpolate();
- double deltaScale = calculateDeltaScale(t);
- scaleImage(deltaScale, bitmapX, bitmapY, stretchImageToSuper);
- translateImageToCenterTouchPosition(t);
- fixScaleTrans();
- setImageMatrix(matrix);
-
- //
- // OnTouchImageViewListener is set: double tap runnable updates listener
- // with every frame.
- //
- if (touchImageViewListener != null) {
- touchImageViewListener.onMove();
- }
-
- if (t < 1f) {
- //
- // We haven't finished zooming
- //
- compatPostOnAnimation(this);
-
- } else {
- //
- // Finished zooming
- //
- setState(State.NONE);
- }
- }
-
- /**
- * Interpolate between where the image should start and end in order to translate
- * the image so that the point that is touched is what ends up centered at the end
- * of the zoom.
- * @param t
- */
- private void translateImageToCenterTouchPosition(float t) {
- float targetX = startTouch.x + t * (endTouch.x - startTouch.x);
- float targetY = startTouch.y + t * (endTouch.y - startTouch.y);
- PointF curr = transformCoordBitmapToTouch(bitmapX, bitmapY);
- matrix.postTranslate(targetX - curr.x, targetY - curr.y);
- }
-
- /**
- * Use interpolator to get t
- * @return
- */
- private float interpolate() {
- long currTime = System.currentTimeMillis();
- float elapsed = (currTime - startTime) / ZOOM_TIME;
- elapsed = Math.min(1f, elapsed);
- return interpolator.getInterpolation(elapsed);
- }
-
- /**
- * Interpolate the current targeted zoom and get the delta
- * from the current zoom.
- * @param t
- * @return
- */
- private double calculateDeltaScale(float t) {
- double zoom = startZoom + t * (targetZoom - startZoom);
- return zoom / normalizedScale;
- }
- }
-
- /**
- * This function will transform the coordinates in the touch event to the coordinate
- * system of the drawable that the imageview contain
- * @param x x-coordinate of touch event
- * @param y y-coordinate of touch event
- * @param clipToBitmap Touch event may occur within view, but outside image content. True, to clip return value
- * to the bounds of the bitmap size.
- * @return Coordinates of the point touched, in the coordinate system of the original drawable.
- */
- private PointF transformCoordTouchToBitmap(float x, float y, boolean clipToBitmap) {
- matrix.getValues(m);
- float origW = getDrawable().getIntrinsicWidth();
- float origH = getDrawable().getIntrinsicHeight();
- float transX = m[Matrix.MTRANS_X];
- float transY = m[Matrix.MTRANS_Y];
- float finalX = ((x - transX) * origW) / getImageWidth();
- float finalY = ((y - transY) * origH) / getImageHeight();
-
- if (clipToBitmap) {
- finalX = Math.min(Math.max(finalX, 0), origW);
- finalY = Math.min(Math.max(finalY, 0), origH);
- }
-
- return new PointF(finalX , finalY);
- }
-
- /**
- * Inverse of transformCoordTouchToBitmap. This function will transform the coordinates in the
- * drawable's coordinate system to the view's coordinate system.
- * @param bx x-coordinate in original bitmap coordinate system
- * @param by y-coordinate in original bitmap coordinate system
- * @return Coordinates of the point in the view's coordinate system.
- */
- private PointF transformCoordBitmapToTouch(float bx, float by) {
- matrix.getValues(m);
- float origW = getDrawable().getIntrinsicWidth();
- float origH = getDrawable().getIntrinsicHeight();
- float px = bx / origW;
- float py = by / origH;
- float finalX = m[Matrix.MTRANS_X] + getImageWidth() * px;
- float finalY = m[Matrix.MTRANS_Y] + getImageHeight() * py;
- return new PointF(finalX , finalY);
- }
-
- /**
- * Fling launches sequential runnables which apply
- * the fling graphic to the image. The values for the translation
- * are interpolated by the Scroller.
- * @author Ortiz
- *
- */
- private class Fling implements Runnable {
-
- CompatScroller scroller;
- int currX, currY;
-
- Fling(int velocityX, int velocityY) {
- setState(State.FLING);
- scroller = new CompatScroller(context);
- matrix.getValues(m);
-
- int startX = (int) m[Matrix.MTRANS_X];
- int startY = (int) m[Matrix.MTRANS_Y];
- int minX, maxX, minY, maxY;
-
- if (getImageWidth() > viewWidth) {
- minX = viewWidth - (int) getImageWidth();
- maxX = 0;
-
- } else {
- minX = maxX = startX;
- }
-
- if (getImageHeight() > viewHeight) {
- minY = viewHeight - (int) getImageHeight();
- maxY = 0;
-
- } else {
- minY = maxY = startY;
- }
-
- scroller.fling(startX, startY, (int) velocityX, (int) velocityY, minX,
- maxX, minY, maxY);
- currX = startX;
- currY = startY;
- }
-
- public void cancelFling() {
- if (scroller != null) {
- setState(State.NONE);
- scroller.forceFinished(true);
- }
- }
-
- @Override
- public void run() {
-
- //
- // OnTouchImageViewListener is set: TouchImageView listener has been flung by user.
- // Listener runnable updated with each frame of fling animation.
- //
- if (touchImageViewListener != null) {
- touchImageViewListener.onMove();
- }
-
- if (scroller.isFinished()) {
- scroller = null;
- return;
- }
-
- if (scroller.computeScrollOffset()) {
- int newX = scroller.getCurrX();
- int newY = scroller.getCurrY();
- int transX = newX - currX;
- int transY = newY - currY;
- currX = newX;
- currY = newY;
- matrix.postTranslate(transX, transY);
- fixTrans();
- setImageMatrix(matrix);
- compatPostOnAnimation(this);
- }
- }
- }
-
- @TargetApi(Build.VERSION_CODES.GINGERBREAD)
- private class CompatScroller {
- Scroller scroller;
- OverScroller overScroller;
- boolean isPreGingerbread;
-
- public CompatScroller(Context context) {
- if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
- isPreGingerbread = true;
- scroller = new Scroller(context);
-
- } else {
- isPreGingerbread = false;
- overScroller = new OverScroller(context);
- }
- }
-
- public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) {
- if (isPreGingerbread) {
- scroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
- } else {
- overScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
- }
- }
-
- public void forceFinished(boolean finished) {
- if (isPreGingerbread) {
- scroller.forceFinished(finished);
- } else {
- overScroller.forceFinished(finished);
- }
- }
-
- public boolean isFinished() {
- if (isPreGingerbread) {
- return scroller.isFinished();
- } else {
- return overScroller.isFinished();
- }
- }
-
- public boolean computeScrollOffset() {
- if (isPreGingerbread) {
- return scroller.computeScrollOffset();
- } else {
- overScroller.computeScrollOffset();
- return overScroller.computeScrollOffset();
- }
- }
-
- public int getCurrX() {
- if (isPreGingerbread) {
- return scroller.getCurrX();
- } else {
- return overScroller.getCurrX();
- }
- }
-
- public int getCurrY() {
- if (isPreGingerbread) {
- return scroller.getCurrY();
- } else {
- return overScroller.getCurrY();
- }
- }
- }
-
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
- private void compatPostOnAnimation(Runnable runnable) {
- if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
- postOnAnimation(runnable);
-
- } else {
- postDelayed(runnable, 1000/60);
- }
- }
-
- private class ZoomVariables {
- public float scale;
- public float focusX;
- public float focusY;
- public ScaleType scaleType;
-
- public ZoomVariables(float scale, float focusX, float focusY, ScaleType scaleType) {
- this.scale = scale;
- this.focusX = focusX;
- this.focusY = focusY;
- this.scaleType = scaleType;
- }
- }
-
- private void printMatrixInfo() {
- float[] n = new float[9];
- matrix.getValues(n);
- Log.d(DEBUG, "Scale: " + n[Matrix.MSCALE_X] + " TransX: " + n[Matrix.MTRANS_X] + " TransY: " + n[Matrix.MTRANS_Y]);
- }
-}
\ No newline at end of file
-/* ownCloud Android client application
- * Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
package com.owncloud.android.utils;
+import android.annotation.TargetApi;
+import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.provider.OpenableColumns;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+import java.io.File;
/**
* A helper class for some Uri operations.
*/
public class UriUtils {
-
+
+ public static final String TAG = UriUtils.class.getSimpleName();
+
public static final String URI_CONTENT_SCHEME = "content://";
public static boolean isContentDocument(Uri uri) {
return uri.toString().startsWith(URI_CONTENT_SCHEME);
}
+
+
+ /**
+ * Translates a content:// URI referred to a local file file to a path on the local filesystem
+ *
+ * @param uri The URI to resolve
+ * @return The path in the file system to the content or null if it could not be found (not a file)
+ */
+ @TargetApi(Build.VERSION_CODES.KITKAT)
+ public static String getLocalPath(Uri uri, Context context) {
+ final boolean isKitKatOrLater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+
+ // DocumentProvider
+ if (isKitKatOrLater && DocumentsContract.isDocumentUri(context, uri)) {
+ // ExternalStorageProvider
+ if (UriUtils.isExternalStorageDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ if ("primary".equalsIgnoreCase(type)) {
+ return Environment.getExternalStorageDirectory() + "/" + split[1];
+ }
+ }
+ // DownloadsProvider
+ else if (UriUtils.isDownloadsDocument(uri)) {
+
+ final String id = DocumentsContract.getDocumentId(uri);
+ final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
+ Long.valueOf(id));
+
+ return UriUtils.getDataColumn(context, contentUri, null, null);
+ }
+ // MediaProvider
+ else if (UriUtils.isMediaDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ Uri contentUri = null;
+ if ("image".equals(type)) {
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ } else if ("video".equals(type)) {
+ contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
+ } else if ("audio".equals(type)) {
+ contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+ }
+
+ final String selection = "_id=?";
+ final String[] selectionArgs = new String[] { split[1] };
+
+ return UriUtils.getDataColumn(context, contentUri, selection, selectionArgs);
+ }
+ // Documents providers returned as content://...
+ else if (UriUtils.isContentDocument(uri)) {
+ return uri.toString();
+ }
+ }
+ // MediaStore (and general)
+ else if ("content".equalsIgnoreCase(uri.getScheme())) {
+
+ // Return the remote address
+ if (UriUtils.isGooglePhotosUri(uri))
+ return uri.getLastPathSegment();
+
+ return UriUtils.getDataColumn(context, uri, null, null);
+ }
+ // File
+ else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return uri.getPath();
+ }
+ return null;
+ }
+
}
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
--- /dev/null
+
+/*
+ * Copyright (C) 2013 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.
+ */
+package third_parties.in.srain.cube;
+
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.database.DataSetObservable;
+import android.database.DataSetObserver;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.Filter;
+import android.widget.Filterable;
+import android.widget.FrameLayout;
+import android.widget.GridView;
+import android.widget.ListAdapter;
+import android.widget.WrapperListAdapter;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+
+/**
+ * A {@link android.widget.GridView} that supports adding header rows in a
+ * very similar way to {@link android.widget.ListView}.
+ * See {@link GridViewWithHeaderAndFooter#addHeaderView(View, Object, boolean)}
+ * See {@link GridViewWithHeaderAndFooter#addFooterView(View, Object, boolean)}
+ */
+public class GridViewWithHeaderAndFooter extends GridView {
+
+ public static boolean DEBUG = false;
+
+ /**
+ * A class that represents a fixed view in a list, for example a header at the top
+ * or a footer at the bottom.
+ */
+ private static class FixedViewInfo {
+ /**
+ * The view to add to the grid
+ */
+ public View view;
+ public ViewGroup viewContainer;
+ /**
+ * The data backing the view. This is returned from {@link android.widget.ListAdapter#getItem(int)}.
+ */
+ public Object data;
+ /**
+ * <code>true</code> if the fixed view should be selectable in the grid
+ */
+ public boolean isSelectable;
+ }
+
+ private int mNumColumns = AUTO_FIT;
+ private View mViewForMeasureRowHeight = null;
+ private int mRowHeight = -1;
+ private static final String LOG_TAG = "grid-view-with-header-and-footer";
+
+ private ArrayList<FixedViewInfo> mHeaderViewInfos = new ArrayList<FixedViewInfo>();
+ private ArrayList<FixedViewInfo> mFooterViewInfos = new ArrayList<FixedViewInfo>();
+
+ private void initHeaderGridView() {
+ }
+
+ public GridViewWithHeaderAndFooter(Context context) {
+ super(context);
+ initHeaderGridView();
+ }
+
+ public GridViewWithHeaderAndFooter(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initHeaderGridView();
+ }
+
+ public GridViewWithHeaderAndFooter(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initHeaderGridView();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ ListAdapter adapter = getAdapter();
+ if (adapter != null && adapter instanceof HeaderViewGridAdapter) {
+ ((HeaderViewGridAdapter) adapter).setNumColumns(getNumColumnsCompatible());
+ ((HeaderViewGridAdapter) adapter).setRowHeight(getRowHeight());
+ }
+ }
+
+ @Override
+ public void setClipChildren(boolean clipChildren) {
+ // Ignore, since the header rows depend on not being clipped
+ }
+
+ /**
+ * Do not call this method unless you know how it works.
+ *
+ * @param clipChildren
+ */
+ public void setClipChildrenSupper(boolean clipChildren) {
+ super.setClipChildren(false);
+ }
+
+ /**
+ * Add a fixed view to appear at the top of the grid. If addHeaderView is
+ * called more than once, the views will appear in the order they were
+ * added. Views added using this call can take focus if they want.
+ * <p/>
+ * NOTE: Call this before calling setAdapter. This is so HeaderGridView can wrap
+ * the supplied cursor with one that will also account for header views.
+ *
+ * @param v The view to add.
+ */
+ public void addHeaderView(View v) {
+ addHeaderView(v, null, true);
+ }
+
+ /**
+ * Add a fixed view to appear at the top of the grid. If addHeaderView is
+ * called more than once, the views will appear in the order they were
+ * added. Views added using this call can take focus if they want.
+ * <p/>
+ * NOTE: Call this before calling setAdapter. This is so HeaderGridView can wrap
+ * the supplied cursor with one that will also account for header views.
+ *
+ * @param v The view to add.
+ * @param data Data to associate with this view
+ * @param isSelectable whether the item is selectable
+ */
+ public void addHeaderView(View v, Object data, boolean isSelectable) {
+ ListAdapter adapter = getAdapter();
+ if (adapter != null && !(adapter instanceof HeaderViewGridAdapter)) {
+ throw new IllegalStateException(
+ "Cannot add header view to grid -- setAdapter has already been called.");
+ }
+
+ ViewGroup.LayoutParams lyp = v.getLayoutParams();
+
+ FixedViewInfo info = new FixedViewInfo();
+ FrameLayout fl = new FullWidthFixedViewLayout(getContext());
+
+ if (lyp != null) {
+ v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height));
+ fl.setLayoutParams(new LayoutParams(lyp.width, lyp.height));
+ }
+ fl.addView(v);
+ info.view = v;
+ info.viewContainer = fl;
+ info.data = data;
+ info.isSelectable = isSelectable;
+ mHeaderViewInfos.add(info);
+ // in the case of re-adding a header view, or adding one later on,
+ // we need to notify the observer
+ if (adapter != null) {
+ ((HeaderViewGridAdapter) adapter).notifyDataSetChanged();
+ }
+ }
+
+ public void addFooterView(View v) {
+ addFooterView(v, null, true);
+ }
+
+ public void addFooterView(View v, Object data, boolean isSelectable) {
+ ListAdapter mAdapter = getAdapter();
+ if (mAdapter != null && !(mAdapter instanceof HeaderViewGridAdapter)) {
+ throw new IllegalStateException(
+ "Cannot add header view to grid -- setAdapter has already been called.");
+ }
+
+ ViewGroup.LayoutParams lyp = v.getLayoutParams();
+
+ FixedViewInfo info = new FixedViewInfo();
+ FrameLayout fl = new FullWidthFixedViewLayout(getContext());
+
+ if (lyp != null) {
+ v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height));
+ fl.setLayoutParams(new LayoutParams(lyp.width, lyp.height));
+ }
+ fl.addView(v);
+ info.view = v;
+ info.viewContainer = fl;
+ info.data = data;
+ info.isSelectable = isSelectable;
+ mFooterViewInfos.add(info);
+
+ if (mAdapter != null) {
+ ((HeaderViewGridAdapter) mAdapter).notifyDataSetChanged();
+ }
+ }
+
+ public int getHeaderViewCount() {
+ return mHeaderViewInfos.size();
+ }
+
+ public int getFooterViewCount() {
+ return mFooterViewInfos.size();
+ }
+
+ /**
+ * Removes a previously-added header view.
+ *
+ * @param v The view to remove
+ * @return true if the view was removed, false if the view was not a header
+ * view
+ */
+ public boolean removeHeaderView(View v) {
+ if (mHeaderViewInfos.size() > 0) {
+ boolean result = false;
+ ListAdapter adapter = getAdapter();
+ if (adapter != null && ((HeaderViewGridAdapter) adapter).removeHeader(v)) {
+ result = true;
+ }
+ removeFixedViewInfo(v, mHeaderViewInfos);
+ return result;
+ }
+ return false;
+ }
+
+ /**
+ * Removes a previously-added footer view.
+ *
+ * @param v The view to remove
+ * @return true if the view was removed, false if the view was not a header
+ * view
+ */
+ public boolean removeFooterView(View v) {
+ if (mFooterViewInfos.size() > 0) {
+ boolean result = false;
+ ListAdapter adapter = getAdapter();
+ if (adapter != null && ((HeaderViewGridAdapter) adapter).removeFooter(v)) {
+ result = true;
+ }
+ removeFixedViewInfo(v, mFooterViewInfos);
+ return result;
+ }
+ return false;
+ }
+
+ private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> where) {
+ int len = where.size();
+ for (int i = 0; i < len; ++i) {
+ FixedViewInfo info = where.get(i);
+ if (info.view == v) {
+ where.remove(i);
+ break;
+ }
+ }
+ }
+
+ @TargetApi(11)
+ private int getNumColumnsCompatible() {
+ if (Build.VERSION.SDK_INT >= 11) {
+ return super.getNumColumns();
+ } else {
+ try {
+ Field numColumns = getClass().getSuperclass().getDeclaredField("mNumColumns");
+ numColumns.setAccessible(true);
+ return numColumns.getInt(this);
+ } catch (Exception e) {
+ if (mNumColumns != -1) {
+ return mNumColumns;
+ }
+ throw new RuntimeException("Can not determine the mNumColumns for this API platform, please call setNumColumns to set it.");
+ }
+ }
+ }
+
+ @TargetApi(16)
+ private int getColumnWidthCompatible() {
+ if (Build.VERSION.SDK_INT >= 16) {
+ return super.getColumnWidth();
+ } else {
+ try {
+ Field numColumns = getClass().getSuperclass().getDeclaredField("mColumnWidth");
+ numColumns.setAccessible(true);
+ return numColumns.getInt(this);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mViewForMeasureRowHeight = null;
+ }
+
+ public void invalidateRowHeight() {
+ mRowHeight = -1;
+ }
+
+ public int getRowHeight() {
+ if (mRowHeight > 0) {
+ return mRowHeight;
+ }
+ ListAdapter adapter = getAdapter();
+ int numColumns = getNumColumnsCompatible();
+
+ // adapter has not been set or has no views in it;
+ if (adapter == null || adapter.getCount() <= numColumns * (mHeaderViewInfos.size() + mFooterViewInfos.size())) {
+ return -1;
+ }
+ int mColumnWidth = getColumnWidthCompatible();
+ View view = getAdapter().getView(numColumns * mHeaderViewInfos.size(), mViewForMeasureRowHeight, this);
+ LayoutParams p = (LayoutParams) view.getLayoutParams();
+ if (p == null) {
+ p = new LayoutParams(-1, -2, 0);
+ view.setLayoutParams(p);
+ }
+ int childHeightSpec = getChildMeasureSpec(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height);
+ int childWidthSpec = getChildMeasureSpec(
+ MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width);
+ view.measure(childWidthSpec, childHeightSpec);
+ mViewForMeasureRowHeight = view;
+ mRowHeight = view.getMeasuredHeight();
+ return mRowHeight;
+ }
+
+ @TargetApi(11)
+ public void tryToScrollToBottomSmoothly() {
+ int lastPos = getAdapter().getCount() - 1;
+ if (Build.VERSION.SDK_INT >= 11) {
+ smoothScrollToPositionFromTop(lastPos, 0);
+ } else {
+ setSelection(lastPos);
+ }
+ }
+
+ @TargetApi(11)
+ public void tryToScrollToBottomSmoothly(int duration) {
+ int lastPos = getAdapter().getCount() - 1;
+ if (Build.VERSION.SDK_INT >= 11) {
+ smoothScrollToPositionFromTop(lastPos, 0, duration);
+ } else {
+ setSelection(lastPos);
+ }
+ }
+
+ @Override
+ public void setAdapter(ListAdapter adapter) {
+ if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {
+ HeaderViewGridAdapter headerViewGridAdapter = new HeaderViewGridAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
+ int numColumns = getNumColumnsCompatible();
+ if (numColumns > 1) {
+ headerViewGridAdapter.setNumColumns(numColumns);
+ }
+ headerViewGridAdapter.setRowHeight(getRowHeight());
+ super.setAdapter(headerViewGridAdapter);
+ } else {
+ super.setAdapter(adapter);
+ }
+ }
+
+ /**
+ * full width
+ */
+ private class FullWidthFixedViewLayout extends FrameLayout {
+
+ public FullWidthFixedViewLayout(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ int realLeft = GridViewWithHeaderAndFooter.this.getPaddingLeft() + getPaddingLeft();
+ // Try to make where it should be, from left, full width
+ if (realLeft != left) {
+ offsetLeftAndRight(realLeft - left);
+ }
+ super.onLayout(changed, left, top, right, bottom);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int targetWidth = GridViewWithHeaderAndFooter.this.getMeasuredWidth()
+ - GridViewWithHeaderAndFooter.this.getPaddingLeft()
+ - GridViewWithHeaderAndFooter.this.getPaddingRight();
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth,
+ MeasureSpec.getMode(widthMeasureSpec));
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ @Override
+ public void setNumColumns(int numColumns) {
+ super.setNumColumns(numColumns);
+ mNumColumns = numColumns;
+ ListAdapter adapter = getAdapter();
+ if (adapter != null && adapter instanceof HeaderViewGridAdapter) {
+ ((HeaderViewGridAdapter) adapter).setNumColumns(numColumns);
+ }
+ }
+
+ /**
+ * ListAdapter used when a HeaderGridView has header views. This ListAdapter
+ * wraps another one and also keeps track of the header views and their
+ * associated data objects.
+ * <p>This is intended as a base class; you will probably not need to
+ * use this class directly in your own code.
+ */
+ private static class HeaderViewGridAdapter implements WrapperListAdapter, Filterable {
+ // This is used to notify the container of updates relating to number of columns
+ // or headers changing, which changes the number of placeholders needed
+ private final DataSetObservable mDataSetObservable = new DataSetObservable();
+ private final ListAdapter mAdapter;
+ static final ArrayList<FixedViewInfo> EMPTY_INFO_LIST =
+ new ArrayList<FixedViewInfo>();
+
+ // This ArrayList is assumed to NOT be null.
+ ArrayList<FixedViewInfo> mHeaderViewInfos;
+ ArrayList<FixedViewInfo> mFooterViewInfos;
+ private int mNumColumns = 1;
+ private int mRowHeight = -1;
+ boolean mAreAllFixedViewsSelectable;
+ private final boolean mIsFilterable;
+ private boolean mCachePlaceHoldView = true;
+ // From Recycle Bin or calling getView, this a question...
+ private boolean mCacheFirstHeaderView = false;
+
+ public HeaderViewGridAdapter(ArrayList<FixedViewInfo> headerViewInfos, ArrayList<FixedViewInfo> footViewInfos, ListAdapter adapter) {
+ mAdapter = adapter;
+ mIsFilterable = adapter instanceof Filterable;
+ if (headerViewInfos == null) {
+ mHeaderViewInfos = EMPTY_INFO_LIST;
+ } else {
+ mHeaderViewInfos = headerViewInfos;
+ }
+
+ if (footViewInfos == null) {
+ mFooterViewInfos = EMPTY_INFO_LIST;
+ } else {
+ mFooterViewInfos = footViewInfos;
+ }
+ mAreAllFixedViewsSelectable = areAllListInfosSelectable(mHeaderViewInfos)
+ && areAllListInfosSelectable(mFooterViewInfos);
+ }
+
+ public void setNumColumns(int numColumns) {
+ if (numColumns < 1) {
+ return;
+ }
+ if (mNumColumns != numColumns) {
+ mNumColumns = numColumns;
+ notifyDataSetChanged();
+ }
+ }
+
+ public void setRowHeight(int height) {
+ mRowHeight = height;
+ }
+
+ public int getHeadersCount() {
+ return mHeaderViewInfos.size();
+ }
+
+ public int getFootersCount() {
+ return mFooterViewInfos.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return (mAdapter == null || mAdapter.isEmpty()) && getHeadersCount() == 0 && getFootersCount() == 0;
+ }
+
+ private boolean areAllListInfosSelectable(ArrayList<FixedViewInfo> infos) {
+ if (infos != null) {
+ for (FixedViewInfo info : infos) {
+ if (!info.isSelectable) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public boolean removeHeader(View v) {
+ for (int i = 0; i < mHeaderViewInfos.size(); i++) {
+ FixedViewInfo info = mHeaderViewInfos.get(i);
+ if (info.view == v) {
+ mHeaderViewInfos.remove(i);
+ mAreAllFixedViewsSelectable =
+ areAllListInfosSelectable(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos);
+ mDataSetObservable.notifyChanged();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean removeFooter(View v) {
+ for (int i = 0; i < mFooterViewInfos.size(); i++) {
+ FixedViewInfo info = mFooterViewInfos.get(i);
+ if (info.view == v) {
+ mFooterViewInfos.remove(i);
+ mAreAllFixedViewsSelectable =
+ areAllListInfosSelectable(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos);
+ mDataSetObservable.notifyChanged();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int getCount() {
+ if (mAdapter != null) {
+ return (getFootersCount() + getHeadersCount()) * mNumColumns + getAdapterAndPlaceHolderCount();
+ } else {
+ return (getFootersCount() + getHeadersCount()) * mNumColumns;
+ }
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ if (mAdapter != null) {
+ return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled();
+ } else {
+ return true;
+ }
+ }
+
+ private int getAdapterAndPlaceHolderCount() {
+ final int adapterCount = (int) (Math.ceil(1f * mAdapter.getCount() / mNumColumns) * mNumColumns);
+ return adapterCount;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ // Header (negative positions will throw an IndexOutOfBoundsException)
+ int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
+ if (position < numHeadersAndPlaceholders) {
+ return position % mNumColumns == 0
+ && mHeaderViewInfos.get(position / mNumColumns).isSelectable;
+ }
+
+ // Adapter
+ final int adjPosition = position - numHeadersAndPlaceholders;
+ int adapterCount = 0;
+ if (mAdapter != null) {
+ adapterCount = getAdapterAndPlaceHolderCount();
+ if (adjPosition < adapterCount) {
+ return adjPosition < mAdapter.getCount() && mAdapter.isEnabled(adjPosition);
+ }
+ }
+
+ // Footer (off-limits positions will throw an IndexOutOfBoundsException)
+ final int footerPosition = adjPosition - adapterCount;
+ return footerPosition % mNumColumns == 0
+ && mFooterViewInfos.get(footerPosition / mNumColumns).isSelectable;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
+ int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
+ if (position < numHeadersAndPlaceholders) {
+ if (position % mNumColumns == 0) {
+ return mHeaderViewInfos.get(position / mNumColumns).data;
+ }
+ return null;
+ }
+
+ // Adapter
+ final int adjPosition = position - numHeadersAndPlaceholders;
+ int adapterCount = 0;
+ if (mAdapter != null) {
+ adapterCount = getAdapterAndPlaceHolderCount();
+ if (adjPosition < adapterCount) {
+ if (adjPosition < mAdapter.getCount()) {
+ return mAdapter.getItem(adjPosition);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ // Footer (off-limits positions will throw an IndexOutOfBoundsException)
+ final int footerPosition = adjPosition - adapterCount;
+ if (footerPosition % mNumColumns == 0) {
+ return mFooterViewInfos.get(footerPosition).data;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public long getItemId(int position) {
+ int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
+ if (mAdapter != null && position >= numHeadersAndPlaceholders) {
+ int adjPosition = position - numHeadersAndPlaceholders;
+ int adapterCount = mAdapter.getCount();
+ if (adjPosition < adapterCount) {
+ return mAdapter.getItemId(adjPosition);
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ if (mAdapter != null) {
+ return mAdapter.hasStableIds();
+ }
+ return false;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, String.format("getView: %s, reused: %s", position, convertView == null));
+ }
+ // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
+ int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
+ if (position < numHeadersAndPlaceholders) {
+ View headerViewContainer = mHeaderViewInfos
+ .get(position / mNumColumns).viewContainer;
+ if (position % mNumColumns == 0) {
+ return headerViewContainer;
+ } else {
+ if (convertView == null) {
+ convertView = new View(parent.getContext());
+ }
+ // We need to do this because GridView uses the height of the last item
+ // in a row to determine the height for the entire row.
+ convertView.setVisibility(View.INVISIBLE);
+ convertView.setMinimumHeight(headerViewContainer.getHeight());
+ return convertView;
+ }
+ }
+ // Adapter
+ final int adjPosition = position - numHeadersAndPlaceholders;
+ int adapterCount = 0;
+ if (mAdapter != null) {
+ adapterCount = getAdapterAndPlaceHolderCount();
+ if (adjPosition < adapterCount) {
+ if (adjPosition < mAdapter.getCount()) {
+ View view = mAdapter.getView(adjPosition, convertView, parent);
+ return view;
+ } else {
+ if (convertView == null) {
+ convertView = new View(parent.getContext());
+ }
+ convertView.setVisibility(View.INVISIBLE);
+ convertView.setMinimumHeight(mRowHeight);
+ return convertView;
+ }
+ }
+ }
+ // Footer
+ final int footerPosition = adjPosition - adapterCount;
+ if (footerPosition < getCount()) {
+ View footViewContainer = mFooterViewInfos
+ .get(footerPosition / mNumColumns).viewContainer;
+ if (position % mNumColumns == 0) {
+ return footViewContainer;
+ } else {
+ if (convertView == null) {
+ convertView = new View(parent.getContext());
+ }
+ // We need to do this because GridView uses the height of the last item
+ // in a row to determine the height for the entire row.
+ convertView.setVisibility(View.INVISIBLE);
+ convertView.setMinimumHeight(footViewContainer.getHeight());
+ return convertView;
+ }
+ }
+ throw new ArrayIndexOutOfBoundsException(position);
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+
+ final int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
+ final int adapterViewTypeStart = mAdapter == null ? 0 : mAdapter.getViewTypeCount() - 1;
+ int type = AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
+ if (mCachePlaceHoldView) {
+ // Header
+ if (position < numHeadersAndPlaceholders) {
+ if (position == 0) {
+ if (mCacheFirstHeaderView) {
+ type = adapterViewTypeStart + mHeaderViewInfos.size() + mFooterViewInfos.size() + 1 + 1;
+ }
+ }
+ if (position % mNumColumns != 0) {
+ type = adapterViewTypeStart + (position / mNumColumns + 1);
+ }
+ }
+ }
+
+ // Adapter
+ final int adjPosition = position - numHeadersAndPlaceholders;
+ int adapterCount = 0;
+ if (mAdapter != null) {
+ adapterCount = getAdapterAndPlaceHolderCount();
+ if (adjPosition >= 0 && adjPosition < adapterCount) {
+ if (adjPosition < mAdapter.getCount()) {
+ type = mAdapter.getItemViewType(adjPosition);
+ } else {
+ if (mCachePlaceHoldView) {
+ type = adapterViewTypeStart + mHeaderViewInfos.size() + 1;
+ }
+ }
+ }
+ }
+
+ if (mCachePlaceHoldView) {
+ // Footer
+ final int footerPosition = adjPosition - adapterCount;
+ if (footerPosition >= 0 && footerPosition < getCount() && (footerPosition % mNumColumns) != 0) {
+ type = adapterViewTypeStart + mHeaderViewInfos.size() + 1 + (footerPosition / mNumColumns + 1);
+ }
+ }
+ if (DEBUG) {
+ Log.d(LOG_TAG, String.format("getItemViewType: pos: %s, result: %s", position, type, mCachePlaceHoldView, mCacheFirstHeaderView));
+ }
+ return type;
+ }
+
+ /**
+ * content view, content view holder, header[0], header and footer placeholder(s)
+ *
+ * @return
+ */
+ @Override
+ public int getViewTypeCount() {
+ int count = mAdapter == null ? 1 : mAdapter.getViewTypeCount();
+ if (mCachePlaceHoldView) {
+ int offset = mHeaderViewInfos.size() + 1 + mFooterViewInfos.size();
+ if (mCacheFirstHeaderView) {
+ offset += 1;
+ }
+ count += offset;
+ }
+ if (DEBUG) {
+ Log.d(LOG_TAG, String.format("getViewTypeCount: %s", count));
+ }
+ return count;
+ }
+
+ @Override
+ public void registerDataSetObserver(DataSetObserver observer) {
+ mDataSetObservable.registerObserver(observer);
+ if (mAdapter != null) {
+ mAdapter.registerDataSetObserver(observer);
+ }
+ }
+
+ @Override
+ public void unregisterDataSetObserver(DataSetObserver observer) {
+ mDataSetObservable.unregisterObserver(observer);
+ if (mAdapter != null) {
+ mAdapter.unregisterDataSetObserver(observer);
+ }
+ }
+
+ @Override
+ public Filter getFilter() {
+ if (mIsFilterable) {
+ return ((Filterable) mAdapter).getFilter();
+ }
+ return null;
+ }
+
+ @Override
+ public ListAdapter getWrappedAdapter() {
+ return mAdapter;
+ }
+
+ public void notifyDataSetChanged() {
+ mDataSetObservable.notifyChanged();
+ }
+ }
+
+
+ /**
+ * Sets the selected item and positions the selection y pixels from the top edge of the ListView.
+ * (If in touch mode, the item will not be selected but it will still be positioned appropriately.)
+ *
+ * @param position Index (starting at 0) of the data item to be selected.
+ * @param y The distance from the top edge of the ListView (plus padding)
+ * that the item will be positioned.
+ *
+ * @see <a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/widget/ListView.java#ListView.setSelectionFromTop%28int%2Cint%29">Original code</a>
+ */
+ public void setSelectionFromTop(int position, int y) {
+ if (getAdapter() == null) {
+ return;
+ }
+
+ setSelection(position);
+ //setSelectionInt(position);
+
+ /*if (!isInTouchMode()) {
+ position = super.lookForSelectablePosition(position, true);
+ if (position >= 0) {
+ setNextSelectedPositionInt(position);
+ }
+ } else {
+ mResurrectToPosition = position;
+ }*/
+
+ /*
+ if (position >= 0) {
+ mLayoutMode = LAYOUT_SPECIFIC;
+ mSpecificTop = mListPadding.top + y;
+
+ if (mNeedSync) {
+ mSyncPosition = position;
+ mSyncRowId = getAdapter().getItemId(position);
+ }
+
+ if (mPositionScroller != null) {
+ mPositionScroller.stop();
+ }
+
+ requestLayout();
+ }
+ */
+ }
+
+}
--- /dev/null
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
\ No newline at end of file
--- /dev/null
+/**
+ * @author Michael Ortiz
+ * @updated Patrick Lackemacher
+ * @updated Babay88
+ * @updated @ipsilondev
+ * @updated hank-cp
+ * @updated singpolyma
+ * Copyright (c) 2012 Michael Ortiz
+ */
+
+package third_parties.michaelOrtiz;
+
+import com.owncloud.android.ui.preview.ImageViewCustom;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.View;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.OverScroller;
+import android.widget.Scroller;
+
+/**
+ * Extends Android ImageView to include pinch zooming, panning, fling and double tap zoom.
+ */
+public class TouchImageViewCustom extends ImageViewCustom {
+ private static final String DEBUG = "DEBUG";
+
+ //
+ // SuperMin and SuperMax multipliers. Determine how much the image can be
+ // zoomed below or above the zoom boundaries, before animating back to the
+ // min/max zoom boundary.
+ //
+ private static final float SUPER_MIN_MULTIPLIER = .75f;
+ private static final float SUPER_MAX_MULTIPLIER = 1.25f;
+
+ //
+ // Scale of image ranges from minScale to maxScale, where minScale == 1
+ // when the image is stretched to fit view.
+ //
+ private float normalizedScale;
+
+ //
+ // Matrix applied to image. MSCALE_X and MSCALE_Y should always be equal.
+ // MTRANS_X and MTRANS_Y are the other values used. prevMatrix is the matrix
+ // saved prior to the screen rotating.
+ //
+ private Matrix matrix, prevMatrix;
+
+ private static enum State { NONE, DRAG, ZOOM, FLING, ANIMATE_ZOOM };
+ private State state;
+
+ private float minScale;
+ private float maxScale;
+ private float superMinScale;
+ private float superMaxScale;
+ private float[] m;
+
+ private Context context;
+ private Fling fling;
+
+ private ScaleType mScaleType;
+
+ private boolean imageRenderedAtLeastOnce;
+ private boolean onDrawReady;
+
+ private ZoomVariables delayedZoomVariables;
+
+ //
+ // Size of view and previous view size (ie before rotation)
+ //
+ private int viewWidth, viewHeight, prevViewWidth, prevViewHeight;
+
+ //
+ // Size of image when it is stretched to fit view. Before and After rotation.
+ //
+ private float matchViewWidth, matchViewHeight, prevMatchViewWidth, prevMatchViewHeight;
+
+ private ScaleGestureDetector mScaleDetector;
+ private GestureDetector mGestureDetector;
+ private GestureDetector.OnDoubleTapListener doubleTapListener = null;
+ private OnTouchListener userTouchListener = null;
+ private OnTouchImageViewListener touchImageViewListener = null;
+
+ public TouchImageViewCustom(Context context) {
+ super(context);
+ sharedConstructing(context);
+ }
+
+ public TouchImageViewCustom(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ sharedConstructing(context);
+ }
+
+ public TouchImageViewCustom(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ sharedConstructing(context);
+ }
+
+ private void sharedConstructing(Context context) {
+ super.setClickable(true);
+ this.context = context;
+ mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
+ mGestureDetector = new GestureDetector(context, new GestureListener());
+ matrix = new Matrix();
+ prevMatrix = new Matrix();
+ m = new float[9];
+ normalizedScale = 1;
+ if (mScaleType == null) {
+ mScaleType = ScaleType.FIT_CENTER;
+ }
+ minScale = 1;
+ maxScale = 3;
+ superMinScale = SUPER_MIN_MULTIPLIER * minScale;
+ superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
+ setImageMatrix(matrix);
+ setScaleType(ScaleType.MATRIX);
+ setState(State.NONE);
+ onDrawReady = false;
+ super.setOnTouchListener(new PrivateOnTouchListener());
+ }
+
+ @Override
+ public void setOnTouchListener(View.OnTouchListener l) {
+ userTouchListener = l;
+ }
+
+ public void setOnTouchImageViewListener(OnTouchImageViewListener l) {
+ touchImageViewListener = l;
+ }
+
+ public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener l) {
+ doubleTapListener = l;
+ }
+
+ @Override
+ public void setImageResource(int resId) {
+ super.setImageResource(resId);
+ savePreviousImageValues();
+ fitImageToView();
+ }
+
+ @Override
+ public void setImageBitmap(Bitmap bm) {
+ super.setImageBitmap(bm);
+ savePreviousImageValues();
+ fitImageToView();
+ }
+
+ @Override
+ public void setImageDrawable(Drawable drawable) {
+ super.setImageDrawable(drawable);
+ savePreviousImageValues();
+ fitImageToView();
+ }
+
+ @Override
+ public void setImageURI(Uri uri) {
+ super.setImageURI(uri);
+ savePreviousImageValues();
+ fitImageToView();
+ }
+
+ @Override
+ public void setScaleType(ScaleType type) {
+ if (type == ScaleType.FIT_START || type == ScaleType.FIT_END) {
+ throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END");
+ }
+ if (type == ScaleType.MATRIX) {
+ super.setScaleType(ScaleType.MATRIX);
+
+ } else {
+ mScaleType = type;
+ if (onDrawReady) {
+ //
+ // If the image is already rendered, scaleType has been called programmatically
+ // and the TouchImageView should be updated with the new scaleType.
+ //
+ setZoom(this);
+ }
+ }
+ }
+
+ @Override
+ public ScaleType getScaleType() {
+ return mScaleType;
+ }
+
+ /**
+ * Returns false if image is in initial, unzoomed state. False, otherwise.
+ * @return true if image is zoomed
+ */
+ public boolean isZoomed() {
+ return normalizedScale != 1;
+ }
+
+ /**
+ * Return a Rect representing the zoomed image.
+ * @return rect representing zoomed image
+ */
+ public RectF getZoomedRect() {
+ if (mScaleType == ScaleType.FIT_XY) {
+ throw new UnsupportedOperationException("getZoomedRect() not supported with FIT_XY");
+ }
+ PointF topLeft = transformCoordTouchToBitmap(0, 0, true);
+ PointF bottomRight = transformCoordTouchToBitmap(viewWidth, viewHeight, true);
+
+ float w = getDrawable().getIntrinsicWidth();
+ float h = getDrawable().getIntrinsicHeight();
+ return new RectF(topLeft.x / w, topLeft.y / h, bottomRight.x / w, bottomRight.y / h);
+ }
+
+ /**
+ * Save the current matrix and view dimensions
+ * in the prevMatrix and prevView variables.
+ */
+ private void savePreviousImageValues() {
+ if (matrix != null && viewHeight != 0 && viewWidth != 0) {
+ matrix.getValues(m);
+ prevMatrix.setValues(m);
+ prevMatchViewHeight = matchViewHeight;
+ prevMatchViewWidth = matchViewWidth;
+ prevViewHeight = viewHeight;
+ prevViewWidth = viewWidth;
+ }
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable("instanceState", super.onSaveInstanceState());
+ bundle.putFloat("saveScale", normalizedScale);
+ bundle.putFloat("matchViewHeight", matchViewHeight);
+ bundle.putFloat("matchViewWidth", matchViewWidth);
+ bundle.putInt("viewWidth", viewWidth);
+ bundle.putInt("viewHeight", viewHeight);
+ matrix.getValues(m);
+ bundle.putFloatArray("matrix", m);
+ bundle.putBoolean("imageRendered", imageRenderedAtLeastOnce);
+ return bundle;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ if (state instanceof Bundle) {
+ Bundle bundle = (Bundle) state;
+ normalizedScale = bundle.getFloat("saveScale");
+ m = bundle.getFloatArray("matrix");
+ prevMatrix.setValues(m);
+ prevMatchViewHeight = bundle.getFloat("matchViewHeight");
+ prevMatchViewWidth = bundle.getFloat("matchViewWidth");
+ prevViewHeight = bundle.getInt("viewHeight");
+ prevViewWidth = bundle.getInt("viewWidth");
+ imageRenderedAtLeastOnce = bundle.getBoolean("imageRendered");
+ super.onRestoreInstanceState(bundle.getParcelable("instanceState"));
+ return;
+ }
+
+ super.onRestoreInstanceState(state);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ onDrawReady = true;
+ imageRenderedAtLeastOnce = true;
+ if (delayedZoomVariables != null) {
+ setZoom(delayedZoomVariables.scale, delayedZoomVariables.focusX, delayedZoomVariables.focusY, delayedZoomVariables.scaleType);
+ delayedZoomVariables = null;
+ }
+ super.onDraw(canvas);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ savePreviousImageValues();
+ }
+
+ /**
+ * Get the max zoom multiplier.
+ * @return max zoom multiplier.
+ */
+ public float getMaxZoom() {
+ return maxScale;
+ }
+
+ /**
+ * Set the max zoom multiplier. Default value: 3.
+ * @param max max zoom multiplier.
+ */
+ public void setMaxZoom(float max) {
+ maxScale = max;
+ superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
+ }
+
+ /**
+ * Get the min zoom multiplier.
+ * @return min zoom multiplier.
+ */
+ public float getMinZoom() {
+ return minScale;
+ }
+
+ /**
+ * Get the current zoom. This is the zoom relative to the initial
+ * scale, not the original resource.
+ * @return current zoom multiplier.
+ */
+ public float getCurrentZoom() {
+ return normalizedScale;
+ }
+
+ /**
+ * Set the min zoom multiplier. Default value: 1.
+ * @param min min zoom multiplier.
+ */
+ public void setMinZoom(float min) {
+ minScale = min;
+ superMinScale = SUPER_MIN_MULTIPLIER * minScale;
+ }
+
+ /**
+ * Reset zoom and translation to initial state.
+ */
+ public void resetZoom() {
+ normalizedScale = 1;
+ fitImageToView();
+ }
+
+ /**
+ * Set zoom to the specified scale. Image will be centered by default.
+ * @param scale
+ */
+ public void setZoom(float scale) {
+ setZoom(scale, 0.5f, 0.5f);
+ }
+
+ /**
+ * Set zoom to the specified scale. Image will be centered around the point
+ * (focusX, focusY). These floats range from 0 to 1 and denote the focus point
+ * as a fraction from the left and top of the view. For example, the top left
+ * corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
+ * @param scale
+ * @param focusX
+ * @param focusY
+ */
+ public void setZoom(float scale, float focusX, float focusY) {
+ setZoom(scale, focusX, focusY, mScaleType);
+ }
+
+ /**
+ * Set zoom to the specified scale. Image will be centered around the point
+ * (focusX, focusY). These floats range from 0 to 1 and denote the focus point
+ * as a fraction from the left and top of the view. For example, the top left
+ * corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
+ * @param scale
+ * @param focusX
+ * @param focusY
+ * @param scaleType
+ */
+ public void setZoom(float scale, float focusX, float focusY, ScaleType scaleType) {
+ //
+ // setZoom can be called before the image is on the screen, but at this point,
+ // image and view sizes have not yet been calculated in onMeasure. Thus, we should
+ // delay calling setZoom until the view has been measured.
+ //
+ if (!onDrawReady) {
+ delayedZoomVariables = new ZoomVariables(scale, focusX, focusY, scaleType);
+ return;
+ }
+
+ if (scaleType != mScaleType) {
+ setScaleType(scaleType);
+ }
+ resetZoom();
+ scaleImage(scale, viewWidth / 2, viewHeight / 2, true);
+ matrix.getValues(m);
+ m[Matrix.MTRANS_X] = -((focusX * getImageWidth()) - (viewWidth * 0.5f));
+ m[Matrix.MTRANS_Y] = -((focusY * getImageHeight()) - (viewHeight * 0.5f));
+ matrix.setValues(m);
+ fixTrans();
+ setImageMatrix(matrix);
+ }
+
+ /**
+ * Set zoom parameters equal to another TouchImageView. Including scale, position,
+ * and ScaleType.
+ * @param img
+ */
+ public void setZoom(TouchImageViewCustom img) {
+ PointF center = img.getScrollPosition();
+ setZoom(img.getCurrentZoom(), center.x, center.y, img.getScaleType());
+ }
+
+ /**
+ * Return the point at the center of the zoomed image. The PointF coordinates range
+ * in value between 0 and 1 and the focus point is denoted as a fraction from the left
+ * and top of the view. For example, the top left corner of the image would be (0, 0).
+ * And the bottom right corner would be (1, 1).
+ * @return PointF representing the scroll position of the zoomed image.
+ */
+ public PointF getScrollPosition() {
+ Drawable drawable = getDrawable();
+ if (drawable == null) {
+ return null;
+ }
+ int drawableWidth = drawable.getIntrinsicWidth();
+ int drawableHeight = drawable.getIntrinsicHeight();
+
+ PointF point = transformCoordTouchToBitmap(viewWidth / 2, viewHeight / 2, true);
+ point.x /= drawableWidth;
+ point.y /= drawableHeight;
+ return point;
+ }
+
+ /**
+ * Set the focus point of the zoomed image. The focus points are denoted as a fraction from the
+ * left and top of the view. The focus points can range in value between 0 and 1.
+ * @param focusX
+ * @param focusY
+ */
+ public void setScrollPosition(float focusX, float focusY) {
+ setZoom(normalizedScale, focusX, focusY);
+ }
+
+ /**
+ * Performs boundary checking and fixes the image matrix if it
+ * is out of bounds.
+ */
+ private void fixTrans() {
+ matrix.getValues(m);
+ float transX = m[Matrix.MTRANS_X];
+ float transY = m[Matrix.MTRANS_Y];
+
+ float fixTransX = getFixTrans(transX, viewWidth, getImageWidth());
+ float fixTransY = getFixTrans(transY, viewHeight, getImageHeight());
+
+ if (fixTransX != 0 || fixTransY != 0) {
+ matrix.postTranslate(fixTransX, fixTransY);
+ }
+ }
+
+ /**
+ * When transitioning from zooming from focus to zoom from center (or vice versa)
+ * the image can become unaligned within the view. This is apparent when zooming
+ * quickly. When the content size is less than the view size, the content will often
+ * be centered incorrectly within the view. fixScaleTrans first calls fixTrans() and
+ * then makes sure the image is centered correctly within the view.
+ */
+ private void fixScaleTrans() {
+ fixTrans();
+ matrix.getValues(m);
+ if (getImageWidth() < viewWidth) {
+ m[Matrix.MTRANS_X] = (viewWidth - getImageWidth()) / 2;
+ }
+
+ if (getImageHeight() < viewHeight) {
+ m[Matrix.MTRANS_Y] = (viewHeight - getImageHeight()) / 2;
+ }
+ matrix.setValues(m);
+ }
+
+ private float getFixTrans(float trans, float viewSize, float contentSize) {
+ float minTrans, maxTrans;
+
+ if (contentSize <= viewSize) {
+ minTrans = 0;
+ maxTrans = viewSize - contentSize;
+
+ } else {
+ minTrans = viewSize - contentSize;
+ maxTrans = 0;
+ }
+
+ if (trans < minTrans)
+ return -trans + minTrans;
+ if (trans > maxTrans)
+ return -trans + maxTrans;
+ return 0;
+ }
+
+ private float getFixDragTrans(float delta, float viewSize, float contentSize) {
+ if (contentSize <= viewSize) {
+ return 0;
+ }
+ return delta;
+ }
+
+ private float getImageWidth() {
+ return matchViewWidth * normalizedScale;
+ }
+
+ private float getImageHeight() {
+ return matchViewHeight * normalizedScale;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ Drawable drawable = getDrawable();
+ if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) {
+ setMeasuredDimension(0, 0);
+ return;
+ }
+
+ int drawableWidth = drawable.getIntrinsicWidth();
+ int drawableHeight = drawable.getIntrinsicHeight();
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ viewWidth = setViewSize(widthMode, widthSize, drawableWidth);
+ viewHeight = setViewSize(heightMode, heightSize, drawableHeight);
+
+ //
+ // Set view dimensions
+ //
+ setMeasuredDimension(viewWidth, viewHeight);
+
+ //
+ // Fit content within view
+ //
+ fitImageToView();
+ }
+
+ /**
+ * If the normalizedScale is equal to 1, then the image is made to fit the screen. Otherwise,
+ * it is made to fit the screen according to the dimensions of the previous image matrix. This
+ * allows the image to maintain its zoom after rotation.
+ */
+ private void fitImageToView() {
+ Drawable drawable = getDrawable();
+ if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) {
+ return;
+ }
+ if (matrix == null || prevMatrix == null) {
+ return;
+ }
+
+ int drawableWidth = drawable.getIntrinsicWidth();
+ int drawableHeight = drawable.getIntrinsicHeight();
+
+ //
+ // Scale image for view
+ //
+ float scaleX = (float) viewWidth / drawableWidth;
+ float scaleY = (float) viewHeight / drawableHeight;
+
+ switch (mScaleType) {
+ case CENTER:
+ scaleX = scaleY = 1;
+ break;
+
+ case CENTER_CROP:
+ scaleX = scaleY = Math.max(scaleX, scaleY);
+ break;
+
+ case CENTER_INSIDE:
+ scaleX = scaleY = Math.min(1, Math.min(scaleX, scaleY));
+
+ case FIT_CENTER:
+ scaleX = scaleY = Math.min(scaleX, scaleY);
+ break;
+
+ case FIT_XY:
+ break;
+
+ default:
+ //
+ // FIT_START and FIT_END not supported
+ //
+ throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END");
+
+ }
+
+ //
+ // Center the image
+ //
+ float redundantXSpace = viewWidth - (scaleX * drawableWidth);
+ float redundantYSpace = viewHeight - (scaleY * drawableHeight);
+ matchViewWidth = viewWidth - redundantXSpace;
+ matchViewHeight = viewHeight - redundantYSpace;
+ if (!isZoomed() && !imageRenderedAtLeastOnce) {
+ //
+ // Stretch and center image to fit view
+ //
+ matrix.setScale(scaleX, scaleY);
+ matrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2);
+ normalizedScale = 1;
+
+ } else {
+ //
+ // These values should never be 0 or we will set viewWidth and viewHeight
+ // to NaN in translateMatrixAfterRotate. To avoid this, call savePreviousImageValues
+ // to set them equal to the current values.
+ //
+ if (prevMatchViewWidth == 0 || prevMatchViewHeight == 0) {
+ savePreviousImageValues();
+ }
+
+ prevMatrix.getValues(m);
+
+ //
+ // Rescale Matrix after rotation
+ //
+ m[Matrix.MSCALE_X] = matchViewWidth / drawableWidth * normalizedScale;
+ m[Matrix.MSCALE_Y] = matchViewHeight / drawableHeight * normalizedScale;
+
+ //
+ // TransX and TransY from previous matrix
+ //
+ float transX = m[Matrix.MTRANS_X];
+ float transY = m[Matrix.MTRANS_Y];
+
+ //
+ // Width
+ //
+ float prevActualWidth = prevMatchViewWidth * normalizedScale;
+ float actualWidth = getImageWidth();
+ translateMatrixAfterRotate(Matrix.MTRANS_X, transX, prevActualWidth, actualWidth, prevViewWidth, viewWidth, drawableWidth);
+
+ //
+ // Height
+ //
+ float prevActualHeight = prevMatchViewHeight * normalizedScale;
+ float actualHeight = getImageHeight();
+ translateMatrixAfterRotate(Matrix.MTRANS_Y, transY, prevActualHeight, actualHeight, prevViewHeight, viewHeight, drawableHeight);
+
+ //
+ // Set the matrix to the adjusted scale and translate values.
+ //
+ matrix.setValues(m);
+ }
+ fixTrans();
+ setImageMatrix(matrix);
+ }
+
+ /**
+ * Set view dimensions based on layout params
+ *
+ * @param mode
+ * @param size
+ * @param drawableWidth
+ * @return
+ */
+ private int setViewSize(int mode, int size, int drawableWidth) {
+ int viewSize;
+ switch (mode) {
+ case MeasureSpec.EXACTLY:
+ viewSize = size;
+ break;
+
+ case MeasureSpec.AT_MOST:
+ viewSize = Math.min(drawableWidth, size);
+ break;
+
+ case MeasureSpec.UNSPECIFIED:
+ viewSize = drawableWidth;
+ break;
+
+ default:
+ viewSize = size;
+ break;
+ }
+ return viewSize;
+ }
+
+ /**
+ * After rotating, the matrix needs to be translated. This function finds the area of image
+ * which was previously centered and adjusts translations so that is again the center, post-rotation.
+ *
+ * @param axis Matrix.MTRANS_X or Matrix.MTRANS_Y
+ * @param trans the value of trans in that axis before the rotation
+ * @param prevImageSize the width/height of the image before the rotation
+ * @param imageSize width/height of the image after rotation
+ * @param prevViewSize width/height of view before rotation
+ * @param viewSize width/height of view after rotation
+ * @param drawableSize width/height of drawable
+ */
+ private void translateMatrixAfterRotate(int axis, float trans, float prevImageSize, float imageSize, int prevViewSize, int viewSize, int drawableSize) {
+ if (imageSize < viewSize) {
+ //
+ // The width/height of image is less than the view's width/height. Center it.
+ //
+ m[axis] = (viewSize - (drawableSize * m[Matrix.MSCALE_X])) * 0.5f;
+
+ } else if (trans > 0) {
+ //
+ // The image is larger than the view, but was not before rotation. Center it.
+ //
+ m[axis] = -((imageSize - viewSize) * 0.5f);
+
+ } else {
+ //
+ // Find the area of the image which was previously centered in the view. Determine its distance
+ // from the left/top side of the view as a fraction of the entire image's width/height. Use that percentage
+ // to calculate the trans in the new view width/height.
+ //
+ float percentage = (Math.abs(trans) + (0.5f * prevViewSize)) / prevImageSize;
+ m[axis] = -((percentage * imageSize) - (viewSize * 0.5f));
+ }
+ }
+
+ private void setState(State state) {
+ this.state = state;
+ }
+
+ public boolean canScrollHorizontallyFroyo(int direction) {
+ return canScrollHorizontally(direction);
+ }
+
+ @Override
+ public boolean canScrollHorizontally(int direction) {
+ matrix.getValues(m);
+ float x = m[Matrix.MTRANS_X];
+
+ if (getImageWidth() < viewWidth) {
+ return false;
+
+ } else if (x >= -1 && direction < 0) {
+ return false;
+
+ } else if (Math.abs(x) + viewWidth + 1 >= getImageWidth() && direction > 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Gesture Listener detects a single click or long click and passes that on
+ * to the view's listener.
+ * @author Ortiz
+ *
+ */
+ private class GestureListener extends GestureDetector.SimpleOnGestureListener {
+
+ @Override
+ public boolean onSingleTapConfirmed(MotionEvent e)
+ {
+ if(doubleTapListener != null) {
+ return doubleTapListener.onSingleTapConfirmed(e);
+ }
+ return performClick();
+ }
+
+ @Override
+ public void onLongPress(MotionEvent e)
+ {
+ performLongClick();
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
+ {
+ if (fling != null) {
+ //
+ // If a previous fling is still active, it should be cancelled so that two flings
+ // are not run simultaenously.
+ //
+ fling.cancelFling();
+ }
+ fling = new Fling((int) velocityX, (int) velocityY);
+ compatPostOnAnimation(fling);
+ return super.onFling(e1, e2, velocityX, velocityY);
+ }
+
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ boolean consumed = false;
+ if(doubleTapListener != null) {
+ consumed = doubleTapListener.onDoubleTap(e);
+ }
+ if (state == State.NONE) {
+ float targetZoom = (normalizedScale == minScale) ? maxScale : minScale;
+ DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, e.getX(), e.getY(), false);
+ compatPostOnAnimation(doubleTap);
+ consumed = true;
+ }
+ return consumed;
+ }
+
+ @Override
+ public boolean onDoubleTapEvent(MotionEvent e) {
+ if(doubleTapListener != null) {
+ return doubleTapListener.onDoubleTapEvent(e);
+ }
+ return false;
+ }
+ }
+
+ public interface OnTouchImageViewListener {
+ public void onMove();
+ }
+
+ /**
+ * Responsible for all touch events. Handles the heavy lifting of drag and also sends
+ * touch events to Scale Detector and Gesture Detector.
+ * @author Ortiz
+ *
+ */
+ private class PrivateOnTouchListener implements OnTouchListener {
+
+ //
+ // Remember last point position for dragging
+ //
+ private PointF last = new PointF();
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ mScaleDetector.onTouchEvent(event);
+ mGestureDetector.onTouchEvent(event);
+ PointF curr = new PointF(event.getX(), event.getY());
+
+ if (state == State.NONE || state == State.DRAG || state == State.FLING) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ last.set(curr);
+ if (fling != null)
+ fling.cancelFling();
+ setState(State.DRAG);
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ if (state == State.DRAG) {
+ float deltaX = curr.x - last.x;
+ float deltaY = curr.y - last.y;
+ float fixTransX = getFixDragTrans(deltaX, viewWidth, getImageWidth());
+ float fixTransY = getFixDragTrans(deltaY, viewHeight, getImageHeight());
+ matrix.postTranslate(fixTransX, fixTransY);
+ fixTrans();
+ last.set(curr.x, curr.y);
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ setState(State.NONE);
+ break;
+ }
+ }
+
+ setImageMatrix(matrix);
+
+ //
+ // User-defined OnTouchListener
+ //
+ if(userTouchListener != null) {
+ userTouchListener.onTouch(v, event);
+ }
+
+ //
+ // OnTouchImageViewListener is set: TouchImageView dragged by user.
+ //
+ if (touchImageViewListener != null) {
+ touchImageViewListener.onMove();
+ }
+
+ //
+ // indicate event was handled
+ //
+ return true;
+ }
+ }
+
+ /**
+ * ScaleListener detects user two finger scaling and scales image.
+ * @author Ortiz
+ *
+ */
+ private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
+ @Override
+ public boolean onScaleBegin(ScaleGestureDetector detector) {
+ setState(State.ZOOM);
+ return true;
+ }
+
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ scaleImage(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY(), true);
+
+ //
+ // OnTouchImageViewListener is set: TouchImageView pinch zoomed by user.
+ //
+ if (touchImageViewListener != null) {
+ touchImageViewListener.onMove();
+ }
+ return true;
+ }
+
+ @Override
+ public void onScaleEnd(ScaleGestureDetector detector) {
+ super.onScaleEnd(detector);
+ setState(State.NONE);
+ boolean animateToZoomBoundary = false;
+ float targetZoom = normalizedScale;
+ if (normalizedScale > maxScale) {
+ targetZoom = maxScale;
+ animateToZoomBoundary = true;
+
+ } else if (normalizedScale < minScale) {
+ targetZoom = minScale;
+ animateToZoomBoundary = true;
+ }
+
+ if (animateToZoomBoundary) {
+ DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, viewWidth / 2, viewHeight / 2, true);
+ compatPostOnAnimation(doubleTap);
+ }
+ }
+ }
+
+ private void scaleImage(double deltaScale, float focusX, float focusY, boolean stretchImageToSuper) {
+
+ float lowerScale, upperScale;
+ if (stretchImageToSuper) {
+ lowerScale = superMinScale;
+ upperScale = superMaxScale;
+
+ } else {
+ lowerScale = minScale;
+ upperScale = maxScale;
+ }
+
+ float origScale = normalizedScale;
+ normalizedScale *= deltaScale;
+ if (normalizedScale > upperScale) {
+ normalizedScale = upperScale;
+ deltaScale = upperScale / origScale;
+ } else if (normalizedScale < lowerScale) {
+ normalizedScale = lowerScale;
+ deltaScale = lowerScale / origScale;
+ }
+
+ matrix.postScale((float) deltaScale, (float) deltaScale, focusX, focusY);
+ fixScaleTrans();
+ }
+
+ /**
+ * DoubleTapZoom calls a series of runnables which apply
+ * an animated zoom in/out graphic to the image.
+ * @author Ortiz
+ *
+ */
+ private class DoubleTapZoom implements Runnable {
+
+ private long startTime;
+ private static final float ZOOM_TIME = 500;
+ private float startZoom, targetZoom;
+ private float bitmapX, bitmapY;
+ private boolean stretchImageToSuper;
+ private AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
+ private PointF startTouch;
+ private PointF endTouch;
+
+ DoubleTapZoom(float targetZoom, float focusX, float focusY, boolean stretchImageToSuper) {
+ setState(State.ANIMATE_ZOOM);
+ startTime = System.currentTimeMillis();
+ this.startZoom = normalizedScale;
+ this.targetZoom = targetZoom;
+ this.stretchImageToSuper = stretchImageToSuper;
+ PointF bitmapPoint = transformCoordTouchToBitmap(focusX, focusY, false);
+ this.bitmapX = bitmapPoint.x;
+ this.bitmapY = bitmapPoint.y;
+
+ //
+ // Used for translating image during scaling
+ //
+ startTouch = transformCoordBitmapToTouch(bitmapX, bitmapY);
+ endTouch = new PointF(viewWidth / 2, viewHeight / 2);
+ }
+
+ @Override
+ public void run() {
+ float t = interpolate();
+ double deltaScale = calculateDeltaScale(t);
+ scaleImage(deltaScale, bitmapX, bitmapY, stretchImageToSuper);
+ translateImageToCenterTouchPosition(t);
+ fixScaleTrans();
+ setImageMatrix(matrix);
+
+ //
+ // OnTouchImageViewListener is set: double tap runnable updates listener
+ // with every frame.
+ //
+ if (touchImageViewListener != null) {
+ touchImageViewListener.onMove();
+ }
+
+ if (t < 1f) {
+ //
+ // We haven't finished zooming
+ //
+ compatPostOnAnimation(this);
+
+ } else {
+ //
+ // Finished zooming
+ //
+ setState(State.NONE);
+ }
+ }
+
+ /**
+ * Interpolate between where the image should start and end in order to translate
+ * the image so that the point that is touched is what ends up centered at the end
+ * of the zoom.
+ * @param t
+ */
+ private void translateImageToCenterTouchPosition(float t) {
+ float targetX = startTouch.x + t * (endTouch.x - startTouch.x);
+ float targetY = startTouch.y + t * (endTouch.y - startTouch.y);
+ PointF curr = transformCoordBitmapToTouch(bitmapX, bitmapY);
+ matrix.postTranslate(targetX - curr.x, targetY - curr.y);
+ }
+
+ /**
+ * Use interpolator to get t
+ * @return
+ */
+ private float interpolate() {
+ long currTime = System.currentTimeMillis();
+ float elapsed = (currTime - startTime) / ZOOM_TIME;
+ elapsed = Math.min(1f, elapsed);
+ return interpolator.getInterpolation(elapsed);
+ }
+
+ /**
+ * Interpolate the current targeted zoom and get the delta
+ * from the current zoom.
+ * @param t
+ * @return
+ */
+ private double calculateDeltaScale(float t) {
+ double zoom = startZoom + t * (targetZoom - startZoom);
+ return zoom / normalizedScale;
+ }
+ }
+
+ /**
+ * This function will transform the coordinates in the touch event to the coordinate
+ * system of the drawable that the imageview contain
+ * @param x x-coordinate of touch event
+ * @param y y-coordinate of touch event
+ * @param clipToBitmap Touch event may occur within view, but outside image content. True, to clip return value
+ * to the bounds of the bitmap size.
+ * @return Coordinates of the point touched, in the coordinate system of the original drawable.
+ */
+ private PointF transformCoordTouchToBitmap(float x, float y, boolean clipToBitmap) {
+ matrix.getValues(m);
+ float origW = getDrawable().getIntrinsicWidth();
+ float origH = getDrawable().getIntrinsicHeight();
+ float transX = m[Matrix.MTRANS_X];
+ float transY = m[Matrix.MTRANS_Y];
+ float finalX = ((x - transX) * origW) / getImageWidth();
+ float finalY = ((y - transY) * origH) / getImageHeight();
+
+ if (clipToBitmap) {
+ finalX = Math.min(Math.max(finalX, 0), origW);
+ finalY = Math.min(Math.max(finalY, 0), origH);
+ }
+
+ return new PointF(finalX , finalY);
+ }
+
+ /**
+ * Inverse of transformCoordTouchToBitmap. This function will transform the coordinates in the
+ * drawable's coordinate system to the view's coordinate system.
+ * @param bx x-coordinate in original bitmap coordinate system
+ * @param by y-coordinate in original bitmap coordinate system
+ * @return Coordinates of the point in the view's coordinate system.
+ */
+ private PointF transformCoordBitmapToTouch(float bx, float by) {
+ matrix.getValues(m);
+ float origW = getDrawable().getIntrinsicWidth();
+ float origH = getDrawable().getIntrinsicHeight();
+ float px = bx / origW;
+ float py = by / origH;
+ float finalX = m[Matrix.MTRANS_X] + getImageWidth() * px;
+ float finalY = m[Matrix.MTRANS_Y] + getImageHeight() * py;
+ return new PointF(finalX , finalY);
+ }
+
+ /**
+ * Fling launches sequential runnables which apply
+ * the fling graphic to the image. The values for the translation
+ * are interpolated by the Scroller.
+ * @author Ortiz
+ *
+ */
+ private class Fling implements Runnable {
+
+ CompatScroller scroller;
+ int currX, currY;
+
+ Fling(int velocityX, int velocityY) {
+ setState(State.FLING);
+ scroller = new CompatScroller(context);
+ matrix.getValues(m);
+
+ int startX = (int) m[Matrix.MTRANS_X];
+ int startY = (int) m[Matrix.MTRANS_Y];
+ int minX, maxX, minY, maxY;
+
+ if (getImageWidth() > viewWidth) {
+ minX = viewWidth - (int) getImageWidth();
+ maxX = 0;
+
+ } else {
+ minX = maxX = startX;
+ }
+
+ if (getImageHeight() > viewHeight) {
+ minY = viewHeight - (int) getImageHeight();
+ maxY = 0;
+
+ } else {
+ minY = maxY = startY;
+ }
+
+ scroller.fling(startX, startY, (int) velocityX, (int) velocityY, minX,
+ maxX, minY, maxY);
+ currX = startX;
+ currY = startY;
+ }
+
+ public void cancelFling() {
+ if (scroller != null) {
+ setState(State.NONE);
+ scroller.forceFinished(true);
+ }
+ }
+
+ @Override
+ public void run() {
+
+ //
+ // OnTouchImageViewListener is set: TouchImageView listener has been flung by user.
+ // Listener runnable updated with each frame of fling animation.
+ //
+ if (touchImageViewListener != null) {
+ touchImageViewListener.onMove();
+ }
+
+ if (scroller.isFinished()) {
+ scroller = null;
+ return;
+ }
+
+ if (scroller.computeScrollOffset()) {
+ int newX = scroller.getCurrX();
+ int newY = scroller.getCurrY();
+ int transX = newX - currX;
+ int transY = newY - currY;
+ currX = newX;
+ currY = newY;
+ matrix.postTranslate(transX, transY);
+ fixTrans();
+ setImageMatrix(matrix);
+ compatPostOnAnimation(this);
+ }
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.GINGERBREAD)
+ private class CompatScroller {
+ Scroller scroller;
+ OverScroller overScroller;
+ boolean isPreGingerbread;
+
+ public CompatScroller(Context context) {
+ if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
+ isPreGingerbread = true;
+ scroller = new Scroller(context);
+
+ } else {
+ isPreGingerbread = false;
+ overScroller = new OverScroller(context);
+ }
+ }
+
+ public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) {
+ if (isPreGingerbread) {
+ scroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
+ } else {
+ overScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
+ }
+ }
+
+ public void forceFinished(boolean finished) {
+ if (isPreGingerbread) {
+ scroller.forceFinished(finished);
+ } else {
+ overScroller.forceFinished(finished);
+ }
+ }
+
+ public boolean isFinished() {
+ if (isPreGingerbread) {
+ return scroller.isFinished();
+ } else {
+ return overScroller.isFinished();
+ }
+ }
+
+ public boolean computeScrollOffset() {
+ if (isPreGingerbread) {
+ return scroller.computeScrollOffset();
+ } else {
+ overScroller.computeScrollOffset();
+ return overScroller.computeScrollOffset();
+ }
+ }
+
+ public int getCurrX() {
+ if (isPreGingerbread) {
+ return scroller.getCurrX();
+ } else {
+ return overScroller.getCurrX();
+ }
+ }
+
+ public int getCurrY() {
+ if (isPreGingerbread) {
+ return scroller.getCurrY();
+ } else {
+ return overScroller.getCurrY();
+ }
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ private void compatPostOnAnimation(Runnable runnable) {
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
+ postOnAnimation(runnable);
+
+ } else {
+ postDelayed(runnable, 1000/60);
+ }
+ }
+
+ private class ZoomVariables {
+ public float scale;
+ public float focusX;
+ public float focusY;
+ public ScaleType scaleType;
+
+ public ZoomVariables(float scale, float focusX, float focusY, ScaleType scaleType) {
+ this.scale = scale;
+ this.focusX = focusX;
+ this.focusY = focusY;
+ this.scaleType = scaleType;
+ }
+ }
+
+ private void printMatrixInfo() {
+ float[] n = new float[9];
+ matrix.getValues(n);
+ Log.d(DEBUG, "Scale: " + n[Matrix.MSCALE_X] + " TransX: " + n[Matrix.MTRANS_X] + " TransY: " + n[Matrix.MTRANS_Y]);
+ }
+}
\ No newline at end of file
-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
--- /dev/null
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " pdf to make PDF files"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html: html-org
+
+html-all: html-release html-org html-com
+
+html-release:
+ $(SPHINXBUILD) -b html -D html_theme='owncloud_release' $(ALLSPHINXOPTS) $(BUILDDIR)/html/release
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/release."
+
+html-org:
+ $(SPHINXBUILD) -b html -D html_theme='owncloud_org' $(ALLSPHINXOPTS) $(BUILDDIR)/html/org
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/org."
+
+html-com:
+ $(SPHINXBUILD) -b html -D html_theme='owncloud_com' $(ALLSPHINXOPTS) $(BUILDDIR)/html/com
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/com."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OwncloudDocumentation.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OwncloudDocumentation.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/OwncloudDocumentation"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OwncloudDocumentation"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+pdf:
+ $(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) $(BUILDDIR)/pdf
+ @echo
+ @echo "build finished. the text files are in $(BUILDDIR)/pdf."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "build finished. the text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
--- /dev/null
+==============================
+Using the ownCloud Android App
+==============================
+
+Accessing your files on your ownCloud server via the Web interface is easy and
+convenient, as you can use any Web browser on any operating system without
+installing special client software. However, the ownCloud Android app offers
+some advantages over the Web interface:
+
+* A simplified interface that fits nicely on a tablet or smartphone
+* Automatic synchronization of your files
+* Instant uploads of photos or videos recorded on your Android device
+* Easily add files from your device to ownCloud
+* Two-factor authentication
+
+Getting the ownCloud Android App
+--------------------------------
+
+One way to get your ownCloud Android app is to log into your ownCloud server
+from your Android device using a Web browser such as Chrome, Firefox, or
+Dolphin. The first time you log in to a new ownCloud account you'll see a screen
+with a download link to the ownCloud app in the `Google Play store
+<https://play.google.com/store/apps/details?id=com.owncloud.android>`_.
+
+.. figure:: images/android-first-screen.jpg
+
+You will also find these links on your Personal page in the Web interface,
+
+You can also get it from the `Amazon App store
+<http://www.amazon.com/ownCloud-Inc/dp/B00944PQMK/>`_, and get source code and
+more information from the `ownCloud download page
+<http://owncloud.org/install/#mobile>`_.
+
+Connecting to Your ownCloud Server
+----------------------------------
+
+The first time you run your ownCloud Android app it opens to a configuration
+screen. Enter your server URL, login name, password, and click the Connect
+button. (Click the eyeball to the right of your password to expose your
+password.)
+
+.. figure:: images/android-new-account.png
+
+For best security your ownCloud server should be SSL-enabled, so that you can
+connect via ``https``. The ownCloud app will test your connection as soon as
+you enter it and tell you if you entered it correctly. If your server has a
+self-signed SSL certificate you'll get a scary warning how it is not to be
+trusted. Click the OK button to accept the certificate and complete your account
+setup.
+
+.. figure:: images/android-ssl-cert.png
+
+Managing Files
+--------------
+
+Now you should see the Files page of your ownCloud account. Click the overflow
+button at the top right (that's the one with three vertical dots, and that is
+really what it is called) to open a user menu. ``Refresh account`` refreshes the
+page view. ``Settings`` take you to your settings menu. ``Sort`` gives you the
+option to sort your files by date, or alphabetically.
+
+.. figure:: images/android-files-page.png
+
+The little file folder icon to the left of the overflow button opens a dialog to
+create a new folder. The arrow button opens a file upload dialog, and you can
+either upload content from other Android apps such as Google Drive, the Gallery,
+your music player, or from your Android filesystem. When you add a new file
+you will see a confirmation on the top left when it has uploaded successfully,
+and it is immediately synchronized with the server.
+
+.. figure:: images/android-upload.png
+
+All files (that you have permission to access) on your ownCloud server are
+displayed in your Android app, but are not downloaded until you download them.
+Downloaded files are marked with a green arrow.
+
+.. figure:: images/android-file-list.png
+
+Download and preview a file with a short press on the filename. When the file
+is in preview mode, a short press on the overflow button opens a menu with
+options for sharing, opening with an app, removing, sending, and displaying file
+details.
+
+.. figure:: images/android-file.png
+
+
+A long press on the filename does not download it, but opens a dialog with
+options for sharing, downloading, renaming, moving, removing, sending, and
+viewing file details.
+
+
+.. figure:: images/android-file-options.png
+
+
+Settings
+--------
+
+The Settings screen offers a number of useful options. In the Accounts
+section you can configure multiple ownCloud accounts.
+
+The Security section sets up strong two-factor authentication by allowing you
+to add a PIN (personal identification number) to access your account.
+
+The Instant Uploads section creates a directory, :file:`/InstantUpload`, and
+any photos or videos created with your Android device's camera are instantly
+uploaded to this directory. You also have the option to choose any other
+existing directory. Another nice option is Upload Pictures/Video via WiFi Only,
+to conserve your Internet data usage.
+
+.. figure:: images/android-settings.png
+
+The bottom section of the Settings screen has links to help and the
+app's version number.
+
+.. figure:: images/android-help.png
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# ownCloud Documentation documentation build configuration file, created by
+# sphinx-quickstart on Mon Oct 22 23:16:40 2012.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os, inspect
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+#path to this script
+scriptpath = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.todo']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = [scriptpath+'/ocdoc/_shared_assets/templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'ownCloud Android App Manual'
+copyright = u'2013-2015, The ownCloud developers'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '1.6.2'
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build','scripts/*', 'ocdoc/*']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+2
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = [scriptpath+'/ocdoc/_shared_assets/themes']
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#html_theme = 'bootstrap'
+html_theme = 'default'
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+html_short_title = "Android App Manual"
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = [scriptpath+'/ocdoc/_shared_assets/static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+html_show_sphinx = False
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'ownCloudAndroidAppManual'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'ownCloudAndroidAppManual.tex', u'ownCloud Android App Manual',
+ u'The ownCloud developers', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('owncloud.1', 'owncloud', u'Android synchronisation and file management utility.',
+ [u'The ownCloud developers'], 1),
+ ('owncloudcmd.1', 'owncloudcmd', u'ownCloud Android app.',
+ [u'The ownCloud developers'], 1),
+]
+
+# If true, show URL addresses after external links.
+man_show_urls = True
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'ownCloudClientManual', u'ownCloud Android App Manual',
+ u'The ownCloud developers', 'ownCloud', 'The ownCloud Android App Manual.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# -- Options for Epub output ---------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = u'ownCloud Android App Manual'
+epub_author = u'The ownCloud developers'
+epub_publisher = u'The ownCloud developers'
+epub_copyright = u'2013-2015, The ownCloud developers'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+#epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#epub_identifier = ''
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# A tuple containing the cover image and cover page html template filenames.
+#epub_cover = ()
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+#epub_exclude_files = []
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
+
+# Include todos?
+todo_include_todos = True
--- /dev/null
+.. _contents:
+
+ownCloud Android App Manual
+==============================
+
+.. toctree::
+ :maxdepth: 2
+
+ android_app
--- /dev/null
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pdf to make a PDF file with rst2pdf
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pdf" (
+ %SPHINXBUILD% -b pdf %ALLSPHINXOPTS% %BUILDDIR%/pdf
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The PDF file is in %BUILDDIR%/pdf.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OwncloudDocumentation.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OwncloudDocumentation.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
--- /dev/null
+Subproject commit 343496c792616459e8204b6614fd42a1b16a6d68