diff --git a/.classpath b/.classpath new file mode 100644 index 000000000..d2ce7e889 --- /dev/null +++ b/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/.fdmeta b/.fdmeta new file mode 100644 index 000000000..3c439de9f --- /dev/null +++ b/.fdmeta @@ -0,0 +1,7 @@ +Web Site:https://f-droid.org +Source Code:https://gitorious.org/f-droid/fdroidclient +Issue Tracker:https://f-droid.org/repository/issues + +Donate:https://f-droid.org/about +FlattrID:343053 +Bitcoin:15u8aAPK4jJ5N8wpWJ5gutAyyeHtKX5i18 diff --git a/.gitignore b/.gitignore index 4f54aeced..22273c3f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ /local.properties -/.classpath /bin/ /gen/ /build/ @@ -9,3 +8,4 @@ /.idea/ /*.iml out +/.settings/ diff --git a/.gitmodules b/.gitmodules index ca1aa6458..b54d0200a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,12 @@ [submodule "extern/Universal-Image-Loader"] - path = extern/Universal-Image-Loader + path = extern/UniversalImageLoader url = https://github.com/nostra13/Android-Universal-Image-Loader - ignore = dirty + ignore = dirty +[submodule "extern/MemorizingTrustManager"] + path = extern/MemorizingTrustManager + url = https://github.com/ge0rg/MemorizingTrustManager.git + ignore = dirty +[submodule "extern/AndroidPinning"] + path = extern/AndroidPinning + url = https://github.com/binaryparadox/AndroidPinning.git + ignore = dirty diff --git a/Android.mk b/Android.mk new file mode 100644 index 000000000..b15a70425 --- /dev/null +++ b/Android.mk @@ -0,0 +1,23 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_PACKAGE_NAME := F-Droid +LOCAL_CERTIFICATE := platform +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := \ + $(call all-java-files-under, src) \ + $(call all-java-files-under, extern/MemorizingTrustManager/src) \ + $(call all-java-files-under, extern/AndroidPinning/src) \ + $(call all-java-files-under, extern/UniversalImageLoader/library/src ) + +res_dirs = res extern/MemorizingTrustManager/res extern/AndroidPinning/res +LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs)) + +LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4 + +LOCAL_AAPT_FLAGS := --auto-add-overlay +LOCAL_AAPT_FLAGS += --extra-packages org.fdroid.fdroid:de.duenndns.ssl:org.thoughtcrime.ssl.pinning + +LOCAL_PRIVILEGED_MODULE := true +include $(BUILD_PACKAGE) + diff --git a/AndroidManifest.xml b/AndroidManifest.xml index a71ffa736..620575958 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="640" + android:versionName="0.64-test" > + + + + + + @@ -36,9 +48,31 @@ android:label="@string/app_name" android:allowBackup="true" android:theme="@style/AppThemeDark" - android:supportsRtl="false" > + android:supportsRtl="true" > + + + + + + + + + @@ -66,9 +100,8 @@ + + @@ -111,15 +150,47 @@ + + + + + + + + + + + + + - + + + + + + + + - + android:label="@string/menu_manage" + android:parentActivityName=".ManageRepo" + android:windowSoftInputMode="stateHidden" /> + + + + @@ -212,10 +286,22 @@ - + - + + + + + + + + + + + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 760fe9829..6719fbf4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,57 @@ ### Upcoming release +* Fix crash on startup for devices with more than 500 installed apps + +* Send apps to other devices directly from the App Details screen via NFC or Bluetooth + +* Improved performance for devices with many installed apps + +* Improve ellipsizing and spacing in the app lists + +* Start translating the category lists + +* Keep track of installed apps internally, rather than asking Android each time + +* Fix some crashes + +* Translation updates + +### 0.63 (2014-04-07) + +* Support for Network Service Discovery of local FDroid repos on Android 4.1+ + from the repository management screen + +* Always remember the selected category in the list of apps + +* Send FDroid via Bluetooth to any device that supports receiving APKs via + Bluetooth (stock Android blocks APKs, most ROMs allow them) + +* NFC support: beam repo configs from the repo detail view (Android 4.0+), + beam the FDroid.apk from FDroid's main screen (Android 4.1+) + +* Support for repositories using self-signed HTTPS certificates through + a Trust-on-first-use popup + +* Support for TLS Subject-Public-Key-Identifier pinning + +* Add native Right-to-Left support on devices running 4.2 and later + +* Filter app compatibility by maxSdkVersion too + +* Major internal changes to enable F-Droid to handle repos with thousands + of apps without slowing down too much. These internal changes will also make + new features easier to implement. + +* Various fixes to layout issues introduced in 0.58 + +* Translation updates + +### 0.58 (2014-01-11) + +* Download icons with a resolution that matches the device's screen density, + which saves resources on smaller devices and gets rid of unnecessary + blurriness on larger devices + * Tweaked some layouts, especially the app lists and their compact layout * App lists now show more useful version information: current version names, @@ -10,13 +62,13 @@ * Slightly increase performance in repo index XML handling by mapping apps with a HashMap, as opposed to doing linear searches -* More info on App Details: The category in which the app was found, all the - categories the app is in and the Android version required to run each one of - its versions available. +* More app info shown in App Details: The category in which the app was found + and all the categories the app is in, as well as the Android version + required to run each one of its versions available * The preferences screen now uses descriptive summaries, which means that you can see what the checkbox preferences actually mean and what the edit and - list preferences are set at. + list preferences are set at * Support for dogecoin donation method added (wow) @@ -27,6 +79,14 @@ * Fixed a crash when trying to access a non-existing app +* F-Droid registers with Android to receive F-Droid URIs https://\*/fdroid/repo + and fdroidrepos:// + +* support including signing key fingerprint in repo URIs + +* when adding new repos that include the fingerprint, check to see whether + that repo exists in F-Droid already, and if the fingerprints match + * Other minor bug fixes * Lots of translation updates @@ -34,6 +94,7 @@ ### 0.55 (2013-11-11) * Fixed problems with category selection and permission lists on Android 2.X devices. + * Lots of translation updates, including new Norwegian translation. ### 0.54 (2013-11-05) diff --git a/README.md b/README.md index 718c54b73..e73703c69 100644 --- a/README.md +++ b/README.md @@ -10,19 +10,42 @@ Building from source The only required tools are the Android SDK and Apache Ant. +Once you have checked out the version you wish to build, run: + ``` git submodule update --init -android update project -p . -android update project -p extern/Universal-Image-Loader/library +./ant-prepare.sh # This runs 'android update' on the libs and the main project ant clean release ``` +The project itself supports Gradle, but some of the libraries it uses don't. +Hence it is currently not possible to build F-Droid with Gradle in a clean way +without manual interaction. + +Building as part of a ROM +------------------------- + +Add the following lines to your repo manifest: + +``` + + + + + + + + +``` + +Adding F-Droid is then just a matter of adding `F-Droid` to your `PRODUCT_PACKAGES`. Direct download --------------- You can [download the application](https://f-droid.org/FDroid.apk) directly -from our site. +from our site or [browse it in the +repo](https://f-droid.org/app/org.fdroid.fdroid). Contributing @@ -36,12 +59,32 @@ and our [Forums](https://f-droid.org/forums/). Translating ----------- -The `locale` dir is automatically updated via the -[android2po](https://github.com/miracle2k/android2po) tool, and translations -are pulled from our Pootle translation server at -[f-droid.org/translate](https://f-droid.org/translate). You should only add or -remove strings in the `res/values/` dir, since all the `res/values-*` dirs are -also generated automatically. +The `res/values-*` dirs are kept up to date automatically via [MediaWiki's +Translate Extension](http://www.mediawiki.org/wiki/Extension:Translate). See +[our translation page](https://f-droid.org/wiki/page/Special:Translate) if you +would like to contribute. + + +Running the test suite +---------------------- + +FDroid client includes a embedded Android Test Project for running tests. It +is in the `test/` subfolder. To run the tests from the command line, do: + +``` +git submodule update --init +./ant-prepare.sh # This runs 'android update' on the libs and the main project +ant clean emma debug install test +``` + +You can also run the tests in Eclipse. Here's how: + +1. Choose *File* -> *Import* -> *Android* -> *Existing Android Code Into Workspace* for the `fdroidclient/` directory. +2. Choose *File* -> *Import* -> *Android* -> *Existing Android Code Into Workspace* for the `fdroidclient/test/` directory +3. If **fdroid-test** has errors, right-click on it, select *Properties*, the +*Java Build Path*, then click on the *Projects* tab. +4. Click on the *Add...* button and select `fdroidclient/` +5. Right-click on the **fdroid-test** project, then *Run As...* -> *Android JUnit Test* License diff --git a/ant-prepare.sh b/ant-prepare.sh new file mode 100755 index 000000000..299d005e9 --- /dev/null +++ b/ant-prepare.sh @@ -0,0 +1,10 @@ +#!/bin/bash -ex + +android update lib-project --path extern/UniversalImageLoader/library +android update lib-project --path extern/AndroidPinning +android update lib-project --path extern/MemorizingTrustManager +android update project --path . --name F-Droid + +# technically optional, needed for the tests +cd test +android update test-project --path . --main .. diff --git a/build.properties b/ant.properties similarity index 100% rename from build.properties rename to ant.properties diff --git a/build.gradle b/build.gradle index a64f6146c..e15c643a0 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:0.7.+' + classpath 'com.android.tools.build:gradle:0.9.1' } } @@ -11,16 +11,47 @@ apply plugin: 'android' dependencies { compile files('libs/android-support-v4.jar') + compile project(':extern:AndroidPinning') + compile project(':extern:UniversalImageLoader:library') + compile project(':extern:MemorizingTrustManager') +} + +project(':extern:UniversalImageLoader:library') { + buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:0.9.1' + } + } + + apply plugin: 'android' + + android { + compileSdkVersion 16 + buildToolsVersion '19.0.3' + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + resources.srcDirs = ['src'] + aidl.srcDirs = ['src'] + renderscript.srcDirs = ['src'] + } + } + } } android { compileSdkVersion 19 - buildToolsVersion "19.0.1" + buildToolsVersion '19.0.3' sourceSets { main { manifest.srcFile 'AndroidManifest.xml' - java.srcDirs = ['src', 'extern/Universal-Image-Loader/library/src'] + java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] @@ -28,14 +59,13 @@ android { assets.srcDirs = ['assets'] } - instrumentTest.setRoot('tests') + instrumentTest.setRoot('test') } buildTypes { release { runProguard true - proguardFile 'proguard-project.txt' - proguardFile getDefaultProguardFile('proguard-android.txt') + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' } } diff --git a/custom_rules.xml b/custom_rules.xml new file mode 100644 index 000000000..7747834aa --- /dev/null +++ b/custom_rules.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/extern/AndroidPinning b/extern/AndroidPinning new file mode 160000 index 000000000..ce84a19e7 --- /dev/null +++ b/extern/AndroidPinning @@ -0,0 +1 @@ +Subproject commit ce84a19e753bbcc3304525f763edb7d7f3b62429 diff --git a/extern/MemorizingTrustManager b/extern/MemorizingTrustManager new file mode 160000 index 000000000..a705441ac --- /dev/null +++ b/extern/MemorizingTrustManager @@ -0,0 +1 @@ +Subproject commit a705441ac53b9e1aba9f00f3f59aab81da6fbc9e diff --git a/extern/Universal-Image-Loader b/extern/Universal-Image-Loader deleted file mode 160000 index 1c2a91e46..000000000 --- a/extern/Universal-Image-Loader +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1c2a91e464b49874068a8bf2a6e39d39aae9208a diff --git a/extern/UniversalImageLoader b/extern/UniversalImageLoader new file mode 160000 index 000000000..ee50fd1ce --- /dev/null +++ b/extern/UniversalImageLoader @@ -0,0 +1 @@ +Subproject commit ee50fd1ce77d866a89374a5ff0886be6e179feb2 diff --git a/libs/README.android-support-v4.txt b/libs/README.android-support-v4.txt index 8c280042c..f1fb7995c 100644 --- a/libs/README.android-support-v4.txt +++ b/libs/README.android-support-v4.txt @@ -1,5 +1,5 @@ -The Android support library v4 is currently at *revision 19* from the Android SDK. -This reversion was released on October 2013. +The Android support library v4 is currently at *revision 19.1* from the Android SDK. +This reversion was released on March 2014. See NOTICE.android-support-v4.txt for license. See http://developer.android.com/tools/extras/support-library.html for further info. diff --git a/libs/android-support-v4.jar b/libs/android-support-v4.jar index 7dad0a742..187bdf48b 100644 Binary files a/libs/android-support-v4.jar and b/libs/android-support-v4.jar differ diff --git a/lint.xml b/lint.xml index 0d7c55dda..e067210a5 100644 --- a/lint.xml +++ b/lint.xml @@ -5,6 +5,9 @@ + + + diff --git a/project.properties b/project.properties index 9d03d0bbe..d6e5f072f 100644 --- a/project.properties +++ b/project.properties @@ -2,4 +2,6 @@ proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project. target=android-19 -android.library.reference.1=extern/Universal-Image-Loader/library +android.library.reference.1=extern/UniversalImageLoader/library +android.library.reference.2=extern/MemorizingTrustManager +android.library.reference.3=extern/AndroidPinning diff --git a/res/drawable-hdpi/ic_repo_app_default.png b/res/drawable-hdpi/ic_repo_app_default.png index 6efe7764a..798531939 100644 Binary files a/res/drawable-hdpi/ic_repo_app_default.png and b/res/drawable-hdpi/ic_repo_app_default.png differ diff --git a/res/drawable-ldpi/ic_repo_app_default.png b/res/drawable-ldpi/ic_repo_app_default.png index 6d3ce44ee..47f30b576 100644 Binary files a/res/drawable-ldpi/ic_repo_app_default.png and b/res/drawable-ldpi/ic_repo_app_default.png differ diff --git a/res/drawable-mdpi/ic_repo_app_default.png b/res/drawable-mdpi/ic_repo_app_default.png index d10bbdeaf..8c9d250ab 100644 Binary files a/res/drawable-mdpi/ic_repo_app_default.png and b/res/drawable-mdpi/ic_repo_app_default.png differ diff --git a/res/drawable-xhdpi/ic_repo_app_default.png b/res/drawable-xhdpi/ic_repo_app_default.png index 0447333e6..b224d0a2e 100644 Binary files a/res/drawable-xhdpi/ic_repo_app_default.png and b/res/drawable-xhdpi/ic_repo_app_default.png differ diff --git a/res/drawable-xxhdpi/ic_repo_app_default.png b/res/drawable-xxhdpi/ic_repo_app_default.png index 15577b09a..6f72988d0 100644 Binary files a/res/drawable-xxhdpi/ic_repo_app_default.png and b/res/drawable-xxhdpi/ic_repo_app_default.png differ diff --git a/res/layout-land/appdetails.xml b/res/layout-land/appdetails.xml index 53c06af43..9f91b96ff 100644 --- a/res/layout-land/appdetails.xml +++ b/res/layout-land/appdetails.xml @@ -16,6 +16,7 @@ android:layout_height="wrap_content" android:padding="5dp" android:layout_marginRight="4dp" + android:layout_marginEnd="4dp" android:orientation="vertical" > + android:scaleType="fitCenter" + /> @@ -39,6 +42,7 @@ @@ -58,6 +62,7 @@ diff --git a/res/layout/addrepo.xml b/res/layout/addrepo.xml index 667bf02fa..665d4fe8c 100644 --- a/res/layout/addrepo.xml +++ b/res/layout/addrepo.xml @@ -37,6 +37,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:drawableLeft="@android:drawable/ic_dialog_alert" + android:drawableStart="@android:drawable/ic_dialog_alert" android:drawablePadding="20dp" android:padding="20dp" android:text="@string/repo_delete_to_overwrite" diff --git a/res/layout/apklistitem.xml b/res/layout/apklistitem.xml index 33f287673..6208b3af2 100644 --- a/res/layout/apklistitem.xml +++ b/res/layout/apklistitem.xml @@ -31,6 +31,7 @@ @@ -39,6 +40,7 @@ android:textSize="13sp" android:layout_below="@id/buildtype" android:layout_alignParentRight="true" + android:layout_alignParentEnd="true" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_marginBottom="4sp" /> @@ -47,7 +49,9 @@ android:textSize="13sp" android:layout_below="@id/buildtype" android:layout_toLeftOf="@id/size" + android:layout_toStartOf="@id/size" android:layout_marginRight="16sp" + android:layout_marginEnd="16sp" android:layout_height="wrap_content" android:layout_width="wrap_content" /> @@ -55,6 +59,15 @@ android:textSize="13sp" android:layout_below="@id/size" android:layout_alignParentRight="true" + android:layout_alignParentEnd="true" + android:layout_height="wrap_content" + android:layout_width="wrap_content" /> + + diff --git a/res/layout/appdetails.xml b/res/layout/appdetails.xml index 455466134..25ce76664 100644 --- a/res/layout/appdetails.xml +++ b/res/layout/appdetails.xml @@ -6,25 +6,32 @@ android:baselineAligned="false" android:orientation="vertical" > - + android:baselineAligned="false" > + android:scaleType="fitCenter" + /> + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_toRightOf="@id/icon" + android:layout_toEndOf="@id/icon" + android:padding="5dp" + android:baselineAligned="false" + android:orientation="vertical" + > - - + android:layout_alignParentEnd="true" + android:singleLine="true" + android:ellipsize="end" + android:layout_marginLeft="6sp" + android:layout_marginStart="6sp" + android:textSize="12sp" + /> + android:layout_alignParentStart="true" + android:textAlignment="viewStart" + android:layout_toLeftOf="@id/license" + android:layout_toStartOf="@id/license" /> + + + android:layout_alignParentStart="true" + android:textAlignment="viewStart" + android:layout_toLeftOf="@id/categories" + android:layout_toStartOf="@id/categories" + android:layout_below="@id/title" /> + + - + @@ -16,7 +17,7 @@ android:id="@+id/appid" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:textSize="13sp" /> + android:textSize="12sp" /> diff --git a/res/layout/applistitem.xml b/res/layout/applistitem.xml index 5711f5fdd..449d974bd 100644 --- a/res/layout/applistitem.xml +++ b/res/layout/applistitem.xml @@ -1,72 +1,99 @@ - - + /> - - + android:baselineAligned="false" + android:layout_marginBottom="3dp" + > - + + + + + + + android:baselineAligned="false" + > - + - + - + - + + + diff --git a/res/layout/repo_item.xml b/res/layout/repo_item.xml index 58d983d18..971a70b30 100644 --- a/res/layout/repo_item.xml +++ b/res/layout/repo_item.xml @@ -12,10 +12,14 @@ http://syedasaraahmed.wordpress.com/2012/10/03/android-onitemclicklistener-not-responding-clickable-rowitem-of-custom-listview/ --> - + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + /> + android:layout_toEndOf="@id/img" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true"/> + android:paddingStart="@dimen/padding_side" + android:paddingRight="@dimen/padding_side" + android:paddingEnd="@dimen/padding_side"> + android:id="@+id/text_repo_fingerprint" + android:layout_below="@id/label_repo_fingerprint" android:textStyle="bold"/> + android:id="@+id/text_repo_fingerprint_description" + android:layout_below="@id/text_repo_fingerprint"/> - \ No newline at end of file + diff --git a/res/layout/repodiscoveryitem.xml b/res/layout/repodiscoveryitem.xml new file mode 100644 index 000000000..c7fc54f88 --- /dev/null +++ b/res/layout/repodiscoveryitem.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/res/layout/repodiscoverylist.xml b/res/layout/repodiscoverylist.xml new file mode 100644 index 000000000..cdd85147d --- /dev/null +++ b/res/layout/repodiscoverylist.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/repolist.xml b/res/layout/repolist.xml deleted file mode 100644 index de08ca0f8..000000000 --- a/res/layout/repolist.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - diff --git a/res/layout/repolisticons.xml b/res/layout/repolisticons.xml index 0c42a3627..8f5d10e07 100644 --- a/res/layout/repolisticons.xml +++ b/res/layout/repolisticons.xml @@ -6,9 +6,12 @@ android:layout_height="wrap_content" android:orientation="horizontal"> - + android:layout_height="wrap_content" + /> \ No newline at end of file +--> diff --git a/res/layout/searchresults.xml b/res/layout/searchresults.xml index b7ddbba70..41ba64b45 100644 --- a/res/layout/searchresults.xml +++ b/res/layout/searchresults.xml @@ -3,7 +3,9 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" android:paddingLeft="2dp" + android:paddingStart="2dp" android:paddingRight="2dp" + android:paddingEnd="2dp" android:baselineAligned="false" android:orientation="vertical"> diff --git a/res/values-ar/array.xml b/res/values-ar/array.xml index 6b1fbe25d..f26ac258c 100644 --- a/res/values-ar/array.xml +++ b/res/values-ar/array.xml @@ -11,9 +11,4 @@ غامق فاتح - - معطل (غير آمن) - عادي - مكتمل - diff --git a/res/values-bg/array.xml b/res/values-bg/array.xml index d7738bcf9..e81f9ad28 100644 --- a/res/values-bg/array.xml +++ b/res/values-bg/array.xml @@ -11,9 +11,4 @@ Dark Light - - Изключено (опасно) - Нормално - Пълно - diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index bb8ac1dd4..de283c920 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -73,7 +73,6 @@ Дисплей Експерт Търсене на приложения - Вид на синхронизация на базата данни Съвместимост на приложенията Root достъп Игнорирай сензорния екран diff --git a/res/values-ca/array.xml b/res/values-ca/array.xml index 4ea57069f..01d48006c 100644 --- a/res/values-ca/array.xml +++ b/res/values-ca/array.xml @@ -11,9 +11,4 @@ Fosc Clar - - Desactivat (no segur) - Normal - Complet - diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 087d66546..d909991ef 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -7,6 +7,8 @@ Sembla que aquest paquet no és compatible amb el vostre dispositiu. Voleu provar a instaŀlar-lo de totes maneres? Aneu a desactualitzar aquesta aplicació. Això podria fer que l\'aplicació no funcionés o inclús es perdessin les vostres dades. Esteu segur que ho voleu fer? Versió + Editar + Esborrar Memòria cau de les aplicacions baixades Actualitzacions Altres @@ -29,7 +31,7 @@ Publicat amb la llicència GNU GPL v3. Un dipòsit és una font d\'aplicacions. Per afegir-ne un, premeu ara el botó MENÚ i entreu la seva URL. -L\'adreça d\'un dipòsit té un aspecte com ara: http://f-droid.org/repo +L\'adreça d\'un dipòsit té un aspecte com ara: https://f-droid.org/repo Instal·lat No està instal·lat S\'ha afegit a %s @@ -39,6 +41,9 @@ L\'adreça d\'un dipòsit té un aspecte com ara: http://f-droid.org/repoAfegeix un nou dipòsit Afegeix Anul·la + Permès + Afegeix clau + Sobreescriu Trieu el dipòsit que voleu suprimir Actualitza els dipòsits Disponible @@ -50,6 +55,7 @@ L\'adreça d\'un dipòsit té un aspecte com ara: http://f-droid.org/repoS\'està actualitzant la llista d\'aplicacions… S\'està obtenint l\'aplicació des de Adreça del dipòsit + Aquest dipòsit ja existeix. La llista de dipòsits ha canviat. La voleu actualitzar? Actualitza els dipòsits @@ -59,6 +65,7 @@ La voleu actualitzar? Cerca Nou dipòsit Suprimeix el dipòsit + Cerca dipòsits locals Executa Comparteix Instal·la @@ -82,7 +89,6 @@ La voleu actualitzar? Pantalla Usuari expert Cerca aplicacions - Mode de sincronització de la base de dades Compatibilitat de les aplicacions Versions incompatibles Root @@ -105,4 +111,10 @@ La voleu actualitzar? No teniu cap aplicació disponible que pugui gestionar %s Vista compacta Tema + URL + Número d\'aplicacions + Descripció + Actualitzant + Nom + Esborrar dipòsit? diff --git a/res/values-de/array.xml b/res/values-de/array.xml index cd7204197..722843fd8 100644 --- a/res/values-de/array.xml +++ b/res/values-de/array.xml @@ -11,9 +11,4 @@ Dunkel Hell - - Aus (unsicher) - Normal - Vollständig - diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index e184664e1..ef5b17981 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -7,14 +7,26 @@ Es sieht so aus, als sei dieses Paket mit Ihrem Gerät nicht kompatibel. Möchten Sie trotzdem versuchen es zu installieren? Sie versuchen eine vorherige Version einer bereits installierten Anwendung zu installieren. Dies kann zu Fehlverhalten der Anwendung und gegebenenfalls zu Datenverlust führen. Möchten Sie dennoch fortfahren? Version - Heruntergeladene Anwendungen zwischenspeichern + Bearbeiten + Löschen + NFC-Transfer aktivieren … + Anwendungszwischenspeicher + Heruntergeladene Programmpakete auf der SD-Karte behalten + Installationsdateien nicht behalten Aktualisierungen Andere Letzte Aktualisierung der Paketquellen: %s niemals + Automatischer Aktualisierungsintervall + Keine automatischen Aktualisierungen der Anwendungsliste Nur über WLAN + Anwendungsliste nur über WLAN automatisch aktualisieren + Anwendungsliste immer automatisch aktualisieren Benachrichtigen + Benachrichtigen, wenn Aktualisierungen verfügbar sind + Über Aktualisierungen nicht benachrichtigen Aktualisierungsverlauf + Anzahl in Tagen, an denen neue oder kürzlich geänderte Anwendungen angezeigt werden: %s Suchergebnisse Anwendungsdetails Keine passende Anwendung gefunden @@ -30,7 +42,7 @@ Veröffentlicht unter der GNU GPLv3 Lizenz. Eine Paketquelle ist eine Sammlung von Anwendungen. Um eine Paketquelle hinzuzufügen drücken Sie jetzt den Menüknopf und geben Sie deren Adresse an. -Die Adresse einer Paketquelle sieht etwa so aus: https://f-droid.org/repo +Die Adresse einer Paketquelle könnte wie folgt aussehen: https://f-droid.org/repo Installiert Nicht installiert Hinzugefügt am %s @@ -53,28 +65,35 @@ Die Adresse einer Paketquelle sieht etwa so aus: https://f-droid.org/repoBitte warten Anwendungsliste wird aktualisiert … Anwendung wird heruntergeladen von + NFC ist deaktiviert! + NFC-Einstellungen öffnen … + Keine Bluetooth-Sendemethode gefunden. Bitte wählen Sie eine aus! + Bluetooth-Sendemethode auswählen Adresse der Paketquelle Fingerabdruck (optional) Diese Paketquelle existiert bereits! Diese Paketquelle ist bereits eingerichtet, dieses wird neue Schlüsselinformationen hinzuzufügen. Diese Paketquelle ist bereits eingerichtet, bestätigen, dass Sie diese wieder aktivieren möchten. Die eingehende Paketquelle ist bereits eingerichtet und aktiviert! - Sie müssen zuerst diese Paketquelle löschen, bevor Sie eine mit einem anderen Schlüssel hinzuzufügen! + Sie müssen diese Paketquelle zuerst löschen, bevor Sie eine mit einem anderen Schlüssel hinzuzufügen! + Fehlerhafte Paketquellenadresse ignorieren: %s Die Liste der genutzten Paketquellen hat sich geändert. Sollen diese aktualisiert werden? Paketquellen aktualisieren Paketquellen verwalten + Bluetooth-FDroid.apk … Einstellungen Über Suchen Paketquelle hinzufügen Paketquelle entfernen + Lokale Paketquellen finden Starten Empfehlen Installieren Entfernen - Alle Aktualisierungen ignorieren - Diese Aktualisierung ignorieren + Alle Aktua. ignorieren + Diese Aktua. ignorieren Internetseite Probleme Quelltext @@ -88,19 +107,28 @@ Sollen diese aktualisiert werden? Diese Anwendung verfolgt und versendet Ihre Aktivitäten Diese Anwendung bewirbt nicht freie Erweiterungen Diese Anwendung bewirbt nicht freie Netzwerkdienste - Diese Anwendung hängt ab von nicht freien Anwendungen + Diese Anwendung hängt von nicht freien Anwendungen ab Der Originalcode ist nicht völlig frei Anzeige Experte + Zusätzliche Informationen anzeigen und zusätzliche Einstellungen aktivieren + Experteneinstellungen ausblenden Anwendungen suchen - Datenbanksynchronisierungsart Kompatibilität der Anwendung Inkompatible Versionen + Mit diesem Gerät inkompatible Anwendungsversionen anzeigen + Mit diesem Gerät inkompatible Anwendungsversionen ausblenden Root + Anwendungen, die Root-Rechte verlangen, nicht ausgrauen + Anwendungen ausgrauen, welche Root-Rechte verlangen Touchscreen ignorieren + Anwendungen, die einen Touchscreen benötigen, anzeigen + Anwendungen normal filtern Alle Was gibt es Neues Kürzlich Aktualisiert + Lokale F-Droid-Paketquellen + Lokale F-Droid-Paketquellen entdecken … Herunterladen %2$s / %3$s (%4$d%%) von %1$s @@ -110,10 +138,52 @@ Sollen diese aktualisiert werden? Verbinden mit %1$s Kompatibilität mit Ihrem Gerät wird überprüft … + App-Details speichern (%1$d%%) Es werden keine Berechtigungen verwendet. Berechtigungen für Version %s Berechtigungen anzeigen + Eine Liste mit Berechtigungen, die von einer Anwendung verlangt werden, anzeigen + Zugriffsrechte nicht vor dem Herunterladen anzeigen Es ist keine Anwendung installiert, die mit %s umgehen kann Kompakte Ansicht + Symbole in einer kleineren Größe anzeigen + Symbole in normaler Größe anzeigen Thema + Nicht signiert + Adresse + Anwendungsanzahl + Fingerabdruck des Paketquellensignaturschlüssels (SHA-256) + Beschreibung + Letzte Aktualisierung + Aktualisierung + Name + Das bedeutet, dass die Liste von + Anwendungen nicht verifiziert werden konnte. + Sie sollten sorgsam mit Anwendungen, heruntergeladen + aus nicht nicht signierten Quellen, sein. + Diese Paketquelle wurde noch nicht benutzt. + Um beinhaltende Anwendungen anzuzeigen, muss diese Paketquelle + zuvor aktualisiert werden. + +Nach der Aktualisierung sind die Beschreibungen und andere Details + hier zu finden. + Möchten Sie die »{0}« + Paketquelle löschen, die {1} Anwendungen beinhaltet? Alle installierten Apps werden + NICHT entfernt. Allerdings werden diese nicht mehr über F-Droid aktualisiert. + Unbekannt + Paketquelle löschen? + Das Löschen einer Paketquelle bedeutet, + dass die Anwendungen daraus nicht mehr in F-Droid verfügbar sein werden. + +Bemerkung: Alle + zuvor installierten Anwendungen bleiben auf Ihrem Gerät. + »%1$s« deaktiviert. + +Sie müssen + diese Paketquelle wieder aktivieren, um Anwendungen daraus installieren zu können. + %s oder später + bis zu %s + %1$s bis zu %2$s + Dieses Gerät befindet sich nicht im selben WLAN, wie die eben hinzugefügte Paketquelle. Versuchen Sie sich mit dem folgenden Netzwerk zu verbinden: %s + Erfordert: %1$s diff --git a/res/values-el/array.xml b/res/values-el/array.xml index 27b24978d..2f02e1184 100644 --- a/res/values-el/array.xml +++ b/res/values-el/array.xml @@ -11,9 +11,4 @@ Σκοτεινό Φωτεινό - - Απενεργοποίηση (επισφαλής) - Κανονικό - Ολόκληρο - diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index b7eef575a..b161b91bf 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -29,7 +29,7 @@ Ένα αποθετήριο είναι μια πηγή εφαρμογών. Για να προσθέσετε κάποιο, πιέστε το πλήκτρο ΜΕΝΟΥ και εισάγετε το URL. -Μια διεύθυνση αποθετηρίου μοιάζει κάπως έτσι: http://f-droid.org/repo +Μια διεύθυνση αποθετηρίου μοιάζει κάπως έτσι: https://f-droid.org/repo Εγκατεστημένο Δεν είναι εγκατεστημένο Προστέθηκε στις %s @@ -59,6 +59,7 @@ Αναζήτηση Νέο Αποθετήριο Αφαίρεση Αποθετηρίου + Εύρεση τοπικών αποθετηρίων Εκτέλεση Διαμοιρασμός Εγκατάσταση @@ -82,7 +83,6 @@ Εμφάνιση Για Προχωρημένους Αναζήτηση εφαρμογών - Λειτουργία συγχρονισμόυ της βάσης δεδομένων Συμβατότητα εφαμοργής Μη συμβατές εκδόσεις Root diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml new file mode 100644 index 000000000..13423d61a --- /dev/null +++ b/res/values-en-rGB/strings.xml @@ -0,0 +1,7 @@ + + + Version: + Enable + Add Key + Overwrite + diff --git a/res/values-eo/array.xml b/res/values-eo/array.xml index fface9219..79d432e35 100644 --- a/res/values-eo/array.xml +++ b/res/values-eo/array.xml @@ -11,9 +11,4 @@ Dark Light - - Off (unsafe) - Normal - Full - diff --git a/res/values-es/array.xml b/res/values-es/array.xml index ce0b75b74..49d24bead 100644 --- a/res/values-es/array.xml +++ b/res/values-es/array.xml @@ -11,9 +11,4 @@ Oscuro Claro - - Desactivado (peligroso) - Normal - Completo - diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 996cdf9b9..b1afbb304 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -7,14 +7,26 @@ Parece que este paquete no es compatible con tu dispositivo. ¿Quieres probar e instalarlo de todos modos? Estás intentando instalar una versión inferior de esta aplicación. Hacerlo puede derivar en mal funcionamiento o incluso pérdida de datos. ¿Quieres intentarlo de todos modos? Versión + Editar + Borrar + Habilitar envío NFC… Caché de aplicaciones descargadas + Mantener en la tarjeta SD los ficheros apk descargados + No conservar ningún archivo apk Actualizaciones Otros Último escaneo del repositorio: %s nunca + Intervalo de actualización automática + No actualizar la lista de aplicaciones automáticamente Sólo con wifi + Actualizar la lista de aplicaciones automáticamente sólo con Wi-Fi + Actualizar la lista de aplicaciones automáticamente siempre Notificar + Notificar cuando hay actualizaciones + No notificar ninguna actualización Historial de actualizaciones + Días para considerar las aplicaciones nuevas o recientes: %s Resultados de la búsqueda Detalles de la aplicación No se encontró la aplicación @@ -39,6 +51,9 @@ La dirección de un repositorio es algo similar a esto: https://f-droid.org/repo Añadir nuevo repositorio Añadir Cancelar + Habilitar + Añadir clave + Sobreescribir Elige el repositorio a eliminar Actualizar repositorios Disponible @@ -49,16 +64,29 @@ La dirección de un repositorio es algo similar a esto: https://f-droid.org/repo Por favor, espera Actualizando la lista de aplicaciones… Obteniendo la aplicación de + ¡No está habilitado NFC! + Ir a los ajustes de NFC… + No se encontró método de envío Bluetooth, ¡elige uno! + Elegir el método de envío Bluetooth Dirección del repositorio + Huella digital (opcional) + ¡Este repositorio ya existe! + Este repositorio ya está configurado, esto agregará nueva información sobre la clave. + Este repositorio ya está configurado, confirma que quieres volver a habilitarlo. + ¡El repositorio ya está configurado y habilitado! + ¡Debes borrar este repositorio antes de añadir uno con una clave diferente! + Ignorando URI de repo mal formada: %s La lista de repositorios usada ha cambiado. ¿Deseas actualizarlos? Actualizar repositorios Gestionar Repositorios + Bluetooth FDroid.apk… Preferencias Acerca de Buscar Repositorio nuevo Borrar Repositorio + Buscar repos locales Ejecutar Compartir Instalar @@ -79,17 +107,27 @@ La dirección de un repositorio es algo similar a esto: https://f-droid.org/repo Esta aplicación promueve complementos no libres Esta aplicación promueve servicios de red no libres Esta aplicación depende de otras no libres + El código fuente original no es totalmente libre Mostrar Experto + Mostrar info extra y habilitar los ajustes extra + Ocultar extras para usuarios experimentados Buscar aplicaciones - Modo síncrono de base de datos Compatibilidad de aplicaciones Versiones incompatibles + Mostrar las versiones de aplicaciones incompatibles con el dispositivo + Ocultar las versiones de aplicaciones no compatibles con el dispositivo Root + No marcar en gris las aplicaciones que requieren privilegios de root + Marcar en gris las aplicaciones que requieren privilegios de root Ignorar pantalla táctil + Incluir aplicaciones que requieran pantalla táctil siempre + Filtrar aplicaciones de manera normal Todos Novedades Recientemente actualizados + Repos de FDroid locales + Descubriendo repos locales de FDroid… Descargando %2$s / %3$s (%4$d%%) de %1$s @@ -99,10 +137,46 @@ La dirección de un repositorio es algo similar a esto: https://f-droid.org/repo Conectando a %1$s Comprobando la compatibilidad de las aplicaciones con tu dispositivo… + Guardando detalles de la aplicación (%1$d%%) No se usan permisos. Permisos para la versión %s Mostrar permisos + Mostrar una lista de los permisos que requiere una aplicación + No mostrar permisos antes de descargar No tienes instalada ninguna aplicación que pueda manejar %s Diseño compacto + Mostrar iconos en tamaño menor + Mostrar iconos en tamaño regular Tema + No firmado + URL + Número de aplicaciones + Huella digital de la clave de firmado del repo (SHA-256) + Descripción + Última actualización + Actualizar + Nombre + Esto significa que la lista de +aplicaciones no ha podido verificarse. +Deberías tener cuidado con aplicaciones descargadas desde índices no firmados. + Este repositorio aún no ha sido usado. +Para ver las aplicaciones que ofrece, necesitarás actualizarlo. +Una vez actualizado, la descripción y otros detalles estarán disponibles aquí. + ¿Quieres borrar el repositorio +\"{0}\", que contiene {1} aplicaciones? +Las aplicaciones instaladas NO se eliminarán, pero ya no podrás actualizarlas desde F-Droid. + Desconocido + ¿Borrar repositorio? + Borrar un repositorio significa +que sus aplicaciones ya no estarán disponibles en F-Droid. + +Nota: todas las aplicaciones previamente instaladas se quedarán en tu dispositivo. + \"%1$s\" deshabilitado. + +Necesitarás volver a habilitar este repositorio para instalar aplicaciones desde él. + %s o posterior + hasta %s + De %1$s a %2$s + ¡Tu dispositivo no está en la misma WiFi que el repo que acabas de añadir! Intenta unirte a esta red: %s + Requiere: %1$s diff --git a/res/values-eu/array.xml b/res/values-eu/array.xml index 80e6b4251..975c0749d 100644 --- a/res/values-eu/array.xml +++ b/res/values-eu/array.xml @@ -11,9 +11,4 @@ Dark Light - - Itzalita (ez da segurua) - Normala - Osoa - diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index b4680d751..88643fd7b 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -5,12 +5,25 @@ \'%s\'-rekin bat datorren aplikaziorik ez da aurkitu Bertsio berria zaharraren desberdina den gako batekin sinatuta dago. Bertsio berria instalatzeko, aurretik zaharra desinstalatu beharra dago. Mesedez, egizu eta saiatu berriro. (Kontutan izan desinstalatzean aplikazioak gordetako barne datuak ezabatuko direla) Bertsioa + Editatu + Ezabatu + Gaitu NFC bidez bidaltzea… Gorde cache-an deskargatutako aplikazioak + Mantendu deskargatutako apk fitxategiak SD txartelean + Ez mantendu apk fitxategirik Eguneraketak Biltegiaren azken eskaneatzea: %s inoiz ez + Wifian soilik + Eguneratu aplikazioen zerrendak automatikoki wifian soilik + Beti eguneratu aplikazioen zerrendak automatikoki Jakinarazi + Jakinarazi eguneraketak eskuragarri daudenean + Ez jakinarazi eguneraketak daudenean Eguneratu historia + Bilaketaren emaitzak + Aplikazioaren xehetasunak + Ez da aplikaziorik aurkitu F-Droid-i buruz Jatorrian Aptoide-n oinarritua. GNU GPLv3 lizentziapean argitaratua. @@ -27,6 +40,9 @@ GNU GPLv3 lizentziapean argitaratua. Gehitu biltegi berria Gehitu Utzi + Gaitu + Gehitu gakoa + Gainidatzi Aukeratu biltegia ezabatzeko Eguneratu biltegiak Eskuragarri @@ -37,7 +53,10 @@ GNU GPLv3 lizentziapean argitaratua. Mesedez itxaron Aplikazio-zerrenda eguneratzen… Aplikazioa eskuratzen hemendik + NFC ez dago gaituta! + Joan NFC ezarpenetara… Biltegiaren helbidea + Biltegi hau dagoeneko existitzen da! Erabilitako biltegien zerrenda aldatu egin da. Eguneratu nahi dituzu? Eguneratu biltegiak @@ -47,12 +66,17 @@ Eguneratu nahi dituzu? Bilatu Biltegi berria Ezabatu biltegia + Bilatu biltegi lokalak Exekutatu + Partekatu Instalatu Desinstalatu + Ezikusi eguneraketa guztiak + Ezikusi eguneraketa hau Webgunea Gaiak Iturburu-kodea + Bertsio-berritu Egin dohaintza %s bertsioa instalatuta Instalatu gabe @@ -62,13 +86,14 @@ Eguneratu nahi dituzu? Bistaratu Aditua Bilatu aplikazioak - Datu-base modu sinkronoa Aplikazioen bateragarritasuna + Bertsio bateraezinak Root Ezikusi egin ukipen-pantailari Guztia Zer da berria Azkenaldian eguneratua + FDroid biltegi lokalak %1$s(e)ra konektatzen Aplikazioak zure gailuarekin bateragarriak diren egiaztatzen… @@ -76,4 +101,14 @@ konektatzen %s bertsioarentzako baimenak Erakutsi baimenak Diseinu trinkoa + Gaia + Sinatu gabea + URLa + Aplikazio kopurua + Deskribapena + Azken eguneraketa + Eguneratu + Izena + Ezezaguna + Biltegia ezabatu? diff --git a/res/values-fa/array.xml b/res/values-fa/array.xml index 14d3a0421..f9d446d9a 100644 --- a/res/values-fa/array.xml +++ b/res/values-fa/array.xml @@ -11,9 +11,4 @@ تاریک روشن - - خاموش (ناامن) - عادی - کامل - diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 1d4c28915..243faedf6 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -7,13 +7,23 @@ به‌نظر می‌رسد این بسته با دستگاه شما هماهنگ نیست. آیا می‌خواهید آن را به هر قیمتی آزمایش و نصب کنید؟ شما در حال قدیمی‌کردن و کاهش درجهٔ این برنامه هستید. انجام چنین کاری ممکن منجر به خرابی یا از دست رفتن داده‌های شما شود. آیا می‌خواهید سعی کنید این برنامه را به هر قیمتی قدیمی کنید؟ نسخه + ویرایش + حذف + فعال‌سازی ارسال ان‌اف‌سی… میانگیری برنامه‌های دریافت‌شده + نگه‌داشتن پرونده‌های ای‌پی‌کی بر روی کارت اس‌دی + هیچ پروندهٔ ای‌پی‌کی را نگه‌ندار به‌روزرسانی‌ها دیگر آخرین اسکن مخزن: %S هیچ‌گاه + به‌روزرسانی دوره‌ای خودکار + به‌روزرسانی‌نکردن خودکار فهرست برنامه‌ها فقط هنگام اتصال وای‌فای + به‌روزرسانی فهرست برنامه‌ها خودکار فقط با وای‌فای + همیشه فهرست برنامه‌ها را خودکار به‌روز کن مطلع‌سازی + آگاهی‌دادن هنگامی که به‌روزرسانی‌ها موجود هستند به‌روزرسانی تاریخچه جستجوی نتایج مشخصات برنامه @@ -59,6 +69,7 @@ جستجو مخزن جدید حذف مخزن + یافتن مخازن محلی اجرا به اشتراک‌گذاری نصب @@ -82,7 +93,6 @@ نمایش خارج‌سازی جستجوی برنامه‌ها - حالت هماهنگی پایگاه داده‌ها هماهنگی برنامه نسخه‌های غیرهماهنگ روت diff --git a/res/values-fi/array.xml b/res/values-fi/array.xml index d4ef0d648..24139afd6 100644 --- a/res/values-fi/array.xml +++ b/res/values-fi/array.xml @@ -11,9 +11,4 @@ Tumma Valo - - Pois päältä (vaarallinen) - Normaali - Täysi - diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index 367475645..26c27f90d 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -61,7 +61,6 @@ Tahdotko päivittää ne? Näyttö Asiantuntija Etsi sovelluksia - Tietokannan synkronointi-tila Sovellusten yhteensopivuus Yhteensopimattomat versiot Root diff --git a/res/values-fr/array.xml b/res/values-fr/array.xml index d204ebad8..61b0d885a 100644 --- a/res/values-fr/array.xml +++ b/res/values-fr/array.xml @@ -11,9 +11,4 @@ Sombre Clair - - Désactivé (non recommandé) - Normal - Complet - diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 55e0d974a..d0306be35 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -7,14 +7,26 @@ Il semble que ce paquet ne soit pas compatible avec votre appareil. Voulez-vous quand même tenter de l\'installer ? Vous essayez de revenir à une ancienne version de cette application. Cela peut causer des problèmes de fonctionnement ou des pertes de données. Voulez-vous tout de même revenir à une ancienne version? Version + Éditer + Supprimer + Activer l\'envoi NFC… Stocker les applications téléchargées sur l\'appareil + Garder les fichiers apk téléchargés sur la carte SD + Ne pas garder les fichiers apk Mises à jour Autres Dernière analyse du dépôt : %s jamais + Intervalle de mise à jour automatique + Pas de mise à jour automatique de la liste d\'applications Seulement par WiFi + Mettre à jour automatiquement les listes d\'applications uniquement par WiFi + Toujours mettre à jour automatiquement les listes d\'apps Notifier + Notifier quand des mises à jour sont disponibles + Ne pas notifier des mises à jour Historique des mises à jour + Jours pour considérer les apps comme nouvelles ou récentes : %s Résultats de la recherche Détails de l\'application Pas d\'application trouvée @@ -29,7 +41,7 @@ Publiée sous licence GNU GPL v3. Un dépôt est une source d\'applications. Pour en ajouter un, appuyez maintenant sur le bouton MENU et entrez l\'adresse URL. -L\'URL d\'un dépôt ressemble à ceci : http://f-droid.org/repo +L\'URL d\'un dépôt ressemble à ceci : https://f-droid.org/repo Installée Pas installée Ajouté le %s @@ -39,6 +51,9 @@ L\'URL d\'un dépôt ressemble à ceci : http://f-droid.org/repo Ajouter un nouveau dépôt Ajouter Annuler + Activer + Ajouter une clé + Écraser Choisissez le dépôt à supprimer Mettre à jour les dépôts Disponible @@ -49,16 +64,29 @@ L\'URL d\'un dépôt ressemble à ceci : http://f-droid.org/repo Patientez Mise à jour de la liste d\'applications… Réception d\'application de + Le NFC n\'est pas activé ! + Allez dans les paramètres NFC… + Pas de méthode d\'envoi Bluetooth trouvée, choisissez-en une ! + Choisir la méthode d\'envoi Bluetooth Adresse du dépôt + Empreinte digitale (optionnel) + Ce dépôt existe déja ! + Ce dépôt est déjà configuré, cela va ajouter les informations des nouvelles clés. + Ce dépôt est déja configuré, confirmer que vous voulez le réactiver. + Le dépôt entrant est déjà configuré et activé ! + Vous devez d\'abord supprimer ce dépôt avant d\'en ajouter avec une clé différente. + URI de dépôt malformé ignoré : %s La liste des dépôts utilisés a changé. Voulez-vous les mettre à jour ? Mettre à jour les dépôts Gestion de dépôts + Bluetooth FDroid.apk… Préférences A propos Rechercher Nouveau dépôt Supprimer un dépôt + Trouver des dépôts locaux Lancer Partager Installer @@ -79,17 +107,27 @@ Voulez-vous les mettre à jour ? Cette application promeut des extensions privatrices Cette application promeut des services réseaux privateurs Cette application dépend d\'autres applications non libres + Le code source en amont n\'est pas entièrement libre Affichage Expert + Afficher plus d\'infos et activer des paramètres supplémentaires + Cacher des extras pour les utilisateurs avancés Rechercher des applications - Mode de synchronisation à la base de données Compatibilité de l\'application Versions incompatibles + Afficher les versions des applications incompatibles avec l\'appareil + Cacher les applications incompatibles avec l\'appareil Root + Ne pas griser les applications nécessitant les privilèges root + Griser les applications nécessitant les privilèges root Ignorer l\'écran tactile + Toujours inclure les apps nécessitant un écran tactile + Filtrer les apps normalement Tout Quoi de neuf ? Mis à jour récemment + Dépôts FDroid locaux + Découverte des dépôts FDroid locaux… Téléchargement %2$s / %3$s (%4$d%%) de %1$s @@ -99,10 +137,47 @@ Voulez-vous les mettre à jour ? Connexion à %1$s Vérification de la compatibilité des applis avec votre appareil… + Sauvegarder les détails de l\'application (%1$d%%) Aucune autorisation n\'est utilisée. Autorisations pour la version %s Afficher les autorisations + Afficher la liste des permissions qu\'une app requiert + Ne pas afficher les permissions avant le téléchargement Vous n\'avez aucune application installée pour gérer %s Affichage compact + Montrer les icônes à une taille plus petite + Montrer les icônes à une taille normale Thème + Non signé + URL + Nombre d\'applications + Empreinte digitale de la clef de signature pour le dépôt (SHA-256) + Description + Dernière mise à jour + Mise à jour + Nom + Cela signifie que la liste + des applications n\'a pu être vérifiée. Vous + devriez faire attention avec les + applications téléchargées d\'indexes non signés. + Ce dépôt n\'a pas encore été utilisé. + Pour voir la liste des applications qu\'il + offre, vous devez le mettre à jour. + +Une fois la mise à jour effectuée, la description + et les autres détails seront affichés ici. + Voulez vous supprimer le dépôt \"{0}\", qui a {1} apps ? Toutes les applications installées ne seront pas supprimés, mais vous ne serez plus en mesure de les mettre à jour via F-Droid. + Inconnu + Supprimer le dépôt ? + Supprimer un dépôt signifie que les apps ne seront disponibles via F-Droid. Note: Toute les apps précédemment installées vont rester sur votre appareil. + « %1$s » a été désactivé.. + +Vous allez devoir + le réactiver pour installer des applications + à partir de ce dépôt. + %s ou plus récent + jusqu\'à %s + De %1$s à %2$s + Votre appareil n\'est sur le même WiFi que le dépôt local que vous venez d\'ajouter ! Essayez de rejoindre ce réseau : %s + Nécessite: %1$s diff --git a/res/values-gl/array.xml b/res/values-gl/array.xml index 1770571ed..722add613 100644 --- a/res/values-gl/array.xml +++ b/res/values-gl/array.xml @@ -11,9 +11,4 @@ Escuro Claro - - Apagado (inseguro) - Normal - Completo - diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index 3b28894da..0175f1829 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -86,7 +86,6 @@ Quere actualizalos? Amosar Experto Buscar aplicativos - Modo de sincronización da base de datos Compatibilidade de aplicativos Versións incompatíbeis Root diff --git a/res/values-gu/array.xml b/res/values-gu/array.xml index 42eac981d..da5e2aa16 100644 --- a/res/values-gu/array.xml +++ b/res/values-gu/array.xml @@ -11,9 +11,4 @@ Dark Light - - બંધ (અસુરક્ષિત) - સામાન્ય - પૂર્ણ - diff --git a/res/values-hu/array.xml b/res/values-hu/array.xml new file mode 100644 index 000000000..8d2f806a0 --- /dev/null +++ b/res/values-hu/array.xml @@ -0,0 +1,14 @@ + + + + Soha + Óránként + 4 óránként + 12 óránként + Naponta + + + Sötét + Világos + + diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml new file mode 100644 index 000000000..0802c7f48 --- /dev/null +++ b/res/values-hu/strings.xml @@ -0,0 +1,141 @@ + + + \"%1$d alkalmazás találat ehhez \'%2$s\':\" + \"Egy alkalmazás találat ehhez \'%s\':\" + \"Nincs ezzel \'%s\' egyező alkalmazás\" + Az új verzió a régitől eltérő kulccsal van aláírva. Az új verzió telepítéséhez először el kell távolítani a régit. Kérem tegye meg ezt és próbálja újra. (Megjegyzendő, hogy az eltávolítás törli az alkalmazás minden tárolt adatát) + Úgy tűnik, ez a csomag nem kompatibilis a készülékkel. Ennek ellenére is megpróbálja telepíteni? + Ön megpróbálta régebbivel felülírni az alkalmazást. Ez hibás működést és az adatok elvesztését okozhatja. Ennek ellenére is megpróbálja telepíteni? + Verzió + App cache + A letöltött apk fájlt megtartja az SD kártyán + Ne tartson meg semmilyen apk fájlt + Frissítések + egyéb + Utolsó vizsgálat: %s + soha + Auto. frissítés intervalluma + Ne frissítsen automatikusan + Csak Wifin + Automatikus app lista frissítés csak Wifin + Mindig frissítse az app listákat automatikusan + Értesítés + Értesít ha frissítés érhető el + Ne jelezzen semmilyen frissítést + Frissítési előzmények + Hány napig tekintse az appot frissnek vagy újnak: %s + Keresési előzmények + App részletei + Nem található ilyen app + Az F-Droid + \"Eredetileg az Aptoide alapján. +Kiadva GNU GPLv3 licensz alatt. + +Honosítás: gidano | sympda.info\" + Weboldal: + Email: + Verzió: + Weboldal + \"Még nincs konfigurálva repository! + +A repo, alkalmazások forrása. Hozzáadáshoz nyomja meg a MENÜ gombot és írja be a címét. + +A repo cím valahogy így néz ki: https://f-droid.org/repo\" + Telepítve + Nincs telepítve + Hozzáadva %s + Oké + Igen + Nem + Új repo hozzáadása + Hozzáad + Mégsem + Engedélyez + Kulcs hozzáadás + Felülírás + Válasszon ki repo-t az eltávolításhoz + Repo-k frissítése + Elérhető + Frissítések + 1 frissítés érhető el. + %d frissítés érhető el. + F-Droid frissítés érhető el + Kérem várjon + Alkalmazáslista frissítése… + Alkalmazás beszerzése + Repo cím + ujjlenyomat (opcionális) + Ez a repo már létezik! + Ez a repo már be van állítva, ez új kulcs információt fog hozzáadni. + Ez a repo már be van állítva, erősítse meg az újraengedélyezését. + A fogadott repo már telepítve és engedélyezve van! + Előbb törölnie kell ezt a repot, mielőtt hozzáad egyet eltérő kulccsal! + \"A használt repo-k listája megváltozott. +Szeretné ezeket frissíteni?\" + Repo-k frissítése + Repo-k kezelése + Lehetőségek + Rólunk + Keresés + Új repository + Repo eltávolítása + Indítás + Megoszt + Telepít + Eltávolít + Mellőz minden frissítést + Ezt a frissítést mellőzi + Weboldal + Kérdések + Forráskód + Frissítés + Adomány + %s verzió telepítve + Nincs telepítve + A letöltött fájl hibás + Letöltés megszakítva + Az alkalmazás reklámot tartalmaz + Az alkalmazás nyomon követi és jelenti a tevékenységeit + Az alkalmazás nem ingyenes kiegészítőket támogat + Az alkalmazás nem ingyenes hálózati szolgáltatásokat támogat + Az alkalmazás egyéb, nem ingyenes alkalmazásoktól függ + Az upstream forráskód nem teljesen szabad + Megjelenés + Szakértő + Extra infókat mutat és extra beállításokat engedélyez + Extrák elrejtése gyakorlott felhasználók számára + Alkalmazások keresése + App kompatibilitás + Inkompatibilis verzió + Megjeleníti, ha az app verzió nem kompatibilis a készülékkel + Elrejti az app inkompatibilitását az eszközzel + Root + Nem szürkíti ki a root jogot igénylő alkalmazásokat + Kiszürkíti a root jogot igénylő alkalmazásokat + Érintőképernyő ignorálás + Mindig tartalmazza az érintőképernyőt igénylő alkalmazásokat + Appok normál szűrése + Összes + \"Újdonságok\" + Legutóbb frissítve + \"Letöltés +%2$s / %3$s (%4$d%%) innen +%1$s\" + \"Feldolgozási kérelem +%2$d of %3$d innen +%1$s\" + \"Kapcsolódás +%1$s\" + Alkalmazások eszközkompatibilitási ellenőrzése… + Nincsenek engedélyei. + Engedélyek erre a verzióra - %s + Engedélyek megjelenítése + Mutassa meg egy listában az app által igényelt engedélyeket + \"Ne mutasson listát letöltés előtt\" + \"Nincs semmilyen app, ami képes ezt kezelni %s\" + Kompakt elrendezés + Ikonok kisebb méretben + Ikonok normál méretben + Téma + Android %s vagy későbbi + diff --git a/res/values-it/array.xml b/res/values-it/array.xml index 7c2f1ef01..2eb94a3d6 100644 --- a/res/values-it/array.xml +++ b/res/values-it/array.xml @@ -11,9 +11,4 @@ Scuro Chiaro - - Disabilitato (non sicuro) - Normale - Completo - diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index fde3ceaff..8b3835d67 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -7,14 +7,26 @@ Sembra che questo pacchetto non sia compatibile con il tuo dispositivo. Vuoi provare comunque ad installarlo? Stai provando a passare ad una versione precedente di questa applicazione. Potresti avere malfunzionamenti e perdita di dati. Vuoi installarla comunque? Versione - Cache applicazioni scaricate + Modifica + Elimina + Attiva Invio NFC… + Cache applicazioni + Conserva i file apk scaricati sulla scheda SD + Non conservare i file apk Aggiornamenti Altro Ultima scansione repository: %s mai + Intervallo degli aggiornamenti automatici + Non aggiornare automaticamente l\'elenco delle applicazioni Solo su wifi + Aggiorna automaticamente gli elenchi di applicazioni solo su wifi + Aggiorna sempre gli elenchi delle applicazioni automaticamente Avviso + Notifica gli aggiornamenti disponibili + Non notificare gli aggiornamenti Aggiorna i repository + Numero di giorni per considerare le applicazioni nuove o recenti: %s Risultati Ricerca Dettagli App Nessuna app corrispondente trovata @@ -39,6 +51,9 @@ Un indirizzo URL di esempio è: https://f-droid.org/repo Aggiungi nuovo repository Aggiungi Annulla + Abilita + Aggiungi chiave + Sovrascrivi Rimuovi repository Aggiorna i repository Disponibile @@ -49,16 +64,29 @@ Un indirizzo URL di esempio è: https://f-droid.org/repo Attendere prego Aggiornamento elenco applicazioni… Scaricamento applicazione da + NFC non attivato! + Vai alle Impostazioni NFC… + Nessun metodo d\'invio via Bluetooth trovato, selezionane uno! + Scegli il metodo di invio Bluetooth Indirizzo repository + Impronta digitale (opzionale) + Questo repository esiste già! + Questo repository è già configurato, una nuova informazione chiave verrà aggiunta. + Questo repository è già configurato, conferma di volerlo abilitare nuovamente. + Il nuovo repository è già configurato e abilitato! + È necessario eliminare questo repository prima di poter aggiungerne uno con una chiave differente! + Ignoro URI repo malformati: %s L\'elenco dei repository in uso è cambiato. Vuoi aggiornarlo? Aggiorna i Repository - Gestione Repository + Gestione dei repository + Bluetooth FDroid.apk… Preferenze Informazioni Cerca Nuovo Repository Rimuovi Repository + Trova dei Repository locali Avvia Condividi Installa @@ -79,17 +107,27 @@ Vuoi aggiornarlo? Questa app promuove add-on non liberi Questa app promuove servizi di rete non liberi Questa app dipende da applicazioni non libere + Il codice sorgente a monte non è completamente libero Mostra Esperto + Mostra le informazioni ulteriori e abilita le impostazioni avanzate + Nascondi le opzioni avanzate per utenti esperti Ricerca applicazioni - Modalità di sincronizzazione database Compatibilità applicazioni Versioni incompatibili + Mostra le versioni incompatibili con il dispositivo + Nascondi le versioni incompatibili con il dispositivo Amministratore + Non disabilitare le applicazioni che richiedono privilegi di root + Disabilita le applicazioni che richiedono privilegi di root Ignora il Touchscreen + Includi sempre le applicazioni con touchscreen obbligatorio + Filtra le applicazioni normalmente Tutte Novità Aggiornate di Recente + Repo FDroid Locali + Rilevazione repo FDroid locali… Scaricamento %2$s / %3$s (%4$d%%) da %1$s @@ -99,10 +137,38 @@ Vuoi aggiornarlo? Connessione a %1$s Controllo compatibilità applicazioni con il tuo dispositivo… + Salvataggio dettagli applicazioni (%1$d%%) Non viene usata alcuna autorizzazione. Autorizzazioni per la versione %s Mostra autorizzazioni + Mostra l\'elenco dei permessi richiesti da un\'applicazione + Non mostrare i permessi prima del download Non hai alcuna app disponibile che può gestire %s Layout Compatto + Mostra le icone a dimensione ridotta + Mostra le icone a dimensione normale Tema + Non firmato + URL + Numero di applicazioni + Impronta digitale della Chiave del Repo (SHA-256) + Descrizione + Ultimo aggiornamento + Aggiorna + Nome + Ciò significa che l\'elenco di applicazioni non potrà essere verificato. È consigliabile prestare attenzione alle applicazioni scaricate da indici non firmati. + Questo repository non è ancora stato utilizzato. +Per poter vedere le applicazioni contenute, è necessario aggiornarlo. +Una volta aggiornato, la descrizione e le altre informazioni saranno disponibili qui. + Si desidera eliminare il \"{0}\" repository, che contiene {1} applicazioni? Le applicazioni installate NON saranno rimosse, ma non sarà più possibile aggiornarle attraverso F-Droid. + Sconosciuto + Eliminare il repository? + Eliminare un repository implica che le applicazioni contenute non saranno più disponibili attraverso F-Droid. +Nota: Tutte le applicazioni installate precedentemente rimarranno sul dispositivo. + \"%1$s\" è disabilitato. +È necessario abilitare nuovamente questo repository per installare le applicazioni contenute. + %s o successivi + Il tuo dispositivo non è nella stessa rete WiFi del Repository locale che hai aggiunto! +Prova a collegarti a questa rete: %s + Richiede: %1$s diff --git a/res/values-ko/array.xml b/res/values-ko/array.xml index 2bf47cb19..d00633ed0 100644 --- a/res/values-ko/array.xml +++ b/res/values-ko/array.xml @@ -11,9 +11,4 @@ 어두운 밝은 - - 해제 (안전하지 않음) - 보통 - 전체 - diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 28be1501c..5baeb291d 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -70,7 +70,6 @@ 표시 전문가 응용 프로그램 검색 - 데이터베이스 동기화 모드 응용 프로그램 호환성 호환되지 않는 버전 터치스크린 무시 diff --git a/res/values-nb/array.xml b/res/values-nb/array.xml index 2fb6485b1..045ca6468 100644 --- a/res/values-nb/array.xml +++ b/res/values-nb/array.xml @@ -8,12 +8,7 @@ Daglig - Mørk - Lys - - - Av (utrygt) - Normalt - Fullt + Mørkt + Lyst diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index bd501e332..d6baa646c 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -7,14 +7,26 @@ Det ser ut til at denne pakken ikke er kompatibel med ditt utstyr. Vil du prøve å installere det likevel? Du prøver å nedgradere denne applikasjonen. Dette kan føre til at applikasjonen henger, og du kan til og med miste dine data. Vil du prøve å nedgradere likevel? Versjon + Rediger + Slett + Skru på NFC-sending Lagre nedlastede applikasjoner i buffer + Behold nedlastede apk-filer på minnekortet + Ikke behold noen apk-filer Oppdateringer Andre Forrige registeroppdatering: %s aldri + Intervall for automatisk oppdatering + Ingen automatiske registerlisteoppdateringer Bare på trådløst + Oppdater applikasjoner automatisk kun på trådløst + Alltid oppdater applikasjonsliste automatisk Varsle + Varsle når nye oppdateringer er tilgjengelige + Ikke vis varsel om noen oppdateringer Oppdater historie + Dager nytt innhold skal anses som ferskt: %s Søkeresultater Programdetaljer Program ikke funnet @@ -35,8 +47,11 @@ Lisensiert GNU GPLv3. Legg til nytt register Legg til Avbryt + Skru på + Legg til nøkkel + Overskriv Velg register du vil fjerne - Oppdater registrene + Oppdater registerne Tilgjengelig Oppdateringer 1 oppdatering tilgjengelig. @@ -45,15 +60,28 @@ Lisensiert GNU GPLv3. Vennligst vent Oppdaterer applikasjonsliste… Henter program fra + NFC (nærfeltskommunikasjon) er ikke påskrudd! + Gå til NFC-innstillinger + Ingen forsendelsesmåte for blåtann funnet, velg en! + Velg forsendelsesmåte for Blåtann Registeradresse + Fingeravtrykk (valgfritt) + Dette registret eksisterer allerede! + Dette registret er allerede satt opp, dette vil legge til ny informasjon om nøkler. + Dette registret er allerede satt opp, bekreft at du vil skru det på igjen. + Oppstrøms-registret er allerede oppsatt og skrudd på! + Du må først slette dette registret før du kan legge til et med en en annen nøkkel! + Ignorerer ugyldig registernettadresse: %s Listen over brukte register har endret seg. Vil du oppdatere dem? Oppdater registrene Endre registrene + Blåtann FDroid.apk… Innstillinger Om Søk Nytt register Fjern register + Finn lokale register Kjør Del Installer @@ -61,7 +89,7 @@ Lisensiert GNU GPLv3. Ignorer alle oppdateringer Ignorer denne oppdateringen Nettside - Saker + Problemoversikt Kildekode Oppgrader Doner @@ -74,17 +102,27 @@ Lisensiert GNU GPLv3. Dette programmet promoterer ufrie utvidelser Dette programmet promoterer ufrie nettverkstjenester Dette programmet avhenger av andre ufrie applikasjoner + Koden fra kilden er ikke helt fri Vis Ekspert + Hvis ekstra info og skru på ekstra innstillinger + Gjem ekstra info for erfarne brukere Søk i programliste - Modus for databasesynkronisering Programstøtte Ukompatible versjoner + Vis programvareversjoner som er ukompatible med enheten + Gjem programvareversjoner som er ukompatible med enheten Rot + Skyggelegg alle app-er som krever superbruker-tilgang + Skyggelegg alle app-er som etterspør superbruker-rettigheter Ignorer pekeskjerm + Alltid inkluder app-er som krever pekeskjerm + Filtrer app-er som normalt Alle Det som er nytt Nylig oppdatert + Lokale F-Droid register + Oppdager lokale FDroid register… Laster ned %2$s / %3$s (%4$d%%) fra %1$s @@ -94,10 +132,47 @@ Lisensiert GNU GPLv3. Kobler til %1$s Sjekker programstøtte for ditt utstyr… + Lagrer programdata (%1$d%%) Krever ingen tillatelser. Tillatelser for versjon %s Vis tillatelser + Vis en liste over rettighetene en app krever + Ikke vis rettigheter før nedlasting Du har ingen tilgjengelige applikasjoner som kan håndtere %s Kompakt layout + Vis ikoner i mindre størrelse + Vis ikoner i vanlig størrelse Utseende + Usignert + URL + Antall app-er + Fingeravtrykk for signeringsnøkkel til register (SHA-256) + Beskrivelse + Siste oppdatering + Oppdater + Navn + Dette betyr at listen over applikasjoner ikke er kontrollert. Du bør være forsiktig med applikasjoner lastet ned fra usignerte lister. + Dette registret har ikke blitt brukt enda. +For å se app-ene det har tilgjengelig, må du oppdatere det. + +Når så er gjort, vil beskrivelser og andre detaljer bli tilgjengelige her. + Vil du slette \"{0}\" +registret, som har {1} app-er i seg? Alle installerte app-er vil IKKE bli +fjernet, men det kan ikke oppdatere dem med F-droid lengre. + Ukjent + Slett register? + Sletting av register betyr + at applikasjoner derfra ikke lenger vil være tilgjengelige i F-droid. + +Merk: Alle + tidligere installerte apper vil fremdeles være å finne på din enhet. + Avskrudd \"%1$\". + +Du må + skru på dette registeret igjen for å installere applikasjoner fra det. + %s eller senere + opptil %s + %1$s opptil %2$s + Din enhet er ikke på det samme lokale WiFi-nettet som registret du nettopp la til! Prøv å koble til dette nettverket: %s + Krever: %1$s diff --git a/res/values-nl/array.xml b/res/values-nl/array.xml index 19c7f0690..765ae052b 100644 --- a/res/values-nl/array.xml +++ b/res/values-nl/array.xml @@ -11,9 +11,4 @@ Donker Licht - - Uit (onveilig) - Normaal - Vol - diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 6eeb3910a..a4a4fa820 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -7,7 +7,11 @@ Dit pakket is niet verenigbaar met uw apparaat. Wilt u het alsnog proberen te installeren? U probeert deze applicatie te degraderen naar een oudere versie. Als u dit doet uw data kan corrupt of verloren raken. Wilt u dit alsnog uitvoeren? Versie + Bewerken + Verwijderen buffer gedownloade apps + Gedownloade apk-files bewaren op SD card + apk-files niet bewaren Updates Andere Laatste bronnen scan: %s @@ -42,13 +46,14 @@ Een bron-adres ziet er ongeveer Voeg nieuwe bron toe Toevoegen Annuleren + Overschrijven Kies bron om te verwijderen Vernieuw bronnen Beschikbaar Updates - 1 vernieuwing is beschikbaar - %d vernieuwingen zijn beschikbaar - F-Droid Vernieuwingen Beschikbaar + 1 update beschikbaar + %d updates beschikbaar + F-Droid update beschikbaar Even geduld aub Applicatie-lijst vernieuwen… downloaden applicatie van @@ -62,12 +67,13 @@ Wilt u ze vernieuwen? Zoeken Nieuwe bron Verwijder bron + Vind lokale oplagplaatsen Start Delen Installeren Deinstalleren - Negeer Alle Verbeteringen - Negeer Deze Verbetering + Negeer Alle Updates + Negeer Deze Update Website Problemen Broncode @@ -85,7 +91,6 @@ Wilt u ze vernieuwen? Laat zien Expert Zoek applicaties - Database sync-modus Applicatie verenigbaarheid Onverenigbare versies Root @@ -93,14 +98,14 @@ Wilt u ze vernieuwen? Alles Wat is nieuw Recentelijk vernieuwd + Lokale FDroid opslagplaatsen Downloaden %2$s / %3$s (%4$d%%) van %1$s Verwerken applicatie %2$d van %3$d van %1$s - Connecteren naar -%1$s + Verbinden met %1$s Controleer app compatibiliteit met uw apparaat… Geen permissies worden gebruikt Permissies voor versie %s @@ -108,4 +113,18 @@ Wilt u ze vernieuwen? U hebt geen beschikbare app die %s kan verwerken Compacte Layout Thema + URL + Aantal apps + Beschrijving + Meest recente update + Naam + Deze opslag is nog niet eerder gebruikt. Om de leverbare apps te zien moet u het updaten. + +Zodra de update gedaan is ziet u hier de beschrijving en andere details. + Weet u zeker dat u de opslag genaamd \"{0}\" met daarin \"{1}\" apps wilt verwijderen? Reeds geïnstalleerde apps blijven behouden, maar kunnen niet meer worden geüpdate via F-Droid. + Onbekend + Het verwijderen van een opslag betekent dat apps hierop niet meer beschikbaar zijn voor F-Droid. + +Noot: Eerder geïnstalleerde apps blijven op uw apparaat. + \"%1$s\" uitgeschakeld. U moet deze weer activeren mocht u apps vanuit deze opslag willen installeren. diff --git a/res/values-pl/array.xml b/res/values-pl/array.xml index 61ff85ad2..e6076d5e5 100644 --- a/res/values-pl/array.xml +++ b/res/values-pl/array.xml @@ -8,12 +8,7 @@ Codziennie - Dark - Light - - - Wyłączone (niebezpieczne) - Normalny - Pełny + Ciemny + Jasny diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index e328439bd..6e709bf01 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -4,22 +4,43 @@ Znaleziono jedną pasującą aplikację \'%s\': Nie znaleziono żadnych pasujących aplikacji \'%s\' Nowa wersja jest podpisana innym kluczem niż poprzednia. Aby ją zainstalować należy najpierw usunąć tę starą. Zrób to i spróbuj ponownie. (Proszę pamiętać, że deinstalacja spowoduje usunięcie wszystkich danych przechowywanych przez aplikację) + Wygląda na to, że ta aplikacja nie jest kompatybilna z twoim urządzeniem. Zainstalować mimo to? + Próbujesz zainstalować starszą wersję tej aplikacji.Może to spowodować nieprawidłowe działanie, a nawet utratę swoich danych. Czy na pewno chcesz spróbować i zainstalować starszą wersję ? Wersja + Edytuj + Usuń Buforuj pobrane aplikacje + Trzymaj ściągnięte pliki apk na karcie SD + Nie zachowuj żadnych apk Aktualizacje Inne Ostatnie uaktualnienie listy aplikacji: %s nigdy + Automatyczna przerwa aktualizacji + Żadnych automatycznych aktualizacji listy aplikacji Tylko przez wifi + Aktualizuj automatycznie tylko przez wifi + Zawsze aktualizuj listę aplikacji automatycznie Powiadom + Powiadom kiedy aktualizacje są dostępne + Nie powiadamiaj o aktualizacjach Historia aktualizacji + Liczba dni, aby uznać aplikację za nową lub niedawną: %s Wyniki wyszukiwania + Szczegóły aplikacji Nie znaleziono takiej aplikacji O F-Droid + Oryginalnie bazowany na Aptoide. +Wydany na licencji GNU GPLv3. Strona internetowa: Email: Wersja: Strona internetowa + Nie masz skonfigurowanych żadnych repozytoriów! + +Repozytorium jest źródłem aplikacji. Aby dodać jedno wciśnij MENU i wprowadź adres URL. + +Przykładowy adres repozytorium: https://f-droid.org/repo Zainstalowano Niezainstalowane Dodano %s @@ -29,14 +50,26 @@ Dodaj nowe repozytorium Dodaj Anuluj + Włącz + Dodaj klucz + Nadpisz Wybierz repozytorium które chcesz usunąć Aktualizuj repozytoria Dostępne Aktualizacje + Dostępne jest 1 uaktualnienie. + Dostępnych jest %d uaktualnień + Uaktualnienie F-Droid jest dostępne Proszę czekać Aktualizowanie listy aplikacji… Pobieranie aplikacji z Adres repozytorium + Odcisk palca (opcjonalnie) + Repozytorium już istnieje! + To repozytorium jest już ustawione, doda to nowe kluczowe informacje + To repozytorium jest już ustawione, potwierdź że chcesz je włączyć ponownie + Nadchodzące repozytorium jest już ustawione i włączone! + Musisz najpierw usunąć to repozytorium zanim dodasz następne z innym kluczem! Lista wykorzystywanych repozytoriów uległa zmianie. Czy chcesz je zaktualizować? Aktualizuj repozytoria @@ -55,20 +88,70 @@ Czy chcesz je zaktualizować? Strona internetowa Problemy Kod żródłowy + Uaktualnij Złóż datek Wersja %s została zainstalowana Nie zainstalowano Pobrany plik jest uszkodzony Anulowano pobieranie + Ta aplikacja zawiera reklamy + Ta aplikacja śledzi twoje działania + Ta aplikacja promuje niewolne dodatki + Ta aplikacja promuje niewolne usługi sieciowe + Ta aplikacja wymaga innych, niewolnych aplikacji + Upstreamowy kod źródłowy nie jest w pełni wolny + Wyświetl Ekspert + Pokaż dodatkowe informacje i włącz dodatkowe ustawienia + Ukryj dodatki dla zaawansowanych użytkowników Wyszukaj aplikacje - Tryb synchronizacji bazy danych Kompatybilność aplikacji + Niekompatybilne wersje + Pokaż wersje aplikacji niekompatybilne z urządzeniem + Ukryj wersje aplikacji niekompatybilnych z urządzeniem Root + Nie przyciemniaj aplikacji wymagających uprawnień roota + Przyciemnij aplikacje wymagające uprawnień roota + Ignoruj ekran dotykowy + Zawsze uwzględniaj aplikacje, które wymagają ekranu dotykowego + Filtruj aplikacje normalnie Wszystkie Co nowego Ostatnio zaktualizowane + Pobieranie %2$s / %3$s(%4$d%%) z %1$s + Przetwarzanie aplikacji %2$d / %3$d z %1$s Trwa łączenie z %1$s + Sprawdzanie kompatybilności aplikacji z urządzeniem… + Brak użytych uprawnień. + Uprawnienia dla wersji %s Wyświetl uprawnienia + Wyświetl listę uprawnień wymaganych przez aplikację + Nie pokazuj uprawnień przed pobraniem + Nie masz żadnej dostępnej aplikacji, która może obsłużyć %s + Widok kompaktowy + Pokaż ikony w mniejszym rozmiarze + Pokaż ikony w zwykłym rozmiarze + Motyw + Niepodpisany + URL + Liczba aplikacji + Opis + Ostatnia modyfikacja + Aktualizacja + Nazwa + To oznacza, że lista aplikacji nie może być zweryfikowana. Powinieneś być ostrożny przy aplikacjach ściągniętych z nie podpisanych źródeł + To repozytorium było jeszcze używane. Aby wyświetlić jego aplikacje musisz je zaktualizować. + +Opis i inne szczegóły będą tu dostępne gdy zaktualizujesz repozytorium + Czy chcesz usunąć repozytorium \"{0}\", zawierające \"{1}\" aplikacji? Zainstalowane aplikacje nie zostaną usunięte, ale nie będziesz mógł ich dłużej aktualizować przez F-Droid + Nieznany + Usunąć repozytorium? + Usunięcie repozytorium oznacza, że aplikacje z niego nie będą dłużej dostępne w F-Droid. + +Uwaga: Wszystkie poprzednio zainstalowane aplikacje zostaną na urządzeniu. + Zablokowane \"%1$s\". + +Aby zainstalować aplikacje z tego repozytorium musisz je włączyć ponownie. + %s lub później diff --git a/res/values-pt-rBR/array.xml b/res/values-pt-rBR/array.xml index 6fc95972c..1614797d3 100644 --- a/res/values-pt-rBR/array.xml +++ b/res/values-pt-rBR/array.xml @@ -11,9 +11,4 @@ Escuro Claro - - Desligada (inseguro) - Normal - Completa - diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml index c51a79245..72164cc15 100644 --- a/res/values-pt-rBR/strings.xml +++ b/res/values-pt-rBR/strings.xml @@ -29,7 +29,7 @@ Lançado sob a licença GNU GPLv3. Um repositório é uma fonte de aplicativos. Para adicionar um, pressione o botão MENU e digite a URL. -Um endereço do repositório é algo similar a isto: http://f-droid.org/repo +Um endereço do repositório é algo similar a isto: https://f-droid.org/repo Instalado Não Instalado Adicionado em %s @@ -82,7 +82,6 @@ Você deseja atualizá-los? Exibição Especialista Pesquisar aplicativos - Modo de sincronia do banco de dados Compatibilidade de aplicativo Versões incompatíveis Root diff --git a/res/values-ro/array.xml b/res/values-ro/array.xml index d8e58ad04..8c1fabb4e 100644 --- a/res/values-ro/array.xml +++ b/res/values-ro/array.xml @@ -11,9 +11,4 @@ Dark Light - - Inchis (nerecomandat) - Normal - Complet - diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 40c1a4fe3..67ea92024 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -1,8 +1,8 @@ - Sa gasit o aplicatie potrivita cu %s\' - Sa gasit o aplicatie potrivita cu %s\' - Nu exita aplicatii potrivite cu %s\': + Sa gasit %1$d aplicații potrivita cu \'%2$s\' + Sa gasit o aplicatie potrivita cu \'%s\' + Nu exita aplicatii potrivite cu \'%s\': Versiune Istoric aplicatii descarcate Noutati @@ -25,6 +25,6 @@ Distribuit sub licenta GNU GPLv3. Actualizare depozit aplicatii Disponibil Actualizare - Asteptati … - Se actualizeaza lista … + Asteptati… + Se actualizeaza lista… diff --git a/res/values-ru/array.xml b/res/values-ru/array.xml index 13a7defd0..8b39f1618 100644 --- a/res/values-ru/array.xml +++ b/res/values-ru/array.xml @@ -11,9 +11,4 @@ Dark Light - - Откл. (опасно) - Обычный - Полный - diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 225e618e9..9250d4172 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -4,14 +4,29 @@ Найдено одно совпадение с \'%s\': Не найдено ни одного совпадения с \'%s\' Новая версия подписана ключом отличным от старого. Для установки новой версии, сначала нужно удалить старую программы. А потом попробовать снова. (Замечание: при удалении программы будут удалены все её данные) + Похоже, что этот пакет не несовместим с Вашим устройством. Вы все ещё хотите попытаться установить его? Вы пытаетесь установить более старую версию приложения. Это может привести к его некорректной работе и даже потере данных. Вы уверены, что хотите продолжить? Версия - Кешировать загруженные приложения + Редактировать + Удалить + Включить отправку по NFC… + Кэшировать загруженные приложения + Хранить загруженные файлы apk на SD-карте + Не хранить файлы apk Обновления + Другой Обновлено: %s никогда + Интервал автоматического обновления + Не обновлять автоматически список приложений + Только по Wi-Fi + Обновлять списки приложений автоматически только по Wi-Fi + Всегда автоматически обновлять списки приложений Уведомление + Сообщать о наличии обновлений + Не уведомлять о любых обновлениях История обновлений + Количество дней, в которые отображаются новые или недавно измененные приложения: %s Результаты поиска Описание приложения Приложение не найдено @@ -36,55 +51,123 @@ Добавить репозиторий Добавить Отменить + Включить + Добавить ключ + Перезаписать Удалить репозиторий Обновить репозитории Доступно Обновления Доступно 1 обновление. Обновлений доступно - %d. + Доступны обновления для F-Droid Подождите Список приложений обновляется… Взять приложение из + NFC не включен! + Перейти в Настройки NFC… + Ни один метод отправки по Bluetooth не найден, выберите один из них! + Выберите метод отправки по Bluetooth Адрес репозитория + Отпечаток ключа (опционально) + Этот репозиторий уже существует! + Этот репозиторий уже установлен, это действие добавит новую информацию о ключе. + Этот репозиторий уже настроен, убедитесь, что вы хотите снова включить его. + Репозиторий уже настроен и включен! + Вы должны удалить этот репозиторий, прежде чем вы можете добавить новый с другим ключом! + Игнорирование неверного URI репозитория: %s Список репозиториев изменился. Обновить его? Обновить репозитории - Редактировать репозитории + Репозитории + Bluetooth FDroid.apk… Настройки О программе Поиск Новый репозиторий Удалить репозиторий + Найти локальные репозитории Запустить Поделиться Установить Удалить + Игнорировать все обновления + Игнорировать данное обновление Сайт Ошибки Исходный код + Обновление Пожертвовать Версия %s установлена Не установлено Загруженный файл повреждён Загрузка остановлена + Это приложение содержит рекламу + Это приложение будет отслеживать ваши действия и сообщать о вашей деятельности + Это приложение предлагает использовать несвободные дополнения + Это приложение предлагает использовать несвободные сетевые услуги + Это приложение зависит от других несвободных приложений + Оригинальный исходный код не является полностью свободным Вид Эксперт + Показать дополнительную информацию и включить дополнительные настройки + Скрыть дополнительные возможности для опытных пользователей Найти приложения - Режим синхронизации базы Совместимость приложений + Несовместимые версии + Показать версии программ, несовместимые с устройством + Скрыть версии программ, несовместимые с устройством Суперпользователь + Не выделять серым цветом приложения, требующие привилегии суперпользователя + Выделять серым цветом приложения, требующие привилегии суперпользователя Игнорировать Тачскрин + Всегда включать приложения, которые требуют сенсорный экран + Фильтровать приложения как обычно Все Что Нового Недавно обновлённые + Локальные репозитории FDroid + Обнаружение локальных репозиториев FDroid… Загрузка %2$s / %3$s (%4$d%%) из +%1$s + Обработка приложения +%2$d из %3$d от %1$s Соединение с %1$s - Проверка совместимости приложений с устройством… + Проверка совместимости приложений с вашим устройством… + Сохранение данных приложений (%1$d%%) Разрешений не требуется. Разрешения для версии %s Показывать разрешения + Отображение списка разрешений, которые требуются приложению + Не показывать разрешения перед загрузкой + У вас нет установленного приложения для обработки %s Компактный вид + Показать иконки в меньшем размере + Показать иконки обычного размера + Тема + Неподписанный + URL + Количество приложений + Отпечаток ключа подписи репозитория (SHA-256) + Описание + Последние обновление + Обновить + Название + Это означает, что список приложений не может быть проверен. Вы должны быть осторожны с приложениями, загруженными из неподписанных источников. + Этот репозиторий еще не был использован. Для того чтобы просмотреть приложения, которые он предоставляет, вы должны обновить его. После обновления, описание и другие детали станут доступны. + Вы хотите удалить \"{0}\" репозиториев, который имеет {1} приложений в нем? Установленные приложения не будут удалены, но вы больше не сможете обновить их через F-Droid. + Неизвестный + Удалить репозиторий? + Удаление репозитория означает что приложения из него больше не будут доступны в F-Droid. + +Примечание: Все ранее установленные приложения будут оставаться на вашем устройстве. + \"%1$s\" отключен. Вам нужно повторно включить этот репозиторий для установки приложений из него. + %s или позднее + до %s + %1$s до %2$s + Данное устройство не находится в той же сети Wi-Fi, что и локальный репозиторий, который вы только что добавили! Попробуйте присоединиться к этой сети: %s + Требуется: %1$s diff --git a/res/values-sl/array.xml b/res/values-sl/array.xml index ba22674f8..bc3404374 100644 --- a/res/values-sl/array.xml +++ b/res/values-sl/array.xml @@ -11,9 +11,4 @@ Dark Light - - Izključeno (ni varno) - Običajno - Polno - diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 304697388..6d83a3572 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -28,7 +28,7 @@ Izdan z licenco GNU GPLv3. Na razpolago Posodobitve Počakajte prosim - Poteka posodobitev spiska aplikacij … + Poteka posodobitev spiska aplikacij… Prejem aplikacije iz Naslov skladišča Spisek uporabljenih skladišč se je spremenil. @@ -52,7 +52,6 @@ Ga želite posodobiti? Tämä ohjelma sisältää mainontaa Napredno Iskanje aplikacij - Način sinhronizacije baze podatkov Združljivost aplikacij Yhteensopimattomat versiot Skrbnik diff --git a/res/values-sr/array.xml b/res/values-sr/array.xml index 0a0c851a6..7d414c084 100644 --- a/res/values-sr/array.xml +++ b/res/values-sr/array.xml @@ -11,9 +11,4 @@ Dark Light - - Искључено (није безбедно) - Нормално - Пуно - diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index bb7a4516e..faf2f69a6 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -29,7 +29,7 @@ Ризнице су места одакле се скидају апликације. Да би сте додали једну, притисните тастер МЕНИ и унесите адресу. -Адреса ризнице би личила на ово: http://f-droid.org/repo +Адреса ризнице би личила на ово: https://f-droid.org/repo Инсталирана Није Инсталирана Додато %s @@ -81,7 +81,6 @@ Прикажи Стручни Претрага апликација - Режим синхронизације базе података Компатибилност апликације Рут Игнориши Додирни Екран diff --git a/res/values-sv/array.xml b/res/values-sv/array.xml index 9edfdb38c..12b70f0e9 100644 --- a/res/values-sv/array.xml +++ b/res/values-sv/array.xml @@ -11,9 +11,4 @@ Mörk Ljus - - Av (osäkert) - Normal - Fullständig - diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 236956d02..63ce10f23 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -7,14 +7,25 @@ Det verkar som att detta program inte är kompatibelt med enheten. Vill ni försöka installera det ändå? Du försöker nedgradera detta program. Detta kan få det att fungera felaktigt eller orsaka förlust av dina data. Vill du ändå försöka nedgradera? Version + Redigera + Ta bort Cacha nerladdade appar + Behåll hämtade apk-filer på SD-kort + Behåll inga apk-filer Uppdateringar Andra Senaste förrådsavsökning: %s aldrig + Automatiskt uppdateringsintervall + Inga automatiska uppdateringar av applistor Endast via WiFi + Uppdatera applistor automatiskt endast över wifi + Uppdatera alltid applistor automatiskt Avisering + Meddela när uppdateringar finns tillgängliga + Meddela inte om uppdateringar Uppdateringshistorik + Antal dagar som appar betraktas som nya: %s Sökresultat Appdetaljer Ingen sådan app funnen @@ -39,6 +50,9 @@ En förrådsadress ser ut så här: https://f-droid.org/repo Lägg till nytt förråd Lägg till Avbryt + Aktivera + Lägg till nyckel + Skriv över Välj förråd att ta bort Uppdatera förråd Tillgängliga @@ -49,7 +63,15 @@ En förrådsadress ser ut så här: https://f-droid.org/repo Var vänlig vänta Uppdaterar programlistan… Hämtar program från + NFC är inte aktiverat! + Gå till NFC-inställningar… Förrådsadress + fingeravtryck (valfritt) + Detta förråd existerar redan! + Detta förråd är redan installerat, detta kommer lägga till ny nyckelinformation. + Detta förråd är redan installerat, bekräfta att du vill återaktivera det. + Inkommande förråd är redan installerat och aktiverat! + Du måste först ta bort detta förråd innan du kan lägga till ett med en annan nyckel! Listan över förråd har ändrats. Vill du uppdatera dem? Uppdatera förråd @@ -59,6 +81,7 @@ Vill du uppdatera dem? Sök Nytt förråd Ta bort förråd + Hitta lokala förråd Kör Dela Installera @@ -79,17 +102,27 @@ Vill du uppdatera dem? Denna app främjar ofria tillägg Denna app främjar ofria nätverkstjänster Denna app beror på andra ofria appar + Källkoden från uppströms är inte fullständigt fri Visning Expert + Visa extra info och aktivera extra inställningar + Dölj extraval för vana användare Sök program - Databassynkroniseringsläge Programkompatibilitet Inkompatibla versioner + Visa appversioner som är inkompatibla med enheten + Dölj appversioner som är inkompatibla med enheten Root + Gråtona inte appar som kräver root-behörighet + Gråtona appar som kräver root-behörighet Ignorera touchscreen + Inkludera alltid appar som kräver touchscreen + Filtrera appar normalt Alla Nyheter Nyligt uppdaterade + Lokala FDroid-förråd + Upptäcker lokala FDroid-förråd… Hämtar %2$s / %3$s (%4$d%%) från %1$s @@ -99,10 +132,34 @@ Vill du uppdatera dem? Ansluter till %1$s Kontrollerar appars kompatibilitet med din enhet… + Sparar programdetaljer (%1$d%%) Inga behörigheter används. Behörigheter för version %s Visa behörigheter + Visa en lista över behörigheter en app behöver + Visa inte behörigheter innan hämtning Du har inte någon app tillgänglig för hantering av %s Kompakt layout + Visa ikoner i en mindre storlek + Visa ikoner i normal storlek Tema + Osignerad + URL + Antal appar + Beskrivning + Senaste uppdatering + Uppdatera + Namn + Detta betyder att listan av program inte kunde verifieras. Du bör vara försiktig med program som hämtats från osignerade index. + Detta förråd har inte använts än. För att se de appar det erbjuder måste du uppdatera det. Då det uppdaterats kommer beskrivning och övriga detaljer finnas tillgängliga här. + Vill du ta bort förrådet \"{0}\" , som innehåller {1} appar? Installerade appar tas INTE bort, men du kommer inte längre kunna uppdatera dem genom F-Droid. + Okänd + Ta bort förråd? + Då ett förråd tas bort kommer inte längre appar därifrån vara tillgängliga via F-Droid. Obs: Alla tidigare installerade appar kommer finnas kvar på din enhet. + Avaktiverade \"%1$s\". Du kommer behöva återaktivera detta förråd för att kunna installera appar från det. + %s eller senare + upp till %s + %1$s upp till %2$s + Din enhet är inte på samma trådlösa nätverk som det lokala förråd du just lagt till! Försök ansluta till detta nätverk: %s + Kräver: %1$s diff --git a/res/values-tr/array.xml b/res/values-tr/array.xml index b7840e71e..73ba4a61a 100644 --- a/res/values-tr/array.xml +++ b/res/values-tr/array.xml @@ -11,9 +11,4 @@ Koyu Açık - - Devre dışı (güvenli değildir) - Normal - Tümü - diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index ab4e6a6c8..4f706b50b 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -7,14 +7,26 @@ Bu paket cihazınızla uyumlu değil gibi görünüyor. Yine de kurmayı denemek istiyor musunuz? Bu uygulamanın eski bir sürümüne dönmek üzeresiniz. Bu, uygulamanın yanlış çalışmasına ve hatta veri kaybına neden olabilir. Devam etmek istiyor musunuz? Sürüm + Düzenle + Sil + NFC göndermesini etkinleştir İndirilen uygulamaları önbelleğe kaydet + İndirilen apk dosyalarını SD kartında tut + Apk dosyalarını saklama Güncellemeler Diğer Son depo analizi: %s asla + Otomatik güncelleme aralığı + Hiçbir otomatik uygulama listesi güncellemesi olmasın Sadece WiFi ile + Uygulama listesini otomatik olarak sadece wifi ile güncelle + Uygulama listesini daima otomatik olarak güncelle Bildirme + Güncellemeler bulunduğunda bunu bildir + Güncellemeleri hiçbir zaman bildirme Güncelleme tarihçesi + Uygulamaların yeni sayılacağı gün sayısı: %s Arama Sonuçları Uygulama Detayları Böyle bir uygulama bulunamadı @@ -39,6 +51,9 @@ Bir depo adresi şuna benzer: https://f-droid.org/repo Yeni depo ekle Ekle İptal + Etkinleştir + Anahtar ekle + Üzerine yaz Kaldırılacak depoyu seç Depoları güncelle Mevcut @@ -49,16 +64,29 @@ Bir depo adresi şuna benzer: https://f-droid.org/repo Bekleyiniz Uygulama listesi güncelleniyor… Uygulama buradan alınıyor: + NFC etkinleştirilmemiştir! + NFC ayarlarına git… + Hiçbir Bluetooth gönderme metodu bulunamadı, birisini seçin! + Bluetooth gönderme metodu seç Depo adresi + Parmak izi (seçime dayalı) + Bu depo zaten mevcut! + Bu depo zaten ayarlanmıştır, bu yeni anahtar verisi ekleyecektir. + Bu depo zaten ayarlanmıştır, tekrar etkinleştirmek istediğinizi teyit ediniz. + Gelen depo zaten kuruludur ve etkinleştirilmiştir! + Değişik anahtarla depo eklemeden evvel bu depoyu silmeniz gerekmektedir! + Yanlış yapılandırılmış depo URI\'si görmezden geliniyor: %s Kullanılan depoların listesi değişti. Güncellemek ister misiniz? Depoları güncelle Depoları Yönet + Bluetooth FDroid.apk… Tercihler Hakkında Arama Yeni Depo Depoyu kaldır + Yerel depoları bul Çalıştır Paylaş Kur @@ -79,17 +107,27 @@ Güncellemek ister misiniz? Bu uygulama özgür olmayan eklentiler tavsiye eder Bu uygulama özgür olmayan ağ servisleri tavsiye eder Bu uygulama özgür olmayan başka uygulamalara bağımlıdır + Kaynak kod tamamen özgür değildir Görüntüleme Uzman + Ek veri göster ve ilâve ayarları etkinleştir + Tecrübeli kullanıcılar için ilâveleri sakla Uygulama ara - Veritabanı eşleşme modu Uygulama uyumu Uyumsuz sürümler + Cihazla uyumsuz uygulama sürümlerini göster + Cihazla uyumsuz uygulama sürümlerini sakla Root + Root yetkileri gerektiren uygulamaları gri yapma + Root yetkileri gerektiren uygulamaları gri olarak göster Dokunmatik ekranı yok say + Dokunmatik ekran gerektiren uygulamaları daima dahil et + Uygulamaları normal olarak süz Tümü Yeni olanlar Yakın geçmişte güncellenen + Yerel FDroid depoları + Yerel FDroid depoları keşfediliyor… İndiriliyor %2$s / %3$s (%4$d%%) şuradan %1$s @@ -99,10 +137,47 @@ Güncellemek ister misiniz? %1$s konumuna bağlanılıyor Uygulamaların cihazınızla uyumluluğu kontrol ediliyor… + Uygulama detayları kaydediliyor (%1$d%%) Hiçbir izin kullanılmıyor. %s sürümü için izinler İzinleri göster + Uygulamaların gerektirdiği izinlerin listesini göster + İndirmeden önce izinleri gösterme %s unsurunu yönetecek hiçbir mevcut uygulamanız yok Yoğun düzen + İkonları daha küçük boyutta görüntüle + İkonları normal boyutta görüntüle Tema + İmzasız + URL + Uygulama sayısı + Depo imza anahtarının parmak izi (SHA-256) + Betimleme + Son güncelleme + Güncelle + İsim + Bu, uygulama listesinin + teyit edilemediği anlamına gelir. İmzasız + endekslerden indirilen uygulamaları dikkatle + kullanmanız gerekir. + Bu depo henüz kullanılmamıştır. + Sunduğu uygulamaları görmek için onu güncellemeniz gerekir. + +Güncelleme yapıldığında betimleler ve diğer ayrıntılar burada gösterilecektir. + {1} uygulama içeren \"{0}\" deposunu silmek istiyor musunuz? Kurulu uygulamalar KALDIRILMAYACAKTIR, ancak bundan böyle onları F-Droid vasıtasıyla güncellemek mümkün olmayacaktır. + Bilinmiyor + Depo silinsin mi? + Bir depoyu silmek, ondan indirilen uygulamaların + bundan böyle F-Droid vasıtasıyla elde edilemeyeceği anlamına gelir. + +Not: Tüm + önceden kurulan uygulamalar cihazınızda kalacaktır. + \"%1$s\" devre dışı bırakıldı. + +Ondan uygulama indirmek için bu depoyu tekrar etkinleştirmeniz gerekecektir. + %s ya da sonrası + %s değerine kadar + %1$s değerinden %2$s değerine kadar + Cihazınız eklemiş olduğunuz yerel depoyla aynı WiFi\'de değildir. Şu şebekeye katılmayı deneyin: %s + Gerektirdiği: %1$s diff --git a/res/values-ug/array.xml b/res/values-ug/array.xml index 35b79432f..25e167824 100644 --- a/res/values-ug/array.xml +++ b/res/values-ug/array.xml @@ -11,9 +11,4 @@ قاراڭغۇ يورۇق - - تاقاق (بىخەتەر ئەمەس) - نورمال - تولۇق - diff --git a/res/values-ug/strings.xml b/res/values-ug/strings.xml index ffb278803..0b1921925 100644 --- a/res/values-ug/strings.xml +++ b/res/values-ug/strings.xml @@ -29,7 +29,7 @@ خەزىنە ئەپلەرنىڭ تارقىتىلىش مەنبەسى بولۇپ، مەنبە قوشۇشتا، تىزىملىك توپچىنى بېسىپ، ئاندىن URLنى كىرگۈزۈڭ. -خەزىنە ئادرېسى بۇنىڭغا ئوخشاش بولىدۇ: http://f-droid.org/repo +خەزىنە ئادرېسى بۇنىڭغا ئوخشاش بولىدۇ: https://f-droid.org/repo ئورنىتىلغان ئورنىتىلمىغان %s دا قوشۇلغان @@ -82,7 +82,6 @@ كۆرسەت ئالىي ئەپ ئىزدە - ساندان قەدەمداش ھالەت ئەپ ماسلىشىشچانلىقى ماسلاشمايدىغان نەشرىلىرى Root diff --git a/res/values-uk/array.xml b/res/values-uk/array.xml index 0d43d54c8..83ea4a1e8 100644 --- a/res/values-uk/array.xml +++ b/res/values-uk/array.xml @@ -11,9 +11,4 @@ Dark Light - - Ніколи (небезпечно) - Типово - Повністю - diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 4ea3a11c4..d9af9a175 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -53,7 +53,6 @@ Звантаження скасовано Експерт Пошук програм - Синхронізація БД Сумісність Суперкористувач Ігнорувати тачскрін diff --git a/res/values-zh-rCN/array.xml b/res/values-zh-rCN/array.xml index 120aefcf0..dd10ac48a 100644 --- a/res/values-zh-rCN/array.xml +++ b/res/values-zh-rCN/array.xml @@ -11,9 +11,4 @@ Dark Light - - 关闭(存在安全风险) - 正常 - 完整的 - diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 80451bdda..b12da2de2 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -53,7 +53,6 @@ 下载取消 高级 搜索应用 - 数据同步模式 应用兼容性 Root 忽略需要触屏的应用 diff --git a/res/values/array.xml b/res/values/array.xml index 7481d8fa6..bea7d606e 100644 --- a/res/values/array.xml +++ b/res/values/array.xml @@ -12,10 +12,4 @@ Dark Light - - - Off (unsafe) - Normal - Full - diff --git a/res/values/default_repo.xml b/res/values/default_repo.xml index a94f210b3..638c93903 100644 --- a/res/values/default_repo.xml +++ b/res/values/default_repo.xml @@ -1,10 +1,18 @@ - F-Droid + 2 + + F-Droid + 1 + 10 + https://f-droid.org/repo + The official FDroid repository. Applications in this repository are mostly built directory from the source code. Some are official binaries built by the original application developers - these will be replaced by source-built versions over time. + 3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef + F-Droid Archive - https://f-droid.org/repo + 0 + 20 https://f-droid.org/archive - The official FDroid repository. Applications in this repository are mostly built directory from the source code. Some are official binaries built by the original application developers - these will be replaced by source-built versions over time. The archive repository of the F-Droid client. This contains older versions of applications from the main repository. - 3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef + 3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef diff --git a/res/values/dimen.xml b/res/values/dimen.xml index 2ba4e3cd3..f20a66205 100644 --- a/res/values/dimen.xml +++ b/res/values/dimen.xml @@ -1,7 +1,5 @@ - - 64dp - - 48dp + 48dp + 32dp diff --git a/res/values/no_trans.xml b/res/values/no_trans.xml index 1adfaed36..af249254d 100644 --- a/res/values/no_trans.xml +++ b/res/values/no_trans.xml @@ -2,7 +2,7 @@ F-Droid - 0.57-test + 0.64-test https://f-droid.org team@f-droid.org @@ -22,12 +22,6 @@ 24 - - off - normal - full - - dark light diff --git a/res/values/strings.xml b/res/values/strings.xml index f0d7d4506..b068d0ae9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -9,6 +9,7 @@ Version Edit Delete + Enable NFC Send… App cache Keep downloaded apk files on SD card Do not keep any apk files @@ -73,6 +74,11 @@ Please Wait Updating application list… Getting application from + NFC is not enabled! + Go to NFC Settings… + No Bluetooth send method found, choose one! + Choose Bluetooth send method + Send via Bluetooth Repository address Fingerprint (optional) @@ -81,6 +87,7 @@ This repo is already setup, confirm that you want to re-enable it. The incoming repo is already setup and enabled! You must first delete this repo before you can add one with a different key! + Ignoring malformed repo URI: %s The list of used repositories has changed.\nDo you @@ -88,11 +95,13 @@ Update Repos Repositories + Bluetooth FDroid.apk… Preferences About Search New Repository Remove Repository + Find Local Repos Run Share @@ -126,8 +135,6 @@ Search applications - Database sync mode - Application compatibility Incompatible versions Show app versions incompatible with the device @@ -143,6 +150,9 @@ What\'s New Recently Updated + Local FDroid Repos + Discovering local FDroid repos… + + + + + + + + + diff --git a/test/ant.properties b/test/ant.properties new file mode 100644 index 000000000..99458bdd5 --- /dev/null +++ b/test/ant.properties @@ -0,0 +1,19 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked into Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + +tested.project.dir=.. +test.runner=com.zutubi.android.junitreport.JUnitReportTestRunner diff --git a/test/custom_rules.xml b/test/custom_rules.xml new file mode 100644 index 000000000..ee90d3fac --- /dev/null +++ b/test/custom_rules.xml @@ -0,0 +1,19 @@ + + + + + + Downloading XML test report (/data/data/${tested.package}/files/junit-report.xml)… + + + + + + + + + + diff --git a/test/libs/android-junit-report-1.5.8.README b/test/libs/android-junit-report-1.5.8.README new file mode 100644 index 000000000..a89c98533 --- /dev/null +++ b/test/libs/android-junit-report-1.5.8.README @@ -0,0 +1,5 @@ + +Needed for Jenkins to get JUnit reports. + +* https://github.com/jsankey/android-junit-report +* https://github.com/downloads/jsankey/android-junit-report/android-junit-report-1.5.8.jar diff --git a/test/libs/android-junit-report-1.5.8.jar b/test/libs/android-junit-report-1.5.8.jar new file mode 100644 index 000000000..09e6a2d4f Binary files /dev/null and b/test/libs/android-junit-report-1.5.8.jar differ diff --git a/test/proguard-project.txt b/test/proguard-project.txt new file mode 100644 index 000000000..f2fe1559a --- /dev/null +++ b/test/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/tests/project.properties b/test/project.properties similarity index 96% rename from tests/project.properties rename to test/project.properties index 1f896ec2b..4ab125693 100644 --- a/tests/project.properties +++ b/test/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-4 +target=android-19 diff --git a/test/src/android/test/ProviderTestCase2MockContext.java b/test/src/android/test/ProviderTestCase2MockContext.java new file mode 100644 index 000000000..f0b64122e --- /dev/null +++ b/test/src/android/test/ProviderTestCase2MockContext.java @@ -0,0 +1,228 @@ +/* + * 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. + */ + +package android.test; + +import android.content.ContentProvider; +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import android.test.mock.MockContext; +import android.test.mock.MockContentResolver; +import android.database.DatabaseUtils; + +import java.io.File; + +/** + * This test case class provides a framework for testing a single + * {@link ContentProvider} and for testing your app code with an + * isolated content provider. Instead of using the system map of + * providers that is based on the manifests of other applications, the test + * case creates its own internal map. It then uses this map to resolve providers + * given an authority. This allows you to inject test providers and to null out + * providers that you do not want to use. + *

+ * This test case also sets up the following mock objects: + *

+ *
    + *
  • + * An {@link android.test.IsolatedContext} that stubs out Context methods that might + * affect the rest of the running system, while allowing tests to do real file and + * database work. + *
  • + *
  • + * A {@link android.test.mock.MockContentResolver} that provides the functionality of a + * regular content resolver, but uses {@link IsolatedContext}. It stubs out + * {@link ContentResolver#notifyChange(Uri, ContentObserver, boolean)} to + * prevent the test from affecting the running system. + *
  • + *
  • + * An instance of the provider under test, running in an {@link IsolatedContext}. + *
  • + *
+ *

+ * This framework is set up automatically by the base class' {@link #setUp()} method. If you + * override this method, you must call the super method as the first statement in + * your override. + *

+ *

+ * In order for their tests to be run, concrete subclasses must provide their own + * constructor with no arguments. This constructor must call + * {@link #ProviderTestCase2MockContext(Class, String)} as its first operation. + *

+ * For more information on content provider testing, please see + * Content Provider Testing. + */ +public abstract class ProviderTestCase2MockContext extends AndroidTestCase { + + Class mProviderClass; + String mProviderAuthority; + + private IsolatedContext mProviderContext; + private MockContentResolver mResolver; + + private class MockContext2 extends MockContext { + + @Override + public Resources getResources() { + return getContext().getResources(); + } + + @Override + public File getDir(String name, int mode) { + // name the directory so the directory will be separated from + // one created through the regular Context + return getContext().getDir("mockcontext2_" + name, mode); + } + + @Override + public Context getApplicationContext() { + return this; + } + } + /** + * Constructor. + * + * @param providerClass The class name of the provider under test + * @param providerAuthority The provider's authority string + */ + public ProviderTestCase2MockContext(Class providerClass, String providerAuthority) { + mProviderClass = providerClass; + mProviderAuthority = providerAuthority; + } + + private T mProvider; + + /** + * Returns the content provider created by this class in the {@link #setUp()} method. + * @return T An instance of the provider class given as a parameter to the test case class. + */ + public T getProvider() { + return mProvider; + } + + abstract protected Context createMockContext(Context delegate); + + /** + * Sets up the environment for the test fixture. + *

+ * Creates a new + * {@link android.test.mock.MockContentResolver}, a new IsolatedContext + * that isolates the provider's file operations, and a new instance of + * the provider under test within the isolated environment. + *

+ * + * @throws Exception + */ + @Override + protected void setUp() throws Exception { + super.setUp(); + + mResolver = new MockContentResolver(); + final String filenamePrefix = "test."; + RenamingDelegatingContext targetContextWrapper = new + RenamingDelegatingContext( + createMockContext(new MockContext2()), // The context that most methods are delegated to + getContext(), // The context that file methods are delegated to + filenamePrefix); + mProviderContext = new IsolatedContext(mResolver, targetContextWrapper); + + mProvider = mProviderClass.newInstance(); + mProvider.attachInfo(mProviderContext, null); + assertNotNull(mProvider); + mResolver.addProvider(mProviderAuthority, getProvider()); + } + + /** + * Tears down the environment for the test fixture. + *

+ * Calls {@link android.content.ContentProvider#shutdown()} on the + * {@link android.content.ContentProvider} represented by mProvider. + */ + @Override + protected void tearDown() throws Exception { + mProvider.shutdown(); + super.tearDown(); + } + + /** + * Gets the {@link MockContentResolver} created by this class during initialization. You + * must use the methods of this resolver to access the provider under test. + * + * @return A {@link MockContentResolver} instance. + */ + public MockContentResolver getMockContentResolver() { + return mResolver; + } + + /** + * Gets the {@link IsolatedContext} created by this class during initialization. + * @return The {@link IsolatedContext} instance + */ + public IsolatedContext getMockContext() { + return mProviderContext; + } + + /** + *

+ * Creates a new content provider of the same type as that passed to the test case class, + * with an authority name set to the authority parameter, and using an SQLite database as + * the underlying data source. The SQL statement parameter is used to create the database. + * This method also creates a new {@link MockContentResolver} and adds the provider to it. + *

+ *

+ * Both the new provider and the new resolver are put into an {@link IsolatedContext} + * that uses the targetContext parameter for file operations and a {@link MockContext} + * for everything else. The IsolatedContext prepends the filenamePrefix parameter to + * file, database, and directory names. + *

+ *

+ * This is a convenience method for creating a "mock" provider that can contain test data. + *

+ * + * @param targetContext The context to use as the basis of the IsolatedContext + * @param filenamePrefix A string that is prepended to file, database, and directory names + * @param providerClass The type of the provider being tested + * @param authority The authority string to associated with the test provider + * @param databaseName The name assigned to the database + * @param databaseVersion The version assigned to the database + * @param sql A string containing the SQL statements that are needed to create the desired + * database and its tables. The format is the same as that generated by the + * sqlite3 tool's .dump command. + * @return ContentResolver A new {@link MockContentResolver} linked to the provider + * + * @throws IllegalAccessException + * @throws InstantiationException + */ + public static ContentResolver newResolverWithContentProviderFromSql( + Context targetContext, String filenamePrefix, Class providerClass, String authority, + String databaseName, int databaseVersion, String sql) + throws IllegalAccessException, InstantiationException { + MockContentResolver resolver = new MockContentResolver(); + RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext( + new MockContext(), // The context that most methods are delegated to + targetContext, // The context that file methods are delegated to + filenamePrefix); + Context context = new IsolatedContext(resolver, targetContextWrapper); + DatabaseUtils.createDbFromSqlStatements(context, databaseName, databaseVersion, sql); + + T provider = providerClass.newInstance(); + provider.attachInfo(context, null); + resolver.addProvider(authority, provider); + + return resolver; + } +} diff --git a/test/src/mock/MockCategoryResources.java b/test/src/mock/MockCategoryResources.java new file mode 100644 index 000000000..2831049d8 --- /dev/null +++ b/test/src/mock/MockCategoryResources.java @@ -0,0 +1,26 @@ +package mock; + +import android.content.Context; +import android.test.mock.*; +import org.fdroid.fdroid.*; + +public class MockCategoryResources extends MockFDroidResources { + + public MockCategoryResources(Context getStringDelegatingContext) { + super(getStringDelegatingContext); + } + + @Override + public String getString(int id) { + if (id == R.string.category_all) { + return "All"; + } else if (id == R.string.category_recentlyupdated) { + return "Recently Updated"; + } else if (id == R.string.category_whatsnew) { + return "Whats New"; + } else { + return ""; + } +} + +} diff --git a/test/src/mock/MockContextEmptyComponents.java b/test/src/mock/MockContextEmptyComponents.java new file mode 100644 index 000000000..eb962bbe9 --- /dev/null +++ b/test/src/mock/MockContextEmptyComponents.java @@ -0,0 +1,14 @@ +package mock; + +/** + * As more components are required to test different parts of F-Droid, we can + * create them and add them here (and accessors to the parent class). + */ +public class MockContextEmptyComponents extends MockContextSwappableComponents { + + public MockContextEmptyComponents() { + setPackageManager(new MockEmptyPackageManager()); + setResources(new MockEmptyResources()); + } + +} diff --git a/test/src/mock/MockContextSwappableComponents.java b/test/src/mock/MockContextSwappableComponents.java new file mode 100644 index 000000000..9cb09f466 --- /dev/null +++ b/test/src/mock/MockContextSwappableComponents.java @@ -0,0 +1,43 @@ +package mock; + +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.test.mock.*; + +public class MockContextSwappableComponents extends MockContext { + + private PackageManager packageManager; + + private Resources resources; + private MockContentResolver contentResolver; + + public MockContextSwappableComponents setPackageManager(PackageManager pm) { + packageManager = pm; + return this; + } + + public MockContextSwappableComponents setResources(Resources resources) { + this.resources = resources; + return this; + } + + public MockContextSwappableComponents setContentResolver(MockContentResolver contentResolver) { + this.contentResolver = contentResolver; + return this; + } + + @Override + public PackageManager getPackageManager() { + return packageManager; + } + + @Override + public Resources getResources() { + return resources; + } + + @Override + public MockContentResolver getContentResolver() { + return contentResolver; + } +} diff --git a/test/src/mock/MockEmptyPackageManager.java b/test/src/mock/MockEmptyPackageManager.java new file mode 100644 index 000000000..39fdee310 --- /dev/null +++ b/test/src/mock/MockEmptyPackageManager.java @@ -0,0 +1,16 @@ +package mock; + +import android.content.pm.PackageInfo; +import android.test.mock.MockPackageManager; + +import java.util.ArrayList; +import java.util.List; + +public class MockEmptyPackageManager extends MockPackageManager { + + @Override + public List getInstalledPackages(int flags) { + return new ArrayList(); + } + +} diff --git a/test/src/mock/MockEmptyResources.java b/test/src/mock/MockEmptyResources.java new file mode 100644 index 000000000..fdc06e47f --- /dev/null +++ b/test/src/mock/MockEmptyResources.java @@ -0,0 +1,12 @@ +package mock; + +import android.test.mock.MockResources; + +public class MockEmptyResources extends MockResources { + + @Override + public String getString(int id) { + return ""; + } + +} diff --git a/test/src/mock/MockFDroidResources.java b/test/src/mock/MockFDroidResources.java new file mode 100644 index 000000000..c2b716d2f --- /dev/null +++ b/test/src/mock/MockFDroidResources.java @@ -0,0 +1,36 @@ +package mock; + +import android.content.Context; +import android.content.res.Resources; +import android.test.mock.*; +import org.fdroid.fdroid.*; + +public class MockFDroidResources extends MockResources { + + private Context getStringDelegatingContext; + + public MockFDroidResources(Context getStringDelegatingContext) { + this.getStringDelegatingContext = getStringDelegatingContext; + } + + @Override + public String getString(int id) { + return getStringDelegatingContext.getString(id); + } + + @Override + public int getInteger(int id) { + if (id == R.integer.default_repo_inuse1) { + return 1; + } else if (id == R.integer.default_repo_inuse2) { + return 0; + } else if (id == R.integer.default_repo_priority1) { + return 10; + } else if (id == R.integer.default_repo_priority2) { + return 20; + } else { + return 0; + } +} + +} diff --git a/test/src/mock/MockInstallablePackageManager.java b/test/src/mock/MockInstallablePackageManager.java new file mode 100644 index 000000000..f291c1517 --- /dev/null +++ b/test/src/mock/MockInstallablePackageManager.java @@ -0,0 +1,52 @@ +package mock; + +import android.content.pm.PackageInfo; +import android.test.mock.MockPackageManager; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class MockInstallablePackageManager extends MockPackageManager { + + private List info = new ArrayList(); + + @Override + public List getInstalledPackages(int flags) { + return info; + } + + public void install(String id, int version, String versionName) { + PackageInfo existing = getPackageInfo(id); + if (existing != null) { + existing.versionCode = version; + existing.versionName = versionName; + } else { + PackageInfo p = new PackageInfo(); + p.packageName = id; + p.versionCode = version; + p.versionName = versionName; + info.add(p); + } + } + + public PackageInfo getPackageInfo(String id) { + for (PackageInfo i : info) { + if (i.packageName.equals(id)) { + return i; + } + } + return null; + } + + public void remove(String id) { + for (Iterator it = info.iterator(); it.hasNext();) { + PackageInfo info = it.next(); + if (info.packageName.equals(id)) { + it.remove(); + return; + } + } + } + +} diff --git a/test/src/org/fdroid/fdroid/ApkProviderHelperTest.java b/test/src/org/fdroid/fdroid/ApkProviderHelperTest.java new file mode 100644 index 000000000..678c9903f --- /dev/null +++ b/test/src/org/fdroid/fdroid/ApkProviderHelperTest.java @@ -0,0 +1,202 @@ +package org.fdroid.fdroid; + +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import org.fdroid.fdroid.data.Apk; +import org.fdroid.fdroid.data.ApkProvider; +import org.fdroid.fdroid.mock.MockApk; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +public class ApkProviderHelperTest extends BaseApkProviderTest { + + public void testKnownApks() { + + for (int i = 0; i < 7; i ++) + TestUtils.insertApk(this, "org.fdroid.fdroid", i); + + for (int i = 0; i < 9; i ++) + TestUtils.insertApk(this, "org.example", i); + + for (int i = 0; i < 3; i ++) + TestUtils.insertApk(this, "com.example", i); + + TestUtils.insertApk(this, "com.apk.thingo", 1); + + Apk[] known = { + new MockApk("org.fdroid.fdroid", 1), + new MockApk("org.fdroid.fdroid", 3), + new MockApk("org.fdroid.fdroid", 5), + + new MockApk("com.example", 1), + new MockApk("com.example", 2), + }; + + Apk[] unknown = { + new MockApk("org.fdroid.fdroid", 7), + new MockApk("org.fdroid.fdroid", 9), + new MockApk("org.fdroid.fdroid", 11), + new MockApk("org.fdroid.fdroid", 13), + + new MockApk("com.example", 3), + new MockApk("com.example", 4), + new MockApk("com.example", 5), + + new MockApk("info.example", 1), + new MockApk("info.example", 2), + }; + + List apksToCheck = new ArrayList(known.length + unknown.length); + Collections.addAll(apksToCheck, known); + Collections.addAll(apksToCheck, unknown); + + String[] projection = { + ApkProvider.DataColumns.APK_ID, + ApkProvider.DataColumns.VERSION_CODE + }; + + List knownApks = ApkProvider.Helper.knownApks(getMockContext(), apksToCheck, projection); + + assertResultCount(known.length, knownApks); + + for (Apk knownApk : knownApks) + assertContains(knownApks, knownApk); + } + + public void testFindByApp() { + + for (int i = 0; i < 7; i ++) + TestUtils.insertApk(this, "org.fdroid.fdroid", i); + + for (int i = 0; i < 9; i ++) + TestUtils.insertApk(this, "org.example", i); + + for (int i = 0; i < 3; i ++) + TestUtils.insertApk(this, "com.example", i); + + TestUtils.insertApk(this, "com.apk.thingo", 1); + + assertTotalApkCount(7 + 9 + 3 + 1); + + List fdroidApks = ApkProvider.Helper.findByApp(getMockContext(), "org.fdroid.fdroid"); + assertResultCount(7, fdroidApks); + assertBelongsToApp(fdroidApks, "org.fdroid.fdroid"); + + List exampleApks = ApkProvider.Helper.findByApp(getMockContext(), "org.example"); + assertResultCount(9, exampleApks); + assertBelongsToApp(exampleApks, "org.example"); + + List exampleApks2 = ApkProvider.Helper.findByApp(getMockContext(), "com.example"); + assertResultCount(3, exampleApks2); + assertBelongsToApp(exampleApks2, "com.example"); + + List thingoApks = ApkProvider.Helper.findByApp(getMockContext(), "com.apk.thingo"); + assertResultCount(1, thingoApks); + assertBelongsToApp(thingoApks, "com.apk.thingo"); + } + + public void testUpdate() { + + Uri apkUri = TestUtils.insertApk(this, "com.example", 10); + + String[] allFields = ApkProvider.DataColumns.ALL; + Cursor cursor = getMockContentResolver().query(apkUri, allFields, null, null, null); + assertResultCount(1, cursor); + + cursor.moveToFirst(); + Apk apk = new Apk(cursor); + + assertEquals("com.example", apk.id); + assertEquals(10, apk.vercode); + + assertNull(apk.features); + assertNull(apk.added); + assertNull(apk.hashType); + + apk.features = Utils.CommaSeparatedList.make("one,two,three"); + long dateTimestamp = System.currentTimeMillis(); + apk.added = new Date(dateTimestamp); + apk.hashType = "i'm a hash type"; + + ApkProvider.Helper.update(getMockContext(), apk); + + // Should not have inserted anything else, just updated the already existing apk. + Cursor allCursor = getMockContentResolver().query(ApkProvider.getContentUri(), allFields, null, null, null); + assertResultCount(1, allCursor); + + Cursor updatedCursor = getMockContentResolver().query(apkUri, allFields, null, null, null); + assertResultCount(1, updatedCursor); + + updatedCursor.moveToFirst(); + Apk updatedApk = new Apk(updatedCursor); + + assertEquals("com.example", updatedApk.id); + assertEquals(10, updatedApk.vercode); + + assertNotNull(updatedApk.features); + assertNotNull(updatedApk.added); + assertNotNull(updatedApk.hashType); + + assertEquals("one,two,three", updatedApk.features.toString()); + assertEquals(new Date(dateTimestamp).getYear(), updatedApk.added.getYear()); + assertEquals(new Date(dateTimestamp).getMonth(), updatedApk.added.getMonth()); + assertEquals(new Date(dateTimestamp).getDay(), updatedApk.added.getDay()); + assertEquals("i'm a hash type", updatedApk.hashType); + } + + public void testFind() { + + // Insert some random apks either side of the "com.example", so that + // the Helper.find() method doesn't stumble upon the app we are interested + // in by shear dumb luck... + for (int i = 0; i < 10; i ++) + TestUtils.insertApk(this, "org.fdroid.apk." + i, i); + + ContentValues values = new ContentValues(); + values.put(ApkProvider.DataColumns.VERSION, "v1.1"); + values.put(ApkProvider.DataColumns.HASH, "xxxxyyyy"); + values.put(ApkProvider.DataColumns.HASH_TYPE, "a hash type"); + TestUtils.insertApk(this, "com.example", 11, values); + + // ...and a few more for good measure... + for (int i = 15; i < 20; i ++) + TestUtils.insertApk(this, "com.other.thing." + i, i); + + Apk apk = ApkProvider.Helper.find(getMockContext(), "com.example", 11); + + assertNotNull(apk); + + // The find() method populates ALL fields if you don't specify any, + // so we expect to find each of the ones we inserted above... + assertEquals("com.example", apk.id); + assertEquals(11, apk.vercode); + assertEquals("v1.1", apk.version); + assertEquals("xxxxyyyy", apk.hash); + assertEquals("a hash type", apk.hashType); + + String[] projection = { + ApkProvider.DataColumns.APK_ID, + ApkProvider.DataColumns.HASH + }; + + Apk apkLessFields = ApkProvider.Helper.find(getMockContext(), "com.example", 11, projection); + + assertNotNull(apkLessFields); + + assertEquals("com.example", apkLessFields.id); + assertEquals("xxxxyyyy", apkLessFields.hash); + + // Didn't ask for these fields, so should be their default values... + assertNull(apkLessFields.hashType); + assertNull(apkLessFields.version); + assertEquals(0, apkLessFields.vercode); + + Apk notFound = ApkProvider.Helper.find(getMockContext(), "com.doesnt.exist", 1000); + assertNull(notFound); + } + +} diff --git a/test/src/org/fdroid/fdroid/ApkProviderTest.java b/test/src/org/fdroid/fdroid/ApkProviderTest.java new file mode 100644 index 000000000..e77ef41bc --- /dev/null +++ b/test/src/org/fdroid/fdroid/ApkProviderTest.java @@ -0,0 +1,313 @@ +package org.fdroid.fdroid; + +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; + +import org.fdroid.fdroid.data.Apk; +import org.fdroid.fdroid.data.ApkProvider; +import org.fdroid.fdroid.data.AppProvider; +import org.fdroid.fdroid.data.RepoProvider; +import org.fdroid.fdroid.mock.MockApk; +import org.fdroid.fdroid.mock.MockApp; +import org.fdroid.fdroid.mock.MockRepo; + +import java.util.ArrayList; +import java.util.List; + +public class ApkProviderTest extends BaseApkProviderTest { + + public void testUris() { + assertInvalidUri(ApkProvider.getAuthority()); + assertInvalidUri(RepoProvider.getContentUri()); + + List apks = new ArrayList(3); + for (int i = 0; i < 10; i ++) { + apks.add(new MockApk("com.example." + i, i)); + } + + assertValidUri(ApkProvider.getContentUri()); + assertValidUri(ApkProvider.getAppUri("org.fdroid.fdroid")); + assertValidUri(ApkProvider.getContentUri(new MockApk("org.fdroid.fdroid", 100))); + assertValidUri(ApkProvider.getContentUri()); + assertValidUri(ApkProvider.getContentUri(apks)); + assertValidUri(ApkProvider.getContentUri("org.fdroid.fdroid", 100)); + assertValidUri(ApkProvider.getRepoUri(1000)); + + List manyApks = new ArrayList(ApkProvider.MAX_APKS_TO_QUERY - 5); + for (int i = 0; i < ApkProvider.MAX_APKS_TO_QUERY - 1; i ++) { + manyApks.add(new MockApk("com.example." + i, i)); + } + assertValidUri(ApkProvider.getContentUri(manyApks)); + + manyApks.add(new MockApk("org.fdroid.fdroid.1", 1)); + manyApks.add(new MockApk("org.fdroid.fdroid.2", 2)); + try { + // Technically, it is a valid URI, because it doesn't + // throw an UnsupportedOperationException. However it + // is still not okay (we run out of bindable parameters + // in the sqlite query. + assertValidUri(ApkProvider.getContentUri(manyApks)); + fail(); + } catch (IllegalArgumentException e) { + // This is the expected error behaviour. + } catch (Exception e) { + fail(); + } + } + + public void testAppApks() { + for (int i = 1; i <= 10; i ++) { + TestUtils.insertApk(this, "org.fdroid.fdroid", i); + TestUtils.insertApk(this, "com.example", i); + } + + assertTotalApkCount(20); + + Cursor fdroidApks = getMockContentResolver().query( + ApkProvider.getAppUri("org.fdroid.fdroid"), + getMinimalProjection(), + null, null, null); + assertResultCount(10, fdroidApks); + assertBelongsToApp(fdroidApks, "org.fdroid.fdroid"); + + Cursor exampleApks = getMockContentResolver().query( + ApkProvider.getAppUri("com.example"), + getMinimalProjection(), + null, null, null); + assertResultCount(10, exampleApks); + assertBelongsToApp(exampleApks, "com.example"); + + ApkProvider.Helper.deleteApksByApp(getMockContext(), new MockApp("com.example")); + + Cursor all = queryAllApks(); + assertResultCount(10, all); + assertBelongsToApp(all, "org.fdroid.fdroid"); + } + + public void testInvalidUpdateUris() { + Apk apk = new MockApk("org.fdroid.fdroid", 10); + + List apks = new ArrayList(); + apks.add(apk); + + assertCantUpdate(ApkProvider.getContentUri()); + assertCantUpdate(ApkProvider.getAppUri("org.fdroid.fdroid")); + assertCantUpdate(ApkProvider.getRepoUri(1)); + assertCantUpdate(ApkProvider.getContentUri(apks)); + assertCantUpdate(Uri.withAppendedPath(ApkProvider.getContentUri(), "some-random-path")); + + // The only valid ones are: + // ApkProvider.getContentUri(apk) + // ApkProvider.getContentUri(id, version) + // which are tested elsewhere. + } + + public void testDeleteArbitraryApks() { + Apk one = insertApkForRepo("com.example.one", 1, 10); + Apk two = insertApkForRepo("com.example.two", 1, 10); + Apk three = insertApkForRepo("com.example.three", 1, 10); + Apk four = insertApkForRepo("com.example.four", 1, 10); + Apk five = insertApkForRepo("com.example.five", 1, 10); + + assertTotalApkCount(5); + + assertEquals("com.example.one", one.id); + assertEquals("com.example.two", two.id); + assertEquals("com.example.five", five.id); + + String[] expectedIds = { + "com.example.one", + "com.example.two", + "com.example.three", + "com.example.four", + "com.example.five", + }; + + List all = ApkProvider.Helper.findByRepo(getSwappableContext(), new MockRepo(10), ApkProvider.DataColumns.ALL); + List actualIds = new ArrayList(); + for (Apk apk : all) { + actualIds.add(apk.id); + } + + TestUtils.assertContainsOnly(actualIds, expectedIds); + + List toDelete = new ArrayList(3); + toDelete.add(two); + toDelete.add(three); + toDelete.add(four); + ApkProvider.Helper.deleteApks(getSwappableContext(), toDelete); + + assertTotalApkCount(2); + + List allRemaining = ApkProvider.Helper.findByRepo(getSwappableContext(), new MockRepo(10), ApkProvider.DataColumns.ALL); + List actualRemainingIds = new ArrayList(); + for (Apk apk : allRemaining) { + actualRemainingIds.add(apk.id); + } + + String[] expectedRemainingIds = { + "com.example.one", + "com.example.five", + }; + + TestUtils.assertContainsOnly(actualRemainingIds, expectedRemainingIds); + } + + public void testInvalidDeleteUris() { + Apk apk = new MockApk("org.fdroid.fdroid", 10); + + assertCantDelete(ApkProvider.getContentUri()); + assertCantDelete(ApkProvider.getContentUri("org.fdroid.fdroid", 10)); + assertCantDelete(ApkProvider.getContentUri(apk)); + assertCantDelete(Uri.withAppendedPath(ApkProvider.getContentUri(), "some-random-path")); + } + + public void testRepoApks() { + + final long REPO_KEEP = 1; + final long REPO_DELETE = 2; + + // Insert apks into two repos, one of which we will later purge the + // the apks from. + for (int i = 1; i <= 5; i ++) { + insertApkForRepo("org.fdroid.fdroid", i, REPO_KEEP); + insertApkForRepo("com.example." + i, 1, REPO_DELETE); + } + for (int i = 6; i <= 10; i ++) { + insertApkForRepo("org.fdroid.fdroid", i, REPO_DELETE); + insertApkForRepo("com.example." + i, 1, REPO_KEEP); + } + + assertTotalApkCount(20); + + Cursor cursor = getMockContentResolver().query( + ApkProvider.getRepoUri(REPO_DELETE), getMinimalProjection(), null, null, null); + assertResultCount(10, cursor); + assertBelongsToRepo(cursor, REPO_DELETE); + + int count = ApkProvider.Helper.deleteApksByRepo(getMockContext(), new MockRepo(REPO_DELETE)); + assertEquals(10, count); + + assertTotalApkCount(10); + cursor = getMockContentResolver().query( + ApkProvider.getRepoUri(REPO_DELETE), getMinimalProjection(), null, null, null); + assertResultCount(0, cursor); + + // The only remaining apks should be those from REPO_KEEP. + assertBelongsToRepo(queryAllApks(), REPO_KEEP); + } + + public void testQuery() { + Cursor cursor = queryAllApks(); + assertNotNull(cursor); + } + + public void testInsert() { + + // Start with an empty database... + Cursor cursor = queryAllApks(); + assertNotNull(cursor); + assertEquals(0, cursor.getCount()); + + Apk apk = new MockApk("org.fdroid.fdroid", 13); + + // Insert a new record... + Uri newUri = TestUtils.insertApk(this, apk.id, apk.vercode); + assertEquals(ApkProvider.getContentUri(apk).toString(), newUri.toString()); + cursor = queryAllApks(); + assertNotNull(cursor); + assertEquals(1, cursor.getCount()); + + // We intentionally throw an IllegalArgumentException if you haven't + // yet called cursor.move*()... + try { + new Apk(cursor); + fail(); + } catch (IllegalArgumentException e) { + // Success! + } catch (Exception e) { + fail(); + } + + // And now we should be able to recover these values from the apk + // value object (because the queryAllApks() helper asks for VERSION_CODE and + // APK_ID. + cursor.moveToFirst(); + Apk toCheck = new Apk(cursor); + assertEquals("org.fdroid.fdroid", toCheck.id); + assertEquals(13, toCheck.vercode); + } + + public void testCount() { + String[] projectionFields = getMinimalProjection(); + String[] projectionCount = new String[] { ApkProvider.DataColumns._COUNT }; + + for (int i = 0; i < 13; i ++) { + TestUtils.insertApk(this, "com.example", i); + } + + Uri all = ApkProvider.getContentUri(); + Cursor allWithFields = getMockContentResolver().query(all, projectionFields, null, null, null); + Cursor allWithCount = getMockContentResolver().query(all, projectionCount, null, null, null); + + assertResultCount(13, allWithFields); + assertResultCount(1, allWithCount); + + allWithCount.moveToFirst(); + int countColumn = allWithCount.getColumnIndex(ApkProvider.DataColumns._COUNT); + assertEquals(13, allWithCount.getInt(countColumn)); + } + + public void testInsertWithExtraFields() { + + assertResultCount(0, queryAllApks()); + + String[] repoFields = new String[] { + RepoProvider.DataColumns.DESCRIPTION, + RepoProvider.DataColumns.ADDRESS, + RepoProvider.DataColumns.FINGERPRINT, + RepoProvider.DataColumns.NAME, + RepoProvider.DataColumns.PUBLIC_KEY + }; + + for (String field : repoFields) { + ContentValues invalidRepo = new ContentValues(); + invalidRepo.put(field, "Test data"); + try { + TestUtils.insertApk(this, "org.fdroid.fdroid", 10, invalidRepo); + fail(); + } catch (IllegalArgumentException e) { + } catch (Exception e) { + fail(); + } + assertResultCount(0, queryAllApks()); + } + + ContentValues values = new ContentValues(); + values.put(ApkProvider.DataColumns.REPO_ID, 10); + values.put(ApkProvider.DataColumns.REPO_ADDRESS, "http://example.com"); + values.put(ApkProvider.DataColumns.REPO_VERSION, 3); + values.put(ApkProvider.DataColumns.FEATURES, "Some features"); + Uri uri = TestUtils.insertApk(this, "com.example.com", 1, values); + + assertResultCount(1, queryAllApks()); + + String[] projections = ApkProvider.DataColumns.ALL; + Cursor cursor = getMockContentResolver().query(uri, projections, null, null, null); + cursor.moveToFirst(); + Apk apk = new Apk(cursor); + + // These should have quietly been dropped when we tried to save them, + // because the provider only knows how to query them (not update them). + assertEquals(null, apk.repoAddress); + assertEquals(0, apk.repoVersion); + + // But this should have saved correctly... + assertEquals("Some features", apk.features.toString()); + assertEquals("com.example.com", apk.id); + assertEquals(1, apk.vercode); + assertEquals(10, apk.repo); + } + +} diff --git a/test/src/org/fdroid/fdroid/AppProviderTest.java b/test/src/org/fdroid/fdroid/AppProviderTest.java new file mode 100644 index 000000000..12124848e --- /dev/null +++ b/test/src/org/fdroid/fdroid/AppProviderTest.java @@ -0,0 +1,377 @@ +package org.fdroid.fdroid; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.res.Resources; +import android.database.Cursor; +import mock.MockCategoryResources; +import mock.MockContextSwappableComponents; +import mock.MockInstallablePackageManager; +import org.fdroid.fdroid.data.ApkProvider; +import org.fdroid.fdroid.data.App; +import org.fdroid.fdroid.data.AppProvider; +import org.fdroid.fdroid.data.InstalledAppCacheUpdater; + +import java.util.ArrayList; +import java.util.List; + +public class AppProviderTest extends FDroidProviderTest { + + public AppProviderTest() { + super(AppProvider.class, AppProvider.getAuthority()); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + getSwappableContext().setResources(new MockCategoryResources(getContext())); + } + + @Override + protected Resources getMockResources() { + return new MockCategoryResources(getContext()); + } + + @Override + protected String[] getMinimalProjection() { + return new String[] { + AppProvider.DataColumns.APP_ID, + AppProvider.DataColumns.NAME + }; + } + + /** + * Although this doesn't directly relate to the AppProvider, it is here because + * the AppProvider used to stumble across this bug when asking for installed apps, + * and the device had over 1000 apps installed. + */ + public void testMaxSqliteParams() { + + MockInstallablePackageManager pm = new MockInstallablePackageManager(); + getSwappableContext().setPackageManager(pm); + + insertApp("com.example.app1", "App 1"); + insertApp("com.example.app100", "App 100"); + insertApp("com.example.app1000", "App 1000"); + + for (int i = 0; i < 50; i ++) { + pm.install("com.example.app" + i, 1, "v" + 1); + } + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(1, AppProvider.getInstalledUri()); + + for (int i = 50; i < 500; i ++) { + pm.install("com.example.app" + i, 1, "v" + 1); + } + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(2, AppProvider.getInstalledUri()); + + for (int i = 500; i < 1100; i ++) { + pm.install("com.example.app" + i, 1, "v" + 1); + } + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(3, AppProvider.getInstalledUri()); + } + + public void testCantFindApp() { + assertNull(AppProvider.Helper.findById(getMockContentResolver(), "com.example.doesnt-exist")); + } + + public void testUris() { + assertInvalidUri(AppProvider.getAuthority()); + assertInvalidUri(ApkProvider.getContentUri()); + + assertValidUri(AppProvider.getContentUri()); + assertValidUri(AppProvider.getSearchUri("'searching!'")); + assertValidUri(AppProvider.getNoApksUri()); + assertValidUri(AppProvider.getInstalledUri()); + assertValidUri(AppProvider.getCanUpdateUri()); + + App app = new App(); + app.id = "org.fdroid.fdroid"; + + List apps = new ArrayList(1); + apps.add(app); + + assertValidUri(AppProvider.getContentUri(app)); + assertValidUri(AppProvider.getContentUri(apps)); + assertValidUri(AppProvider.getContentUri("org.fdroid.fdroid")); + } + + public void testQuery() { + Cursor cursor = queryAllApps(); + assertNotNull(cursor); + } + + private void insertApps(int count) { + for (int i = 0; i < count; i ++) { + insertApp("com.example.test." + i, "Test app " + i); + } + } + + private void insertAndInstallApp( + MockInstallablePackageManager packageManager, + String id, int installedVercode, int suggestedVercode, + boolean ignoreAll, int ignoreVercode) { + ContentValues values = new ContentValues(3); + values.put(AppProvider.DataColumns.SUGGESTED_VERSION_CODE, suggestedVercode); + values.put(AppProvider.DataColumns.IGNORE_ALLUPDATES, ignoreAll); + values.put(AppProvider.DataColumns.IGNORE_THISUPDATE, ignoreVercode); + insertApp(id, "App: " + id, values); + + TestUtils.installAndBroadcast(getMockContext(), packageManager, id, installedVercode, "v" + installedVercode); + } + + public void testCanUpdate() { + + MockContextSwappableComponents c = getSwappableContext(); + + MockInstallablePackageManager pm = new MockInstallablePackageManager(); + c.setPackageManager(pm); + + insertApp("not installed", "not installed"); + insertAndInstallApp(pm, "installed, only one version available", 1, 1, false, 0); + insertAndInstallApp(pm, "installed, already latest, no ignore", 10, 10, false, 0); + insertAndInstallApp(pm, "installed, already latest, ignore all", 10, 10, true, 0); + insertAndInstallApp(pm, "installed, already latest, ignore latest", 10, 10, false, 10); + insertAndInstallApp(pm, "installed, already latest, ignore old", 10, 10, false, 5); + insertAndInstallApp(pm, "installed, old version, no ignore", 5, 10, false, 0); + insertAndInstallApp(pm, "installed, old version, ignore all", 5, 10, true, 0); + insertAndInstallApp(pm, "installed, old version, ignore latest", 5, 10, false, 10); + insertAndInstallApp(pm, "installed, old version, ignore newer, but not latest", 5, 10, false, 8); + + ContentResolver r = getMockContentResolver(); + + // Can't "update", although can "install"... + App notInstalled = AppProvider.Helper.findById(r, "not installed"); + assertFalse(notInstalled.canAndWantToUpdate()); + + App installedOnlyOneVersionAvailable = AppProvider.Helper.findById(r, "installed, only one version available"); + App installedAlreadyLatestNoIgnore = AppProvider.Helper.findById(r, "installed, already latest, no ignore"); + App installedAlreadyLatestIgnoreAll = AppProvider.Helper.findById(r, "installed, already latest, ignore all"); + App installedAlreadyLatestIgnoreLatest = AppProvider.Helper.findById(r, "installed, already latest, ignore latest"); + App installedAlreadyLatestIgnoreOld = AppProvider.Helper.findById(r, "installed, already latest, ignore old"); + + assertFalse(installedOnlyOneVersionAvailable.canAndWantToUpdate()); + assertFalse(installedAlreadyLatestNoIgnore.canAndWantToUpdate()); + assertFalse(installedAlreadyLatestIgnoreAll.canAndWantToUpdate()); + assertFalse(installedAlreadyLatestIgnoreLatest.canAndWantToUpdate()); + assertFalse(installedAlreadyLatestIgnoreOld.canAndWantToUpdate()); + + App installedOldNoIgnore = AppProvider.Helper.findById(r, "installed, old version, no ignore"); + App installedOldIgnoreAll = AppProvider.Helper.findById(r, "installed, old version, ignore all"); + App installedOldIgnoreLatest = AppProvider.Helper.findById(r, "installed, old version, ignore latest"); + App installedOldIgnoreNewerNotLatest = AppProvider.Helper.findById(r, "installed, old version, ignore newer, but not latest"); + + assertTrue(installedOldNoIgnore.canAndWantToUpdate()); + assertFalse(installedOldIgnoreAll.canAndWantToUpdate()); + assertFalse(installedOldIgnoreLatest.canAndWantToUpdate()); + assertTrue(installedOldIgnoreNewerNotLatest.canAndWantToUpdate()); + + Cursor canUpdateCursor = r.query(AppProvider.getCanUpdateUri(), AppProvider.DataColumns.ALL, null, null, null); + canUpdateCursor.moveToFirst(); + List canUpdateIds = new ArrayList(canUpdateCursor.getCount()); + while (!canUpdateCursor.isAfterLast()) { + canUpdateIds.add(new App(canUpdateCursor).id); + canUpdateCursor.moveToNext(); + } + + String[] expectedUpdateableIds = { + "installed, old version, no ignore", + "installed, old version, ignore newer, but not latest", + }; + + TestUtils.assertContainsOnly(expectedUpdateableIds, canUpdateIds); + } + + public void testIgnored() { + + MockInstallablePackageManager pm = new MockInstallablePackageManager(); + getSwappableContext().setPackageManager(pm); + + insertApp("not installed", "not installed"); + insertAndInstallApp(pm, "installed, only one version available", 1, 1, false, 0); + insertAndInstallApp(pm, "installed, already latest, no ignore", 10, 10, false, 0); + insertAndInstallApp(pm, "installed, already latest, ignore all", 10, 10, true, 0); + insertAndInstallApp(pm, "installed, already latest, ignore latest", 10, 10, false, 10); + insertAndInstallApp(pm, "installed, already latest, ignore old", 10, 10, false, 5); + insertAndInstallApp(pm, "installed, old version, no ignore", 5, 10, false, 0); + insertAndInstallApp(pm, "installed, old version, ignore all", 5, 10, true, 0); + insertAndInstallApp(pm, "installed, old version, ignore latest", 5, 10, false, 10); + insertAndInstallApp(pm, "installed, old version, ignore newer, but not latest", 5, 10, false, 8); + + assertResultCount(10, AppProvider.getContentUri()); + + String[] projection = { AppProvider.DataColumns.APP_ID }; + List ignoredApps = AppProvider.Helper.findIgnored(getMockContext(), projection); + + String[] expectedIgnored = { + "installed, already latest, ignore all", + "installed, already latest, ignore latest", + // NOT "installed, already latest, ignore old" - because it + // is should only ignore if "ignored version" is >= suggested + + "installed, old version, ignore all", + "installed, old version, ignore latest" + // NOT "installed, old version, ignore newer, but not latest" + // for the same reason as above. + }; + + assertContainsOnlyIds(ignoredApps, expectedIgnored); + } + + private void assertContainsOnlyIds(List actualApps, String[] expectedIds) { + List actualIds = new ArrayList(actualApps.size()); + for (App app : actualApps) { + actualIds.add(app.id); + } + TestUtils.assertContainsOnly(actualIds, expectedIds); + } + + public void testInstalled() { + MockInstallablePackageManager pm = new MockInstallablePackageManager(); + getSwappableContext().setPackageManager(pm); + + insertApps(100); + + assertResultCount(100, AppProvider.getContentUri()); + assertResultCount(0, AppProvider.getInstalledUri()); + + for (int i = 10; i < 20; i ++) { + TestUtils.installAndBroadcast(getMockContext(), pm, "com.example.test." + i, i, "v1"); + } + + assertResultCount(10, AppProvider.getInstalledUri()); + } + + public void testInsert() { + + // Start with an empty database... + Cursor cursor = queryAllApps(); + assertNotNull(cursor); + assertEquals(0, cursor.getCount()); + + // Insert a new record... + insertApp("org.fdroid.fdroid", "F-Droid"); + cursor = queryAllApps(); + assertNotNull(cursor); + assertEquals(1, cursor.getCount()); + + // We intentionally throw an IllegalArgumentException if you haven't + // yet called cursor.move*()... + try { + new App(cursor); + fail(); + } catch (IllegalArgumentException e) { + // Success! + } catch (Exception e) { + fail(); + } + + // And now we should be able to recover these values from the app + // value object (because the queryAllApps() helper asks for NAME and + // APP_ID. + cursor.moveToFirst(); + App app = new App(cursor); + assertEquals("org.fdroid.fdroid", app.id); + assertEquals("F-Droid", app.name); + } + + private Cursor queryAllApps() { + return getMockContentResolver().query(AppProvider.getContentUri(), getMinimalProjection(), null, null, null); + } + + // ======================================================================== + // "Categories" + // (at this point) not an additional table, but we treat them sort of + // like they are. That means that if we change the implementation to + // use a separate table in the future, these should still pass. + // ======================================================================== + + public void testCategoriesSingle() { + insertAppWithCategory("com.dog", "Dog", "Animal"); + insertAppWithCategory("com.rock", "Rock", "Mineral"); + insertAppWithCategory("com.banana", "Banana", "Vegetable"); + + List categories = AppProvider.Helper.categories(getMockContext()); + String[] expected = new String[] { + getMockContext().getResources().getString(R.string.category_whatsnew), + getMockContext().getResources().getString(R.string.category_recentlyupdated), + getMockContext().getResources().getString(R.string.category_all), + "Animal", + "Mineral", + "Vegetable" + }; + TestUtils.assertContainsOnly(categories, expected); + } + + public void testCategoriesMultiple() { + insertAppWithCategory("com.rock.dog", "Rock-Dog", "Mineral,Animal"); + insertAppWithCategory("com.dog.rock.apple", "Dog-Rock-Apple", "Animal,Mineral,Vegetable"); + insertAppWithCategory("com.banana.apple", "Banana", "Vegetable,Vegetable"); + + List categories = AppProvider.Helper.categories(getMockContext()); + String[] expected = new String[] { + getMockContext().getResources().getString(R.string.category_whatsnew), + getMockContext().getResources().getString(R.string.category_recentlyupdated), + getMockContext().getResources().getString(R.string.category_all), + + "Animal", + "Mineral", + "Vegetable" + }; + TestUtils.assertContainsOnly(categories, expected); + + insertAppWithCategory("com.example.game", "Game", + "Running,Shooting,Jumping,Bleh,Sneh,Pleh,Blah,Test category," + + "The quick brown fox jumps over the lazy dog,With apostrophe's"); + + List categoriesLonger = AppProvider.Helper.categories(getMockContext()); + String[] expectedLonger = new String[] { + getMockContext().getResources().getString(R.string.category_whatsnew), + getMockContext().getResources().getString(R.string.category_recentlyupdated), + getMockContext().getResources().getString(R.string.category_all), + + "Animal", + "Mineral", + "Vegetable", + + "Running", + "Shooting", + "Jumping", + "Bleh", + "Sneh", + "Pleh", + "Blah", + "Test category", + "The quick brown fox jumps over the lazy dog", + "With apostrophe's" + }; + + TestUtils.assertContainsOnly(categoriesLonger, expectedLonger); + } + + // ======================================================================= + // Misc helper functions + // (to be used by any tests in this suite) + // ======================================================================= + + private void insertApp(String id, String name) { + insertApp(id, name, new ContentValues()); + } + + private void insertAppWithCategory(String id, String name, String categories) { + ContentValues values = new ContentValues(1); + values.put(AppProvider.DataColumns.CATEGORIES, categories); + insertApp(id, name, values); + } + + private void insertApp(String id, String name, + ContentValues additionalValues) { + TestUtils.insertApp(getMockContentResolver(), id, name, additionalValues); + } + +} diff --git a/test/src/org/fdroid/fdroid/BaseApkProviderTest.java b/test/src/org/fdroid/fdroid/BaseApkProviderTest.java new file mode 100644 index 000000000..7c2e42bc4 --- /dev/null +++ b/test/src/org/fdroid/fdroid/BaseApkProviderTest.java @@ -0,0 +1,78 @@ +package org.fdroid.fdroid; + +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import org.fdroid.fdroid.data.Apk; +import org.fdroid.fdroid.data.ApkProvider; + +import java.util.List; + +/** + * Provides helper methods that can be used by both Helper and plain old + * Provider tests. Allows the test classes to contain only test methods, + * hopefully making them easier to understand. + * + * This should not contain any test methods, or else they get executed + * once for every concrete subclass. + */ +abstract class BaseApkProviderTest extends FDroidProviderTest { + + public BaseApkProviderTest() { + super(ApkProvider.class, ApkProvider.getAuthority()); + } + + @Override + protected String[] getMinimalProjection() { + return new String[] { + ApkProvider.DataColumns.APK_ID, + ApkProvider.DataColumns.VERSION_CODE, + ApkProvider.DataColumns.NAME, + ApkProvider.DataColumns.REPO_ID + }; + } + + protected final Cursor queryAllApks() { + return getMockContentResolver().query(ApkProvider.getContentUri(), getMinimalProjection(), null, null, null); + } + + protected void assertContains(List apks, Apk apk) { + boolean found = false; + for (Apk a : apks) { + if (a.vercode == apk.vercode && a.id.equals(apk.id)) { + found = true; + break; + } + } + if (!found) { + fail("Apk [" + apk + "] not found in " + TestUtils.listToString(apks)); + } + } + + protected void assertBelongsToApp(Cursor apks, String appId) { + assertBelongsToApp(ApkProvider.Helper.cursorToList(apks), appId); + } + + protected void assertBelongsToApp(List apks, String appId) { + for (Apk apk : apks) { + assertEquals(appId, apk.id); + } + } + + protected void assertTotalApkCount(int expected) { + assertResultCount(expected, queryAllApks()); + } + + protected void assertBelongsToRepo(Cursor apkCursor, long repoId) { + for (Apk apk : ApkProvider.Helper.cursorToList(apkCursor)) { + assertEquals(repoId, apk.repo); + } + } + + protected Apk insertApkForRepo(String id, int versionCode, long repoId) { + ContentValues additionalValues = new ContentValues(); + additionalValues.put(ApkProvider.DataColumns.REPO_ID, repoId); + Uri uri = TestUtils.insertApk(this, id, versionCode, additionalValues); + return ApkProvider.Helper.get(getSwappableContext(), uri); + } +} diff --git a/test/src/org/fdroid/fdroid/FDroidProviderTest.java b/test/src/org/fdroid/fdroid/FDroidProviderTest.java new file mode 100644 index 000000000..1be7eec3d --- /dev/null +++ b/test/src/org/fdroid/fdroid/FDroidProviderTest.java @@ -0,0 +1,168 @@ +package org.fdroid.fdroid; + +import android.annotation.TargetApi; +import android.content.ContentValues; +import android.content.Context; +import android.content.res.Resources; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.provider.ContactsContract; +import android.test.ProviderTestCase2MockContext; +import mock.MockContextEmptyComponents; +import mock.MockContextSwappableComponents; +import mock.MockFDroidResources; +import org.fdroid.fdroid.data.*; + +import java.util.List; + +public abstract class FDroidProviderTest extends ProviderTestCase2MockContext { + + private FDroidProvider[] allProviders = { + new AppProvider(), + new RepoProvider(), + new ApkProvider(), + new InstalledAppProvider(), + }; + + private MockContextSwappableComponents swappableContext; + + public FDroidProviderTest(Class providerClass, String providerAuthority) { + super(providerClass, providerAuthority); + } + + protected Resources getMockResources() { + return new MockFDroidResources(getContext()); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + + // Instantiate all providers other than the one which was already created by the base class. + // This is because F-Droid providers tend to perform joins onto tables managed by other + // providers, and so we need to be able to insert into those other providers for these + // joins to be tested correctly. + for (FDroidProvider provider : allProviders) { + if (!provider.getName().equals(getProvider().getName())) { + provider.attachInfo(getMockContext(), null); + getMockContentResolver().addProvider(provider.getName(), provider); + } + } + + getSwappableContext().setResources(getMockResources()); + + // The *Provider.Helper.* functions tend to take a Context as their + // first parameter. This context is used to connect to the relevant + // content provider. Thus, we need a context that is able to connect + // to the mock content resolver, in order to reach the provider + // under test. + getSwappableContext().setContentResolver(getMockContentResolver()); + + } + + @TargetApi(Build.VERSION_CODES.ECLAIR) + public void testObviouslyInvalidUris() { + assertInvalidUri("http://www.google.com"); + assertInvalidUri(ContactsContract.AUTHORITY_URI); + assertInvalidUri("junk"); + } + + @Override + protected Context createMockContext(Context delegate) { + swappableContext = new MockContextEmptyComponents(); + return swappableContext; + } + + public MockContextSwappableComponents getSwappableContext() { + return swappableContext; + } + + protected void assertCantDelete(Uri uri) { + try { + getMockContentResolver().delete(uri, null, null); + fail(); + } catch (UnsupportedOperationException e) { + } catch (Exception e) { + fail(); + } + } + + protected void assertCantUpdate(Uri uri) { + try { + getMockContentResolver().update(uri, new ContentValues(), null, null); + fail(); + } catch (UnsupportedOperationException e) { + } catch (Exception e) { + fail(); + } + } + + protected void assertInvalidUri(String uri) { + assertInvalidUri(Uri.parse(uri)); + } + + protected void assertValidUri(String uri) { + assertValidUri(Uri.parse(uri)); + } + + protected void assertInvalidUri(Uri uri) { + try { + // Use getProvdider instead of getContentResolver, because the mock + // content resolver wont result in the provider we are testing, and + // hence we don't get to see how our provider responds to invalid + // uris. + getProvider().query(uri, getMinimalProjection(), null, null, null); + fail(); + } catch (UnsupportedOperationException e) {} + } + + protected void assertValidUri(Uri uri) { + Cursor cursor = getMockContentResolver().query(uri, getMinimalProjection(), null, null, null); + assertNotNull(cursor); + } + + /** + * Many queries need at least some sort of projection in order to produce + * valid SQL. As such, we also need to know about that, so we can provide + * helper functions that revolve around the contnet provider under test. + */ + protected abstract String[] getMinimalProjection(); + + protected void assertResultCount(int expectedCount, Uri uri) { + Cursor cursor = getMockContentResolver().query(uri, getMinimalProjection(), null, null, null); + assertResultCount(expectedCount, cursor); + } + + protected void assertResultCount(int expectedCount, List items) { + assertNotNull(items); + assertEquals(expectedCount, items.size()); + } + + protected void assertResultCount(int expectedCount, Cursor result) { + assertNotNull(result); + assertEquals(expectedCount, result.getCount()); + } + + protected void assertIsInstalledVersionInDb(String appId, int versionCode, String versionName) { + Uri uri = InstalledAppProvider.getAppUri(appId); + + String[] projection = { + InstalledAppProvider.DataColumns.APP_ID, + InstalledAppProvider.DataColumns.VERSION_CODE, + InstalledAppProvider.DataColumns.VERSION_NAME, + }; + + Cursor cursor = getMockContentResolver().query(uri, projection, null, null, null); + + assertNotNull(cursor); + assertEquals("App \"" + appId + "\" not installed", 1, cursor.getCount()); + + cursor.moveToFirst(); + + assertEquals(appId, cursor.getString(cursor.getColumnIndex(InstalledAppProvider.DataColumns.APP_ID))); + assertEquals(versionCode, cursor.getInt(cursor.getColumnIndex(InstalledAppProvider.DataColumns.VERSION_CODE))); + assertEquals(versionName, cursor.getString(cursor.getColumnIndex(InstalledAppProvider.DataColumns.VERSION_NAME))); + } + +} diff --git a/test/src/org/fdroid/fdroid/FDroidTest.java b/test/src/org/fdroid/fdroid/FDroidTest.java new file mode 100644 index 000000000..07d9f3ee3 --- /dev/null +++ b/test/src/org/fdroid/fdroid/FDroidTest.java @@ -0,0 +1,14 @@ +package org.fdroid.fdroid; + +import android.annotation.TargetApi; +import android.os.Build; +import android.test.ActivityInstrumentationTestCase2; + +@TargetApi(Build.VERSION_CODES.CUPCAKE) +public class FDroidTest extends ActivityInstrumentationTestCase2 { + + public FDroidTest() { + super("org.fdroid.fdroid", FDroid.class); + } + +} diff --git a/test/src/org/fdroid/fdroid/InstalledAppCacheTest.java b/test/src/org/fdroid/fdroid/InstalledAppCacheTest.java new file mode 100644 index 000000000..2a849da7f --- /dev/null +++ b/test/src/org/fdroid/fdroid/InstalledAppCacheTest.java @@ -0,0 +1,179 @@ +package org.fdroid.fdroid; + +import android.database.Cursor; +import android.net.Uri; +import mock.MockInstallablePackageManager; +import org.fdroid.fdroid.data.InstalledAppCacheUpdater; +import org.fdroid.fdroid.data.InstalledAppProvider; + +/** + * Tests the ability of the {@link org.fdroid.fdroid.data.InstalledAppCacheUpdater} to stay in sync with + * the {@link android.content.pm.PackageManager}. + * For practical reasons, it extends FDroidProviderTest, although there is also a + * separate test for the InstalledAppProvider which tests the CRUD operations in more detail. + */ +public class InstalledAppCacheTest extends FDroidProviderTest { + + private MockInstallablePackageManager packageManager; + + public InstalledAppCacheTest() { + super(InstalledAppProvider.class, InstalledAppProvider.getAuthority()); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + packageManager = new MockInstallablePackageManager(); + getSwappableContext().setPackageManager(packageManager); + } + + @Override + protected String[] getMinimalProjection() { + return new String[] { + InstalledAppProvider.DataColumns.APP_ID + }; + } + + public void install(String appId, int versionCode, String versionName) { + packageManager.install(appId, versionCode, versionName); + } + + public void remove(String appId) { + packageManager.remove(appId); + } + + public void testFromEmptyCache() { + assertResultCount(0, InstalledAppProvider.getContentUri()); + for (int i = 1; i <= 15; i ++) { + install("com.example.app" + i, 200, "2.0"); + } + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + String[] expectedInstalledIds = { + "com.example.app1", + "com.example.app2", + "com.example.app3", + "com.example.app4", + "com.example.app5", + "com.example.app6", + "com.example.app7", + "com.example.app8", + "com.example.app9", + "com.example.app10", + "com.example.app11", + "com.example.app12", + "com.example.app13", + "com.example.app14", + "com.example.app15", + }; + + TestUtils.assertContainsOnly(getInstalledAppIdsFromProvider(), expectedInstalledIds); + } + + private String[] getInstalledAppIdsFromProvider() { + Uri uri = InstalledAppProvider.getContentUri(); + String[] projection = { InstalledAppProvider.DataColumns.APP_ID }; + Cursor result = getMockContext().getContentResolver().query(uri, projection, null, null, null); + if (result == null) { + return new String[0]; + } + + String[] installedAppIds = new String[result.getCount()]; + result.moveToFirst(); + int i = 0; + while (!result.isAfterLast()) { + installedAppIds[i] = result.getString(result.getColumnIndex(InstalledAppProvider.DataColumns.APP_ID)); + result.moveToNext(); + i ++; + } + result.close(); + return installedAppIds; + } + + public void testAppsAdded() { + assertResultCount(0, InstalledAppProvider.getContentUri()); + + install("com.example.app1", 1, "v1"); + install("com.example.app2", 1, "v1"); + install("com.example.app3", 1, "v1"); + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(3, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app1", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app2", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app3", 1, "v1"); + + install("com.example.app10", 1, "v1"); + install("com.example.app11", 1, "v1"); + install("com.example.app12", 1, "v1"); + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(6, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app10", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app11", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app12", 1, "v1"); + } + + public void testAppsRemoved() { + install("com.example.app1", 1, "v1"); + install("com.example.app2", 1, "v1"); + install("com.example.app3", 1, "v1"); + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(3, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app1", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app2", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app3", 1, "v1"); + + remove("com.example.app2"); + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(2, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app1", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app3", 1, "v1"); + } + + public void testAppsUpdated() { + install("com.example.app1", 1, "v1"); + install("com.example.app2", 1, "v1"); + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(2, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app1", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app2", 1, "v1"); + + install("com.example.app2", 20, "v2.0"); + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(2, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app1", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app2", 20, "v2.0"); + } + + public void testAppsAddedRemovedAndUpdated() { + install("com.example.app1", 1, "v1"); + install("com.example.app2", 1, "v1"); + install("com.example.app3", 1, "v1"); + install("com.example.app4", 1, "v1"); + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(4, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app1", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app2", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app3", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app4", 1, "v1"); + + install("com.example.app1", 13, "v1.3"); + remove("com.example.app2"); + remove("com.example.app3"); + install("com.example.app10", 1, "v1"); + InstalledAppCacheUpdater.updateInForeground(getMockContext()); + + assertResultCount(3, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app1", 13, "v1.3"); + assertIsInstalledVersionInDb("com.example.app4", 1, "v1"); + assertIsInstalledVersionInDb("com.example.app10", 1, "v1"); + + } + +} diff --git a/test/src/org/fdroid/fdroid/InstalledAppProviderTest.java b/test/src/org/fdroid/fdroid/InstalledAppProviderTest.java new file mode 100644 index 000000000..14ff885c9 --- /dev/null +++ b/test/src/org/fdroid/fdroid/InstalledAppProviderTest.java @@ -0,0 +1,178 @@ +package org.fdroid.fdroid; + +import android.content.ContentValues; +import mock.MockInstallablePackageManager; +import org.fdroid.fdroid.data.ApkProvider; +import org.fdroid.fdroid.data.AppProvider; +import org.fdroid.fdroid.data.InstalledAppProvider; +import org.fdroid.fdroid.data.RepoProvider; + +public class InstalledAppProviderTest extends FDroidProviderTest { + + private MockInstallablePackageManager packageManager; + + public InstalledAppProviderTest() { + super(InstalledAppProvider.class, InstalledAppProvider.getAuthority()); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + packageManager = new MockInstallablePackageManager(); + getSwappableContext().setPackageManager(packageManager); + } + + protected MockInstallablePackageManager getPackageManager() { + return packageManager; + } + + public void testUris() { + assertInvalidUri(InstalledAppProvider.getAuthority()); + assertInvalidUri(RepoProvider.getContentUri()); + assertInvalidUri(AppProvider.getContentUri()); + assertInvalidUri(ApkProvider.getContentUri()); + assertInvalidUri("blah"); + + assertValidUri(InstalledAppProvider.getContentUri()); + assertValidUri(InstalledAppProvider.getAppUri("com.example.com")); + assertValidUri(InstalledAppProvider.getAppUri("blah")); + } + + public void testInsert() { + + assertResultCount(0, InstalledAppProvider.getContentUri()); + + insertInstalledApp("com.example.com1", 1, "v1"); + insertInstalledApp("com.example.com2", 2, "v2"); + insertInstalledApp("com.example.com3", 3, "v3"); + + assertResultCount(3, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.com1", 1, "v1"); + assertIsInstalledVersionInDb("com.example.com2", 2, "v2"); + assertIsInstalledVersionInDb("com.example.com3", 3, "v3"); + } + + public void testUpdate() { + + insertInstalledApp("com.example.app1", 10, "1.0"); + insertInstalledApp("com.example.app2", 10, "1.0"); + + assertResultCount(2, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app2", 10, "1.0"); + + try { + getMockContentResolver().update( + InstalledAppProvider.getAppUri("com.example.app2"), + createContentValues(11, "1.1"), + null, null + ); + fail(); + } catch (UnsupportedOperationException e) { + // We expect this to happen, because we should be using insert() instead. + } + + getMockContentResolver().insert( + InstalledAppProvider.getContentUri(), + createContentValues("com.example.app2", 11, "1.1") + ); + + assertResultCount(2, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app2", 11, "1.1"); + + } + + public void testDelete() { + + insertInstalledApp("com.example.app1", 10, "1.0"); + insertInstalledApp("com.example.app2", 10, "1.0"); + + assertResultCount(2, InstalledAppProvider.getContentUri()); + + getMockContentResolver().delete(InstalledAppProvider.getAppUri("com.example.app1"), null, null); + + assertResultCount(1, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.app2", 10, "1.0"); + + } + + public void testInsertWithBroadcast() { + + installAndBroadcast("com.example.broadcasted1", 10, "v1.0"); + installAndBroadcast("com.example.broadcasted2", 105, "v1.05"); + + assertResultCount(2, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.broadcasted1", 10, "v1.0"); + assertIsInstalledVersionInDb("com.example.broadcasted2", 105, "v1.05"); + } + + public void testUpdateWithBroadcast() { + + installAndBroadcast("com.example.toUpgrade", 1, "v0.1"); + + assertResultCount(1, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.toUpgrade", 1, "v0.1"); + + upgradeAndBroadcast("com.example.toUpgrade", 2, "v0.2"); + + assertResultCount(1, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.toUpgrade", 2, "v0.2"); + + } + + public void testDeleteWithBroadcast() { + + installAndBroadcast("com.example.toKeep", 1, "v0.1"); + installAndBroadcast("com.example.toDelete", 1, "v0.1"); + + assertResultCount(2, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.toKeep", 1, "v0.1"); + assertIsInstalledVersionInDb("com.example.toDelete", 1, "v0.1"); + + removeAndBroadcast("com.example.toDelete"); + + assertResultCount(1, InstalledAppProvider.getContentUri()); + assertIsInstalledVersionInDb("com.example.toKeep", 1, "v0.1"); + + } + + @Override + protected String[] getMinimalProjection() { + return new String[] { + InstalledAppProvider.DataColumns.APP_ID, + InstalledAppProvider.DataColumns.VERSION_CODE, + InstalledAppProvider.DataColumns.VERSION_NAME, + }; + } + + private ContentValues createContentValues(int versionCode, String versionNumber) { + return createContentValues(null, versionCode, versionNumber); + } + + private ContentValues createContentValues(String appId, int versionCode, String versionNumber) { + ContentValues values = new ContentValues(3); + if (appId != null) { + values.put(InstalledAppProvider.DataColumns.APP_ID, appId); + } + values.put(InstalledAppProvider.DataColumns.VERSION_CODE, versionCode); + values.put(InstalledAppProvider.DataColumns.VERSION_NAME, versionNumber); + return values; + } + + private void insertInstalledApp(String appId, int versionCode, String versionNumber) { + ContentValues values = createContentValues(appId, versionCode, versionNumber); + getMockContentResolver().insert(InstalledAppProvider.getContentUri(), values); + } + + private void removeAndBroadcast(String appId) { + TestUtils.removeAndBroadcast(getMockContext(), getPackageManager(), appId); + } + + private void upgradeAndBroadcast(String appId, int versionCode, String versionName) { + TestUtils.upgradeAndBroadcast(getMockContext(), getPackageManager(), appId, versionCode, versionName); + } + + private void installAndBroadcast(String appId, int versionCode, String versionName) { + TestUtils.installAndBroadcast(getMockContext(), getPackageManager(), appId, versionCode, versionName); + } + +} diff --git a/test/src/org/fdroid/fdroid/TestUtils.java b/test/src/org/fdroid/fdroid/TestUtils.java new file mode 100644 index 000000000..e4927a3fe --- /dev/null +++ b/test/src/org/fdroid/fdroid/TestUtils.java @@ -0,0 +1,178 @@ +package org.fdroid.fdroid; + +import android.content.*; +import android.net.Uri; +import junit.framework.AssertionFailedError; +import mock.MockInstallablePackageManager; +import org.fdroid.fdroid.data.ApkProvider; +import org.fdroid.fdroid.data.AppProvider; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class TestUtils { + + public static void assertContainsOnly(List actualList, T[] expectedArray) { + List expectedList = new ArrayList(expectedArray.length); + Collections.addAll(expectedList, expectedArray); + assertContainsOnly(actualList, expectedList); + } + + public static void assertContainsOnly(T[] actualArray, List expectedList) { + List actualList = new ArrayList(actualArray.length); + Collections.addAll(actualList, actualArray); + assertContainsOnly(actualList, expectedList); + } + + public static void assertContainsOnly(T[] actualArray, T[] expectedArray) { + List expectedList = new ArrayList(expectedArray.length); + Collections.addAll(expectedList, expectedArray); + assertContainsOnly(actualArray, expectedList); + } + + public static String listToString(List list) { + String string = "["; + for (int i = 0; i < list.size(); i ++) { + if (i > 0) { + string += ", "; + } + string += "'" + list.get(i) + "'"; + } + string += "]"; + return string; + } + + public static void assertContainsOnly(List actualList, List expectedContains) { + if (actualList.size() != expectedContains.size()) { + String message = + "List sizes don't match.\n" + + "Expected: " + + listToString(expectedContains) + "\n" + + "Actual: " + + listToString(actualList); + throw new AssertionFailedError(message); + } + for (T required : expectedContains) { + boolean containsRequired = false; + for (T itemInList : actualList) { + if (required.equals(itemInList)) { + containsRequired = true; + break; + } + } + if (!containsRequired) { + String message = + "List doesn't contain \"" + required + "\".\n" + + "Expected: " + + listToString(expectedContains) + "\n" + + "Actual: " + + listToString(actualList); + throw new AssertionFailedError(message); + } + } + } + + public static void insertApp(ContentResolver resolver, String appId, String name) { + insertApp(resolver, appId, name, new ContentValues()); + } + + public static void insertApp(ContentResolver resolver, String id, String name, ContentValues additionalValues) { + + ContentValues values = new ContentValues(); + values.put(AppProvider.DataColumns.APP_ID, id); + values.put(AppProvider.DataColumns.NAME, name); + + // Required fields (NOT NULL in the database). + values.put(AppProvider.DataColumns.SUMMARY, "test summary"); + values.put(AppProvider.DataColumns.DESCRIPTION, "test description"); + values.put(AppProvider.DataColumns.LICENSE, "GPL?"); + values.put(AppProvider.DataColumns.IS_COMPATIBLE, 1); + values.put(AppProvider.DataColumns.IGNORE_ALLUPDATES, 0); + values.put(AppProvider.DataColumns.IGNORE_THISUPDATE, 0); + + values.putAll(additionalValues); + + Uri uri = AppProvider.getContentUri(); + + resolver.insert(uri, values); + } + + public static Uri insertApk(FDroidProviderTest providerTest, String id, int versionCode) { + return insertApk(providerTest, id, versionCode, new ContentValues()); + } + + public static Uri insertApk(FDroidProviderTest providerTest, String id, int versionCode, ContentValues additionalValues) { + + ContentValues values = new ContentValues(); + + values.put(ApkProvider.DataColumns.APK_ID, id); + values.put(ApkProvider.DataColumns.VERSION_CODE, versionCode); + + // Required fields (NOT NULL in the database). + values.put(ApkProvider.DataColumns.REPO_ID, 1); + values.put(ApkProvider.DataColumns.VERSION, "The good one"); + values.put(ApkProvider.DataColumns.HASH, "11111111aaaaaaaa"); + values.put(ApkProvider.DataColumns.NAME, "Test Apk"); + values.put(ApkProvider.DataColumns.SIZE, 10000); + values.put(ApkProvider.DataColumns.IS_COMPATIBLE, 1); + + values.putAll(additionalValues); + + Uri uri = ApkProvider.getContentUri(); + + return providerTest.getMockContentResolver().insert(uri, values); + } + + /** + * Will tell {@code pm} that we are installing {@code appId}, and then alert the + * {@link org.fdroid.fdroid.PackageAddedReceiver}. This will in turn update the + * "installed apps" table in the database. + * + * Note: in order for this to work, the {@link AppProviderTest#getSwappableContext()} + * will need to be aware of the package manager that we have passed in. Therefore, + * you will have to have called + * {@link mock.MockContextSwappableComponents#setPackageManager(android.content.pm.PackageManager)} + * on the {@link AppProviderTest#getSwappableContext()} before invoking this method. + */ + public static void installAndBroadcast( + Context context, MockInstallablePackageManager pm, + String appId, int versionCode, String versionName) { + + pm.install(appId, versionCode, versionName); + Intent installIntent = new Intent(Intent.ACTION_PACKAGE_ADDED); + installIntent.setData(Uri.parse("package:" + appId)); + new PackageAddedReceiver().onReceive(context, installIntent); + + } + + /** + * @see org.fdroid.fdroid.TestUtils#installAndBroadcast(android.content.Context context, mock.MockInstallablePackageManager, String, int, String) + */ + public static void upgradeAndBroadcast( + Context context, MockInstallablePackageManager pm, + String appId, int versionCode, String versionName) { + /* + removeAndBroadcast(context, pm, appId); + installAndBroadcast(context, pm, appId, versionCode, versionName); + */ + pm.install(appId, versionCode, versionName); + Intent installIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED); + installIntent.setData(Uri.parse("package:" + appId)); + new PackageUpgradedReceiver().onReceive(context, installIntent); + + } + + /** + * @see org.fdroid.fdroid.TestUtils#installAndBroadcast(android.content.Context context, mock.MockInstallablePackageManager, String, int, String) + */ + public static void removeAndBroadcast(Context context, MockInstallablePackageManager pm, String appId) { + + pm.remove(appId); + Intent installIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED); + installIntent.setData(Uri.parse("package:" + appId)); + new PackageRemovedReceiver().onReceive(context, installIntent); + + } + +} diff --git a/test/src/org/fdroid/fdroid/mock/MockApk.java b/test/src/org/fdroid/fdroid/mock/MockApk.java new file mode 100644 index 000000000..f3da31d6d --- /dev/null +++ b/test/src/org/fdroid/fdroid/mock/MockApk.java @@ -0,0 +1,12 @@ +package org.fdroid.fdroid.mock; + +import org.fdroid.fdroid.data.Apk; + +public class MockApk extends Apk { + + public MockApk(String id, int versionCode) { + this.id = id; + this.vercode = versionCode; + } + +} diff --git a/test/src/org/fdroid/fdroid/mock/MockApp.java b/test/src/org/fdroid/fdroid/mock/MockApp.java new file mode 100644 index 000000000..1a983865c --- /dev/null +++ b/test/src/org/fdroid/fdroid/mock/MockApp.java @@ -0,0 +1,16 @@ +package org.fdroid.fdroid.mock; + +import org.fdroid.fdroid.data.App; + +public class MockApp extends App { + + public MockApp(String id) { + this(id, "App " + id); + } + + public MockApp(String id, String name) { + this.id = id; + this.name = name; + } + +} diff --git a/test/src/org/fdroid/fdroid/mock/MockRepo.java b/test/src/org/fdroid/fdroid/mock/MockRepo.java new file mode 100644 index 000000000..3b3fce976 --- /dev/null +++ b/test/src/org/fdroid/fdroid/mock/MockRepo.java @@ -0,0 +1,11 @@ +package org.fdroid.fdroid.mock; + +import org.fdroid.fdroid.data.Repo; + +public class MockRepo extends Repo { + + public MockRepo(long repoId) { + id = repoId; + } + +} diff --git a/tests/gen/org/fdroid/fdroid/tests/BuildConfig.java b/tests/gen/org/fdroid/fdroid/tests/BuildConfig.java deleted file mode 100644 index 2892c52fb..000000000 --- a/tests/gen/org/fdroid/fdroid/tests/BuildConfig.java +++ /dev/null @@ -1,8 +0,0 @@ -/*___Generated_by_IDEA___*/ - -/** Automatically generated file. DO NOT MODIFY */ -package org.fdroid.fdroid.tests; - -public final class BuildConfig { - public final static boolean DEBUG = true; -} \ No newline at end of file diff --git a/tests/gen/org/fdroid/fdroid/tests/Manifest.java b/tests/gen/org/fdroid/fdroid/tests/Manifest.java deleted file mode 100644 index 15e60435f..000000000 --- a/tests/gen/org/fdroid/fdroid/tests/Manifest.java +++ /dev/null @@ -1,7 +0,0 @@ -/*___Generated_by_IDEA___*/ - -package org.fdroid.fdroid.tests; - -/* This stub is for using by IDE only. It is NOT the Manifest class actually packed into APK */ -public final class Manifest { -} \ No newline at end of file diff --git a/tests/gen/org/fdroid/fdroid/tests/R.java b/tests/gen/org/fdroid/fdroid/tests/R.java deleted file mode 100644 index 40f6d3574..000000000 --- a/tests/gen/org/fdroid/fdroid/tests/R.java +++ /dev/null @@ -1,7 +0,0 @@ -/*___Generated_by_IDEA___*/ - -package org.fdroid.fdroid.tests; - -/* This stub is for using by IDE only. It is NOT the R class actually packed into APK */ -public final class R { -} \ No newline at end of file diff --git a/tests/local.properties b/tests/local.properties deleted file mode 100644 index 12a01149a..000000000 --- a/tests/local.properties +++ /dev/null @@ -1,10 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must *NOT* be checked into Version Control Systems, -# as it contains information specific to your local configuration. - -# location of the SDK. This is only used by Ant -# For customization when using a Version Control System, please read the -# header note. -sdk.dir=/opt/android-sdk diff --git a/tools/fix-ellipsis.sh b/tools/fix-ellipsis.sh index 5a69f89b1..b3f02fb85 100755 --- a/tools/fix-ellipsis.sh +++ b/tools/fix-ellipsis.sh @@ -2,4 +2,4 @@ # Fix TypographyEllipsis programmatically -find res -name strings.xml -type f | xargs -n 1 sed -i 's/\.\.\./…/g' +sed -i 's/\.\.\./…/g' res/values*/*.xml diff --git a/tools/fix-formats.sh b/tools/fix-formats.sh new file mode 100755 index 000000000..972ff6d1f --- /dev/null +++ b/tools/fix-formats.sh @@ -0,0 +1,5 @@ +#!/bin/bash -x + +# Fix StringFormatMatches programmatically + +sed -i 's/\(%[0-9]\)%\([a-z]\)/\1$\2/g' res/values*/*.xml diff --git a/tools/remove-unused-trans.sh b/tools/remove-unused-trans.sh new file mode 100755 index 000000000..574c2d2ab --- /dev/null +++ b/tools/remove-unused-trans.sh @@ -0,0 +1,13 @@ +#!/bin/bash -x + +# Remove extra translations + +lint . --quiet --check ExtraTranslation --nolines | \ + sed -n 's@res/values-[^/]\+/\([^\.]\+\)\.xml:.*Error: "\([^"]*\)" is translated here but not found in default locale.*@\1 \2@p' | \ + while read file name; do + if [[ $file == strings ]]; then + sed -i "/name=\"$name\"/d" res/values-*/strings.xml + elif [[ $file == array ]]; then + sed -i "/